From c89bf51af26003d01fb73eece3899c2b6e97e7bd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 28 Jun 2015 18:02:38 +0200 Subject: [PATCH 0001/1891] Update sample configuration for Smart HTTP Using uWSGI for the Smart HTTP protocol caused some issues, see e.g. FS#45428. Suggest using fcgiwrap instead which is more lightweight, has better documentation and is easier to debug. Signed-off-by: Lukas Fleischer --- INSTALL | 27 ++++++++++----------------- conf/fcgiwrap.service.proto | 11 +++++++++++ conf/fcgiwrap.socket.proto | 11 +++++++++++ 3 files changed, 32 insertions(+), 17 deletions(-) create mode 100644 conf/fcgiwrap.service.proto create mode 100644 conf/fcgiwrap.socket.proto diff --git a/INSTALL b/INSTALL index b090789d..d68fa269 100644 --- a/INSTALL +++ b/INSTALL @@ -63,24 +63,17 @@ Setup on Arch Linux AuthorizedKeysCommand /usr/local/bin/aur-git-auth "%t" "%k" AuthorizedKeysCommandUser aur -9) If you want to enable smart HTTP support with nginx and uWSGI, you can use - the following directives: +9) If you want to enable smart HTTP support with nginx and fcgiwrap, you can + use the following directives: location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { - include uwsgi_params; - uwsgi_modifier1 9; - uwsgi_param PATH_INFO /aur.git/$2; - uwsgi_param GIT_NAMESPACE $1; - uwsgi_pass unix:/run/uwsgi/smarthttp/aurweb.sock; + fastcgi_pass unix:/run/fcgiwrap.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; + fastcgi_param PATH_INFO /aur.git/$3; + fastcgi_param GIT_HTTP_EXPORT_ALL ""; + fastcgi_param GIT_NAMESPACE $1; + fastcgi_param GIT_PROJECT_ROOT /srv/http/aurweb/; } - For the uWSGI configuration, the following template can be used: - - [uwsgi] - plugins = cgi - uid = aur - processes = 1 - threads = 8 - env = GIT_HTTP_EXPORT_ALL= - env = GIT_PROJECT_ROOT=/srv/http/aurweb - cgi = /usr/lib/git-core/git-http-backend + Sample systemd unit files for fcgiwrap can be found under conf/. diff --git a/conf/fcgiwrap.service.proto b/conf/fcgiwrap.service.proto new file mode 100644 index 00000000..c4e85448 --- /dev/null +++ b/conf/fcgiwrap.service.proto @@ -0,0 +1,11 @@ +[Unit] +Description=Simple CGI Server +After=nss-user-lookup.target + +[Service] +ExecStart=/usr/sbin/fcgiwrap +User=aur +Group=aur + +[Install] +Also=fcgiwrap.socket diff --git a/conf/fcgiwrap.socket.proto b/conf/fcgiwrap.socket.proto new file mode 100644 index 00000000..a1bc8260 --- /dev/null +++ b/conf/fcgiwrap.socket.proto @@ -0,0 +1,11 @@ +[Unit] +Description=fcgiwrap Socket + +[Socket] +ListenStream=/run/fcgiwrap.sock +SocketUser=http +SocketGroup=http +SocketMode=0700 + +[Install] +WantedBy=sockets.target From feeda37bb754a57c480fdd58d68701d7853928f6 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 29 Jun 2015 08:57:28 +0200 Subject: [PATCH 0002/1891] Accept SSH keys with whitespace in comments `ssh-keygen -l` returns more than four tokens when there is whitespace in the key comment. Fixes FS#45488. Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 861de0ac..edd38ee8 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -1250,7 +1250,7 @@ function ssh_key_fingerprint($ssh_key) { unlink($tmpfile); $tokens = explode(' ', $out[0]); - if (count($tokens) != 4) { + if (count($tokens) < 4) { return false; } From ea59f7277849c9f37a166375293d57bdd97bb20b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sat, 4 Jul 2015 12:31:41 +0200 Subject: [PATCH 0003/1891] RPC: Add decimal_fields array for floating-point fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes FS#45537. Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 7b77da46..debffc46 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -45,6 +45,9 @@ class AurJSON { 'ID', 'PackageBaseID', 'NumVotes', 'OutOfDate', 'FirstSubmitted', 'LastModified' ); + private static $decimal_fields = array( + 'Popularity' + ); /* * Handles post data, and routes the request. @@ -255,6 +258,10 @@ class AurJSON { $row[$field] = intval($row[$field]); } + foreach (self::$decimal_fields as $field) { + $row[$field] = floatval($row[$field]); + } + if ($this->version >= 2 && ($type == 'info' || $type == 'multiinfo')) { $row = array_merge($row, $this->get_extended_fields($row['ID'])); } From f4f1921fc60a759c647fb6004655c4dd9e8639cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sat, 4 Jul 2015 13:39:16 +0200 Subject: [PATCH 0004/1891] git-update: Fix error when printing SRCINFO errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes a bug introduced by ae2907a (git: Use .format everywhere instead of %, 2015-06-27) where passing the error tuple to .format wasn't prefixed with an asterisk. Fixes FS#45545. Reported-by: Marty Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 592f127e..ba65cab6 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -242,7 +242,7 @@ for commit in walker: "when parsing .SRCINFO in commit\n") sys.stderr.write("error: {:s}:\n".format(str(commit.id))) for error in errors: - sys.stderr.write("error: line {:d}: {:s}\n".format(error)) + sys.stderr.write("error: line {:d}: {:s}\n".format(*error)) exit(1) srcinfo_pkgbase = srcinfo._pkgbase['pkgname'] From 881b550dec07fbfbebea2229a6667bcc37eef0f2 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 12 Jul 2015 11:46:44 -0400 Subject: [PATCH 0005/1891] use rel="nofollow" for links in comments This removes the incentive for spammers to post links by asking search engines to ignore them. Signed-off-by: Daniel Micay Signed-off-by: Lukas Fleischer --- web/lib/aur.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 7a455c6e..b410db5a 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -595,7 +595,7 @@ function parse_comment($comment) { if ($i % 2) { # convert links $html .= '' . htmlspecialchars($matches[$i]) . ''; + '" rel="nofollow">' . htmlspecialchars($matches[$i]) . ''; } else { # convert everything else From 29bffe64ad324ee64376123230ef75b9ba2a5d1a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 14 Jul 2015 11:04:35 +0200 Subject: [PATCH 0006/1891] stats.inc.php: Improve definition of "added" Until now, a package is listed under "Packages added in the past 7 days" if it was added at most one week ago and if the last modification time matches the submission time stamp. A package is considered "updated" if it was modified at most one week ago and the modification time stamp differs from the submission time stamp. Since we are using Git to store packages now, there always is a delay between package creation (which is handled in git-serve) and last modification (which is handled by git-update). Thus, by the above definitions, almost every package is considered "updated". Since there is no reason for excluding packages that were both added and updated within the past seven days from the "Packages added in the past 7 days" counter, we can drop the check whether the last modification time matches the submission time stamp. Also, to identify packages that were actually updated, we now only count packages that were modified at least one hour after the initial submission. Signed-off-by: Lukas Fleischer --- web/lib/stats.inc.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/web/lib/stats.inc.php b/web/lib/stats.inc.php index 52637be5..203be0ad 100644 --- a/web/lib/stats.inc.php +++ b/web/lib/stats.inc.php @@ -77,25 +77,29 @@ function general_stats_table() { $yearstamp = intval(strtotime("-1 year")); $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS >= $targstamp "; - $q.= "AND ModifiedTS = SubmittedTS "; + $q.= "WHERE SubmittedTS >= $targstamp "; $q.= "AND PackagerUID IS NOT NULL"; $add_count = db_cache_value($q, 'add_count'); + /* + * A package whose last modification time differs less than an hour + * from the initial submission time is considered new. + */ + $q = "SELECT COUNT(*) FROM PackageBases "; $q.= "WHERE ModifiedTS >= $targstamp "; - $q.= "AND ModifiedTS != SubmittedTS "; + $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; $q.= "AND PackagerUID IS NOT NULL"; $update_count = db_cache_value($q, 'update_count'); $q = "SELECT COUNT(*) FROM PackageBases "; $q.= "WHERE ModifiedTS >= $yearstamp "; - $q.= "AND ModifiedTS != SubmittedTS "; + $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; $q.= "AND PackagerUID IS NOT NULL"; $update_year_count = db_cache_value($q, 'update_year_count'); $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS = SubmittedTS "; + $q.= "WHERE ModifiedTS - SubmittedTS < 3600 "; $q.= "AND PackagerUID IS NOT NULL"; $never_update_count = db_cache_value($q, 'never_update_count'); From 38b1bbe78df3a518f0688e50f1d6361221b95ea1 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 16 Jul 2015 14:09:55 +0200 Subject: [PATCH 0007/1891] git-update: Error out if PKGBUILD is missing Fixes FS#45646. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index ba65cab6..935fa5bb 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -216,8 +216,9 @@ cur.execute("SELECT Name FROM PackageBlacklist") blacklist = [row[0] for row in cur.fetchall()] for commit in walker: - if not '.SRCINFO' in commit.tree: - die_commit("missing .SRCINFO", str(commit.id)) + for fname in ('.SRCINFO', 'PKGBUILD'): + if not fname in commit.tree: + die_commit("missing {:s}".format(fname), str(commit.id)) for treeobj in commit.tree: blob = repo[treeobj.id] From f19892f7c2ecc1667fd24331d15217cc4f848d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sat, 1 Aug 2015 18:16:46 +0200 Subject: [PATCH 0008/1891] aurinfo: Allow lines starting with spaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- git-interface/aurinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/aurinfo.py b/git-interface/aurinfo.py index 201f8642..dfee3c14 100644 --- a/git-interface/aurinfo.py +++ b/git-interface/aurinfo.py @@ -121,7 +121,7 @@ def ParseAurinfoFromIterable(iterable, ecatcher=None): current_package = None continue - if not line.startswith('\t'): + if not (line.startswith('\t') or line.startswith(' ')): # start of new package try: key, value = map(str.strip, line.split('=', 1)) From 950abb0189eca4ba34e538d85c568015487c126c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sat, 1 Aug 2015 18:16:47 +0200 Subject: [PATCH 0009/1891] aurinfo: Fix parsing with custom file when running script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- git-interface/aurinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/aurinfo.py b/git-interface/aurinfo.py index dfee3c14..b286316f 100644 --- a/git-interface/aurinfo.py +++ b/git-interface/aurinfo.py @@ -194,7 +194,7 @@ if __name__ == '__main__': action, filename = sys.argv[1:3] if action == 'parse': - aurinfo = ParseAurinfo() + aurinfo = ParseAurinfo(filename) for pkgname in aurinfo.GetPackageNames(): print(">>> merged package: {:s}".format(pkgname)) pp.pprint(aurinfo.GetMergedPackage(pkgname)) From 046d3e25fa6e493045e43ab67ec42a35f36c98f2 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 8 Aug 2015 12:57:23 +0200 Subject: [PATCH 0010/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 322 ++++++++++++++++++++--------------- po/ast.po | 109 ++++++------ po/ca.po | 87 +++++----- po/cs.po | 85 +++++----- po/da.po | 300 +++++++++++++++++---------------- po/de.po | 149 +++++++++++------ po/el.po | 87 +++++----- po/es.po | 162 +++++++++++------- po/es_419.po | 197 +++++++++++++--------- po/fi.po | 176 +++++++++++-------- po/fr.po | 189 +++++++++++++-------- po/he.po | 81 +++++---- po/hr.po | 81 +++++---- po/hu.po | 183 +++++++++++++------- po/it.po | 229 +++++++++++++------------ po/ja.po | 179 +++++++++++++------- po/nb.po | 87 +++++----- po/nl.po | 465 +++++++++++++++++++++++++++++---------------------- po/pl.po | 135 ++++++++------- po/pt_BR.po | 146 ++++++++++------ po/pt_PT.po | 114 +++++++------ po/ro.po | 87 +++++----- po/ru.po | 87 +++++----- po/sk.po | 176 ++++++++++++------- po/sr.po | 91 +++++----- po/tr.po | 93 ++++++----- po/uk.po | 93 ++++++----- po/zh_CN.po | 87 +++++----- po/zh_TW.po | 118 +++++++------ 29 files changed, 2562 insertions(+), 1833 deletions(-) diff --git a/po/ar.po b/po/ar.po index 82f321d4..24c9de49 100644 --- a/po/ar.po +++ b/po/ar.po @@ -1,22 +1,25 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# +# # Translators: +# safa1996alfulaij , 2015 # صفا الفليج , 2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-18 10:15+0200\n" -"PO-Revision-Date: 2015-06-24 20:42+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-25 09:44+0000\n" "Last-Translator: صفا الفليج \n" -"Language-Team: Arabic (http://www.transifex.com/projects/p/aur/language/ar/)\n" +"Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" +"ar/)\n" +"Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ar\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" msgid "Page Not Found" msgstr "لم يُعثر على الصّفحة" @@ -52,11 +55,8 @@ msgstr "استخدم هذه الاستمارة للبحث عن الحسابات msgid "You must log in to view user information." msgstr "عليك الولوج لعرض معلومات المستخدمين." -msgid "Use this form to create an account." -msgstr "استخدم هذه الاستمارة لإنشاء حساب." - msgid "Add Proposal" -msgstr "" +msgstr "أضف رأيًا" msgid "Invalid token for user action." msgstr "" @@ -72,28 +72,28 @@ msgid "Invalid type." msgstr "النّوع غير صالح." msgid "Proposal cannot be empty." -msgstr "" +msgstr "لا يمكن أن يكون الرّأي فارغًا." msgid "New proposal submitted." -msgstr "" +msgstr "قُدّم رأي جديد." msgid "Submit a proposal to vote on." -msgstr "" +msgstr "قدّم رأيًا للتّصويت عليه." msgid "Applicant/TU" msgstr "" msgid "(empty if not applicable)" -msgstr "" +msgstr "(فارغ إن لم ينطبق)" msgid "Type" msgstr "النّوع" msgid "Addition of a TU" -msgstr "" +msgstr "إضافة م‌م" msgid "Removal of a TU" -msgstr "" +msgstr "إزالة م‌م" msgid "Removal of a TU (undeclared inactivity)" msgstr "" @@ -102,13 +102,13 @@ msgid "Amendment of Bylaws" msgstr "" msgid "Proposal" -msgstr "" +msgstr "الرّأي" msgid "Submit" -msgstr "" +msgstr "قدّم" msgid "Manage Co-maintainers" -msgstr "" +msgstr "أدر المصينين المشاركين" msgid "Home" msgstr "الرّئيسيّة" @@ -117,13 +117,17 @@ msgstr "الرّئيسيّة" msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ الموثوقين (م‌م)%s لمعلومات أكثر." +msgstr "" +"مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ " +"الموثوقين (م‌م)%s لمعلومات أكثر." #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "ملفّات PKGBUILD المساعم بها %sيجب%s أن تتبع %sمعايير التّحزيم في آرتش%s وإلا ستُحذف!" +msgstr "" +"ملفّات PKGBUILD المساهم بها %sيجب%s أن تتبع %sمعايير التّحزيم في آرتش%s وإلا " +"ستُحذف!" msgid "Remember to vote for your favourite packages!" msgstr "تذكّر أن تصوّت لحزمك المفضّلة!" @@ -137,7 +141,9 @@ msgstr "إخلاء مسؤوليّة" msgid "" "Unsupported packages are user produced content. Any use of the provided " "files is at your own risk." -msgstr "الحزم غير المدعومة محتوًى قدّمه المستخدمون. أيّ استخدام للملفّات الموفّرة هي على مسؤوليّتك الخاصّة." +msgstr "" +"الحزم غير المدعومة محتوًى قدّمه المستخدمون. أيّ استخدام للملفّات الموفّرة هي على " +"مسؤوليّتك الخاصّة." msgid "Learn more..." msgstr "تعلّم أكثر..." @@ -150,9 +156,11 @@ msgstr "طلبات الحزم" #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة تفاصيل الحزمة:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة " +"تفاصيل الحزمة:" msgid "Orphan Request" msgstr "طلب \"يتيمة\"" @@ -160,16 +168,21 @@ msgstr "طلب \"يتيمة\"" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة كقديمة لوقت طويل." +msgstr "" +"اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة " +"كقديمة لوقت طويل." msgid "Deletion Request" msgstr "طلب الحذف" msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن طلب \"يتيمة\" إن تطلّب الأمر." +msgstr "" +"اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت " +"الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن " +"طلب \"يتيمة\" إن تطلّب الأمر." msgid "Merge Request" msgstr "طلب الدّمج" @@ -177,23 +190,29 @@ msgstr "طلب الدّمج" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "اطل دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو استبدال بحزمة تقسيميّة." +msgstr "" +"اطل دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو " +"استبدال بحزمة تقسيميّة." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." +msgstr "" +"إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. " +"لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." msgid "Submitting Packages" msgstr "تقديم الحزم" #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." +msgstr "" +"غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع " +"قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." msgid "The following SSH fingerprints are used for the AUR:" msgstr "بصمات SSH الآتية مستخدمة في م‌م‌آ:" @@ -203,10 +222,13 @@ msgstr "النّقاش" #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين تكون في %saur-general%s. للنّقاشات المتعلّقة لتطوير واجهة وِب م‌م‌آ، استخدم قائمة %saur-dev%s البريديّة." +msgstr "" +"النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين " +"تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِب م‌م‌آ، استخدم " +"قائمة %saur-dev%s البريديّة." msgid "Bug Reporting" msgstr "الإبلاغ عن العلل" @@ -217,31 +239,34 @@ msgid "" "our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." -msgstr "إن وجدت علّة في واجهة وِب م‌م‌آ، فضلًا املأ تقريرًا بها في %sمتعقّب العلل%s. استخدم المتعقّب للإبلاغ عن العلل في م‌م‌آ %sفقط%s. للإبلاغ عن علل الحزم راسل مديرها أو اترك تعليقًا في صفحة الحزمة المناسبة." +msgstr "" +"إن وجدت علّة في واجهة وِب م‌م‌آ، فضلًا املأ تقريرًا بها في %sمتعقّب العلل%s. استخدم " +"المتعقّب للإبلاغ عن العلل في م‌م‌آ %sفقط%s. للإبلاغ عن علل الحزم راسل مديرها أو " +"اترك تعليقًا في صفحة الحزمة المناسبة." msgid "Package Search" msgstr "ابحث عن حزمة" msgid "Adopt" -msgstr "" +msgstr "تبنّ" msgid "Vote" -msgstr "" +msgstr "صوّت" msgid "UnVote" -msgstr "" +msgstr "أزل التّصويت" msgid "Notify" -msgstr "" +msgstr "الإخطار" msgid "UnNotify" -msgstr "" +msgstr "أزل الإخطار" msgid "Flag" -msgstr "" +msgstr "علّم" msgid "UnFlag" -msgstr "" +msgstr "أزل التّعليم" msgid "Login" msgstr "لِج" @@ -300,7 +325,9 @@ msgid "" "A password reset request was submitted for the account %s associated with " "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." -msgstr "قُدّم طلب تصفير كلمة مرور الحساب %s المرتبط بعنوان بريدك الإلكتروني. إن رغبت بتصغير كلمة مرورك اتبع الوصلة أدناه، وإلّا تجاهل هذه الرّسالة ولن يحدث شيء." +msgstr "" +"قُدّم طلب تصفير كلمة مرور الحساب %s المرتبط بعنوان بريدك الإلكتروني. إن رغبت " +"بتصغير كلمة مرورك اتبع الوصلة أدناه، وإلّا تجاهل هذه الرّسالة ولن يحدث شيء." msgid "Password Reset" msgstr "صفّر كلمة المرور" @@ -325,9 +352,11 @@ msgstr "تابع" #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى قائمة %saur-general%s البريديّة." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى " +"قائمة %saur-general%s البريديّة." msgid "Enter your e-mail address:" msgstr "أدخل عنوان بريدك الإلكترونيّ:" @@ -335,7 +364,7 @@ msgstr "أدخل عنوان بريدك الإلكترونيّ:" msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" +msgstr "لم يُتنازل عن الحزم المحدّدة، افحص مربع تأشير التّأكيد." msgid "Cannot find package to merge votes and comments into." msgstr "تعذّر العثور على الحزمة لدمج التّصويتات والتّعليقات معها." @@ -344,9 +373,8 @@ msgid "Cannot merge a package base with itself." msgstr "لا يمكن الدّمج بلا أساس الحزمة نفسه." msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "" +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "لم تُحذف الحزم المحدّدة، افحص مربع تأشير التّأكيد." msgid "Package Deletion" msgstr "احذف حزمة" @@ -385,19 +413,21 @@ msgstr "تنازل عن الحزمة: %s" #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة ونقل ملكيّتها إلى %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" +msgstr "بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة." msgid "Confirm to disown the package" msgstr "أكّد التّنازل عن الحزمة" @@ -435,13 +465,13 @@ msgid "Confirm package merge" msgstr "أكّد دمج الحزم" msgid "Merge" -msgstr "" +msgstr "دمج" msgid "Only Trusted Users and Developers can merge packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين دمج الحزم." msgid "File Request" -msgstr "" +msgstr "افتح طلبًا" msgid "Close Request" msgstr "أغلق الطّلب" @@ -459,25 +489,31 @@ msgid "Last" msgstr "الأخيرة" msgid "Requests" -msgstr "" +msgstr "الطّلبات" + +msgid "Register" +msgstr "سجّل" + +msgid "Use this form to create an account." +msgstr "استخدم هذه الاستمارة لإنشاء حساب." msgid "Trusted User" msgstr "مستخدم موثوق" msgid "Could not retrieve proposal details." -msgstr "" +msgstr "تعذّر استرجاع تفاصيل الرّأي." msgid "Voting is closed for this proposal." -msgstr "" +msgstr "أُغلق التّصويت على هذا الرّأي." msgid "Only Trusted Users are allowed to vote." msgstr "فقط المستخدمين الموثوقين مسموح لهم بالتّصويت." msgid "You cannot vote in an proposal about you." -msgstr "" +msgstr "لا يمكنك التّصويت على رأي عنك." msgid "You've already voted for this proposal." -msgstr "" +msgstr "لقد صوّتّ على هذا الرّأي بالفعل." msgid "Vote ID not valid." msgstr "معرّف التّصويت غير صالح." @@ -494,7 +530,9 @@ msgstr "المصوّتون" msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك" +msgstr "" +"تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " +"المتكرّرة. آسفون لإزاعجك" msgid "Missing User ID" msgstr "معرّف المستخدم ناقص" @@ -555,7 +593,9 @@ msgid "" "Welcome to %s! In order to set an initial password for your new account, " "please click the link below. If the link does not work try copying and " "pasting it into your browser." -msgstr "مرحبًا بك في %s! لتعيين كلمة مرور أوليّة لحسابك الجديد، فضلًأ انقر الوصلة أدناه. إن لم تعمل الوصلة جرّب النّسخ واللصق في متصفّحك." +msgstr "" +"مرحبًا بك في %s! لتعيين كلمة مرور أوليّة لحسابك الجديد، فضلًأ انقر الوصلة " +"أدناه. إن لم تعمل الوصلة جرّب النّسخ واللصق في متصفّحك." msgid "A password reset key has been sent to your e-mail address." msgstr "مفتاح تصفير كلمة المرور أُرسل إلى عنوان بريدك الإلكترونيّ." @@ -571,7 +611,9 @@ msgstr "عُدّل الحساب %s%s%s بنجاح." msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك." +msgstr "" +"استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " +"المتكرّرة. آسفون لإزاعجك." msgid "Account suspended" msgstr "عُلّق الحساب" @@ -581,7 +623,10 @@ msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من صفحة %sصفّر كلمة المرور%s." +msgstr "" +"لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد " +"الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من " +"صفحة %sصفّر كلمة المرور%s." msgid "Bad username or password." msgstr "اسم مستخدم أو كلمة مرور سيئّة." @@ -590,7 +635,7 @@ msgid "An error occurred trying to generate a user session." msgstr "حدث خطأ أثناء توليد جلسة مستخدم." msgid "Invalid e-mail and reset key combination." -msgstr "" +msgstr "البريد الإلكترونيّ وتجميعة مفاتيح التّصفير غير صالحة." msgid "None" msgstr "بلا" @@ -621,7 +666,7 @@ msgid "You did not select any packages to unflag." msgstr "لم تحدّد أيّ حزم لإزالة تعليمها." msgid "The selected packages have been unflagged." -msgstr "أُزيل تعليم الحزم المحدّدة." +msgstr "أزثيل تعليم الحزم المحدّدة." msgid "You do not have permission to delete packages." msgstr "لا صلاحيّة لديك لحذف الحزم." @@ -645,10 +690,10 @@ msgid "You did not select any packages to disown." msgstr "لم تحدّد أيّ حزم للتّنازل عنها." msgid "The selected packages have been adopted." -msgstr "" +msgstr "تُبنّيت الحزم المحدّدة." msgid "The selected packages have been disowned." -msgstr "" +msgstr "تُنوزل عن الحزم المحدّدة." msgid "You must be logged in before you can vote for packages." msgstr "عليك الولوج قبل التّصويت للحزم." @@ -663,18 +708,18 @@ msgid "Your votes have been removed from the selected packages." msgstr "أُزيلت تصويتاتك من الحزم المحدّدة." msgid "Your votes have been cast for the selected packages." -msgstr "" +msgstr "أُدليت تصويتاتك على الحزم المحدّدة." msgid "Couldn't add to notification list." msgstr "تعذّرت الإضافة إلى قائمة الإخطارات." #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "" +msgstr "أُضفت إلى قائمة إخطار التّعليقات لِـ %s." #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "" +msgstr "أُزلت من قائمة إخطار التّعليقات لِـ %s." msgid "You must be logged in before you can edit package information." msgstr "عليك الولوج قبل تحرير معلومات الحزم." @@ -695,20 +740,20 @@ msgid "The package base keywords have been updated." msgstr "حُدّثت كلمات أساس الحزمة المفتاحيّة." msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "ليس مسموحًا لك بإدارة مصيني أساس الحزمة هذا المشاركين." #, php-format msgid "Invalid user name: %s" msgstr "اسم مستخدم غير صالح: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "حُدّث مصيني أساس الحزمة المشاركين." msgid "View packages details for" msgstr "اعرض تفاصيل حزمة" msgid "You must be logged in to file package requests." -msgstr "" +msgstr "عليك الولوج لفتح طلبات حزم." msgid "Invalid name: only lowercase letters are allowed." msgstr "اسم غير صالح: فقط الأحرف بالحالة الصغيرة مسموح بها." @@ -746,13 +791,13 @@ msgid "Account Type" msgstr "نوع الحساب" msgid "User" -msgstr "" +msgstr "مستخدم" msgid "Developer" -msgstr "" +msgstr "مطوّر" msgid "Trusted User & Developer" -msgstr "" +msgstr "مستخدم موثوق ومطوّر" msgid "Email Address" msgstr "البريد الإلكترونيّ" @@ -767,7 +812,7 @@ msgid "PGP Key Fingerprint" msgstr "بصمة مفتاح PGP" msgid "Status" -msgstr "" +msgstr "الحالة" msgid "Inactive since" msgstr "غير نشط منذ" @@ -792,7 +837,7 @@ msgid "Click %shere%s if you want to permanently delete this account." msgstr "انقر %sهنا%s إن أردت حذف هذا الحساب نهائيًّا." msgid "required" -msgstr "" +msgstr "مطلوب" msgid "Normal user" msgstr "مستخدم عاديّ" @@ -813,8 +858,8 @@ msgid "Language" msgstr "اللغة" msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "المعلومات الآتية مطلوبة فقط إن أردت تقديم حزم إلى مستودع مستخدمي آرتش." msgid "SSH Public Key" @@ -852,12 +897,12 @@ msgstr "لا نتائج أخرى لعرضها." #, php-format msgid "Manage Co-maintainers: %s" -msgstr "" +msgstr "أدر المصينين المشاركين: %s" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" +msgstr "استخدم هذه الاستمارة لإضافة مصينين مشاركين لِـ %s%s%s (اسم في كلّ سطر):" msgid "Users" msgstr "المستخدمون" @@ -871,15 +916,6 @@ msgstr "حزمي" msgid " My Account" msgstr "حسابي" -msgid "Register" -msgstr "سجّل" - -msgid "unknown" -msgstr "" - -msgid "Package Base Details" -msgstr "تفاصيل أساس الحزمة" - msgid "Package Actions" msgstr "إجراءات الحزمة" @@ -905,7 +941,7 @@ msgid "Unflag package" msgstr "أزل تعليم الحزمة" msgid "Remove vote" -msgstr "" +msgstr "أزل التّصويت" msgid "Vote for this package" msgstr "صوّت لهذه الحزمة" @@ -917,17 +953,17 @@ msgid "Notify of new comments" msgstr "أخطرني بالتّعليقات الجديدة" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "أدر المصينين المشاركين" #, php-format msgid "%d pending request" msgid_plural "%d pending requests" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" +msgstr[0] "لا طلبات منتظرة" +msgstr[1] "طلب واحد منتظر" +msgstr[2] "طلبان منتظران" +msgstr[3] "%d طلبات منتظرة" +msgstr[4] "%d طلبًا منتظرًا" +msgstr[5] "%d طلب منتظر" msgid "Delete Package" msgstr "احذف الحزمة" @@ -938,11 +974,17 @@ msgstr "ادمج الحزم" msgid "Adopt Package" msgstr "تبنّ الحزمة" +msgid "unknown" +msgstr "مجهول" + +msgid "Package Base Details" +msgstr "تفاصيل أساس الحزمة" + msgid "Git Clone URL" msgstr "عنوان غِت للاستنساخ" msgid "read-only" -msgstr "" +msgstr "للقراءة فقط" msgid "Keywords" msgstr "الكلمات المفتاحيّة" @@ -1034,7 +1076,7 @@ msgstr "المصادر" #, php-format msgid "Close Request: %s" -msgstr "" +msgstr "أغلق الطّلب: %s" #, php-format msgid "Use this form to close the request for package base %s%s%s." @@ -1046,7 +1088,8 @@ msgstr "ملاحظة" msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." +msgstr "" +"يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." msgid "Reason" msgstr "السّبب" @@ -1062,13 +1105,14 @@ msgstr "التّعليقات" #, php-format msgid "File Request: %s" -msgstr "" +msgstr "افتح طلبًا: %s" #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +"استخدم هذه الاستمارة لفتح طلب لأساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" msgid "Request type" msgstr "نوع الطّلب" @@ -1085,12 +1129,12 @@ msgstr "ادمج مع" #, php-format msgid "%d package request found." msgid_plural "%d package requests found." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" +msgstr[0] "لم تُعثر على أيّة طلبات حزم." +msgstr[1] "عُثر على طلب حزمة واحد." +msgstr[2] "عُثر على طلبا حزم." +msgstr[3] "عُثر على %d طلبات حزم." +msgstr[4] "عُثر على %d طلب حزمة." +msgstr[5] "عُثر على %d طلب حزمة." #, php-format msgid "Page %d of %d." @@ -1100,7 +1144,7 @@ msgid "Package" msgstr "الحزم" msgid "Filed by" -msgstr "" +msgstr "فتحه:" msgid "Date" msgstr "التّاريخ" @@ -1112,12 +1156,12 @@ msgstr "" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" +msgstr[0] "بقي بضع دقائق" +msgstr[1] "بقي حوالي ساعة" +msgstr[2] "بقي حوالي ساعتين" +msgstr[3] "بقي حوالي %d ساعات" +msgstr[4] "بقي حوالي %d ساعةً" +msgstr[5] "بقي حوالي %d ساعة" msgid "<1 hour left" msgstr "بقيت أقلّ من ساعة" @@ -1162,7 +1206,7 @@ msgid "Popularity" msgstr "الشّعبيّة" msgid "Voted" -msgstr "" +msgstr "مصوّت عليها" msgid "Age" msgstr "العمر" @@ -1180,7 +1224,7 @@ msgid "Search by" msgstr "ابحث حسب" msgid "Out of Date" -msgstr "قديمة" +msgstr "القديمة" msgid "Sort by" msgstr "افرز حسب" @@ -1206,12 +1250,12 @@ msgstr "لا حزم طابقت معايير بحثك." #, php-format msgid "%d package found." msgid_plural "%d packages found." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" -msgstr[4] "" -msgstr[5] "" +msgstr[0] "لم يُعثر على أيّة حزمة." +msgstr[1] "عُثر على حزمة واحدة." +msgstr[2] "عُثر على حزمتين." +msgstr[3] "عُثر على %d حزم." +msgstr[4] "عُثر على %d حزمةً." +msgstr[5] "عُثر على %d حزمة." msgid "Version" msgstr "الإصدارة" @@ -1285,20 +1329,20 @@ msgid "My Statistics" msgstr "إحصائيّاتي" msgid "Packages in unsupported" -msgstr "" +msgstr "الحزم في \"غير مدعوم\"" msgid "Proposal Details" -msgstr "" +msgstr "تفاصيل الرّأي" msgid "This vote is still running." msgstr "ما زال هذا التّصويت قائمًا." #, php-format msgid "Submitted: %s by %s" -msgstr "" +msgstr "قدّمه (في %s) ‏%s" msgid "End" -msgstr "" +msgstr "النّهاية" msgid "Result" msgstr "النّتيجة" @@ -1307,25 +1351,25 @@ msgid "No" msgstr "لا" msgid "Abstain" -msgstr "" +msgstr "الامتناع" msgid "Total" msgstr "المجموع" msgid "Participation" -msgstr "" +msgstr "المشاركة" msgid "Last Votes by TU" -msgstr "" +msgstr "آخر التّصويتات لِـ م‌م" msgid "Last vote" -msgstr "" +msgstr "آخر تصويت" msgid "No results found." msgstr "لم يُعثر على أيّ نتيجة." msgid "Start" -msgstr "" +msgstr "البداية" msgid "Back" -msgstr "" +msgstr "السّابق" diff --git a/po/ast.po b/po/ast.po index 1a5c86de..bf674e74 100644 --- a/po/ast.po +++ b/po/ast.po @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Asturian (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-07-06 14:08+0000\n" +"Last-Translator: enolp \n" +"Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" "ast/)\n" "Language: ast\n" "MIME-Version: 1.0\n" @@ -28,7 +28,7 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Perdón, la páxina que pidisti nun esiste." msgid "Service Unavailable" -msgstr "" +msgstr "Serviciu non disponible" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." @@ -55,9 +55,6 @@ msgstr "Usa esti formulariu pa guetar cuentes esistentes." msgid "You must log in to view user information." msgstr "Tienes d'aniciar sesión pa ver la información del usuariu." -msgid "Use this form to create an account." -msgstr "Usa esti formulariu pa crear una cuenta." - msgid "Add Proposal" msgstr "Amestar propuesta" @@ -148,11 +145,14 @@ msgstr "" "Los paquetes ensin sofitu son producíos polos usuarios. Cualesquier usu de " "los ficheros apurríos ta sol to propiu riesgu." +msgid "Learn more..." +msgstr "Llei más..." + msgid "Support" -msgstr "" +msgstr "Sofitu" msgid "Package Requests" -msgstr "" +msgstr "Solicitúes de paquetes" #, php-format msgid "" @@ -161,7 +161,7 @@ msgid "" msgstr "" msgid "Orphan Request" -msgstr "" +msgstr "Solicitú güérfana" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " @@ -169,7 +169,7 @@ msgid "" msgstr "" msgid "Deletion Request" -msgstr "" +msgstr "Solicitú de desaniciu" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " @@ -178,7 +178,7 @@ msgid "" msgstr "" msgid "Merge Request" -msgstr "" +msgstr "Solicitú de desanciu" msgid "" "Request a package to be merged into another one. Can be used when a package " @@ -191,6 +191,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Discutiniu" @@ -457,6 +470,12 @@ msgstr "" msgid "Requests" msgstr "Solicitúes" +msgid "Register" +msgstr "Rexistrase" + +msgid "Use this form to create an account." +msgstr "Usa esti formulariu pa crear una cuenta." + msgid "Trusted User" msgstr "" @@ -479,13 +498,13 @@ msgid "Vote ID not valid." msgstr "Nun ye válida la ID del votu." msgid "Current Votes" -msgstr "" +msgstr "Votos actuales" msgid "Past Votes" -msgstr "" +msgstr "Votos pasaos" msgid "Voters" -msgstr "" +msgstr "Votantes" msgid "" "Account registration has been disabled for your IP address, probably due to " @@ -591,6 +610,10 @@ msgstr "" msgid "None" msgstr "" +#, php-format +msgid "View account information for %s" +msgstr "" + msgid "Error retrieving package details." msgstr "" @@ -680,17 +703,11 @@ msgstr "El comentariu amestóse." msgid "You are not allowed to delete this comment." msgstr "Nun tienes permisu pa desaniciar esti comentariu." -msgid "Missing category ID." -msgstr "Falta la ID de la estaya." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "ID d'estaya non válida" - -msgid "You are not allowed to change this package category." -msgstr "Nun tienes permisu pa camudar la estaya d'esti paquete." - -msgid "Package category changed." -msgstr "La estaya'l paquete camudó." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -870,15 +887,6 @@ msgstr "Los mios paquetes" msgid " My Account" msgstr "La mio cuenta" -msgid "Register" -msgstr "Rexistrase" - -msgid "unknown" -msgstr "Desconocíu" - -msgid "Package Base Details" -msgstr "Detalles del paquete base" - msgid "Package Actions" msgstr "Aiciones de paquete" @@ -933,20 +941,22 @@ msgstr "" msgid "Adopt Package" msgstr "" +msgid "unknown" +msgstr "Desconocíu" + +msgid "Package Base Details" +msgstr "Detalles del paquete base" + msgid "Git Clone URL" msgstr "URL pa clonar con Git" -msgid "Category" -msgstr "Estaya" - -msgid "Change category" -msgstr "Camudar estaya" - -msgid "Submitter" +msgid "read-only" msgstr "" -#, php-format -msgid "View account information for %s" +msgid "Keywords" +msgstr "Pallabres clave" + +msgid "Submitter" msgstr "" msgid "Maintainer" @@ -1169,15 +1179,9 @@ msgstr "Descendente" msgid "Enter search criteria" msgstr "" -msgid "Any" -msgstr "" - msgid "Search by" msgstr "Guetar per" -msgid "Keywords" -msgstr "Pallabres clave" - msgid "Out of Date" msgstr "Ensin anovar" @@ -1211,6 +1215,11 @@ msgstr[1] "Alcontráronse %d paquetes" msgid "Version" msgstr "Versión" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Sí" diff --git a/po/ca.po b/po/ca.po index ed424f2d..69fb0c4e 100644 --- a/po/ca.po +++ b/po/ca.po @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Catalan (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" "ca/)\n" "Language: ca\n" "MIME-Version: 1.0\n" @@ -55,9 +55,6 @@ msgstr "Utilitzeu aquest formulari per a cercar comptes existents." msgid "You must log in to view user information." msgstr "Heu d'identificar-vos per a veure la inforació de l'usuari." -msgid "Use this form to create an account." -msgstr "Utilitzeu aquest formulari per a crear un compte." - msgid "Add Proposal" msgstr "Afegeix proposta" @@ -148,6 +145,9 @@ msgstr "" "Els paquets sense suport són creats per diferents usuaris. Qualsevol ús " "d'aquests és sempre sota el seu propi risc." +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -191,6 +191,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Discussió" @@ -461,6 +474,12 @@ msgstr "Darrer" msgid "Requests" msgstr "" +msgid "Register" +msgstr "Registrar-se" + +msgid "Use this form to create an account." +msgstr "Utilitzeu aquest formulari per a crear un compte." + msgid "Trusted User" msgstr "Usuari de Confiança" @@ -609,6 +628,10 @@ msgstr "" msgid "None" msgstr "Res" +#, php-format +msgid "View account information for %s" +msgstr "Veure l'informació del compte per %s" + msgid "Error retrieving package details." msgstr "No s'han pogut obtenir els detalls del paquet." @@ -698,17 +721,11 @@ msgstr "S'ha esborrat el comentari." msgid "You are not allowed to delete this comment." msgstr "No esteu autoritzat per esborrar aquest comentari." -msgid "Missing category ID." -msgstr "Manca la identificació de categoria." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "L'identificador de la categoria no és vàlid." - -msgid "You are not allowed to change this package category." -msgstr "No esteu autoritzats a canviar la categoria del paquet." - -msgid "Package category changed." -msgstr "Ha canviat la categoria del paquet." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -887,15 +904,6 @@ msgstr "Els meus paquets" msgid " My Account" msgstr "El meu Compte" -msgid "Register" -msgstr "Registrar-se" - -msgid "unknown" -msgstr "desconegut" - -msgid "Package Base Details" -msgstr "" - msgid "Package Actions" msgstr "Accions Paquet" @@ -950,22 +958,24 @@ msgstr "Fusionar el paquet" msgid "Adopt Package" msgstr "Adoptar Paquet" +msgid "unknown" +msgstr "desconegut" + +msgid "Package Base Details" +msgstr "" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Categoria" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "Canvi de categoria" +msgid "Keywords" +msgstr "Paraules Clau" msgid "Submitter" msgstr "Remitent" -#, php-format -msgid "View account information for %s" -msgstr "Veure l'informació del compte per %s" - msgid "Maintainer" msgstr "Mantenidor" @@ -1184,15 +1194,9 @@ msgstr "Descendent" msgid "Enter search criteria" msgstr "Introdueixi in criteri de cerca" -msgid "Any" -msgstr "Cap" - msgid "Search by" msgstr "Cerca per" -msgid "Keywords" -msgstr "Paraules Clau" - msgid "Out of Date" msgstr "No-Actualitzat" @@ -1226,6 +1230,11 @@ msgstr[1] "" msgid "Version" msgstr "Versió" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Sí" diff --git a/po/cs.po b/po/cs.po index 933bfb72..7b97dd0d 100644 --- a/po/cs.po +++ b/po/cs.po @@ -11,10 +11,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Czech (http://www.transifex.com/projects/p/aur/language/cs/)\n" +"Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -55,9 +55,6 @@ msgstr "Pro vyhledání existujících účtů použíte tento formulář." msgid "You must log in to view user information." msgstr "Musíte se přihlásit, pro zobrazení informací o uživateli." -msgid "Use this form to create an account." -msgstr "Použíte tento formulář k založení účtu." - msgid "Add Proposal" msgstr "Přidat návrh" @@ -144,6 +141,9 @@ msgid "" "files is at your own risk." msgstr "" +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -187,6 +187,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Diskuze" @@ -451,6 +464,12 @@ msgstr "Poslední" msgid "Requests" msgstr "Požadavky" +msgid "Register" +msgstr "Registrovat" + +msgid "Use this form to create an account." +msgstr "Použíte tento formulář k založení účtu." + msgid "Trusted User" msgstr "Důvěryhodný uživatel" @@ -585,6 +604,10 @@ msgstr "" msgid "None" msgstr "" +#, php-format +msgid "View account information for %s" +msgstr "" + msgid "Error retrieving package details." msgstr "Došlo k chybě při získávání detailů o balíčku." @@ -675,16 +698,10 @@ msgstr "Komentář byl smazán." msgid "You are not allowed to delete this comment." msgstr "Nemáte oprávnění pro smazání tohoto komentáře." -msgid "Missing category ID." +msgid "You are not allowed to edit the keywords of this package base." msgstr "" -msgid "Invalid category ID." -msgstr "Chybné ID kategorie." - -msgid "You are not allowed to change this package category." -msgstr "" - -msgid "Package category changed." +msgid "The package base keywords have been updated." msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." @@ -864,15 +881,6 @@ msgstr "Moje balíčky" msgid " My Account" msgstr "Můj účet" -msgid "Register" -msgstr "Registrovat" - -msgid "unknown" -msgstr "neznámý" - -msgid "Package Base Details" -msgstr "" - msgid "Package Actions" msgstr "" @@ -928,20 +936,22 @@ msgstr "" msgid "Adopt Package" msgstr "Adoptovat balíček" +msgid "unknown" +msgstr "neznámý" + +msgid "Package Base Details" +msgstr "" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Kategorie" - -msgid "Change category" -msgstr "Upravit kategorii" - -msgid "Submitter" +msgid "read-only" msgstr "" -#, php-format -msgid "View account information for %s" +msgid "Keywords" +msgstr "Klíčová slova" + +msgid "Submitter" msgstr "" msgid "Maintainer" @@ -1164,15 +1174,9 @@ msgstr "Sestupně" msgid "Enter search criteria" msgstr "Zadat kritéria vyhledávání" -msgid "Any" -msgstr "jakákoliv" - msgid "Search by" msgstr "Vyhledat dle" -msgid "Keywords" -msgstr "Klíčová slova" - msgid "Out of Date" msgstr "Zastaralé" @@ -1207,6 +1211,11 @@ msgstr[2] "Nalezeno %d balíčků." msgid "Version" msgstr "Verze" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Ano" diff --git a/po/da.po b/po/da.po index b43917c7..f514488f 100644 --- a/po/da.po +++ b/po/da.po @@ -3,15 +3,16 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# Louis Tim Larsen , 2015 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Danish (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" "da/)\n" "Language: da\n" "MIME-Version: 1.0\n" @@ -20,20 +21,20 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Page Not Found" -msgstr "" +msgstr "Siden blev ikke fundet" msgid "Sorry, the page you've requested does not exist." -msgstr "" +msgstr "Beklager, den forspurgte side findes ikke." msgid "Service Unavailable" -msgstr "" +msgstr "Service utilgængelig" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" msgid "Account" -msgstr "" +msgstr "Konto" msgid "Accounts" msgstr "Konti" @@ -53,9 +54,6 @@ msgstr "Brug denne formular til at søge i eksisterende konti." msgid "You must log in to view user information." msgstr "Du skal være logget ind for at se brugerinformation." -msgid "Use this form to create an account." -msgstr "Brug denne formular til at oprette en konto." - msgid "Add Proposal" msgstr "" @@ -140,6 +138,9 @@ msgid "" "files is at your own risk." msgstr "" +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -183,6 +184,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Diskussion" @@ -205,10 +219,10 @@ msgid "" msgstr "" msgid "Package Search" -msgstr "" +msgstr "Pakkesøgning" msgid "Adopt" -msgstr "" +msgstr "Adopter" msgid "Vote" msgstr "Stem" @@ -251,7 +265,7 @@ msgid "Remember me" msgstr "Husk mig" msgid "Forgot Password" -msgstr "" +msgstr "Glemt adgangskode" #, php-format msgid "" @@ -278,7 +292,7 @@ msgid "Your password must be at least %s characters." msgstr "Din adgangskode skal være mindst %s tegn." msgid "Invalid e-mail." -msgstr "" +msgstr "Ugyldig mail." #, php-format msgid "" @@ -288,25 +302,25 @@ msgid "" msgstr "" msgid "Password Reset" -msgstr "" +msgstr "Nulstil adgangskode" msgid "Check your e-mail for the confirmation link." -msgstr "" +msgstr "Tjek din mail for bekræftelses-link." msgid "Your password has been reset successfully." -msgstr "" +msgstr "Din adgangskode blev nulstillet." msgid "Confirm your e-mail address:" -msgstr "" +msgstr "Bekræft din nye mail-adresse:" msgid "Enter your new password:" -msgstr "" +msgstr "Indtast din nye adgangskode:" msgid "Confirm your new password:" -msgstr "" +msgstr "Bekræft din nye adgangskode:" msgid "Continue" -msgstr "" +msgstr "Forsæt" #, php-format msgid "" @@ -315,7 +329,7 @@ msgid "" msgstr "" msgid "Enter your e-mail address:" -msgstr "" +msgstr "Indtast din mail-adresse:" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -337,7 +351,7 @@ msgstr "" #, php-format msgid "Delete Package: %s" -msgstr "" +msgstr "Slet pakke: %s" #, php-format msgid "" @@ -346,19 +360,19 @@ msgid "" msgstr "" msgid "Deletion of a package is permanent. " -msgstr "" +msgstr "Sletning af en pakke er permanent" msgid "Select the checkbox to confirm action." msgstr "" msgid "Confirm package deletion" -msgstr "" +msgstr "Bekræft sletning af pakke" msgid "Delete" -msgstr "" +msgstr "Slet" msgid "Only Trusted Users and Developers can delete packages." -msgstr "" +msgstr "Kun betroede brugere og udviklere kan slette pakker." msgid "Disown Package" msgstr "" @@ -404,7 +418,7 @@ msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" msgid "The following packages will be deleted: " -msgstr "" +msgstr "Følgende pakker vil blive slettet:" msgid "Once the package has been merged it cannot be reversed. " msgstr "" @@ -425,25 +439,31 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "" msgid "File Request" -msgstr "" +msgstr "Udfyld forspørgsel" msgid "Close Request" -msgstr "" +msgstr "Luk forspørgsel" msgid "First" -msgstr "" +msgstr "Første" msgid "Previous" -msgstr "" +msgstr "Tidligere" msgid "Next" msgstr "Næste" msgid "Last" -msgstr "" +msgstr "Sidste" msgid "Requests" -msgstr "" +msgstr "Forspørgelser" + +msgid "Register" +msgstr "Register" + +msgid "Use this form to create an account." +msgstr "Brug denne formular til at oprette en konto." msgid "Trusted User" msgstr "Betroet bruger (TU)" @@ -558,7 +578,7 @@ msgid "" msgstr "" msgid "Account suspended" -msgstr "" +msgstr "Konto suspenderet" #, php-format msgid "" @@ -568,7 +588,7 @@ msgid "" msgstr "" msgid "Bad username or password." -msgstr "" +msgstr "Forkert brugernavn eller adgangskode" msgid "An error occurred trying to generate a user session." msgstr "" @@ -577,6 +597,10 @@ msgid "Invalid e-mail and reset key combination." msgstr "" msgid "None" +msgstr "Ingen" + +#, php-format +msgid "View account information for %s" msgstr "" msgid "Error retrieving package details." @@ -604,7 +628,7 @@ msgid "The selected packages have been unflagged." msgstr "De valgte pakker er afmarkeret." msgid "You do not have permission to delete packages." -msgstr "" +msgstr "Du har ikke tilladelse til, at slette pakker." msgid "You did not select any packages to delete." msgstr "Du har ikke valgt nogle pakker at slette." @@ -668,16 +692,10 @@ msgstr "Kommentaren er slettet." msgid "You are not allowed to delete this comment." msgstr "Du har ikke rettigheder til at slette denne kommentar." -msgid "Missing category ID." +msgid "You are not allowed to edit the keywords of this package base." msgstr "" -msgid "Invalid category ID." -msgstr "Ugyldigt kategori ID." - -msgid "You are not allowed to change this package category." -msgstr "" - -msgid "Package category changed." +msgid "The package base keywords have been updated." msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." @@ -685,13 +703,13 @@ msgstr "" #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Ugyldigt brugernavn: %s" msgid "The package base co-maintainers have been updated." msgstr "" msgid "View packages details for" -msgstr "" +msgstr "Vis pakkedeltaljer for" msgid "You must be logged in to file package requests." msgstr "" @@ -709,7 +727,7 @@ msgid "Added request successfully." msgstr "" msgid "Invalid reason." -msgstr "" +msgstr "Ugyldig årsag" msgid "Only TUs and developers can close requests." msgstr "" @@ -726,7 +744,7 @@ msgid "%sWARNING%s: This action cannot be undone." msgstr "" msgid "Confirm deletion" -msgstr "" +msgstr "Bekræft sletning" msgid "Account Type" msgstr "Kontotype" @@ -738,7 +756,7 @@ msgid "Developer" msgstr "Udvikler" msgid "Trusted User & Developer" -msgstr "" +msgstr "Betroet bruger og udvikler" msgid "Email Address" msgstr "E-mail adresse" @@ -756,13 +774,13 @@ msgid "Status" msgstr "Status" msgid "Inactive since" -msgstr "" +msgstr "Inaktiv siden" msgid "Active" msgstr "Aktiv" msgid "Last Login" -msgstr "" +msgstr "Sidste login" msgid "Never" msgstr "Aldrig" @@ -790,7 +808,7 @@ msgid "Account Suspended" msgstr "Konto suspenderet" msgid "Inactive" -msgstr "" +msgstr "Inaktiv" msgid "Re-type password" msgstr "Bekræft adgangskode" @@ -846,34 +864,25 @@ msgid "" msgstr "" msgid "Users" -msgstr "" +msgstr "Brugere" msgid "Save" -msgstr "" +msgstr "Gem" msgid "My Packages" msgstr "Mine pakker" msgid " My Account" -msgstr "" - -msgid "Register" -msgstr "" - -msgid "unknown" -msgstr "" - -msgid "Package Base Details" -msgstr "" +msgstr "Min konto" msgid "Package Actions" msgstr "" msgid "View PKGBUILD" -msgstr "" +msgstr "Vis PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Vis ændringer" msgid "Download snapshot" msgstr "" @@ -891,13 +900,13 @@ msgid "Unflag package" msgstr "" msgid "Remove vote" -msgstr "" +msgstr "Fjern stemme" msgid "Vote for this package" -msgstr "" +msgstr "Stem på denne pakke" msgid "Disable notifications" -msgstr "" +msgstr "Deaktiver notifikationer" msgid "Notify of new comments" msgstr "" @@ -912,72 +921,74 @@ msgstr[0] "" msgstr[1] "" msgid "Delete Package" -msgstr "" +msgstr "Slet pakke" msgid "Merge Package" msgstr "" msgid "Adopt Package" +msgstr "Adopter pakke" + +msgid "unknown" +msgstr "ukendt" + +msgid "Package Base Details" msgstr "" msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Kategori" - -msgid "Change category" +msgid "read-only" msgstr "" +msgid "Keywords" +msgstr "Nøgleord" + msgid "Submitter" -msgstr "" - -#, php-format -msgid "View account information for %s" -msgstr "" +msgstr "Indsender" msgid "Maintainer" msgstr "Ejer" msgid "Last Packager" -msgstr "" +msgstr "Sidste pakker" msgid "Votes" msgstr "Stemmer" msgid "First Submitted" -msgstr "" +msgstr "Først tilføjet" msgid "Last Updated" -msgstr "" +msgstr "Sidst opdateret" msgid "Add Comment" -msgstr "" +msgstr "Tilføj kommentar" msgid "Comment has been added." -msgstr "" +msgstr "Kommentaren blev tilføjet" msgid "View all comments" -msgstr "" +msgstr "Vis alle kommentarer" msgid "Latest Comments" -msgstr "" +msgstr "Seneste kommentarer" msgid "Delete comment" msgstr "Slet kommentar" #, php-format msgid "Comment by %s" -msgstr "" +msgstr "Kommentar fra %s" msgid "Anonymous comment" -msgstr "" +msgstr "Anonym kommentar" msgid "deleted" -msgstr "" +msgstr "slettet" msgid "All comments" -msgstr "" +msgstr "Alle kommentarer" msgid "Package Details" msgstr "Detaljer om pakken" @@ -992,22 +1003,22 @@ msgid "Upstream URL" msgstr "" msgid "Visit the website for" -msgstr "" +msgstr "Besøg hjemmesiden for" msgid "Licenses" -msgstr "" +msgstr "Licenser" msgid "Groups" -msgstr "" +msgstr "Grupper" msgid "Conflicts" -msgstr "" +msgstr "Konflikter" msgid "Provides" -msgstr "" +msgstr "Tilbyder" msgid "Replaces" -msgstr "" +msgstr "Erstatter" msgid "Dependencies" msgstr "Afhængigheder" @@ -1016,11 +1027,11 @@ msgid "Required by" msgstr "Påkrævet af" msgid "Sources" -msgstr "" +msgstr "Kilder" #, php-format msgid "Close Request: %s" -msgstr "" +msgstr "Luk forspørgsel: %s" #, php-format msgid "Use this form to close the request for package base %s%s%s." @@ -1038,13 +1049,13 @@ msgid "Reason" msgstr "" msgid "Accepted" -msgstr "" +msgstr "Accepteret" msgid "Rejected" -msgstr "" +msgstr "Afvist" msgid "Comments" -msgstr "" +msgstr "Kommentarer" #, php-format msgid "File Request: %s" @@ -1060,10 +1071,10 @@ msgid "Request type" msgstr "" msgid "Deletion" -msgstr "" +msgstr "Sletning" msgid "Orphan" -msgstr "" +msgstr "Forladt" msgid "Merge into" msgstr "" @@ -1076,56 +1087,56 @@ msgstr[1] "" #, php-format msgid "Page %d of %d." -msgstr "" +msgstr "Side %d af %d." msgid "Package" -msgstr "" +msgstr "Pakke" msgid "Filed by" -msgstr "" +msgstr "Udfyldt af" msgid "Date" -msgstr "" +msgstr "Dato" #, php-format msgid "~%d days left" -msgstr "" +msgstr "~%d dage tilbage" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "~%d time tilbage" +msgstr[1] "~%d timer tilbage" msgid "<1 hour left" -msgstr "" +msgstr "<1 time tilbage" msgid "Accept" -msgstr "" +msgstr "Accepter" msgid "Locked" -msgstr "" +msgstr "Låst" msgid "Close" -msgstr "" +msgstr "Luk" msgid "Closed" -msgstr "" +msgstr "Lukket" msgid "Name, Description" -msgstr "" +msgstr "Navn, beskrivelse" msgid "Name Only" -msgstr "" +msgstr "Kun navn" msgid "Exact Name" -msgstr "" +msgstr "Præcist navn" msgid "Exact Package Base" msgstr "" msgid "All" -msgstr "" +msgstr "Alle" msgid "Flagged" msgstr "" @@ -1137,13 +1148,13 @@ msgid "Name" msgstr "Navn" msgid "Popularity" -msgstr "" +msgstr "Popularitet" msgid "Voted" msgstr "Stemt" msgid "Age" -msgstr "" +msgstr "Alder" msgid "Ascending" msgstr "" @@ -1154,17 +1165,11 @@ msgstr "" msgid "Enter search criteria" msgstr "" -msgid "Any" -msgstr "Alle" - msgid "Search by" msgstr "Søg efter" -msgid "Keywords" -msgstr "" - msgid "Out of Date" -msgstr "" +msgstr "Forældet" msgid "Sort by" msgstr "Sortér efter" @@ -1190,10 +1195,15 @@ msgstr "Ingen pakker opfylder dine søgekriterier." #, php-format msgid "%d package found." msgid_plural "%d packages found." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d pakke fundet." +msgstr[1] "%d pakker fundet." msgid "Version" +msgstr "Version" + +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." msgstr "" msgid "Yes" @@ -1221,7 +1231,7 @@ msgid "Delete Packages" msgstr "Slet pakker" msgid "Confirm" -msgstr "" +msgstr "Forsæt" msgid "Any type" msgstr "Vilkårlig type" @@ -1230,34 +1240,34 @@ msgid "Search" msgstr "Søg" msgid "Statistics" -msgstr "" +msgstr "Statistikker" msgid "Orphan Packages" -msgstr "" +msgstr "Forladte pakker" msgid "Packages added in the past 7 days" -msgstr "" +msgstr "Pakker tilføjet indenfor de seneste 7 dage" msgid "Packages updated in the past 7 days" -msgstr "" +msgstr "Pakker opdateret indenfor de seneste 7 dage" msgid "Packages updated in the past year" -msgstr "" +msgstr "Pakker opdateret indenfor det seneste år" msgid "Packages never updated" -msgstr "" +msgstr "Pakker aldrig opdateret" msgid "Registered Users" -msgstr "" +msgstr "Registerede brugere" msgid "Trusted Users" -msgstr "" +msgstr "Betroede brugere" msgid "Recent Updates" -msgstr "" +msgstr "Seneste opdateringer" msgid "My Statistics" -msgstr "" +msgstr "Mine statistikker" msgid "Packages in unsupported" msgstr "" @@ -1276,7 +1286,7 @@ msgid "End" msgstr "Slut" msgid "Result" -msgstr "" +msgstr "Resultat" msgid "No" msgstr "Nej" @@ -1288,13 +1298,13 @@ msgid "Total" msgstr "Total" msgid "Participation" -msgstr "" +msgstr "Deltagelse" msgid "Last Votes by TU" msgstr "" msgid "Last vote" -msgstr "" +msgstr "Sidste stemme" msgid "No results found." msgstr "Ingen resultater fundet." diff --git a/po/de.po b/po/de.po index e7cb4c06..6ddc0ffe 100644 --- a/po/de.po +++ b/po/de.po @@ -7,6 +7,7 @@ # Alexander Griesbaum , 2013-2014 # bjo , 2013 # FabianS_ , 2012 +# go2sh , 2015 # FabianS_ , 2012 # Giuliano Schneider , 2015 # Lukas Fleischer , 2011 @@ -22,10 +23,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: German (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 09:49+0000\n" +"Last-Translator: go2sh \n" +"Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" "de/)\n" "Language: de\n" "MIME-Version: 1.0\n" @@ -40,11 +41,13 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Die angeforderte Seite existiert leider nicht." msgid "Service Unavailable" -msgstr "" +msgstr "Dienst nicht verfügbr" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir " +"werden gleich zurück sein ..." msgid "Account" msgstr "Konto" @@ -68,9 +71,6 @@ msgstr "Benutze dieses Formular, um vorhandene Konten zu suchen." msgid "You must log in to view user information." msgstr "Du musst Dich anmelden, um Benutzerinformationen anzusehen." -msgid "Use this form to create an account." -msgstr "Benutze dieses Formular, um ein Konto zu erstellen." - msgid "Add Proposal" msgstr "Vorschlag hinzufügen" @@ -165,48 +165,80 @@ msgstr "" "Nicht unterstützte Pakete sind von Benutzern erzeugte Inhalte. Jegliche " "Nutzung der zur Verfügung gestellten Dateien erfolgt auf eigene Gefahr." +msgid "Learn more..." +msgstr "Erfahre mehr ..." + msgid "Support" -msgstr "" +msgstr "Untersttzung" msgid "Package Requests" -msgstr "" +msgstr "Paketanfragen" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Es gibt drei Arten von Anfragen, die in der %sPaketaktionen%s Box auf der " +"Paketdetailseite eingereicht werden können:" msgid "Orphan Request" -msgstr "" +msgstr "Verweisungsanfrage" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Anfrage eine Pakte abzugeben, z.B. wenn der Verwalten nicht aktiv ist und " +"das Paket vor einer ganzen Weile als veraltet makiert wurde." msgid "Deletion Request" -msgstr "" +msgstr "Lösch-Antrag" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte " +"benutzen Sie diese nicht, wenn das Paket kaputt ist und leich repariert " +"werden kann. Sondern kontaktieren Sie den Paketverwalter und reichen Sie " +"eine Verwaisungsanfrage ein wenn nötig." msgid "Merge Request" -msgstr "" +msgstr "Zusammenführungsanfrage" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Anfrage ein Paket mit einem anderen zusammenzuführen. Wird benutzt, wenn ein " +"Paket umbenannt werden muss oder durch ein geteiltes Paket ersetzt wird." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Wenn Sie eine Anfrage diskutieren wollen, können sie die %saur-requests%s " +"Mailingliste benutzen. Jedoch benutzen Sie diese nicht um Anfragen " +"einzureichen." + +msgid "Submitting Packages" +msgstr "Pakete einreichen" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Git über SSH wird jetzt benutzt um Pakete in das AUR einzureichen. Siehe die " +"%sEinreichen von Paketen%s Sektion von der Arch User Repository ArchWiki " +"Seite für mehr Details." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Die folgenden SSH Fingerabdrücke werden für das AUR benutzt:" msgid "Discussion" msgstr "Diskussion" @@ -217,6 +249,10 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und " +"vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für " +"Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface nutzen Sie " +"die %saur-dev%s Mailingliste." msgid "Bug Reporting" msgstr "Fehler melden" @@ -228,6 +264,11 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-" +"Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um " +"Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte " +"direkte an den zuständigen Maintainer, oder hinterlass einen Kommentar auf " +"der entsprechenden Seite des Paketes." msgid "Package Search" msgstr "Paketsuche" @@ -414,12 +455,16 @@ msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"Benutzen Sie dieses Formular um die Paketbasis %s%s%s, welche die folgenden " +"Pakete enhält, abzugeben:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"Durch das markieren des Kontrollkästchen bestätigen Sie, dass Sie das Pakte " +"abegen und den Besitz an %s%s%s übergeben wollen." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." @@ -476,7 +521,7 @@ msgstr "" "Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." msgid "File Request" -msgstr "Datei Anfrage" +msgstr "Anfrage einreichen" msgid "Close Request" msgstr "Anfrage schließen" @@ -496,6 +541,12 @@ msgstr "Letzte" msgid "Requests" msgstr "Anfragen" +msgid "Register" +msgstr "Registrieren" + +msgid "Use this form to create an account." +msgstr "Benutze dieses Formular, um ein Konto zu erstellen." + msgid "Trusted User" msgstr "Vertrauenswürdiger Benutzer (TU)" @@ -644,6 +695,10 @@ msgstr "Ungültige Kombination aus E-Mail und Reset-Schlüssel." msgid "None" msgstr "Keine" +#, php-format +msgid "View account information for %s" +msgstr "Konto-Informationen aufrufen für %s" + msgid "Error retrieving package details." msgstr "Fehler beim Aufrufen der Paket-Details." @@ -734,33 +789,27 @@ msgstr "Kommentar wurde gelöscht." msgid "You are not allowed to delete this comment." msgstr "Du darfst diesen Kommentar nicht löschen." -msgid "Missing category ID." -msgstr "Kategorie-ID fehlt." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Du bist nicht berechtigt die Schlagworte dieser Paketbasis zu ändern." -msgid "Invalid category ID." -msgstr "Kategorie-ID ungültig." - -msgid "You are not allowed to change this package category." -msgstr "Du darfst diese Paketkategorie nicht ändern." - -msgid "Package category changed." -msgstr "Die Kategorie des Pakets wurde verändert." +msgid "The package base keywords have been updated." +msgstr "Die Schlagwörter der Paketbasis wurden aktualisiert." msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "Du darfst die Mitbetreuer für diese Paketbasis nicht verwalten." #, php-format msgid "Invalid user name: %s" msgstr "Ungültiger Nutzername: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "Die Mitbetreuer der Paketbasis wurden aktualisiert." msgid "View packages details for" msgstr "Paket-Informationen aufrufen für" msgid "You must be logged in to file package requests." -msgstr "Du musst angemeldet sein, um ein Paket anfordern zu können." +msgstr "Du musst angemeldet sein, um Paketanfragen einreichen zu können." msgid "Invalid name: only lowercase letters are allowed." msgstr "Ungültiger Name: Es dürfen nur Kleinbuchstaben verwendet werden." @@ -915,6 +964,8 @@ msgstr "Verwalte Ko-Maintainer: %s" msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"Benutze dieses Formular um Mitbetreuer für %s%s%s hinzuzufügen (ein " +"Benutzername pro Zeile):" msgid "Users" msgstr "Benutzer" @@ -928,15 +979,6 @@ msgstr "Meine Pakete" msgid " My Account" msgstr "Mein Konto" -msgid "Register" -msgstr "Registrieren" - -msgid "unknown" -msgstr "unbekannt" - -msgid "Package Base Details" -msgstr "Paketbasis Details" - msgid "Package Actions" msgstr "Paketaktionen" @@ -991,22 +1033,24 @@ msgstr "Paket verschmelzen" msgid "Adopt Package" msgstr "Paket übernehmen" +msgid "unknown" +msgstr "unbekannt" + +msgid "Package Base Details" +msgstr "Paketbasis Details" + msgid "Git Clone URL" msgstr "Git Clone URL" -msgid "Category" -msgstr "Kategorie" +msgid "read-only" +msgstr "nur lesen" -msgid "Change category" -msgstr "Kategorie wechseln" +msgid "Keywords" +msgstr "Schlüsselwörter" msgid "Submitter" msgstr "Eingereicht von" -#, php-format -msgid "View account information for %s" -msgstr "Konto-Informationen aufrufen für %s" - msgid "Maintainer" msgstr "Betreuer" @@ -1123,7 +1167,7 @@ msgstr "Kommentare" #, php-format msgid "File Request: %s" -msgstr "Dateianfrage: %s" +msgstr "Anfrage einreichen: %s" #, php-format msgid "" @@ -1214,7 +1258,7 @@ msgid "Name" msgstr "Name" msgid "Popularity" -msgstr "" +msgstr "Beliebtheit" msgid "Voted" msgstr "Abgestimmt" @@ -1231,15 +1275,9 @@ msgstr "Absteigend" msgid "Enter search criteria" msgstr "Suchkriterien eingeben" -msgid "Any" -msgstr "Alle" - msgid "Search by" msgstr "Suche nach" -msgid "Keywords" -msgstr "Schlüsselwörter" - msgid "Out of Date" msgstr "Veraltet" @@ -1273,6 +1311,13 @@ msgstr[1] "%d Pakete gefunden." msgid "Version" msgstr "Version" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"Die Beliebtheit berechnet sich als Summe aller Stimmen, wobei jede Stimme " +"mit einem Faktor von 0,98 pro Tag seit der Erstellung gewichtet wird." + msgid "Yes" msgstr "Ja" diff --git a/po/el.po b/po/el.po index e1f8263a..6e613df9 100644 --- a/po/el.po +++ b/po/el.po @@ -14,10 +14,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Greek (http://www.transifex.com/projects/p/aur/language/el/)\n" +"Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -59,9 +59,6 @@ msgstr "" msgid "You must log in to view user information." msgstr "Πρέπει να συνδεθείτε για να δείτε πληροφορίες χρήστη." -msgid "Use this form to create an account." -msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να δημιουργήσετε λογαριασμό." - msgid "Add Proposal" msgstr "Προσθέστε Πρόταση" @@ -152,6 +149,9 @@ msgstr "" "Τα πακέτα στο \"Unsupported\" έχουν περιεχόμενο που παρέχεται απο τους " "χρήστες. Χρησιμοποιήστε τα με δική σας ευθύνη." +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -195,6 +195,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Συζήτηση" @@ -469,6 +482,12 @@ msgstr "Τελευταίο" msgid "Requests" msgstr "" +msgid "Register" +msgstr "Εγγραφείτε" + +msgid "Use this form to create an account." +msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να δημιουργήσετε λογαριασμό." + msgid "Trusted User" msgstr "Trusted User" @@ -617,6 +636,10 @@ msgstr "Μη έγκυρο e-mail και συνδυασμός κλειδιού ε msgid "None" msgstr "Κανένα" +#, php-format +msgid "View account information for %s" +msgstr "Δείτε τις πληροφορίες λογαριασμού του %s" + msgid "Error retrieving package details." msgstr "Σφάλμα κατά τη διάρκεια φόρτωσης των πληροφοριών του πακέτου." @@ -710,17 +733,11 @@ msgstr "Το σχόλιο έχει διαγραφεί." msgid "You are not allowed to delete this comment." msgstr "Δεν σας επιτρέπεται να διαγράψετε αυτό το σχόλιο." -msgid "Missing category ID." -msgstr "Μη υπαρκτό ID κατηγορίας." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "Μη έγκυρο ID κατηγορίας." - -msgid "You are not allowed to change this package category." -msgstr "Δεν σας επιτρέπεται να αλλάξετε την κατηγορία αυτού του πακέτου." - -msgid "Package category changed." -msgstr "Έγινε αλλαγή κατηγορίας πακέτου." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -899,15 +916,6 @@ msgstr "Τα πακέτα μου" msgid " My Account" msgstr "Ο λογαριασμός μου" -msgid "Register" -msgstr "Εγγραφείτε" - -msgid "unknown" -msgstr "άγνωστο" - -msgid "Package Base Details" -msgstr "" - msgid "Package Actions" msgstr "Ενέργειες Πακέτου" @@ -962,22 +970,24 @@ msgstr "Συγχώνευση πακέτου" msgid "Adopt Package" msgstr "Υιοθετήστε το Πακέτο" +msgid "unknown" +msgstr "άγνωστο" + +msgid "Package Base Details" +msgstr "" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Κατηγορία" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "Αλλαγή κατηγορίας" +msgid "Keywords" +msgstr "Λέξεις κλειδιά" msgid "Submitter" msgstr "Υποβάλλων" -#, php-format -msgid "View account information for %s" -msgstr "Δείτε τις πληροφορίες λογαριασμού του %s" - msgid "Maintainer" msgstr "Συντηρητής" @@ -1196,15 +1206,9 @@ msgstr "Φθίνουσα" msgid "Enter search criteria" msgstr "Εισάγετε κριτήρια αναζήτησης" -msgid "Any" -msgstr "Οποιαδήποτε" - msgid "Search by" msgstr "Αναζήτηση κατά" -msgid "Keywords" -msgstr "Λέξεις κλειδιά" - msgid "Out of Date" msgstr "Παρωχημένα" @@ -1238,6 +1242,11 @@ msgstr[1] "" msgid "Version" msgstr "Έκδοση" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Ναι" diff --git a/po/es.po b/po/es.po index fe940e06..8861a548 100644 --- a/po/es.po +++ b/po/es.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# Adolfo Jayme Barrientos, 2015 # Angel Velasquez , 2011 # juantascon , 2011 # Lukas Fleischer , 2011 @@ -14,10 +15,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Spanish (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-21 21:28+0000\n" +"Last-Translator: Pablo Roberto Francisco Lezaeta Reyes \n" +"Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" "es/)\n" "Language: es\n" "MIME-Version: 1.0\n" @@ -29,14 +30,16 @@ msgid "Page Not Found" msgstr "Página no encontrada" msgid "Sorry, the page you've requested does not exist." -msgstr "Disculpe, la página que solicitó no existe." +msgstr "La página solicitada no existe." msgid "Service Unavailable" -msgstr "" +msgstr "Servicio no disponible" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"¡No se asuste! El sitio está desactivado por tareas de mantenimiento. " +"Volveremos pronto." msgid "Account" msgstr "Cuenta" @@ -59,14 +62,11 @@ msgstr "Use este formulario para buscar cuentas existentes." msgid "You must log in to view user information." msgstr "Debe autentificarse para ver la información del usuario." -msgid "Use this form to create an account." -msgstr "Use este formulario para crear una cuenta." - msgid "Add Proposal" msgstr "Añadir propuesta" msgid "Invalid token for user action." -msgstr "Elemento inválido para la acción del usuario." +msgstr "La ficha no es válida para la acción de usuario." msgid "Username does not exist." msgstr "El nombre de usuario no existe." @@ -106,7 +106,7 @@ msgid "Removal of a TU (undeclared inactivity)" msgstr "Remover a un usuario de confianza (no declarado inactivo)" msgid "Amendment of Bylaws" -msgstr "Enmienda a las Bylaws (Reglas de los TU)" +msgstr "Enmienda a los Estatutos" msgid "Proposal" msgstr "Propuesta" @@ -154,48 +154,81 @@ msgstr "" "Los paquetes no soportados son producidos por los usuarios. Cualquier uso de " "los archivos de estos es a su propio riesgo." +msgid "Learn more..." +msgstr "Más información…" + msgid "Support" -msgstr "" +msgstr "Ayuda" msgid "Package Requests" -msgstr "" +msgstr "Solicitudes para los paquetes" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Hay tres tipos de solicitudes que puede presentar en el cuadro %sAcciones " +"del paquete%s en la página de detalles del paquete:" msgid "Orphan Request" -msgstr "" +msgstr "Solicitud de orfandad" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está " +"inactivo y el paquete se ha marcado como desactualizado por un largo tiempo." msgid "Deletion Request" -msgstr "" +msgstr "Solicitud de eliminación" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Solicitar la eliminación de un paquete del repositorio de usuarios de Arch. " +"No utilice esta opción si un paquete está roto pero puede ser arreglado " +"fácilmente. En cambio, contacte al encargado del paquete y presentar " +"solicitud orfandad si es necesario." msgid "Merge Request" -msgstr "" +msgstr "Solicitud de unión" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Solicitar que un paquete sea unido con otro. Puede ser utilizado cuando un " +"paquete tiene que ser cambiado de nombre o sustituido por un paquete " +"dividido." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Si quiere discutir una solicitud, puede utilizar la lista de correo %saur-" +"requests%s. Sin embargo, por favor no utilice esa lista para presentar " +"solicitudes." + +msgid "Submitting Packages" +msgstr "Subir paquetes" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Ahora se utiliza Git sobre SSH para subir paquetes al AUR. Vea la sección " +"%sSubir paquetes%s de la wiki del repositorio de usuarios de Arch para más " +"detalles." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Las siguientes huellas SSH están en uso para AUR." msgid "Discussion" msgstr "Debate" @@ -206,6 +239,10 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"La discusión general sobre el repositorio de usuarios de Arch (AUR) y la " +"estructura de usuarios de confianza se realiza en la lista de correos %saur-" +"general%s. Para la discusión en relación con el desarrollo de la interfaz " +"web del AUR, utilice la lista de correo %saur-dev%s." msgid "Bug Reporting" msgstr "Informe de errores" @@ -217,6 +254,11 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Si encuentra un error en la interfaz web del AUR, llene un informe de error " +"en nuestro %srastreador de errores o «bug tracker»%s. Use este para reportar " +"%súnicamente%s errores del AUR. Para reportar errores de empaquetado debe " +"contactar al encargado o deje un comentario en la página respectiva del " +"paquete." msgid "Package Search" msgstr "Buscar paquetes" @@ -253,7 +295,7 @@ msgid "Logout" msgstr "Salir" msgid "Enter login credentials" -msgstr "Introduce las credenciales de autentificación" +msgstr "Proporcione sus datos de acceso" msgid "Username" msgstr "Nombre de usuario" @@ -265,7 +307,7 @@ msgid "Remember me" msgstr "Recordarme" msgid "Forgot Password" -msgstr "Olvidó su cotraseña" +msgstr "¿Olvidó su contraseña?" #, php-format msgid "" @@ -308,22 +350,22 @@ msgstr "" "nada." msgid "Password Reset" -msgstr "Reiniciar la contraseña" +msgstr "Restablecer la contraseña" msgid "Check your e-mail for the confirmation link." msgstr "Compruebe su correo para ver el enlace de confirmación." msgid "Your password has been reset successfully." -msgstr "Su contraseña ha sido reiniciada con éxito." +msgstr "Se ha restablecido la contraseña correctamente." msgid "Confirm your e-mail address:" msgstr "Confirme su dirección de correo:" msgid "Enter your new password:" -msgstr "Introduzca su nueva contraseña:" +msgstr "Escriba su contraseña nueva:" msgid "Confirm your new password:" -msgstr "Confirme su nueva contraseña:" +msgstr "Confirme la contraseña nueva:" msgid "Continue" msgstr "Continuar" @@ -484,6 +526,12 @@ msgstr "Último" msgid "Requests" msgstr "Solicitud" +msgid "Register" +msgstr "Registro" + +msgid "Use this form to create an account." +msgstr "Use este formulario para crear una cuenta." + msgid "Trusted User" msgstr "Usuario de confianza" @@ -574,7 +622,7 @@ msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, fue creada satisfactoriamente." msgid "Click on the Login link above to use your account." -msgstr "Haz clic en el enlace de autentificación para usar su cuenta." +msgstr "Pulse en el enlace de acceso anterior para utilizar la cuenta." #, php-format msgid "" @@ -587,7 +635,9 @@ msgstr "" "la barra de direcciones de su navegador web." msgid "A password reset key has been sent to your e-mail address." -msgstr "Una llave para reiniciar su contraseña a sido enviada a su correo." +msgstr "" +"Se envió una clave de restablecimiento de contraseña a su dirección de " +"correo electrónico." #, php-format msgid "No changes were made to the account, %s%s%s." @@ -631,6 +681,10 @@ msgstr "Combinación de dirección de correo y clave no válida." msgid "None" msgstr "Nada" +#, php-format +msgid "View account information for %s" +msgstr "Ver información de la cuenta para %s" + msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." @@ -720,17 +774,11 @@ msgstr "Comentario eliminado." msgid "You are not allowed to delete this comment." msgstr "No está autorizado a eliminar este comentario." -msgid "Missing category ID." -msgstr "Falta el Identificador de categoría." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "No está autorizado a editar las palabras clave de este paquete base." -msgid "Invalid category ID." -msgstr "El identificador de categoría no es válido." - -msgid "You are not allowed to change this package category." -msgstr "No puede cambiar la categoría de este paquete." - -msgid "Package category changed." -msgstr "Categoría del paquete cambiada." +msgid "The package base keywords have been updated." +msgstr "Las palabras clave del paquete base se han actualizado." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "No se le permite administrar los coencargados de este paquete base." @@ -858,8 +906,8 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" -"La siguiente información solamente es necesaria si desea subir paquetes al " -"Repositorio de Usuarios de Arch." +"La siguiente información únicamente es necesaria si desea subir paquetes al " +"repositorio de usuarios de Arch." msgid "SSH Public Key" msgstr "Clave pública SSH" @@ -918,15 +966,6 @@ msgstr "Mis paquetes" msgid " My Account" msgstr "Mi cuenta" -msgid "Register" -msgstr "Registro" - -msgid "unknown" -msgstr "desconocido" - -msgid "Package Base Details" -msgstr "Detalles del paquete base" - msgid "Package Actions" msgstr "Acciones del paquete" @@ -981,22 +1020,24 @@ msgstr "Unir paquete" msgid "Adopt Package" msgstr "Adoptar paquete" +msgid "unknown" +msgstr "desconocido" + +msgid "Package Base Details" +msgstr "Detalles del paquete base" + msgid "Git Clone URL" msgstr "Dirección URL de clonado con Git" -msgid "Category" -msgstr "Categoría" +msgid "read-only" +msgstr "Solamente lectura" -msgid "Change category" -msgstr "Cambiar categoría" +msgid "Keywords" +msgstr "Palabras claves" msgid "Submitter" msgstr "Primer encargado" -#, php-format -msgid "View account information for %s" -msgstr "Ver información de la cuenta para %s" - msgid "Maintainer" msgstr "Encargado" @@ -1203,7 +1244,7 @@ msgid "Name" msgstr "Nombre" msgid "Popularity" -msgstr "" +msgstr "Popularidad" msgid "Voted" msgstr "Votado" @@ -1220,15 +1261,9 @@ msgstr "Descendente" msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" -msgid "Any" -msgstr "Cualquiera" - msgid "Search by" msgstr "Buscar por" -msgid "Keywords" -msgstr "Palabras claves" - msgid "Out of Date" msgstr "Desactualizado" @@ -1262,6 +1297,13 @@ msgstr[1] "%d paquetes fueron encontrados." msgid "Version" msgstr "Versión" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"La popularidad se calcula como la suma de todos los votos con cada voto " +"ponderado con un factor de 0,98 por día desde la creación del paquete." + msgid "Yes" msgstr "Sí" diff --git a/po/es_419.po b/po/es_419.po index 555cd486..057e27c0 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -13,10 +13,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Spanish (Latin America) (http://www.transifex.com/projects/p/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 22:12+0000\n" +"Last-Translator: Pablo Roberto Francisco Lezaeta Reyes \n" +"Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" "aur/language/es_419/)\n" "Language: es_419\n" "MIME-Version: 1.0\n" @@ -31,11 +31,13 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Disculpe, la página que solicitó no existe." msgid "Service Unavailable" -msgstr "" +msgstr "Servicio no disponible" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"¡No se asustes! El sitio está desactivado por mantenimiento. Pronto " +"volveremos." msgid "Account" msgstr "Cuenta" @@ -58,9 +60,6 @@ msgstr "Use este formulario para buscar cuentas existentes." msgid "You must log in to view user information." msgstr "Debe autentificarse para ver la información del usuario." -msgid "Use this form to create an account." -msgstr "Use este formulario para crear una cuenta." - msgid "Add Proposal" msgstr "Añadir propuesta" @@ -150,51 +149,83 @@ msgid "" "Unsupported packages are user produced content. Any use of the provided " "files is at your own risk." msgstr "" -"Los paquetes no soportados son producidos por los usuarios. Cualquier uso de " -"ellos o sus archivos es a su propio riesgo." +"Los paquetes en AUR son producidos por los usuarios. Cualquier uso de ellos " +"o sus archivos es a su propio riesgo." + +msgid "Learn more..." +msgstr "Aprenda más..." msgid "Support" -msgstr "" +msgstr "Soporte" msgid "Package Requests" -msgstr "" +msgstr "Peticiones para los paquetes" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Existen tres tipos de peticiones que pueden presentarse en el recuadro " +"%sAcciones del paquete%s en la página de detalles del paquete:" msgid "Orphan Request" -msgstr "" +msgstr "Petición de Orfandad" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Pedir la orfandad de un paquete, por ejemplo, cuando el encargado está " +"inactivo y el paquete fue marcado como desactualizado un largo tiempo." msgid "Deletion Request" -msgstr "" +msgstr "Petición de Borrado" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Pedir que un paquete sea borrado del Repositorio Usuarios de Arch. Por " +"favor, no use esta opción si un paquete está roto y se puede arreglar " +"fácilmente. En cambio, contacte con el encargado del paquete y presentar " +"solicitud orfandad si es necesario." msgid "Merge Request" -msgstr "" +msgstr "Petición de Fusión" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Pedir que se fusione un paquete en otro. Puede usarla cuando un paquete " +"tiene que ser cambiado de nombre o sustituido por un paquete dividido." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Si quiere discutir una petición, puede usar la lista de correo %saur-" +"peticiones%s. Sin embargo, por favor no utilice esa lista para presentar " +"solicitudes." + +msgid "Submitting Packages" +msgstr "Subir paquetes" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Ahora se usa Git sobre SSH para subir paquetes al AUR. Véase la sección " +"%sSubir paquetes%s de la wiki del Repositorio de Usuarios de Arch para más " +"información." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Las siguientes huellas SSH están en uso para AUR." msgid "Discussion" msgstr "Debate" @@ -205,6 +236,10 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"La discusión general acerca del Repositorio de Usuarios de Arch (AUR) y la " +"estructura de Usuarios de Confianza se realiza en la lista de correos %saur-" +"general%s. Para discusiones relacionadas con el desarrollo de la interfaz " +"web del AUR, utilice la lista de correo %saur-dev%s." msgid "Bug Reporting" msgstr "Informe de errores" @@ -216,6 +251,10 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Si encuentra un error en la interfaz web del AUR, llene un informe de fallo " +"en nuestro %s«bug tracker»%s. Use este para reportar %súnicamente%s errores " +"del AUR. Para reportar errores de empaquetado debe contactar con el " +"encargado o dejar un comentario en la página respectiva del paquete." msgid "Package Search" msgstr "Buscar paquetes" @@ -301,9 +340,9 @@ msgid "" "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." msgstr "" -"Una solicitud de restablecimiento de contraseña se presentó para la cuenta " -"%s asociado a su dirección de correo. Si desea restablecer su contraseña " -"siga el enlace de abajo, si no ignore este mensaje y no pasará nada." +"Una petición de restablecimiento de contraseña se presentó para la cuenta %s " +"asociado a su dirección de correo. Si desea restablecer su contraseña siga " +"el enlace de abajo, si no ignore este mensaje y no pasará nada." msgid "Password Reset" msgstr "Reiniciar la contraseña" @@ -385,8 +424,7 @@ msgid "Delete" msgstr "Borrar" msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Solamente Usuarios de Confianza y Desarrolladores pueden borrar paquetes." +msgstr "Solo Usuarios de Confianza y Desarrolladores pueden borrar paquetes." msgid "Disown Package" msgstr "Abandonar paquete" @@ -425,8 +463,8 @@ msgstr "Abandonar" msgid "Only Trusted Users and Developers can disown packages." msgstr "" -"Solamente Usuarios de Confianza y Desarrolladores pueden forzar el abandono " -"de paquetes." +"Solo Usuarios de Confianza y Desarrolladores pueden forzar el abandono de " +"paquetes." msgid "Package Merging" msgstr "Fusión de paquetes" @@ -459,14 +497,13 @@ msgid "Merge" msgstr "Fusión" msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Solamente Usuarios de Confianza y Desarrolladores pueden fusionar paquetes." +msgstr "Solo Usuarios de Confianza y Desarrolladores pueden fusionar paquetes." msgid "File Request" -msgstr "Solicitud para el paquete" +msgstr "Petición para el paquete" msgid "Close Request" -msgstr "Cerrar solicitud" +msgstr "Cerrar Petición" msgid "First" msgstr "Primero" @@ -481,7 +518,13 @@ msgid "Last" msgstr "Último" msgid "Requests" -msgstr "Solicitud" +msgstr "Petición" + +msgid "Register" +msgstr "Registro" + +msgid "Use this form to create an account." +msgstr "Use este formulario para crear una cuenta." msgid "Trusted User" msgstr "Usuario de Confianza" @@ -493,7 +536,7 @@ msgid "Voting is closed for this proposal." msgstr "Las votaciones para esta propuesta están cerradas." msgid "Only Trusted Users are allowed to vote." -msgstr "Solamente Usuarios de Confianza pueden votar." +msgstr "Solo Usuarios de Confianza pueden votar." msgid "You cannot vote in an proposal about you." msgstr "No puede votar en una propuesta sobre usted." @@ -535,7 +578,7 @@ msgid "Start and end with a letter or number" msgstr "Comenzar y acabar con una letra o número" msgid "Can contain only one period, underscore or hyphen." -msgstr "Solamente puede contener un punto, guion bajo o guion." +msgstr "Solo puede contener un punto, guion bajo o guion." msgid "The email address is invalid." msgstr "La dirección de correo no es válida." @@ -630,6 +673,10 @@ msgstr "Combinación de dirección de correo y clave no válida." msgid "None" msgstr "Nada" +#, php-format +msgid "View account information for %s" +msgstr "Ver información de la cuenta para %s" + msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." @@ -719,17 +766,12 @@ msgstr "Comentario borrado." msgid "You are not allowed to delete this comment." msgstr "No está autorizado a borrar este comentario." -msgid "Missing category ID." -msgstr "Falta el Identificador de categoría." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" +"No está autorizado para editar las palabras clave de este paquete base." -msgid "Invalid category ID." -msgstr "El identificador de categoría no es válido." - -msgid "You are not allowed to change this package category." -msgstr "No puede cambiar la categoría de este paquete." - -msgid "Package category changed." -msgstr "Categoría del paquete cambiada." +msgid "The package base keywords have been updated." +msgstr "Las palabras clave del paquete base actualizaron ." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "No tiene permitido administrar los coencargados de este paquete base." @@ -745,30 +787,29 @@ msgid "View packages details for" msgstr "Ver detalles del paquete para" msgid "You must be logged in to file package requests." -msgstr "Debe estar identificado para realizar solicitudes para el paquete." +msgstr "Debe estar identificado para realizar peticiones para el paquete." msgid "Invalid name: only lowercase letters are allowed." -msgstr "Nombre no válido: solamente son permitidas las letras minúsculas." +msgstr "Nombre no válido: solo se permiten letras minúsculas." msgid "The comment field must not be empty." msgstr "El campo de comentarios no debe estar vacío." msgid "Invalid request type." -msgstr "Tipo de solicitud no válida." +msgstr "Tipo de petición no válida." msgid "Added request successfully." -msgstr "Solicitud agregada con éxito." +msgstr "Petición agregada con éxito." msgid "Invalid reason." msgstr "Razón no válida." msgid "Only TUs and developers can close requests." msgstr "" -"Solamente los Usuarios de Confianza y Desarrolladores pueden cerrar una " -"solicitud." +"Solo Usuarios de Confianza y Desarrolladores pueden cerrar una petición." msgid "Request closed successfully." -msgstr "Solicitud cerrada exitosamente" +msgstr "Petición cerrada exitosamente" #, php-format msgid "You can use this form to permanently delete the AUR account %s." @@ -857,7 +898,7 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" -"La siguiente información es necesaria solamente si quiere subir paquetes al " +"La siguiente información es necesaria únicamente si quiere subir paquetes al " "Repositorio de Usuarios de Arch." msgid "SSH Public Key" @@ -917,15 +958,6 @@ msgstr "Mis paquetes" msgid " My Account" msgstr "Mi cuenta" -msgid "Register" -msgstr "Registro" - -msgid "unknown" -msgstr "desconocido" - -msgid "Package Base Details" -msgstr "Detalles del paquete base" - msgid "Package Actions" msgstr "Acciones del paquete" @@ -968,8 +1000,8 @@ msgstr "Administrar coencargados" #, php-format msgid "%d pending request" msgid_plural "%d pending requests" -msgstr[0] "Hay %d solicitud pendiente" -msgstr[1] "Hay %d solicitudes pendientes" +msgstr[0] "Hay %d petición pendiente" +msgstr[1] "Hay %d peticiones pendientes" msgid "Delete Package" msgstr "Borrar paquete" @@ -980,22 +1012,24 @@ msgstr "Fusionar paquete" msgid "Adopt Package" msgstr "Adoptar paquete" +msgid "unknown" +msgstr "desconocido" + +msgid "Package Base Details" +msgstr "Detalles del paquete base" + msgid "Git Clone URL" msgstr "URL de clonado con Git" -msgid "Category" -msgstr "Categoría" +msgid "read-only" +msgstr "Solo lectura" -msgid "Change category" -msgstr "Cambiar categoría" +msgid "Keywords" +msgstr "Palabras claves" msgid "Submitter" msgstr "Primer encargado" -#, php-format -msgid "View account information for %s" -msgstr "Ver información de la cuenta para %s" - msgid "Maintainer" msgstr "Encargado" @@ -1080,12 +1114,12 @@ msgstr "Fuentes" #, php-format msgid "Close Request: %s" -msgstr "Cerrar solicitud: %s" +msgstr "Cerrar petición: %s" #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -"Use este formulario para cerrar la solicitud para el paquete base %s%s%s." +"Use este formulario para cerrar la petición para el paquete base %s%s%s." msgid "Note" msgstr "Nota" @@ -1095,7 +1129,7 @@ msgid "" "add a comment when rejecting a request." msgstr "" "El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda " -"encarecidamente añadir un comentario al rechazar una solicitud." +"encarecidamente añadir un comentario al rechazar una petición." msgid "Reason" msgstr "Razón" @@ -1111,18 +1145,18 @@ msgstr "Comentario" #, php-format msgid "File Request: %s" -msgstr "Solicitud para el paquete: %s" +msgstr "Petición para el paquete: %s" #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -"Use este formulario para presentar una solicitud para el paquete base %s%s%s " +"Use este formulario para presentar una petición para el paquete base %s%s%s " "el cual incluye los siguientes paquetes:" msgid "Request type" -msgstr "Tipo de solicitud" +msgstr "Tipo de petición" msgid "Deletion" msgstr "Borrado" @@ -1181,7 +1215,7 @@ msgid "Name, Description" msgstr "Nombre, descripción" msgid "Name Only" -msgstr "Solamente nombre" +msgstr "Solo nombre" msgid "Exact Name" msgstr "Nombre exacto" @@ -1202,7 +1236,7 @@ msgid "Name" msgstr "Nombre" msgid "Popularity" -msgstr "" +msgstr "Popularidad" msgid "Voted" msgstr "Votado" @@ -1219,15 +1253,9 @@ msgstr "Descendente" msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" -msgid "Any" -msgstr "Cualquiera" - msgid "Search by" msgstr "Buscar por" -msgid "Keywords" -msgstr "Palabras claves" - msgid "Out of Date" msgstr "Desactualizado" @@ -1261,6 +1289,13 @@ msgstr[1] "%d paquetes fueron encontrados." msgid "Version" msgstr "Versión" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"La Popularidad es calculada como la suma de todos los votos ponderados con " +"un factor de 0,98 por día desde la creación del paquete." + msgid "Yes" msgstr "Sí" @@ -1325,7 +1360,7 @@ msgid "My Statistics" msgstr "Mis estadísticas" msgid "Packages in unsupported" -msgstr "Paquetes en AUR" +msgstr "Sus paquetes en AUR" msgid "Proposal Details" msgstr "Detalles de la propuesta" diff --git a/po/fi.po b/po/fi.po index fcd87c6c..803ef9ea 100644 --- a/po/fi.po +++ b/po/fi.po @@ -3,15 +3,15 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: -# Jesse Jaara , 2011-2012 +# Jesse Jaara , 2011-2012,2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Finnish (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-20 23:09+0000\n" +"Last-Translator: Jesse Jaara \n" +"Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" "fi/)\n" "Language: fi\n" "MIME-Version: 1.0\n" @@ -53,9 +53,6 @@ msgstr "Etsi käyttäjätilejä." msgid "You must log in to view user information." msgstr "Sinun pitää kirjautua sisään tarkastellaksesi käyttäjien tietoja." -msgid "Use this form to create an account." -msgstr "Käytä tätä lomaketta uuden käyttäjätilin luomiseen." - msgid "Add Proposal" msgstr "Lisää ehdotus" @@ -148,48 +145,82 @@ msgstr "" "Nämä paketit eivät ole virallisesti tuettuja. Tämän sivun paketit ovat " "käyttäjien tuotosta. Näiden käyttäminen on omalla vastuullaasi" +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" msgid "Package Requests" -msgstr "" +msgstr "Pakettienhallintapyydöt" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Pakettien sivuilta löytyvän %spakettitoiminnot%s -laatikon kautta voi " +"lähettää TU-käyttäjille kolme erilaista pakettienhallintapyyntöä." msgid "Orphan Request" -msgstr "" +msgstr "Hylkäämispyyntö" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Hallintapyyntö paketin poistamiseksi sen nykyiseltä ylläpitäjältä, esimerksi " +"jos ylläpitäjä ei vastaa kommentteihin eikä sähköpostiin ja paketti on " +"merkitty vanhentuneeksi jo kauan sitten." msgid "Deletion Request" -msgstr "" +msgstr "Poistopyyntö" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Hallintapyyntö paketin poistamiseksi AUR:ista. Jos paketti on jollain tapaa " +"rikki tai huono, mutta helposti korjattavissa, tulisi ensisijaisesti olla " +"yhteydessä paketin ylläpitäjään ja viimekädessä pistää paketin " +"hylkäämispyyntö menemään." msgid "Merge Request" -msgstr "" +msgstr "Yhdistämispyyntö" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Hallintapyyntö kahden eri paketin yhdistämiseksi. Voidaan käyttää muun " +"muassa silloin kun jokin paketti on nimettyuudelleen tai korvattu " +"monipaketilla (split package)." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Pakettienhallintapyynnöistä voi keskustella niin yleisellä- kuin myös " +"tiettyyn pyyntöön littyvällä tasolla %saur-requests%s -postituslistalla. Älä " +"kuitenkaan lähetä hallintapyyntöjä postituslistalle." + +msgid "Submitting Packages" +msgstr "Paketien lisääminen ja päivittäminen" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Pakettien lisääminen ja päivittäminen uudessa AUR versiossa tapahtuu SSH-" +"yhteyden yli Git-versionhallinan avulla. Tarkemman ohjeet löytyvät Arch " +"Linuxin wiki-oppaan AUR-sivulta kohdasta %sPakettien lisääminen%s." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "AUR käyttää seuraavia SSH-tunnisteita:" msgid "Discussion" msgstr "Keskustelu" @@ -211,9 +242,14 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Jos löydät AUR:in verkkokäyttöliittymästä jonkin virheen, niin voit " +"raportoida sen %svirheidenhallinta%s -sivulla. Virheidenhallinta -sivulle " +"tulee raportoida vain ja ainoastaan %sitsessään%s AUR:iin liittyviä " +"virheitä, jos virhe liittyy johonkin tiettyyn pakettiin tulee ensisijaisesti " +"ottaa yhteyttä paketin ylläpitäjään tai kirjoittaa kommentti paketin sivulle." msgid "Package Search" -msgstr "" +msgstr "Pakettihaku" msgid "Adopt" msgstr "" @@ -461,6 +497,12 @@ msgstr "Viimeinen" msgid "Requests" msgstr "" +msgid "Register" +msgstr "Rekisteröidy" + +msgid "Use this form to create an account." +msgstr "Käytä tätä lomaketta uuden käyttäjätilin luomiseen." + msgid "Trusted User" msgstr "Luotettu käyttäjä (TU)" @@ -595,6 +637,10 @@ msgstr "Epäkelvollinen sähköposti ja palautusavain yhdistelmä." msgid "None" msgstr "" +#, php-format +msgid "View account information for %s" +msgstr "" + msgid "Error retrieving package details." msgstr "Virhe haettaessa paketin tietoja." @@ -684,17 +730,11 @@ msgstr "Kommentti on poistettu." msgid "You are not allowed to delete this comment." msgstr "Sinulla ei ole oikeuksia tämän kommentin poistamiseen." -msgid "Missing category ID." -msgstr "Kategorian ID puuttuu." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "Kategorian ID ei ole kelvollinen." - -msgid "You are not allowed to change this package category." -msgstr "Sinulla ei ole oikeuksia tämän paketin kategorian muuttamiseen." - -msgid "Package category changed." -msgstr "Paketin kategoria vaihdettu." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -820,7 +860,7 @@ msgid "" msgstr "" msgid "SSH Public Key" -msgstr "" +msgstr "Julkinen SSH avain" msgid "Update" msgstr "Päivitä" @@ -873,29 +913,20 @@ msgstr "Omat paketit" msgid " My Account" msgstr "Omat tiedot" -msgid "Register" -msgstr "Rekisteröidy" - -msgid "unknown" -msgstr "tuntematon" - -msgid "Package Base Details" -msgstr "" - msgid "Package Actions" -msgstr "" +msgstr "Pakettitoiminnot" msgid "View PKGBUILD" msgstr "Näytö PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Näytä muutoshistoria" msgid "Download snapshot" -msgstr "" +msgstr "Lataa tuorein versio" msgid "Search wiki" -msgstr "" +msgstr "Etsi wikistä" msgid "Flagged out-of-date" msgstr "Merkitty vanhentuneeksi" @@ -904,59 +935,61 @@ msgid "Flag package out-of-date" msgstr "Merkitse paketti vanhentuneeksi" msgid "Unflag package" -msgstr "" +msgstr "Poista merkintä" msgid "Remove vote" -msgstr "" +msgstr "Poista ääneni" msgid "Vote for this package" -msgstr "Äännestä tätä pakettia" +msgstr "Äännestä pakettia" msgid "Disable notifications" -msgstr "" +msgstr "En halua enää ilmoituksia" msgid "Notify of new comments" msgstr "Lähetä ilmoitus uusista kommnteista" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "Hallitse ylläpitäjäkumppaneita" #, php-format msgid "%d pending request" msgid_plural "%d pending requests" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d käsittelemätön hallintapyyntö" +msgstr[1] "%d käsittelemätöntä hallintapyyntöä" msgid "Delete Package" msgstr "Poista paketti" msgid "Merge Package" -msgstr "" +msgstr "Yhdistä toiseen pakettiin" msgid "Adopt Package" +msgstr "Ryhdy ylläpitäjäksi" + +msgid "unknown" +msgstr "tuntematon" + +msgid "Package Base Details" msgstr "" msgid "Git Clone URL" -msgstr "" +msgstr "Git kopionti osoite" -msgid "Category" -msgstr "Kategoria" +msgid "read-only" +msgstr "vain luku" -msgid "Change category" -msgstr "Vaihda kategoriaa" +msgid "Keywords" +msgstr "Avainsanat" msgid "Submitter" msgstr "Lisääjä" -#, php-format -msgid "View account information for %s" -msgstr "" - msgid "Maintainer" msgstr "Ylläpitäjä" msgid "Last Packager" -msgstr "" +msgstr "Uusimman versionn luoja" msgid "Votes" msgstr "Äänet" @@ -974,7 +1007,7 @@ msgid "Comment has been added." msgstr "Kommentti lisätty." msgid "View all comments" -msgstr "" +msgstr "Näytä kaikki kommentit" msgid "Latest Comments" msgstr "Uusimmat kommentit" @@ -987,10 +1020,10 @@ msgid "Comment by %s" msgstr "Kommentin kirjoitti %s" msgid "Anonymous comment" -msgstr "" +msgstr "Tuntematon kommentoija" msgid "deleted" -msgstr "" +msgstr "poistettu" msgid "All comments" msgstr "Kaikki kommentit" @@ -999,31 +1032,31 @@ msgid "Package Details" msgstr "Paketin tiedot" msgid "Package Base" -msgstr "" +msgstr "Ylipaketti" msgid "Description" msgstr "Kuvaus" msgid "Upstream URL" -msgstr "" +msgstr "Kotisivu" msgid "Visit the website for" msgstr "" msgid "Licenses" -msgstr "" +msgstr "Lisenssit" msgid "Groups" msgstr "" msgid "Conflicts" -msgstr "" +msgstr "Ristiriidat" msgid "Provides" -msgstr "" +msgstr "Tarjoaa paketit" msgid "Replaces" -msgstr "" +msgstr "Korvaa paketit" msgid "Dependencies" msgstr "Riippuvuudet" @@ -1170,15 +1203,9 @@ msgstr "Laskeva" msgid "Enter search criteria" msgstr "" -msgid "Any" -msgstr "Mikä tahansa" - msgid "Search by" msgstr "Etsintäperuste" -msgid "Keywords" -msgstr "Avainsanat" - msgid "Out of Date" msgstr "Vanhentunut" @@ -1212,6 +1239,11 @@ msgstr[1] "" msgid "Version" msgstr "Versio" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Kyllä" @@ -1246,7 +1278,7 @@ msgid "Search" msgstr "Etsi" msgid "Statistics" -msgstr "Statistiikkat" +msgstr "Tilastoja" msgid "Orphan Packages" msgstr "Hylättyjä paketteja" @@ -1273,7 +1305,7 @@ msgid "Recent Updates" msgstr "Viimeisimmät päivitykset" msgid "My Statistics" -msgstr "Statistiikkani" +msgstr "Tilastoni" msgid "Packages in unsupported" msgstr "Pakettieni määrä" diff --git a/po/fr.po b/po/fr.po index 972d9543..a9b9172a 100644 --- a/po/fr.po +++ b/po/fr.po @@ -4,20 +4,21 @@ # # Translators: # Antoine Lubineau , 2012 -# Antoine Lubineau , 2013-2014 +# Antoine Lubineau , 2012-2014 # Cedric Girard , 2011,2014 # lordheavy , 2011 # lordheavy , 2013-2014 # lordheavy , 2011-2012 # Lukas Fleischer , 2011 +# Xorg , 2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: French (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-19 21:40+0000\n" +"Last-Translator: Xorg \n" +"Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" "fr/)\n" "Language: fr\n" "MIME-Version: 1.0\n" @@ -32,11 +33,13 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Désolé, la page que vous avez demandée n’existe pas." msgid "Service Unavailable" -msgstr "" +msgstr "Service indisponible" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Ne paniquez pas ! Le site est fermé pour maintenance. Nous serons bientôt de " +"retour." msgid "Account" msgstr "Compte" @@ -60,9 +63,6 @@ msgid "You must log in to view user information." msgstr "" "Vous devez vous authentifier pour voir les informations de l’utilisateur." -msgid "Use this form to create an account." -msgstr "Utilisez ce formulaire pour créer un compte." - msgid "Add Proposal" msgstr "Ajoutez une proposition" @@ -116,7 +116,7 @@ msgid "Submit" msgstr "Soumettre" msgid "Manage Co-maintainers" -msgstr "" +msgstr "Gérer les co-mainteneurs" msgid "Home" msgstr "Accueil" @@ -156,48 +156,80 @@ msgstr "" "Les paquets non supportés sont produits par des utilisateurs. Toute " "utilisation des fichiers fournis se fait à vos propres risques." +msgid "Learn more..." +msgstr "En apprendre plus..." + msgid "Support" -msgstr "" +msgstr "Soutien" msgid "Package Requests" -msgstr "" +msgstr "Requêtes de paquet" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Il existe trois types de requêtes qui peuvent être soumises dans la boîte " +"%sActions du paquet%s sur la page des détails d'un paquet :" msgid "Orphan Request" -msgstr "" +msgstr "Requête de destitution" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Demande qu'un paquet soit destitué, c'est-à-dire quand le mainteneur est " +"inactif et que le paquet a été marqué comme périmé depuis un long moment." msgid "Deletion Request" -msgstr "" +msgstr "Requête de suppression" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Demande qu'un paquet soit supprimé d'AUR. Prière de ne pas l'utiliser si un " +"paquet est cassé et que le problème peut être réglé facilement. À la place, " +"contactez le mainteneur du paquet, et soumettez une requête de destitution " +"si nécessaire." msgid "Merge Request" -msgstr "" +msgstr "Requête de fusion" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Demande que le paquet soit fusionné dans un autre. Peut être utilisé quand " +"un paquet a besoin d'être renommé ou bien remplacé par un paquet splitté." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Si vous voulez débattre d'une requête, vous pouvez utiliser la mailing-list " +"%saur-requests%s. Cependant, merci de ne pas utiliser cette liste pour " +"soumettre des requêtes." + +msgid "Submitting Packages" +msgstr "Soumission de paquets" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Git par-dessus SSH est maintenant utilisé pour soumettre des paquets sur " +"AUR. Voir la section %sSoumettre des paquets%s sur la page Arch User " +"Repository du wiki pour plus de détails." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Les empreintes SSH suivantes sont utilisées pour AUR :" msgid "Discussion" msgstr "Discussion" @@ -208,6 +240,11 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Les discussions générales en rapport avec AUR (Arch User Repository, dépôt " +"des utilisateurs d’Arch Linux) et les TU (Trusted User, utilisateurs de " +"confiance) ont lieu sur %saur-general%s. Pour les discussions en rapport " +"avec le développement de l'interface web d'AUR, utilisez la mailing-list " +"%saur-dev.%s" msgid "Bug Reporting" msgstr "Rapports de bug" @@ -219,6 +256,10 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Si vous trouvez un bug dans l'interface web d'AUR, merci de remplir un " +"rapport de bug sur le %sbug tracker%s. N’utilisez le tracker %sque%s pour " +"les bugs de AUR. Pour signaler un bug dans un paquet, contactez directement " +"le mainteneur du paquet, ou laissez un commentaire sur la page du paquet." msgid "Package Search" msgstr "Recherche d'un paquet" @@ -304,6 +345,10 @@ msgid "" "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." msgstr "" +"La demande de réinitialisation de mot de passe a été envoyée au compte %s " +"associé à votre adresse e-mail. Si vous voulez réinitialiser votre mot de " +"passe, cliquez sur le lien ci-dessous, sinon ignorez ce message et aucune " +"modification sera effectuée." msgid "Password Reset" msgstr "Réinitialisation de mot de passe" @@ -341,6 +386,8 @@ msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +"Les paquets sélectionnés n'ont pas été destitués, vérifiez la boîte de " +"confirmation." msgid "Cannot find package to merge votes and comments into." msgstr "" @@ -393,32 +440,39 @@ msgstr "Destituer le paquet" #, php-format msgid "Disown Package: %s" -msgstr "" +msgstr "Destituer le paquet : %s" #, php-format msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"Utilisez ce formulaire pour destituer le paquet de base %s%s%s qui inclut " +"les paquets suivants : " #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"En cochant la case, vous confirmez que vous voulez destituer le paquet et " +"transférer sa propriété à %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +"En cochant la case, vous confirmez que vous voulez destituer le paquet." msgid "Confirm to disown the package" -msgstr "" +msgstr "Confirmer la destitution du paquet" msgid "Disown" msgstr "Destituer" msgid "Only Trusted Users and Developers can disown packages." msgstr "" +"Seuls les Utilisateur de Confiance et les Développeurs peuvent destituer des " +"paquets." msgid "Package Merging" msgstr "Fusion de paquet" @@ -454,8 +508,8 @@ msgstr "Fusionner" msgid "Only Trusted Users and Developers can merge packages." msgstr "" -"Seuls les utilisateurs de confiance et les développeurs peuvent fusionner " -"des paquets." +"Seuls les Utilisateur de Confiance et les Développeurs peuvent fusionner des " +"paquets." msgid "File Request" msgstr "Requête de Fichier" @@ -478,6 +532,12 @@ msgstr "Dernière" msgid "Requests" msgstr "Requêtes" +msgid "Register" +msgstr "S’inscrire" + +msgid "Use this form to create an account." +msgstr "Utilisez ce formulaire pour créer un compte." + msgid "Trusted User" msgstr "Utilisateur de confiance (TU)" @@ -538,7 +598,7 @@ msgid "The PGP key fingerprint is invalid." msgstr "L’empreinte de clé PGP est invalide." msgid "The SSH public key is invalid." -msgstr "" +msgstr "La clé SSH publique est invalide." msgid "Cannot increase account permissions." msgstr "Ne peut pas augmenter les autorisations du compte." @@ -556,7 +616,7 @@ msgstr "L’adresse %s%s%s est déjà utilisée." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "La clé SSH publique, %s%s%s, est déjà utilisée." #, php-format msgid "Error trying to create account, %s%s%s." @@ -625,6 +685,10 @@ msgstr "Combinaison entre l'e-mail et la clef de réinitialisation invalides." msgid "None" msgstr "Aucun" +#, php-format +msgid "View account information for %s" +msgstr "Voir les informations du compte pour %s" + msgid "Error retrieving package details." msgstr "Erreur en recherchant les détails du paquet." @@ -722,27 +786,22 @@ msgstr "Le commentaire a été supprimé." msgid "You are not allowed to delete this comment." msgstr "Vous n'êtes pas autorisé(e) à supprimer ce commentaire." -msgid "Missing category ID." -msgstr "ID de catégorie manquant." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Vous n'êtes pas autorisé à éditer les mots-clés de ce paquet de base." -msgid "Invalid category ID." -msgstr "ID de catégorie non valide." - -msgid "You are not allowed to change this package category." -msgstr "Vous n'êtes pas autorisé à modifier la catégorie de ce paquet." - -msgid "Package category changed." -msgstr "Catégorie du paquet changé." +msgid "The package base keywords have been updated." +msgstr "Les mots-clés du paquet de base ont été mis à jour." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +"Vous n'êtes pas autorisé à gérer les co-mainteneurs de ce paquet de base." #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Nom d'utilisateur invalide : %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "Les co-mainteneurs du paquet de base ont été mis à jour." msgid "View packages details for" msgstr "Voir le paquet" @@ -781,7 +840,7 @@ msgstr "" #, php-format msgid "%sWARNING%s: This action cannot be undone." -msgstr "%sWARNING%s: cette action ne peut étre annulée" +msgstr "%sATTENTION%s: cette action ne peut être annulée" msgid "Confirm deletion" msgstr "Confirmer la suppression" @@ -860,9 +919,11 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"L'information suivante est requise uniquement si vous voulez soumettre des " +"paquets sur AUR" msgid "SSH Public Key" -msgstr "" +msgstr "Clé SSH publique" msgid "Update" msgstr "Mise à jour" @@ -896,18 +957,20 @@ msgstr "Plus de résultats à afficher." #, php-format msgid "Manage Co-maintainers: %s" -msgstr "" +msgstr "Gérer les co-mainteneurs : %s" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"Utilisez ce formulaire pour ajouter des co-mainteneurs pour %s%s%s (un nom " +"d'utilisateur par ligne) :" msgid "Users" -msgstr "" +msgstr "Utilisateurs" msgid "Save" -msgstr "" +msgstr "Sauvegarder" msgid "My Packages" msgstr "Mes paquets" @@ -915,15 +978,6 @@ msgstr "Mes paquets" msgid " My Account" msgstr "Mon compte" -msgid "Register" -msgstr "S’inscrire" - -msgid "unknown" -msgstr "inconnu" - -msgid "Package Base Details" -msgstr "Détails du paquet de base" - msgid "Package Actions" msgstr "Actions du paquet" @@ -931,10 +985,10 @@ msgid "View PKGBUILD" msgstr "Voir le PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Voir les changements" msgid "Download snapshot" -msgstr "" +msgstr "Télécharger un instantané" msgid "Search wiki" msgstr "Rechercher sur le wiki" @@ -961,7 +1015,7 @@ msgid "Notify of new comments" msgstr "Avertir des nouveaux commentaires" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "Gérer les co-mainteneurs" #, php-format msgid "%d pending request" @@ -978,22 +1032,24 @@ msgstr "Fusionner le paquet" msgid "Adopt Package" msgstr "Adopter ce paquet" +msgid "unknown" +msgstr "inconnu" + +msgid "Package Base Details" +msgstr "Détails du paquet de base" + msgid "Git Clone URL" -msgstr "" +msgstr "URL de clone (Git)" -msgid "Category" -msgstr "Catégorie" +msgid "read-only" +msgstr "lecture seule" -msgid "Change category" -msgstr "Changer de catégorie" +msgid "Keywords" +msgstr "Mots-clés" msgid "Submitter" msgstr "Contributeur" -#, php-format -msgid "View account information for %s" -msgstr "Voir les informations du compte %s" - msgid "Maintainer" msgstr "Mainteneur" @@ -1200,7 +1256,7 @@ msgid "Name" msgstr "Nom" msgid "Popularity" -msgstr "" +msgstr "Popularité" msgid "Voted" msgstr "Voté" @@ -1217,15 +1273,9 @@ msgstr "Descendant" msgid "Enter search criteria" msgstr "Saisissez les critères de recherche" -msgid "Any" -msgstr "Tous" - msgid "Search by" msgstr "Rechercher par" -msgid "Keywords" -msgstr "Mots-clés" - msgid "Out of Date" msgstr "Périmé" @@ -1259,6 +1309,13 @@ msgstr[1] "%d paquets trouvés." msgid "Version" msgstr "Version" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"La popularité est calculée à partir de la somme de tous les votes, chacun " +"étant pondéré par un facteur de 0.98 par jour depuis sa création." + msgid "Yes" msgstr "Oui" diff --git a/po/he.po b/po/he.po index ff35d48e..853c887e 100644 --- a/po/he.po +++ b/po/he.po @@ -8,10 +8,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Hebrew (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" "he/)\n" "Language: he\n" "MIME-Version: 1.0\n" @@ -53,9 +53,6 @@ msgstr "נא להשתמש בטופס על מנת לחפש אחר חשבונות msgid "You must log in to view user information." msgstr "עליך להתחבר על מנת לצפות בנתוני משתמש." -msgid "Use this form to create an account." -msgstr "ניתן להשתמש בטופס זה על מנת ליצור חשבון." - msgid "Add Proposal" msgstr "הוספת הצעה" @@ -140,6 +137,9 @@ msgid "" "files is at your own risk." msgstr "" +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -183,6 +183,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "דיון" @@ -445,6 +458,12 @@ msgstr "" msgid "Requests" msgstr "" +msgid "Register" +msgstr "" + +msgid "Use this form to create an account." +msgstr "ניתן להשתמש בטופס זה על מנת ליצור חשבון." + msgid "Trusted User" msgstr "משתמש אמין" @@ -579,6 +598,10 @@ msgstr "" msgid "None" msgstr "" +#, php-format +msgid "View account information for %s" +msgstr "" + msgid "Error retrieving package details." msgstr "שגיאה בקבלת נתוני חבילה." @@ -668,16 +691,10 @@ msgstr "הערה נמחקה." msgid "You are not allowed to delete this comment." msgstr "אין לך הרשאה למחוק הערה זו." -msgid "Missing category ID." +msgid "You are not allowed to edit the keywords of this package base." msgstr "" -msgid "Invalid category ID." -msgstr "מס׳ הזיהוי של הקטגוריה אינו תקין" - -msgid "You are not allowed to change this package category." -msgstr "" - -msgid "Package category changed." +msgid "The package base keywords have been updated." msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." @@ -857,15 +874,6 @@ msgstr "החבילות שלי" msgid " My Account" msgstr "" -msgid "Register" -msgstr "" - -msgid "unknown" -msgstr "" - -msgid "Package Base Details" -msgstr "" - msgid "Package Actions" msgstr "" @@ -920,22 +928,24 @@ msgstr "" msgid "Adopt Package" msgstr "" +msgid "unknown" +msgstr "" + +msgid "Package Base Details" +msgstr "" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "קטגוריה" +msgid "read-only" +msgstr "" -msgid "Change category" +msgid "Keywords" msgstr "" msgid "Submitter" msgstr "" -#, php-format -msgid "View account information for %s" -msgstr "" - msgid "Maintainer" msgstr "מתחזק" @@ -1154,15 +1164,9 @@ msgstr "" msgid "Enter search criteria" msgstr "" -msgid "Any" -msgstr "כל" - msgid "Search by" msgstr "חיפוש לפי" -msgid "Keywords" -msgstr "" - msgid "Out of Date" msgstr "" @@ -1196,6 +1200,11 @@ msgstr[1] "" msgid "Version" msgstr "" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "כן" diff --git a/po/hr.po b/po/hr.po index 4adabae9..ef5e289d 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,10 +8,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Croatian (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" "hr/)\n" "Language: hr\n" "MIME-Version: 1.0\n" @@ -54,9 +54,6 @@ msgstr "Koristite ovaj formular za pretraživanj postoječih računa." msgid "You must log in to view user information." msgstr "Morate se logirati kako bi pregledali informacije o korisniku." -msgid "Use this form to create an account." -msgstr "Koristite ovaj formular za kreiranje računa." - msgid "Add Proposal" msgstr "" @@ -141,6 +138,9 @@ msgid "" "files is at your own risk." msgstr "" +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -184,6 +184,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Rasprava" @@ -446,6 +459,12 @@ msgstr "" msgid "Requests" msgstr "" +msgid "Register" +msgstr "" + +msgid "Use this form to create an account." +msgstr "Koristite ovaj formular za kreiranje računa." + msgid "Trusted User" msgstr "Pouzdan korisnik" @@ -580,6 +599,10 @@ msgstr "" msgid "None" msgstr "" +#, php-format +msgid "View account information for %s" +msgstr "" + msgid "Error retrieving package details." msgstr "Došlo je do greške prilikom preuzimanja detalja o paketu." @@ -669,16 +692,10 @@ msgstr "Komentar je izbrisan." msgid "You are not allowed to delete this comment." msgstr "Brisanje ovog komentara Vam nije dozvoljeno." -msgid "Missing category ID." +msgid "You are not allowed to edit the keywords of this package base." msgstr "" -msgid "Invalid category ID." -msgstr "Neispravan ID kategorije." - -msgid "You are not allowed to change this package category." -msgstr "" - -msgid "Package category changed." +msgid "The package base keywords have been updated." msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." @@ -858,15 +875,6 @@ msgstr "Moji paketi" msgid " My Account" msgstr "" -msgid "Register" -msgstr "" - -msgid "unknown" -msgstr "nepoznato" - -msgid "Package Base Details" -msgstr "" - msgid "Package Actions" msgstr "" @@ -922,22 +930,24 @@ msgstr "" msgid "Adopt Package" msgstr "" +msgid "unknown" +msgstr "nepoznato" + +msgid "Package Base Details" +msgstr "" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Kategorija" +msgid "read-only" +msgstr "" -msgid "Change category" +msgid "Keywords" msgstr "" msgid "Submitter" msgstr "" -#, php-format -msgid "View account information for %s" -msgstr "" - msgid "Maintainer" msgstr "Održavatelj" @@ -1158,15 +1168,9 @@ msgstr "" msgid "Enter search criteria" msgstr "" -msgid "Any" -msgstr "Bilo koji" - msgid "Search by" msgstr "Traži po" -msgid "Keywords" -msgstr "" - msgid "Out of Date" msgstr "Zastario" @@ -1201,6 +1205,11 @@ msgstr[2] "" msgid "Version" msgstr "" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Da" diff --git a/po/hu.po b/po/hu.po index 9f5788fd..d7046a8a 100644 --- a/po/hu.po +++ b/po/hu.po @@ -4,16 +4,16 @@ # # Translators: # György Balló , 2013 -# György Balló , 2011,2013-2014 +# György Balló , 2011,2013-2015 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Hungarian (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-07-18 23:05+0000\n" +"Last-Translator: György Balló \n" +"Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" "hu/)\n" "Language: hu\n" "MIME-Version: 1.0\n" @@ -28,11 +28,12 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Sajnálom, a megtekinteni kívánt oldal nem létezik." msgid "Service Unavailable" -msgstr "" +msgstr "Szolgáltatás nem elérhető" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Nyugalom! Ez a webhely karbantartás miatt nem üzemel. Hamarosan visszajövünk." msgid "Account" msgstr "Fiók" @@ -55,9 +56,6 @@ msgstr "Már meglévő felhasználói fiókok kereséséhez használd ezt az űr msgid "You must log in to view user information." msgstr "A felhasználói információ megtekintéshez be kell jelentkezned." -msgid "Use this form to create an account." -msgstr "Használd ezt a űrlapot felhasználói fiók létrehozására." - msgid "Add Proposal" msgstr "Indítvány hozzáadása" @@ -111,7 +109,7 @@ msgid "Submit" msgstr "Feltöltés" msgid "Manage Co-maintainers" -msgstr "" +msgstr "Társkarbantartók kezelése" msgid "Home" msgstr "Honlap" @@ -149,48 +147,80 @@ msgstr "" "szolgáltatott fájlok bármilyen felhasználása csak saját felelősségre " "történik." +msgid "Learn more..." +msgstr "Tudj meg többet..." + msgid "Support" -msgstr "" +msgstr "Támogatás" msgid "Package Requests" -msgstr "" +msgstr "Csomagkérelmek" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Háromfajta kérelem tölthető ki a %sCsomagműveletek%s dobozban a csomag " +"részletei oldalon:" msgid "Orphan Request" -msgstr "" +msgstr "Megtagadási kérelem" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Egy csomag megtagadásának kérése, pl. amikor a karbantartó inaktív, és a " +"csomag régóta elavultnak lett jelölve." msgid "Deletion Request" -msgstr "" +msgstr "Törlési kérelem" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Egy csomag Arch User Repositoriból való törlésének kérése. Kérünk, ne " +"használd ezt, ha a csomag törött, és könnyen javítható. Ehelyett vedd fel a " +"kapcsolatot a csomag karbantartójával, és tölts ki megtagadási kérelmet, ha " +"szükséges." msgid "Merge Request" -msgstr "" +msgstr "Beolvasztási kérelem" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Egy csomag másik csomagba történő beolvasztásának kérése. Akkor használható, " +"amikor egy csomagot át kell nevezni, vagy lecserélésre kerül egy osztott " +"csomagra." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Ha meg szeretnél tárgyalni egy kérelmet, használd az %saur-requests%s " +"levelezőlistát. Azonban ne használd ezt a listát kérvények beadására." + +msgid "Submitting Packages" +msgstr "Csomagok beküldése" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Jelenleg SSH-n keresztüli Git használandó a csomagok beküldéséhez az AUR-ba. " +"További részletekért lásd a %sCsomagok beküldése%s szakaszt az Arch User " +"Repository ArchWiki oldalon." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Az alábbi SSH ujjlenyomatokat használjuk az AUR-hoz:" msgid "Discussion" msgstr "Megbeszélés" @@ -201,6 +231,10 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Az Arch User Repositoryval (AUR) és a Trusted User struktúrával kapcsolatos " +"általános tanácskozás helye az %saur-general%s. Az AUR webes felületének " +"fejlesztésével kapcsolatos tanácskozáshoz az %saur-dev%s levelezőlista " +"használandó." msgid "Bug Reporting" msgstr "Hibajelentés" @@ -212,6 +246,10 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Ha hibát találsz az AUR webes felületén, kérjük, tölts ki egy hibajelentést " +"a %shibabejelentőnkön%s. %sCsak%s az AUR-ban lévő hibák jelentésére használd " +"a bejelentőt. Csomagolási hibák jelentéséhez vedd fel a kapcsolatot a csomag " +"karbantartójával, vagy hagyj egy hozzászólást a megfelelő csomag oldalán." msgid "Package Search" msgstr "Csomag keresése" @@ -297,6 +335,10 @@ msgid "" "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." msgstr "" +"Egy jelszó-visszaállítási kérelem került beküldésre az e-mail címedhez " +"tartozó %s felhasználói fiókhoz. Ha szeretnéd visszaállítani a jelszavad, " +"kövesd az alábbi hivatkozást, egyébként hagyd figyelmen kívül ezt az " +"üzenetet, és nem történik semmi." msgid "Password Reset" msgstr "Jelszó visszaállítása" @@ -334,6 +376,8 @@ msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +"A kiválasztott csomagok nem kerültek megtagadásra, ellenőrizd a megerősítő " +"jelölőnégyzetet." msgid "Cannot find package to merge votes and comments into." msgstr "" @@ -384,32 +428,39 @@ msgstr "Csomag megtagadása" #, php-format msgid "Disown Package: %s" -msgstr "" +msgstr "Csomag megtagadása: %s" #, php-format msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"Használd ezt az űrlapot a(z) %s%s%s alapcsomag megtagadásához, amely a " +"következő csomagokat tartalmazza:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " +"csomagot, és átadni a tulajdonjogot neki: %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " +"csomagot." msgid "Confirm to disown the package" -msgstr "" +msgstr "Csomag megtagadásának megerősítése." msgid "Disown" msgstr "Megtagadás" msgid "Only Trusted Users and Developers can disown packages." msgstr "" +"Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." msgid "Package Merging" msgstr "Csomag beolvasztása" @@ -468,6 +519,12 @@ msgstr "Utolsó" msgid "Requests" msgstr "Kérelmek" +msgid "Register" +msgstr "Regisztráció" + +msgid "Use this form to create an account." +msgstr "Használd ezt a űrlapot felhasználói fiók létrehozására." + msgid "Trusted User" msgstr "Megbízható felhasználó" @@ -528,7 +585,7 @@ msgid "The PGP key fingerprint is invalid." msgstr "A PGP kulcs ujjlenyomata érvénytelen." msgid "The SSH public key is invalid." -msgstr "" +msgstr "A nyilvános SSH kulcs érvénytelen." msgid "Cannot increase account permissions." msgstr "Nem lehet megnövelni a fiók jogosultságait." @@ -546,7 +603,7 @@ msgstr "A(z) %s%s%s cím már használatban van." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "A(z) %s%s%s nyilvános SSH kulcs már használatban van." #, php-format msgid "Error trying to create account, %s%s%s." @@ -613,6 +670,10 @@ msgstr "Érvénytelen e-mail és visszaállító kulcs kombináció." msgid "None" msgstr "Nincs" +#, php-format +msgid "View account information for %s" +msgstr "Fiók információinak megtekintése – %s" + msgid "Error retrieving package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." @@ -703,27 +764,21 @@ msgstr "Megjegyzés törölve." msgid "You are not allowed to delete this comment." msgstr "Nem törölheted ezt a megjegyzést." -msgid "Missing category ID." -msgstr "Hiányzó kategóriaazonosító." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Nem szerkesztheted ennek az alapcsomagnak a kulcsszavait." -msgid "Invalid category ID." -msgstr "Érvénytelen kategóriaazonosító." - -msgid "You are not allowed to change this package category." -msgstr "Nem változtathatod meg ennek a csomagnak a kategóriáját." - -msgid "Package category changed." -msgstr "A csomag kategóriája megváltoztatva." +msgid "The package base keywords have been updated." +msgstr "Az alapcsomag kulcsszavai frissítve lettek." msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "Nem szerkesztheted ennek az alapcsomagnak a társkarbantartóit." #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Érvénytelen felhasználónév: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "Az alapcsomag társkarbantartói frissítve lettek." msgid "View packages details for" msgstr "Csomag részleteinek megtekintése –" @@ -837,9 +892,11 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"Az alábbi információ csak akkor szükséges, ha csomagokat szeretnél beküldeni " +"az Arch User Repositoryba." msgid "SSH Public Key" -msgstr "" +msgstr "Nyilvános SSH kulcs" msgid "Update" msgstr "Frissítés" @@ -873,18 +930,20 @@ msgstr "Nincs több kijelezhető eredmény." #, php-format msgid "Manage Co-maintainers: %s" -msgstr "" +msgstr "Társkarbantartók kezelése: %s" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"Használd ezt az űrlapot társszerkesztők hozzáadásához a(z) %s%s%s csomaghoz " +"(soronként egy felhasználónév):" msgid "Users" -msgstr "" +msgstr "Felhasználók" msgid "Save" -msgstr "" +msgstr "Mentés" msgid "My Packages" msgstr "Csomagjaim" @@ -892,15 +951,6 @@ msgstr "Csomagjaim" msgid " My Account" msgstr " Fiókom" -msgid "Register" -msgstr "Regisztráció" - -msgid "unknown" -msgstr "ismeretlen" - -msgid "Package Base Details" -msgstr "Alapcsomag részletei" - msgid "Package Actions" msgstr "Csomagműveletek" @@ -908,10 +958,10 @@ msgid "View PKGBUILD" msgstr "PKGBUILD megtekintése" msgid "View Changes" -msgstr "" +msgstr "Módosítások megtekintése" msgid "Download snapshot" -msgstr "" +msgstr "Pillanatkép letöltése" msgid "Search wiki" msgstr "Keresés wikiben" @@ -938,7 +988,7 @@ msgid "Notify of new comments" msgstr "Értesítés új hozzászólásról" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "Társszerkesztők kezelése" #, php-format msgid "%d pending request" @@ -955,22 +1005,24 @@ msgstr "Csomag beolvasztása" msgid "Adopt Package" msgstr "Csomag örökbe fogadása" +msgid "unknown" +msgstr "ismeretlen" + +msgid "Package Base Details" +msgstr "Alapcsomag részletei" + msgid "Git Clone URL" -msgstr "" +msgstr "Git klónozási URL" -msgid "Category" -msgstr "Kategória" +msgid "read-only" +msgstr "csak olvasható" -msgid "Change category" -msgstr "Kategória megváltoztatása" +msgid "Keywords" +msgstr "Kulcsszavak" msgid "Submitter" msgstr "Beküldő" -#, php-format -msgid "View account information for %s" -msgstr "Fiók információinak megtekintése – %s" - msgid "Maintainer" msgstr "Karbantartó" @@ -1104,7 +1156,7 @@ msgid "Deletion" msgstr "Törlés" msgid "Orphan" -msgstr "Árva" +msgstr "Megtagadás" msgid "Merge into" msgstr "Beolvasztás ebbe:" @@ -1178,7 +1230,7 @@ msgid "Name" msgstr "Név" msgid "Popularity" -msgstr "" +msgstr "Népszerűség" msgid "Voted" msgstr "Szavazva" @@ -1195,15 +1247,9 @@ msgstr "Csökkenő" msgid "Enter search criteria" msgstr "Keresési feltételek megadása" -msgid "Any" -msgstr "Bármi" - msgid "Search by" msgstr "Keresés eszerint" -msgid "Keywords" -msgstr "Kulcsszavak" - msgid "Out of Date" msgstr "Elavult" @@ -1237,6 +1283,13 @@ msgstr[1] "%d csomag található." msgid "Version" msgstr "Verzió" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat " +"súlyozásra kerül naponta 0,98-as faktorral a létrehozása óta." + msgid "Yes" msgstr "Igen" diff --git a/po/it.po b/po/it.po index c5f83ba0..ef222dd5 100644 --- a/po/it.po +++ b/po/it.po @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-12 13:45+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-23 09:15+0000\n" "Last-Translator: Giovanni Scafora \n" -"Language-Team: Italian (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" "it/)\n" "Language: it\n" "MIME-Version: 1.0\n" @@ -25,7 +25,7 @@ msgid "Page Not Found" msgstr "Impossibile trovare la pagina" msgid "Sorry, the page you've requested does not exist." -msgstr "Spiacenti, la pagina che hai richiesto non esiste." +msgstr "Spiacenti, la pagina richiesta non esiste." msgid "Service Unavailable" msgstr "Servizio non disponibile" @@ -43,7 +43,7 @@ msgid "Accounts" msgstr "Account" msgid "You are not allowed to access this area." -msgstr "Non puoi accedere a quest'area." +msgstr "Non sei autorizzato ad accedere a quest'area." msgid "Could not retrieve information for the specified user." msgstr "Impossibile recuperare le informazioni dell'utente specificato." @@ -57,9 +57,6 @@ msgstr "Usa questo modulo per cercare gli account esistenti." msgid "You must log in to view user information." msgstr "Devi autenticarti per visualizzare le informazioni dell'utente." -msgid "Use this form to create an account." -msgstr "Usa questo modulo per creare un account." - msgid "Add Proposal" msgstr "Aggiungi una proposta" @@ -83,7 +80,7 @@ msgid "New proposal submitted." msgstr "La nuova proposta è stata inviata." msgid "Submit a proposal to vote on." -msgstr "Invia una proposta di voto." +msgstr "Invia una proposta da votare." msgid "Applicant/TU" msgstr "Candidato/TU" @@ -123,8 +120,8 @@ msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" -"Benvenuto in AUR! Per ottenere maggiori informazioni, leggi le %sAUR User " -"Guidelines%s e le %sAUR TU Guidelines%s." +"Benvenuto in AUR! Per maggiori informazioni, leggi le %sAUR User Guidelines" +"%s e le %sAUR TU Guidelines%s." #, php-format msgid "" @@ -149,9 +146,12 @@ msgid "" "Unsupported packages are user produced content. Any use of the provided " "files is at your own risk." msgstr "" -"I pacchetti presenti in AUR sono stati inviati dagli utenti. Usali a tuo " +"i pacchetti presenti in AUR sono stati inviati dagli utenti. Usali a tuo " "rischio e pericolo." +msgid "Learn more..." +msgstr "Ulteriori informazioni..." + msgid "Support" msgstr "Supporto" @@ -163,8 +163,8 @@ msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" -"Ci sono tre tipi di richieste che possono essere effettuate tramite il box " -"%sAzioni del pacchetto%s, presente sulla pagina dei dettagli del pacchetto:" +"Ci sono tre tipi di richieste che si possono effettuare dal riquadro " +"%sAzioni del pacchetto%s presente nella pagina dei dettagli del pacchetto:" msgid "Orphan Request" msgstr "Richiesta di un pacchetto orfano" @@ -185,20 +185,20 @@ msgid "" "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -"richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usate " -"questo se il pacchetto non funziona e se può essere sistemato facilmente. " -"Contattate il manutentore del pacchetto e, se necessario, inviate una " -"richiesta per renderlo orfano." +"richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usare " +"questo tipo di richiesta se un pacchetto non funziona e se può essere " +"sistemato facilmente. Contatta il manutentore del pacchetto e, se " +"necessario, invia una richiesta per renderlo orfano." msgid "Merge Request" -msgstr "Richiesta di unione" +msgstr "Richiesta di unione di un pacchetto" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" "richiesta di un pacchetto da unire con un altro. Può essere usata quando un " -"pacchetto necessita di essere rinominato o sostituito da un pacchetto " +"pacchetto necessita di essere rinominato o rimpiazzato da un pacchetto " "suddiviso" #, php-format @@ -207,7 +207,23 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" "Se vuoi discutere una richiesta, puoi usare la lista di discussione %saur-" -"requests%s. Non usare questa lista per inoltrare le tue richieste." +"requests%s. Non usare questa lista per inoltrare richieste." + +msgid "Submitting Packages" +msgstr "Invio dei pacchetti" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Per inviare i pacchetti in AUR, adesso, si utilizza Git via SSH. Per " +"maggiori informazioni, vedi la sezione %sInviare i pacchetti%s della pagina " +"Arch User Repository dell'ArchWiki." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Per AUR si usano le seguenti fingerprint SSH:" msgid "Discussion" msgstr "Discussione" @@ -233,9 +249,9 @@ msgid "" "the appropriate package page." msgstr "" "Se trovi un bug nell'interfaccia web di AUR, invia un report al nostro %sbug " -"tracker%s. Usa il tracker %ssolo%s per inviare i bug di AUR. Per inviare bug " -"inerenti alla pacchettizzazione, contatta il manutentore oppure lascia un " -"commento sulla pagina del pacchetto." +"tracker%s. Usa il tracker %ssolo%s per inviare i bug di AUR. Per segnalare " +"bug inerenti alla pacchettizzazione, contatta il manutentore oppure lascia " +"un commento nella pagina del pacchetto." msgid "Package Search" msgstr "Ricerca dei pacchetti" @@ -294,7 +310,7 @@ msgstr "" "HTTPs%s." msgid "Search Criteria" -msgstr "Criterio di ricerca" +msgstr "Criteri di ricerca" msgid "Packages" msgstr "Pacchetti" @@ -322,19 +338,19 @@ msgid "" "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." msgstr "" -"È stata inviata una richiesta per resettare la password dell'account %s " -"associato al tuo indirizzo e-mail. Se desideri resettare la tua password, " +"È stata inviata una richiesta per ripristinare la password dell'account %s " +"associato al tuo indirizzo e-mail. Se desideri ripristinare la tua password, " "clicca sul link sottostante, altrimenti ignora questo messaggio e non " "succederà nulla." msgid "Password Reset" -msgstr "Resetta la password" +msgstr "Ripristina la password" msgid "Check your e-mail for the confirmation link." msgstr "Controlla la tua e-mail per il link di conferma." msgid "Your password has been reset successfully." -msgstr "La tua password è stata resettata con successo." +msgstr "La tua password è stata ripristinata con successo." msgid "Confirm your e-mail address:" msgstr "Conferma il tuo indirizzo e-mail:" @@ -353,8 +369,8 @@ msgid "" "If you have forgotten the e-mail address you used to register, please send a " "message to the %saur-general%s mailing list." msgstr "" -"Se hai dimenticato l'indirizzo e-mail che hai utilizzato per registrarti, " -"invia un messaggio nella mailing list %saur-general%s." +"Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un " +"messaggio nella mailing list %saur-general%s." msgid "Enter your e-mail address:" msgstr "Inserisci il tuo indirizzo email:" @@ -377,7 +393,7 @@ msgstr "Impossibile unire un pacchetto base con se stesso." msgid "" "The selected packages have not been deleted, check the confirmation checkbox." msgstr "" -"I pacchetti selezionati non sono stati eliminati, conferma la tua scelta, " +"I pacchetti selezionati non sono stati eliminati, conferma la tua scelta " "inserendo un segno di spunta nell'apposita casella di controllo." msgid "Package Deletion" @@ -402,7 +418,7 @@ msgid "Select the checkbox to confirm action." msgstr "Seleziona la casella di controllo per confermare l'azione richiesta." msgid "Confirm package deletion" -msgstr "Conferma la rimozione del pacchetto" +msgstr "Conferma di voler rimuovere il pacchetto" msgid "Delete" msgstr "Elimina" @@ -440,7 +456,7 @@ msgstr "" "pacchetto." msgid "Confirm to disown the package" -msgstr "Conferma di abbandonare il pacchetto" +msgstr "Conferma di voler abbandonare il pacchetto" msgid "Disown" msgstr "Abbandona" @@ -449,7 +465,7 @@ msgid "Only Trusted Users and Developers can disown packages." msgstr "Solo i TU e gli sviluppatori possono abbandonare i pacchetti." msgid "Package Merging" -msgstr "Fusione dei pacchetti" +msgstr "Unione dei pacchetti" #, php-format msgid "Merge Package: %s" @@ -458,10 +474,10 @@ msgstr "Unisci il pacchetto: %s" #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -"Usa questo modulo per unire il pacchetto base %s%s%s in un altro pacchetto." +"Usa questo modulo per unire il pacchetto base %s%s%s con un altro pacchetto." msgid "The following packages will be deleted: " -msgstr "I seguenti pacchetti verranno eliminati:" +msgstr "I seguenti pacchetti saranno eliminati:" msgid "Once the package has been merged it cannot be reversed. " msgstr "" @@ -475,7 +491,7 @@ msgid "Merge into:" msgstr "Unisci con:" msgid "Confirm package merge" -msgstr "Conferma l'unione del pacchetto" +msgstr "Conferma di voler unire il pacchetto" msgid "Merge" msgstr "Unisci" @@ -484,7 +500,7 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo i TU e gli sviluppatori possono unire i pacchetti." msgid "File Request" -msgstr "Richiesta di file" +msgstr "Invia richiesta" msgid "Close Request" msgstr "Chiudi la richiesta" @@ -504,6 +520,12 @@ msgstr "Ultimo" msgid "Requests" msgstr "Richieste" +msgid "Register" +msgstr "Registrati" + +msgid "Use this form to create an account." +msgstr "Usa questo modulo per creare un account." + msgid "Trusted User" msgstr "TU" @@ -514,7 +536,7 @@ msgid "Voting is closed for this proposal." msgstr "Non puoi più votare per questa proposta." msgid "Only Trusted Users are allowed to vote." -msgstr "Solo i Trusted User possono votare." +msgstr "Solo i TU possono votare." msgid "You cannot vote in an proposal about you." msgstr "Non puoi votare per una proposta che ti riguarda in prima persona." @@ -537,7 +559,10 @@ msgstr "Votanti" msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "È stato inviato un key reset della password al tuo indirizzo e-mail." +msgstr "" +"La registrazione dell'account è stata disabilitata per il tuo indirizzo IP, " +"probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per " +"l'inconveniente." msgid "Missing User ID" msgstr "Manca l'ID dell'utente" @@ -559,13 +584,13 @@ msgid "The email address is invalid." msgstr "L'indirizzo email non risulta valido." msgid "The PGP key fingerprint is invalid." -msgstr "L'impronta della chiave PGP non è valida." +msgstr "La fingerprint della chiave PGP non è valida." msgid "The SSH public key is invalid." msgstr "La chiave pubblica SSH non è valida." msgid "Cannot increase account permissions." -msgstr "Non è possibile aumentare i permessi dell'account." +msgstr "Non è possibile incrementare i permessi dell'account." msgid "Language is not currently supported." msgstr "Lingua attualmente non supportata." @@ -580,7 +605,7 @@ msgstr "L'indirizzo %s%s%s è già in uso." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "La chiave pubblica SSH, %s%s%s, è già in uso." +msgstr "La chiave pubblica SSH %s%s%s, è già in uso." #, php-format msgid "Error trying to create account, %s%s%s." @@ -604,7 +629,9 @@ msgstr "" "copiarlo e ad incollarlo nella barra degli indirizzi del tuo browser." msgid "A password reset key has been sent to your e-mail address." -msgstr "È stato inviato un key reset della password al tuo indirizzo e-mail." +msgstr "" +"È stata inviata una chiave di ripristino della password al tuo indirizzo e-" +"mail." #, php-format msgid "No changes were made to the account, %s%s%s." @@ -631,9 +658,10 @@ msgid "" "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." msgstr "" -"La tua password è stata resettata. Se hai appena creato un nuovo account, " -"usa il link presente nell'email di conferma, per impostare una password " -"iniziale. Altrimenti, richiedi un key reset dalla pagina %sPassword Reset%s." +"La tua password è stata ripristinata. Se hai creato da poco un nuovo " +"account, usa il link presente nell'email di conferma, per impostare una " +"password iniziale. Altrimenti, richiedi il ripristino della password dalla " +"pagina %sRipristina la password%s." msgid "Bad username or password." msgstr "Nome utente o password errati." @@ -643,11 +671,15 @@ msgstr "" "Si è verificato un errore provando a generare una sessione dell'utente." msgid "Invalid e-mail and reset key combination." -msgstr "Combinazione non valida del pulsante reset e dell'e-mail." +msgstr "La combinazione e-mail e chiave di ripristino non è valida." msgid "None" msgstr "Nessuno" +#, php-format +msgid "View account information for %s" +msgstr "Mostra le informazioni dell'account %s" + msgid "Error retrieving package details." msgstr "" "Si è verificato un errore durante il recupero dei dettagli del pacchetto." @@ -686,7 +718,7 @@ msgid "The selected packages have been deleted." msgstr "I pacchetti selezionati sono stati eliminati." msgid "You must be logged in before you can adopt packages." -msgstr "Devi autenticarti prima di poter adottare dei pacchetti." +msgstr "Devi autenticarti prima di poter adottare i pacchetti." msgid "You must be logged in before you can disown packages." msgstr "Devi autenticarti prima di poter abbandonare i pacchetti." @@ -740,19 +772,14 @@ msgid "Comment has been deleted." msgstr "Il commento è stato rimosso." msgid "You are not allowed to delete this comment." -msgstr "Non puoi rimuovere questo commento." +msgstr "Non sei autorizzato a rimuovere questo commento." -msgid "Missing category ID." -msgstr "Manca l'ID della categoria." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" +"Non sei autorizzato a modificare le parole chiave di questo pacchetto base." -msgid "Invalid category ID." -msgstr "L'ID della categoria non è valido." - -msgid "You are not allowed to change this package category." -msgstr "Non puoi modificare la categoria di questo pacchetto." - -msgid "Package category changed." -msgstr "La categoria del pacchetto è stata modificata." +msgid "The package base keywords have been updated." +msgstr "Le parole chiave del pacchetto base sono state aggiornate." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -766,7 +793,7 @@ msgid "The package base co-maintainers have been updated." msgstr "I co-menutentori del pacchetto base sono stati aggiornati." msgid "View packages details for" -msgstr "Visualizza i dettagli dei pacchetti di" +msgstr "Mostra i dettagli dei pacchetti di" msgid "You must be logged in to file package requests." msgstr "Devi autenticarti per richiedere i pacchetti." @@ -795,14 +822,14 @@ msgstr "La richiesta è stata chiusa con successo." #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -"Puoi usare questo modulo per eliminare definitivamente l'account %s di AUR." +"Puoi usare questo modulo per eliminare definitivamente da AUR l'account %s." #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sATTENZIONE%s: questa azione non può essere incompiuta." msgid "Confirm deletion" -msgstr "Conferma l'eliminazione" +msgstr "Conferma la rimozione" msgid "Account Type" msgstr "Tipo di account" @@ -814,7 +841,7 @@ msgid "Developer" msgstr "Sviluppatore" msgid "Trusted User & Developer" -msgstr "Trusted User e Sviluppatore" +msgstr "TU e sviluppatore" msgid "Email Address" msgstr "Indirizzo email" @@ -844,10 +871,10 @@ msgid "Never" msgstr "Mai" msgid "View this user's packages" -msgstr "Visualizza i pacchetti di quest'utente" +msgstr "Mostra i pacchetti di quest'utente" msgid "Edit this user's account" -msgstr "Modifica l'account di questo utente" +msgstr "Modifica l'account di quest'utente" #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -894,7 +921,7 @@ msgid "Reset" msgstr "Cancella" msgid "No results matched your search criteria." -msgstr "Nessun risultato corrisponde ai criteri della ricerca." +msgstr "Nessun risultato corrisponde ai tuoi criteri di ricerca." msgid "Edit Account" msgstr "Modifica l'account" @@ -912,7 +939,7 @@ msgid "More" msgstr "Successivo" msgid "No more results to display." -msgstr "Non vi sono ulteriori risultati da visualizzare." +msgstr "Non vi sono ulteriori risultati da mostrare." #, php-format msgid "Manage Co-maintainers: %s" @@ -937,29 +964,20 @@ msgstr "I miei pacchetti" msgid " My Account" msgstr "Il mio account" -msgid "Register" -msgstr "Registrati" - -msgid "unknown" -msgstr "sconosciuta" - -msgid "Package Base Details" -msgstr "Dettagli del pacchetto base" - msgid "Package Actions" msgstr "Azioni del pacchetto" msgid "View PKGBUILD" -msgstr "Visualizza il PKGBUILD" +msgstr "Mostra il PKGBUILD" msgid "View Changes" -msgstr "Mostra i cambiamenti" +msgstr "Mostra le modifiche" msgid "Download snapshot" msgstr "Scarica lo snapshot" msgid "Search wiki" -msgstr "Cerca nella wiki" +msgstr "Cerca nel wiki" msgid "Flagged out-of-date" msgstr "Il pacchetto non è aggiornato" @@ -1000,22 +1018,24 @@ msgstr "Unisci il pacchetto" msgid "Adopt Package" msgstr "Adotta il pacchetto" +msgid "unknown" +msgstr "sconosciuta" + +msgid "Package Base Details" +msgstr "Dettagli del pacchetto base" + msgid "Git Clone URL" msgstr "Git Clone URL" -msgid "Category" -msgstr "Categoria" +msgid "read-only" +msgstr "sola lettura" -msgid "Change category" -msgstr "Cambia la categoria" +msgid "Keywords" +msgstr "Parole chiave" msgid "Submitter" msgstr "Contributore" -#, php-format -msgid "View account information for %s" -msgstr "Visualizza le informazioni dell'account %s" - msgid "Maintainer" msgstr "Manutentore" @@ -1038,7 +1058,7 @@ msgid "Comment has been added." msgstr "Il commento è stato inserito." msgid "View all comments" -msgstr "Vedi tutti i commenti" +msgstr "Mostra tutti i commenti" msgid "Latest Comments" msgstr "Ultimi commenti" @@ -1130,7 +1150,7 @@ msgstr "Commenti" #, php-format msgid "File Request: %s" -msgstr "Richiesta di file: %s" +msgstr "Invia una richiesta per: %s" #, php-format msgid "" @@ -1144,10 +1164,10 @@ msgid "Request type" msgstr "Tipo di richiesta" msgid "Deletion" -msgstr "Eliminazione" +msgstr "Elimina" msgid "Orphan" -msgstr "Orfano" +msgstr "Abbandona" msgid "Merge into" msgstr "Unisci con" @@ -1160,7 +1180,7 @@ msgstr[1] "Sono stati trovati %d pacchetti." #, php-format msgid "Page %d of %d." -msgstr "Pagina %d du %d." +msgstr "Pagina %d di %d." msgid "Package" msgstr "Pacchetto" @@ -1236,17 +1256,11 @@ msgid "Descending" msgstr "Discendente" msgid "Enter search criteria" -msgstr "Inserisci un criterio di ricerca" - -msgid "Any" -msgstr "Qualsiasi" +msgstr "Seleziona i criteri di ricerca" msgid "Search by" msgstr "Cerca per" -msgid "Keywords" -msgstr "Parole chiave" - msgid "Out of Date" msgstr "Non aggiornati" @@ -1260,7 +1274,7 @@ msgid "Per page" msgstr "Per pagina" msgid "Go" -msgstr "Vai" +msgstr "Cerca" msgid "Orphans" msgstr "Orfani" @@ -1270,7 +1284,7 @@ msgstr "" "Si è verificato un errore durante il recupero della lista dei pacchetti." msgid "No packages matched your search criteria." -msgstr "Nessun pacchetto corrisponde ai criteri della ricerca." +msgstr "Nessun pacchetto corrisponde ai tuoi criteri di ricerca." #, php-format msgid "%d package found." @@ -1281,6 +1295,13 @@ msgstr[1] "Sono stati trovati %d pacchetti." msgid "Version" msgstr "Versione" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"La popolarità viene calcolata come la somma di tutti i voti con ogni voto " +"ponderato con un fattore di 0,98 al giorno dalla sua creazione." + msgid "Yes" msgstr "Sì" @@ -1376,7 +1397,7 @@ msgid "Participation" msgstr "Partecipazione" msgid "Last Votes by TU" -msgstr "Ultimi voti dai TU" +msgstr "Ultimi voti dei TU" msgid "Last vote" msgstr "Ultimo voto" diff --git a/po/ja.po b/po/ja.po index 7d300a6b..d95ee440 100644 --- a/po/ja.po +++ b/po/ja.po @@ -5,15 +5,15 @@ # Translators: # kusakata , 2013 # kusakata , 2013 -# kusakata , 2013-2014 +# kusakata , 2013-2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Japanese (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-08-04 12:23+0000\n" +"Last-Translator: kusakata \n" +"Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" "ja/)\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -28,11 +28,13 @@ msgid "Sorry, the page you've requested does not exist." msgstr "あなたがリクエストしたページは存在しませんでした。" msgid "Service Unavailable" -msgstr "" +msgstr "Service Unavailable" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"落ち着いて下さい!このサイトはメンテナンスのためにダウンしています。すぐに復" +"帰する予定です。" msgid "Account" msgstr "アカウント" @@ -55,9 +57,6 @@ msgstr "アカウントの検索はこのフォームを使って下さい。" msgid "You must log in to view user information." msgstr "ユーザー情報を見るにはログインする必要があります。" -msgid "Use this form to create an account." -msgstr "このフォームを使ってアカウントを作成してください。" - msgid "Add Proposal" msgstr "提案を追加する" @@ -111,7 +110,7 @@ msgid "Submit" msgstr "投稿" msgid "Manage Co-maintainers" -msgstr "" +msgstr "共同メンテナの管理" msgid "Home" msgstr "ホーム" @@ -149,48 +148,80 @@ msgstr "" "ユーザーが作成したパッケージにサポートはありません。それぞれのファイルの利用" "は自己責任でお願いします。" +msgid "Learn more..." +msgstr "詳細..." + msgid "Support" -msgstr "" +msgstr "サポート" msgid "Package Requests" -msgstr "" +msgstr "パッケージリクエスト" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"各パッケージの詳細ページにある%sパッケージアクション%sボックスから送信するこ" +"とができるリクエストは3種類あります:" msgid "Orphan Request" -msgstr "" +msgstr "孤児リクエスト" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"パッケージを孤児にするようにリクエストします。メンテナが活動を停止していて" +"パッケージが長い間 out-of-date のまま放置されている場合などに使います。" msgid "Deletion Request" -msgstr "" +msgstr "削除リクエスト" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Arch User Repository からパッケージを削除するようにリクエストします。パッケー" +"ジが壊れていて、その不具合を簡単に修正できるような場合、このリクエストは使わ" +"ないで下さい。代わりに、パッケージのメンテナに連絡したり、必要に応じて孤児リ" +"クエストを送りましょう。" msgid "Merge Request" -msgstr "" +msgstr "マージリクエスト" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"あるパッケージを他のパッケージとマージするようにリクエストします。パッケージ" +"の名前を変更する必要があるときや分割パッケージによって置き換えるときに使用し" +"ます。" #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"リクエストについて議論したい場合、%saur-requests%s メーリングリストを使いま" +"す。ただし、このメーリングリスト宛にリクエストを送るのは止めて下さい。" + +msgid "Submitting Packages" +msgstr "パッケージの投稿" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"現在 AUR にパッケージを送信するときは SSH を介して Git を使うことになっていま" +"す。詳しくは ArchWiki の Arch User Repository のページの%sパッケージの投稿%s" +"セクションを見て下さい。" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "AUR では以下の SSH フィンガープリントが使われます:" msgid "Discussion" msgstr "議論" @@ -201,6 +232,9 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Arch User Repository (AUR) や Trusted User に関する一般的な議論は %saur-" +"general%s で行って下さい。AUR ウェブインターフェイスの開発に関しては、%saur-" +"dev%s メーリングリストを使用します。" msgid "Bug Reporting" msgstr "バグレポート" @@ -212,6 +246,10 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"AUR ウェブインターフェイスにバグを発見した場合、私たちの%sバグトラッカー%sに" +"バグを報告してください。AUR のバグを報告するとき%sのみ%sにこのトラッカーを" +"使って下さい。パッケージのバグについては、パッケージメンテナに連絡するか適切" +"なパッケージページにコメントを残して下さい。" msgid "Package Search" msgstr "パッケージ検索" @@ -296,6 +334,9 @@ msgid "" "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." msgstr "" +"あなたのメールアドレスと関連付けられたアカウント %s のパスワードのリセットリ" +"クエストが送信されました。パスワードをリセットしたいときは下のリンクを開いて" +"下さい、そうでない場合はこのメッセージは無視して下さい。" msgid "Password Reset" msgstr "パスワードのリセット" @@ -333,6 +374,8 @@ msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +"選択されたパッケージは孤児になっていません。確認チェックボックスにチェックを" +"入れて下さい。" msgid "Cannot find package to merge votes and comments into." msgstr "投票やコメントのマージをするパッケージが見つかりません。" @@ -381,32 +424,37 @@ msgstr "パッケージの放棄" #, php-format msgid "Disown Package: %s" -msgstr "" +msgstr "孤児にするパッケージ: %s" #, php-format msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"このフォームを使って以下のパッケージを含むパッケージベース %s%s%s を孤児にす" +"ることができます:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"チェックボックスを選択して、パッケージを孤児にして所有権を %s%s%s に移すこと" +"を確定して下さい。" msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +"チェックボックスを選択して、パッケージを孤児にすることを確定してください。" msgid "Confirm to disown the package" -msgstr "" +msgstr "パッケージを孤児にすることの確認" msgid "Disown" msgstr "放棄" msgid "Only Trusted Users and Developers can disown packages." -msgstr "" +msgstr "Trusted User と開発者だけがパッケージを孤児にできます。" msgid "Package Merging" msgstr "パッケージのマージ" @@ -463,6 +511,12 @@ msgstr "最後" msgid "Requests" msgstr "リクエスト" +msgid "Register" +msgstr "登録" + +msgid "Use this form to create an account." +msgstr "このフォームを使ってアカウントを作成してください。" + msgid "Trusted User" msgstr "Trusted User" @@ -523,7 +577,7 @@ msgid "The PGP key fingerprint is invalid." msgstr "PGP 鍵のフィンガープリントが不正です。" msgid "The SSH public key is invalid." -msgstr "" +msgstr "SSH 公開鍵が不正です。" msgid "Cannot increase account permissions." msgstr "アカウント権限を増やすことはできません。" @@ -541,7 +595,7 @@ msgstr "%s%s%s というメールアドレスは既に使われています。" #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "SSH 公開鍵、%s%s%s は既に使われています。" #, php-format msgid "Error trying to create account, %s%s%s." @@ -606,6 +660,10 @@ msgstr "メールアドレスとリセットキーの不正な組み合わせ。 msgid "None" msgstr "なし" +#, php-format +msgid "View account information for %s" +msgstr "%s のアカウント情報を見る" + msgid "Error retrieving package details." msgstr "パッケージの詳細の取得エラー。" @@ -695,27 +753,21 @@ msgstr "コメントが削除されました。" msgid "You are not allowed to delete this comment." msgstr "このコメントを削除することはできません。" -msgid "Missing category ID." -msgstr "カテゴリ ID がありません。" +msgid "You are not allowed to edit the keywords of this package base." +msgstr "このパッケージベースのキーワードを編集することはできません。" -msgid "Invalid category ID." -msgstr "不正なカテゴリ ID です。" - -msgid "You are not allowed to change this package category." -msgstr "このパッケージのカテゴリを変更することはできません。" - -msgid "Package category changed." -msgstr "パッケージのカテゴリが変更されました。" +msgid "The package base keywords have been updated." +msgstr "パッケージベースのキーワードは更新されました。" msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "このパッケージベースの共同メンテナを管理することはできません。" #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "不正なユーザー名: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "パッケージベースの共同メンテナが更新されました。" msgid "View packages details for" msgstr "パッケージの詳細を見る" @@ -830,9 +882,11 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"以下の情報は Arch User Repository にパッケージを送信したい場合にのみ必要にな" +"ります。" msgid "SSH Public Key" -msgstr "" +msgstr "SSH 公開鍵" msgid "Update" msgstr "更新" @@ -866,18 +920,20 @@ msgstr "表示する結果はもうありません。" #, php-format msgid "Manage Co-maintainers: %s" -msgstr "" +msgstr "共同メンテナの管理: %s" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"このフォームを使って %s%s%s の共同メンテナを追加することができます (一行につ" +"き一人のユーザー名を入力):" msgid "Users" -msgstr "" +msgstr "ユーザー" msgid "Save" -msgstr "" +msgstr "保存" msgid "My Packages" msgstr "自分のパッケージ" @@ -885,15 +941,6 @@ msgstr "自分のパッケージ" msgid " My Account" msgstr "アカウント" -msgid "Register" -msgstr "登録" - -msgid "unknown" -msgstr "不明" - -msgid "Package Base Details" -msgstr "パッケージベースの詳細" - msgid "Package Actions" msgstr "パッケージアクション" @@ -901,10 +948,10 @@ msgid "View PKGBUILD" msgstr "PKGBUILD を見る" msgid "View Changes" -msgstr "" +msgstr "変更履歴" msgid "Download snapshot" -msgstr "" +msgstr "スナップショットのダウンロード" msgid "Search wiki" msgstr "wiki を検索" @@ -931,7 +978,7 @@ msgid "Notify of new comments" msgstr "新しいコメントを通知" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "共同メンテナの管理" #, php-format msgid "%d pending request" @@ -947,22 +994,24 @@ msgstr "パッケージのマージ" msgid "Adopt Package" msgstr "パッケージを承継する" +msgid "unknown" +msgstr "不明" + +msgid "Package Base Details" +msgstr "パッケージベースの詳細" + msgid "Git Clone URL" -msgstr "" +msgstr "Git クローン URL" -msgid "Category" -msgstr "カテゴリ" +msgid "read-only" +msgstr "リードオンリー" -msgid "Change category" -msgstr "カテゴリの変更" +msgid "Keywords" +msgstr "キーワード" msgid "Submitter" msgstr "投稿者" -#, php-format -msgid "View account information for %s" -msgstr "%s のアカウント情報を見る" - msgid "Maintainer" msgstr "メンテナ" @@ -1168,7 +1217,7 @@ msgid "Name" msgstr "名前" msgid "Popularity" -msgstr "" +msgstr "人気度" msgid "Voted" msgstr "投票済" @@ -1185,15 +1234,9 @@ msgstr "降順" msgid "Enter search criteria" msgstr "検索条件を入力" -msgid "Any" -msgstr "全て" - msgid "Search by" msgstr "検索対象" -msgid "Keywords" -msgstr "キーワード" - msgid "Out of Date" msgstr "Out of Date" @@ -1226,6 +1269,12 @@ msgstr[0] "パッケージが %d 個見つかりました。" msgid "Version" msgstr "バージョン" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"人気度は各投票に作成日からの日数を0.98倍した全投票の合計で計算されます。" + msgid "Yes" msgstr "はい" diff --git a/po/nb.po b/po/nb.po index ee2e2514..e7f2398f 100644 --- a/po/nb.po +++ b/po/nb.po @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Norwegian Bokmål (http://www.transifex.com/projects/p/aur/" +"Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" "language/nb/)\n" "Language: nb\n" "MIME-Version: 1.0\n" @@ -55,9 +55,6 @@ msgstr "Bruk dette skjemaet for å lete etter eksisterende kontoer." msgid "You must log in to view user information." msgstr "Du må logge inn for å se brukerinformasjon." -msgid "Use this form to create an account." -msgstr "Bruk dette feltet for å opprette en konto." - msgid "Add Proposal" msgstr "Legg til forslag" @@ -148,6 +145,9 @@ msgstr "" "Uoffisielle pakker har innhold produsert av andre brukere. All bruk av de " "tilgjengelige filene er på eget ansvar." +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -191,6 +191,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Diskusjon" @@ -461,6 +474,12 @@ msgstr "Siste" msgid "Requests" msgstr "Forespørsler" +msgid "Register" +msgstr "Registrer" + +msgid "Use this form to create an account." +msgstr "Bruk dette feltet for å opprette en konto." + msgid "Trusted User" msgstr "Betrodd bruker" @@ -607,6 +626,10 @@ msgstr "Ugyldig kombinasjon av e-post og nullstillingsnøkkel." msgid "None" msgstr "Ingen" +#, php-format +msgid "View account information for %s" +msgstr "Vis kontoinformasjon for %s" + msgid "Error retrieving package details." msgstr "Kunne ikke finne frem pakkedetaljer." @@ -697,17 +720,11 @@ msgstr "Kommentar slettet." msgid "You are not allowed to delete this comment." msgstr "Du har ikke tilgang til å slette denne kommentaren." -msgid "Missing category ID." -msgstr "Manglende kategori-ID." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "Ugyldig kategori-ID." - -msgid "You are not allowed to change this package category." -msgstr "Du har ikke tilgang til å endre denne pakkekategorien." - -msgid "Package category changed." -msgstr "Pakkekategori endret." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -886,15 +903,6 @@ msgstr "Mine pakker" msgid " My Account" msgstr " Min konto" -msgid "Register" -msgstr "Registrer" - -msgid "unknown" -msgstr "ukjent" - -msgid "Package Base Details" -msgstr "Grunnpakkedetaljer" - msgid "Package Actions" msgstr "Pakkehandlinger" @@ -949,22 +957,24 @@ msgstr "Slå sammen pakke" msgid "Adopt Package" msgstr "Adopter pakke" +msgid "unknown" +msgstr "ukjent" + +msgid "Package Base Details" +msgstr "Grunnpakkedetaljer" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Kategori" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "Endre kategori" +msgid "Keywords" +msgstr "Nøkkelord" msgid "Submitter" msgstr "Innsender" -#, php-format -msgid "View account information for %s" -msgstr "Vis kontoinformasjon for %s" - msgid "Maintainer" msgstr "Vedlikeholder" @@ -1187,15 +1197,9 @@ msgstr "Synkende" msgid "Enter search criteria" msgstr "Fyll ut søkekriterier" -msgid "Any" -msgstr "Hvilken som helst" - msgid "Search by" msgstr "Søk etter" -msgid "Keywords" -msgstr "Nøkkelord" - msgid "Out of Date" msgstr "Foreldet" @@ -1229,6 +1233,11 @@ msgstr[1] "Fant %d pakker." msgid "Version" msgstr "Versjon" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Ja" diff --git a/po/nl.po b/po/nl.po index 2f2869bd..c85a2a37 100644 --- a/po/nl.po +++ b/po/nl.po @@ -3,17 +3,19 @@ # This file is distributed under the same license as the PACKAGE package. # # Translators: +# Heimen Stoffels , 2015 # jelly , 2011 # Sietse , 2013 # Sietse , 2013 +# Wijnand Modderman-Lenstra , 2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Dutch (http://www.transifex.com/projects/p/aur/language/nl/)\n" +"Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,63 +23,62 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Page Not Found" -msgstr "Pagina niet gevonden" +msgstr "De pagina kon niet worden gevonden" msgid "Sorry, the page you've requested does not exist." -msgstr "Sorry, de pagina die je hebt aangevraagd bestaat niet." +msgstr "Sorry, de pagina die u heeft aangevraagd bestaat niet." msgid "Service Unavailable" -msgstr "" +msgstr "De dienst is niet beschikbaar" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Raak niet in paniek! De website is uit de lucht wegens werkzaamheden. We " +"zullen snel weer terug in de lucht zijn." msgid "Account" -msgstr "" +msgstr "Account" msgid "Accounts" msgstr "Accounts" msgid "You are not allowed to access this area." -msgstr "Geen toegang tot dit gebied." +msgstr "U heeft geen toegang tot dit gebied." msgid "Could not retrieve information for the specified user." msgstr "Kon geen informatie ophalen voor de opgegeven gebruiker." msgid "You do not have permission to edit this account." -msgstr "Je hebt geen toestemming om dit account te bewerken." +msgstr "U heeft geen toestemming om dit account te bewerken." msgid "Use this form to search existing accounts." -msgstr "Gebruik dit formulier om bestaande accounts zoeken." +msgstr "Gebruik dit formulier om bestaande accounts te zoeken." msgid "You must log in to view user information." msgstr "U moet inloggen om de gebruikersinformatie te bekijken." -msgid "Use this form to create an account." -msgstr "Gebruik dit formulier om een ​​account aan te maken." - msgid "Add Proposal" -msgstr "Voeg Voorstel Toe" +msgstr "Voorstel toevoegen" msgid "Invalid token for user action." msgstr "Ongeldige token voor gebruikersactie." msgid "Username does not exist." -msgstr "Gebruikersnaam bestaat niet." +msgstr "De gebruikersnaam bestaat niet." #, php-format msgid "%s already has proposal running for them." -msgstr "Er loopt al een voorstel voor %s." +msgstr "%s heeft al een voorstel ervoor lopen." msgid "Invalid type." -msgstr "" +msgstr "Ongeldig type." msgid "Proposal cannot be empty." -msgstr "Voorstel kan niet leeg zijn." +msgstr "Het voorstel mag niet leeg worden gelaten." msgid "New proposal submitted." -msgstr "Nieuw voorstel ingediend." +msgstr "Het nieuwe voorstel is ingediend." msgid "Submit a proposal to vote on." msgstr "Een voorstel indienen om op te stemmen." @@ -86,56 +87,58 @@ msgid "Applicant/TU" msgstr "Aanvrager/TU" msgid "(empty if not applicable)" -msgstr "(Leeg indien niet van toepassing)" +msgstr "(laat leeg indien niet van toepassing)" msgid "Type" msgstr "Type" msgid "Addition of a TU" -msgstr "" +msgstr "Toevoeging van een TU" msgid "Removal of a TU" -msgstr "" +msgstr "Verwijdering van een TU" msgid "Removal of a TU (undeclared inactivity)" -msgstr "" +msgstr "Verwijdering van een TU (onverklaarbare inactiviteit)" msgid "Amendment of Bylaws" -msgstr "" +msgstr "Wijziging van de statuten" msgid "Proposal" msgstr "Voorstel" msgid "Submit" -msgstr "Opsturen" +msgstr "Versturen" msgid "Manage Co-maintainers" -msgstr "" +msgstr "Mede-onderhouders beheren" msgid "Home" -msgstr "Home" +msgstr "Startgedeelte" #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" -"Welkom bij de AUR! Lees de %sAUR Gebruikersvoorschriften%s en %sAUR " -"Ontwikkelaarsvoorschriften%s voor meer informatie." +"Welkom bij de AUR! Lees de %sAUR-gebruikersrichtlijnen%s en de %sAUR-" +"ontwikkelaarsrichtlijnen%s voor meer informatie." #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" -"PKGBUILDs %smoeten%s voeldoen aan de %sArch Packaging Standaarden%s anders " -"zullen ze verwijderd worden!" +"Bijgedragen PKGBUILDs %smoeten%s voldoen aan de %sArch-pakketstandaarden%s, " +"anders zullen ze worden verwijderd!" msgid "Remember to vote for your favourite packages!" -msgstr "Vergeet niet te stemmen voor je favoriete pakketten!" +msgstr "Vergeet niet te stemmen op uw favoriete pakketten!" msgid "Some packages may be provided as binaries in [community]." -msgstr "Sommige pakketten kunnen worden geleverd als binaries in [community]." +msgstr "" +"Sommige pakketten kunnen worden geleverd als uitvoerbare bestanden in " +"[community]." msgid "DISCLAIMER" msgstr "DISCLAIMER" @@ -144,51 +147,83 @@ msgid "" "Unsupported packages are user produced content. Any use of the provided " "files is at your own risk." msgstr "" -"Niet-ondersteunde pakketten zijn door gebruikers geproduceerde content. Elk " +"Niet-ondersteunde pakketten zijn door gebruikers geproduceerde inhoud. Elk " "gebruik van de geleverde bestanden is op eigen risico." +msgid "Learn more..." +msgstr "Meer leren..." + msgid "Support" -msgstr "" +msgstr "Ondersteuning" msgid "Package Requests" -msgstr "" +msgstr "Pakketaanvragen" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Er zijn drie typen aanvragen die kunnen worden ingedeeld in het " +"%sPakketacties%s-veld op de pakketdetails-pagina:" msgid "Orphan Request" -msgstr "" +msgstr "Weesaanvraag" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Vragen om het pakket te markeren als wees, bijv. wanneer de onderhouder " +"inactief is en het pakket langere tijd als verouderd gemarkeerd is." msgid "Deletion Request" -msgstr "" +msgstr "Verwijderaanvraag" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Verzoek om een pakket uit de Arch User Repository te laten verwijderen. " +"Gebruik dit niet als een pakket niet naar behoren functioneert en eenvoudig " +"gerepareerd kan worden. Neem in zo'n geval contact op met de " +"pakketontwikkelaar en open zo nodig een weesverzoek." msgid "Merge Request" -msgstr "" +msgstr "Aanvraag samenvoegen" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Verzoek om een pakket samen te laten voegen met een ander pakket. Dit kan " +"gebruikt worden als een pakket hernoemd moet worden of vervangen wordt door " +"een opgesplitst pakket." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Indien je het verzoek wilt bediscussiëren, dan kun je de %saur-requests%s " +"maillijst gebruiken. Gebruik deze lijst niet om verzoeken in te dienen." + +msgid "Submitting Packages" +msgstr "Het bijdragen van pakketten" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Git via SSA is nu in gebruik om pakketten bij te dragen aan de AUR. Zie de " +"%sHet bijdragen van pakketten%s-gedeelte van de Arch User Repository " +"ArchWiki-pagina voor meer details." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "De volgende SSH-vingerafdrukken worden gebruikt voor de AUR:" msgid "Discussion" msgstr "Discussie" @@ -199,9 +234,13 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Algemene discussies met betrekking tot de Arch User Repository (AUR) en de " +"opzet van Trusted Users vinden plaats op %saur-general%s. Voor discussies " +"gerelateerd aan de ontwikkeling van de AUR web interface, gebruik de %saur-" +"dev%s mailinglijst." msgid "Bug Reporting" -msgstr "Bug Rapportage" +msgstr "Bug-rapportage" #, php-format msgid "" @@ -210,43 +249,47 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Als u een bug tegenkomt in de AUR web interface, maak dan een melding in " +"onze %sbugtracker%s. Gebruik de bugtracker %salléén%s om bugs over AUR te " +"melden. Om fouten in de pakketsamenstelling te melden, neem contact op met " +"de pakketontwikkelaar of laat commentaar achter op de relevante pakketpagina." msgid "Package Search" -msgstr "Pakketten Zoeken" +msgstr "Pakketten zoeken" msgid "Adopt" -msgstr "" +msgstr "Adopteren" msgid "Vote" -msgstr "Stem" +msgstr "Stemmen" msgid "UnVote" -msgstr "Verwijder Stem" +msgstr "Stem verwijderen" msgid "Notify" msgstr "Informeren" msgid "UnNotify" -msgstr "Informeer niet" +msgstr "Niet informeren" msgid "Flag" -msgstr "Markeer" +msgstr "Markeren" msgid "UnFlag" -msgstr "Markering Verwijderen" +msgstr "De-markeren" msgid "Login" -msgstr "Login" +msgstr "Inloggen" #, php-format msgid "Logged-in as: %s" -msgstr "Ingelogd as: %s" +msgstr "Ingelogd als: %s" msgid "Logout" -msgstr "Log uit" +msgstr "Uitloggen" msgid "Enter login credentials" -msgstr "Voer login gegevens in" +msgstr "Vul uw inloggegevens in" msgid "Username" msgstr "Gebruikersnaam" @@ -263,7 +306,8 @@ msgstr "Wachtwoord vergeten" #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP login is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." +msgstr "" +"HTTP-inloggen is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." msgid "Search Criteria" msgstr "Zoekcriteria" @@ -278,14 +322,14 @@ msgid "Missing a required field." msgstr "Er ontbreekt een verplicht veld." msgid "Password fields do not match." -msgstr "Wachtwoord velden komen niet overeen." +msgstr "Wachtwoordvelden komen niet overeen." #, php-format msgid "Your password must be at least %s characters." -msgstr "Je wachtwoord moet minimaal %s karakters lang zijn." +msgstr "Uw wachtwoord moet minimaal %s karakters lang zijn." msgid "Invalid e-mail." -msgstr "Ongeldig e-mail adres." +msgstr "Ongeldig e-mailadres." #, php-format msgid "" @@ -293,9 +337,13 @@ msgid "" "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." msgstr "" +"Een verzoek om het wachtwoord te resetten was ingediend voor het account %s " +"wat geassocieerd is met uw e-mailadres. Indien u uw wachtwoord wilt resetten " +"volg dan onderstaande link. Als u uw wachtwoord niet wilt wijzigen kunt u " +"deze mail negeren, er gebeurt dan niets." msgid "Password Reset" -msgstr "Wachtwoord Reset" +msgstr "Wachtwoordherstel" msgid "Check your e-mail for the confirmation link." msgstr "Controleer uw e-mail voor de bevestigingslink." @@ -304,7 +352,7 @@ msgid "Your password has been reset successfully." msgstr "Uw wachtwoord is met succes teruggezet." msgid "Confirm your e-mail address:" -msgstr "Bevestig uw e-mail adres:" +msgstr "Bevestig uw e-mailadres:" msgid "Enter your new password:" msgstr "Voer uw nieuwe wachtwoord in:" @@ -330,12 +378,14 @@ msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +"De geselecteerde pakketten zijn niet onteigend, vink het bevestigingsvakje " +"aan." msgid "Cannot find package to merge votes and comments into." msgstr "Kan geen pakket vinden om stemmen en comments mee samen te voegen" msgid "Cannot merge a package base with itself." -msgstr "" +msgstr "Het basispakket kan niet met zichzelf worden samengevoegd." msgid "" "The selected packages have not been deleted, check the confirmation checkbox." @@ -343,17 +393,19 @@ msgstr "" "De geselecteerde pakketten zijn niet gewist, vink het bevestigingsvakje aan." msgid "Package Deletion" -msgstr "Pakket Verwijdering." +msgstr "Pakketverwijdering" #, php-format msgid "Delete Package: %s" -msgstr "Verwijder Pakket: %s" +msgstr "Pakket verwijderen: %s" #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +"Gebruik dit formulier om basispakket %s%s%s te verwijderen van AUR met " +"inbegrip van de volgende pakketten:" msgid "Deletion of a package is permanent. " msgstr "Verwijdering van een pakket is permanent." @@ -365,57 +417,65 @@ msgid "Confirm package deletion" msgstr "Bevestig pakketverwijdering" msgid "Delete" -msgstr "Verwijder" +msgstr "Verwijderen" msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Alleen Vertrouwde Gebruikers en Ontwikkelaars kunnen pakketten verwijderen." +msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten verwijderen." msgid "Disown Package" -msgstr "Onteigen Pakket" +msgstr "Pakket onteigenen" #, php-format msgid "Disown Package: %s" -msgstr "" +msgstr "Pakket onteigenen: %s" #, php-format msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"Gebruik dit formulier om basispakket %s%s%s te onteigenen met inbegrip van " +"de volgende pakketten:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen het " +"pakket en het eigendom over te dragen aan %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen van " +"het pakket." msgid "Confirm to disown the package" -msgstr "" +msgstr "Bevestig de onteigening van het pakket" msgid "Disown" -msgstr "" +msgstr "Onteigenen" msgid "Only Trusted Users and Developers can disown packages." msgstr "" +"Alleen Vertouwde Gebruikers en ontwikkelaars kunnen pakketten onteigenen." msgid "Package Merging" msgstr "Pakketsamenvoeging" #, php-format msgid "Merge Package: %s" -msgstr "Voeg Pakket Samen: %s" +msgstr "Pakket samenvoegen: %s" #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +"Gebruik dit formulier om basispakkete %s%s%s samen te voegen met een ander " +"pakket." msgid "The following packages will be deleted: " -msgstr "" +msgstr "De volgende pakketten zullen worden verwijderd:" msgid "Once the package has been merged it cannot be reversed. " msgstr "Als dit pakket samengevoegd is kan dit niet teruggedraaid worden." @@ -425,23 +485,22 @@ msgstr "" "Geef de naam van het pakket waarmee dit pakket samengevoegd moet worden." msgid "Merge into:" -msgstr "Voeg samen met:" +msgstr "Samenvoegen naar:" msgid "Confirm package merge" -msgstr "Bevestig samenvoeging" +msgstr "Samenvoeging bevestigen" msgid "Merge" -msgstr "Voeg samen" +msgstr "Samenvoegen" msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Alleen Vertrouwde Gebruikers en Ontwikkelaars kunnen pakketten samen voegen." +msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten samen voegen." msgid "File Request" -msgstr "" +msgstr "Aanvraag indienen" msgid "Close Request" -msgstr "" +msgstr "Aanvraag sluiten" msgid "First" msgstr "Eerste" @@ -456,34 +515,40 @@ msgid "Last" msgstr "Laatste" msgid "Requests" -msgstr "" +msgstr "Aanvragen" + +msgid "Register" +msgstr "Registreren" + +msgid "Use this form to create an account." +msgstr "Gebruik dit formulier om een ​​account aan te maken." msgid "Trusted User" -msgstr "Vertrouwde Gebruiker" +msgstr "Trusted User" msgid "Could not retrieve proposal details." -msgstr "Voorstel details kunnen niet opgehaald worden." +msgstr "Voorsteldetails kunnen niet opgehaald worden." msgid "Voting is closed for this proposal." msgstr "Stemmen is gesloten voor dit voorstel." msgid "Only Trusted Users are allowed to vote." -msgstr "" +msgstr "Alleen Trusted Users kunnen stemmen." msgid "You cannot vote in an proposal about you." -msgstr "Je kunt niet stemmen in een voorstel over jou." +msgstr "U kunt niet stemmen op een voorstel over u." msgid "You've already voted for this proposal." -msgstr "Je hebt al gestemd voor dit voorstel." +msgstr "U heeft al gestemd op dit voorstel." msgid "Vote ID not valid." -msgstr "Stem ID niet geldig." +msgstr "Uw stem-ID is ongeldig." msgid "Current Votes" -msgstr "Huidige Stemmen" +msgstr "Huidig aantal stemmen" msgid "Past Votes" -msgstr "Eerdere Stemmen" +msgstr "Eerdere stemmen" msgid "Voters" msgstr "Stemmers" @@ -496,7 +561,7 @@ msgstr "" "langdurige spam aanvallen. Excuses voor het ongemak." msgid "Missing User ID" -msgstr "Missende User ID" +msgstr "Gebruikers-ID ontbreekt" msgid "The username is invalid." msgstr "De gebruikersnaam is ongeldig." @@ -506,19 +571,19 @@ msgid "It must be between %s and %s characters long" msgstr "Het moet tussen de %s en %s karakters lang zijn" msgid "Start and end with a letter or number" -msgstr "Begin en eindig met een letter of nummer" +msgstr "Beginnen en eindigen met een letter of nummer" msgid "Can contain only one period, underscore or hyphen." msgstr "Kan maar één punt, komma of koppelteken bevatten." msgid "The email address is invalid." -msgstr "Het e-mail adres is ongeldig." +msgstr "Het e-mailadres is ongeldig." msgid "The PGP key fingerprint is invalid." msgstr "De vingerafdruk van de PGP sleutel is ongeldig." msgid "The SSH public key is invalid." -msgstr "" +msgstr "De publieke SSH-sleutel is ongeldig." msgid "Cannot increase account permissions." msgstr "Kan de account permissies niet verhogen." @@ -536,7 +601,7 @@ msgstr "Het adres %s%s%s is al in gebruik." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "De SSH publieke sleutel, %s%s%s, is al ingebruik." #, php-format msgid "Error trying to create account, %s%s%s." @@ -580,7 +645,7 @@ msgstr "" "vanwege langdurige spam-aanvallen. Excuses voor het ongemak." msgid "Account suspended" -msgstr "" +msgstr "Account is geschorst" #, php-format msgid "" @@ -597,7 +662,7 @@ msgid "Bad username or password." msgstr "Verkeerd gebruiker of wachtwoord" msgid "An error occurred trying to generate a user session." -msgstr "" +msgstr "Er is een fout opgetreden bij het aanmaken van een gebruikerssessie." msgid "Invalid e-mail and reset key combination." msgstr "Ongeldige e-mail en reset-toets combinatie." @@ -605,6 +670,10 @@ msgstr "Ongeldige e-mail en reset-toets combinatie." msgid "None" msgstr "Geen" +#, php-format +msgid "View account information for %s" +msgstr "Toon accountinformatie voor %s" + msgid "Error retrieving package details." msgstr "Fout bij het ophalen van pakketdetails." @@ -697,65 +766,62 @@ msgstr "Comment is verwijderd." msgid "You are not allowed to delete this comment." msgstr "Je hebt geen toestemming deze comment te verwijderen." -msgid "Missing category ID." -msgstr "Missende categorie ID." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" +"Je hebt geen toestemming de sleutelwoorden van dit basispakket aan te passen." -msgid "Invalid category ID." -msgstr "Ongeldige categorie ID." - -msgid "You are not allowed to change this package category." -msgstr "Je hebt geen toestemming deze pakketcategorie aan te passen." - -msgid "Package category changed." -msgstr "Pakketcategorie aangepast." +msgid "The package base keywords have been updated." +msgstr "De sleutelwoorden van het basispakket zijn bijgewerkt." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +"Je hebt geen toestemming om de mede-eigenaren van dit basispakket aan te " +"passen." #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Ongeldige gebruikersnaam: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "De mede-onderhouders van het basispakket zijn bijgewerkt." msgid "View packages details for" msgstr "Toon pakketdetails voor" msgid "You must be logged in to file package requests." -msgstr "" +msgstr "Je moet ingelogd zijn voordat je pekketverzoeken kunt indienen." msgid "Invalid name: only lowercase letters are allowed." msgstr "Ongeldige naam: alleen kleine letters zijn toegestaan." msgid "The comment field must not be empty." -msgstr "" +msgstr "Het commentaarveld mag niet leeg zijn." msgid "Invalid request type." -msgstr "" +msgstr "Ongeldig verzoektype." msgid "Added request successfully." -msgstr "" +msgstr "Verzoek succesvol toegevoegd." msgid "Invalid reason." -msgstr "" +msgstr "Ongeldige reden." msgid "Only TUs and developers can close requests." -msgstr "" +msgstr "Alleen TUs en ontwikkelaars mogen verzoeken sluiten." msgid "Request closed successfully." -msgstr "" +msgstr "Verzoek succesvol gesloten." #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" +msgstr "Gebruik dit formulier om permanent AUR account %s te verwijderen." #, php-format msgid "%sWARNING%s: This action cannot be undone." -msgstr "" +msgstr "%sWAARSCHUWING%s: Deze actie kan niet ongedaan worden gemaakt." msgid "Confirm deletion" -msgstr "" +msgstr "Bevestig verwijdering" msgid "Account Type" msgstr "Account Type" @@ -767,7 +833,7 @@ msgid "Developer" msgstr "Ontwikkelaar" msgid "Trusted User & Developer" -msgstr "" +msgstr "Trusted User & Ontwikkelaar" msgid "Email Address" msgstr "E-mail adres" @@ -785,13 +851,13 @@ msgid "Status" msgstr "Status" msgid "Inactive since" -msgstr "" +msgstr "Geen activiteit sinds" msgid "Active" msgstr "Actief" msgid "Last Login" -msgstr "" +msgstr "Laatste Login" msgid "Never" msgstr "Nooit" @@ -800,11 +866,11 @@ msgid "View this user's packages" msgstr "Bekijk gebruiker zijn pakketten" msgid "Edit this user's account" -msgstr "" +msgstr "Bewerk account van deze gebruiker" #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "" +msgstr "Klik %shier%s als u dit account permanent wilt verwijderen." msgid "required" msgstr "verplicht" @@ -813,13 +879,13 @@ msgid "Normal user" msgstr "Normale gebruiker" msgid "Trusted user" -msgstr "Vertrouwde gebruiker" +msgstr "Trusted user" msgid "Account Suspended" msgstr "Account Geschorst" msgid "Inactive" -msgstr "" +msgstr "Inactief" msgid "Re-type password" msgstr "Voer wachtwoord opnieuw in" @@ -831,9 +897,11 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"De volgende informatie is alleen verplicht als u pakketten aan de Arch User " +"Repository wilt toevoegen." msgid "SSH Public Key" -msgstr "" +msgstr "SSH Publieke Sleutel" msgid "Update" msgstr "Update" @@ -867,18 +935,20 @@ msgstr "Geen andere resultaten gevonden " #, php-format msgid "Manage Co-maintainers: %s" -msgstr "" +msgstr "Beheer mede-onderhouders: %s" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"Gebruik dit formulier om mede-onderhouders voor %s%s%s toe te voegen (een " +"gebruikersnaam per regel):" msgid "Users" -msgstr "" +msgstr "Gebruikers" msgid "Save" -msgstr "" +msgstr "Bewaren" msgid "My Packages" msgstr "Mijn pakketten" @@ -886,15 +956,6 @@ msgstr "Mijn pakketten" msgid " My Account" msgstr "Mijn Account" -msgid "Register" -msgstr "Registreren" - -msgid "unknown" -msgstr "onbekend" - -msgid "Package Base Details" -msgstr "" - msgid "Package Actions" msgstr "Pakket Acties" @@ -902,13 +963,13 @@ msgid "View PKGBUILD" msgstr "Toon PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Bekijk Wijzigingen" msgid "Download snapshot" -msgstr "" +msgstr "Download momentopname" msgid "Search wiki" -msgstr "" +msgstr "Doorzoek wiki" msgid "Flagged out-of-date" msgstr "Markeer als verouderd" @@ -932,13 +993,13 @@ msgid "Notify of new comments" msgstr "Notificatie bij nieuwe comment" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "Beheer mede-onderhouders" #, php-format msgid "%d pending request" msgid_plural "%d pending requests" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d verzoek in wachtrij" +msgstr[1] "%d verzoeken in wachtrij" msgid "Delete Package" msgstr "Verwijder Pakket" @@ -949,27 +1010,29 @@ msgstr "Voeg Pakket Samen" msgid "Adopt Package" msgstr "Adopteer Pakket" +msgid "unknown" +msgstr "onbekend" + +msgid "Package Base Details" +msgstr "Details van Basispakket" + msgid "Git Clone URL" +msgstr "Git Clone URL" + +msgid "read-only" msgstr "" -msgid "Category" -msgstr "Categorie" - -msgid "Change category" -msgstr "Verander categorie" +msgid "Keywords" +msgstr "Sleutelwoorden" msgid "Submitter" msgstr "Inzender" -#, php-format -msgid "View account information for %s" -msgstr "Toon accountinformatie voor %s" - msgid "Maintainer" msgstr "Beheerder" msgid "Last Packager" -msgstr "" +msgstr "Laatste Packager" msgid "Votes" msgstr "Stemmen" @@ -987,7 +1050,7 @@ msgid "Comment has been added." msgstr "Opmerking is toegevoegd." msgid "View all comments" -msgstr "" +msgstr "Bekijk alle commentaar" msgid "Latest Comments" msgstr "Nieuwste Comments" @@ -1000,10 +1063,10 @@ msgid "Comment by %s" msgstr "Comment door %s" msgid "Anonymous comment" -msgstr "" +msgstr "Anoniem commentaar" msgid "deleted" -msgstr "" +msgstr "verwijderd" msgid "All comments" msgstr "Alle comments" @@ -1012,7 +1075,7 @@ msgid "Package Details" msgstr "Pakketdetails" msgid "Package Base" -msgstr "" +msgstr "Basispakket" msgid "Description" msgstr "Omschrijving" @@ -1024,19 +1087,19 @@ msgid "Visit the website for" msgstr "Bezoek de website voor" msgid "Licenses" -msgstr "" +msgstr "Licenties" msgid "Groups" -msgstr "" +msgstr "Groepen" msgid "Conflicts" -msgstr "" +msgstr "Conflicten" msgid "Provides" -msgstr "" +msgstr "Voorziet in" msgid "Replaces" -msgstr "" +msgstr "Vervangt" msgid "Dependencies" msgstr "Afhankelijkheden" @@ -1049,50 +1112,55 @@ msgstr "Bronnen" #, php-format msgid "Close Request: %s" -msgstr "" +msgstr "Sluit Verzoek: %s" #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +"Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." msgid "Note" -msgstr "" +msgstr "Notitie" msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +"Het commentaarveld mag leeg blijven. Echter, het wordt sterk aanbevolen om " +"een afwijzing van commentaar te voorzien." msgid "Reason" -msgstr "" +msgstr "Reden" msgid "Accepted" -msgstr "" +msgstr "Geaccepteerd" msgid "Rejected" -msgstr "" +msgstr "Afgewezen" msgid "Comments" -msgstr "" +msgstr "Commentaar" #, php-format msgid "File Request: %s" -msgstr "" +msgstr "Nieuw Verzoek: %s" #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +"Gebruik dit formulier om een verzoek in te dienen voor basispakket %s%s%s " +"welke de volgende pakketten omvat:" msgid "Request type" -msgstr "" +msgstr "Verzoektype" msgid "Deletion" -msgstr "" +msgstr "Verwijdering" msgid "Orphan" -msgstr "" +msgstr "Wees" msgid "Merge into" msgstr "Voeg samen met" @@ -1100,46 +1168,46 @@ msgstr "Voeg samen met" #, php-format msgid "%d package request found." msgid_plural "%d package requests found." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d pakketverzoek gevonden" +msgstr[1] "%d pakketverzoeken gevonden" #, php-format msgid "Page %d of %d." -msgstr "" +msgstr "Pagina %d van %d." msgid "Package" -msgstr "" +msgstr "Pakket" msgid "Filed by" -msgstr "" +msgstr "Ingediend door" msgid "Date" -msgstr "" +msgstr "Datum" #, php-format msgid "~%d days left" -msgstr "" +msgstr "~%d dagen resterend" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "~%d uur resterend" +msgstr[1] "~%d uur resterend" msgid "<1 hour left" -msgstr "" +msgstr "<1 uur resterend" msgid "Accept" -msgstr "" +msgstr "Accepteer" msgid "Locked" -msgstr "" +msgstr "Vergrendeld" msgid "Close" -msgstr "" +msgstr "Sluit" msgid "Closed" -msgstr "" +msgstr "Gesloten" msgid "Name, Description" msgstr "Naam, omschrijving" @@ -1148,10 +1216,10 @@ msgid "Name Only" msgstr "Alleen de naam" msgid "Exact Name" -msgstr "" +msgstr "Exacte Naam" msgid "Exact Package Base" -msgstr "" +msgstr "Exact Basispakket" msgid "All" msgstr "Alle" @@ -1166,7 +1234,7 @@ msgid "Name" msgstr "Naam" msgid "Popularity" -msgstr "" +msgstr "Populariteit" msgid "Voted" msgstr "Gestemd" @@ -1183,15 +1251,9 @@ msgstr "Aflopend" msgid "Enter search criteria" msgstr "Voer zoekcriteria in" -msgid "Any" -msgstr "Elke" - msgid "Search by" msgstr "Zoek op" -msgid "Keywords" -msgstr "Sleutelwoorden" - msgid "Out of Date" msgstr "Verouderd" @@ -1219,12 +1281,17 @@ msgstr "Geen pakketen gevonden die aan uw zoekcriteria voldoen" #, php-format msgid "%d package found." msgid_plural "%d packages found." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d pakket gevonden" +msgstr[1] "%d pakketten gevonden" msgid "Version" msgstr "Versie" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Ja" @@ -1280,7 +1347,7 @@ msgid "Registered Users" msgstr "Geregistreerde Gebruikers" msgid "Trusted Users" -msgstr "Vertrouwde Gebruikers" +msgstr "Trusted Users" msgid "Recent Updates" msgstr "Recente updates" @@ -1305,7 +1372,7 @@ msgid "End" msgstr "Einde" msgid "Result" -msgstr "" +msgstr "Resultaat" msgid "No" msgstr "Nee" @@ -1317,13 +1384,13 @@ msgid "Total" msgstr "Totaal" msgid "Participation" -msgstr "" +msgstr "Participatie" msgid "Last Votes by TU" -msgstr "" +msgstr "Laatste stemmen door TU" msgid "Last vote" -msgstr "" +msgstr "Laatste stem" msgid "No results found." msgstr "Geen resultaten gevonden." diff --git a/po/pl.po b/po/pl.po index ece06fd7..a0a671b1 100644 --- a/po/pl.po +++ b/po/pl.po @@ -10,15 +10,15 @@ # Kwpolska , 2011 # Lukas Fleischer , 2011 # Nuc1eoN , 2014 -# Piotr Strębski , 2013-2014 +# Piotr Strębski , 2013-2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Polish (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-30 13:02+0000\n" +"Last-Translator: Piotr Strębski \n" +"Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" "pl/)\n" "Language: pl\n" "MIME-Version: 1.0\n" @@ -34,14 +34,16 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Przepraszamy, strona o którą prosiłeś nie istnieje." msgid "Service Unavailable" -msgstr "" +msgstr "Usługa niedostępna" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Nie panikuj! W związku z przeprowadzanymi pracami technicznymi strona jest " +"chwilowo niedostępna. Już wkrótce wrócimy." msgid "Account" -msgstr "" +msgstr "Konto" msgid "Accounts" msgstr "Konta" @@ -61,9 +63,6 @@ msgstr "Przy użyciu tego formularza możesz przeszukać istniejące konta." msgid "You must log in to view user information." msgstr "Musisz być zalogowany aby móc oglądać informacje o użytkownikach." -msgid "Use this form to create an account." -msgstr "Przy użyciu tego formularza możesz utworzyć konto." - msgid "Add Proposal" msgstr "Dodaj Propozycję" @@ -117,7 +116,7 @@ msgid "Submit" msgstr "Wyślij" msgid "Manage Co-maintainers" -msgstr "" +msgstr "Zarządzanie współutrzymującymi" msgid "Home" msgstr "Start" @@ -154,11 +153,14 @@ msgstr "" "Zamieszczone pakiety są niewspierane i utworzone przez użytkowników. Używasz " "ich na własne ryzyko." +msgid "Learn more..." +msgstr "Dowiedz się więcej..." + msgid "Support" -msgstr "" +msgstr "Wsparcie" msgid "Package Requests" -msgstr "" +msgstr "Prośby o pakiet" #, php-format msgid "" @@ -175,7 +177,7 @@ msgid "" msgstr "" msgid "Deletion Request" -msgstr "" +msgstr "Prośba o usunięcie" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " @@ -184,7 +186,7 @@ msgid "" msgstr "" msgid "Merge Request" -msgstr "" +msgstr "Prośba o połączenie" msgid "" "Request a package to be merged into another one. Can be used when a package " @@ -197,6 +199,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "Przesyłanie pakietów" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Dyskusja" @@ -469,6 +484,12 @@ msgstr "Ostatnia" msgid "Requests" msgstr "Propozcje" +msgid "Register" +msgstr "Zarejestruj się" + +msgid "Use this form to create an account." +msgstr "Przy użyciu tego formularza możesz utworzyć konto." + msgid "Trusted User" msgstr "Zaufany Użytkownik" @@ -616,6 +637,10 @@ msgstr "Nieprawidłowy e-mail i klucz do resetowania." msgid "None" msgstr "Żaden" +#, php-format +msgid "View account information for %s" +msgstr "Wyświetl informacje o koncie %s" + msgid "Error retrieving package details." msgstr "Błąd podczas pobierania informacji o pakiecie." @@ -705,24 +730,18 @@ msgstr "Komentarz został usunięty." msgid "You are not allowed to delete this comment." msgstr "Nie masz uprawnień do usunięcia tego komentarza." -msgid "Missing category ID." -msgstr "Brakujące ID kategorii." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "Nieprawidłowy identyfikator kategorii." - -msgid "You are not allowed to change this package category." -msgstr "Nie masz uprawnień, by zmienić kategorię tego pakietu." - -msgid "Package category changed." -msgstr "Kategoria pakietu zmieniona." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Niepoprawna nazwa użytkownika: %s" msgid "The package base co-maintainers have been updated." msgstr "" @@ -841,7 +860,7 @@ msgid "" msgstr "" msgid "SSH Public Key" -msgstr "" +msgstr "Klucz publiczny SSH" msgid "Update" msgstr "Aktualizuj" @@ -883,10 +902,10 @@ msgid "" msgstr "" msgid "Users" -msgstr "" +msgstr "Użytkownicy" msgid "Save" -msgstr "" +msgstr "Zapisz" msgid "My Packages" msgstr "Moje pakiety" @@ -894,15 +913,6 @@ msgstr "Moje pakiety" msgid " My Account" msgstr "Moje konto" -msgid "Register" -msgstr "Zarejestruj się" - -msgid "unknown" -msgstr "nieznana" - -msgid "Package Base Details" -msgstr "Szczegóły bazy pakietu" - msgid "Package Actions" msgstr "Działania na pakietach" @@ -910,7 +920,7 @@ msgid "View PKGBUILD" msgstr "Pokaż PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Zobacz zmiany" msgid "Download snapshot" msgstr "" @@ -958,22 +968,24 @@ msgstr "Scal pakiet" msgid "Adopt Package" msgstr "Przejmij pakiet" +msgid "unknown" +msgstr "nieznana" + +msgid "Package Base Details" +msgstr "Szczegóły bazy pakietu" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Kategoria" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "Zmień kategorię." +msgid "Keywords" +msgstr "Słowa kluczowe" msgid "Submitter" msgstr "Nadesłał" -#, php-format -msgid "View account information for %s" -msgstr "Wyświetl informacje o koncie %s" - msgid "Maintainer" msgstr "Opiekun" @@ -1065,7 +1077,7 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" msgid "Note" -msgstr "" +msgstr "Uwaga" msgid "" "The comments field can be left empty. However, it is highly recommended to " @@ -1073,7 +1085,7 @@ msgid "" msgstr "" msgid "Reason" -msgstr "" +msgstr "Powód" msgid "Accepted" msgstr "Zaakceptowany" @@ -1130,23 +1142,23 @@ msgstr "Data" #, php-format msgid "~%d days left" -msgstr "" +msgstr "pozostało ~%d dni" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "pozostała ~%d godzina" +msgstr[1] "pozostały ~%d godziny" +msgstr[2] "pozostało ~%d godzin" msgid "<1 hour left" -msgstr "" +msgstr "pozostała <1 godzina" msgid "Accept" msgstr "Akceptuj" msgid "Locked" -msgstr "" +msgstr "Zablokowane" msgid "Close" msgstr "Zamknij" @@ -1179,7 +1191,7 @@ msgid "Name" msgstr "Nazwa" msgid "Popularity" -msgstr "" +msgstr "Popularność" msgid "Voted" msgstr "Głos" @@ -1196,15 +1208,9 @@ msgstr "Malejąco" msgid "Enter search criteria" msgstr "Podaj kryteria wyszukiwania" -msgid "Any" -msgstr "Dowolna" - msgid "Search by" msgstr "Szukaj według" -msgid "Keywords" -msgstr "Słowa kluczowe" - msgid "Out of Date" msgstr "Nieaktualny" @@ -1239,6 +1245,11 @@ msgstr[2] "%d pakietów znaleziono" msgid "Version" msgstr "Wersja" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Tak" diff --git a/po/pt_BR.po b/po/pt_BR.po index 3198fc24..a9664486 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -4,17 +4,17 @@ # # Translators: # Albino Biasutti Neto Bino , 2011 -# Rafael Ferreira , 2012-2015 -# Rafael Ferreira , 2011 +# Rafael Fontenelle , 2012-2015 +# Rafael Fontenelle , 2011 # Sandro , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/aur/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-20 15:11+0000\n" +"Last-Translator: Rafael Fontenelle \n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" "language/pt_BR/)\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" @@ -29,11 +29,13 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Desculpe, a página que você solicitou não existe." msgid "Service Unavailable" -msgstr "" +msgstr "Serviço Indisponível" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Sem pânico! Este site está fechado para manutenção. Voltaremos às atividades " +"em breve." msgid "Account" msgstr "Conta" @@ -56,9 +58,6 @@ msgstr "Utilize este formulário para procurar contas existentes." msgid "You must log in to view user information." msgstr "Você precisa fazer login para ver as informações do usuário." -msgid "Use this form to create an account." -msgstr "Utilize este formulário para criar uma conta." - msgid "Add Proposal" msgstr "Adicionar proposta" @@ -150,48 +149,80 @@ msgstr "" "Pacotes sem suporte são pacotes produzidos pelos usuários. Qualquer uso dos " "arquivos fornecidos é de sua própria conta e risco." +msgid "Learn more..." +msgstr "Aprenda mais..." + msgid "Support" -msgstr "" +msgstr "Suporte" msgid "Package Requests" -msgstr "" +msgstr "Requisições de pacote" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Há três tipos de requisições que podem ser realizadas na caixa %sAções do " +"pacote%s na página de detalhes do pacote:" msgid "Orphan Request" -msgstr "" +msgstr "Requisição para tornar o pacote órfão" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Requisite que seja desvinculado um pacote de seu mantenedor, de forma que o " +"pacote fique órfão, quando, por exemplo, o mantenedor está inativo e o " +"pacote foi marcado como desatualizado há muito tempo." msgid "Deletion Request" -msgstr "" +msgstr "Requisição de exclusão" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Requisite que um pacote seja removido do Arch User Repository. Por favor, " +"não use esta opção se um pacote está quebrado, mas que pode ser corrigido " +"facilmente. Ao invés disso, contate o mantenedor do pacote e, se necessário, " +"preencha uma requisição para tornar esse pacote órfão." msgid "Merge Request" -msgstr "" +msgstr "Requisição de mesclagem" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Requisite que um pacote seja mesclado com outro. Pode ser usado quando um " +"pacote precisa ser renomeado ou substituído por um pacote dividido." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Se você quiser discutir uma requisição, você pode user a lista de discussão " +"%saur-request%s. Porém, por favor não use essa lista para fazer requisições." + +msgid "Submitting Packages" +msgstr "Enviando pacotes" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Git sobre SSH agora é usado para enviar pacotes para o AUR. Veja a seção " +"%sEnviando pacotes%s da página wiki do Arch User Repository para mais " +"detalhes." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "As seguintes fingeprints SSH são usadas para o AUR:" msgid "Discussion" msgstr "Discussão" @@ -202,6 +233,9 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) " +"e do Trusted User acontecem no %saur-general%s. Para discussão relacionada " +"ao desenvolvimento do AUR web, use a lista de discussão do %saur-dev%s" msgid "Bug Reporting" msgstr "Relatório de erros" @@ -213,6 +247,11 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Se você encontrar um erro na interface web do AUR, por favor preencha um " +"relatório de erro no nosso %sbug tracker%s. Use o tracker para relatar erros " +"encontrados no AUR, %ssomente%s. Para relatar erros de empacotamento, " +"contate o mantenedor do pacote ou deixe um comentário na página de pacote " +"apropriada." msgid "Package Search" msgstr "Pesquisar pacote" @@ -474,6 +513,12 @@ msgstr "Última" msgid "Requests" msgstr "Requisições" +msgid "Register" +msgstr "Registrar" + +msgid "Use this form to create an account." +msgstr "Utilize este formulário para criar uma conta." + msgid "Trusted User" msgstr "Trusted User" @@ -620,6 +665,10 @@ msgstr "Combinação entre email e chave de redefinição é inválida" msgid "None" msgstr "Nenhum" +#, php-format +msgid "View account information for %s" +msgstr "Ver informações da conta para %s" + msgid "Error retrieving package details." msgstr "Erro ao obter detalhes do pacote." @@ -709,28 +758,23 @@ msgstr "O comentário foi excluído." msgid "You are not allowed to delete this comment." msgstr "Você não tem permissão para excluir esse comentário." -msgid "Missing category ID." -msgstr "Faltando ID de categoria." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" +"Você não tem permissão para editar as palavras-chaves deste pacote base." -msgid "Invalid category ID." -msgstr "ID de categoria inválido." - -msgid "You are not allowed to change this package category." -msgstr "Você não tem permissão para alterar a categoria desse pacote." - -msgid "Package category changed." -msgstr "Categoria do pacote alterada." +msgid "The package base keywords have been updated." +msgstr "As palavras-chave do pacote base foram atualizadas." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -"Você não tem permissão para gerenciar co-mantenedores deste pacote base." +"Você não tem permissão para gerenciar comantenedores deste pacote base." #, php-format msgid "Invalid user name: %s" msgstr "Nome de usuário inválido: %s" msgid "The package base co-maintainers have been updated." -msgstr "Os co-mantenedores do pacote base foram atualizados." +msgstr "Os comantenedores do pacote base foram atualizados." msgid "View packages details for" msgstr "Ver detalhes de pacotes para" @@ -884,13 +928,13 @@ msgstr "Não há mais resultados para serem exibidos." #, php-format msgid "Manage Co-maintainers: %s" -msgstr "Gerenciar co-mantenedores: %s" +msgstr "Gerenciar comantenedores: %s" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -"Use este formulário para adicionar co-mantenedores para %s%s%s (um nome de " +"Use este formulário para adicionar comantenedores para %s%s%s (um nome de " "usuário por linha):" msgid "Users" @@ -905,15 +949,6 @@ msgstr "Meus pacotes" msgid " My Account" msgstr " Minha conta" -msgid "Register" -msgstr "Registrar" - -msgid "unknown" -msgstr "desconhecido" - -msgid "Package Base Details" -msgstr "Detalhes do pacote base" - msgid "Package Actions" msgstr "Ações do pacote" @@ -951,7 +986,7 @@ msgid "Notify of new comments" msgstr "Notificar sobre novos comentários" msgid "Manage Co-Maintainers" -msgstr "Gerenciar co-mantenedores" +msgstr "Gerenciar comantenedores" #, php-format msgid "%d pending request" @@ -968,22 +1003,24 @@ msgstr "Mesclar pacote" msgid "Adopt Package" msgstr "Adotar pacote" +msgid "unknown" +msgstr "desconhecido" + +msgid "Package Base Details" +msgstr "Detalhes do pacote base" + msgid "Git Clone URL" msgstr "Git Clone URL" -msgid "Category" -msgstr "Categoria" +msgid "read-only" +msgstr "somente leitura" -msgid "Change category" -msgstr "Alterar categoria" +msgid "Keywords" +msgstr "Palavras-chave" msgid "Submitter" msgstr "Criado por" -#, php-format -msgid "View account information for %s" -msgstr "Ver informações da conta para %s" - msgid "Maintainer" msgstr "Mantenedor" @@ -1190,7 +1227,7 @@ msgid "Name" msgstr "Nome" msgid "Popularity" -msgstr "" +msgstr "Popularidade" msgid "Voted" msgstr "Votado" @@ -1207,15 +1244,9 @@ msgstr "Decrescente" msgid "Enter search criteria" msgstr "Digite os critérios de pesquisa" -msgid "Any" -msgstr "Qualquer" - msgid "Search by" msgstr "Pesquisar por" -msgid "Keywords" -msgstr "Palavras-chave" - msgid "Out of Date" msgstr "Desatualizado" @@ -1249,6 +1280,13 @@ msgstr[1] "%d pacotes encontrados." msgid "Version" msgstr "Versão" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"Popularidade é calculada como a soma de todos os votos, sendo cada voto " +"pesado com um fator de 0.98 por dia desde sua criação." + msgid "Yes" msgstr "Sim" diff --git a/po/pt_PT.po b/po/pt_PT.po index 0787b584..0024e72c 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -6,16 +6,16 @@ # Gaspar Santos , 2011 # R00KIE , 2013 # R00KIE , 2011 -# DarkVenger , 2013-2014 +# DarkVenger , 2013-2015 # DarkVenger , 2012 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/" +"Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" "aur/language/pt_PT/)\n" "Language: pt_PT\n" "MIME-Version: 1.0\n" @@ -30,14 +30,16 @@ msgid "Sorry, the page you've requested does not exist." msgstr "As nossas desculpas, a página que pediu não existe." msgid "Service Unavailable" -msgstr "" +msgstr "Serviço não disponível" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Não entre em pânico! Esta página encontra-se em baixo devido a manutenção. " +"Voltaremos brevemente." msgid "Account" -msgstr "" +msgstr "Conta" msgid "Accounts" msgstr "Contas" @@ -57,9 +59,6 @@ msgstr "Utilize este formulário para procurar contas existentes." msgid "You must log in to view user information." msgstr "Necessita iniciar sessão para visualizar a informação do utilizador." -msgid "Use this form to create an account." -msgstr "Para criar uma conta utilize este formulário." - msgid "Add Proposal" msgstr "Adicionar Proposta" @@ -113,7 +112,7 @@ msgid "Submit" msgstr "Enviar" msgid "Manage Co-maintainers" -msgstr "" +msgstr "Gerir responsáveis" msgid "Home" msgstr "Início" @@ -152,34 +151,46 @@ msgstr "" "Os pacotes não suportados são produzidos por utilizadores. O seu uso é por " "sua conta e risco." +msgid "Learn more..." +msgstr "Saber mais..." + msgid "Support" -msgstr "" +msgstr "Suporte" msgid "Package Requests" -msgstr "" +msgstr "Pedidos de Pacotes" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Existem três tipos de pedidos que podem ser preenchidos na caixa " +"%sPackageActions%s na página de detalhes de um pacote." msgid "Orphan Request" -msgstr "" +msgstr "Pedido para Tornar Orfão" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Pedido para que um pacote dique sem dono, por exemplo, quando o atual " +"responsável se encontra inativo e o pacote foi marcado como desatualizado há " +"muito tempo." msgid "Deletion Request" -msgstr "" +msgstr "Pedido para Apagar" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Pedido para que um pacote seja removido do Arch User Repository. Por favor " +"não use este pedido se um pacote está danificado e pode ser resolvido " +"facilmente. Contacte o responsável pelo mesmo e faça um Pedido para Tornar " +"Orfão se necessário." msgid "Merge Request" msgstr "" @@ -195,6 +206,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Discussão" @@ -466,6 +490,12 @@ msgstr "Ultimo." msgid "Requests" msgstr "Pedidos" +msgid "Register" +msgstr "Registar" + +msgid "Use this form to create an account." +msgstr "Para criar uma conta utilize este formulário." + msgid "Trusted User" msgstr "Utilizador de Confiança" @@ -615,6 +645,10 @@ msgstr "Combinação de e-mail e chave de recuperação inválidos." msgid "None" msgstr "Nenhum" +#, php-format +msgid "View account information for %s" +msgstr "Ver informação de conta de %s" + msgid "Error retrieving package details." msgstr "Erro ao obter os detalhes do pacote." @@ -704,17 +738,11 @@ msgstr "O comentário foi apagado." msgid "You are not allowed to delete this comment." msgstr "Não tem permissão para apagar este comentário." -msgid "Missing category ID." -msgstr "ID de categoria em falta." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "ID de categoria inválido." - -msgid "You are not allowed to change this package category." -msgstr "Não tem permissão para mudar a categoria deste pacote." - -msgid "Package category changed." -msgstr "Categoria do pacote modificada." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -893,15 +921,6 @@ msgstr "Os meus pacotes" msgid " My Account" msgstr "A minha Conta" -msgid "Register" -msgstr "Registar" - -msgid "unknown" -msgstr "desconhecido" - -msgid "Package Base Details" -msgstr "Pacote Base Detalhes" - msgid "Package Actions" msgstr "Ações sobre Pacotes" @@ -956,22 +975,24 @@ msgstr "Fundir Pacote" msgid "Adopt Package" msgstr "Adotar Pacote" +msgid "unknown" +msgstr "desconhecido" + +msgid "Package Base Details" +msgstr "Pacote Base Detalhes" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Categoria" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "Mudar categoria" +msgid "Keywords" +msgstr "Palavras-chave" msgid "Submitter" msgstr "Submissor" -#, php-format -msgid "View account information for %s" -msgstr "Ver informação de conta de %s" - msgid "Maintainer" msgstr "Responsável pela manutenção" @@ -1192,15 +1213,9 @@ msgstr "Descendente" msgid "Enter search criteria" msgstr "Introduzir critério de pesquisa" -msgid "Any" -msgstr "Qualquer" - msgid "Search by" msgstr "Procurar por" -msgid "Keywords" -msgstr "Palavras-chave" - msgid "Out of Date" msgstr "Desactualizado" @@ -1234,6 +1249,11 @@ msgstr[1] "%d pacotes encontrados." msgid "Version" msgstr "Versão" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Sim" diff --git a/po/ro.po b/po/ro.po index f484c94b..f4f93d6b 100644 --- a/po/ro.po +++ b/po/ro.po @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Romanian (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" "ro/)\n" "Language: ro\n" "MIME-Version: 1.0\n" @@ -58,9 +58,6 @@ msgstr "" "Trebuie să fi autentificat pentru a putea vedea informații despre " "utilizatori." -msgid "Use this form to create an account." -msgstr "Folosește acest formular pentru a crea un cont." - msgid "Add Proposal" msgstr "Adaugă o propunere" @@ -151,6 +148,9 @@ msgstr "" "Pachetele fără suport sunt conținut produs de utilizatori. Orice folosire a " "fișierelor oferite este pe risc propriu!" +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -194,6 +194,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Discuție" @@ -464,6 +477,12 @@ msgstr "Ultim" msgid "Requests" msgstr "Cereri" +msgid "Register" +msgstr "Înregistrare" + +msgid "Use this form to create an account." +msgstr "Folosește acest formular pentru a crea un cont." + msgid "Trusted User" msgstr "Trusted User" @@ -609,6 +628,10 @@ msgstr "Combinație e-mail și cheie pentru resetare nevalidă." msgid "None" msgstr "Nimic" +#, php-format +msgid "View account information for %s" +msgstr "Vezi informații despre contul lui %s" + msgid "Error retrieving package details." msgstr "Eroare la preluarea detaliilor pachetului." @@ -704,17 +727,11 @@ msgstr "Comentariul a fost șters." msgid "You are not allowed to delete this comment." msgstr "Nu ai voie să ștergi acest comentariu." -msgid "Missing category ID." -msgstr "ID-ul categoriei lipsește." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "ID-ul categoriei nu este valid." - -msgid "You are not allowed to change this package category." -msgstr "Nu ai permisiunea de a schimba categoria acestui pachet." - -msgid "Package category changed." -msgstr "Categoria pachetului a fost schimbată." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -893,15 +910,6 @@ msgstr "Pachetele mele" msgid " My Account" msgstr "Contul meu" -msgid "Register" -msgstr "Înregistrare" - -msgid "unknown" -msgstr "necunoscut" - -msgid "Package Base Details" -msgstr "Detalii pachet de bază" - msgid "Package Actions" msgstr "Operațiuni" @@ -957,22 +965,24 @@ msgstr "Fuzionează pachet" msgid "Adopt Package" msgstr "Adoptă pachet" +msgid "unknown" +msgstr "necunoscut" + +msgid "Package Base Details" +msgstr "Detalii pachet de bază" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Categorie" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "Schimbă categoria" +msgid "Keywords" +msgstr "Cuvinte cheie" msgid "Submitter" msgstr "Autor" -#, php-format -msgid "View account information for %s" -msgstr "Vezi informații despre contul lui %s" - msgid "Maintainer" msgstr "Responsabil" @@ -1199,15 +1209,9 @@ msgstr "Descrescător" msgid "Enter search criteria" msgstr "Introdu criteriul de căutare" -msgid "Any" -msgstr "Orice" - msgid "Search by" msgstr "Caută după" -msgid "Keywords" -msgstr "Cuvinte cheie" - msgid "Out of Date" msgstr "Neactualizate" @@ -1242,6 +1246,11 @@ msgstr[2] "%d de pachete găsite" msgid "Version" msgstr "Versiune" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Da" diff --git a/po/ru.po b/po/ru.po index 849bc7a4..4341702c 100644 --- a/po/ru.po +++ b/po/ru.po @@ -13,10 +13,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Russian (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" "ru/)\n" "Language: ru\n" "MIME-Version: 1.0\n" @@ -61,9 +61,6 @@ msgid "You must log in to view user information." msgstr "" "Вы должны представиться для того, чтобы посмотреть информацию о пользователе." -msgid "Use this form to create an account." -msgstr "Используйте эту форму для создания учетной записи." - msgid "Add Proposal" msgstr "Добавить предложение" @@ -157,6 +154,9 @@ msgstr "" "Неподдерживаемые пакеты — это пакеты, созданные пользователями. Любой способ " "их использования осуществляется на ваш страх и риск." +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -200,6 +200,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "Обсуждение" @@ -468,6 +481,12 @@ msgstr "Последний" msgid "Requests" msgstr "Запросы" +msgid "Register" +msgstr "Регистрация" + +msgid "Use this form to create an account." +msgstr "Используйте эту форму для создания учетной записи." + msgid "Trusted User" msgstr "Доверенный пользователь" @@ -613,6 +632,10 @@ msgstr "Неверная электронная почта и комбинаци msgid "None" msgstr "Нет" +#, php-format +msgid "View account information for %s" +msgstr "Просмотр информации об аккаунте %s" + msgid "Error retrieving package details." msgstr "Ошибка получения информации о пакете." @@ -702,17 +725,11 @@ msgstr "Комментарий удален." msgid "You are not allowed to delete this comment." msgstr "У вас нет прав для удаления этого комментария." -msgid "Missing category ID." -msgstr "Отсутствует идентификатор категории." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "Неверный идентификатор категории." - -msgid "You are not allowed to change this package category." -msgstr "Вам не позволено менять категорию этого пакета." - -msgid "Package category changed." -msgstr "Категория пакета изменилась." +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -893,15 +910,6 @@ msgstr "Мои пакеты" msgid " My Account" msgstr "Моя учётная запись" -msgid "Register" -msgstr "Регистрация" - -msgid "unknown" -msgstr "неизвестно" - -msgid "Package Base Details" -msgstr "Информация по группе пакетов" - msgid "Package Actions" msgstr "Действия над пакетом" @@ -958,22 +966,24 @@ msgstr "Объединить пакеты" msgid "Adopt Package" msgstr "Усыновить пакет" +msgid "unknown" +msgstr "неизвестно" + +msgid "Package Base Details" +msgstr "Информация по группе пакетов" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "Категория" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "Изменить категорию" +msgid "Keywords" +msgstr "Ключевые слова" msgid "Submitter" msgstr "Автор" -#, php-format -msgid "View account information for %s" -msgstr "Просмотр информации об аккаунте %s" - msgid "Maintainer" msgstr "Ответственный" @@ -1200,15 +1210,9 @@ msgstr "По убыванию" msgid "Enter search criteria" msgstr "Введите критерии поиска" -msgid "Any" -msgstr "Любой" - msgid "Search by" msgstr "Искать по" -msgid "Keywords" -msgstr "Ключевые слова" - msgid "Out of Date" msgstr "Устарел" @@ -1244,6 +1248,11 @@ msgstr[3] "Найдено %d пакетов." msgid "Version" msgstr "Версия" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "Да" diff --git a/po/sk.po b/po/sk.po index 1a5fa63d..6e3de984 100644 --- a/po/sk.po +++ b/po/sk.po @@ -9,10 +9,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Slovak (http://www.transifex.com/projects/p/aur/language/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-07-22 19:39+0000\n" +"Last-Translator: archetyp \n" +"Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" "sk/)\n" "Language: sk\n" "MIME-Version: 1.0\n" @@ -27,11 +27,12 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Mrzí nás to, ale stránka, ktorú ste zadali, neexistuje." msgid "Service Unavailable" -msgstr "" +msgstr "Služba nie je dostupná" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +"Zachovajte pokoj. Na stránke momentálne prebieha údržba. Vrátime sa čoskoro." msgid "Account" msgstr "Účet" @@ -54,9 +55,6 @@ msgstr "Použite tento formulár pre vyhľadávanie v existujúcich účtoch." msgid "You must log in to view user information." msgstr "Musíte sa prihlásiť, pre zobrazenie užívateľských informácií. " -msgid "Use this form to create an account." -msgstr "Použite tento formulár pre vytvorenie účtu. " - msgid "Add Proposal" msgstr "Pridať návrh" @@ -110,7 +108,7 @@ msgid "Submit" msgstr "Odoslať" msgid "Manage Co-maintainers" -msgstr "" +msgstr "Manažovať spolupracovníkov" msgid "Home" msgstr "Domov" @@ -147,48 +145,79 @@ msgstr "" "Nepodporované balíčky sú vytvárané užívateľmi. Akékoľvek použitie " "poskytnutých súborov je na vaše vlastné riziko. " +msgid "Learn more..." +msgstr "Dozvedieť sa viac..." + msgid "Support" -msgstr "" +msgstr "Podpora" msgid "Package Requests" -msgstr "" +msgstr "Žiadosti ohľadom balíčkov" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"V súčasnosti existujú tri typy žiadostí, ktoré možno vyplniť v časti %sAkcie " +"balíčka%s na stránke s detailami balíčka, a to:" msgid "Orphan Request" -msgstr "" +msgstr "Žiadosť o osirenie" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Žiadosť o odobratie vlastníctva balíčka, napr. ak správca balíčka nie je " +"aktívny a balíček bol dlhšiu dobu označený ako neaktuálny." msgid "Deletion Request" -msgstr "" +msgstr "Žiadosť o vymazanie" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Žiadosť o odstránenie balíčka z AUR. Nepoužívajte prosím túto možnosť v " +"prípade, že balíček je pokazený a možno ho ľahko opraviť. Namiesto toho " +"radšej kontaktujte jeho správcu alebo v prípade nutnosti požiadajte o jeho " +"osirenie." msgid "Merge Request" -msgstr "" +msgstr "Žiadosť o zlúčenie" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Žiadosť o zlúčenie balíčka do iného. Možno použiť tiež v prípade, že balíček " +"potrebuje byť premenovaný alebo nahradený rozdeleným balíčkom." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Ak potrebujete prediskutovať nejakú požiadavku, kedykoľvek môžete napísať na " +"mailing list %saur-requests%s. Nepoužívajte však tento mailing list na " +"posielanie požiadaviek." + +msgid "Submitting Packages" +msgstr "Podanie balíčkov" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Git cez SSH sa teraz používa na podanie balíčkov do AUR. Pre ďalšie " +"informácie pozri tiež sekciu %sPodanie balíčkov%s na AUR stránke v ArchWiki." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Uvedené SSH fingerprints sa používajú pre AUR:" msgid "Discussion" msgstr "Diskusia" @@ -199,6 +228,9 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Všeobecná diskusia týkajúca sa Arch Užívateľského Repozitára (AUR) a " +"štruktúry dôverovaných užívateľov (TU) je na %saur-general%s. Na diskusiu " +"týkajúcu sa vývoja AUR webu použite %saur-dev%s mailing list." msgid "Bug Reporting" msgstr "Ohlasovanie chýb" @@ -210,6 +242,10 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"Ak nájdete chybu na AUR webe, napíšte prosím správu o chybe na náš %sbug " +"tracker%s. Používajte ho %slen%s na chyby AUR webu. Ohľadom chýb balíčka " +"kontaktujte prosím jeho spravovateľa alebo zanechajte komentár na stránke " +"balíčka." msgid "Package Search" msgstr "Hľadanie balíčka" @@ -295,6 +331,9 @@ msgid "" "your e-mail address. If you wish to reset your password follow the link " "below, otherwise ignore this message and nothing will happen." msgstr "" +"Na účet %s spojený s Vašou emailovou adresou bola zaslaná požiadava na " +"resetovanie hesla. Ak si želáte heslo resetovať, kliknite na odkaz nižšie, " +"inak môžete túto správu ignorovať, žiadna zmena sa nestane." msgid "Password Reset" msgstr "Obnova hesla" @@ -332,6 +371,8 @@ msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +"Vybrané balíčky neboli vyvlastnené, pozrite potvrdzovacie zaškrtávacie " +"políčko." msgid "Cannot find package to merge votes and comments into." msgstr "" @@ -379,32 +420,37 @@ msgstr "Vyvlastni balíček" #, php-format msgid "Disown Package: %s" -msgstr "" +msgstr "Vyvlastni balíček: %s" #, php-format msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"Použite tento formulár na vyvlastnenie základne balíčka %s%s%s, ktorá " +"zahrňuje nasledujúce balíčky:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček " +"a presunúť vlastníctvo na %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček." msgid "Confirm to disown the package" -msgstr "" +msgstr "Potvrďte na vyvlastnenie balíčka" msgid "Disown" msgstr "Vyvlastniť" msgid "Only Trusted Users and Developers can disown packages." -msgstr "" +msgstr "Len dôverovaní užívatelia a vývojári môžu vyvlastňovať balíčky." msgid "Package Merging" msgstr "Zlúčenie balíčkov" @@ -461,6 +507,12 @@ msgstr "Posledný" msgid "Requests" msgstr "Žiadosti" +msgid "Register" +msgstr "Registrovať" + +msgid "Use this form to create an account." +msgstr "Použite tento formulár pre vytvorenie účtu. " + msgid "Trusted User" msgstr "Dôverovaný užívateľ (TU)" @@ -521,7 +573,7 @@ msgid "The PGP key fingerprint is invalid." msgstr "PGP otlačok kľúča je neplatný." msgid "The SSH public key is invalid." -msgstr "" +msgstr "Verejný SSH kľúč nie je platný." msgid "Cannot increase account permissions." msgstr "Nepodarilo sa rozšíriť práva účtu." @@ -539,7 +591,7 @@ msgstr "Adresa %s%s%s sa už používa." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "Verejný SSH kľúč %s%s%s sa už používa." #, php-format msgid "Error trying to create account, %s%s%s." @@ -606,6 +658,10 @@ msgstr "Neplatný email a kombinácia obnovovacích znakov." msgid "None" msgstr "Žiadny" +#, php-format +msgid "View account information for %s" +msgstr "Pozri informácie o účte pre %s" + msgid "Error retrieving package details." msgstr "Chyba pri získavaní informácií o balíčku." @@ -695,27 +751,21 @@ msgstr "Komentár bol vymazaný." msgid "You are not allowed to delete this comment." msgstr "Nemáte práva na vymazanie tohto komentára." -msgid "Missing category ID." -msgstr "Chýba ID kategórie." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Nemáte oprávnenie na editovanie kľúčových slov tejto základne balíčka." -msgid "Invalid category ID." -msgstr "Neplatné ID kategórie." - -msgid "You are not allowed to change this package category." -msgstr "Na zmenu kategórie balíčka nemáte oprávnenie." - -msgid "Package category changed." -msgstr "Kategória balíčka bola zmenená." +msgid "The package base keywords have been updated." +msgstr "Kľúčové slová základne balíčka boli aktualizované." msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "Nie ste oprávnený manažovať spolupracovníkov tejto základne balíčka." #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Neplatné užívateľské meno: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "Spolupracovníci základne balíčka boli aktualizovaní." msgid "View packages details for" msgstr "Pozri detaily balíčky pre" @@ -829,9 +879,11 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"Nasledujúca informácia je dôležitá iba v prípade, že chcete podať balíčky do " +"AUR." msgid "SSH Public Key" -msgstr "" +msgstr "Verejný SSH kľúč" msgid "Update" msgstr "Aktualizácia" @@ -865,18 +917,20 @@ msgstr "Nie sú ďalšie výsledky na zobrazenie." #, php-format msgid "Manage Co-maintainers: %s" -msgstr "" +msgstr "Manažovať spolupracovníkov: %s" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno " +"užívateľké meno na riadok):" msgid "Users" -msgstr "" +msgstr "Užívatelia" msgid "Save" -msgstr "" +msgstr "Uložiť" msgid "My Packages" msgstr "Moje balíčky" @@ -884,15 +938,6 @@ msgstr "Moje balíčky" msgid " My Account" msgstr "Môj účet" -msgid "Register" -msgstr "Registrovať" - -msgid "unknown" -msgstr "neznámy" - -msgid "Package Base Details" -msgstr "Detaily základne balíčka" - msgid "Package Actions" msgstr "Akcie balíčka" @@ -900,10 +945,10 @@ msgid "View PKGBUILD" msgstr "Pozrieť PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Prezrieť zmeny" msgid "Download snapshot" -msgstr "" +msgstr "Stiahnuť snapshot" msgid "Search wiki" msgstr "Prehľadať wiki" @@ -930,7 +975,7 @@ msgid "Notify of new comments" msgstr "Upozorni na nové komentáre" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "Manažovať spolupracovníkov" #, php-format msgid "%d pending request" @@ -948,22 +993,24 @@ msgstr "Zlúč balíček" msgid "Adopt Package" msgstr "Adoptuj balíček" +msgid "unknown" +msgstr "neznámy" + +msgid "Package Base Details" +msgstr "Detaily základne balíčka" + msgid "Git Clone URL" -msgstr "" +msgstr "Git Clone URL" -msgid "Category" -msgstr "Kategória" +msgid "read-only" +msgstr "len na čítanie" -msgid "Change category" -msgstr "Zmeniť kategóriu" +msgid "Keywords" +msgstr "Kľúčové slová" msgid "Submitter" msgstr "Prispievateľ" -#, php-format -msgid "View account information for %s" -msgstr "Pozri informácie o účte pre %s" - msgid "Maintainer" msgstr "Spravovateľ" @@ -1172,7 +1219,7 @@ msgid "Name" msgstr "Meno" msgid "Popularity" -msgstr "" +msgstr "Popularita" msgid "Voted" msgstr "Hlasoval" @@ -1189,15 +1236,9 @@ msgstr "Zostupne" msgid "Enter search criteria" msgstr "Zadaj kritériá pre vyhľadávanie" -msgid "Any" -msgstr "Ľubovoľné" - msgid "Search by" msgstr "Vyhľadávať podľa" -msgid "Keywords" -msgstr "Kľúčové slová" - msgid "Out of Date" msgstr "Neaktuálny" @@ -1232,6 +1273,13 @@ msgstr[2] "%d nájdených balíčkov." msgid "Version" msgstr "Verzia" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"Popularita sa počíta ako suma všetkých hlasov, pričom každý hlas je násobený " +"váhovým faktorom 0.98 za deň od dátumu vzniku." + msgid "Yes" msgstr "Áno" diff --git a/po/sr.po b/po/sr.po index 7899e15f..89b34444 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-12 02:57+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 12:30+0000\n" "Last-Translator: Slobodan Terzić \n" -"Language-Team: Serbian (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" "sr/)\n" "Language: sr\n" "MIME-Version: 1.0\n" @@ -57,9 +57,6 @@ msgstr "Ovim obrascem pretražujete postojeće naloge." msgid "You must log in to view user information." msgstr "Morate se prijaviti da bi videli podatke o korisniku." -msgid "Use this form to create an account." -msgstr "Ovim formularom pravite nalog." - msgid "Add Proposal" msgstr "Dodavanje predloga" @@ -150,6 +147,9 @@ msgstr "" "Paketi označeni sa [unsupported] su sadržaj koji stvaraju korisnici. " "Upotrebljavate ih na sopstvenu odgovornost." +msgid "Learn more..." +msgstr "Saznajte više..." + msgid "Support" msgstr "Podrška" @@ -205,6 +205,21 @@ msgstr "" "%saur-requests%s. Međutim, molimo da ne koristite tu listu za podnošenje " "zahteva." +msgid "Submitting Packages" +msgstr "Prilaganje paketa" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Za prilaganje paketa u AUR sada se koristi Git reko SSH. Pogledajte sekciju " +"%sPrilaganje paketa%s na stranici or AUR-u na Arčovom wikiju." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Sledeći SSH otisci se koriste za AUR:" + msgid "Discussion" msgstr "Diskusija" @@ -485,6 +500,12 @@ msgstr "Zadnja" msgid "Requests" msgstr "Zahtevi" +msgid "Register" +msgstr "Registracija" + +msgid "Use this form to create an account." +msgstr "Ovim formularom pravite nalog." + msgid "Trusted User" msgstr "Poverljivi korisnik" @@ -630,6 +651,10 @@ msgstr "Neispravna kombinacija e-pošte i ključa za resetovanje." msgid "None" msgstr "Nema" +#, php-format +msgid "View account information for %s" +msgstr "Prikaži podatke o nalogu za %s" + msgid "Error retrieving package details." msgstr "Greška pri dobavaljanju podataka o paketu." @@ -719,17 +744,11 @@ msgstr "Komentar je obrisan." msgid "You are not allowed to delete this comment." msgstr "Nije vam dozvoljeno brisanje ovog komentara." -msgid "Missing category ID." -msgstr "Nedostaje ID kategorije." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Nije vam dozvoljeno da uređujete ključne reči za ovu osnovu paketa." -msgid "Invalid category ID." -msgstr "Neispravan ID kategorije." - -msgid "You are not allowed to change this package category." -msgstr "Nemate dozvolu da promenite kategoriju ovog paketa." - -msgid "Package category changed." -msgstr "Kategorija paketa je izmenjena." +msgid "The package base keywords have been updated." +msgstr "Ključne reči baze paketa su ažurirane." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nije vam dozvvoljeno da upravljate koodržavaocima ove osnove paketa." @@ -912,15 +931,6 @@ msgstr "Moji paketi" msgid " My Account" msgstr "Moj nalog" -msgid "Register" -msgstr "Registracija" - -msgid "unknown" -msgstr "nepoznata" - -msgid "Package Base Details" -msgstr "Podaci o bazi paketa" - msgid "Package Actions" msgstr "Radnje nad paketom" @@ -976,22 +986,24 @@ msgstr "Spoji paket" msgid "Adopt Package" msgstr "Usvoji paket" +msgid "unknown" +msgstr "nepoznata" + +msgid "Package Base Details" +msgstr "Podaci o bazi paketa" + msgid "Git Clone URL" msgstr "URL za git kloniranje" -msgid "Category" -msgstr "Kategorija" +msgid "read-only" +msgstr "samo za čitanje" -msgid "Change category" -msgstr "Promeni kategoriju" +msgid "Keywords" +msgstr "Ključne reči" msgid "Submitter" msgstr "Pošiljalac" -#, php-format -msgid "View account information for %s" -msgstr "Prikaži podatke o nalogu za %s" - msgid "Maintainer" msgstr "Održavalac" @@ -1216,15 +1228,9 @@ msgstr "opadajući" msgid "Enter search criteria" msgstr "Unesite kriterijum pretrage" -msgid "Any" -msgstr "bilo koja" - msgid "Search by" msgstr "Traži se" -msgid "Keywords" -msgstr "Ključne reči" - msgid "Out of Date" msgstr "Zastareli paketi" @@ -1259,6 +1265,13 @@ msgstr[2] "Nađeno %d paketa." msgid "Version" msgstr "Verzija" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"Popularnost se izračunava kao suma svih glasova, gde glas ima faktor težine " +"0,98 za svaki dan od njegovog nastanka." + msgid "Yes" msgstr "Da" diff --git a/po/tr.po b/po/tr.po index 988fd2ac..35f44145 100644 --- a/po/tr.po +++ b/po/tr.po @@ -14,10 +14,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-12 08:15+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:45+0000\n" "Last-Translator: Atilla Öntaş \n" -"Language-Team: Turkish (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" "tr/)\n" "Language: tr\n" "MIME-Version: 1.0\n" @@ -61,9 +61,6 @@ msgstr "Mevcut hesaplar içinde arama yapmak için bu formu kullanın." msgid "You must log in to view user information." msgstr "Kullanıcı bilgilerini görmek için giriş yapmalısınız." -msgid "Use this form to create an account." -msgstr "Yeni bir hesap oluşturmak için bu formu kullanın." - msgid "Add Proposal" msgstr "Öneri ekle" @@ -156,6 +153,9 @@ msgstr "" "sahiptirler. Bu paketlerin kullanımından doğan risk kullanıcının kendisine " "aittir." +msgid "Learn more..." +msgstr "Daha fazlasını öğrenin..." + msgid "Support" msgstr "Destek" @@ -213,6 +213,22 @@ msgstr "" "listesini kullanabilirsiniz. Bununla birlikte o e-posta listesini dosya " "talepleri için kullanmamalısınız." +msgid "Submitting Packages" +msgstr "Paketleri göndermek" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Artık AUR' a paket göndermek için SSH üzerinden Git kullanılmaktadır. Daha " +"fazla bilgi için Arch Kullanıcı Deposu ArchWiki sayfasındaki %sPaketleri " +"Göndermek%s bölümüne bakın." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "AUR için şu SSH parmak izleri kullanılmaktadır:" + msgid "Discussion" msgstr "Tartışma" @@ -501,6 +517,12 @@ msgstr "Son" msgid "Requests" msgstr "Talepler" +msgid "Register" +msgstr "Kayıt ol" + +msgid "Use this form to create an account." +msgstr "Yeni bir hesap oluşturmak için bu formu kullanın." + msgid "Trusted User" msgstr "Güvenilen Kullanıcı" @@ -645,6 +667,10 @@ msgstr "Geçersiz e-posta adresi ve sıfırlama anahtarı bileşimi" msgid "None" msgstr "Yok" +#, php-format +msgid "View account information for %s" +msgstr "%s için hesap bilgilerini görüntüle" + msgid "Error retrieving package details." msgstr "Paket bilgileri alınırken hata oluştu." @@ -734,17 +760,12 @@ msgstr "Yorum silindi." msgid "You are not allowed to delete this comment." msgstr "Bu yorumu silme yetkiniz yok." -msgid "Missing category ID." -msgstr "Kategori kimliği bulunamadı." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" +"Bu paket temelinin anahtar kelimelerini düzenleme yetkisine sahip değilsiniz." -msgid "Invalid category ID." -msgstr "Geçersiz kategori." - -msgid "You are not allowed to change this package category." -msgstr "Bu paket kategorisini değiştirmek için gerekli izne sahip değilsiniz." - -msgid "Package category changed." -msgstr "Paket kategorisi değiştirildi." +msgid "The package base keywords have been updated." +msgstr "Paket temeli anahtar kelimeleri güncellendi." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -928,15 +949,6 @@ msgstr "Paketlerim" msgid " My Account" msgstr "Hesabım" -msgid "Register" -msgstr "Kayıt ol" - -msgid "unknown" -msgstr "bilinmiyor" - -msgid "Package Base Details" -msgstr "Paket Temeli Ayrıntıları" - msgid "Package Actions" msgstr "Paket Eylemleri" @@ -991,22 +1003,24 @@ msgstr "Paketi Birleştir" msgid "Adopt Package" msgstr "Paketi Sahiplen" +msgid "unknown" +msgstr "bilinmiyor" + +msgid "Package Base Details" +msgstr "Paket Temeli Ayrıntıları" + msgid "Git Clone URL" msgstr "Git Clone URL" -msgid "Category" -msgstr "Kategori" +msgid "read-only" +msgstr "salt okunur" -msgid "Change category" -msgstr "Kategori değiştir" +msgid "Keywords" +msgstr "Anahtar kelimeler" msgid "Submitter" msgstr "Yükleyen" -#, php-format -msgid "View account information for %s" -msgstr "%s için hesap bilgilerini görüntüle" - msgid "Maintainer" msgstr "Sorumlu" @@ -1230,15 +1244,9 @@ msgstr "Yeniden eskiye" msgid "Enter search criteria" msgstr "Arama kriteri girin" -msgid "Any" -msgstr "Tümü" - msgid "Search by" msgstr "Buna göre ara" -msgid "Keywords" -msgstr "Anahtar kelimeler" - msgid "Out of Date" msgstr "Güncelliğini Yitirmiş" @@ -1272,6 +1280,13 @@ msgstr[1] "%d adet paket bulundu." msgid "Version" msgstr "Sürüm" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"Beğenilirlik, oluşturulmasından itibaren günlük 0.98 oranı ile çarpılarak " +"bulunan her oyun toplamı ile ölçülür." + msgid "Yes" msgstr "Evet" diff --git a/po/uk.po b/po/uk.po index e431c5f6..078b3887 100644 --- a/po/uk.po +++ b/po/uk.po @@ -12,10 +12,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-12 12:02+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:54+0000\n" "Last-Translator: Yarema aka Knedlyk \n" -"Language-Team: Ukrainian (http://www.transifex.com/projects/p/aur/language/" +"Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" "uk/)\n" "Language: uk\n" "MIME-Version: 1.0\n" @@ -60,9 +60,6 @@ msgstr "Шукайте облікові записи за допомогою ц msgid "You must log in to view user information." msgstr "Ви повинні увійти в систему для перегляду даних користувача." -msgid "Use this form to create an account." -msgstr "Створіть обліковий запис за допомогою цієї форми." - msgid "Add Proposal" msgstr "Додати пропозицію" @@ -154,6 +151,9 @@ msgstr "" "Пакунки, що не підтримуються - це пакунки, створені користувачами. Ви можете " "використовувати їх тільки на Ваш власний страх і ризик." +msgid "Learn more..." +msgstr "Дізнатись більше..." + msgid "Support" msgstr "Підтримка" @@ -209,6 +209,22 @@ msgstr "" "Якщо Ви бажаєте обговорити запит, використайте список розсилки %saur-requests" "%s. Будь ласка, не використовуйте цю розсилку для подання запитів." +msgid "Submitting Packages" +msgstr "Надсилання пакунків" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"Git через SSH тепер використовується для надсилання пакунків до AUR. Для " +"деталей дивіться розділ %sНадсилання пакунків%s на сторінці ArchWiki про " +"Сховище Користувацьких Пакунків AUR." + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "Наступні відбитки ключів SSH використовуються в AUR:" + msgid "Discussion" msgstr "Обговорення" @@ -492,6 +508,12 @@ msgstr "Останній" msgid "Requests" msgstr "Запити" +msgid "Register" +msgstr "Зареєструватись" + +msgid "Use this form to create an account." +msgstr "Створіть обліковий запис за допомогою цієї форми." + msgid "Trusted User" msgstr "Довірений користувач" @@ -639,6 +661,10 @@ msgstr "Неприпустима адреса електронної пошти msgid "None" msgstr "Немає" +#, php-format +msgid "View account information for %s" +msgstr "Показати інформацію про рахунок для %s" + msgid "Error retrieving package details." msgstr "Помилка пошуку інформації про пакунок." @@ -730,17 +756,12 @@ msgstr "Коментар вилучено." msgid "You are not allowed to delete this comment." msgstr "У вас немає прав, щоб вилучити цей коментар." -msgid "Missing category ID." -msgstr "Пропущено ідентифікатор категорії." +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" +"Ви не маєте прав для редагування ключових слів для цього базового пакунку." -msgid "Invalid category ID." -msgstr "Неправильний ідентифікатор категорії." - -msgid "You are not allowed to change this package category." -msgstr "Ви не можете змінити катеогрію цього пакунку." - -msgid "Package category changed." -msgstr "Категорію пакунку змінено." +msgid "The package base keywords have been updated." +msgstr "Ключові слова базового пакунку оновлено." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Ви не має прав для керування супровідниками цього базового пакунку." @@ -923,15 +944,6 @@ msgstr "Мої пакунки" msgid " My Account" msgstr "Мій рахунок" -msgid "Register" -msgstr "Зареєструватись" - -msgid "unknown" -msgstr "невідомо" - -msgid "Package Base Details" -msgstr "Деталі бази пакунків" - msgid "Package Actions" msgstr "Дії над пакунком" @@ -987,22 +999,24 @@ msgstr "Об’єднати пакунок" msgid "Adopt Package" msgstr "Прийняти пакунок" +msgid "unknown" +msgstr "невідомо" + +msgid "Package Base Details" +msgstr "Деталі бази пакунків" + msgid "Git Clone URL" msgstr "Адреса URL для клонування Git" -msgid "Category" -msgstr "Категорія" +msgid "read-only" +msgstr "тільки для читання" -msgid "Change category" -msgstr "Змінити категорію" +msgid "Keywords" +msgstr "Ключові слова" msgid "Submitter" msgstr "Подавач" -#, php-format -msgid "View account information for %s" -msgstr "Показати інформацію про рахунок для %s" - msgid "Maintainer" msgstr "Супровідник" @@ -1227,15 +1241,9 @@ msgstr "Спадний" msgid "Enter search criteria" msgstr "Введіть критерії пошуку" -msgid "Any" -msgstr "Будь-який" - msgid "Search by" msgstr "Де шукати" -msgid "Keywords" -msgstr "Ключові слова" - msgid "Out of Date" msgstr "Застарілих" @@ -1270,6 +1278,13 @@ msgstr[2] "Знайдено %d пакунків." msgid "Version" msgstr "Версія" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" +"Популярність розраховується як сума всіх голосувань, де кожен голос береться " +"з ваговим коефіцієнтом 0.98 за кожен день з часу створення." + msgid "Yes" msgstr "Так" diff --git a/po/zh_CN.po b/po/zh_CN.po index 693ad6df..279b0c74 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -13,10 +13,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 08:16+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/aur/" +"Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" "language/zh_CN/)\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" @@ -58,9 +58,6 @@ msgstr "使用此表单查找存在的帐户。" msgid "You must log in to view user information." msgstr "您需要登录后才能察看用户信息。" -msgid "Use this form to create an account." -msgstr "使用此表单创建帐号。" - msgid "Add Proposal" msgstr "添加提议" @@ -147,6 +144,9 @@ msgid "" "files is at your own risk." msgstr "位于 unsupported 的软件包为用户产生的内容。使用它们造成的后果自负。" +msgid "Learn more..." +msgstr "" + msgid "Support" msgstr "" @@ -190,6 +190,19 @@ msgid "" "list. However, please do not use that list to file requests." msgstr "" +msgid "Submitting Packages" +msgstr "" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "" + msgid "Discussion" msgstr "邮件列表" @@ -453,6 +466,12 @@ msgstr "末页" msgid "Requests" msgstr "请求" +msgid "Register" +msgstr "注册" + +msgid "Use this form to create an account." +msgstr "使用此表单创建帐号。" + msgid "Trusted User" msgstr "受信用户" @@ -595,6 +614,10 @@ msgstr "邮箱和重置 key 不匹配。" msgid "None" msgstr "无" +#, php-format +msgid "View account information for %s" +msgstr "查看 %s 的账户信息" + msgid "Error retrieving package details." msgstr "获取软件包详情时发生错误。" @@ -684,17 +707,11 @@ msgstr "评论已被删除。" msgid "You are not allowed to delete this comment." msgstr "您没有权限删除此评论。" -msgid "Missing category ID." -msgstr "缺少分类 ID。" +msgid "You are not allowed to edit the keywords of this package base." +msgstr "" -msgid "Invalid category ID." -msgstr "非法的类别标识" - -msgid "You are not allowed to change this package category." -msgstr "您无权修改此软件包的类别。" - -msgid "Package category changed." -msgstr "软件包分类已更改。" +msgid "The package base keywords have been updated." +msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" @@ -873,15 +890,6 @@ msgstr "我的软件包" msgid " My Account" msgstr "我的帐户" -msgid "Register" -msgstr "注册" - -msgid "unknown" -msgstr "未知" - -msgid "Package Base Details" -msgstr "包基础详情" - msgid "Package Actions" msgstr "软件包操作" @@ -935,22 +943,24 @@ msgstr "合并软件包" msgid "Adopt Package" msgstr "接管软件包" +msgid "unknown" +msgstr "未知" + +msgid "Package Base Details" +msgstr "包基础详情" + msgid "Git Clone URL" msgstr "" -msgid "Category" -msgstr "类别" +msgid "read-only" +msgstr "" -msgid "Change category" -msgstr "修改分类" +msgid "Keywords" +msgstr "关键字" msgid "Submitter" msgstr "提交人" -#, php-format -msgid "View account information for %s" -msgstr "查看 %s 的账户信息" - msgid "Maintainer" msgstr "维护者" @@ -1167,15 +1177,9 @@ msgstr "从大到小" msgid "Enter search criteria" msgstr "输入搜索条件" -msgid "Any" -msgstr "所有" - msgid "Search by" msgstr "搜索" -msgid "Keywords" -msgstr "关键字" - msgid "Out of Date" msgstr "过期状态" @@ -1208,6 +1212,11 @@ msgstr[0] "找到了 %d 个软件包。" msgid "Version" msgstr "版本" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "" + msgid "Yes" msgstr "是" diff --git a/po/zh_TW.po b/po/zh_TW.po index f1451354..16c89dfc 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -8,10 +8,10 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-11 23:45+0200\n" -"PO-Revision-Date: 2015-06-11 21:46+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/aur/" +"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"PO-Revision-Date: 2015-06-18 10:37+0000\n" +"Last-Translator: Jeff Huang \n" +"Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" "language/zh_TW/)\n" "Language: zh_TW\n" "MIME-Version: 1.0\n" @@ -53,9 +53,6 @@ msgstr "使用此表單來搜尋已有的帳號。" msgid "You must log in to view user information." msgstr "您必須登入以檢視使用者資訊。" -msgid "Use this form to create an account." -msgstr "使用此表單來新建一個帳號。" - msgid "Add Proposal" msgstr "添加建議" @@ -144,48 +141,74 @@ msgid "" "files is at your own risk." msgstr "AUR 上的檔案是使用者產生的內容。任何使用檔案的風險由您自行承擔。" +msgid "Learn more..." +msgstr "了解更多..." + msgid "Support" -msgstr "" +msgstr "支援" msgid "Package Requests" -msgstr "" +msgstr "套件請求" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" -msgstr "" +msgstr "有三種您可以在套件細節頁面中的 %s套件動作%s 中使用的請求:" msgid "Orphan Request" -msgstr "" +msgstr "棄置請求" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"請求一個套件被解除擁有權,例如:當維護者不活躍且套件已經被標記為過期很長一段" +"時間。" msgid "Deletion Request" -msgstr "" +msgstr "刪除請求" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"請求套件從 Arch 使用者套件庫中移除。如果套件損毀但可以很容易的被修復,請不要" +"使用這個請求。您應該聯絡套件維護者,並在必要時提出棄置請求。" msgid "Merge Request" -msgstr "" +msgstr "合併請求" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"請求將一個套件合併到另一個。可以使用在需要重新命名或是由分裂的套件所取代的套" +"件。" #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"如果您想要討論某一個請求,您可以使用 %saur-requests%s 郵件列表。但請不要使用" +"這個列表來提出請求。" + +msgid "Submitting Packages" +msgstr "遞交套件" + +#, php-format +msgid "" +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " +"details." +msgstr "" +"現在透過 SSH 的 Git 開始用於遞交套件到 AUR 上。參見 ArchWiki 上的 Arch User " +"Repository 頁面之 %s遞交套件%s 章節以取得更多資訊。" + +msgid "The following SSH fingerprints are used for the AUR:" +msgstr "下列 SSH 指紋被用於 AUR:" msgid "Discussion" msgstr "討論" @@ -196,6 +219,8 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"與 Arch 使用者套件庫(AUR)及受信使用者結構相關的一般性討論請見 %saur-general" +"%s 。討論關於 AUR 網頁介面的開發,請使用 %saur-dev%s 郵件列表。" msgid "Bug Reporting" msgstr "臭蟲回報" @@ -207,6 +232,9 @@ msgid "" "report packaging bugs contact the package maintainer or leave a comment on " "the appropriate package page." msgstr "" +"如果您在 AUR 網頁介面中發現了臭蟲,請在我們的 %s臭蟲追蹤系統%s 中回報。請%s" +"只%s回報 AUR 本身的臭蟲。要回報打包臭蟲,請連絡套件的維護者或是在對應的套件頁" +"面中留下評論。" msgid "Package Search" msgstr "搜尋套件" @@ -453,6 +481,12 @@ msgstr "最後一頁" msgid "Requests" msgstr "請求" +msgid "Register" +msgstr "註冊" + +msgid "Use this form to create an account." +msgstr "使用此表單來新建一個帳號。" + msgid "Trusted User" msgstr "受信使用者" @@ -595,6 +629,10 @@ msgstr "無效的電子郵件與密鑰組合。" msgid "None" msgstr "無" +#, php-format +msgid "View account information for %s" +msgstr "檢視 %s 的帳號資訊" + msgid "Error retrieving package details." msgstr "擷取套件細節時發生錯誤。" @@ -684,17 +722,11 @@ msgstr "評論已被刪除。" msgid "You are not allowed to delete this comment." msgstr "您不被允許刪除此則評論。" -msgid "Missing category ID." -msgstr "遺失分類 ID。" +msgid "You are not allowed to edit the keywords of this package base." +msgstr "您不被允許編輯此套件基礎的關鍵字。" -msgid "Invalid category ID." -msgstr "無效的分類 ID。" - -msgid "You are not allowed to change this package category." -msgstr "您不被允許改變此套件的分類。" - -msgid "Package category changed." -msgstr "套件分類已變更。" +msgid "The package base keywords have been updated." +msgstr "套件基礎關鍵字已更新。" msgid "You are not allowed to manage co-maintainers of this package base." msgstr "您不被允許管理此套件基礎的共同維護者。" @@ -873,15 +905,6 @@ msgstr "我的套件" msgid " My Account" msgstr "我的帳號" -msgid "Register" -msgstr "註冊" - -msgid "unknown" -msgstr "未知" - -msgid "Package Base Details" -msgstr "套件基礎詳細資訊" - msgid "Package Actions" msgstr "套件動作" @@ -935,22 +958,24 @@ msgstr "合併套件" msgid "Adopt Package" msgstr "接管套件" +msgid "unknown" +msgstr "未知" + +msgid "Package Base Details" +msgstr "套件基礎詳細資訊" + msgid "Git Clone URL" msgstr "Git Clone URL" -msgid "Category" -msgstr "分類" +msgid "read-only" +msgstr "唯讀" -msgid "Change category" -msgstr "變更分類" +msgid "Keywords" +msgstr "關鍵字" msgid "Submitter" msgstr "提交人" -#, php-format -msgid "View account information for %s" -msgstr "檢視 %s 的帳號資訊" - msgid "Maintainer" msgstr "維護者" @@ -1150,7 +1175,7 @@ msgid "Name" msgstr "名稱" msgid "Popularity" -msgstr "" +msgstr "人氣" msgid "Voted" msgstr "已投票" @@ -1167,15 +1192,9 @@ msgstr "遞減" msgid "Enter search criteria" msgstr "輸入搜尋條件" -msgid "Any" -msgstr "任意" - msgid "Search by" msgstr "以何種方式搜尋" -msgid "Keywords" -msgstr "關鍵字" - msgid "Out of Date" msgstr "過期狀態" @@ -1208,6 +1227,11 @@ msgstr[0] "找到 %d 個套件。" msgid "Version" msgstr "版本" +msgid "" +"Popularity is calculated as the sum of all votes with each vote being " +"weighted with a factor of 0.98 per day since its creation." +msgstr "人氣的計算方式為,將所有票數加總,且每一票自建立以來每天乘上 0.98。" + msgid "Yes" msgstr "是" From 7fbf5a82f384b9d989bf8fefe374799c6353be72 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 8 Aug 2015 12:58:28 +0200 Subject: [PATCH 0011/1891] Release 4.0.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index f2588bb8..099c8a7a 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Sun, 28 Jun 2015 15:37:28 +0200 Subject: [PATCH 0012/1891] Delete unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index debffc46..5a8154a4 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -204,7 +204,6 @@ class AurJSON { private function process_query($type, $where_condition) { $max_results = config_get_int('options', 'max_rpc_results'); - $package_url = config_get('options', 'package_url'); if ($this->version == 1) { $fields = implode(',', self::$fields_v1); From 94aeead4ecd230ea4c8cba0bb64501da1ef10886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sun, 28 Jun 2015 19:48:22 +0200 Subject: [PATCH 0013/1891] aurjson: Pass http_data array to all functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a preparatory patch that simplifies adding more arguments to the parse functions Signed-off-by: Johannes Löthberg Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 5a8154a4..9e7c2201 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -87,7 +87,7 @@ class AurJSON { $this->dbh = DB::connect(); $type = str_replace('-', '_', $http_data['type']); - $json = call_user_func(array(&$this, $type), $http_data['arg']); + $json = call_user_func(array(&$this, $type), $http_data); $etag = md5($json); header("Etag: \"$etag\""); @@ -293,11 +293,12 @@ class AurJSON { * IDs and package names are valid; sort them into the relevant arrays and * escape/quote the names. * - * @param $args the arg string or array to parse. + * @param array $http_data Query parameters. * * @return mixed An array containing 'ids' and 'names'. */ - private function parse_multiinfo_args($args) { + private function parse_multiinfo_args($http_data) { + $args = $http_data['arg']; if (!is_array($args)) { $args = array($args); } @@ -321,11 +322,13 @@ class AurJSON { /* * Performs a fulltext mysql search of the package database. * - * @param $keyword_string A string of keywords to search with. + * @param array $http_data Query parameters. * * @return mixed Returns an array of package matches. */ - private function search($keyword_string) { + private function search($http_data) { + $keyword_string = $http_data['arg']; + if (strlen($keyword_string) < 2) { return $this->json_error('Query arg too small'); } @@ -341,11 +344,12 @@ class AurJSON { /* * Returns the info on a specific package. * - * @param $pqdata The ID or name of the package. Package Query Data. + * @param array $http_data Query parameters. * * @return mixed Returns an array of value data containing the package data */ - private function info($pqdata) { + private function info($http_data) { + $pqdata = $http_data['arg']; if (is_numeric($pqdata)) { $where_condition = "Packages.ID = $pqdata"; } else { @@ -358,11 +362,12 @@ class AurJSON { /* * Returns the info on multiple packages. * - * @param $pqdata A comma-separated list of IDs or names of the packages. + * @param array $http_data Query parameters. * * @return mixed Returns an array of results containing the package data */ - private function multiinfo($pqdata) { + private function multiinfo($http_data) { + $pqdata = $http_data['arg']; $args = $this->parse_multiinfo_args($pqdata); $ids = $args['ids']; $names = $args['names']; @@ -394,11 +399,12 @@ class AurJSON { /* * Returns all the packages for a specific maintainer. * - * @param $maintainer The name of the maintainer. + * @param array $http_data Query parameters. * * @return mixed Returns an array of value data containing the package data */ - private function msearch($maintainer) { + private function msearch($http_data) { + $maintainer = $http_data['arg']; $maintainer = $this->dbh->quote($maintainer); $where_condition = "Users.Username = $maintainer "; @@ -409,11 +415,12 @@ class AurJSON { /* * Get all package names that start with $search. * - * @param string $search Search string. + * @param array $http_data Query parameters. * * @return string The JSON formatted response data. */ - private function suggest($search) { + private function suggest($http_data) { + $search = $http_data['arg']; $query = "SELECT Packages.Name FROM Packages "; $query.= "LEFT JOIN PackageBases "; $query.= "ON PackageBases.ID = Packages.PackageBaseID "; @@ -435,11 +442,12 @@ class AurJSON { /* * Get all package base names that start with $search. * - * @param string $search Search string. + * @param array $http_data Query parameters. * * @return string The JSON formatted response data. */ - private function suggest_pkgbase($search) { + private function suggest_pkgbase($http_data) { + $search = $http_data['arg']; $query = "SELECT Name FROM PackageBases WHERE Name LIKE "; $query.= $this->dbh->quote(addcslashes($search, '%_') . '%'); $query.= " AND PackageBases.PackagerUID IS NOT NULL "; From d8142abbbee6a44693bd303838777fb93013b5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sun, 28 Jun 2015 19:48:23 +0200 Subject: [PATCH 0014/1891] Expose name-only search through the RPC interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes FS#37317. Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 9e7c2201..8ead253a 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -16,6 +16,9 @@ class AurJSON { 'search', 'info', 'multiinfo', 'msearch', 'suggest', 'suggest-pkgbase' ); + private static $exposed_fields = array( + 'name', 'name-desc' + ); private static $fields_v1 = array( 'Packages.ID', 'Packages.Name', 'PackageBases.ID AS PackageBaseID', @@ -83,6 +86,9 @@ class AurJSON { if (!in_array($http_data['type'], self::$exposed_methods)) { return $this->json_error('Incorrect request type specified.'); } + if (isset($http_data['search_by']) && !in_array($http_data['search_by'], self::$exposed_fields)) { + return $this->json_error('Incorrect search_by field specified.'); + } $this->dbh = DB::connect(); @@ -328,6 +334,11 @@ class AurJSON { */ private function search($http_data) { $keyword_string = $http_data['arg']; + if (isset($http_data['search_by'])) { + $search_by = $http_data['search_by']; + } else { + $search_by = 'name-desc'; + } if (strlen($keyword_string) < 2) { return $this->json_error('Query arg too small'); @@ -335,8 +346,12 @@ class AurJSON { $keyword_string = $this->dbh->quote("%" . addcslashes($keyword_string, '%_') . "%"); - $where_condition = "(Packages.Name LIKE $keyword_string OR "; - $where_condition .= "Description LIKE $keyword_string)"; + if ($search_by === 'name') { + $where_condition = "(Packages.Name LIKE $keyword_string)"; + } else if ($search_by === 'name-desc') { + $where_condition = "(Packages.Name LIKE $keyword_string OR "; + $where_condition .= "Description LIKE $keyword_string)"; + } return $this->process_query('search', $where_condition); } From 9746a654736cba12c234f3c1b3d7b67427678ce3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 27 Jun 2015 22:20:48 +0200 Subject: [PATCH 0015/1891] Port notification routines to Python Use a Python script for sending notification emails. The notification action and additional parameters are passed via command line arguments. For comment and package request notifications, the text is passed via stdin. Signed-off-by: Lukas Fleischer --- conf/config.proto | 5 + scripts/notify.py | 232 +++++++++++++++++++++++++++++++++++ web/html/passreset.php | 9 +- web/lib/acctfuncs.inc.php | 72 ++++++----- web/lib/pkgbasefuncs.inc.php | 106 ++-------------- web/lib/pkgreqfuncs.inc.php | 115 ++--------------- 6 files changed, 298 insertions(+), 241 deletions(-) create mode 100755 scripts/notify.py diff --git a/conf/config.proto b/conf/config.proto index 2fbc27a3..52da7967 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -31,6 +31,11 @@ snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 +[notifications] +sendmail = /usr/bin/sendmail +sender = notify@aur.archlinux.org +reply-to = noreply@aur.archlinux.org + [fingerprints] Ed25519 = SHA256:HQ03dn6EasJHNDlt51KpQpFkT3yBX83x7BoIkA1iv2k ECDSA = SHA256:L71Q91yHwmHPYYkJMDgj0xmUuw16qFOhJbBr1mzsiOI diff --git a/scripts/notify.py b/scripts/notify.py new file mode 100755 index 00000000..017555a7 --- /dev/null +++ b/scripts/notify.py @@ -0,0 +1,232 @@ +#!/usr/bin/python3 + +import configparser +import email.mime.text +import mysql.connector +import os +import smtplib +import subprocess +import sys +import textwrap + +config = configparser.RawConfigParser() +config.read(os.path.dirname(os.path.realpath(__file__)) + '/../conf/config') + +aur_db_host = config.get('database', 'host') +aur_db_name = config.get('database', 'name') +aur_db_user = config.get('database', 'user') +aur_db_pass = config.get('database', 'password') +aur_db_socket = config.get('database', 'socket') + +aur_location = config.get('options', 'aur_location') +aur_request_ml = config.get('options', 'aur_request_ml') + +sendmail = config.get('notifications', 'sendmail') +sender = config.get('notifications', 'sender') +reply_to = config.get('notifications', 'reply-to') + + +def send_notification(to, subject, body, cc=None, reference=None): + body = str.join('\n', [textwrap.fill(line) for line in body.splitlines()]) + + for recipient in to: + msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') + msg['Subject'] = subject + msg['From'] = sender + msg['Reply-to'] = reply_to + msg['To'] = recipient + + if cc: + msg['Cc'] = str.join(', ', cc) + + if reference: + msg['In-Reply-To'] = reference + msg['References'] = reference + + p = subprocess.Popen([sendmail, '-t', '-oi'], stdin=subprocess.PIPE) + p.communicate(msg.as_bytes()) + +def username_from_id(cur, uid): + cur.execute('SELECT UserName FROM Users WHERE ID = %s', [uid]) + return cur.fetchone()[0] + +def pkgbase_from_id(cur, pkgbase_id): + cur.execute('SELECT Name FROM PackageBases WHERE ID = %s', [pkgbase_id]) + return cur.fetchone()[0] + +def pkgbase_from_pkgreq(cur, reqid): + cur.execute('SELECT PackageBaseID FROM PackageRequests WHERE ID = %s', + [reqid]) + return cur.fetchone()[0] + +def get_maintainer_email(cur, pkgbase_id): + cur.execute('SELECT Users.Email FROM Users ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.MaintainerUID = Users.ID WHERE ' + + 'PackageBases.ID = %s', [pkgbase_id]) + return cur.fetchone()[0] + +def get_recipients(cur, pkgbase_id, uid): + cur.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN CommentNotify ' + + 'ON CommentNotify.UserID = Users.ID WHERE ' + + 'CommentNotify.UserID != %s AND ' + + 'CommentNotify.PackageBaseID = %s', [uid, pkgbase_id]) + return [row[0] for row in cur.fetchall()] + +def get_request_recipients(cur, pkgbase_id, uid): + cur.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.MaintainerUID = Users.ID WHERE ' + + 'Users.ID = %s OR PackageBases.ID = %s', [uid, pkgbase_id]) + return [row[0] for row in cur.fetchall()] + +def send_resetkey(cur, uid): + cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', + [uid]) + username, to, resetkey = cur.fetchone() + + subject = 'AUR Password Reset' + body = 'A password reset request was submitted for the account %s ' \ + 'associated with your e-mail address. If you wish to reset your ' \ + 'password follow the link below, otherwise ignore this message ' \ + 'and nothing will happen.' % (username) + body += '\n\n' + body += '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey + + send_notification([to], subject, body) + +def welcome(cur, uid): + cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', + [uid]) + username, to, resetkey = cur.fetchone() + + subject = 'Welcome to the Arch User Repository' + body = 'Welcome to %s! In order to set an initial password for your new ' \ + 'account, please click the link below. If the link does not work ' \ + 'try copying and pasting it into your browser.' % (aur_location) + body += '\n\n' + body += '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey + + send_notification([to], subject, body) + +def comment(cur, uid, pkgbase_id): + user = username_from_id(cur, uid) + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = get_recipients(cur, pkgbase_id, uid) + text = sys.stdin.read() + + uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = 'AUR Comment for %s' % (pkgbase) + body = 'from %s\n%s wrote:\n\n%s\n\n--- \n' \ + 'If you no longer wish to receive notifications about this ' \ + 'package, please go the the above package page and click the ' \ + 'UnNotify button.' % (uri, user, text) + thread_id = '' + + send_notification(to, subject, body, reference=thread_id) + +def flag(cur, uid, pkgbase_id): + user = username_from_id(cur, uid) + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = [get_maintainer_email(cur, pkgbase_id)] + + user_uri = aur_location + '/account/' + user + '/' + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = 'AUR Out-of-date Notification for %s' % (pkgbase) + body = 'Your package %s has been flagged out of date by %s [1]. ' \ + 'You may view your package at:\n%s\n\n[1] %s' % \ + (pkgbase, user, pkgbase_uri, user_uri) + + send_notification(to, subject, body) + +def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): + user = username_from_id(cur, uid) + old_pkgbase = pkgbase_from_id(cur, old_pkgbase_id) + if new_pkgbase_id: + new_pkgbase = pkgbase_from_id(cur, new_pkgbase_id) + to = get_recipients(cur, old_pkgbase_id, uid) + + subject = 'AUR Package deleted: %s' % (old_pkgbase) + if new_pkgbase_id: + new_pkgbase_uri = aur_location + '/pkgbase/' + new_pkgbase + '/' + body = '%s merged "%s" into "%s".\n\nYou will no longer receive ' \ + 'notifications about this package, please go to %s and click ' \ + 'the Notify button if you wish to recieve them again.' % \ + (user, old_pkgbase, new_pkgbase, new_pkgbase_uri) + else: + body = '%s deleted "%s".\n\nYou will no longer receive ' \ + 'notifications about this package.' % (user, old_pkgbase) + + send_notification(to, subject, body) + +def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): + user = username_from_id(cur, uid) + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = [aur_request_ml] + cc = get_request_recipients(cur, pkgbase_id, uid) + text = sys.stdin.read() + + user_uri = aur_location + '/account/' + user + '/' + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = '[PRQ#%d] %s Request for %s' % \ + (int(reqid), reqtype.title(), pkgbase) + if merge_into: + merge_into_uri = aur_location + '/pkgbase/' + merge_into + '/' + body = '%s [1] filed a request to merge %s [2] into %s [3]:\n\n' \ + '%s\n\n[1] %s\n[2] %s\n[3] %s\n' % \ + (user, pkgbase, merge_into, text, user_uri, pkgbase_uri, + merge_into_uri) + else: + body = '%s [1] filed a %s request for %s [2]:\n\n' \ + '%s\n\n[1] %s\n[2] %s\n' % \ + (user, reqtype, pkgbase, text, user_uri, pkgbase_uri) + thread_id = '' + + send_notification(to, subject, body, cc, thread_id) + +def request_close(cur, uid, reqid, reason): + user = username_from_id(cur, uid) + pkgbase_id = pkgbase_from_pkgreq(cur, reqid) + to = [aur_request_ml] + cc = get_request_recipients(cur, pkgbase_id, uid) + text = sys.stdin.read() + + user_uri = aur_location + '/account/' + user + '/' + + subject = '[PRQ#%d] Request %s' % (int(reqid), reason.title()) + body = 'Request #%d has been %s by %s [1]' % (int(reqid), reason, user) + if text.strip() == '': + body += '.\n\n' + else: + body += ':\n\n' + text + '\n\n' + body += '[1] ' + user_uri + thread_id = '' + + send_notification(to, subject, body, cc, thread_id) + + +if __name__ == '__main__': + action = sys.argv[1] + action_map = { + 'send-resetkey': send_resetkey, + 'welcome': welcome, + 'comment': comment, + 'flag': flag, + 'delete': delete, + 'request-open': request_open, + 'request-close': request_close, + } + + db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) + cur = db.cursor() + + action_map[action](cur, *sys.argv[2:]) + + db.commit() + db.close() diff --git a/web/html/passreset.php b/web/html/passreset.php index 29f2c648..cb2f6bcd 100644 --- a/web/html/passreset.php +++ b/web/html/passreset.php @@ -46,14 +46,7 @@ if (isset($_GET['resetkey'], $_POST['email'], $_POST['password'], $_POST['confir if (empty($email)) { $error = __('Missing a required field.'); } else { - $subject = 'AUR Password Reset'; - $body = __('A password reset request was submitted for the ' . - 'account %s associated with your e-mail address. ' . - 'If you wish to reset your password follow the ' . - 'link below, otherwise ignore this message and ' . - 'nothing will happen.', $username); - send_resetkey($email, $subject, $body); - + send_resetkey($email); header('Location: ' . get_uri('/passreset/') . '?step=confirm'); exit(); } diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index edd38ee8..2b57b2dd 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -288,26 +288,14 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", "", htmlspecialchars($U,ENT_QUOTES), ""); print "

\n"; - if (!$send_resetkey) { + if ($send_resetkey) { + send_resetkey($email, true); + print __("A password reset key has been sent to your e-mail address."); + print "

\n"; + } else { print __("Click on the Login link above to use your account."); print "

\n"; - return; } - - $subject = 'Welcome to the Arch User Repository'; - $body = __('Welcome to %s! In order ' . - 'to set an initial password ' . - 'for your new account, ' . - 'please click the link ' . - 'below. If the link does ' . - 'not work try copying and ' . - 'pasting it into your ' . - 'browser.', - aur_location()); - send_resetkey($email, $subject, $body); - - print __("A password reset key has been sent to your e-mail address."); - print "

\n"; } else { /* Modify an existing account. */ $q = "SELECT InactivityTS FROM Users WHERE "; @@ -705,12 +693,11 @@ function create_resetkey($resetkey, $uid) { * Send a reset key to a specific e-mail address * * @param string $email E-mail address of the user resetting their password - * @param string $subject Subject of the email - * @param string $body Body of the email + * @param bool $welcome Whether to use the welcome message * * @return void */ -function send_resetkey($email, $subject, $body) { +function send_resetkey($email, $welcome=false) { $uid = uid_from_email($email); if ($uid == null) { return; @@ -721,16 +708,7 @@ function send_resetkey($email, $subject, $body) { create_resetkey($resetkey, $uid); /* Send e-mail with confirmation link. */ - $body = wordwrap($body, 70); - $body .= "\n\n". get_uri('/passreset/', true) . - "?resetkey={$resetkey}"; - $headers = "MIME-Version: 1.0\r\n" . - "Content-type: text/plain; charset=UTF-8\r\n" . - "Reply-to: noreply@aur.archlinux.org\r\n" . - "From: notify@aur.archlinux.org\r\n" . - "X-Mailer: PHP\r\n" . - "X-MimeOLE: Produced By AUR"; - @mail($email, $subject, $body, $headers); + notify(array($welcome ? 'welcome' : 'send-resetkey', $uid)); } /** @@ -1309,3 +1287,37 @@ function account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints) { return true; } + +/* + * Invoke the email notification script. + * + * @param string $params Command line parameters for the script. + * @param string $text Text to pass via stdin. + * + * @return void + */ +function notify($params, $text='') { + $cmd = realpath('../../scripts/notify.py'); + foreach ($params as $param) { + $cmd .= ' ' . escapeshellarg($param); + } + + $descspec = array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ); + + $p = proc_open($cmd, $descspec, $pipes); + + if (!is_resource($p)) { + return false; + } + + fwrite($pipes[0], $text); + fclose($pipes[0]); + fclose($pipes[1]); + fclose($pipes[2]); + + return proc_close($p); +} diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 92202bf8..5d191ebf 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -97,37 +97,7 @@ function pkgbase_add_comment($base_id, $uid, $comment) { $bcc = array(); if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - array_push($bcc, $row['Email']); - } - - $q = "SELECT Name FROM PackageBases WHERE ID = "; - $q.= intval($base_id); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_ASSOC); - - /* - * TODO: Add native language emails for users, based on their - * preferences. Simply making these strings translatable won't - * work, users would be getting emails in the language that the - * user who posted the comment was in. - */ - $body = 'from ' . get_pkgbase_uri($row['Name'], true) . "\n" - . username_from_sid($_COOKIE['AURSID']) . " wrote:\n\n" - . $comment - . "\n\n---\nIf you no longer wish to receive notifications about this package, please go the the above package page and click the UnNotify button."; - $body = wordwrap($body, 70); - $bcc = implode(', ', $bcc); - $thread_id = ""; - $headers = "MIME-Version: 1.0\r\n" . - "Content-type: text/plain; charset=UTF-8\r\n" . - "Bcc: $bcc\r\n" . - "Reply-to: noreply@aur.archlinux.org\r\n" . - "From: notify@aur.archlinux.org\r\n" . - "In-Reply-To: $thread_id\r\n" . - "References: $thread_id\r\n" . - "X-Mailer: AUR"; - @mail('undisclosed-recipients: ;', "AUR Comment for " . $row['Name'], $body, $headers); + notify(array('comment', $uid, $base_id), $comment); } } @@ -355,33 +325,11 @@ function pkgbase_flag($base_ids) { $q.= " OutOfDateTS = UNIX_TIMESTAMP()"; $q.= " WHERE ID IN (" . implode(",", $base_ids) . ")"; $q.= " AND OutOfDateTS IS NULL"; + $dbh->exec($q); - $affected_pkgs = $dbh->exec($q); - - if ($affected_pkgs > 0) { - /* Notify of flagging by e-mail. */ - $f_name = username_from_sid($_COOKIE['AURSID']); - $f_email = email_from_sid($_COOKIE['AURSID']); - $f_uid = uid_from_sid($_COOKIE['AURSID']); - $q = "SELECT PackageBases.Name, Users.Email "; - $q.= "FROM PackageBases, Users "; - $q.= "WHERE PackageBases.ID IN (" . implode(",", $base_ids) .") "; - $q.= "AND Users.ID = PackageBases.MaintainerUID "; - $q.= "AND Users.ID != " . $f_uid; - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $body = "Your package " . $row['Name'] . " has been flagged out of date by " . $f_name . " [1]. You may view your package at:\n" . get_pkgbase_uri($row['Name'], true) . "\n\n[1] - " . get_user_uri($f_name, true); - $body = wordwrap($body, 70); - $headers = "MIME-Version: 1.0\r\n" . - "Content-type: text/plain; charset=UTF-8\r\n" . - "Reply-to: noreply@aur.archlinux.org\r\n" . - "From: notify@aur.archlinux.org\r\n" . - "X-Mailer: PHP\r\n" . - "X-MimeOLE: Produced By AUR"; - @mail($row['Email'], "AUR Out-of-date Notification for ".$row['Name'], $body, $headers); - } - } + $uid = uid_from_sid($_COOKIE['AURSID']); + foreach ($base_ids as $base_id) { + notify(array('flag', $uid, $base_id)); } return array(true, __("The selected packages have been flagged out-of-date.")); @@ -449,46 +397,12 @@ function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) { $merge_base_name = pkgbase_name_from_id($merge_base_id); } - /* Send e-mail notifications. */ + $uid = uid_from_sid($_COOKIE['AURSID']); foreach ($base_ids as $base_id) { - $q = "SELECT CommentNotify.*, Users.Email "; - $q.= "FROM CommentNotify, Users "; - $q.= "WHERE Users.ID = CommentNotify.UserID "; - $q.= "AND CommentNotify.UserID != " . uid_from_sid($_COOKIE['AURSID']) . " "; - $q.= "AND CommentNotify.PackageBaseID = " . $base_id; - $result = $dbh->query($q); - $bcc = array(); - - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - array_push($bcc, $row['Email']); - } - if (!empty($bcc)) { - $pkgbase_name = pkgbase_name_from_id($base_id); - - /* - * TODO: Add native language emails for users, based on - * their preferences. Simply making these strings - * translatable won't work, users would be getting - * emails in the language that the user who posted the - * comment was in. - */ - $body = ""; - if ($merge_base_id) { - $body .= username_from_sid($_COOKIE['AURSID']) . " merged \"".$pkgbase_name."\" into \"$merge_base_name\".\n\n"; - $body .= "You will no longer receive notifications about this package, please go to https://aur.archlinux.org" . get_pkgbase_uri($merge_base_name) . " and click the Notify button if you wish to recieve them again."; - } else { - $body .= username_from_sid($_COOKIE['AURSID']) . " deleted \"".$pkgbase_name."\".\n\n"; - $body .= "You will no longer receive notifications about this package."; - } - $body = wordwrap($body, 70); - $bcc = implode(', ', $bcc); - $headers = "MIME-Version: 1.0\r\n" . - "Content-type: text/plain; charset=UTF-8\r\n" . - "Bcc: $bcc\r\n" . - "Reply-to: noreply@aur.archlinux.org\r\n" . - "From: notify@aur.archlinux.org\r\n" . - "X-Mailer: AUR"; - @mail('undisclosed-recipients: ;', "AUR Package deleted: " . $pkgbase_name, $body, $headers); + if ($merge_base_id) { + notify(array('delete', $uid, $base_id, $merge_base_id)); + } else { + notify(array('delete', $uid, $base_id)); } } diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index c056d681..3ea46926 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -153,59 +153,12 @@ function pkgreq_file($ids, $type, $merge_into, $comments) { $dbh->exec($q); $request_id = $dbh->lastInsertId(); - /* - * Send e-mail notifications. - * TODO: Move notification logic to separate function where it belongs. - */ - $cc = array(pkgreq_get_creator_email($request_id)); - - $q = "SELECT Users.Email "; - $q.= "FROM Users INNER JOIN PackageBases "; - $q.= "ON PackageBases.MaintainerUID = Users.ID "; - $q.= "WHERE PackageBases.ID = " . $base_id; - $result = $dbh->query($q); - if ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $cc[] = $row['Email']; + /* Send e-mail notifications. */ + $params = array('request-open', $uid, $request_id, $type, $base_id); + if ($type === 'merge') { + $params[] = $merge_into; } - - $q = "SELECT Name FROM PackageBases WHERE ID = " . $base_id; - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_ASSOC); - - /* - * TODO: Add native language emails for users, based on their - * preferences. Simply making these strings translatable won't - * work, users would be getting emails in the language that the - * user who posted the comment was in. - */ - $username = username_from_sid($_COOKIE['AURSID']); - if ($type == 'merge') { - $body = - $username . " [1] filed a request to merge " . - $row['Name'] . " [2] into " . $merge_into . - " [3]:\n\n" . $comments . "\n\n" . - "[1] " . get_user_uri($username, true) . "\n" . - "[2] " . get_pkgbase_uri($row['Name'], true) . "\n" . - "[3] " . get_pkgbase_uri($merge_into, true) . "\n"; - } else { - $body = - $username . " [1] filed a " . $type . " request for " . - $row['Name'] . " [2]:\n\n" . $comments . "\n\n" . - "[1] " . get_user_uri($username, true) . "\n" . - "[2] " . get_pkgbase_uri($row['Name'], true) . "\n"; - } - $body = wordwrap($body, 70); - $cc = array_unique($cc); - $headers = "MIME-Version: 1.0\r\n" . - "Content-type: text/plain; charset=UTF-8\r\n" . - "Cc: " . implode(', ', $cc) . "\r\n"; - $thread_id = ""; - $headers .= "From: notify@aur.archlinux.org\r\n" . - "Message-ID: $thread_id\r\n" . - "X-Mailer: AUR"; - $ml = config_get('options', 'aur_request_ml'); - @mail($ml, "[PRQ#" . $request_id . "] " . ucfirst($type) . - " Request for " . $row['Name'], $body, $headers); + notify($params, $comments); $auto_orphan_age = config_get('options', 'auto_orphan_age'); $auto_delete_age = config_get('options', 'auto_delete_age'); @@ -268,6 +221,7 @@ function pkgreq_close($id, $reason, $comments, $auto_close=false) { $dbh = DB::connect(); $id = intval($id); + $uid = uid_from_sid($_COOKIE["AURSID"]); if (!$auto_close && !has_credential(CRED_PKGREQ_CLOSE)) { return array(false, __("Only TUs and developers can close requests.")); @@ -277,61 +231,8 @@ function pkgreq_close($id, $reason, $comments, $auto_close=false) { $q.= "WHERE ID = " . intval($id); $dbh->exec($q); - /* - * Send e-mail notifications. - * TODO: Move notification logic to separate function where it belongs. - */ - $cc = array(pkgreq_get_creator_email($id)); - - $q = "SELECT Users.Email "; - $q.= "FROM Users INNER JOIN PackageBases "; - $q.= "ON PackageBases.MaintainerUID = Users.ID "; - $q.= "INNER JOIN PackageRequests "; - $q.= "ON PackageRequests.PackageBaseID = PackageBases.ID "; - $q.= "WHERE PackageRequests.ID = " . $id; - $result = $dbh->query($q); - if ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $cc[] = $row['Email']; - } - - /* - * TODO: Add native language emails for users, based on their - * preferences. Simply making these strings translatable won't - * work, users would be getting emails in the language that the - * user who posted the comment was in. - */ - if ($auto_close) { - $body = "Request #" . intval($id) . " has been " . $reason . - " automatically by the Arch User Repository package " . - "request system"; - } else { - $username = username_from_sid($_COOKIE['AURSID']); - $body = "Request #" . intval($id) . " has been " . $reason . - " by " . $username . " [1]"; - } - if (!empty(trim($comments))) { - $body .= ":\n\n" . $comments . "\n"; - } else { - $body .= ".\n"; - } - if (!$auto_close) { - $body .= "\n"; - $body .= "[1] " . get_user_uri($username, true); - $body .= "\n"; - } - $body = wordwrap($body, 70); - $cc = array_unique($cc); - $headers = "MIME-Version: 1.0\r\n" . - "Content-type: text/plain; charset=UTF-8\r\n" . - "Cc: " . implode(', ', $cc) . "\r\n"; - $thread_id = ""; - $headers .= "From: notify@aur.archlinux.org\r\n" . - "In-Reply-To: $thread_id\r\n" . - "References: $thread_id\r\n" . - "X-Mailer: AUR"; - $ml = config_get('options', 'aur_request_ml'); - @mail($ml, "[PRQ#" . $id . "] Request " . ucfirst($reason), - $body, $headers); + /* Send e-mail notifications. */ + notify(array('request-close', $uid, $id, $reason), $comments); return array(true, __("Request closed successfully.")); } From a46f34a6c09ac8f26a71b4865d9bf87f2e88b2e8 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 28 Jun 2015 09:46:32 +0200 Subject: [PATCH 0016/1891] notify: Reword notification emails * Use numbered references for links. * Reword some messages. * Fix a typo. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 78 +++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 017555a7..8be3a701 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -88,9 +88,9 @@ def send_resetkey(cur, uid): subject = 'AUR Password Reset' body = 'A password reset request was submitted for the account %s ' \ - 'associated with your e-mail address. If you wish to reset your ' \ - 'password follow the link below, otherwise ignore this message ' \ - 'and nothing will happen.' % (username) + 'associated with your email address. If you wish to reset your ' \ + 'password follow the link [1] below, otherwise ignore this ' \ + 'message and nothing will happen.' % (username) body += '\n\n' body += '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey @@ -102,9 +102,10 @@ def welcome(cur, uid): username, to, resetkey = cur.fetchone() subject = 'Welcome to the Arch User Repository' - body = 'Welcome to %s! In order to set an initial password for your new ' \ - 'account, please click the link below. If the link does not work ' \ - 'try copying and pasting it into your browser.' % (aur_location) + body = 'Welcome to the Arch User Repository! In order to set an initial ' \ + 'password for your new account, please click the link [1] below. ' \ + 'If the link does not work, try copying and pasting it into your ' \ + 'browser.' body += '\n\n' body += '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey @@ -118,11 +119,18 @@ def comment(cur, uid, pkgbase_id): uri = aur_location + '/pkgbase/' + pkgbase + '/' + user_uri = aur_location + '/account/' + user + '/' + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + subject = 'AUR Comment for %s' % (pkgbase) - body = 'from %s\n%s wrote:\n\n%s\n\n--- \n' \ - 'If you no longer wish to receive notifications about this ' \ - 'package, please go the the above package page and click the ' \ - 'UnNotify button.' % (uri, user, text) + body = '%s [1] added the following comment to %s [2]:' % (user, pkgbase) + body += '\n\n' + text + '\n\n' + body += 'If you no longer wish to receive notifications about this ' \ + 'package, please go to the package page [2] and select "%s".' % \ + ('Disable notifications') + body += '\n\n' + body += '[1] ' + user_uri + '\n' + body += '[2] ' + pkgbase_uri thread_id = '' send_notification(to, subject, body, reference=thread_id) @@ -136,9 +144,11 @@ def flag(cur, uid, pkgbase_id): pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' subject = 'AUR Out-of-date Notification for %s' % (pkgbase) - body = 'Your package %s has been flagged out of date by %s [1]. ' \ - 'You may view your package at:\n%s\n\n[1] %s' % \ - (pkgbase, user, pkgbase_uri, user_uri) + body = 'Your package %s [1] has been flagged out-of-date by %s [2]. ' % \ + (pkgbase, user) + body += '\n\n' + body += '[1] ' + pkgbase_uri + '\n' + body += '[2] ' + user_uri send_notification(to, subject, body) @@ -149,16 +159,28 @@ def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): new_pkgbase = pkgbase_from_id(cur, new_pkgbase_id) to = get_recipients(cur, old_pkgbase_id, uid) + user_uri = aur_location + '/account/' + user + '/' + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + subject = 'AUR Package deleted: %s' % (old_pkgbase) if new_pkgbase_id: new_pkgbase_uri = aur_location + '/pkgbase/' + new_pkgbase + '/' - body = '%s merged "%s" into "%s".\n\nYou will no longer receive ' \ - 'notifications about this package, please go to %s and click ' \ - 'the Notify button if you wish to recieve them again.' % \ - (user, old_pkgbase, new_pkgbase, new_pkgbase_uri) + body = '%s [1] merged %s [2] into %s [3].\n\n' \ + 'You will no longer receive notifications about this ' \ + 'package, please go to [3] and click "%s" if you wish to ' \ + 'receive them again.' % \ + (user, old_pkgbase, new_pkgbase, 'Notify of new comments') + body += '\n\n' + body += '[1] ' + user_uri + '\n' + body += '[2] ' + pkgbase_uri + '\n' + body += '[3] ' + new_pkgbase_uri else: - body = '%s deleted "%s".\n\nYou will no longer receive ' \ - 'notifications about this package.' % (user, old_pkgbase) + body = '%s [1] deleted %s [2].\n\n' \ + 'You will no longer receive notifications about this ' \ + 'package.' % (user, old_pkgbase) + body += '\n\n' + body += '[1] ' + user_uri + '\n' + body += '[2] ' + pkgbase_uri send_notification(to, subject, body) @@ -176,14 +198,18 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): (int(reqid), reqtype.title(), pkgbase) if merge_into: merge_into_uri = aur_location + '/pkgbase/' + merge_into + '/' - body = '%s [1] filed a request to merge %s [2] into %s [3]:\n\n' \ - '%s\n\n[1] %s\n[2] %s\n[3] %s\n' % \ - (user, pkgbase, merge_into, text, user_uri, pkgbase_uri, - merge_into_uri) + body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \ + (user, pkgbase, merge_into) + body += '\n\n' + text + '\n\n' + body += '[1] ' + user_uri + '\n' + body += '[2] ' + pkgbase_uri + '\n' + body += '[3] ' + merge_into_uri else: - body = '%s [1] filed a %s request for %s [2]:\n\n' \ - '%s\n\n[1] %s\n[2] %s\n' % \ - (user, reqtype, pkgbase, text, user_uri, pkgbase_uri) + body = '%s [1] filed a %s request for %s [2]:' % \ + (user, reqtype, pkgbase) + body += '\n\n' + text + '\n\n' + body += '[1] ' + user_uri + '\n' + body += '[2] ' + pkgbase_uri + '\n' thread_id = '' send_notification(to, subject, body, cc, thread_id) From 828506e868aea994d8fb842ac1391d439cecca69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Thu, 2 Jul 2015 16:55:14 +0200 Subject: [PATCH 0017/1891] Reindent web/html/packages with tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/html/packages.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/web/html/packages.php b/web/html/packages.php index 75a574e6..bf3daf88 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -46,31 +46,31 @@ html_header($title, $details); From 4ca87473964a6da45bd6b8a1679afcdc1a0694af Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Wed, 8 Jul 2015 03:36:05 +0200 Subject: [PATCH 0018/1891] Remove superfluous close tags These are already output by html_action_link. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/pkgbase_actions.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php index 61ad18f5..c7428ee6 100644 --- a/web/template/pkgbase_actions.php +++ b/web/template/pkgbase_actions.php @@ -28,15 +28,15 @@ -
  • +
  • 0) { echo _n('%d pending request', '%d pending requests', $row["RequestCount"]); } ?>
  • -
  • +
  • -
  • -
  • +
  • +
  • From 8375d212106918b602911f6286d2e4fd172d446e Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Thu, 9 Jul 2015 00:33:25 +0200 Subject: [PATCH 0019/1891] Use SVG image for comment deletion icon This also puts the icon to the right and the timestamp in the byline and wipes out a repeated instance of the byline. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 16 ++++++++++++++++ web/html/images/x.min.svg | 3 +++ web/html/images/x.png | Bin 725 -> 0 bytes web/html/images/x.svg | 31 +++++++++++++++++++++++++++++++ web/html/index.php | 4 ++++ web/template/pkg_comments.php | 28 +++++++++++----------------- 6 files changed, 65 insertions(+), 17 deletions(-) create mode 100644 web/html/images/x.min.svg delete mode 100644 web/html/images/x.png create mode 100644 web/html/images/x.svg diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index d67877a0..adc02bb1 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -96,6 +96,22 @@ color: #999; } +.delete-comment-form { + float: right; +} + +.delete-comment { + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + opacity: 0.6; +} + +.delete-comment:hover { + -webkit-filter: none; + filter: none; + opacity: 1; +} + legend { padding: 1em 0; } diff --git a/web/html/images/x.min.svg b/web/html/images/x.min.svg new file mode 100644 index 00000000..833d4f22 --- /dev/null +++ b/web/html/images/x.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/html/images/x.png b/web/html/images/x.png deleted file mode 100644 index a85e169237108fc532c15c7b90e497b1f6a12649..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 725 zcmV;`0xJE9P)Q7YGt$v@9|^M=wAO@LqqIh; z-F06dDvi_B%;3ce@(-7( zlty@E{4GKE?K^}kzu1_10AYw>Sr~2&jbr1uef?N<^=!VHMaAaf0fbtECkd7oQNLGk zPxa6~ahGIg7m2oZnr}|v_Vp7L@$bj{!`>6F*?Dms1T)Rd3 z@(t|nUMkxKw&$iXLWz?~q4ZH;N>lLzOvi=gz7lYq)+bi8|?ZM=;d!1p~OxmsYnHd65;G4 ztbt*+-n}F&7LE?UtZ!f~w?VR{mW}5#IH@#FDuoULOveEscBCyW5f%$97d+}aIt~XL zymXZ>Po^mpd=wTcuTYzt2OfJwxZ9`O+ZdUg+&eF-`8oapyPjt9#lg;Q00000NkvXX Hu0mjf + + + + + image/svg+xml + + + + + + + + diff --git a/web/html/index.php b/web/html/index.php index 27d897c7..2d5f2a97 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -173,6 +173,10 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { header("Content-Type: image/png"); readfile("./$path"); break; + case "/images/x.min.svg": + header("Content-Type: image/svg+xml"); + readfile("./$path"); + break; case "/js/bootstrap-typeahead.min.js": header("Content-Type: application/javascript"); readfile("./$path"); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 3e99d9b3..03a65817 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -20,32 +20,26 @@ $count = pkgbase_comments_count($base_id, $include_deleted); $row['UserName'] = "{$row['UserName']}"; endif; ?> class="comment-deleted"> + + + + + + + + () + -
    +
    - +
    - - - - -
    - - - - - - - - () - -

    From 92e19e95f3c07745e7ba7c6e358921b7789f8abe Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Fri, 10 Jul 2015 18:47:31 +0200 Subject: [PATCH 0020/1891] Add comment edit icon and form Show an icon next to the comment deletion icon, which leads to a comment edit form. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/commentedit.php | 21 ++++++++++++ web/html/css/aurweb.css | 13 ++++++-- web/html/images/pencil.min.svg | 3 ++ web/html/images/pencil.svg | 55 +++++++++++++++++++++++++++++++ web/html/index.php | 4 +++ web/html/pkgbase.php | 4 +-- web/lib/aur.inc.php | 19 +++++++++++ web/lib/credentials.inc.php | 2 ++ web/lib/pkgfuncs.inc.php | 14 ++++++++ web/template/pkg_comment_form.php | 10 ++++-- web/template/pkg_comments.php | 3 ++ 11 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 web/html/commentedit.php create mode 100644 web/html/images/pencil.min.svg create mode 100644 web/html/images/pencil.svg diff --git a/web/html/commentedit.php b/web/html/commentedit.php new file mode 100644 index 00000000..83d86dd5 --- /dev/null +++ b/web/html/commentedit.php @@ -0,0 +1,21 @@ + + + diff --git a/web/html/images/pencil.svg b/web/html/images/pencil.svg new file mode 100644 index 00000000..91f08991 --- /dev/null +++ b/web/html/images/pencil.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/web/html/index.php b/web/html/index.php index 2d5f2a97..175a533f 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -89,6 +89,9 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { case "comaintainers": include('comaintainers.php'); return; + case "edit-comment": + include('commentedit.php'); + return; default: header("HTTP/1.0 404 Not Found"); include "./404.php"; @@ -174,6 +177,7 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { readfile("./$path"); break; case "/images/x.min.svg": + case "/images/pencil.min.svg": header("Content-Type: image/svg+xml"); readfile("./$path"); break; diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 5179d0c1..f9080290 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -104,9 +104,7 @@ if (check_token()) { list($ret, $output) = pkgreq_close($_POST['reqid'], $_POST['reason'], $_POST['comments']); } elseif (current_action("do_EditComaintainers")) { list($ret, $output) = pkgbase_set_comaintainers($base_id, explode("\n", $_POST['users'])); - } - - if (isset($_REQUEST['comment'])) { + } elseif (current_action("do_AddComment")) { $uid = uid_from_sid($_COOKIE["AURSID"]); pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); $ret = true; diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index b410db5a..99975356 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -576,6 +576,25 @@ function salted_hash($passwd, $salt) { return md5($salt . $passwd); } +/** + * Get a package comment + * + * @param int $comment_id The ID of the comment + * + * @return array The user ID and comment OR null, null in case of an error + */ +function comment_by_id($comment_id) { + $dbh = DB::connect(); + $q = "SELECT UsersID, Comments FROM PackageComments "; + $q.= "WHERE ID = " . intval($comment_id); + $result = $dbh->query($q); + if (!$result) { + return array(null, null); + } + + return $result->fetch(PDO::FETCH_NUM); +} + /** * Process submitted comments so any links can be followed * diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index cf1fccab..648d78c8 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -7,6 +7,7 @@ define("CRED_ACCOUNT_LAST_LOGIN", 4); define("CRED_ACCOUNT_SEARCH", 5); define("CRED_COMMENT_DELETE", 6); define("CRED_COMMENT_VIEW_DELETED", 22); +define("CRED_COMMENT_EDIT", 25); define("CRED_PKGBASE_ADOPT", 7); define("CRED_PKGBASE_SET_KEYWORDS", 8); define("CRED_PKGBASE_DELETE", 9); @@ -58,6 +59,7 @@ function has_credential($credential, $approved_users=array()) { case CRED_ACCOUNT_SEARCH: case CRED_COMMENT_DELETE: case CRED_COMMENT_VIEW_DELETED: + case CRED_COMMENT_EDIT: case CRED_PKGBASE_ADOPT: case CRED_PKGBASE_SET_KEYWORDS: case CRED_PKGBASE_DELETE: diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 110290ba..7cb2ffcf 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -42,6 +42,20 @@ function can_delete_comment_array($comment) { return has_credential(CRED_COMMENT_DELETE, array($comment['UsersID'])); } +/** + * Determine if the user can edit a specific package comment using an array + * + * Only the comment submitter, Trusted Users, and Developers can edit + * comments. This function is used for the frontend side of comment editing. + * + * @param array $comment All database information relating a specific comment + * + * @return bool True if the user can edit the comment, otherwise false + */ +function can_edit_comment_array($comment) { + return has_credential(CRED_COMMENT_EDIT, array($comment['UsersID'])); +} + /** * Check to see if the package name already exists in the database * diff --git a/web/template/pkg_comment_form.php b/web/template/pkg_comment_form.php index 8a74dc13..16a92b1b 100644 --- a/web/template/pkg_comment_form.php +++ b/web/template/pkg_comment_form.php @@ -1,5 +1,5 @@

    -

    +

    + " /> + + +

    - +

    - " /> + " />

    diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 03a65817..6cc95555 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -39,6 +39,9 @@ $count = pkgbase_comments_count($base_id, $include_deleted); + + <?= __('Edit comment') ?> +

    From e331ce273cab901726983e18249e0bb3455fc463 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Fri, 10 Jul 2015 18:47:32 +0200 Subject: [PATCH 0021/1891] Support comment editing in the backend Create two new actions, do_AddComment and do_EditComment. When editing or deleting a comment, a timestamp is added. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 3 +++ upgrading/4.1.0.txt | 9 +++++++++ web/html/pkgbase.php | 2 ++ web/lib/pkgbasefuncs.inc.php | 34 +++++++++++++++++++++++++++++++++- web/lib/pkgfuncs.inc.php | 26 ++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 upgrading/4.1.0.txt diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 594a804d..444cb5ed 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -254,11 +254,14 @@ CREATE TABLE PackageComments ( UsersID INTEGER UNSIGNED NULL DEFAULT NULL, Comments TEXT NOT NULL DEFAULT '', CommentTS BIGINT UNSIGNED NOT NULL DEFAULT 0, + EditedTS BIGINT UNSIGNED NULL DEFAULT NULL, + EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, DelUsersID INTEGER UNSIGNED NULL DEFAULT NULL, PRIMARY KEY (ID), INDEX (UsersID), INDEX (PackageBaseID), FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE SET NULL, + FOREIGN KEY (EditedUsersID) REFERENCES Users(ID) ON DELETE SET NULL, FOREIGN KEY (DelUsersID) REFERENCES Users(ID) ON DELETE CASCADE, FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE ) ENGINE = InnoDB; diff --git a/upgrading/4.1.0.txt b/upgrading/4.1.0.txt new file mode 100644 index 00000000..78620304 --- /dev/null +++ b/upgrading/4.1.0.txt @@ -0,0 +1,9 @@ +1. Add a timestamp for comment editing/deletion and an ID of the last user +who edited a comment: + +---- +ALTER TABLE PackageComments + ADD COLUMN EditedTS BIGINT UNSIGNED NULL DEFAULT NULL, + ADD COLUMN EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, + ADD FOREIGN KEY (EditedUsersID) REFERENCES Users(ID) ON DELETE SET NULL; +---- diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index f9080290..5886f714 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -108,6 +108,8 @@ if (check_token()) { $uid = uid_from_sid($_COOKIE["AURSID"]); pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); $ret = true; + } elseif (current_action("do_EditComment")) { + list($ret, $output) = pkgbase_edit_comment($_REQUEST['comment']); } if ($ret) { diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 5d191ebf..1ae31665 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -830,7 +830,8 @@ function pkgbase_delete_comment() { $dbh = DB::connect(); if (can_delete_comment($comment_id)) { $q = "UPDATE PackageComments "; - $q.= "SET DelUsersID = ".$uid." "; + $q.= "SET DelUsersID = ".$uid.", "; + $q.= "EditedTS = UNIX_TIMESTAMP() "; $q.= "WHERE ID = ".intval($comment_id); $dbh->exec($q); return array(true, __("Comment has been deleted.")); @@ -839,6 +840,37 @@ function pkgbase_delete_comment() { } } +/** + * Edit a package comment + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_edit_comment($comment) { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + $dbh = DB::connect(); + if (can_edit_comment($comment_id)) { + $q = "UPDATE PackageComments "; + $q.= "SET EditedUsersID = ".$uid.", "; + $q.= "Comments = ".$dbh->quote($comment).", "; + $q.= "EditedTS = UNIX_TIMESTAMP() "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been edited.")); + } else { + return array(false, __("You are not allowed to edit this comment.")); + } +} + /** * Get a list of package base keywords * diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 7cb2ffcf..de57c3e0 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -42,6 +42,32 @@ function can_delete_comment_array($comment) { return has_credential(CRED_COMMENT_DELETE, array($comment['UsersID'])); } +/** + * Determine if the user can edit a specific package comment + * + * Only the comment submitter, Trusted Users, and Developers can edit + * comments. This function is used for the backend side of comment editing. + * + * @param string $comment_id The comment ID in the database + * + * @return bool True if the user can edit the comment, otherwise false + */ +function can_edit_comment($comment_id=0) { + $dbh = DB::connect(); + + $q = "SELECT UsersID FROM PackageComments "; + $q.= "WHERE ID = " . intval($comment_id); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_EDIT, array($uid)); +} + /** * Determine if the user can edit a specific package comment using an array * From 9cde6b0566390002d167703fa900129bb90e07d8 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Fri, 10 Jul 2015 18:47:33 +0200 Subject: [PATCH 0022/1891] Show dateline when a comment is edited or deleted Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 5 +++++ web/lib/pkgbasefuncs.inc.php | 9 ++++++--- web/template/pkg_comments.php | 38 ++++++++++++++++++++++++----------- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index b5ca1f38..b33726c4 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -96,6 +96,11 @@ color: #999; } +.edited { + font-size: 0.9em; + color: #999; +} + .delete-comment-form, .edit-comment { float: right; margin-left: 8px; diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 1ae31665..6057d104 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -47,9 +47,12 @@ function pkgbase_comments($base_id, $limit, $include_deleted) { } $dbh = DB::connect(); - $q = "SELECT PackageComments.ID, UserName, UsersID, Comments, "; - $q.= "CommentTS, DelUsersID FROM PackageComments LEFT JOIN Users "; - $q.= "ON PackageComments.UsersID = Users.ID "; + $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; + $q.= "CommentTS, EditedTS, B.UserName AS EditUserName, "; + $q.= "DelUsersID, C.UserName AS DelUserName FROM PackageComments "; + $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; + $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; + $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; $q.= "WHERE PackageBaseID = " . $base_id . " "; if (!$include_deleted) { $q.= "AND DelUsersID IS NULL "; diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 6cc95555..8650db29 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -16,19 +16,33 @@ $count = pkgbase_comments_count($base_id, $include_deleted); - {$row['UserName']}"; - endif; ?> + ('; + if ($row['DelUsersID']) { + $user_fmtd = html_format_username($row['DelUserName']); + $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); + } else { + $user_fmtd = html_format_username($row['EditUserName']); + $heading .= __('last edited on %s by %s', $date_fmtd, $user_fmtd); + } + $heading .= ')'; + } + + $row['DelUserName'] = html_format_username($row['DelUserName']); + $row['EditUserName'] = html_format_username($row['EditUserName']); + ?> class="comment-deleted"> - - - - - - - - () - +

    From 4c5a299e8078f357b14246c268e8793b27bd5679 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Fri, 10 Jul 2015 18:47:34 +0200 Subject: [PATCH 0023/1891] Only autofocus search field on the package search page This needs to be disabled on package pages to be able to add a URL fragment after comment editing. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/pkg_search_form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php index 2d03cfa5..404d16ec 100644 --- a/web/template/pkg_search_form.php +++ b/web/template/pkg_search_form.php @@ -57,7 +57,7 @@ $per_page = array(50, 100, 250);
    - " maxlength='35' autofocus="autofocus" /> + " maxlength='35' />
    From 67cff2cd5ac67d16c7934d95391518836acd1a36 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Fri, 10 Jul 2015 18:47:35 +0200 Subject: [PATCH 0024/1891] Add IDs to comments Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/pkg_comments.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 8650db29..26fddfd5 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -41,7 +41,7 @@ $count = pkgbase_comments_count($base_id, $include_deleted); $row['DelUserName'] = html_format_username($row['DelUserName']); $row['EditUserName'] = html_format_username($row['EditUserName']); ?> - class="comment-deleted"> +

    class="comment-deleted"> From 19aff5f9583b2450208cbd748c1e4b2ce27b3fe0 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Fri, 10 Jul 2015 18:47:36 +0200 Subject: [PATCH 0025/1891] Jump to comment after editing Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 5886f714..65077b37 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -46,6 +46,7 @@ if (isset($_POST['IDs'])) { /* Perform package base actions. */ $ret = false; $output = ""; +$fragment = ""; if (check_token()) { if (current_action("do_Flag")) { list($ret, $output) = pkgbase_flag($ids); @@ -110,6 +111,9 @@ if (check_token()) { $ret = true; } elseif (current_action("do_EditComment")) { list($ret, $output) = pkgbase_edit_comment($_REQUEST['comment']); + if ($ret && isset($_POST["comment_id"])) { + $fragment = '#comment-' . intval($_POST["comment_id"]); + } } if ($ret) { @@ -120,7 +124,7 @@ if (check_token()) { exit(); } if (isset($base_id)) { /* Redirect back to package base page on success. */ - header('Location: ' . get_pkgbase_uri($pkgbase_name)); + header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); exit(); } else { /* Redirect back to package search page. */ @@ -134,9 +138,9 @@ $pkgs = pkgbase_get_pkgnames($base_id); if (!$output && count($pkgs) == 1) { /* Not a split package. Redirect to the package page. */ if (empty($_SERVER['QUERY_STRING'])) { - header('Location: ' . get_pkg_uri($pkgs[0])); + header('Location: ' . get_pkg_uri($pkgs[0]) . $fragment); } else { - header('Location: ' . get_pkg_uri($pkgs[0]) . '?' . $_SERVER['QUERY_STRING']); + header('Location: ' . get_pkg_uri($pkgs[0]) . '?' . $_SERVER['QUERY_STRING'] . $fragment); } } From f2ff9782a5508a9208c297d0b46f9dfb7910f062 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sat, 11 Jul 2015 00:24:09 +0200 Subject: [PATCH 0026/1891] Jump to latest comments after adding a comment Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 65077b37..15818699 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -109,6 +109,7 @@ if (check_token()) { $uid = uid_from_sid($_COOKIE["AURSID"]); pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); $ret = true; + $fragment = '#news'; } elseif (current_action("do_EditComment")) { list($ret, $output) = pkgbase_edit_comment($_REQUEST['comment']); if ($ret && isset($_POST["comment_id"])) { From 7927a6decd07bb80223ea22bf1db395aa7c12cc4 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 19 Jul 2015 22:32:04 +0200 Subject: [PATCH 0027/1891] Use username from the database if one is provided by the user This fixes a bug where the new user name input by the user was invalid, causing the account deletion link and the form action to be wrong. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/account.php | 4 ++-- web/lib/acctfuncs.inc.php | 8 +++++--- web/template/account_edit_form.php | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index c447de35..f5e6c19c 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -61,7 +61,7 @@ if (isset($_COOKIE["AURSID"])) { $row["AccountTypeID"], $row["Suspended"], $row["Email"], "", "", $row["RealName"], $row["LangPreference"], $row["IRCNick"], $row["PGPKey"], $PK, - $row["InactivityTS"] ? 1 : 0, $row["ID"]); + $row["InactivityTS"] ? 1 : 0, $row["ID"], $row["Username"]); } else { print __("You do not have permission to edit this account."); } @@ -100,7 +100,7 @@ if (isset($_COOKIE["AURSID"])) { in_request("E"), in_request("P"), in_request("C"), in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("PK"), in_request("J"), - in_request("ID")); + in_request("ID"), $row["Username"]); } } else { if (has_credential(CRED_ACCOUNT_SEARCH)) { diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 2b57b2dd..9d6f5ee4 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -56,11 +56,12 @@ function html_format_pgp_fingerprint($fingerprint) { * @param string $PK The list of SSH public keys * @param string $J The inactivity status of the displayed user * @param string $UID The user ID of the displayed user + * @param string $N The username as present in the database * * @return void */ function display_account_form($A,$U="",$T="",$S="",$E="",$P="",$C="",$R="", - $L="",$I="",$K="",$PK="",$J="", $UID=0) { + $L="",$I="",$K="",$PK="",$J="",$UID=0,$N="") { global $SUPPORTED_LANGS; include("account_edit_form.php"); @@ -86,11 +87,12 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$P="",$C="",$R="", * @param string $PK The list of public SSH keys * @param string $J The inactivity status of the user * @param string $UID The user ID of the modified account + * @param string $N The username as present in the database * * @return string|void Return void if successful, otherwise return error */ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", - $R="",$L="",$I="",$K="",$PK="",$J="",$UID=0) { + $R="",$L="",$I="",$K="",$PK="",$J="",$UID=0,$N="") { global $SUPPORTED_LANGS; $error = ''; @@ -247,7 +249,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", if ($error) { print "
    • ".$error."
    \n"; display_account_form($A, $U, $T, $S, $E, "", "", - $R, $L, $I, $K, $PK, $J, $UID); + $R, $L, $I, $K, $PK, $J, $UID, $N); return; } diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 56bdd454..0aadb9dc 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -1,9 +1,9 @@

    - ', '') ?> + ', '') ?>

    - + From cb9c0d2477480b63294854ce2abf7d9a34059ee6 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 19 Jul 2015 22:32:05 +0200 Subject: [PATCH 0028/1891] Surround message with

    tags Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/register.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/register.php b/web/html/register.php index 014d8026..cb3e8dd2 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -25,7 +25,7 @@ if (in_request("Action") == "NewAccount") { in_request("PK")); } else { - print __("Use this form to create an account."); + print '

    ' . __("Use this form to create an account.") . '

    '; display_account_form("NewAccount", "", "", "", "", "", "", "", $LANG); } From 8db2ff5da679b3c2d5a53f67f67863d786057f36 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 19 Jul 2015 22:32:06 +0200 Subject: [PATCH 0029/1891] Set correct 'My Account' link after changing username Don't print messages (and the account form) in process_account_form() anymore, but return them to the caller. When updating accounts, this function will be called before the headers are written. If a username has been changed by process_account_form(), the headers now show the updated username from the database in the 'My Account' link. Clicking on it immediately after changing a username will no longer lead to a non-existing URL. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/account.php | 38 ++++++++++++++++++++++++++++---------- web/html/register.php | 11 ++++++++++- web/lib/acctfuncs.inc.php | 31 ++++++++++++++++--------------- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index f5e6c19c..adc2542c 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -19,6 +19,26 @@ if (in_array($action, $need_userinfo)) { $PK = implode("\n", account_get_ssh_keys($row["ID"])); } +/* This has to be done before the navigation headers are written, + * because html_header() fetches the current username from the database, + * which could be changed by process_account_form() + */ +if ($action == "UpdateAccount") { + $update_account_message = ''; + /* Details for account being updated */ + /* Verify user permissions and that the request is a valid POST */ + if (can_edit_account($row) && check_token()) { + /* Update the details for the existing account */ + list($success, $update_account_message) = process_account_form( + "edit", "UpdateAccount", + in_request("U"), in_request("T"), in_request("S"), + in_request("E"), in_request("P"), in_request("C"), + in_request("R"), in_request("L"), in_request("I"), + in_request("K"), in_request("PK"), in_request("J"), + in_request("ID"), $row["Username"]); + } +} + if ($action == "AccountInfo") { html_header(__('Account') . ' ' . $row['Username']); } else { @@ -91,17 +111,15 @@ if (isset($_COOKIE["AURSID"])) { } } elseif ($action == "UpdateAccount") { - /* Details for account being updated */ - /* Verify user permissions and that the request is a valid POST */ - if (can_edit_account($row) && check_token()) { - /* Update the details for the existing account */ - process_account_form("edit", "UpdateAccount", - in_request("U"), in_request("T"), in_request("S"), - in_request("E"), in_request("P"), in_request("C"), - in_request("R"), in_request("L"), in_request("I"), - in_request("K"), in_request("PK"), in_request("J"), - in_request("ID"), $row["Username"]); + print $update_account_message; + + if (!$success) { + display_account_form("UpdateAccount", in_request("U"), in_request("T"), + in_request("S"), in_request("E"), in_request("P"), in_request("C"), + in_request("R"), in_request("L"), in_request("I"), in_request("K"), + in_request("PK"), in_request("J"), in_request("ID"), $row["Username"]); } + } else { if (has_credential(CRED_ACCOUNT_SEARCH)) { # display the search page if they're a TU/dev diff --git a/web/html/register.php b/web/html/register.php index cb3e8dd2..9c5c1cc1 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -19,11 +19,20 @@ echo '
    '; echo '

    ' . __('Register') . '

    '; if (in_request("Action") == "NewAccount") { - process_account_form("new", "NewAccount", in_request("U"), 1, 0, + list($success, $message) = process_account_form( + "new", "NewAccount", in_request("U"), 1, 0, in_request("E"), '', '', in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("PK")); + print $message; + + if (!$success) { + display_account_form("NewAccount", in_request("U"), 1, 0, + in_request("E"), '', '', in_request("R"), + in_request("L"), in_request("I"), in_request("K"), + in_request("PK")); + } } else { print '

    ' . __("Use this form to create an account.") . '

    '; display_account_form("NewAccount", "", "", "", "", "", "", "", $LANG); diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 9d6f5ee4..f718a773 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -89,13 +89,14 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$P="",$C="",$R="", * @param string $UID The user ID of the modified account * @param string $N The username as present in the database * - * @return string|void Return void if successful, otherwise return error + * @return array Boolean indicating success and message to be printed */ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", $R="",$L="",$I="",$K="",$PK="",$J="",$UID=0,$N="") { global $SUPPORTED_LANGS; $error = ''; + $message = ''; if (is_ipbanned()) { $error = __('Account registration has been disabled ' . @@ -247,10 +248,8 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", } if ($error) { - print "
    • ".$error."
    \n"; - display_account_form($A, $U, $T, $S, $E, "", "", - $R, $L, $I, $K, $PK, $J, $UID, $N); - return; + $message = "
    • ".$error."
    \n"; + return array(false, $message); } if ($TYPE == "new") { @@ -278,25 +277,25 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", $q.= "$I, $K)"; $result = $dbh->exec($q); if (!$result) { - print __("Error trying to create account, %s%s%s.", + $message = __("Error trying to create account, %s%s%s.", "", htmlspecialchars($U,ENT_QUOTES), ""); - return; + return array(false, $message); } $uid = $dbh->lastInsertId(); account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints); - print __("The account, %s%s%s, has been successfully created.", + $message = __("The account, %s%s%s, has been successfully created.", "", htmlspecialchars($U,ENT_QUOTES), ""); - print "

    \n"; + $message .= "

    \n"; if ($send_resetkey) { send_resetkey($email, true); - print __("A password reset key has been sent to your e-mail address."); - print "

    \n"; + $message .= __("A password reset key has been sent to your e-mail address."); + $message .= "

    \n"; } else { - print __("Click on the Login link above to use your account."); - print "

    \n"; + $message .= __("Click on the Login link above to use your account."); + $message .= "

    \n"; } } else { /* Modify an existing account. */ @@ -341,13 +340,15 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", $ssh_key_result = account_set_ssh_keys($UID, $ssh_keys, $ssh_fingerprints); if ($result === false || $ssh_key_result === false) { - print __("No changes were made to the account, %s%s%s.", + $message = __("No changes were made to the account, %s%s%s.", "", htmlspecialchars($U,ENT_QUOTES), ""); } else { - print __("The account, %s%s%s, has been successfully modified.", + $message = __("The account, %s%s%s, has been successfully modified.", "", htmlspecialchars($U,ENT_QUOTES), ""); } } + + return array(true, $message); } /** From e610360c95682bbaa359e1bf3d3abffb97a9820b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 21 Jul 2015 14:50:25 +0200 Subject: [PATCH 0030/1891] Show popularity in package base details Fixes FS#45600. Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 2 +- web/lib/pkgfuncs.inc.php | 4 ++-- web/template/pkg_details.php | 5 +++++ web/template/pkgbase_details.php | 5 +++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 6057d104..2d1969be 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -140,7 +140,7 @@ function pkgbase_get_details($base_id) { $dbh = DB::connect(); $q = "SELECT PackageBases.ID, PackageBases.Name, "; - $q.= "PackageBases.NumVotes, "; + $q.= "PackageBases.NumVotes, PackageBases.Popularity, "; $q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, "; $q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, "; $q.= "PackageBases.MaintainerUID, PackageBases.PackagerUID, "; diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index de57c3e0..bcadf54a 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -431,8 +431,8 @@ function pkg_get_details($id=0) { $dbh = DB::connect(); $q = "SELECT Packages.*, PackageBases.ID AS BaseID, "; - $q.= "PackageBases.Name AS BaseName, "; - $q.= "PackageBases.NumVotes, PackageBases.OutOfDateTS, "; + $q.= "PackageBases.Name AS BaseName, PackageBases.NumVotes, "; + $q.= "PackageBases.Popularity, PackageBases.OutOfDateTS, "; $q.= "PackageBases.SubmittedTS, PackageBases.ModifiedTS, "; $q.= "PackageBases.SubmitterUID, PackageBases.MaintainerUID, "; $q.= "PackageBases.PackagerUID, "; diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index ae8d0848..9730d7e6 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -25,6 +25,7 @@ if ($row["MaintainerUID"] !== NULL) { } $votes = $row['NumVotes']; +$popularity = $row['Popularity']; # In case of wanting to put a custom message $msg = __('unknown'); @@ -253,6 +254,10 @@ endif; + + + + diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index 667b3f77..d4304e3e 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -24,6 +24,7 @@ if ($row["MaintainerUID"] !== NULL) { } $votes = $row['NumVotes']; +$popularity = $row['Popularity']; # In case of wanting to put a custom message $msg = __('unknown'); @@ -104,6 +105,10 @@ endif; + + + + From c751921affdcc8e67df2c04cb00de2d0c58e1927 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 21 Jul 2015 14:41:54 +0200 Subject: [PATCH 0031/1891] Do not use the term "unsupported" for AUR packages We no longer use the term [unsupported] to refer to the "repository" of AUR packages. Update texts and variable names accordingly. Fixes FS#45381. Signed-off-by: Lukas Fleischer --- web/html/home.php | 2 +- web/lib/stats.inc.php | 5 ++--- web/template/cgit/footer.html | 2 +- web/template/footer.php | 2 +- web/template/stats/general_stats_table.php | 2 +- web/template/stats/user_table.php | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/web/html/home.php b/web/html/home.php index 3252876f..23f37fe2 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -39,7 +39,7 @@ html_header( __("Home") );

    : - +

    diff --git a/web/lib/stats.inc.php b/web/lib/stats.inc.php index 203be0ad..5a245918 100644 --- a/web/lib/stats.inc.php +++ b/web/lib/stats.inc.php @@ -39,8 +39,7 @@ function user_table($userid) { $base_q.= "WHERE MaintainerUID = " . $userid . " "; $base_q.= "AND PackagerUID IS NOT NULL"; - $maintainer_unsupported_count = db_cache_value($base_q, - 'user_unsupported_count:' . $userid); + $user_pkg_count = db_cache_value($base_q, 'user_pkg_count:' . $userid); $q = "SELECT COUNT(*) FROM PackageBases "; $q.= "WHERE OutOfDateTS IS NOT NULL "; @@ -60,7 +59,7 @@ function user_table($userid) { function general_stats_table() { # AUR statistics $q = "SELECT COUNT(*) FROM PackageBases WHERE PackagerUID IS NOT NULL"; - $unsupported_count = db_cache_value($q, 'unsupported_count'); + $pkg_count = db_cache_value($q, 'pkg_count'); $q = "SELECT COUNT(*) FROM PackageBases "; $q.= "WHERE MaintainerUID IS NULL "; diff --git a/web/template/cgit/footer.html b/web/template/cgit/footer.html index 80481d92..36e0f1b1 100644 --- a/web/template/cgit/footer.html +++ b/web/template/cgit/footer.html @@ -1,6 +1,6 @@ diff --git a/web/template/footer.php b/web/template/footer.php index 068cc060..1b3c9363 100644 --- a/web/template/footer.php +++ b/web/template/footer.php @@ -6,7 +6,7 @@

    aurweb

    Copyright © 2004- aurweb Development Team.

    -

    +

    diff --git a/web/template/stats/general_stats_table.php b/web/template/stats/general_stats_table.php index 5b598321..9dcc3aaf 100644 --- a/web/template/stats/general_stats_table.php +++ b/web/template/stats/general_stats_table.php @@ -3,7 +3,7 @@ - + diff --git a/web/template/stats/user_table.php b/web/template/stats/user_table.php index 284d5b9e..e7b00834 100644 --- a/web/template/stats/user_table.php +++ b/web/template/stats/user_table.php @@ -8,9 +8,9 @@ $username = username_from_sid($_COOKIE["AURSID"]); - + From e1a258bd832c3ba76b5f898cbd068c5bdf4eb4dc Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 30 Aug 2015 16:24:13 +0200 Subject: [PATCH 0052/1891] Remember user ID when flagging package bases Add a new FlaggerUID field to the database and use it to store the user ID of the account who recently flagged a package out-of-date. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 ++ upgrading/4.1.0.txt | 8 ++++++++ web/lib/pkgbasefuncs.inc.php | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 444cb5ed..9556b20a 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -84,6 +84,7 @@ CREATE TABLE PackageBases ( OutOfDateTS BIGINT UNSIGNED NULL DEFAULT NULL, SubmittedTS BIGINT UNSIGNED NOT NULL, ModifiedTS BIGINT UNSIGNED NOT NULL, + FlaggerUID BIGINT UNSIGNED NULL DEFAULT NULL, -- who flagged the package out-of-date? SubmitterUID INTEGER UNSIGNED NULL DEFAULT NULL, -- who submitted it? MaintainerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- User PackagerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- Last packager @@ -93,6 +94,7 @@ CREATE TABLE PackageBases ( INDEX (SubmitterUID), INDEX (MaintainerUID), INDEX (PackagerUID), + FOREIGN KEY (FlaggerUID) REFERENCES Users(ID) ON DELETE SET NULL, -- deleting a user will cause packages to be orphaned, not deleted FOREIGN KEY (SubmitterUID) REFERENCES Users(ID) ON DELETE SET NULL, FOREIGN KEY (MaintainerUID) REFERENCES Users(ID) ON DELETE SET NULL, diff --git a/upgrading/4.1.0.txt b/upgrading/4.1.0.txt index 78620304..c0bf5732 100644 --- a/upgrading/4.1.0.txt +++ b/upgrading/4.1.0.txt @@ -7,3 +7,11 @@ ALTER TABLE PackageComments ADD COLUMN EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, ADD FOREIGN KEY (EditedUsersID) REFERENCES Users(ID) ON DELETE SET NULL; ---- + +2. Add a field to store the ID of the last user who flagged a package +out-of-date: + +---- +ALTER TABLE PackageBases + ADD COLUMN FlaggerUID BIGINT UNSIGNED NULL DEFAULT NULL; +---- diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 677ae6b8..df1ae186 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -328,15 +328,15 @@ function pkgbase_flag($base_ids) { return array(false, __("You did not select any packages to flag.")); } + $uid = uid_from_sid($_COOKIE['AURSID']); $dbh = DB::connect(); $q = "UPDATE PackageBases SET"; - $q.= " OutOfDateTS = UNIX_TIMESTAMP()"; + $q.= " OutOfDateTS = UNIX_TIMESTAMP(), FlaggerUID = " . $uid; $q.= " WHERE ID IN (" . implode(",", $base_ids) . ")"; $q.= " AND OutOfDateTS IS NULL"; $dbh->exec($q); - $uid = uid_from_sid($_COOKIE['AURSID']); foreach ($base_ids as $base_id) { notify(array('flag', $uid, $base_id)); } From 57db4814a47d2a40d4b74e3ae0df261bbfeb45b8 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 30 Aug 2015 16:32:34 +0200 Subject: [PATCH 0053/1891] Allow users to unflag packages they flagged themselves Sometimes, a user accidentally flags a package out-of-date. Allow users to unflag packages that they flagged themselves, thereby providing a way to undo these actions. Implements FS#46145. Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 3 ++- web/lib/pkgfuncs.inc.php | 2 +- web/template/pkg_details.php | 3 ++- web/template/pkgbase_actions.php | 2 +- web/template/pkgbase_details.php | 3 ++- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index df1ae186..24d3393f 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -150,6 +150,7 @@ function pkgbase_get_details($base_id) { $q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, "; $q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, "; $q.= "PackageBases.MaintainerUID, PackageBases.PackagerUID, "; + $q.= "PackageBases.FlaggerUID, "; $q.= "(SELECT COUNT(*) FROM PackageRequests "; $q.= " WHERE PackageRequests.PackageBaseID = PackageBases.ID "; $q.= " AND PackageRequests.Status = 0) AS RequestCount "; @@ -370,7 +371,7 @@ function pkgbase_unflag($base_ids) { $maintainers = array_merge(pkgbase_maintainer_uids($base_ids), pkgbase_get_comaintainer_uids($base_ids)); if (!has_credential(CRED_PKGBASE_UNFLAG, $maintainers)) { - $q.= "AND MaintainerUID = " . $uid; + $q.= "AND (MaintainerUID = " . $uid . " OR FlaggerUID = " . $uid. ")"; } $result = $dbh->exec($q); diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index f4034718..d760429e 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -435,7 +435,7 @@ function pkg_get_details($id=0) { $q.= "PackageBases.Popularity, PackageBases.OutOfDateTS, "; $q.= "PackageBases.SubmittedTS, PackageBases.ModifiedTS, "; $q.= "PackageBases.SubmitterUID, PackageBases.MaintainerUID, "; - $q.= "PackageBases.PackagerUID, "; + $q.= "PackageBases.PackagerUID, PackageBases.FlaggerUID, "; $q.= "(SELECT COUNT(*) FROM PackageRequests "; $q.= " WHERE PackageRequests.PackageBaseID = Packages.PackageBaseID "; $q.= " AND PackageRequests.Status = 0) AS RequestCount "; diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index f4eed514..5ba3607a 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -21,8 +21,9 @@ $packager = username_from_id($row["PackagerUID"]); if ($row["MaintainerUID"] !== NULL) { $maintainers = array_merge(array($row["MaintainerUID"]), pkgbase_get_comaintainer_uids(array($base_id))); } else { - $maintainers = NULL; + $maintainers = array(); } +$unflaggers = array_merge($maintainers, array($row["FlaggerUID"])); $votes = $row['NumVotes']; $popularity = $row['Popularity']; diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php index c7428ee6..dea348e3 100644 --- a/web/template/pkgbase_actions.php +++ b/web/template/pkgbase_actions.php @@ -11,7 +11,7 @@
  • - +
  • diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index d4304e3e..1012c4e6 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -20,8 +20,9 @@ $packager = username_from_id($row["PackagerUID"]); if ($row["MaintainerUID"] !== NULL) { $maintainers = array_merge(array($row["MaintainerUID"]), pkgbase_get_comaintainer_uids(array($base_id))); } else { - $maintainers = NULL; + $maintainers = array(); } +$unflaggers = array_merge($maintainers, array($row["FlaggerUID"])); $votes = $row['NumVotes']; $popularity = $row['Popularity']; From 209879d63f25276e38337983fc034da08b58ff3a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 31 Aug 2015 18:01:13 +0200 Subject: [PATCH 0054/1891] Fix duplicate escaping of action links The __() helper function already escapes HTML special characters. Do not escape them again in html_action_*(). Fixes FS#45780. Signed-off-by: Lukas Fleischer --- web/lib/aur.inc.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 99975356..7d659132 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -225,18 +225,18 @@ function html_format_maintainers($maintainer, $comaintainers) { * Format a link in the package actions box * * @param string $uri The link target - * @param string $desc The link label + * @param string $inner The HTML code to use for the link label * * @return string The generated HTML code for the action link */ -function html_action_link($uri, $desc) { +function html_action_link($uri, $inner) { if (isset($_COOKIE["AURSID"])) { $code = ''; } else { $code = ''; } - $code .= htmlspecialchars($desc) . ''; + $code .= $inner . ''; return $code; } @@ -246,11 +246,11 @@ function html_action_link($uri, $desc) { * * @param string $uri The link target * @param string $action The action name (passed as HTTP POST parameter) - * @param string $desc The link label + * @param string $inner The HTML code to use for the link label * * @return string The generated HTML code for the action link */ -function html_action_form($uri, $action, $desc) { +function html_action_form($uri, $action, $inner) { if (isset($_COOKIE["AURSID"])) { $code = ''; $code .= ''; + $code .= 'value="' . $inner . '" />'; $code .= ''; } else { $code = ''; - $code .= htmlspecialchars($desc) . ''; + $code .= $inner . ''; } return $code; From 6b7e26a2d19c53438a9594ee3068f1afcdb1ee0d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 31 Aug 2015 18:18:24 +0200 Subject: [PATCH 0055/1891] Move package base flagging to a separate form Show a separate confirmation page when flagging a package out-of-date. Implements FS#44967. Signed-off-by: Lukas Fleischer --- web/html/index.php | 4 +-- web/html/pkgflag.php | 44 ++++++++++++++++++++++++++++++++ web/template/pkgbase_actions.php | 2 +- 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 web/html/pkgflag.php diff --git a/web/html/index.php b/web/html/index.php index 7068d763..ec99bb72 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -68,8 +68,8 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { $_POST['do_UnNotify'] = __('UnNotify'); break; case "flag": - $_POST['do_Flag'] = __('Flag'); - break; + include('pkgflag.php'); + return; case "unflag": $_POST['do_UnFlag'] = __('UnFlag'); break; diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php new file mode 100644 index 00000000..9d86909d --- /dev/null +++ b/web/html/pkgflag.php @@ -0,0 +1,44 @@ + +
    +

    +

    + ', htmlspecialchars($pkgbase_name), ''); ?> +

    +
      + +
    • + +
    +

    + ', ''); ?> +

    +
    +
    + + + +

    " />

    +
    + +
    + +
  • -
  • +
  • From 396e50bdc88feae9d0048d1c3dab776388d96dc7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 31 Aug 2015 18:29:06 +0200 Subject: [PATCH 0056/1891] Require comments when flagging packages out-of-date Implements FS#42827. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 1 + scripts/notify.py | 5 +++-- upgrading/4.1.0.txt | 7 ++++--- web/html/pkgbase.php | 7 ++++++- web/html/pkgflag.php | 5 +++++ web/lib/pkgbasefuncs.inc.php | 14 ++++++++------ 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 9556b20a..ff137dc6 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -82,6 +82,7 @@ CREATE TABLE PackageBases ( NumVotes INTEGER UNSIGNED NOT NULL DEFAULT 0, Popularity DECIMAL(10,6) UNSIGNED NOT NULL DEFAULT 0, OutOfDateTS BIGINT UNSIGNED NULL DEFAULT NULL, + FlaggerComment VARCHAR(255) NOT NULL, SubmittedTS BIGINT UNSIGNED NOT NULL, ModifiedTS BIGINT UNSIGNED NOT NULL, FlaggerUID BIGINT UNSIGNED NULL DEFAULT NULL, -- who flagged the package out-of-date? diff --git a/scripts/notify.py b/scripts/notify.py index 8be3a701..55b29110 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -139,14 +139,15 @@ def flag(cur, uid, pkgbase_id): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) to = [get_maintainer_email(cur, pkgbase_id)] + text = sys.stdin.read() user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' subject = 'AUR Out-of-date Notification for %s' % (pkgbase) - body = 'Your package %s [1] has been flagged out-of-date by %s [2]. ' % \ + body = 'Your package %s [1] has been flagged out-of-date by %s [2]:' % \ (pkgbase, user) - body += '\n\n' + body += '\n\n' + text + '\n\n' body += '[1] ' + pkgbase_uri + '\n' body += '[2] ' + user_uri diff --git a/upgrading/4.1.0.txt b/upgrading/4.1.0.txt index c0bf5732..e9545ffb 100644 --- a/upgrading/4.1.0.txt +++ b/upgrading/4.1.0.txt @@ -8,10 +8,11 @@ ALTER TABLE PackageComments ADD FOREIGN KEY (EditedUsersID) REFERENCES Users(ID) ON DELETE SET NULL; ---- -2. Add a field to store the ID of the last user who flagged a package -out-of-date: +2. Add fields to store the ID and comment of the last user who flagged a +package out-of-date: ---- ALTER TABLE PackageBases - ADD COLUMN FlaggerUID BIGINT UNSIGNED NULL DEFAULT NULL; + ADD COLUMN FlaggerUID BIGINT UNSIGNED NULL DEFAULT NULL, + ADD COLUMN FlaggerComment VARCHAR(255) NOT NULL; ---- diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index bc32e43c..a241c749 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -49,7 +49,12 @@ $output = ""; $fragment = ""; if (check_token()) { if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($ids); + if (strlen($_POST['comments']) >= 3) { + list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); + } else { + $output = __("The selected packages have not been flagged, please enter a comment."); + $ret = false; + } } elseif (current_action("do_UnFlag")) { list($ret, $output) = pkgbase_unflag($ids); } elseif (current_action("do_Adopt")) { diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php index 9d86909d..bfe89e03 100644 --- a/web/html/pkgflag.php +++ b/web/html/pkgflag.php @@ -25,12 +25,17 @@ if (has_credential(CRED_PKGBASE_FLAG)): ?>

    ', ''); ?> +

    +

    + + +

    " />

    diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 24d3393f..799f1da9 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -316,10 +316,11 @@ function pkgbase_maintainer_uids($base_ids) { * Flag package(s) as out-of-date * * @param array $base_ids Array of package base IDs to flag/unflag + * @param string $comment The comment to add * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_flag($base_ids) { +function pkgbase_flag($base_ids, $comment) { if (!has_credential(CRED_PKGBASE_FLAG)) { return array(false, __("You must be logged in before you can flag packages.")); } @@ -332,14 +333,15 @@ function pkgbase_flag($base_ids) { $uid = uid_from_sid($_COOKIE['AURSID']); $dbh = DB::connect(); - $q = "UPDATE PackageBases SET"; - $q.= " OutOfDateTS = UNIX_TIMESTAMP(), FlaggerUID = " . $uid; - $q.= " WHERE ID IN (" . implode(",", $base_ids) . ")"; - $q.= " AND OutOfDateTS IS NULL"; + $q = "UPDATE PackageBases SET "; + $q.= "OutOfDateTS = UNIX_TIMESTAMP(), FlaggerUID = " . $uid . ", "; + $q.= "FlaggerComment = " . $dbh->quote($comment) . " "; + $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; + $q.= "AND OutOfDateTS IS NULL"; $dbh->exec($q); foreach ($base_ids as $base_id) { - notify(array('flag', $uid, $base_id)); + notify(array('flag', $uid, $base_id), $comment); } return array(true, __("The selected packages have been flagged out-of-date.")); From c5014b0752d2544cfb04522bda164e89246702bd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 11 Sep 2015 21:56:51 +0200 Subject: [PATCH 0057/1891] Remove superfluous function valid_user() This helper function was almost 100% identical to uid_from_username(). Switch to using uid_from_username(), which has a much better name and implementation, everywhere. Signed-off-by: Lukas Fleischer --- web/html/addvote.php | 2 +- web/lib/acctfuncs.inc.php | 27 +-------------------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/web/html/addvote.php b/web/html/addvote.php index 03725182..d1529412 100644 --- a/web/html/addvote.php +++ b/web/html/addvote.php @@ -24,7 +24,7 @@ if (has_credential(CRED_TU_ADD_VOTE)) { $error = ""; if (!empty($_POST['user'])) { - if (!valid_user($_POST['user'])) { + if (!uid_from_username($_POST['user'])) { $error.= __("Username does not exist."); } else { diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index f718a773..ee8f0e3f 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -479,7 +479,7 @@ function try_login() { } $dbh = DB::connect(); - $userID = valid_user($_REQUEST['user']); + $userID = uid_from_username($_REQUEST['user']); if (user_suspended($userID)) { $login_error = __('Account suspended'); @@ -608,31 +608,6 @@ function valid_username($user) { return true; } -/** - * Determine if a username exists in the database - * - * @param string $user Username to check in the database - * - * @return string|void Return user ID if in database, otherwise void - */ -function valid_user($user) { - if (!$user) { - return false; - } - - $dbh = DB::connect(); - - $q = "SELECT ID FROM Users WHERE "; - $q.= "Username = " . $dbh->quote($user); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; -} - /** * Determine if a user already has a proposal open about themselves * From ee9a8f232b960c5bfad7376f129710d19871edcc Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 11 Sep 2015 22:01:46 +0200 Subject: [PATCH 0058/1891] Allow for logging in via email address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accept both user names and email addresses in the login prompt. Suggested-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/html/login.php | 2 +- web/lib/acctfuncs.inc.php | 2 +- web/lib/aur.inc.php | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/web/html/login.php b/web/html/login.php index ab7bac9e..cef9be48 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -28,7 +28,7 @@ html_header('AUR ' . __("Login"));

    - +

    diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index ee8f0e3f..756c8477 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -479,7 +479,7 @@ function try_login() { } $dbh = DB::connect(); - $userID = uid_from_username($_REQUEST['user']); + $userID = uid_from_loginname($_REQUEST['user']); if (user_suspended($userID)) { $login_error = __('Account suspended'); diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 7d659132..9015ae8f 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -466,6 +466,21 @@ function uid_from_username($username) { return $row[0]; } +/** + * Determine the user's ID in the database using a username or email address + * + * @param string $username The username or email address of an account + * + * @return string Return user ID if exists, otherwise null + */ +function uid_from_loginname($loginname) { + $uid = uid_from_username($loginname); + if (!$uid) { + $uid = uid_from_email($loginname); + } + return $uid; +} + /** * Determine the user's ID in the database using an e-mail address * From 209b0b6edad0c18a2ea14eac83c6c4787264aa63 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Sep 2015 10:04:43 +0200 Subject: [PATCH 0059/1891] Mitigate JSONP callback vulnerabilities The callback parameter of the RPC interface currently allows for specifying a prefix of arbitrary length of the returned result. This can be exploited by certain attacks. As a countermeasure, this patch restricts the allowed character set for the callback name to letters, digits, underscores, parenthesis and dots. It also limits the length of the name to 128 characters. Furthermore, the reflected callback name is now always prepended with "/**/", which is a common workaround to protect against attacks such as Rosetta Flash. Fixes FS#46259. Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index e102fed4..e646c636 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -110,9 +110,13 @@ class AurJSON { return; } - if (isset($http_data['callback'])) { + $callback = $http_data['callback']; + if (isset($callback)) { + if (!preg_match('/^[a-zA-Z0-9().]{1,128}$/D', $callback)) { + return $this->json_error('Invalid callback name.'); + } header('content-type: text/javascript'); - return $http_data['callback'] . "({$json})"; + return '/**/' . $callback . '(' . $json . ')'; } else { header('content-type: application/json'); return $json; From f9476c10930029ca7a44a14b5e1749d36512880c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Sep 2015 17:54:36 +0200 Subject: [PATCH 0060/1891] Show providers in dependencies For all "virtual provisions" in package dependencies, show links to the actual packages providing the dependency. This partly implements FS#14125. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 67 +++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index d760429e..d83a01ff 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -154,6 +154,33 @@ function pkg_groups($pkgid) { return $grps; } +/** + * Get providers for a specific package + * + * @param string $name The name of the "package" to get providers for + * + * @return array The IDs and names of all providers of the package + */ +function pkg_providers($name) { + $dbh = DB::connect(); + $q = "SELECT p.ID, p.Name FROM Packages p "; + $q.= "INNER JOIN PackageRelations pr ON pr.PackageID = p.ID "; + $q.= "INNER JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; + $q.= "WHERE rt.Name = 'provides' "; + $q.= "AND pr.RelName = " . $dbh->quote($name); + $result = $dbh->query($q); + + if (!$result) { + return array(); + } + + $providers = array(); + while ($row = $result->fetch(PDO::FETCH_NUM)) { + $providers[] = $row; + } + return $providers; +} + /** * Get package dependencies for a specific package * @@ -232,15 +259,41 @@ function pkg_depend_link($name, $type, $cond, $arch, $pkg_id, $show_desc=true) { $desc = '(unknown)'; } - $link = ' 0) { + $link = htmlspecialchars($name) . ' '; + $link .= '('; + foreach ($providers as $provider) { + $name = $provider[1]; + $link .= ''; + $link .= htmlspecialchars($name) . ', '; + } + $link = substr($link, 0, -2); + $link .= ')'; + } else { + $link = ''; + $link .= htmlspecialchars($name) . ''; + $link .= htmlspecialchars($cond); } - $link .= '" title="' . __('View packages details for') .' ' . htmlspecialchars($name) . '">'; - $link .= htmlspecialchars($name) . ''; - $link .= htmlspecialchars($cond); if ($type != 'depends' || $arch) { $link .= ' ('; From 34e7f7084ae30cd2cb50edfef5ff14f3a311e11a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Sep 2015 14:45:15 +0200 Subject: [PATCH 0061/1891] Transfer notifications when merging packages When a package base is merged into another one, followers of the old package base usually want to be notified about comments the new package base as well. Fixes FS#27687. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 7 +++---- web/lib/pkgbasefuncs.inc.php | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 55b29110..f6bf6ffb 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -167,10 +167,9 @@ def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): if new_pkgbase_id: new_pkgbase_uri = aur_location + '/pkgbase/' + new_pkgbase + '/' body = '%s [1] merged %s [2] into %s [3].\n\n' \ - 'You will no longer receive notifications about this ' \ - 'package, please go to [3] and click "%s" if you wish to ' \ - 'receive them again.' % \ - (user, old_pkgbase, new_pkgbase, 'Notify of new comments') + 'If you no longer wish receive notifications about the new ' \ + 'package, please go to [3] and click "%s".' %\ + (user, old_pkgbase, new_pkgbase, 'Disable notifications') body += '\n\n' body += '[1] ' + user_uri + '\n' body += '[2] ' + pkgbase_uri + '\n' diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 799f1da9..cb756f61 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -448,6 +448,20 @@ function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) { $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")"; $dbh->exec($q); + /* Merge notifications */ + $q = "SELECT DISTINCT UserID FROM CommentNotify cn "; + $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ") "; + $q.= "AND NOT EXISTS (SELECT * FROM CommentNotify cn2 "; + $q.= "WHERE cn2.PackageBaseID = " . intval($merge_base_id) . " "; + $q.= "AND cn2.UserID = cn.UserID)"; + $result = $dbh->query($q); + + while ($notify_uid = $result->fetch(PDO::FETCH_COLUMN, 0)) { + $q = "INSERT INTO CommentNotify (UserID, PackageBaseID) "; + $q.= "VALUES (" . intval($notify_uid) . ", " . intval($merge_base_id) . ")"; + $dbh->exec($q); + } + /* Merge votes */ foreach ($base_ids as $base_id) { $q = "UPDATE PackageVotes "; From 2c20403cc4e7f788b04afbf7adda6e96e3cfcf27 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 16 Sep 2015 22:07:59 +0200 Subject: [PATCH 0062/1891] git-update: Use proper stop value for slice Fixes a regression introduced in 4112e57 (Add a restore command to the SSH interface, 2015-08-14). Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 5ff8b285..4698382d 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -188,7 +188,7 @@ if len(sys.argv) == 2 and sys.argv[1] == "restore": refname = "refs/heads/master" sha1_old = sha1_new = repo.lookup_reference('refs/heads/' + pkgbase).target elif len(sys.argv) == 4: - refname, sha1_old, sha1_new = sys.argv[1:3] + refname, sha1_old, sha1_new = sys.argv[1:4] else: die("invalid arguments") From dd808ac8023175f940f54746fc69f9a61a80fc03 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 17 Sep 2015 19:06:18 +0200 Subject: [PATCH 0063/1891] Use a separate function for "Required by" links Do not use the same function for generating dependency and inverse dependency links. Instead, factor out common code and create two separate functions for those (rather different) functionalities. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 92 +++++++++++++++++++++++++----------- web/template/pkg_details.php | 2 +- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index d83a01ff..2939c25f 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -238,6 +238,48 @@ function pkg_relations($pkgid) { return $rels; } +/** + * Get the HTML code to display a package dependency link annotation + * (dependency type, architecture, ...) + * + * @param string $type The name of the dependency type + * @param string $arch The package dependency architecture + * @param string $desc An optdepends description + * + * @return string The HTML code of the label to display + */ +function pkg_deplink_annotation($type, $arch, $desc=false) { + if ($type == 'depends' && !$arch) { + return ''; + } + + $link = ' ('; + + if ($type == 'makedepends') { + $link .= 'make'; + } elseif ($type == 'checkdepends') { + $link .= 'check'; + } elseif ($type == 'optdepends') { + $link .= 'optional'; + } + + if ($type != 'depends' && $arch) { + $link .= ', '; + } + + if ($arch) { + $link .= htmlspecialchars($arch); + } + + $link .= ')'; + if ($type == 'optdepends' && $desc) { + $link .= ' – ' . htmlspecialchars($desc) . ' '; + } + $link .= ''; + + return $link; +} + /** * Get the HTML code to display a package dependency link * @@ -246,11 +288,10 @@ function pkg_relations($pkgid) { * @param string $cond The package dependency condition string * @param string $arch The package dependency architecture * @param int $pkg_id The package of the package to display the dependency for - * @param bool $show_desc Whether the description of optdepends is shown * * @return string The HTML code of the label to display */ -function pkg_depend_link($name, $type, $cond, $arch, $pkg_id, $show_desc=true) { +function pkg_depend_link($name, $type, $cond, $arch, $pkg_id) { if ($type == 'optdepends' && strpos($name, ':') !== false) { $tokens = explode(':', $name, 2); $name = $tokens[0]; @@ -295,33 +336,30 @@ function pkg_depend_link($name, $type, $cond, $arch, $pkg_id, $show_desc=true) { $link .= htmlspecialchars($cond); } - if ($type != 'depends' || $arch) { - $link .= ' ('; + return $link . pkg_deplink_annotation($type, $arch, $desc); +} - if ($type == 'makedepends') { - $link .= 'make'; - } elseif ($type == 'checkdepends') { - $link .= 'check'; - } elseif ($type == 'optdepends') { - $link .= 'optional'; - } - - if ($type != 'depends' && $arch) { - $link .= ', '; - } - - if ($arch) { - $link .= htmlspecialchars($arch); - } - - $link .= ')'; - if ($show_desc && $type == 'optdepends') { - $link .= ' – ' . htmlspecialchars($desc) . ' '; - } - $link .= ''; +/** + * Get the HTML code to display a package requirement link + * + * @param string $name The name of the requirement + * @param string $type The name of the dependency type + * @param string $arch The package dependency architecture + * + * @return string The HTML code of the link to display + */ +function pkg_requiredby_link($name, $type, $arch) { + if ($type == 'optdepends' && strpos($name, ':') !== false) { + $tokens = explode(':', $name, 2); + $name = $tokens[0]; } - return $link; + $link = ''; + $link .= htmlspecialchars($name) . ''; + + return $link . pkg_deplink_annotation($type, $arch); } /** @@ -379,7 +417,7 @@ function pkg_required($name="") { $deps = array(); if ($name != "") { $dbh = DB::connect(); - $q = "SELECT p.Name, dt.Name, '' AS DepCondition, pd.DepArch, p.ID FROM PackageDepends pd "; + $q = "SELECT p.Name, dt.Name, pd.DepArch FROM PackageDepends pd "; $q.= "LEFT JOIN Packages p ON p.ID = pd.PackageID "; $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; $q.= "WHERE pd.DepName = " . $dbh->quote($name) . " "; diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 5ba3607a..0a2d90eb 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -285,7 +285,7 @@ endif; 0): ?>

      -
    • +
    From 9d2d8f1c8c1cbc65d0842544e1803d95e8a5b130 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 17 Sep 2015 19:15:47 +0200 Subject: [PATCH 0064/1891] Honor virtual provisions in package requirements Implements FS#14125. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 31 ++++++++++++++++++++++++++----- web/template/pkg_details.php | 8 ++++---- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 2939c25f..b00b22d2 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -343,12 +343,14 @@ function pkg_depend_link($name, $type, $cond, $arch, $pkg_id) { * Get the HTML code to display a package requirement link * * @param string $name The name of the requirement + * @param string $depends The (literal) name of the dependency of $name * @param string $type The name of the dependency type * @param string $arch The package dependency architecture + * @param string $pkgname The name of dependant package * * @return string The HTML code of the link to display */ -function pkg_requiredby_link($name, $type, $arch) { +function pkg_requiredby_link($name, $depends, $type, $arch, $pkgname) { if ($type == 'optdepends' && strpos($name, ':') !== false) { $tokens = explode(':', $name, 2); $name = $tokens[0]; @@ -359,6 +361,18 @@ function pkg_requiredby_link($name, $type, $arch) { $link .= '" title="' . __('View packages details for') .' ' . htmlspecialchars($name) . '">'; $link .= htmlspecialchars($name) . ''; + if ($depends != $pkgname) { + $depname = $depends; + if (strpos($depends, ':') !== false) { + $tokens = explode(':', $depname, 2); + $depname = $tokens[0]; + } + + $link .= ' ('; + $link .= __('requires %s', htmlspecialchars($depname)); + $link .= ')'; + } + return $link . pkg_deplink_annotation($type, $arch); } @@ -410,18 +424,25 @@ function pkg_source_link($url, $arch) { * Determine packages that depend on a package * * @param string $name The package name for the dependency search + * @param array $provides A list of virtual provisions of the package * * @return array All packages that depend on the specified package name */ -function pkg_required($name="") { +function pkg_required($name="", $provides) { $deps = array(); if ($name != "") { $dbh = DB::connect(); - $q = "SELECT p.Name, dt.Name, pd.DepArch FROM PackageDepends pd "; + + $name_list = $dbh->quote($name); + foreach ($provides as $p) { + $name_list .= ',' . $dbh->quote($p[0]); + } + + $q = "SELECT p.Name, pd.DepName, dt.Name, pd.DepArch FROM PackageDepends pd "; $q.= "LEFT JOIN Packages p ON p.ID = pd.PackageID "; $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; - $q.= "WHERE pd.DepName = " . $dbh->quote($name) . " "; - $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) = " . $dbh->quote($name) . " "; + $q.= "WHERE pd.DepName IN (" . $name_list . ") "; + $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) IN (" . $name_list . ") "; $q.= "ORDER BY p.Name"; $result = $dbh->query($q); if (!$result) {return array();} diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 0a2d90eb..b9fd51ba 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -40,9 +40,6 @@ $out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : gmdate("Y-m-d", intval($ $lics = pkg_licenses($row["ID"]); $grps = pkg_groups($row["ID"]); -$deps = pkg_dependencies($row["ID"]); -$requiredby = pkg_required($row["Name"]); - usort($deps, function($x, $y) { if ($x[1] != $y[1]) { if ($x[1] == "depends") { @@ -83,6 +80,9 @@ foreach ($rels as $rel) { } } +$deps = pkg_dependencies($row["ID"]); +$requiredby = pkg_required($row["Name"], $rels_p); + # $sources[0] = 'src'; $sources = pkg_sources($row["ID"]); @@ -285,7 +285,7 @@ endif; 0): ?>
      -
    • +
    From 0dd27a86b1bceaa01d406e4b85139acbd8c885ab Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 18 Sep 2015 07:52:15 +0200 Subject: [PATCH 0065/1891] Remove legacy code In 74edb6f (Use Git repositories to store packages, 2014-06-06), package creation was moved to the Python backend. Remove several PHP functions that are no longer needed. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 189 --------------------------------------- 1 file changed, 189 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index b00b22d2..d3cad12f 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -515,23 +515,6 @@ function pkg_name_from_id($pkgids) { } } -/** - * Determine if a package name is on the database blacklist - * - * @param string $name The package name to check - * - * @return bool True if the name is blacklisted, otherwise false - */ -function pkg_name_is_blacklisted($name) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM PackageBlacklist "; - $q.= "WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - - if (!$result) return false; - return ($result->fetchColumn() > 0); -} - /** * Get the package details * @@ -912,178 +895,6 @@ function sanitize_ids($ids) { return $new_ids; } -/** - * Add package information to the database for a specific package - * - * @param int $base_id ID of the package base - * @param string $pkgname Name of the new package - * @param string $pkgver Version of the new package - * @param string $pkgdesc Description of the new package - * @param string $pkgurl Upstream URL for the new package - * - * @return int ID of the new package - */ -function pkg_create($base_id, $pkgname, $pkgver, $pkgdesc, $pkgurl) { - $dbh = DB::connect(); - $q = sprintf("INSERT INTO Packages (PackageBaseID, Name, Version, " . - "Description, URL) VALUES (%d, %s, %s, %s, %s)", - $base_id, $dbh->quote($pkgname), $dbh->quote($pkgver), - $dbh->quote($pkgdesc), $dbh->quote($pkgurl)); - $dbh->exec($q); - return $dbh->lastInsertId(); -} - -/** - * Add a dependency for a specific package to the database - * - * @param int $pkgid The package ID to add the dependency for - * @param string $type The type of dependency to add - * @param string $depname The name of the dependency to add - * @param string $depcondition The type of dependency for the package - * @param string $deparch The architecture of the dependency to add - * - * @return void - */ -function pkg_add_dep($pkgid, $type, $depname, $depcondition, $deparch) { - $dbh = DB::connect(); - $q = sprintf("INSERT INTO PackageDepends (PackageID, DepTypeID, DepName, DepCondition, DepArch) VALUES (%d, %d, %s, %s, %s)", - $pkgid, - pkg_dependency_type_id_from_name($type), - $dbh->quote($depname), - $dbh->quote($depcondition), - $deparch ? $dbh->quote($deparch) : 'NULL' - ); - $dbh->exec($q); -} - -/** - * Add a relation for a specific package to the database - * - * @param int $pkgid The package ID to add the relation for - * @param string $type The type of relation to add - * @param string $relname The name of the relation to add - * @param string $relcondition The version requirement of the relation - * @param string $relarch The architecture of the relation to add - * - * @return void - */ -function pkg_add_rel($pkgid, $type, $relname, $relcondition, $relarch) { - $dbh = DB::connect(); - $q = sprintf("INSERT INTO PackageRelations (PackageID, RelTypeID, RelName, RelCondition, RelArch) VALUES (%d, %d, %s, %s, %s)", - $pkgid, - pkg_relation_type_id_from_name($type), - $dbh->quote($relname), - $dbh->quote($relcondition), - $relarch ? $dbh->quote($relarch) : 'NULL' - ); - $dbh->exec($q); -} - -/** - * Add a source for a specific package to the database - * - * @param int $pkgid The package ID to add the source for - * @param string $pkgsrc The package source to add to the database - * @param string $srcarch The architecture of the source to add - * - * @return void - */ -function pkg_add_src($pkgid, $pkgsrc, $srcarch) { - $dbh = DB::connect(); - $q = sprintf("INSERT INTO PackageSources (PackageID, Source, SourceArch) VALUES (%d, %s, %s)", - $pkgid, - $dbh->quote($pkgsrc), - $srcarch ? $dbh->quote($srcarch) : 'NULL' - ); - $dbh->exec($q); -} - -/** - * Creates a new group and returns its ID - * - * If the groups already exists, the ID of the already existing group is - * returned. - * - * @param string $name The name of the group to create - * - * @return int The ID of the group - */ -function pkg_create_group($name) { - $dbh = DB::connect(); - $q = sprintf("SELECT ID FROM Groups WHERE Name = %s", $dbh->quote($name)); - $result = $dbh->query($q); - if ($result) { - $grpid = $result->fetch(PDO::FETCH_COLUMN, 0); - if ($grpid > 0) { - return $grpid; - } - } - - $q = sprintf("INSERT INTO Groups (Name) VALUES (%s)", $dbh->quote($name)); - $dbh->exec($q); - return $dbh->lastInsertId(); -} - -/** - * Add a package to a group - * - * @param int $pkgid The package ID of the package to add - * @param int $grpid The group ID of the group to add the package to - * - * @return void - */ -function pkg_add_grp($pkgid, $grpid) { - $dbh = DB::connect(); - $q = sprintf("INSERT INTO PackageGroups (PackageID, GroupID) VALUES (%d, %d)", - $pkgid, - $grpid - ); - $dbh->exec($q); -} - -/** - * Creates a new license and returns its ID - * - * If the license already exists, the ID of the already existing license is - * returned. - * - * @param string $name The name of the license to create - * - * @return int The ID of the license - */ -function pkg_create_license($name) { - $dbh = DB::connect(); - $q = sprintf("SELECT ID FROM Licenses WHERE Name = %s", $dbh->quote($name)); - $result = $dbh->query($q); - if ($result) { - $licid = $result->fetch(PDO::FETCH_COLUMN, 0); - if ($licid > 0) { - return $licid; - } - } - - $q = sprintf("INSERT INTO Licenses (Name) VALUES (%s)", $dbh->quote($name)); - $dbh->exec($q); - return $dbh->lastInsertId(); -} - -/** - * Add a license to a package - * - * @param int $pkgid The package ID of the package - * @param int $grpid The ID of the license to add - * - * @return void - */ -function pkg_add_lic($pkgid, $licid) { - $dbh = DB::connect(); - $q = sprintf("INSERT INTO PackageLicenses (PackageID, LicenseID) VALUES (%d, %d)", - $pkgid, - $licid - ); - $dbh->exec($q); -} - /** * Determine package information for latest package * From 9cae17ff7c4eeb7af66e06ba38de3b64d08dec2f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 18 Sep 2015 08:02:33 +0200 Subject: [PATCH 0066/1891] Extract package name from details When requesting package details, instead of performing another SQL query to obtain the package name, extract the name from the result of the package details query. Also, drop pkg_name_from_id() which is no longer needed after this optimization. Signed-off-by: Lukas Fleischer --- web/html/packages.php | 27 ++++++++++++++------------- web/lib/pkgfuncs.inc.php | 36 ------------------------------------ 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/web/html/packages.php b/web/html/packages.php index bf3daf88..38a2e296 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -11,19 +11,25 @@ check_sid(); # see if they're still logged in if (!isset($pkgid) || !isset($pkgname)) { if (isset($_GET['ID'])) { $pkgid = intval($_GET['ID']); - $pkgname = pkg_name_from_id($_GET['ID']); } else if (isset($_GET['N'])) { $pkgid = pkg_from_name($_GET['N']); - $pkgname = $_GET['N']; } else { - unset($pkgid, $pkgname); + unset($pkgid); } +} - if (isset($pkgid) && ($pkgid == 0 || $pkgid == NULL || $pkgname == NULL)) { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } +$details = array(); +if (isset($pkgid)) { + $details = pkg_get_details($pkgid); + $pkgname = $details['Name']; +} else { + unset($pkgname); +} + +if (isset($pkgid) && ($pkgid == 0 || $pkgid == NULL || $pkgname == NULL)) { + header("HTTP/1.0 404 Not Found"); + include "./404.php"; + return; } # Set the title to the current query or package name @@ -35,11 +41,6 @@ if (isset($pkgname)) { $title = __("Packages"); } -$details = array(); -if (isset($pkgname)) { - $details = pkg_get_details($pkgid); -} - html_header($title, $details); ?> diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index d3cad12f..62bea652 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -479,42 +479,6 @@ function pkg_sources($pkgid) { return $sources; } -/** - * Determine package names from package IDs - * - * @param string|array $pkgids The package IDs to get names for - * - * @return array|string All names if multiple package IDs, otherwise package name - */ -function pkg_name_from_id($pkgids) { - if (is_array($pkgids)) { - $pkgids = sanitize_ids($pkgids); - $names = array(); - $dbh = DB::connect(); - $q = "SELECT Name FROM Packages WHERE ID IN ("; - $q.= implode(",", $pkgids) . ")"; - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $names[] = $row['Name']; - } - } - return $names; - } - elseif ($pkgids > 0) { - $dbh = DB::connect(); - $q = "SELECT Name FROM Packages WHERE ID = " . $pkgids; - $result = $dbh->query($q); - if ($result) { - $name = $result->fetch(PDO::FETCH_NUM); - } - return $name[0]; - } - else { - return NULL; - } -} - /** * Get the package details * From 0478a0a2dade87e9bce71e9839b791c67fddfdc8 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Fri, 18 Sep 2015 23:12:13 +0200 Subject: [PATCH 0067/1891] Fix type of FlaggerUID in table PackageBases Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.1.0.txt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index ff137dc6..2c45a976 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -85,7 +85,7 @@ CREATE TABLE PackageBases ( FlaggerComment VARCHAR(255) NOT NULL, SubmittedTS BIGINT UNSIGNED NOT NULL, ModifiedTS BIGINT UNSIGNED NOT NULL, - FlaggerUID BIGINT UNSIGNED NULL DEFAULT NULL, -- who flagged the package out-of-date? + FlaggerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- who flagged the package out-of-date? SubmitterUID INTEGER UNSIGNED NULL DEFAULT NULL, -- who submitted it? MaintainerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- User PackagerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- Last packager diff --git a/upgrading/4.1.0.txt b/upgrading/4.1.0.txt index e9545ffb..439562f7 100644 --- a/upgrading/4.1.0.txt +++ b/upgrading/4.1.0.txt @@ -13,6 +13,7 @@ package out-of-date: ---- ALTER TABLE PackageBases - ADD COLUMN FlaggerUID BIGINT UNSIGNED NULL DEFAULT NULL, - ADD COLUMN FlaggerComment VARCHAR(255) NOT NULL; + ADD COLUMN FlaggerUID INTEGER UNSIGNED NULL DEFAULT NULL, + ADD COLUMN FlaggerComment VARCHAR(255) NOT NULL, + ADD FOREIGN KEY (FlaggerUID) REFERENCES Users(ID) ON DELETE SET NULL; ---- From f3ec4d1ef553259b0a617b9d11da4ece2ecc9dfd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 20 Sep 2015 11:03:15 +0200 Subject: [PATCH 0068/1891] Rename "Age" search order to "Last modified" Use a better description for sorting by modification time, as it is not clear whether "Age" refers to the package creation date or to the modification date. The possibility to sort by "Age" is kept internally (but hidden from the user interface) such that old links to search results still work. Fixes FS#46319. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 4 ++++ web/template/pkg_search_form.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 62bea652..600e5905 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -755,7 +755,11 @@ function pkg_search_page($SID="") { case 'm': $q_sort .= "Maintainer " . $order . ", "; break; + case 'l': + $q_sort .= "ModifiedTS " . $order . ", "; + break; case 'a': + /* For compatibility with old search links. */ $q_sort .= "-ModifiedTS " . $order . ", "; break; default: diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php index 404d16ec..1cc5fb26 100644 --- a/web/template/pkg_search_form.php +++ b/web/template/pkg_search_form.php @@ -24,7 +24,7 @@ $sortby = array( 'w' => __('Voted'), 'o' => __('Notify'), 'm' => __('Maintainer'), - 'a' => __('Age') + 'l' => __('Last modified') ); $orderby = array( From d5d08b8f926e8882864afbfd7446440acc1005d0 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 20 Sep 2015 20:12:25 +0200 Subject: [PATCH 0069/1891] Add option to hide one's email address Implements FS#42343. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 1 + upgrading/4.1.0.txt | 7 +++++++ web/html/account.php | 19 ++++++++++--------- web/html/register.php | 6 +++--- web/lib/acctfuncs.inc.php | 11 +++++++++-- web/template/account_details.php | 12 +++++++++++- web/template/account_edit_form.php | 5 +++++ 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 2c45a976..53dc468b 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -26,6 +26,7 @@ CREATE TABLE Users ( Suspended TINYINT UNSIGNED NOT NULL DEFAULT 0, Username VARCHAR(32) NOT NULL, Email VARCHAR(64) NOT NULL, + HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0, Passwd CHAR(32) NOT NULL, Salt CHAR(32) NOT NULL DEFAULT '', ResetKey CHAR(32) NOT NULL DEFAULT '', diff --git a/upgrading/4.1.0.txt b/upgrading/4.1.0.txt index 439562f7..26f9f65e 100644 --- a/upgrading/4.1.0.txt +++ b/upgrading/4.1.0.txt @@ -17,3 +17,10 @@ ALTER TABLE PackageBases ADD COLUMN FlaggerComment VARCHAR(255) NOT NULL, ADD FOREIGN KEY (FlaggerUID) REFERENCES Users(ID) ON DELETE SET NULL; ---- + +3. Add field to store the state of a user's email address: + +---- +ALTER TABLE Users + ADD COLUMN HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0; +---- diff --git a/web/html/account.php b/web/html/account.php index adc2542c..b2886fc6 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -32,10 +32,10 @@ if ($action == "UpdateAccount") { list($success, $update_account_message) = process_account_form( "edit", "UpdateAccount", in_request("U"), in_request("T"), in_request("S"), - in_request("E"), in_request("P"), in_request("C"), - in_request("R"), in_request("L"), in_request("I"), - in_request("K"), in_request("PK"), in_request("J"), - in_request("ID"), $row["Username"]); + in_request("E"), in_request("H"), in_request("P"), + in_request("C"), in_request("R"), in_request("L"), + in_request("I"), in_request("K"), in_request("PK"), + in_request("J"), in_request("ID"), $row["Username"]); } } @@ -79,8 +79,8 @@ if (isset($_COOKIE["AURSID"])) { if (can_edit_account($row)) { display_account_form("UpdateAccount", $row["Username"], $row["AccountTypeID"], $row["Suspended"], $row["Email"], - "", "", $row["RealName"], $row["LangPreference"], - $row["IRCNick"], $row["PGPKey"], $PK, + $row["HideEmail"], "", "", $row["RealName"], + $row["LangPreference"], $row["IRCNick"], $row["PGPKey"], $PK, $row["InactivityTS"] ? 1 : 0, $row["ID"], $row["Username"]); } else { print __("You do not have permission to edit this account."); @@ -115,9 +115,10 @@ if (isset($_COOKIE["AURSID"])) { if (!$success) { display_account_form("UpdateAccount", in_request("U"), in_request("T"), - in_request("S"), in_request("E"), in_request("P"), in_request("C"), - in_request("R"), in_request("L"), in_request("I"), in_request("K"), - in_request("PK"), in_request("J"), in_request("ID"), $row["Username"]); + in_request("S"), in_request("E"), in_request("H"), in_request("P"), + in_request("C"), in_request("R"), in_request("L"), in_request("I"), + in_request("K"), in_request("PK"), in_request("J"), in_request("ID"), + $row["Username"]); } } else { diff --git a/web/html/register.php b/web/html/register.php index 9c5c1cc1..f8400a37 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -21,7 +21,7 @@ echo '

    ' . __('Register') . '

    '; if (in_request("Action") == "NewAccount") { list($success, $message) = process_account_form( "new", "NewAccount", in_request("U"), 1, 0, - in_request("E"), '', '', in_request("R"), + in_request("E"), in_request("H"), '', '', in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("PK")); @@ -29,13 +29,13 @@ if (in_request("Action") == "NewAccount") { if (!$success) { display_account_form("NewAccount", in_request("U"), 1, 0, - in_request("E"), '', '', in_request("R"), + in_request("E"), in_request("H"), '', '', in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("PK")); } } else { print '

    ' . __("Use this form to create an account.") . '

    '; - display_account_form("NewAccount", "", "", "", "", "", "", "", $LANG); + display_account_form("NewAccount", "", "", "", "", "", "", "", "", $LANG); } echo ''; diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 756c8477..a2009988 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -47,6 +47,7 @@ function html_format_pgp_fingerprint($fingerprint) { * @param string $T The account type of the displayed user * @param string $S Whether the displayed user has a suspended account * @param string $E The e-mail address of the displayed user + * @param string $H Whether the e-mail address of the displayed user is hidden * @param string $P The password value of the displayed user * @param string $C The confirmed password value of the displayed user * @param string $R The real name of the displayed user @@ -60,7 +61,7 @@ function html_format_pgp_fingerprint($fingerprint) { * * @return void */ -function display_account_form($A,$U="",$T="",$S="",$E="",$P="",$C="",$R="", +function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="", $L="",$I="",$K="",$PK="",$J="",$UID=0,$N="") { global $SUPPORTED_LANGS; @@ -78,6 +79,7 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$P="",$C="",$R="", * @param string $T The account type for the user * @param string $S Whether or not the account is suspended * @param string $E The e-mail address for the user + * @param string $H Whether or not the e-mail address should be hidden * @param string $P The password for the user * @param string $C The confirmed password for the user * @param string $R The real name of the user @@ -91,7 +93,7 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$P="",$C="",$R="", * * @return array Boolean indicating success and message to be printed */ -function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", +function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", $R="",$L="",$I="",$K="",$PK="",$J="",$UID=0,$N="") { global $SUPPORTED_LANGS; @@ -324,6 +326,11 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="", $q.= ", Suspended = 0"; } $q.= ", Email = " . $dbh->quote($E); + if ($H) { + $q.= ", HideEmail = 1"; + } else { + $q.= ", HideEmail = 0"; + } if ($P) { $salt = generate_salt(); $hash = salted_hash($P, $salt); diff --git a/web/template/account_details.php b/web/template/account_details.php index 9282b2c2..59a6a63b 100644 --- a/web/template/account_details.php +++ b/web/template/account_details.php @@ -25,7 +25,17 @@
    - + diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 83aedb0d..16655c0f 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -76,6 +76,11 @@

    +

    + + /> +

    +

    From 4516f07d9c135f32dc1341d289606cd0c4801d82 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Tue, 22 Sep 2015 22:02:37 +0200 Subject: [PATCH 0070/1891] Add search for keywords only Implements FS#45619. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 103 +++++++++++++++++++------------ web/template/pkg_search_form.php | 1 + 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 600e5905..edc747b8 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -575,7 +575,10 @@ function pkg_display_details($id=0, $row, $SID="") { * SeB- property that search string (K) represents * values: n - package name * nd - package name & description - * x - package name (exact match) + * b - package base name + * N - package name (exact match) + * B - package base name (exact match) + * k - package keyword(s) * m - package maintainer's username * s - package submitter's username * do_Orphans - boolean. whether to search packages @@ -667,6 +670,10 @@ function pkg_search_page($SID="") { $K = "%" . addcslashes($_GET['K'], '%_') . "%"; $q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") "; } + elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "k") { + /* Search by keywords. */ + $q_where .= construct_keyword_search($dbh, false); + } elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "N") { /* Search by name (exact match). */ $q_where .= "AND (Packages.Name = " . $dbh->quote($_GET['K']) . ") "; @@ -677,44 +684,7 @@ function pkg_search_page($SID="") { } else { /* Keyword search (default). */ - $count = 0; - $q_keywords = ""; - $op = ""; - - foreach (str_getcsv($_GET['K'], ' ') as $term) { - if ($term == "") { - continue; - } - if ($count > 0 && strtolower($term) == "and") { - $op = "AND "; - continue; - } - if ($count > 0 && strtolower($term) == "or") { - $op = "OR "; - continue; - } - if ($count > 0 && strtolower($term) == "not") { - $op .= "NOT "; - continue; - } - - $term = "%" . addcslashes($term, '%_') . "%"; - $q_keywords .= $op . " (Packages.Name LIKE " . $dbh->quote($term) . " OR "; - $q_keywords .= "Description LIKE " . $dbh->quote($term) . " OR "; - $q_keywords .= "EXISTS (SELECT * FROM PackageKeywords WHERE "; - $q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND "; - $q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) "; - - $count++; - if ($count >= 20) { - break; - } - $op = "AND "; - } - - if (!empty($q_keywords)) { - $q_where .= "AND (" . $q_keywords . ") "; - } + $q_where .= construct_keyword_search($dbh, true); } } @@ -833,6 +803,61 @@ function pkg_search_page($SID="") { return; } +/** + * Construct the WHERE part of the sophisticated keyword search + * + * @param handle $dbh Database handle + * @param boolean $namedesc Search name and description fields + * + * @return string WHERE part of the SQL clause + */ +function construct_keyword_search($dbh, $namedesc) { + $count = 0; + $where_part = ""; + $q_keywords = ""; + $op = ""; + + foreach (str_getcsv($_GET['K'], ' ') as $term) { + if ($term == "") { + continue; + } + if ($count > 0 && strtolower($term) == "and") { + $op = "AND "; + continue; + } + if ($count > 0 && strtolower($term) == "or") { + $op = "OR "; + continue; + } + if ($count > 0 && strtolower($term) == "not") { + $op .= "NOT "; + continue; + } + + $term = "%" . addcslashes($term, '%_') . "%"; + $q_keywords .= $op . " ("; + if ($namedesc) { + $q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " OR "; + $q_keywords .= "Description LIKE " . $dbh->quote($term) . " OR "; + } + $q_keywords .= "EXISTS (SELECT * FROM PackageKeywords WHERE "; + $q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND "; + $q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) "; + + $count++; + if ($count >= 20) { + break; + } + $op = "AND "; + } + + if (!empty($q_keywords)) { + $where_part = "AND (" . $q_keywords . ") "; + } + + return $where_part; +} + /** * Determine if a POST string has been sent by a visitor * diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php index 1cc5fb26..795a796e 100644 --- a/web/template/pkg_search_form.php +++ b/web/template/pkg_search_form.php @@ -7,6 +7,7 @@ $searchby = array( 'b' => __('Package Base'), 'N' => __('Exact Name'), 'B' => __('Exact Package Base'), + 'k' => __('Keywords'), 'm' => __('Maintainer'), 's' => __('Submitter') ); From 311c7f0366fe1c48a07dd1f7b230d8f1034508e0 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 23 Sep 2015 21:46:33 +0200 Subject: [PATCH 0071/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 196 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 138 insertions(+), 58 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index f7b9a1bc..47cf22bb 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -1,14 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. +# This file is distributed under the same license as the AUR package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.0.0-rc5\n" +"Project-Id-Version: AUR v4.0.0\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" +"POT-Creation-Date: 2015-09-23 21:46+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -137,6 +137,10 @@ msgstr "" msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + #: html/home.php template/header.php msgid "Home" msgstr "" @@ -169,8 +173,8 @@ msgstr "" #: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" #: html/home.php @@ -295,10 +299,6 @@ msgstr "" msgid "UnNotify" msgstr "" -#: html/index.php -msgid "Flag" -msgstr "" - #: html/index.php msgid "UnFlag" msgstr "" @@ -320,9 +320,8 @@ msgstr "" msgid "Enter login credentials" msgstr "" -#: html/login.php template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php -msgid "Username" +#: html/login.php +msgid "User name or email address" msgstr "" #: html/login.php template/account_edit_form.php @@ -348,7 +347,7 @@ msgid "Search Criteria" msgstr "" #: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "" @@ -373,14 +372,6 @@ msgstr "" msgid "Invalid e-mail." msgstr "" -#: html/passreset.php -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - #: html/passreset.php msgid "Password Reset" msgstr "" @@ -420,6 +411,10 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + #: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " @@ -515,6 +510,48 @@ msgstr "" msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "" + +#: html/pkgflag.php +msgid "Flag" +msgstr "" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + #: html/pkgmerge.php msgid "Package Merging" msgstr "" @@ -705,22 +742,14 @@ msgstr "" msgid "The account, %s%s%s, has been successfully created." msgstr "" -#: lib/acctfuncs.inc.php -msgid "Click on the Login link above to use your account." -msgstr "" - -#: lib/acctfuncs.inc.php -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" - #: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." @@ -770,6 +799,26 @@ msgstr "" msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php +msgid "You do not have the right to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "" + #: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "" @@ -888,6 +937,14 @@ msgstr "" msgid "You are not allowed to delete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + #: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" @@ -913,6 +970,11 @@ msgstr "" msgid "View packages details for" msgstr "" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + #: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" @@ -959,6 +1021,11 @@ msgstr "" msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "" + #: template/account_details.php template/account_edit_form.php #: template/search_accounts_form.php msgid "Account Type" @@ -984,6 +1051,10 @@ msgstr "" msgid "Email Address" msgstr "" +#: template/account_details.php +msgid "hidden" +msgstr "" + #: template/account_details.php template/account_edit_form.php #: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" @@ -1053,6 +1124,16 @@ msgstr "" msgid "Inactive" msgstr "" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + #: template/account_edit_form.php msgid "Re-type password" msgstr "" @@ -1127,7 +1208,7 @@ msgstr "" msgid "Users" msgstr "" -#: template/comaintainers_form.php +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" @@ -1251,6 +1332,11 @@ msgstr "" msgid "Votes" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" @@ -1259,12 +1345,13 @@ msgstr "" msgid "Last Updated" msgstr "" -#: template/pkg_comment_form.php -msgid "Add Comment" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_form.php -msgid "Comment has been added." +#: template/pkg_comment_box.php template/pkg_comment_form.php +msgid "Add Comment" msgstr "" #: template/pkg_comments.php @@ -1276,20 +1363,27 @@ msgid "Latest Comments" msgstr "" #: template/pkg_comments.php -msgid "Delete comment" +#, php-format +msgid "%s commented on %s" msgstr "" #: template/pkg_comments.php #, php-format -msgid "Comment by %s" +msgid "Anonymous comment on %s" msgstr "" #: template/pkg_comments.php -msgid "Anonymous comment" +#, php-format +msgid "deleted on %s by %s" msgstr "" #: template/pkg_comments.php -msgid "deleted" +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php +msgid "Delete comment" msgstr "" #: template/pkg_comments.php @@ -1382,11 +1476,6 @@ msgstr "" msgid "Rejected" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php -msgid "Comments" -msgstr "" - #: template/pkgreq_form.php #, php-format msgid "File Request: %s" @@ -1503,17 +1592,13 @@ msgstr "" msgid "Name" msgstr "" -#: template/pkg_search_form.php template/pkg_search_results.php -msgid "Popularity" -msgstr "" - #: template/pkg_search_form.php template/pkg_search_results.php #: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "" #: template/pkg_search_form.php -msgid "Age" +msgid "Last modified" msgstr "" #: template/pkg_search_form.php @@ -1581,8 +1666,7 @@ msgid "" "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php +#: template/pkg_search_results.php template/tu_details.php template/tu_list.php msgid "Yes" msgstr "" @@ -1666,10 +1750,6 @@ msgstr "" msgid "My Statistics" msgstr "" -#: template/stats/user_table.php -msgid "Packages in unsupported" -msgstr "" - #: template/tu_details.php msgid "Proposal Details" msgstr "" From df160b61e87939689ec359926975892505aa2168 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Wed, 23 Sep 2015 23:48:56 +0200 Subject: [PATCH 0072/1891] Make it more clear that the bug tracker is for aurweb only Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/home.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/home.php b/web/html/home.php index 7e9a00fe..475370bb 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -112,7 +112,7 @@ html_header( __("Home") );

    ', '', '', From 2f8e0dfa3ac67a4225b27135977a48b124717762 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 24 Sep 2015 18:27:21 +0200 Subject: [PATCH 0073/1891] aurjson.class.php: Fix "Undefined index" notices Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index e646c636..304a50a6 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -110,8 +110,8 @@ class AurJSON { return; } - $callback = $http_data['callback']; - if (isset($callback)) { + if (isset($http_data['callback'])) { + $callback = $http_data['callback']; if (!preg_match('/^[a-zA-Z0-9().]{1,128}$/D', $callback)) { return $this->json_error('Invalid callback name.'); } @@ -281,11 +281,15 @@ class AurJSON { * proper data types in the JSON response. */ foreach (self::$numeric_fields as $field) { - $row[$field] = intval($row[$field]); + if (isset($row[$field])) { + $row[$field] = intval($row[$field]); + } } foreach (self::$decimal_fields as $field) { - $row[$field] = floatval($row[$field]); + if (isset($row[$field])) { + $row[$field] = floatval($row[$field]); + } } if ($this->version >= 2 && ($type == 'info' || $type == 'multiinfo')) { From 938b1058ebb6f652133fcba8f26606b4fb557d29 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 24 Sep 2015 18:31:47 +0200 Subject: [PATCH 0074/1891] pkgfuncs.inc.php: Squelch PHP warning Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index edc747b8..66bc249d 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -792,6 +792,7 @@ function pkg_search_page($SID="") { include('pkg_search_form.php'); + $searchresults = array(); if ($result) { while ($row = $result->fetch(PDO::FETCH_ASSOC)) { $searchresults[] = $row; From c67e5a1cdf970062c75ad11f019340d318193cbb Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 26 Sep 2015 07:42:05 +0200 Subject: [PATCH 0075/1891] aurjson.class.php: Sync error message with front-end Instead of introducing a new message "You do not have the right to edit this comment." for the RPC interface, use "You are not allowed to edit this comment." which we already show in the front-end. Reported-by: Christoph Seitz Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 304a50a6..db9cc547 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -532,7 +532,7 @@ class AurJSON { if (!has_credential(CRED_COMMENT_EDIT, array($user_id))) { $output = array( 'success' => 0, - 'error' => __('You do not have the right to edit this comment.') + 'error' => __('You are not allowed to edit this comment.') ); return json_encode($output); } elseif (is_null($comment)) { From e66595fb92204c4178b475e0cddf39f54154269d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 26 Sep 2015 07:49:27 +0200 Subject: [PATCH 0076/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index 47cf22bb..f2160406 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: AUR v4.0.0\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-23 21:46+0200\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -270,9 +270,9 @@ msgstr "" #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" #: html/home.php @@ -803,8 +803,8 @@ msgstr "" msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php -msgid "You do not have the right to edit this comment." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." msgstr "" #: lib/aurjson.class.php @@ -941,10 +941,6 @@ msgstr "" msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "You are not allowed to edit this comment." -msgstr "" - #: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" From fcb495874f3ff66b42dc723c99cb8ca4678a348a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 29 Sep 2015 08:14:54 +0200 Subject: [PATCH 0077/1891] AUTHORS: Add date ranges to current maintainers Signed-off-by: Lukas Fleischer --- AUTHORS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4462cab8..18c1337d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,8 +1,8 @@ Current Maintainers ------------------- -* Lukas Fleischer -* Johannes Löthberg +* Lukas Fleischer (2011-present) +* Johannes Löthberg (2015-present) Past Maintainers ---------------- From 693e4b50a3fb57f90d802806fd1b8b78f21bd499 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 29 Sep 2015 20:47:24 +0200 Subject: [PATCH 0078/1891] Remove empty package bases after 24 hours By using the setup-repo command, it is currently possible to create empty package bases, which can be used to make package base reservations. Add a maintenance script to remove such empty package bases after 24 hours. Fixes FS#46279. Signed-off-by: Lukas Fleischer --- scripts/pkgmaint.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 scripts/pkgmaint.py diff --git a/scripts/pkgmaint.py b/scripts/pkgmaint.py new file mode 100755 index 00000000..0eb94221 --- /dev/null +++ b/scripts/pkgmaint.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 + +import configparser +import mysql.connector +import os + +config = configparser.RawConfigParser() +config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") + +aur_db_host = config.get('database', 'host') +aur_db_name = config.get('database', 'name') +aur_db_user = config.get('database', 'user') +aur_db_pass = config.get('database', 'password') +aur_db_socket = config.get('database', 'socket') + +db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) +cur = db.cursor() + +cur.execute("DELETE FROM PackageBases WHERE " + + "UNIX_TIMESTAMP() - SubmittedTS > 86400 AND PackagerUID IS NULL") + +db.commit() +db.close() From 612300b39c3c19153fa4efa6cbb539c53f5f71ea Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 29 Sep 2015 08:03:26 +0200 Subject: [PATCH 0079/1891] Show a warning if .SRCINFO is unchanged Warn users when a remote ref update does not change the content of .SRCINFO such that users are reminded of updating package meta data. Implements FS#46130. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 4698382d..b4185251 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -169,6 +169,9 @@ def die(msg): sys.stderr.write("error: {:s}\n".format(msg)) exit(1) +def warn(msg): + sys.stderr.write("warning: {:s}\n".format(msg)) + def die_commit(msg, commit): sys.stderr.write("error: The following error " + "occurred when parsing commit\n") @@ -282,6 +285,13 @@ for commit in walker: if not fname in commit.tree: die_commit('missing source file: {:s}'.format(fname), str(commit.id)) +# Display a warning if .SRCINFO is unchanged. +if sha1_old != "0000000000000000000000000000000000000000": + srcinfo_id_old = repo[sha1_old].tree['.SRCINFO'].id + srcinfo_id_new = repo[sha1_new].tree['.SRCINFO'].id + if srcinfo_id_old == srcinfo_id_new: + warn(".SRCINFO unchanged. The package database will not be updated!") + # Read .SRCINFO from the HEAD commit. srcinfo_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode() srcinfo_raw = srcinfo_raw.split('\n') From 34153f41a99422374ec00ce284f068b733b49c2e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 09:26:32 +0200 Subject: [PATCH 0080/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 728 +++++++++++++++++++++++++++++++++-------- po/ast.po | 684 +++++++++++++++++++++++++++++++++------ po/ca.po | 687 ++++++++++++++++++++++++++++++++------- po/cs.po | 645 +++++++++++++++++++++++++++++++----- po/da.po | 637 +++++++++++++++++++++++++++++++----- po/de.po | 820 ++++++++++++++++++++++++++++++++++------------ po/el.po | 701 ++++++++++++++++++++++++++++++++------- po/es.po | 899 +++++++++++++++++++++++++++++++++++++-------------- po/es_419.po | 795 ++++++++++++++++++++++++++++++++++----------- po/fi.po | 704 ++++++++++++++++++++++++++++++++-------- po/fr.po | 831 ++++++++++++++++++++++++++++++++++------------- po/he.po | 635 +++++++++++++++++++++++++++++++----- po/hr.po | 638 +++++++++++++++++++++++++++++++----- po/hu.po | 788 +++++++++++++++++++++++++++++++++----------- po/it.po | 818 ++++++++++++++++++++++++++++++++++------------ po/ja.po | 771 +++++++++++++++++++++++++++++++++---------- po/nb.po | 694 ++++++++++++++++++++++++++++++++------- po/nl.po | 786 +++++++++++++++++++++++++++++++++----------- po/pl.po | 703 +++++++++++++++++++++++++++++++++------- po/pt_BR.po | 791 +++++++++++++++++++++++++++++++++----------- po/pt_PT.po | 716 ++++++++++++++++++++++++++++++++-------- po/ro.po | 713 ++++++++++++++++++++++++++++++++-------- po/ru.po | 792 +++++++++++++++++++++++++++++++++++---------- po/sk.po | 767 +++++++++++++++++++++++++++++++++---------- po/sr.po | 752 +++++++++++++++++++++++++++++++++--------- po/tr.po | 779 +++++++++++++++++++++++++++++++++----------- po/uk.po | 769 +++++++++++++++++++++++++++++++++---------- po/zh_CN.po | 660 +++++++++++++++++++++++++++++++------ po/zh_TW.po | 694 ++++++++++++++++++++++++++++++++------- 29 files changed, 17088 insertions(+), 4309 deletions(-) diff --git a/po/ar.po b/po/ar.po index 24c9de49..1c7d53cd 100644 --- a/po/ar.po +++ b/po/ar.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # safa1996alfulaij , 2015 # صفا الفليج , 2015 @@ -9,952 +9,1268 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-25 09:44+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 07:10+0000\n" "Last-Translator: صفا الفليج \n" -"Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" -"ar/)\n" -"Language: ar\n" +"Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " -"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"Language: ar\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +#: html/404.php msgid "Page Not Found" msgstr "لم يُعثر على الصّفحة" +#: html/404.php msgid "Sorry, the page you've requested does not exist." -msgstr "آسفون، الصّفحة الّتي طلبت غير موجودة." +msgstr "آسفون، الصّفحة التي طلبتها غير موجودة." +#: html/503.php msgid "Service Unavailable" msgstr "الخدمة غير متوفّرة" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "لا تفزع! عُطّل الموقع لأعمال الصّيانة. سنعود قريبًا." +#: html/account.php msgid "Account" msgstr "حساب" +#: html/account.php template/header.php msgid "Accounts" msgstr "الحسابات" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "ليس مسموحًا لك بالنّفاذ إلى هنا." +#: html/account.php msgid "Could not retrieve information for the specified user." -msgstr "تعذّر استرجاع معلومات المستخدم المحدّد." +msgstr "تعذّر جلب معلومات المستخدم المحدّد." +#: html/account.php msgid "You do not have permission to edit this account." -msgstr "لا صلاحيّة لديك لتحرير هذا الحساب." +msgstr "لا صلاحيّات لديك لتحرير هذا الحساب." +#: html/account.php msgid "Use this form to search existing accounts." -msgstr "استخدم هذه الاستمارة للبحث عن الحسابات الموجودة." +msgstr "استخدم هذه الاستمارة للبحث عن حسابات موجودة." +#: html/account.php msgid "You must log in to view user information." msgstr "عليك الولوج لعرض معلومات المستخدمين." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "أضف رأيًا" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "اسم المستخدم غير موجود." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "" +#: html/addvote.php msgid "Invalid type." msgstr "النّوع غير صالح." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "لا يمكن أن يكون الرّأي فارغًا." +#: html/addvote.php msgid "New proposal submitted." msgstr "قُدّم رأي جديد." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "قدّم رأيًا للتّصويت عليه." +#: html/addvote.php msgid "Applicant/TU" msgstr "" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(فارغ إن لم ينطبق)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "النّوع" +#: html/addvote.php msgid "Addition of a TU" msgstr "إضافة م‌م" +#: html/addvote.php msgid "Removal of a TU" msgstr "إزالة م‌م" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "الرّأي" +#: html/addvote.php msgid "Submit" msgstr "قدّم" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "أدر المصينين المشاركين" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "حرّر التّعليق" + +#: html/home.php template/header.php msgid "Home" msgstr "الرّئيسيّة" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ " -"الموثوقين (م‌م)%s لمعلومات أكثر." +msgstr "مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ الموثوقين (م‌م)%s لمعلومات أكثر." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"ملفّات PKGBUILD المساهم بها %sيجب%s أن تتبع %sمعايير التّحزيم في آرتش%s وإلا " -"ستُحذف!" +msgstr "ملفّات PKGBUILD التي تساهم بها %sيجب%s أن تتّبع %sمعايير التّحزيم في آرتش%s وإلا فستُحذف!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "تذكّر أن تصوّت لحزمك المفضّلة!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "قد تكون بعض الحزم متوفّرة كثنائيّات في مستودع المجتمع [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "إخلاء مسؤوليّة" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"الحزم غير المدعومة محتوًى قدّمه المستخدمون. أيّ استخدام للملفّات الموفّرة هي على " -"مسؤوليّتك الخاصّة." +#: html/home.php msgid "Learn more..." -msgstr "تعلّم أكثر..." +msgstr "اطّلع على المزيد..." +#: html/home.php msgid "Support" msgstr "الدّعم" +#: html/home.php msgid "Package Requests" msgstr "طلبات الحزم" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة " -"تفاصيل الحزمة:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة تفاصيل الحزمة:" +#: html/home.php msgid "Orphan Request" msgstr "طلب \"يتيمة\"" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة " -"كقديمة لوقت طويل." +msgstr "اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة كقديمة لوقت طويل." +#: html/home.php msgid "Deletion Request" msgstr "طلب الحذف" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت " -"الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن " -"طلب \"يتيمة\" إن تطلّب الأمر." +msgstr "اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن طلب \"يتيمة\" إن تطلّب الأمر." +#: html/home.php msgid "Merge Request" msgstr "طلب الدّمج" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"اطل دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو " -"استبدال بحزمة تقسيميّة." +msgstr "اطلب دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو استبدال بحزمة تقسيميّة." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. " -"لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." +msgstr "إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." +#: html/home.php msgid "Submitting Packages" msgstr "تقديم الحزم" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع " -"قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." +msgstr "غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "بصمات SSH الآتية مستخدمة في م‌م‌آ:" +#: html/home.php msgid "Discussion" msgstr "النّقاش" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين " -"تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِب م‌م‌آ، استخدم " -"قائمة %saur-dev%s البريديّة." +msgstr "النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِب م‌م‌آ، استخدم قائمة %saur-dev%s البريديّة." +#: html/home.php msgid "Bug Reporting" msgstr "الإبلاغ عن العلل" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"إن وجدت علّة في واجهة وِب م‌م‌آ، فضلًا املأ تقريرًا بها في %sمتعقّب العلل%s. استخدم " -"المتعقّب للإبلاغ عن العلل في م‌م‌آ %sفقط%s. للإبلاغ عن علل الحزم راسل مديرها أو " -"اترك تعليقًا في صفحة الحزمة المناسبة." +#: html/home.php msgid "Package Search" msgstr "ابحث عن حزمة" +#: html/index.php msgid "Adopt" msgstr "تبنّ" +#: html/index.php msgid "Vote" msgstr "صوّت" +#: html/index.php msgid "UnVote" msgstr "أزل التّصويت" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "الإخطار" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "أزل الإخطار" -msgid "Flag" -msgstr "علّم" - +#: html/index.php msgid "UnFlag" msgstr "أزل التّعليم" +#: html/login.php template/header.php msgid "Login" msgstr "لِج" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "والج كَـ: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "اخرج" +#: html/login.php msgid "Enter login credentials" msgstr "أدخل بيانات الولوج" -msgid "Username" -msgstr "اسم المستخدم" +#: html/login.php +msgid "User name or email address" +msgstr "اسم المستخدم أو عنوان البريد الإلكترونيّ" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "كلمة المرور" +#: html/login.php msgid "Remember me" msgstr "تذكّرني" +#: html/login.php msgid "Forgot Password" msgstr "نسيت كلمة المرور" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "ولوج HTTP معطّل. فضلًا %sبدّل إلى HTTPs%s إن أردت الولوج." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "معايير البحث" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "الحزم" +#: html/packages.php msgid "Error trying to retrieve package details." -msgstr "خطأ في محاولة استرجاع تفاصيل الحزمة." +msgstr "خطأ في محاولة جلب تفاصيل الحزمة." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "أحد الحقول المطلوبة ناقصة." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "حقلا كلمة المرور لا يتطابقان." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "يجب أن تكون كلمة مرورك بطول %s محارف على الأقل." +#: html/passreset.php msgid "Invalid e-mail." msgstr "بريد إلكترونيّ غير صالح." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"قُدّم طلب تصفير كلمة مرور الحساب %s المرتبط بعنوان بريدك الإلكتروني. إن رغبت " -"بتصغير كلمة مرورك اتبع الوصلة أدناه، وإلّا تجاهل هذه الرّسالة ولن يحدث شيء." - +#: html/passreset.php msgid "Password Reset" msgstr "صفّر كلمة المرور" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "افحص بريدك الإلكترونيّ لوصلة التّأكيد." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "صُفّرت كلمة مرورك بنجاح." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "أكّد عنوان بريدك الإلكترونيّ:" +#: html/passreset.php msgid "Enter your new password:" msgstr "أدخل كلمة مرورك الجديدة:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "أكّد كلمة مرورك الجديدة:" +#: html/passreset.php msgid "Continue" msgstr "تابع" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى " -"قائمة %saur-general%s البريديّة." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى قائمة %saur-general%s البريديّة." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "أدخل عنوان بريدك الإلكترونيّ:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "لم يُتنازل عن الحزم المحدّدة، افحص مربع تأشير التّأكيد." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "تعذّر العثور على الحزمة لدمج التّصويتات والتّعليقات معها." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "لا يمكن الدّمج بلا أساس الحزمة نفسه." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "لم تُحذف الحزم المحدّدة، افحص مربع تأشير التّأكيد." +#: html/pkgdel.php msgid "Package Deletion" msgstr "احذف حزمة" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "احذف الحزمة: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "استخدم هذه الاستمارة لحذف أساس الحزمة %s%s%s والحزم الآتية من م‌م‌آ:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "حذف الحزم نهائيّ." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "حدّد مربع تأشير لتأكيد الإجراء." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "أكّد حذف الحزمة" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "احذف" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين حذف الحزم." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "تنازل عن حزمة" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "تنازل عن الحزمة: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة ونقل ملكيّتها إلى %s%s%s." +msgstr "بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة ونقل ملكيّتها إلى %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "أكّد التّنازل عن الحزمة" +#: html/pkgdisown.php msgid "Disown" msgstr "تنازل" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين التّنازل عن الحزم." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "علّم الحزمة كقديمة" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "من فضلك %sلا%s تستخدم هذه الاستمارة للتّبليع عن العلل. علّق على الحزم بدل ذلك." + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "التّعليقات" + +#: html/pkgflag.php +msgid "Flag" +msgstr "علّم" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "ادمج حزمة" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "ادمج الحزمة: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "استخدم هذه الاستمارة لدمج أساس الحزمة %s%s%s مع حزمة أخرى." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "ستُحذف الحزم الآتية:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "بمجرّد دمج الحزمة لا يمكن عكس الإجراء." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "أدخل اسم الحزمة التي ترغب بدمج الحزمة معها." +#: html/pkgmerge.php msgid "Merge into:" msgstr "ادمج مع:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "أكّد دمج الحزم" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "دمج" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين دمج الحزم." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "افتح طلبًا" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "أغلق الطّلب" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "الأولى" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "السّابقة" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "التّالية" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "الأخيرة" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "الطّلبات" +#: html/register.php template/header.php msgid "Register" msgstr "سجّل" +#: html/register.php msgid "Use this form to create an account." msgstr "استخدم هذه الاستمارة لإنشاء حساب." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "مستخدم موثوق" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "تعذّر استرجاع تفاصيل الرّأي." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "أُغلق التّصويت على هذا الرّأي." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "فقط المستخدمين الموثوقين مسموح لهم بالتّصويت." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "لا يمكنك التّصويت على رأي عنك." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "لقد صوّتّ على هذا الرّأي بالفعل." +#: html/tu.php msgid "Vote ID not valid." msgstr "معرّف التّصويت غير صالح." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "التّصويتات الحاليّة" +#: html/tu.php msgid "Past Votes" msgstr "التّصويتات الماضية" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "المصوّتون" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " -"المتكرّرة. آسفون لإزاعجك" +msgstr "تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "معرّف المستخدم ناقص" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "اسم المستخدم غير صالح." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "يجب أن يكون بطول بين %s و %s محرفًا" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "يجب أن يبدأ وينتهي بحرف أو رقم." +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "يمكنه احتواء نقطة واحدة، أو شرطة سفليّة واحدة أو شرطة واحدة." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "عنوان البريد الإلكترونيّ غير صالح." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "بصمة مفتاح PGP غير صالحة." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "مفتاح SSH العموميّ غير صالح." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "لا يمكن زيادة صلاحيّات الحساب." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "اللغة غير مدعومة حاليًّا." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "اسم المستخدم %s%s%s مستخدم بالفعل." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "العنوان %s%s%s مستخدم بالفعل." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "مفتاح SSH العموميّ %s%s%s مستخدم بالفعل." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "فشلت محاولة إنشاء الحساب %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "أُنشئ الحساب %s%s%s بنجاح." -msgid "Click on the Login link above to use your account." -msgstr "انقر وصلة الولوج أعلاه لاستخدام حسابك." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"مرحبًا بك في %s! لتعيين كلمة مرور أوليّة لحسابك الجديد، فضلًأ انقر الوصلة " -"أدناه. إن لم تعمل الوصلة جرّب النّسخ واللصق في متصفّحك." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "مفتاح تصفير كلمة المرور أُرسل إلى عنوان بريدك الإلكترونيّ." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "انقر وصلة الولوج أعلاه لاستخدام حسابك." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "لم تتمّ أيّ تغييرات على الحساب %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "عُدّل الحساب %s%s%s بنجاح." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " -"المتكرّرة. آسفون لإزاعجك." +msgstr "استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "عُلّق الحساب" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد " -"الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من " -"صفحة %sصفّر كلمة المرور%s." +msgstr "لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من صفحة %sصفّر كلمة المرور%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "اسم مستخدم أو كلمة مرور سيئّة." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "حدث خطأ أثناء توليد جلسة مستخدم." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "البريد الإلكترونيّ وتجميعة مفاتيح التّصفير غير صالحة." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "بلا" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "اعرض معلومات حساب %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "التّعليق غير موجود." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "أُضيف التّعليق" + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "خطأ في استرجاع تفاصيل الحزمة." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "تعذّر العثور على تفاصيل الحزمة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "عليك الولوج قبل تعليم الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "لم تحدّد أيّ حزم لتعليمها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "عُلّمت الحزم المحدّدة كقديمة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "عليك الولوج قبل إزالة تعليم الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "لم تحدّد أيّ حزم لإزالة تعليمها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "أزثيل تعليم الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "لا صلاحيّة لديك لحذف الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "لم تحدّد أيّ حزم لحذفها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "حُذفت الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "عليك الولوج قبل تبنّي الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "عليك الولوج قبل التّنازل عن الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "لم تحدّد أيّ حزم لتبنّيها." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "لم تحدّد أيّ حزم للتّنازل عنها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "تُبنّيت الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "تُنوزل عن الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "عليك الولوج قبل التّصويت للحزم." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "عليك الولوج قبل إزالة التصّويت للحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "لم تحدّد أيّ حزم للتّصويت لها." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "أُزيلت تصويتاتك من الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "أُدليت تصويتاتك على الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "تعذّرت الإضافة إلى قائمة الإخطارات." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "أُضفت إلى قائمة إخطار التّعليقات لِـ %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "أُزلت من قائمة إخطار التّعليقات لِـ %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "عليك الولوج قبل تحرير معلومات الحزم." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "معرّف التّعليق ناقص." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "حُذف التّعليق." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "ليس مسموحًا لك بحذف هذا التّعليق." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "ليس مسموحًا لك بتحرير كلمات أساس الحزمة المفتاحيّة." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "حُدّثت كلمات أساس الحزمة المفتاحيّة." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "ليس مسموحًا لك بإدارة مصيني أساس الحزمة هذا المشاركين." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "اسم مستخدم غير صالح: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "حُدّث مصيني أساس الحزمة المشاركين." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "اعرض تفاصيل حزمة" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "تطلب %s" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "عليك الولوج لفتح طلبات حزم." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "اسم غير صالح: فقط الأحرف بالحالة الصغيرة مسموح بها." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "يجب ألّا يكون حقل التّعليق فارغًا." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "نوع الطّلب غير صالح." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "أُضيف الطّلب بنجاح." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "سبب غير صالح." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين إغلاق الطّلبات." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "ُأُغلق الطّلب بنجاح." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "يمكنك استخدام هذه الاستمارة لحذف حساب م‌م‌آ هذا %s نهائيًّا." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sتحذير%s: هذا إجراء لا عودة فيه." +#: template/account_delete.php msgid "Confirm deletion" msgstr "أكّد الحذف" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "اسم المستخدم" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "نوع الحساب" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "مستخدم" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "مطوّر" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "مستخدم موثوق ومطوّر" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "البريد الإلكترونيّ" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "الاسم الحقيقيّ" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "اسم آي‌آر‌سي المستعار" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "بصمة مفتاح PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "الحالة" +#: template/account_details.php msgid "Inactive since" msgstr "غير نشط منذ" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "نشط" +#: template/account_details.php msgid "Last Login" msgstr "آخر ولوج" +#: template/account_details.php msgid "Never" msgstr "أبدًا" +#: template/account_details.php msgid "View this user's packages" msgstr "اعرض ملفّ هذا المستخدم الشخصيّ" +#: template/account_details.php msgid "Edit this user's account" msgstr "حرّر حساب هذا المستخدم" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "انقر %sهنا%s إن أردت حذف هذا الحساب نهائيًّا." +#: template/account_edit_form.php msgid "required" msgstr "مطلوب" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "مستخدم عاديّ" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "مستخدم موثوق" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "حساب معلّق" +#: template/account_edit_form.php msgid "Inactive" msgstr "غير نشط" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "أخفِ عنوان البريد الإلكترونيّ" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "أعد كتابة كلمة المرور" +#: template/account_edit_form.php msgid "Language" msgstr "اللغة" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "المعلومات الآتية مطلوبة فقط إن أردت تقديم حزم إلى مستودع مستخدمي آرتش." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "مفتاح SSH العموميّ" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "حدّث" +#: template/account_edit_form.php msgid "Create" msgstr "أنشئ" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "صفّر" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "لا نتائج طابقت معايير بحثك." +#: template/account_search_results.php msgid "Edit Account" msgstr "حرّر الحساب" +#: template/account_search_results.php msgid "Suspended" msgstr "معلّق" +#: template/account_search_results.php msgid "Edit" msgstr "حرّر" +#: template/account_search_results.php msgid "Less" msgstr "أقلّ" +#: template/account_search_results.php msgid "More" msgstr "أكثر" +#: template/account_search_results.php msgid "No more results to display." msgstr "لا نتائج أخرى لعرضها." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "أدر المصينين المشاركين: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "استخدم هذه الاستمارة لإضافة مصينين مشاركين لِـ %s%s%s (اسم في كلّ سطر):" +#: template/comaintainers_form.php msgid "Users" msgstr "المستخدمون" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "احفظ" +#: template/header.php msgid "My Packages" msgstr "حزمي" +#: template/header.php msgid " My Account" msgstr "حسابي" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "إجراءات الحزمة" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "اعرض PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "اعرض التّغييرات" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "نزّل لقطة شاشة" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "ابحث في الويكي" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "معلّمة كقديمة" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "علّم الحزمة كقديمة" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "أزل تعليم الحزمة" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "أزل التّصويت" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "صوّت لهذه الحزمة" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "عطّل الإخطارات" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "أخطرني بالتّعليقات الجديدة" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "أدر المصينين المشاركين" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -965,167 +1281,232 @@ msgstr[3] "%d طلبات منتظرة" msgstr[4] "%d طلبًا منتظرًا" msgstr[5] "%d طلب منتظر" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "احذف الحزمة" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "ادمج الحزم" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "تبنّ الحزمة" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "مجهول" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "تفاصيل أساس الحزمة" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "عنوان غِت للاستنساخ" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "للقراءة فقط" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "الكلمات المفتاحيّة" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "المقدّم" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "المصين" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "آخر محزّم" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "التّصويتات" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "الشّعبيّة" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "أول تقديم" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "آخر تحديث" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "أضف تعليقًا" -msgid "Comment has been added." -msgstr "أُضيف التّعليق" - +#: template/pkg_comments.php msgid "View all comments" msgstr "اعرض كلّ التّعليقات" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "آخر التّعليقات" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "علّق %s على %s" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "تعليق مجهول على %s" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "احذف التّعليق" -#, php-format -msgid "Comment by %s" -msgstr "تعليق لِـ %s" - -msgid "Anonymous comment" -msgstr "تعليق مجهول" - -msgid "deleted" -msgstr "محذوف" - +#: template/pkg_comments.php msgid "All comments" msgstr "كلّ التّعليقات" +#: template/pkg_details.php msgid "Package Details" msgstr "تفاصيل الحزمة" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "أساس الحزمة" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "الوصف" +#: template/pkg_details.php msgid "Upstream URL" msgstr "عنوان المنبع" +#: template/pkg_details.php msgid "Visit the website for" msgstr "زُر موقع وِب" +#: template/pkg_details.php msgid "Licenses" msgstr "الرّخص" +#: template/pkg_details.php msgid "Groups" msgstr "المجموعات" +#: template/pkg_details.php msgid "Conflicts" msgstr "تتعارض مع" +#: template/pkg_details.php msgid "Provides" msgstr "توفّر" +#: template/pkg_details.php msgid "Replaces" msgstr "تستبدل" +#: template/pkg_details.php msgid "Dependencies" msgstr "الاعتماديّات" +#: template/pkg_details.php msgid "Required by" msgstr "تطلبها" +#: template/pkg_details.php msgid "Sources" msgstr "المصادر" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "أغلق الطّلب: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "استخدم هذه الاستمارة لإغلاق طلب أساس الحزمة %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "ملاحظة" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." +msgstr "يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "السّبب" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "مقبول" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "مرفوض" -msgid "Comments" -msgstr "التّعليقات" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "افتح طلبًا: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"استخدم هذه الاستمارة لفتح طلب لأساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +msgstr "استخدم هذه الاستمارة لفتح طلب لأساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +#: template/pkgreq_form.php msgid "Request type" msgstr "نوع الطّلب" +#: template/pkgreq_form.php msgid "Deletion" msgstr "حذف" +#: template/pkgreq_form.php msgid "Orphan" msgstr "يتيمة" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "ادمج مع" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1136,23 +1517,29 @@ msgstr[3] "عُثر على %d طلبات حزم." msgstr[4] "عُثر على %d طلب حزمة." msgstr[5] "عُثر على %d طلب حزمة." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "الصّفحة %d من %d." +#: template/pkgreq_results.php msgid "Package" msgstr "الحزم" +#: template/pkgreq_results.php msgid "Filed by" msgstr "فتحه:" +#: template/pkgreq_results.php msgid "Date" msgstr "التّاريخ" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1163,90 +1550,116 @@ msgstr[3] "بقي حوالي %d ساعات" msgstr[4] "بقي حوالي %d ساعةً" msgstr[5] "بقي حوالي %d ساعة" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "بقيت أقلّ من ساعة" +#: template/pkgreq_results.php msgid "Accept" msgstr "اقبل" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "أغلق" +#: template/pkgreq_results.php msgid "Closed" msgstr "مغلق" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "الاسم، الوصف" +#: template/pkg_search_form.php msgid "Name Only" msgstr "الاسم فقط" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "الاسم بالضّبط" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "أساس الحزمة بالضّبط" +#: template/pkg_search_form.php msgid "All" msgstr "الكلّ" +#: template/pkg_search_form.php msgid "Flagged" msgstr "المعلّمة" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "غير المعلّمة" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "الاسم" -msgid "Popularity" -msgstr "الشّعبيّة" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "مصوّت عليها" -msgid "Age" -msgstr "العمر" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "تصاعديًّا" +#: template/pkg_search_form.php msgid "Descending" msgstr "تنازليًّا" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "أدخل معايير البحث" +#: template/pkg_search_form.php msgid "Search by" msgstr "ابحث حسب" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "القديمة" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "افرز حسب" +#: template/pkg_search_form.php msgid "Sort order" msgstr "ترتيب الفرز" +#: template/pkg_search_form.php msgid "Per page" msgstr "لكلّ صفحة" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "انطلق" +#: template/pkg_search_form.php msgid "Orphans" msgstr "اليتيمة" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "خطأ في استرجاع قائمة الحزم." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "لا حزم طابقت معايير بحثك." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1257,119 +1670,154 @@ msgstr[3] "عُثر على %d حزم." msgstr[4] "عُثر على %d حزمةً." msgstr[5] "عُثر على %d حزمة." +#: template/pkg_search_results.php msgid "Version" msgstr "الإصدارة" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "نعم" +#: template/pkg_search_results.php msgid "orphan" msgstr "يتيمة" +#: template/pkg_search_results.php msgid "Actions" msgstr "الإجراءات" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "علّم كقديمة" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "أزل التّعليم كقديمة" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "تبنّ الحزم" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "تنازل عن الحزم" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "احذف الحزم" +#: template/pkg_search_results.php msgid "Confirm" msgstr "أكّد" +#: template/search_accounts_form.php msgid "Any type" msgstr "أيّ نوع" +#: template/search_accounts_form.php msgid "Search" msgstr "ابحث" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "الإحصائيّات" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "الحزم اليتيمة" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "الحزم المضافة في السّبعة أيّام الماضية" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "الحزم المحدّثة في السّبعة أيّام الماضية" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "الحزم المضافة في السّنة الماضية" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "الحزم التي لم تحدّث مطلقًا" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "المستخدمون المسجّلون" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "المستخدمون الموثوقون" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "التّحديثات الأخيرة" +#: template/stats/user_table.php msgid "My Statistics" msgstr "إحصائيّاتي" -msgid "Packages in unsupported" -msgstr "الحزم في \"غير مدعوم\"" - +#: template/tu_details.php msgid "Proposal Details" msgstr "تفاصيل الرّأي" +#: template/tu_details.php msgid "This vote is still running." msgstr "ما زال هذا التّصويت قائمًا." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "قدّمه (في %s) ‏%s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "النّهاية" +#: template/tu_details.php msgid "Result" msgstr "النّتيجة" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "لا" +#: template/tu_details.php msgid "Abstain" msgstr "الامتناع" +#: template/tu_details.php msgid "Total" msgstr "المجموع" +#: template/tu_details.php msgid "Participation" msgstr "المشاركة" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "آخر التّصويتات لِـ م‌م" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "آخر تصويت" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "لم يُعثر على أيّ نتيجة." +#: template/tu_list.php msgid "Start" msgstr "البداية" +#: template/tu_list.php msgid "Back" msgstr "السّابق" diff --git a/po/ast.po b/po/ast.po index bf674e74..85ed7864 100644 --- a/po/ast.po +++ b/po/ast.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # enolp , 2014-2015 # Ḷḷumex03 , 2014 @@ -10,587 +10,770 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-07-06 14:08+0000\n" -"Last-Translator: enolp \n" -"Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" -"ast/)\n" -"Language: ast\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: ast\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Nun s'alcontró la páxina" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Perdón, la páxina que pidisti nun esiste." +#: html/503.php msgid "Service Unavailable" msgstr "Serviciu non disponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "Cuenta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentes" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nun tienes permisu p'acceder a esta area." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nun pudo recibise la información pal usuariu especificáu." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nun tienes permisu pa editar esta cuenta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa esti formulariu pa guetar cuentes esistentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Tienes d'aniciar sesión pa ver la información del usuariu." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Amestar propuesta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Token non válidu pa la aición del usuariu" +#: html/addvote.php msgid "Username does not exist." msgstr "El nome d'usuariu nun esiste." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s yá tien la propuesta que cuerre pa ellos." +#: html/addvote.php msgid "Invalid type." msgstr "Triba non válida." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta nun pue tar balera" +#: html/addvote.php msgid "New proposal submitted." msgstr "" +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "" +#: html/addvote.php msgid "Applicant/TU" msgstr "Aplicante/Usuariu d'Enfotu." +#: html/addvote.php msgid "(empty if not applicable)" -msgstr "" +msgstr "(baletu si nun s'aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Triba" +#: html/addvote.php msgid "Addition of a TU" msgstr "Añedir un Usuariu d'Enfotu" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" +#: html/addvote.php msgid "Submit" msgstr "" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Aniciu" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"¡Bienllegáu al AUR! Llei la %sGuía d'usuariu del AUR%s y la %sGuía d'usuariu " -"TU del AUR%s pa más información." +msgstr "¡Bienllegáu al AUR! Llei la %sGuía d'usuariu del AUR%s y la %sGuía d'usuariu TU del AUR%s pa más información." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Los PKGBUILD contribuyíos %stienen%s de ser compatibles col %sEstándar de " -"empaquetado de Arch%s d'otra forma van ser esaniciaos." +msgstr "Los PKGBUILD contribuyíos %stienen%s de ser compatibles col %sEstándar de empaquetado de Arch%s d'otra forma van ser esaniciaos." +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerda votar los tos paquetes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Dellos paquetes puen apurrise como binarios en [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Los paquetes ensin sofitu son producíos polos usuarios. Cualesquier usu de " -"los ficheros apurríos ta sol to propiu riesgu." +#: html/home.php msgid "Learn more..." msgstr "Llei más..." +#: html/home.php msgid "Support" msgstr "Sofitu" +#: html/home.php msgid "Package Requests" msgstr "Solicitúes de paquetes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "Solicitú güérfana" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "Solicitú de desaniciu" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "Solicitú de desanciu" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" -msgstr "" +msgstr "Unviu de paquetes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" +msgstr "Agora úsase GIT sobro SSH pa unviar paquetes a AUR. Mira la estaya %sUnviu de paquetes%s de la páxina ArchWiki del AUR pa más detalles." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "Les buelgues SSH de darréu úsense pal AUR:" +#: html/home.php msgid "Discussion" msgstr "Discutiniu" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Informe de fallos" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Gueta de paquete" +#: html/index.php msgid "Adopt" msgstr "" +#: html/index.php msgid "Vote" msgstr "" +#: html/index.php msgid "UnVote" msgstr "" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "" -msgid "Flag" -msgstr "" - +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "Aniciar sesión" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "" +#: html/login.php template/header.php msgid "Logout" msgstr "Zarrar sesión" +#: html/login.php msgid "Enter login credentials" msgstr "Introduz les tos credenciales d'aniuciu sesión" -msgid "Username" -msgstr "Nome d'usuariu" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" +#: html/login.php msgid "Remember me" msgstr "Recordáime" +#: html/login.php msgid "Forgot Password" msgstr "Escaecí la contraseña" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteriu de gueta" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campu riquíu." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." -msgstr "" +msgstr "Nun concasen los campos de contraseñes" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La to contraseña tien de tener polo menos %s carauteres." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Corréu electrónicu non válidu" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Reaniciu de contraseña" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "" +msgstr "Comprueba'l to corréu pal enllaz de confirmación." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La to contraseña reanicióse con ésitu." +#: html/passreset.php msgid "Confirm your e-mail address:" -msgstr "" +msgstr "Confirma'l to corréu:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Introduz la to contraseña nueva:" +#: html/passreset.php msgid "Confirm your new password:" -msgstr "" +msgstr "Confirma la to contraseña nueva:" +#: html/passreset.php msgid "Continue" -msgstr "" +msgstr "Siguir" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si escaecisti la dirección de corréu electrónicu utilizasti pa rexistrar, " -"complacer unviar un mensaxe a la llista de orréu %saur-xeneral%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si escaecisti la dirección de corréu electrónicu utilizasti pa rexistrar, complacer unviar un mensaxe a la llista de orréu %saur-xeneral%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduz la to direción de corréu:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "Desaniciu de paquete" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Desaniciar paquete: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Usa esti formulariu pa desaniciar el paquete base %s%s%s y los paquetes " -"siguientes d'AUR:" +msgstr "Usa esti formulariu pa desaniciar el paquete base %s%s%s y los paquetes siguientes d'AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El desaniciu d'un paquete ye permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Desaniciar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Comentarios" + +#: html/pkgflag.php +msgid "Flag" +msgstr "" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Desaniciaránse los paquetes de darréu:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduz el nome del paquete al que deseyes amestar" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Solicitú de ficheru" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zarar solicitú" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Solicitúes" +#: html/register.php template/header.php msgid "Register" msgstr "Rexistrase" +#: html/register.php msgid "Use this form to create an account." msgstr "Usa esti formulariu pa crear una cuenta." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "" +#: html/tu.php msgid "Vote ID not valid." msgstr "Nun ye válida la ID del votu." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" +#: html/tu.php msgid "Past Votes" msgstr "Votos pasaos" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta la ID d'usuariu" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nome d'usuariu nun ye válidu" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Tien de tar ente %s y %s carauteres de llargor" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La direición de corréu nun ye válida." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La buelga de la clave PGP nun ye válida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave SSH pública nun ye válida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nun puen aumentase los permisos de la cuenta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "La llingua nun ta anguaño sofitada." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nome d'usuariu, %s%s%s, yá ta n'usu." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La direición, %s%s%s, yá ta n'usu." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La llave pública SSH, %s%s%s, ye yá n'usu." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Fallu intentando crear la cuenta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, creóse con ésitu." -msgid "Click on the Login link above to use your account." -msgstr "" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, modificóse con ésitu." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -598,733 +781,1028 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nome d'usuariu o contraseña incorreutos" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Asocedió un fallu intentando xenerar una sesión d'usuariu." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Amestóse'l comentariu." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nun pudieron alcontrase los detalles del paquete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nun esbillesti dengún ficheru pa desaniciar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Desaniciáronse los paquetes esbillaos." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Falta la ID del comentariu." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "El comentariu amestóse." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nun tienes permisu pa desaniciar esti comentariu." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Nome d'usuariu non válidu: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles de paquetes pa" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campu del comentariu nun tien de tar baleru." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Triba de solicitú non válida." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Amestada con ésitu la solicitú." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón non válida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Solicitú zarrada con ésitu." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Pues usar esti formulariu pa desaniciar la cuenta del AUR %s dafechu." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sAVISU%s: Esta aición nun pue desfacese." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar desaniciu" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nome d'usuariu" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Triba de cuenta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuariu" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desendolcador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Direición de corréu" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alcuñu nel IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Buelga de clave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estáu" +#: template/account_details.php msgid "Inactive since" msgstr "Inactivu dende" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activu" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Enxamás" +#: template/account_details.php msgid "View this user's packages" msgstr "" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Primi %sequí%s si quies desaniciar esta cuenta dafechu." +#: template/account_edit_form.php msgid "required" msgstr "riquíu" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuariu normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuariu d'Enfotu" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivu" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Teclexa de nueves la contraseña" +#: template/account_edit_form.php msgid "Language" msgstr "Llingua" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La información de darréu namái se rique si quies xubir paquetes al AUR." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La información de darréu namái se rique si quies xubir paquetes al AUR." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave SSH pública" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Anovar" +#: template/account_edit_form.php msgid "Create" msgstr "Crear" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reafitar" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "" +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar cuenta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendíu" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Más" +#: template/account_search_results.php msgid "No more results to display." msgstr "" +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Alministra comantenedores: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuarios" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Guardar" +#: template/header.php msgid "My Packages" msgstr "Los mios paquetes" +#: template/header.php msgid " My Account" msgstr "La mio cuenta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Aiciones de paquete" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver camudancies" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Baxar instantánea" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Guetar na wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marcar como non actualizáu" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcáu como non actualizáu" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Quitar marca de non actualizáu" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Quitar votu" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar pol paquete" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Alministra comantenedores" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "Desconocíu" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL pa clonar con Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Pallabres clave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Caltenedor" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Amestar comentariu" -msgid "Comment has been added." -msgstr "Amestóse'l comentariu." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver tolos comentarios" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Comentarios caberos" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Desaniciar comentariu" -#, php-format -msgid "Comment by %s" -msgstr "Comentáu por %s" - -msgid "Anonymous comment" -msgstr "Comentariu anónimu" - -msgid "deleted" -msgstr "desaniciáu" - +#: template/pkg_comments.php msgid "All comments" msgstr "Tolos comentarios" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "Llicencies" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "Apurre" +#: template/pkg_details.php msgid "Replaces" msgstr "Troca" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencies" +#: template/pkg_details.php msgid "Required by" msgstr "Riquíu por" +#: template/pkg_details.php msgid "Sources" msgstr "Fontes" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Zarrar solicitú: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa esti formulariu pa zarrar la solicitú pal paquete base %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"El campu de comentarios pue dexase baleru, Por embargu, encamiéntase amestar " -"un comentariu al refugar una solicitú." +msgstr "El campu de comentarios pue dexase baleru, Por embargu, encamiéntase amestar un comentariu al refugar una solicitú." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceutáu" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Refugáu" -msgid "Comments" -msgstr "Comentarios" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "Triba de solicitú" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Desaniciu" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Güérfanu" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Páxina %d de %d" +#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Falten ~%d díes" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Falta ~%d hora" msgstr[1] "Falten ~%d hores" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "Falta menos d'una hora" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceutar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloquiáu" +#: template/pkgreq_results.php msgid "Close" msgstr "Zarrar" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zarráu" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descripción" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Namái nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exautu" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exautu" +#: template/pkg_search_form.php msgid "All" msgstr "Too" +#: template/pkg_search_form.php msgid "Flagged" msgstr "" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "" -msgid "Age" -msgstr "Edá" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Guetar per" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Ensin anovar" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar per" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Mou d'ordenación" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per páxina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Dir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Güérfanos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nun hai paquetes que concasen col criteriu de gueta." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Alcontróse %d paquete." msgstr[1] "Alcontráronse %d paquetes" +#: template/pkg_search_results.php msgid "Version" msgstr "Versión" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "güérfanu" +#: template/pkg_search_results.php msgid "Actions" msgstr "Aiciones" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "" +#: template/pkg_search_results.php msgid "Confirm" msgstr "" +#: template/search_accounts_form.php msgid "Any type" msgstr "" +#: template/search_accounts_form.php msgid "Search" msgstr "" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadístiques" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes güérfanos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes amestaos nos pasaos 7 díes" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes anovaos nos pasaos 7 díes" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes anovaos nel añu caberu" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes qu'enxamás s'anovaron" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios rexistraos." +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios d'enfotu." +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Anovamientos recientes" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Les mios estadístiques" -msgid "Packages in unsupported" -msgstr "Paquetes ensin sofitu" - +#: template/tu_details.php msgid "Proposal Details" msgstr "" +#: template/tu_details.php msgid "This vote is still running." msgstr "" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Resultáu" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Non" +#: template/tu_details.php msgid "Abstain" msgstr "Astención" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nun s'alcontró dengún resultáu." +#: template/tu_list.php msgid "Start" msgstr "" +#: template/tu_list.php msgid "Back" msgstr "" diff --git a/po/ca.po b/po/ca.po index 69fb0c4e..5f7349c6 100644 --- a/po/ca.po +++ b/po/ca.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Adolfo Jayme Barrientos, 2014 # Hector Mtz-Seara , 2011,2013 @@ -10,1336 +10,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" -"ca/)\n" -"Language: ca\n" +"Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "No s’ha trobat la pàgina" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Ho sentim, la pàgina que ha sol·licitat no existeix." +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "Compte" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No esteu autoritzat per a accedir a aquesta àrea." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No s'ha pogut obtenir la informació de l'usuari especificat." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "No teniu permís per a editar aquest compte." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilitzeu aquest formulari per a cercar comptes existents." +#: html/account.php msgid "You must log in to view user information." msgstr "Heu d'identificar-vos per a veure la inforació de l'usuari." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Afegeix proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Element invàlid per acció de l'usuari." +#: html/addvote.php msgid "Username does not exist." msgstr "El nom d’usuari no existeix." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ja te una proposta corrent per ells." +#: html/addvote.php msgid "Invalid type." msgstr "El tipus no és vàlid." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La proposta no pot estar buit." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta presentada." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Presentar una proposta per votar." +#: html/addvote.php msgid "Applicant/TU" msgstr "Sol.licitant / TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(Buit si no s'aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipus" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Envia" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Inici" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Benvingut a l'AUR! Si us plau, llegiu les %sdirectrius d'usuari d'AUR%s i " -"les %sdirectrius de TU (usuari de confiança) d'AUR%s per més informació." +msgstr "Benvingut a l'AUR! Si us plau, llegiu les %sdirectrius d'usuari d'AUR%s i les %sdirectrius de TU (usuari de confiança) d'AUR%s per més informació." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"És %sobligatori%s que els PKGBUILDs amb que es contribueix s'ajustin als " -"%sEstandars d'empaquetament d'Arc%s, en cas contrari seran esborrats!" +msgstr "És %sobligatori%s que els PKGBUILDs amb que es contribueix s'ajustin als %sEstandars d'empaquetament d'Arc%s, en cas contrari seran esborrats!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Recordeu votar els vostres paquets preferits!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Alguns paquets poden ser oferts com binaris a [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "Avís legal" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Els paquets sense suport són creats per diferents usuaris. Qualsevol ús " -"d'aquests és sempre sota el seu propi risc." +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Discussió" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Comunicar errada" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Cercar Paquets" +#: html/index.php msgid "Adopt" msgstr "" +#: html/index.php msgid "Vote" msgstr "Vota" +#: html/index.php msgid "UnVote" msgstr "Lleva el vot" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notifica" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Lleva notificació" -msgid "Flag" -msgstr "Marcar" - +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Entra" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Identificat com: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Surt" +#: html/login.php msgid "Enter login credentials" msgstr "Introduïu les credencials d'inici de sessió" -msgid "Username" -msgstr "Nom d'usuari" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contrasenya" +#: html/login.php msgid "Remember me" msgstr "Recorda'm" +#: html/login.php msgid "Forgot Password" msgstr "Has oblidat la teva contrasenya" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"L'inici de sessió HTTP està deshabilitat. Si us plau %s canvia a HTTPs %s si " -"voleu iniciar la sessió." +msgstr "L'inici de sessió HTTP està deshabilitat. Si us plau %s canvia a HTTPs %s si voleu iniciar la sessió." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteri de cerca" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquets" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "S'ha produït un error en obtenir els detalls del paquet." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Manca un camp requerit." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Els camps de contrasenya no coincideixen." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La seva contrasenya ha de tenir almenys %s caràcters." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Direcció de correu electrònic no vàlida." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Restablir contrasenya" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Revisi el seu correu electrònic per a l'enllaç de confirmació." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La seva contrasenya s'ha restablert correctament." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Tots" +#: html/passreset.php msgid "Enter your new password:" msgstr "Marcat" +#: html/passreset.php msgid "Confirm your new password:" msgstr "No marcat" +#: html/passreset.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si ha oblidat l'adreça de correu electrònic utilitzada al registrar-se, si " -"us plau envïi un missatge a la llista de correu %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si ha oblidat l'adreça de correu electrònic utilitzada al registrar-se, si us plau envïi un missatge a la llista de correu %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduiu la vostra adreça de correu." +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "No es pot trobar el paquet on combinar vots i comentaris." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Els paquets seleccionats no s'han esborrat, marqui la casella de confirmació." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Els paquets seleccionats no s'han esborrat, marqui la casella de confirmació." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Esborrament Paquet" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Esborrar Paquet: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "L'esborrament del paquet és permanent." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Marqueu el quadre de verificació per confirmar l'operació." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmeu l'eliminació del paquet" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Esborra" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Només els usuaris de confiança (TUs) i desenvolupadors poden eliminar " -"paquets." +msgstr "Només els usuaris de confiança (TUs) i desenvolupadors poden eliminar paquets." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Desposseir-se del paquet" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Comentaris" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Marcar" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusió de Paquets" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Fusiona el Paquet: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vegada que el paquet s'ha fusionat que no es pot revertir." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introdueixi el nom del paquet amb que voleu fusionar aquest paquet." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionar amb:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmi la fusió del paquet" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusió" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Només el usuaris de confiança (TUs) i desenvolupadors poden fusionar paquets." +msgstr "Només el usuaris de confiança (TUs) i desenvolupadors poden fusionar paquets." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primer" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Següent" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Darrer" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "Registrar-se" +#: html/register.php msgid "Use this form to create an account." msgstr "Utilitzeu aquest formulari per a crear un compte." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuari de Confiança" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No es va poder recuperar detalls de la proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "La votació es va tancar per a aquesta proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No pots votar en una proposta sobre tu." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ja has votat en aquesta proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "L'identificador de vot no és vàlid." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Vots actuals" +#: html/tu.php msgid "Past Votes" msgstr "Últims vots" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votants" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El registre de comptes ha estat inhabilitat per la seva adreça IP, " -"probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +msgstr "El registre de comptes ha estat inhabilitat per la seva adreça IP, probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manca l'identificador de l'usuari" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nom d'usuari és icorrecte." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "En número de caràcters ha d'estar entre %s i %s" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comença i finalitza amb una lletra o número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Només pot contenir un punt, guió o guió baix." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adreça del correu-e no és vàlida." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "L'empremta de la clau PGP no és vàlida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No es possible augmentar els permisos del compte." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "L'idioma no està suportat actualment." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nom d'usuari, %s%s%s, ja s'està fent servir." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L'adressa, %s%s%s, ja s'està fent servir." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error al intentar crear el compte, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "El compte, %s%s%s, s'ha creat correctament." -msgid "Click on the Login link above to use your account." -msgstr "" -"Feu clic a l'enllaç superior d'Inici de sessió per utilitzar el seu compte." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Benvingut a %s! Per configurar una contrasenya inicial per la seu nou compte " -"feu clic a l'enllaç de sota. Si l'enllaç no funciona, tracti de copiar-lo i " -"enganxar-lo al seu navegador." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "S'ha enviat una contrasenya nova al seu correu electrònic." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Feu clic a l'enllaç superior d'Inici de sessió per utilitzar el seu compte." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No s'han fet canvis al compte, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "El compte, %s%s%s, s'ha modificat correctament." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El formulari de registre està deshabilitat per la seva adreça IP, " -"probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +msgstr "El formulari de registre està deshabilitat per la seva adreça IP, probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"La seva contrasenya s'ha restablert. Si acaba de crear un nou compte, si us " -"plau utilitzeu l'enllaç al correu electrònic de confirmació per configurar " -"una contrasenya inicial. En cas contrari, sol·liciti una clau de reinici a " -"la pàgina %s de restabliment de contanenya %s." +msgstr "La seva contrasenya s'ha restablert. Si acaba de crear un nou compte, si us plau utilitzeu l'enllaç al correu electrònic de confirmació per configurar una contrasenya inicial. En cas contrari, sol·liciti una clau de reinici a la pàgina %s de restabliment de contanenya %s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "nom d'usuari o contrasenya incorrectes." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." -msgstr "" -"Direcció de correu electrònic i combinació de tecles de restabliment no " -"vàlida." +msgstr "Direcció de correu electrònic i combinació de tecles de restabliment no vàlida." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Res" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Veure l'informació del compte per %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "S'ha afegit el comentari." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "No s'han pogut obtenir els detalls del paquet." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "No s'han pogut trobar els detalls del paquet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Heu d'identificar-vos abans de marcar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No heu seleccionat cap paquet per a marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Els paquets seleccionats s'han marcat com No-Actualitzats." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Heu d'identificar-vos abans de desmarcar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No heu seleccionat cap paquet per a desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Els paquets seleccionats s'han desmarcat." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No té permís per eliminar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No heu seleccionat cap paquet per a esborrar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Els paquets seleccionats s'han esborrat." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Heu d'identificar-vos abans d'apropiar-se paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Heu d'identificar-vos abans de desapropiàr-se paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No heu seleccionat cap paquet per apropiar-se'n." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No heu seleccionat cap paquet per desapropiar-se'n." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Els paquets seleccionats s'han apropiat." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Els paquets seleccionats han sigut desapropiats." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Heu d'identificar-vos abans de votar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Heu d'identificar-vos abans de llevar el vot als paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No heu seleccionat cap paquet per votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Els vostres vots s'han suprimit dels paquets seleccionats." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Els vostres vots s'han enviat per als paquets seleccionats." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No s'ha pogut afegir a la llista de notificació." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Heu estat afegit a la llista de notificacions de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Heu sigut esborrat de la llista de notificacions de comentaris de %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Heu d'identificar-vos abans d'editar qualsevol informació de paquet." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Manca l'identificador del comentari." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "S'ha esborrat el comentari." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No esteu autoritzat per esborrar aquest comentari." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Veure els detalls del paquet per" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nom no vàlid: sols es permet lletres minúscules." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "El tipus de sol·licitud no és vàlid." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nom d'usuari" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipus de compte" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuari" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolupador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adreça de correu-e" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nom real" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nom d'usuari IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Emprempta clau PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estat" +#: template/account_details.php msgid "Inactive since" msgstr "" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actiu" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Mai" +#: template/account_details.php msgid "View this user's packages" msgstr "Visualitza els paquets d'aquest usuari" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "requerit" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuari normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuari de Confiança" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "El compte s'ha suspès" +#: template/account_edit_form.php msgid "Inactive" msgstr "" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Escriu altre cop la contrasenya" +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualitza" +#: template/account_edit_form.php msgid "Create" msgstr "Crea" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Restaura" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "No s'ha trobat cap coindidència amb els criteris de cerca." +#: template/account_search_results.php msgid "Edit Account" msgstr "Edita compte" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspès" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menys" +#: template/account_search_results.php msgid "More" msgstr "Més" +#: template/account_search_results.php msgid "No more results to display." msgstr "No hi ha més resultats per mostrar." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Els meus paquets" +#: template/header.php msgid " My Account" msgstr "El meu Compte" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Accions Paquet" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Veure PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marcat com a no-actualitzat" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar el paquet com a no-actualitzat" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar el paquet" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "eliminar vot" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Vota per aquest paquet" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Deshabilitar notificacions" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificar comentaris nous" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Esborrar el paquet" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Fusionar el paquet" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar Paquet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconegut" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Paraules Clau" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Remitent" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mantenidor" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Vots" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Primer enviament" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualització" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Afegir un comentari" -msgid "Comment has been added." -msgstr "S'ha afegit el comentari." - +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Darrers Comentaris" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Esborra comentari" -#, php-format -msgid "Comment by %s" -msgstr "Comentari de %s" - -msgid "Anonymous comment" -msgstr "" - -msgid "deleted" -msgstr "" - +#: template/pkg_comments.php msgid "All comments" msgstr "Tots el comentaris" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalls del paquet" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripció" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Enllaç URL Upstream" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visiti la pàgina web per" +#: template/pkg_details.php msgid "Licenses" msgstr "" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "" +#: template/pkg_details.php msgid "Replaces" msgstr "" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependències" +#: template/pkg_details.php msgid "Required by" msgstr "Requerit per" +#: template/pkg_details.php msgid "Sources" msgstr "Fonts" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motiu" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Acceptat" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rebutjat" -msgid "Comments" -msgstr "Comentaris" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Combinar amb" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pàgina %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nom, Descripció" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Només nom" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Tots" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcat" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No Marcat" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nom" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votat" -msgid "Age" -msgstr "Antiguitat" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendent" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendent" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introdueixi in criteri de cerca" +#: template/pkg_search_form.php msgid "Search by" msgstr "Cerca per" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "No-Actualitzat" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordena per" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordena en sentit" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pàgina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Vés" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfes" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "S'ha produït un error en obtenir la llista de paquets." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "No s'ha trobat cap coincidència amb el teu criteri de cerca." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +#: template/pkg_search_results.php msgid "Version" msgstr "Versió" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "orfe" +#: template/pkg_search_results.php msgid "Actions" msgstr "Accions" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marca com No-Actualitzat" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarca No-Actualitzat" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Apròpia paquets" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Desapròpia els paquets" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Esborra paquet" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualsevol tipus" +#: template/search_accounts_form.php msgid "Search" msgstr "Cerca" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadístiques" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquets orfes" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquets afegits en els darrers 7 dies" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquets actualitzats en els darrers 7 dies" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquets actualitzats en l'últim any" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquets mai actualitzats" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuaris registrats" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuaris de Confiança" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualitzacions recents" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Les meves estadístiques" -msgid "Packages in unsupported" -msgstr "Paquets a \"unsupported\"" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalls de la proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Aquesta votació encara es troba en funcionament." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Enviat: %s per %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fi" +#: template/tu_details.php msgid "Result" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Abstenir-se" +#: template/tu_details.php msgid "Total" msgstr "Nom exacte" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No s'han trobat resultats." +#: template/tu_list.php msgid "Start" msgstr "Inici" +#: template/tu_list.php msgid "Back" msgstr "Enrere" diff --git a/po/cs.po b/po/cs.po index 7b97dd0d..6f930f2e 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Jaroslav Lichtblau , 2015 # Jaroslav Lichtblau , 2014 @@ -11,580 +11,770 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" -"Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +#: html/404.php msgid "Page Not Found" msgstr "Stránka nenalezena" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Omlouváme se, požadovaná stránka neexistuje." +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "Účet" +#: html/account.php template/header.php msgid "Accounts" msgstr "Účty" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Zde nemáte povolený přístup." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nelze obdržet informace pro vybraného uživatele." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemáte oprávnění pro úpravu tohoto účtu." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Pro vyhledání existujících účtů použíte tento formulář." +#: html/account.php msgid "You must log in to view user information." msgstr "Musíte se přihlásit, pro zobrazení informací o uživateli." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Přidat návrh" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Chybný token uživatelské akce." +#: html/addvote.php msgid "Username does not exist." msgstr "Uživatelské jméno neexistuje." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Pro %s se již hlasuje." +#: html/addvote.php msgid "Invalid type." msgstr "Chybný typ." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Návrh nemůže být prázdný." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nový návrh podán." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Předložit návrh na hlasování." +#: html/addvote.php msgid "Applicant/TU" msgstr "Uchazeč/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vynechat pokud neni vhodný)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Typ" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Úprava směrnic" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Návrh" +#: html/addvote.php msgid "Submit" msgstr "Odeslat" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Domů" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nezapomeň hlasovat pro svoje oblíbené balíčky!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Některé balíčky mohou být poskytnuty v binární podobě v repozitáři " -"[community]." +msgstr "Některé balíčky mohou být poskytnuty v binární podobě v repozitáři [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Diskuze" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Hlášení chyb" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Vyhledávání balíčků" +#: html/index.php msgid "Adopt" msgstr "Adoptovat" +#: html/index.php msgid "Vote" msgstr "Hlasovat" +#: html/index.php msgid "UnVote" msgstr "Odebrat hlas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Oznamovat" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Neoznamovat" -msgid "Flag" -msgstr "Označit" - +#: html/index.php msgid "UnFlag" msgstr "Odznačit" +#: html/login.php template/header.php msgid "Login" msgstr "Přihlašovací jméno" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Přihlášen jako: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Odhlásit" +#: html/login.php msgid "Enter login credentials" msgstr "Vložit přihlašovací údaje" -msgid "Username" -msgstr "Uživatelské jméno" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Heslo" +#: html/login.php msgid "Remember me" msgstr "Pamatuj si mě" +#: html/login.php msgid "Forgot Password" msgstr "Zapomenuté heslo" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Vyhledávací kritéria" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Balíčky" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Došlo k chybě při získávání detailů balíčku." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Chybí povinný údaj." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Hesla se neshodují" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Heslo musí mít nejméně %s znaků." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Neplatný e-mail." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Reset hesla" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Heslo bylo úspěšně resetováno." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrďte svou e-mailovou adresu:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Zadejte nové heslo:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrďte nové heslo:" +#: html/passreset.php msgid "Continue" msgstr "Pokračovat" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Pokud jste zapomněli emailovou adresu použitou při registraci, pošlete " -"zprávu na %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Pokud jste zapomněli emailovou adresu použitou při registraci, pošlete zprávu na %saur-general%s mailing list." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Zadejte emailovou adresu:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "Smazání balíčku" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Smazat balíček: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Smazání balíčku je trvalé." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaškrtnout políčko pro potvrzení akce." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrdit smazání balíčku" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Smazat" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Komentáře" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Označit" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Spojení balíčku" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrdit spojení balíčku" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Spojit" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Zadat požadavek" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Uzavřít požadavek" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "První" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Předchozí" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Další" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Poslední" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Požadavky" +#: html/register.php template/header.php msgid "Register" msgstr "Registrovat" +#: html/register.php msgid "Use this form to create an account." msgstr "Použíte tento formulář k založení účtu." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Důvěryhodný uživatel" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nelze obdržet navrhované detaily." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Toto hlasování již skončilo." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemůžete volit sami pro sebe." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Již jste hlasoval." +#: html/tu.php msgid "Vote ID not valid." msgstr "Nesprávné ID hlasování." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Současný počet hlasů" +#: html/tu.php msgid "Past Votes" msgstr "Předešlá hlasování" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Hlasující" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Chybějící Uživateské ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Chybně zadané uživatelské jméno" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Délka musí být %s až %s znaků" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Začíná a končí písmenem nebo číslicí" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Může obsahovat pouze jednu tečku, podtržítko nebo spojovník." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Vadná emailová adresa." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jazyk není momentálné podporován." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -msgid "Click on the Login link above to use your account." -msgstr "" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Účet pozastaven" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -592,334 +782,497 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Chybné uživatelské jméno nebo heslo." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Komentář byl přidán" + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Došlo k chybě při získávání detailů o balíčku." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Detailní informace o balíčku nejsou dostupné." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Před nastavením příznaku balíčků se musíte přihlásit." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nezvolili jste žádný balíček k označení." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Zvoleným balíčkům byl nastaven příznak zastaralé." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musíte být příhlášeni, abyste mohli odznačit balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nevybrali jste žádne balíčky k odebrání příznaku." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Zvoleným bálíčkům bylo odebráno označení." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nevybrali jste žádné balíčky ke smazání." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Zvolené balíčky byly smazány." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musíte být přihlášeni, než si budete moci osvojit balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musíte být přihlášeni, pro odebrání vlastnictví u svých balíčků." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nevybrali jste žádný balíček k osvojení." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nevybrali jste žádný balíček pro odebrání vlastnictví." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Zvolené balíčky byly osvojeny." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Vybraným balíčkům bylo odebráno vlastnictví." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Před hlasováním se musíte přihlásit." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musíte být přihlášeni, než budete moci odebrat hlasování pro balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nezvolili jste žádné balíčky k hlasování." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaše hlasování bylo odebráno vybraným balíčkům." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Vaše hlasování bylo započteno pro vybrané balíčky." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nelze přidat do seznamu upozornění." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Byly jste přidáni do seznamu oznámení ohledně %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Byli jste odebrání ze seznamu upozornění ohledně %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Musíte být přihlášeni, než budete moci upravovat informace o balíčcích." +msgstr "Musíte být přihlášeni, než budete moci upravovat informace o balíčcích." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Chybějící ID komentáře." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentář byl smazán." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nemáte oprávnění pro smazání tohoto komentáře." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Chybný název: jsou povolena pouze malá písmena." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Uživatelské jméno" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Typ účtu" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Uživatel" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Vyvojář" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Emailová adresa" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Skutečné jméno" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC přezdívka" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Neaktivní od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivní" +#: template/account_details.php msgid "Last Login" msgstr "Poslední přihlášení" +#: template/account_details.php msgid "Never" msgstr "Nikdy" +#: template/account_details.php msgid "View this user's packages" msgstr "Zobrazit balíčky tohoto uživatele" +#: template/account_details.php msgid "Edit this user's account" msgstr "Upravit tento uživatelský účet" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "vyžadováno" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Obyčejný uživatel" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Důvěryhodný uživatel" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Účet pozastaven" +#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktivní" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Heslo znovu" +#: template/account_edit_form.php msgid "Language" msgstr "Jazyk" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualizovat" +#: template/account_edit_form.php msgid "Create" msgstr "Vytvořit" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reset" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Pro Váš dotaz nebyl nalezen žádný odpovídající výsledek." +#: template/account_search_results.php msgid "Edit Account" msgstr "Upravit účet" +#: template/account_search_results.php msgid "Suspended" msgstr "Pozastavený" +#: template/account_search_results.php msgid "Edit" msgstr "Upravit" +#: template/account_search_results.php msgid "Less" msgstr "Méně" +#: template/account_search_results.php msgid "More" msgstr "Více" +#: template/account_search_results.php msgid "No more results to display." msgstr "Žádné další výsledky." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Moje balíčky" +#: template/header.php msgid " My Account" msgstr "Můj účet" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Zobrazit PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Prohledat wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Označeno jako zastaralé" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Označit balíček jako zastaralý" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Zrušit označení balíčku" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Vzít zpět hlas" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Hlasovat pro tento balíček" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Vypnout oznámení" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Oznamovat nové komentáře" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -927,165 +1280,232 @@ msgstr[0] "%d čekající požadavek" msgstr[1] "%d čekající požadavky" msgstr[2] "%d čekajících požadavků" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Smazat balíček" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptovat balíček" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "neznámý" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Klíčová slova" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Správce" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Hlasy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Naposledy aktualizováno" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Přidat komentář" -msgid "Comment has been added." -msgstr "Komentář byl přidán" - +#: template/pkg_comments.php msgid "View all comments" msgstr "Zobrazit všechny komentáře" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Nejnovější komentáře" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Smazat komentář" -#, php-format -msgid "Comment by %s" -msgstr "" - -msgid "Anonymous comment" -msgstr "Anonymní komentář" - -msgid "deleted" -msgstr "smazáno" - +#: template/pkg_comments.php msgid "All comments" msgstr "Všechny komentáře" +#: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčku" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Popis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "Licence" +#: template/pkg_details.php msgid "Groups" msgstr "Skupiny" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikty" +#: template/pkg_details.php msgid "Provides" msgstr "Poskytuje" +#: template/pkg_details.php msgid "Replaces" msgstr "Nahrazuje" +#: template/pkg_details.php msgid "Dependencies" msgstr "Závislosti" +#: template/pkg_details.php msgid "Required by" msgstr "Vyžadováno" +#: template/pkg_details.php msgid "Sources" msgstr "Zdroje" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Zavřít požadavek: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Důvod" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Přijato" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Zamítnuto" -msgid "Comments" -msgstr "Komentáře" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Zadat požadavek: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "Typ požadavku" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Smazání" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1093,23 +1513,29 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1117,90 +1543,116 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "Přijmout" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zamčeno" +#: template/pkgreq_results.php msgid "Close" msgstr "Uzavřít" +#: template/pkgreq_results.php msgid "Closed" msgstr "Uzavřeno" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Jméno, popis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Pouze jméno" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Přesné jméno" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Vše" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Označené" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Neoznačené" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Název" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Hlasováno" -msgid "Age" -msgstr "Stáří" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Vzestupně" +#: template/pkg_search_form.php msgid "Descending" msgstr "Sestupně" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Zadat kritéria vyhledávání" +#: template/pkg_search_form.php msgid "Search by" msgstr "Vyhledat dle" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastaralé" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Seřadit dle" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Řadit" +#: template/pkg_search_form.php msgid "Per page" msgstr "Na jedné stránce" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Jdi" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Sirotci" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Chyba při získávání seznamu balíčků." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Žádný balíček neodpovídá zadaným kritériím." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1208,119 +1660,154 @@ msgstr[0] "Nalezen %d balíček." msgstr[1] "Nalezeny %d balíčky." msgstr[2] "Nalezeno %d balíčků." +#: template/pkg_search_results.php msgid "Version" msgstr "Verze" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ano" +#: template/pkg_search_results.php msgid "orphan" msgstr "sirotek" +#: template/pkg_search_results.php msgid "Actions" msgstr "Akce" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Označit jako zastaralý" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Odebrat příznak zastaralý" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Osvojit balíček" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odebrat vlastnictví" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Smazat balíčky" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrdit" +#: template/search_accounts_form.php msgid "Any type" msgstr "Jakýkoliv" +#: template/search_accounts_form.php msgid "Search" msgstr "Hledat" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiky" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Balíčků bez správce" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Přidaných balíčků za posledních 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Aktualizovaných balíčků za posledních 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Aktualizovaných balíčků v posledním roce" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Balíčků, které nebyly nikdy aktualizovány" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovaných uživatelů" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Důvěryhodných uživatelů" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedávné aktualizace" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moje statistiky" -msgid "Packages in unsupported" -msgstr "" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaily návrhu" +#: template/tu_details.php msgid "This vote is still running." msgstr "Hlasování stále probíhá." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Vloženo: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Konec" +#: template/tu_details.php msgid "Result" msgstr "Výsledek" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" +#: template/tu_details.php msgid "Abstain" msgstr "Zdržet se" +#: template/tu_details.php msgid "Total" msgstr "Celkem" +#: template/tu_details.php msgid "Participation" msgstr "Účast" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Naposledy hlasováno" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Žádné výsledky." +#: template/tu_list.php msgid "Start" msgstr "Začátek" +#: template/tu_list.php msgid "Back" msgstr "Zpět" diff --git a/po/da.po b/po/da.po index f514488f..ff1cf908 100644 --- a/po/da.po +++ b/po/da.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Louis Tim Larsen , 2015 # Lukas Fleischer , 2011 @@ -9,577 +9,770 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" -"da/)\n" -"Language: da\n" +"Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: da\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Siden blev ikke fundet" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Beklager, den forspurgte side findes ikke." +#: html/503.php msgid "Service Unavailable" msgstr "Service utilgængelig" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Konti" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Du har ikke tilladelse til dette område." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kunne ikke hente information om den specifikke bruger." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du har ikke tilladelse til at redigere denne konto." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Brug denne formular til at søge i eksisterende konti." +#: html/account.php msgid "You must log in to view user information." msgstr "Du skal være logget ind for at se brugerinformation." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "Brugernavnet findes ikke." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s har allerede et forslag kørende for dem." +#: html/addvote.php msgid "Invalid type." msgstr "" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Forslag må ikke være tomt." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nyt forslag tilføjet." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Fremsæt et forslag til afstemning." +#: html/addvote.php msgid "Applicant/TU" msgstr "" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tomt hvis ikke relevant)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Forslag" +#: html/addvote.php msgid "Submit" msgstr "Tilføj" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Hjem" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" +#: html/home.php msgid "DISCLAIMER" msgstr "" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Diskussion" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Pakkesøgning" +#: html/index.php msgid "Adopt" msgstr "Adopter" +#: html/index.php msgid "Vote" msgstr "Stem" +#: html/index.php msgid "UnVote" msgstr "Tilbagetræk stemme" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Påmindelse" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ingen påmindelse" -msgid "Flag" -msgstr "" - +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "Log ind" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Logget ind som: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Log ud" +#: html/login.php msgid "Enter login credentials" msgstr "" -msgid "Username" -msgstr "Brugernavn" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Adgangskode" +#: html/login.php msgid "Remember me" msgstr "Husk mig" +#: html/login.php msgid "Forgot Password" msgstr "Glemt adgangskode" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Søgekriterier" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakker" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Fejl ved modtagning af pakkedetaljer." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Du mangler at udfylde et påkrævet felt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Adgangskoderne stemmer ikke overens." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Din adgangskode skal være mindst %s tegn." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ugyldig mail." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Nulstil adgangskode" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Tjek din mail for bekræftelses-link." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Din adgangskode blev nulstillet." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bekræft din nye mail-adresse:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Indtast din nye adgangskode:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bekræft din nye adgangskode:" +#: html/passreset.php msgid "Continue" msgstr "Forsæt" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." msgstr "" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Indtast din mail-adresse:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Slet pakke: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Sletning af en pakke er permanent" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bekræft sletning af pakke" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Slet" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Kun betroede brugere og udviklere kan slette pakker." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Kommentarer" + +#: html/pkgflag.php +msgid "Flag" +msgstr "" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Følgende pakker vil blive slettet:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Udfyld forspørgsel" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Luk forspørgsel" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Tidligere" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Næste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Sidste" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Forspørgelser" +#: html/register.php template/header.php msgid "Register" msgstr "Register" +#: html/register.php msgid "Use this form to create an account." msgstr "Brug denne formular til at oprette en konto." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Betroet bruger (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Kunne ikke hente detaljer om forslaget." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Afstemningen er lukket for dette forslag." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Du kan ikke stemme i et forslag om dig selv." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du har allerede stemt ved dette forslag." +#: html/tu.php msgid "Vote ID not valid." msgstr "Stemme ID er ikke gyldigt." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Aktuelle stemmer" +#: html/tu.php msgid "Past Votes" msgstr "" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manglende bruger-ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Brugernavnet er ugyldigt." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Skal være mellem %s og %s tegn." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Start og slut med et bogstav eller tal" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun indeholde ét punktum, én bundstreg eller én bindestreg." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mail adressen er ugyldig." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Sproget er ikke understøttet på nuværende tidspunkt." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -msgid "Click on the Login link above to use your account." -msgstr "" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto suspenderet" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -587,730 +780,1028 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Forkert brugernavn eller adgangskode" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Ingen" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Kommentaren blev tilføjet" + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Fejl ved modtagelse af pakkedetaljer." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Kunne ikke finde pakkedetaljerne.." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du skal være logget ind for at markere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Du har ikke valgt nogle pakker at markere." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "De valgte pakker er markeret forældet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Du skal være logget ind for at afmarkere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Du har ikke valgt nogle at afmarkere." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De valgte pakker er afmarkeret." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du har ikke tilladelse til, at slette pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du har ikke valgt nogle pakker at slette." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De valgte pakker er blevet slettet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du skal være logget ind for at adoptere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du skal være logget ind for at opgive ejerskabet for pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du har ikke valgt nogle pakker at adoptere." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du har ikke valgt nogle pakker at opgive ejerskabet for." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "De valgte pakker er adopteret." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De valgte pakker er blevet efterladt." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du skal være logget ind for at stemme på pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du skal være logget ind for at fjerne din stemme fra pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du har ikke valgt nogle pakker at stemme på." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Dine stemmer er fjernet fra de valgte pakker." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Din stemme er afgivet for de valgte pakker." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kunne ikke tilføje til listen over påmindelser." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du vil nu modtage besked, når der kommer nye kommentarer til %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du vil ikke længere modtage besked ved nye kommentarer for %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Du skal være logget ind for at redigere pakkeoplysninger." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Manglende kommentar ID." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentaren er slettet." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du har ikke rettigheder til at slette denne kommentar." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ugyldigt brugernavn: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vis pakkedeltaljer for" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ugyldigt navn: kun små bogstaver er tilladt." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ugyldig årsag" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bekræft sletning" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Brugernavn" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Kontotype" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Bruger" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Udvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Betroet bruger og udvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail adresse" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Rigtigt navn" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC kaldenavn" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Inaktiv siden" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" +#: template/account_details.php msgid "Last Login" msgstr "Sidste login" +#: template/account_details.php msgid "Never" msgstr "Aldrig" +#: template/account_details.php msgid "View this user's packages" msgstr "Vis pakker fra denne bruger" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "påkrævet" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normal bruger" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Betroet bruger (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto suspenderet" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Bekræft adgangskode" +#: template/account_edit_form.php msgid "Language" msgstr "Sprog" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Opdater" +#: template/account_edit_form.php msgid "Create" msgstr "Opret" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Nulstil" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Ingen resultater opfyldte dine søgekriterier." +#: template/account_search_results.php msgid "Edit Account" msgstr "Rediger konto" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspenderet" +#: template/account_search_results.php msgid "Edit" msgstr "" +#: template/account_search_results.php msgid "Less" msgstr "Færre" +#: template/account_search_results.php msgid "More" msgstr "Flere" +#: template/account_search_results.php msgid "No more results to display." msgstr "Ikke flere resultater at vise." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "Brugere" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Gem" +#: template/header.php msgid "My Packages" msgstr "Mine pakker" +#: template/header.php msgid " My Account" msgstr "Min konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Vis PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Vis ændringer" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Fjern stemme" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem på denne pakke" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Deaktiver notifikationer" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Slet pakke" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter pakke" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "ukendt" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Nøgleord" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Indsender" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ejer" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Sidste pakker" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmer" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularitet" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Først tilføjet" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Sidst opdateret" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Tilføj kommentar" -msgid "Comment has been added." -msgstr "Kommentaren blev tilføjet" - +#: template/pkg_comments.php msgid "View all comments" msgstr "Vis alle kommentarer" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Seneste kommentarer" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Slet kommentar" -#, php-format -msgid "Comment by %s" -msgstr "Kommentar fra %s" - -msgid "Anonymous comment" -msgstr "Anonym kommentar" - -msgid "deleted" -msgstr "slettet" - +#: template/pkg_comments.php msgid "All comments" msgstr "Alle kommentarer" +#: template/pkg_details.php msgid "Package Details" msgstr "Detaljer om pakken" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beskrivelse" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Besøg hjemmesiden for" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenser" +#: template/pkg_details.php msgid "Groups" msgstr "Grupper" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikter" +#: template/pkg_details.php msgid "Provides" msgstr "Tilbyder" +#: template/pkg_details.php msgid "Replaces" msgstr "Erstatter" +#: template/pkg_details.php msgid "Dependencies" msgstr "Afhængigheder" +#: template/pkg_details.php msgid "Required by" msgstr "Påkrævet af" +#: template/pkg_details.php msgid "Sources" msgstr "Kilder" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Luk forspørgsel: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Accepteret" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Afvist" -msgid "Comments" -msgstr "Kommentarer" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Sletning" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Forladt" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Side %d af %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakke" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Udfyldt af" +#: template/pkgreq_results.php msgid "Date" msgstr "Dato" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dage tilbage" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d time tilbage" msgstr[1] "~%d timer tilbage" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 time tilbage" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accepter" +#: template/pkgreq_results.php msgid "Locked" msgstr "Låst" +#: template/pkgreq_results.php msgid "Close" msgstr "Luk" +#: template/pkgreq_results.php msgid "Closed" msgstr "Lukket" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Navn, beskrivelse" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Kun navn" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Præcist navn" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Navn" -msgid "Popularity" -msgstr "Popularitet" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Stemt" -msgid "Age" -msgstr "Alder" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "" +#: template/pkg_search_form.php msgid "Descending" msgstr "" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Søg efter" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Forældet" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortér efter" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorter efter" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per side" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Søg" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Forladt" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fejl ved modtagelse af pakkeliste." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ingen pakker opfylder dine søgekriterier." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pakke fundet." msgstr[1] "%d pakker fundet." +#: template/pkg_search_results.php msgid "Version" msgstr "Version" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "forladt" +#: template/pkg_search_results.php msgid "Actions" msgstr "Handlinger" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marker forældet" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Afmarker forældet" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter pakker" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Fjern ejerskab for pakker" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Slet pakker" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Forsæt" +#: template/search_accounts_form.php msgid "Any type" msgstr "Vilkårlig type" +#: template/search_accounts_form.php msgid "Search" msgstr "Søg" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistikker" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Forladte pakker" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakker tilføjet indenfor de seneste 7 dage" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakker opdateret indenfor de seneste 7 dage" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakker opdateret indenfor det seneste år" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pakker aldrig opdateret" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registerede brugere" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Betroede brugere" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Seneste opdateringer" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mine statistikker" -msgid "Packages in unsupported" -msgstr "" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaljer om forslag" +#: template/tu_details.php msgid "This vote is still running." msgstr "Denne afstemning er stadig aktiv." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Tilføjet: %s af %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Slut" +#: template/tu_details.php msgid "Result" msgstr "Resultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nej" +#: template/tu_details.php msgid "Abstain" msgstr "Undlad at stemme" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Deltagelse" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Sidste stemme" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ingen resultater fundet." +#: template/tu_list.php msgid "Start" msgstr "Start" +#: template/tu_list.php msgid "Back" msgstr "Tilbage" diff --git a/po/de.po b/po/de.po index 6ddc0ffe..e6505dd4 100644 --- a/po/de.po +++ b/po/de.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Alexander Griesbaum , 2013 # Alexander Griesbaum , 2013-2014 @@ -10,6 +10,7 @@ # go2sh , 2015 # FabianS_ , 2012 # Giuliano Schneider , 2015 +# go2sh , 2015 # Lukas Fleischer , 2011 # Mark Gerlach, 2015 # Mark Gerlach, 2015 @@ -23,1406 +24,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 09:49+0000\n" -"Last-Translator: go2sh \n" -"Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" -"de/)\n" -"Language: de\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 18:35+0000\n" +"Last-Translator: Matthias Gorissen \n" +"Language-Team: German (http://www.transifex.com/lfleischer/aur/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Seite nicht gefunden" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Die angeforderte Seite existiert leider nicht." +#: html/503.php msgid "Service Unavailable" msgstr "Dienst nicht verfügbr" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir " -"werden gleich zurück sein ..." +msgstr "Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir werden gleich zurück sein ..." +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Konten" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Es ist Dir nicht erlaubt, auf diesen Bereich zuzugreifen." +#: html/account.php msgid "Could not retrieve information for the specified user." -msgstr "" -"Es konnten keine Informationen für den angegebenen Benutzer geladen werden." +msgstr "Es konnten keine Informationen für den angegebenen Benutzer geladen werden." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du hast keine Berechtigung, dieses Konto zu ändern." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Benutze dieses Formular, um vorhandene Konten zu suchen." +#: html/account.php msgid "You must log in to view user information." msgstr "Du musst Dich anmelden, um Benutzerinformationen anzusehen." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Vorschlag hinzufügen" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Ungültiges Zeichen für eine Benutzer-Aktion." +#: html/addvote.php msgid "Username does not exist." msgstr "Der Nutzername existiert nicht." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Es läuft bereits ein Vorschlag für %s." +#: html/addvote.php msgid "Invalid type." msgstr "Ungültiger Typ." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Vorschlag darf nicht leer sein." +#: html/addvote.php msgid "New proposal submitted." msgstr "Neuer Vorschlag eingereicht." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Reiche einen Vorschlag zur Abstimmung ein." +#: html/addvote.php msgid "Applicant/TU" msgstr "Bewerber/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(leer, falls nicht zutreffend)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Typ" +#: html/addvote.php msgid "Addition of a TU" msgstr "TU hinzugefügt" +#: html/addvote.php msgid "Removal of a TU" msgstr "TU entfernt" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU entfernt (unerklärte Inaktivität)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Änderung der Bestimmungen" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Vorschlag" +#: html/addvote.php msgid "Submit" msgstr "Abschicken" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Verwalte Ko-Maintainer" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "Kommentar bearbeiten" + +#: html/home.php template/header.php msgid "Home" msgstr "Startseite" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Willkommen im AUR! Für weitere Informationen lies bitte die %sAUR User " -"Guidelines%s und die %sAUR TU Guidelines%s." +msgstr "Willkommen im AUR! Für weitere Informationen lies bitte die %sAUR User Guidelines%s und die %sAUR TU Guidelines%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Alle hier eingereichten PKGBUILDs %smüssen%s den %sArch Packaging Standards" -"%s entsprechen. Andernfalls werden sie entfernt!" +msgstr "Alle hier eingereichten PKGBUILDs %smüssen%s den %sArch Packaging Standards%s entsprechen. Andernfalls werden sie entfernt!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Denk daran, für Deine bevorzugten Pakete zu stimmen!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Manche Pakete könnten als Binär-Pakete in [community] bereitgestellt sein." +msgstr "Manche Pakete könnten als Binär-Pakete in [community] bereitgestellt sein." +#: html/home.php msgid "DISCLAIMER" -msgstr "" -"DISCLAIMER: Offiziell nicht unterstützte PKGBUILDS werden von den Benutzern " -"erstellt - durch den Download willigt man ein, diese auf eigene Gefahr zu " -"benutzen." +msgstr "DISCLAIMER: Offiziell nicht unterstützte PKGBUILDS werden von den Benutzern erstellt - durch den Download willigt man ein, diese auf eigene Gefahr zu benutzen." +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." -msgstr "" -"Nicht unterstützte Pakete sind von Benutzern erzeugte Inhalte. Jegliche " -"Nutzung der zur Verfügung gestellten Dateien erfolgt auf eigene Gefahr." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." +msgstr "AUR Pakete sind von Benutzern erstellter Inhalt. Die Benutzung der angebotenen Dateien erfolgt auf eingenes Risiko." +#: html/home.php msgid "Learn more..." msgstr "Erfahre mehr ..." +#: html/home.php msgid "Support" msgstr "Untersttzung" +#: html/home.php msgid "Package Requests" msgstr "Paketanfragen" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Es gibt drei Arten von Anfragen, die in der %sPaketaktionen%s Box auf der " -"Paketdetailseite eingereicht werden können:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Es gibt drei Arten von Anfragen, die in der %sPaketaktionen%s Box auf der Paketdetailseite eingereicht werden können:" +#: html/home.php msgid "Orphan Request" msgstr "Verweisungsanfrage" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Anfrage eine Pakte abzugeben, z.B. wenn der Verwalten nicht aktiv ist und " -"das Paket vor einer ganzen Weile als veraltet makiert wurde." +msgstr "Anfrage eine Pakte abzugeben, z.B. wenn der Verwalten nicht aktiv ist und das Paket vor einer ganzen Weile als veraltet makiert wurde." +#: html/home.php msgid "Deletion Request" msgstr "Lösch-Antrag" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte " -"benutzen Sie diese nicht, wenn das Paket kaputt ist und leich repariert " -"werden kann. Sondern kontaktieren Sie den Paketverwalter und reichen Sie " -"eine Verwaisungsanfrage ein wenn nötig." +msgstr "Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte benutzen Sie diese nicht, wenn das Paket kaputt ist und leich repariert werden kann. Sondern kontaktieren Sie den Paketverwalter und reichen Sie eine Verwaisungsanfrage ein wenn nötig." +#: html/home.php msgid "Merge Request" msgstr "Zusammenführungsanfrage" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Anfrage ein Paket mit einem anderen zusammenzuführen. Wird benutzt, wenn ein " -"Paket umbenannt werden muss oder durch ein geteiltes Paket ersetzt wird." +msgstr "Anfrage ein Paket mit einem anderen zusammenzuführen. Wird benutzt, wenn ein Paket umbenannt werden muss oder durch ein geteiltes Paket ersetzt wird." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Wenn Sie eine Anfrage diskutieren wollen, können sie die %saur-requests%s " -"Mailingliste benutzen. Jedoch benutzen Sie diese nicht um Anfragen " -"einzureichen." +msgstr "Wenn Sie eine Anfrage diskutieren wollen, können sie die %saur-requests%s Mailingliste benutzen. Jedoch benutzen Sie diese nicht um Anfragen einzureichen." +#: html/home.php msgid "Submitting Packages" msgstr "Pakete einreichen" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git über SSH wird jetzt benutzt um Pakete in das AUR einzureichen. Siehe die " -"%sEinreichen von Paketen%s Sektion von der Arch User Repository ArchWiki " -"Seite für mehr Details." +msgstr "Git über SSH wird jetzt benutzt um Pakete in das AUR einzureichen. Siehe die %sEinreichen von Paketen%s Sektion von der Arch User Repository ArchWiki Seite für mehr Details." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Die folgenden SSH Fingerabdrücke werden für das AUR benutzt:" +#: html/home.php msgid "Discussion" msgstr "Diskussion" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und " -"vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für " -"Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface nutzen Sie " -"die %saur-dev%s Mailingliste." +msgstr "Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface nutzen Sie die %saur-dev%s Mailingliste." +#: html/home.php msgid "Bug Reporting" msgstr "Fehler melden" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." -msgstr "" -"Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-" -"Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um " -"Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte " -"direkte an den zuständigen Maintainer, oder hinterlass einen Kommentar auf " -"der entsprechenden Seite des Paketes." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte direkt an den zuständigen Maintainer, oder hinterlaß einen Kommentar auf der entsprechenden Seite des Paketes." +#: html/home.php msgid "Package Search" msgstr "Paketsuche" +#: html/index.php msgid "Adopt" msgstr "Übernimm Paket" +#: html/index.php msgid "Vote" msgstr "Abstimmen" +#: html/index.php msgid "UnVote" msgstr "Stimme zurückziehen" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Benachrichtigen" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Nicht mehr benachrichtigen" -msgid "Flag" -msgstr "Markieren" - +#: html/index.php msgid "UnFlag" msgstr "Markierung aufheben" +#: html/login.php template/header.php msgid "Login" msgstr "Anmelden" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Angemeldet als: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Abmelden" +#: html/login.php msgid "Enter login credentials" msgstr "Zugangsdaten eingeben" -msgid "Username" -msgstr "Nutzername" +#: html/login.php +msgid "User name or email address" +msgstr "Benutzername oder E-Mail-Adresse" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Passwort" +#: html/login.php msgid "Remember me" msgstr "Angemeldet bleiben" +#: html/login.php msgid "Forgot Password" msgstr "Passwort vergessen" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Die Anmeldung über HTTP wurde deaktiviert. Zum Anmelden %swechsle bitte zu " -"HTTPS%s." +msgstr "Die Anmeldung über HTTP wurde deaktiviert. Zum Anmelden %swechsle bitte zu HTTPS%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Suchkriterien" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakete" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Während des Empfangs der Paket-Details ist ein Fehler aufgetreten." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Ein benötigtes Feld ist nicht ausgefüllt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Passwort-Felder sind unterschiedlich." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Dein Passwort muss mindestens %s Zeichen lang sein." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ungültige E-Mail-Adresse." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Es wurde ein Passwort-Reset für den Account %s, der mit dieser E-Mail-" -"Adresse verknüpft ist, angefordert. Wenn Du Dein Passwort zurücksetzen " -"möchtest, folge dem untenstehenden Link, ansonsten kannst Du diese Nachricht " -"ignorieren und nichts wird geschehen." - +#: html/passreset.php msgid "Password Reset" msgstr "Passwort zurücksetzen" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Überprüfe Dein E-Mail-Postfach hinsichtlich des Bestätigungslinks." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Dein Passwort wurde erfolgreich zurückgesetzt." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bestätige Deine E-Mail-Adresse:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Gib Dein neues Passwort ein:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bestätige Dein neues Passwort:" +#: html/passreset.php msgid "Continue" msgstr "Weiter" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Wenn Du die E-Mail-Adresse vergessen hast, die Du für Deine Registrierung " -"benutzt hast, sende bitte eine Nachricht an die %saur-general%s Mailing-" -"Liste." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Wenn Du die E-Mail-Adresse vergessen hast, die Du für Deine Registrierung benutzt hast, sende bitte eine Nachricht an die %saur-general%s Mailing-Liste." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Gib Deine E-Mail-Adresse ein:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Die gewählten Pakete wurden nicht makiert, bitte einen Kommentar eingeben." + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Die Betreuung der ausgewählten Pakete wurde nicht abgegeben, überprüfe die " -"Bestätigungs-Checkbox." +msgstr "Die Betreuung der ausgewählten Pakete wurde nicht abgegeben, überprüfe die Bestätigungs-Checkbox." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Das Paket, in das die Stimmen und Kommentare übernommen werden sollen, kann " -"nicht gefunden werden." +msgstr "Das Paket, in das die Stimmen und Kommentare übernommen werden sollen, kann nicht gefunden werden." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Eine Paketbasis kann nicht mit sich selbst verschmolzen werden." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Die ausgewählten Pakete wurden nicht gelöscht, bitte aktiviere die " -"Bestätigungs-Checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Die ausgewählten Pakete wurden nicht gelöscht, bitte aktiviere die Bestätigungs-Checkbox." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Pakete entfernen" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Paket löschen: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Benutze dieses Formular um die Paketbasis %s%s%s und die folgenden Pakete " -"vom AUR zu löschen:" +msgstr "Benutze dieses Formular um die Paketbasis %s%s%s und die folgenden Pakete vom AUR zu löschen:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Die Löschung eines Pakets ist endgültig." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Wähle ein Kästchen aus, um die Aktion zu bestätigen." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bestätige das Löschen des Pakets" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Löschen" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Nur vertrauenswürdige Benutzer und Entwickler können Pakete löschen." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Paket abgeben" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Paket-Betreuung abgeben: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Benutzen Sie dieses Formular um die Paketbasis %s%s%s, welche die folgenden " -"Pakete enhält, abzugeben:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Benutzen Sie dieses Formular um die Paketbasis %s%s%s, welche die folgenden Pakete enhält, abzugeben:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Durch das markieren des Kontrollkästchen bestätigen Sie, dass Sie das Pakte " -"abegen und den Besitz an %s%s%s übergeben wollen." +msgstr "Durch das markieren des Kontrollkästchen bestätigen Sie, dass Sie das Pakte abegen und den Besitz an %s%s%s übergeben wollen." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Durch Auswahl dieser Checkbox bestätigst du, dass du die Betreuung dieses " -"Paketes abgeben willst." +msgstr "Durch Auswahl dieser Checkbox bestätigst du, dass du die Betreuung dieses Paketes abgeben willst." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Bestätige die Abgabe der Paket-Betreuung" +#: html/pkgdisown.php msgid "Disown" msgstr "Gebe Paket ab" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Nur Tus und Developer können die Paket-Betreuung abgeben." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "Paket als \"veraltet\" makieren" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "Paket als \"veraltet\" markieren: %s" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Benutze dieses Formular, um die Paketbasis %s%s%s und die folgenden Pakete als \"veraltet\" zu markieren." + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "Bitte benutze dieses Formular %snicht%s, um Fehler zu melden. Benutze stattdessen die Paketkommentare." + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "Beschreibe genauer, warum das Paket \"veraltet\" ist, vorzugsweise mit Links zu der Veröffentlichungsankündigung oder dem Release-Tar-Archive." + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Kommentare" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Markieren" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "Nur registrierte Benutzer können Pakete als \"veraltet\" markieren." + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakete verschmelzen" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Verschmelze Paket: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Benutze dieses Formular um die Paketbasis %s%s%s in ein anderes Paket zu " -"verschmelzen." +msgstr "Benutze dieses Formular um die Paketbasis %s%s%s in ein anderes Paket zu verschmelzen." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Die folgenden Pakete werden gelöscht:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Wenn das Paket einmal verschmolzen ist, kann diese Aktion nicht mehr " -"revidiert werden." +msgstr "Wenn das Paket einmal verschmolzen ist, kann diese Aktion nicht mehr revidiert werden." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Trag den Namen des Pakets ein, in welches Du das vorliegende Paket " -"verschmelzen willst." +msgstr "Trag den Namen des Pakets ein, in welches Du das vorliegende Paket verschmelzen willst." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Verschmelze in:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Bestätige Verschmelzung der Pakete" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Verschmelzen" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." +msgstr "Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Anfrage einreichen" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Anfrage schließen" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Erste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Zurück" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Weiter" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Letzte" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Anfragen" +#: html/register.php template/header.php msgid "Register" msgstr "Registrieren" +#: html/register.php msgid "Use this form to create an account." msgstr "Benutze dieses Formular, um ein Konto zu erstellen." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Vertrauenswürdiger Benutzer (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Es konnten keine Vorschlag-Details ermittelt werden." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Die Abstimmungsphase für diesen Vorschlag ist beendet." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Nur Trusted User dürfen wählen." +#: html/tu.php msgid "You cannot vote in an proposal about you." -msgstr "" -"Du kannst über einen Vorschlag, der dich selbst betrifft, nicht abstimmen." +msgstr "Du kannst über einen Vorschlag, der dich selbst betrifft, nicht abstimmen." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du hast über diesen Vorschlag bereits abgestimmt." +#: html/tu.php msgid "Vote ID not valid." msgstr "Ungültige Abstimmungs-ID." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Laufende Abstimmungen" +#: html/tu.php msgid "Past Votes" msgstr "Abgeschlossene Abstimmungen" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Abstimmende" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Die Registrierung ist aktuell für deine IP-Adresse deaktiviert. Ein " -"möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die " -"Unannehmlichkeiten." +msgstr "Die Registrierung ist aktuell für deine IP-Adresse deaktiviert. Ein möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die Unannehmlichkeiten." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Benutzer-ID fehlt" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Der Nutzername ist ungültig." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Er muss zwischen %s und %s Zeichen lang sein." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Muss mit einem Buchstaben oder einer Zahl beginnen und enden" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kann nur einen Punkt, Unter- oder Bindestrich enthalten." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Die E-Mail-Adresse ist ungültig." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Der PGP-Schlüssel-Fingerabdruck ist ungültig." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Der öffentliche SSH Schlüssel ist ungültig." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Die Zugriffsrechte des Kontos können nicht erweitert werden." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Diese Sprache wird momentan noch nicht unterstützt." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Der Nutzername %s%s%s ist bereits vergeben." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Die Adresse %s%s%s wird bereits verwendet." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Der öffentliche SSH Schlüssel, %s%s%s, ist bereits in Benutzung." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Beim Erstellen des Kontos %s%s%s ist ein Fehler aufgetreten." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Das Konto %s%s%s wurde erfolgreich erstellt." -msgid "Click on the Login link above to use your account." -msgstr "Klicke zur Anmeldung bitte oben auf den Login-Link." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Willkommen bei %s! Um ein Passwort für dein neues Konto festzulegen, klick " -"bitte auf den unten stehenden Link. Sollte das nicht funktionieren, versuche " -"den Link zu kopieren und in deinem Browser einzufügen." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ein Rücksetzungscode wurde an deine E-Mail-Adresse gesendet." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Klicke zur Anmeldung bitte oben auf den Login-Link." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Es wurden keine Änderungen am Konto %s%s%s vorgenommen." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Das Konto %s%s%s wurde erfolgreich bearbeitet." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Das Loginformular ist aktuell für deine IP-Adresse deaktiviert. Ein " -"möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die " -"Unannehmlichkeiten." +msgstr "Das Loginformular ist aktuell für deine IP-Adresse deaktiviert. Ein möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die Unannehmlichkeiten." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto aufgehoben" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Dein Passwort wurde zurückgesetzt. Solltest du ein neues Konto erstellt " -"haben, verwende bitte den Bestätigungslink aus der E-Mail, um dein Passwort " -"festzulegen. Fordere andernfalls bitte einen Rücksetzungscode über die " -"%sPasswort zurücksetzen%s Seite an." +msgstr "Dein Passwort wurde zurückgesetzt. Solltest du ein neues Konto erstellt haben, verwende bitte den Bestätigungslink aus der E-Mail, um dein Passwort festzulegen. Fordere andernfalls bitte einen Rücksetzungscode über die %sPasswort zurücksetzen%s Seite an." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Falscher Nutzername oder falsches Passwort." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Es geschah ein Fehler beim Versuch eine Nutzersitzung zu erstellen." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ungültige Kombination aus E-Mail und Reset-Schlüssel." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Keine" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Konto-Informationen aufrufen für %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "Paketbasis ID oder Paketbasis Name fehlen." + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "Du bist nicht berechtigt diesen Kommentar zu ändern." + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "Kommentar existiert nicht" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "Kommentar darf nicht leer sein." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Kommentar wurde hinzugefügt." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Fehler beim Aufrufen der Paket-Details." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paket-Details konnten nicht gefunden werden." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du musst Dich anmelden, um Pakete markieren zu können." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Du hast kein Paket zum Markieren ausgewählt." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Die gewählten Pakete wurden als \"veraltet\" markiert." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Du musst Dich anmelden, um die Markierung von Paketen entfernen zu können." +msgstr "Du musst Dich anmelden, um die Markierung von Paketen entfernen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Du hast kein Paket für das Entfernen der Markierung ausgewählt." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Die Markierungen der gewählten Pakete wurden entfernt." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du hast keine Berechtigung zum Löschen von Paketen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du hast keine Pakete zum Löschen ausgewählt." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Die gewählten Pakete wurden gelöscht." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du musst angemeldet sein, um Pakete übernehmen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du musst anmeldet sein, um die Betreuung eines Paketes abzugeben." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du hast keine Pakete zum Übernehmen gewählt." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du hast keine Pakete gewählt, deren Betreuung Du abgeben willst." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Die gewählten Pakete wurde übernommen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Die Betreuung der gewählten Pakete wurde abgegeben." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du musst angemeldet sein, um für Pakete stimmen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du musst angemeldet sein, um Pakete abwählen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du hast keine Pakete zum Wählen markiert." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Deine Stimmen wurden von den markierten Paketen entfernt." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Deine Stimmen wurden für die markierten Pakete gezählt." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Es konnte nichts zur Benachrichtigungsliste hinzugefügt werden." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du wurdest zur Benachrichtigungliste für %s hinzugefügt." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du wurdest von der Benachrichtigungsliste für %s entfernt." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Du musst angemeldet sein, um Paket-Informationen zu bearbeiten." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Kommentar-ID fehlt." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentar wurde gelöscht." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du darfst diesen Kommentar nicht löschen." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "Kommentar wurde geändert." + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Du bist nicht berechtigt die Schlagworte dieser Paketbasis zu ändern." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Die Schlagwörter der Paketbasis wurden aktualisiert." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Du darfst die Mitbetreuer für diese Paketbasis nicht verwalten." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ungültiger Nutzername: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Die Mitbetreuer der Paketbasis wurden aktualisiert." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Paket-Informationen aufrufen für" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "Benötigt %s" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Du musst angemeldet sein, um Paketanfragen einreichen zu können." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ungültiger Name: Es dürfen nur Kleinbuchstaben verwendet werden." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Das Kommentarfeld darf nicht leer sein." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ungültiger Anfragetyp." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Anfrage erfolgreich hinzugefügt." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ungültiger Grund." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Nur Entwicker und TUs können Anfragen schließen." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Anfrage erfolgreich geschlossen." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Du kannst dieses Formular verwenden, um den AUR Account unwiderruflich zu " -"entfernen %s." +msgstr "Du kannst dieses Formular verwenden, um den AUR Account unwiderruflich zu entfernen %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWARNUNG%s: Diese Aktion kann nicht rückgängig gemacht werden." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bestätige das Entfernen" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nutzername" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Konto-Typ" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Benutzer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Entwickler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Vertrauenswürdiger Benutzer & Entwickler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-Mail-Adresse" +#: template/account_details.php +msgid "hidden" +msgstr "versteckt" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Echter Name" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC-Name" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP-Schlüssel-Fingerabdruck" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Nicht aktiv seit" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" +#: template/account_details.php msgid "Last Login" msgstr "Letzter Login" +#: template/account_details.php msgid "Never" msgstr "Niemals" +#: template/account_details.php msgid "View this user's packages" msgstr "Alle Pakete dieses Benutzers anzeigen" +#: template/account_details.php msgid "Edit this user's account" msgstr "Konto dieses Nutzers bearbeiten" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "" -"Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchtest." +msgstr "Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchtest." +#: template/account_edit_form.php msgid "required" msgstr "Notwendig" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normaler Benutzer" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Vertrauenswürdiger Benutzer (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto gesperrt" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "Bitte stell sicher, dass du deine E-Mail korrekt eingegeben hast, sonst wirst du dich aussperren." + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "Verstecke E-Mail-Adresse" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Bestätige das Passwort" +#: template/account_edit_form.php msgid "Language" msgstr "Sprache" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Die folgende Information wird nur benötigt, wenn du Pakete beim Arch User " -"Repository einreichen willst." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Die folgende Information wird nur benötigt, wenn du Pakete beim Arch User Repository einreichen willst." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Öffentlicher SSH Schlüssel" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualisieren" +#: template/account_edit_form.php msgid "Create" msgstr "Erstellen" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Zurücksetzen" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Deine Suche enthält leider keine Ergebnisse." +#: template/account_search_results.php msgid "Edit Account" msgstr "Konto bearbeiten" +#: template/account_search_results.php msgid "Suspended" msgstr "Gesperrt" +#: template/account_search_results.php msgid "Edit" msgstr "Ändern" +#: template/account_search_results.php msgid "Less" msgstr "Weniger" +#: template/account_search_results.php msgid "More" msgstr "Mehr" +#: template/account_search_results.php msgid "No more results to display." msgstr "Keine weiteren Ergebnisse." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Verwalte Ko-Maintainer: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Benutze dieses Formular um Mitbetreuer für %s%s%s hinzuzufügen (ein " -"Benutzername pro Zeile):" +msgstr "Benutze dieses Formular um Mitbetreuer für %s%s%s hinzuzufügen (ein Benutzername pro Zeile):" +#: template/comaintainers_form.php msgid "Users" msgstr "Benutzer" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Speichern" +#: template/header.php msgid "My Packages" msgstr "Meine Pakete" +#: template/header.php msgid " My Account" msgstr "Mein Konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Paketaktionen" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD ansehen" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Änderungen betrachten" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Schnappschuss herunterladen" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Durchsuche Wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Als \"veraltet\" markiert" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Paket als \"veraltet\" markieren" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Paketmarkierung entfernen" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Stimme entfernen" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Für dieses Paket stimmen" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Benachrichtigungen deaktivieren" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Über neue Kommentare benachrichtigen" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Verwalte Ko-Maintainer" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d ausstehende Anfrage" msgstr[1] "%d ausstehende Anfragen" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Paket löschen" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Paket verschmelzen" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Paket übernehmen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "unbekannt" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Paketbasis Details" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "nur lesen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Schlüsselwörter" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Eingereicht von" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Betreuer" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Letzter Paketierer" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stimmen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Beliebtheit" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Zuerst eingereicht am" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Letzte Aktualisierung" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "Bearbeite Kommentar für: %s" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Kommentar hinzufügen" -msgid "Comment has been added." -msgstr "Kommentar wurde hinzugefügt." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Zeige alle Kommentare" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Neueste Kommentare" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "%s kommentierte %s" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "Anonym kommentierte %s" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "gelöscht am %s von %s" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "zuletzt geändert am %s von %s" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Kommentar löschen" -#, php-format -msgid "Comment by %s" -msgstr "Kommentar von %s" - -msgid "Anonymous comment" -msgstr "Anonymer Kommentar" - -msgid "deleted" -msgstr "gelöscht" - +#: template/pkg_comments.php msgid "All comments" msgstr "Alle Kommentare" +#: template/pkg_details.php msgid "Package Details" msgstr "Paket-Details" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paketbasis" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beschreibung" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Besuche die Web-Seite für" +#: template/pkg_details.php msgid "Licenses" msgstr "Lizenzen" +#: template/pkg_details.php msgid "Groups" msgstr "Gruppen" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikte" +#: template/pkg_details.php msgid "Provides" msgstr "Liefert" +#: template/pkg_details.php msgid "Replaces" msgstr "Ersetzt" +#: template/pkg_details.php msgid "Dependencies" msgstr "Abhängigkeiten" +#: template/pkg_details.php msgid "Required by" msgstr "Benötigt von" +#: template/pkg_details.php msgid "Sources" msgstr "Quellen" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Anfrage schließen: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Benutze dieses Formular, um die Anfrage für die Paketbasis %s%s%s zu " -"schließen." +msgstr "Benutze dieses Formular, um die Anfrage für die Paketbasis %s%s%s zu schließen." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Anmerkung" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Das Kommentarfeld kann leer gelassen werden, es wird jedoch strengstens " -"empfohlen, beim Ablehnen einer Anfrage einen Kommentar hinzuzufügen." +msgstr "Das Kommentarfeld kann leer gelassen werden, es wird jedoch strengstens empfohlen, beim Ablehnen einer Anfrage einen Kommentar hinzuzufügen." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Grund" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Akzeptiert" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Zurückgewiesen" -msgid "Comments" -msgstr "Kommentare" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Anfrage einreichen: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Benutze dieses Formular um eine Anfrage für die Paketbasis %s%s%s " -"einzureichen, welche die folgenden Pakete enthält:" +msgstr "Benutze dieses Formular um eine Anfrage für die Paketbasis %s%s%s einzureichen, welche die folgenden Pakete enthält:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Anfragetyp" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Löschung" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Verwaist" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Verschmelzen mit" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d Paket gefunden." msgstr[1] "%d Paketanfragen gefunden." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Seite %d von %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Eingereicht von" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d Tage verbleibend" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d Stunde verbleibend" msgstr[1] "~%d Stunden verbleibend" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 Stunde verbleibend" +#: template/pkgreq_results.php msgid "Accept" msgstr "Akzeptieren" +#: template/pkgreq_results.php msgid "Locked" msgstr "Gesperrt" +#: template/pkgreq_results.php msgid "Close" msgstr "Schließen" +#: template/pkgreq_results.php msgid "Closed" msgstr "Geschlossen" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Name, Beschreibung" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Nur Name" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Exakter Name" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Exakte Paketbasis" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Markiert" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nicht markiert" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Name" -msgid "Popularity" -msgstr "Beliebtheit" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Abgestimmt" -msgid "Age" -msgstr "Alter" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "Zuletzt geändert" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Aufsteigend" +#: template/pkg_search_form.php msgid "Descending" msgstr "Absteigend" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Suchkriterien eingeben" +#: template/pkg_search_form.php msgid "Search by" msgstr "Suche nach" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Veraltet" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortieren nach" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Neu ordnen" +#: template/pkg_search_form.php msgid "Per page" msgstr "Pro Seite" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Los" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Verwaiste Pakete" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fehler beim Aufrufen der Paket-Liste." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Keine Pakete entsprachen deinen Suchkriterien." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d Paket gefunden." msgstr[1] "%d Pakete gefunden." +#: template/pkg_search_results.php msgid "Version" msgstr "Version" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"Die Beliebtheit berechnet sich als Summe aller Stimmen, wobei jede Stimme " -"mit einem Faktor von 0,98 pro Tag seit der Erstellung gewichtet wird." +msgstr "Die Beliebtheit berechnet sich als Summe aller Stimmen, wobei jede Stimme mit einem Faktor von 0,98 pro Tag seit der Erstellung gewichtet wird." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "Verwaist" +#: template/pkg_search_results.php msgid "Actions" msgstr "Aktionen" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Als \"veraltet\" markieren" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "\"veraltet\"-Markierung entfernen" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Pakete übernehmen" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Betreuung der Pakete abgeben" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Pakete löschen" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Bestätige" +#: template/search_accounts_form.php msgid "Any type" msgstr "Beliebiger Typ" +#: template/search_accounts_form.php msgid "Search" msgstr "Suche" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiken" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Verwaiste Pakete" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakete, die in den letzten 7 Tagen hinzugefügt wurden" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakete, die in den letzten 7 Tagen aktualisiert wurden" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakete, die im letzten Jahr aktualisiert wurden" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pakete, die nie aktualisiert wurden" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrierte Benutzer" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Vertrauenswürdige Benutzer (TU)" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Letzte Aktualisierungen" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Meine Statistiken" -msgid "Packages in unsupported" -msgstr "Pakete in \"unsupported\"" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Vorschlag-Details" +#: template/tu_details.php msgid "This vote is still running." msgstr "Diese Abstimmung läuft noch." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Eingereicht: %s von %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Ende" +#: template/tu_details.php msgid "Result" msgstr "Ergebnis" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nein" +#: template/tu_details.php msgid "Abstain" msgstr "Enthalten" +#: template/tu_details.php msgid "Total" msgstr "Insgesamt" +#: template/tu_details.php msgid "Participation" msgstr "Teilnahme" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Letzte Stimme vom TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Letzte Stimme" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Keine Ergebnisse gefunden" +#: template/tu_list.php msgid "Start" msgstr "Beginn" +#: template/tu_list.php msgid "Back" msgstr "Zurück" diff --git a/po/el.po b/po/el.po index 6e613df9..d869ec23 100644 --- a/po/el.po +++ b/po/el.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Achilleas Pipinellis, 2014 # Achilleas Pipinellis, 2013 @@ -14,1344 +14,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" -"Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: el\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Η σελίδα δε βρέθηκε" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Μας συγχωρείτε, η σελίδα που ζητήσατε δεν υπάρχει." +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "Λογαριασμοί" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Δεν σας επιτρέπεται η πρόσβαση σε αυτήν την περιοχή." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Δεν ήταν δυνατή η λήψη πληροφοριών για αυτόν τον χρήστη." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Δεν έχετε την άδεια να επεξεργαστείτε αυτόν τον λογαριασμό." +#: html/account.php msgid "Use this form to search existing accounts." -msgstr "" -"Χρησιμοποιήστε αυτή τη φόρμα για να αναζητήσετε υπάρχοντες λογαριασμούς." +msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να αναζητήσετε υπάρχοντες λογαριασμούς." +#: html/account.php msgid "You must log in to view user information." msgstr "Πρέπει να συνδεθείτε για να δείτε πληροφορίες χρήστη." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Προσθέστε Πρόταση" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Μη έγκυρο διακριτικό για την ενέργεια του χρήστη." +#: html/addvote.php msgid "Username does not exist." msgstr "Αυτό το όνομα χρήστη δεν υπάρχει." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s έχει ήδη πρόταση σε εξέλιξη για αυτό το θέμα." +#: html/addvote.php msgid "Invalid type." msgstr "Άκυρος τύπος." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Η πρόταση δεν μπορεί να είναι κενή." +#: html/addvote.php msgid "New proposal submitted." msgstr "Υποβλήθηκε νέα πρόταση." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Υποβάλετε μία πρόταση προς ψήφιση." +#: html/addvote.php msgid "Applicant/TU" msgstr "Αιτών / TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(κενό εάν δεν είναι εφαρμόσιμο)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Είδος" +#: html/addvote.php msgid "Addition of a TU" msgstr "Προσθήκη ενός TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Αφαίρεση ενός TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Αφαίρεση ενός TU (αδήλωτη αδράνεια)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Τροποποίηση των " +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Πρόταση" +#: html/addvote.php msgid "Submit" msgstr "Υποβολή" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Αρχική" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Καλωσήρθατε στο AUR! Διαβάστε παρακαλώ τον %sOδηγό Χρηστών του AUR%s και τον " -"%sΟδηγό των Trusted Users%s για περισσότερες πληροφορίες. " +msgstr "Καλωσήρθατε στο AUR! Διαβάστε παρακαλώ τον %sOδηγό Χρηστών του AUR%s και τον %sΟδηγό των Trusted Users%s για περισσότερες πληροφορίες. " +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Τα συνεισφέροντα PKGBUILDs %sπρέπει%s να ακολουθούν τα %sΠρότυπα δημιουργίας " -"πακέτων του Arch%s αλλιώς θα διαγράφονται! " +msgstr "Τα συνεισφέροντα PKGBUILDs %sπρέπει%s να ακολουθούν τα %sΠρότυπα δημιουργίας πακέτων του Arch%s αλλιώς θα διαγράφονται! " +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Θυμηθείτε να ψηφίσετε τα αγαπημένα σας πακέτα!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Ορισμένα πακέτα μπορεί να μεταφερθούν ως binaries στο [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ΑΠΟΠΟΙΗΣΗ ΕΥΘΥΝΗΣ" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Τα πακέτα στο \"Unsupported\" έχουν περιεχόμενο που παρέχεται απο τους " -"χρήστες. Χρησιμοποιήστε τα με δική σας ευθύνη." +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Συζήτηση" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Αναφορά Σφαλμάτων" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Αναζήτηση Πακέτου" +#: html/index.php msgid "Adopt" msgstr "Υιοθέτηση" +#: html/index.php msgid "Vote" msgstr "Ψηφίστε" +#: html/index.php msgid "UnVote" msgstr "Αναίρεση ψήφου" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Ειδοποίηση" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Διακοπή Ειδοποίησης" -msgid "Flag" -msgstr "Επισήμανση" - +#: html/index.php msgid "UnFlag" msgstr "Αποχαρακτήριση" +#: html/login.php template/header.php msgid "Login" msgstr "Σύνδεση" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Έχετε συνδεθεί ως: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Αποσύνδεση" +#: html/login.php msgid "Enter login credentials" msgstr "Εισάγετε πιστοποιητικά εισόδου" -msgid "Username" -msgstr "Όνομα χρήστη" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Κωδικός" +#: html/login.php msgid "Remember me" msgstr "Θυμήσου με" +#: html/login.php msgid "Forgot Password" msgstr "Ξεχάσατε τον κωδικό σας" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Το HTTP είναι απενεργοποιημένο. Παρακαλώ %sγυρίστε σε HTTPs%s αν θέλετε να " -"εισέλθετε." +msgstr "Το HTTP είναι απενεργοποιημένο. Παρακαλώ %sγυρίστε σε HTTPs%s αν θέλετε να εισέλθετε." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Κριτήρια Αναζήτησης" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Πακέτα" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Σφάλμα στη διαδικασία λήψης των πληροφοριών του πακέτου." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Λείπει ένα απαραίτητο πεδίο." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." -msgstr "" -"Οι τιμές που εισαγάγατε στα πεδία “κωδικού” και “επιβεβαίωσης κωδικού” δεν " -"είναι ίδιες." +msgstr "Οι τιμές που εισαγάγατε στα πεδία “κωδικού” και “επιβεβαίωσης κωδικού” δεν είναι ίδιες." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Ο κωδικός πρέπει να αποτελείται τουλάχιστον %s χαρακτήρες." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Μη έγκυρο e-mail." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Επαναφορά Κωδικού" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Ελέγξτε το e-mail σας για το σύνδεσμο επιβεβαίωσης." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Το συνθηματικό σας έχει επαναφερθεί με επιτυχία." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Παρακαλώ επιβεβαιώστε την διεύθυνση e-mail σας:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Εισάγετε νέο κωδικό" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Επιβεβαιώστε το νέο σας συνθηματικό:" +#: html/passreset.php msgid "Continue" msgstr "Συνεχίστε" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Εάν έχετε ξεχάσει την ηλεκτρονική διεύθυνση που χρησιμοποιήσατε για να " -"εγγραφείτε, παρακαλώ στείλτε ένα μήνυμα στη λίστα ταχυδρομείου %saur-general" -"%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Εάν έχετε ξεχάσει την ηλεκτρονική διεύθυνση που χρησιμοποιήσατε για να εγγραφείτε, παρακαλώ στείλτε ένα μήνυμα στη λίστα ταχυδρομείου %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Εισάγετε την διεύθυνση e-mail σας:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Δεν μπορεί να βρεθεί το πακέτο για τη συγχώνευση ψήφων και σχόλιων" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Τα επιλεγμένα πακέτα δεν έχουν διαγραφεί, παρακαλώ ελέγξτε το κουτάκι " -"επιβεβαίωσης." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Τα επιλεγμένα πακέτα δεν έχουν διαγραφεί, παρακαλώ ελέγξτε το κουτάκι επιβεβαίωσης." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Διαγραφή Πακέτου" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Διαγράψτε Πακέτο: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Η διαγραφή ενός πακέτου είναι μόνιμη." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Επιλέξτε το κουτάκι για να επιβεβαιώσετε." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Επιβεβαιώστε τη διαγραφή του πακέτου" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Διαγράψτε" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Μόνο οι Trusted Users και οι Developers μπορούν να διαγράψουν πακέτα." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Aποδεσμεύστε το Πακέτο" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "Αποδέσμευση" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Επισήμανση" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Συγχώνευση Πακέτου" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Συγχώνευσε Πακέτο: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Μόλις το πακέτο συγχωνευτεί, η διαδικασία δεν μπορεί να αντιστραφεί." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Εισάγετε το όνομα του πακέτου με το οποίο επιθυμείτε να συγχωνεύσετε το " -"τρέχον πακέτο." +msgstr "Εισάγετε το όνομα του πακέτου με το οποίο επιθυμείτε να συγχωνεύσετε το τρέχον πακέτο." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Συγχωνεύστε σε:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Επιβεβαιώστε τη συγχώνευση του πακέτου" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Συγχώνευση" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Μόνο οι Trusted Users και οι Developers μπορούν να συγχωνεύσουν πακέτα." +msgstr "Μόνο οι Trusted Users και οι Developers μπορούν να συγχωνεύσουν πακέτα." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Πρώτο" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Προηγούμενο" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Επόμενο" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Τελευταίο" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "Εγγραφείτε" +#: html/register.php msgid "Use this form to create an account." msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να δημιουργήσετε λογαριασμό." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Δεν ήταν δυνατή η ανάκτηση των στοιχείων της πρότασης." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Η ψηφοφορία έχει κλείσει για αυτή την πρόταση." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Μόνο οι Trusted Users έχουν δικαίωμα ψήφου." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Δεν μπορείτε να ψηφίσετε σε μία πρόταση που αφορά σε εσάς." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Έχετε ήδη ψηφίσει για αυτή τη πρόταση." +#: html/tu.php msgid "Vote ID not valid." msgstr "Το ID της ψήφου δεν είναι έγκυρο." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Τρέχουσες ψήφοι" +#: html/tu.php msgid "Past Votes" msgstr "Παρελθόντες ψήφοι" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Ψηφίσαντες" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Η εγγραφή λογαριασμών έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω " -"επιθέσεων spam. Μας συγχωρείτε για την ενόχληση." +msgstr "Η εγγραφή λογαριασμών έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω επιθέσεων spam. Μας συγχωρείτε για την ενόχληση." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Λείπει το ID Χρήστη" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Το όνομα χρήστη δεν είναι έγκυρο." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Πρέπει να αποτελείται από %s έως %s χαρακτήρες" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Ξεκινήστε και τελειώστε με γράμμα ή αριθμό" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Μπορεί να περιλαμβάνει μόνο μία τελεία, κάτω παύλα ή παύλα." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Αυτή η διεύθυνση email δεν είναι έγκυρη." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Το fingerprint του PGP κλειδιού δεν είναι έγκυρο." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Δε γίνεται να αυξηθούν τα δικαιώματα του λογαριασμού" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Η γλώσσα αυτή δεν υποστηρίζεται ακόμη." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Το όνομα, %s%s%s, χρησιμοποιείται ήδη." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Η διεύθυνση, %s%s%s, χρησιμοποιείται ήδη." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Σφάλμα κατά τη δημιουργία του λογαριασμού, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Ο λογαριασμός, %s%s%s, δημιουργήθηκε επιτυχώς." -msgid "Click on the Login link above to use your account." -msgstr "" -"Πατήστε στον παραπάνω σύνδεσμο Σύνδεση για να χρησιμοποιήσετε το λογαριασμό " -"σας." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Καλώς ήρθατε στο %s! Για να ορίσετε έναν αρχικό κωδικό για το νέο σας " -"λογαριασμό, παρακαλώ πατήστε τον παρακάτω σύνδεσμο. Αν ο σύνδεσμος δε " -"δουλέψει προσπαθήστε να τον κάνετε αντιγραφή και επικόλληση στον browser σας." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Ένα κλειδί επαναφοράς του κωδικού έχει σταλεί στην ηλεκτρονική σας διεύθυνση." +msgstr "Ένα κλειδί επαναφοράς του κωδικού έχει σταλεί στην ηλεκτρονική σας διεύθυνση." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Πατήστε στον παραπάνω σύνδεσμο Σύνδεση για να χρησιμοποιήσετε το λογαριασμό σας." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Δεν έγιναν αλλαγές στο λογαριασμό, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Ο λογαριασμός, %s%s%s, τροποποποιήθηκε επιτυχώς." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Η σύνδεση στο λογαριασμό σας έχει απενεργοποιηθεί για την IP σας, πιθανόν " -"λόγω επιθέσεων spam. Μας συγχωρείτε για την ταλαιπωρία." +msgstr "Η σύνδεση στο λογαριασμό σας έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω επιθέσεων spam. Μας συγχωρείτε για την ταλαιπωρία." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Ο λογαριασμός έχει ανασταλεί" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Η επαναφορά του κωδικού σας έχει πραγματοποιηθεί. Αν μόλις δημιουργήσατε ένα " -"νέο λογαρισμό, παρακαλώ χρησιμοποιείστε τον σύνδεσμο από το email " -"ενεργοποίησης για να ορίσετε έναν αρχικό κωδικό. Διαφορετικά, παρακαλείσθε " -"να ζητήσετε ένα κλειδί επαναφοράς στη σελίδα %sPassword Reset%s." +msgstr "Η επαναφορά του κωδικού σας έχει πραγματοποιηθεί. Αν μόλις δημιουργήσατε ένα νέο λογαρισμό, παρακαλώ χρησιμοποιείστε τον σύνδεσμο από το email ενεργοποίησης για να ορίσετε έναν αρχικό κωδικό. Διαφορετικά, παρακαλείσθε να ζητήσετε ένα κλειδί επαναφοράς στη σελίδα %sPassword Reset%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Λάθος όνομα χρήστη ή συνθηματικό." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ένα σφάλμα προέκυψε προσπαθώντας να δημιουργήσετε μια συνεδρία χρήστη." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Μη έγκυρο e-mail και συνδυασμός κλειδιού επαναφοράς" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Κανένα" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Δείτε τις πληροφορίες λογαριασμού του %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Το σχόλιο έχει προστεθεί." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Σφάλμα κατά τη διάρκεια φόρτωσης των πληροφοριών του πακέτου." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Οι πληροφορίες του πακέτου δεν μπόρεσαν να βρεθούν." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Πρέπει να έχετε συνδεθεί για να επισημάνετε τα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Δεν επιλέξατε κάποιο πακέτο για επισήμανση." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Τα συγκεκριμένα πακέτα έχουν επισημανθεί ως παρωχημένα." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να αποχαρακτηρίσετε πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Δεν επιλέξατε κάποιο πακέτο για να αποχαρακτηρίσετε." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Τα συγκεκριμένα πακέτα έχουν αποεπισημανθεί." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Δεν έχετε τα απαραίτητα δικαιώματα για να διαγράψετε τα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Δεν επιλέξατε κάποιο πακέτο για να διαγράψετε." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Tα επιλεγμένα πακέτα έχουν διαγραφεί." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να υιοθετήσετε πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να αποδεσμεύσετε πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Δεν επιλέξατε κανένα πακέτο για να υιοθετήσετε." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Δεν επιλέξατε κάποιο πακέτο για απόρριψη." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Τα επιλεγμένα πακέτα έχουν υιοθετηθεί." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Τα επιλεγμένα πακέτα έχουν αποδεσμευθεί." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να ψηφίσετε για πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "" -"Πρέπει να έχετε συνδεθεί για να μπορέσετε να ακυρώσετε την ψήφο σας για " -"πακέτα." +msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να ακυρώσετε την ψήφο σας για πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Δεν επιλέξατε κάποιο πακέτο για να το ψηφίσετε." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Οι ψήφοι σας έχουν αφαιρεθεί από τα επιλεγμένα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Οι ψήφοι σας προστέθηκαν στα επιλεγμένα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Δεν ήταν δυνατή η προσθήκη του στη λίστα ειδοποίησης." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Έχετε προστεθεί στη λίστα ειδοποίησης σχολίων για το %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Έχετε αφαιρεθεί από τη λίστα ειδοποίησης σχολίων για το %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Πρέπει να έχετε συνδεθεί για να προσπαθήσετε να επεξεργαστείτε τις " -"πληροφορίες του πακέτου." +msgstr "Πρέπει να έχετε συνδεθεί για να προσπαθήσετε να επεξεργαστείτε τις πληροφορίες του πακέτου." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Λείπει το ID του σχολίου." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Το σχόλιο έχει διαγραφεί." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Δεν σας επιτρέπεται να διαγράψετε αυτό το σχόλιο." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Δείτε τις λεπτομέρειες πακέτου για το" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Μη έγκυρο όνομα: μόνο πεζοί χαρακτήρες επιτρέπονται." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Όνομα χρήστη" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Είδος λογαριασμού" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Χρήστης" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Developer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Διεύθυνση email" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Πραγματικό 'Ονομα" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Ψευδώνυμο IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP Key Fingerprint" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Κατάσταση" +#: template/account_details.php msgid "Inactive since" msgstr "Αδρανής από" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Ενεργός" +#: template/account_details.php msgid "Last Login" msgstr "Τελευταία σύνδεση" +#: template/account_details.php msgid "Never" msgstr "Ποτέ" +#: template/account_details.php msgid "View this user's packages" msgstr "Δείτε τα πακέτα αυτού του χρήστη" +#: template/account_details.php msgid "Edit this user's account" msgstr "Τροποποιήστε το λογαριασμό αυτού του χρήστη" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "απαιτούμενο" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Απλός χρήστης" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Αξιόπιστος χρήστης" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Ο Λογαριασμός έχει Ανασταλεί." +#: template/account_edit_form.php msgid "Inactive" msgstr "Αδρανής" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Πληκτρολογήστε ξανά τον κωδικό σας." +#: template/account_edit_form.php msgid "Language" msgstr "Γλώσσα" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Eνημέρωση" +#: template/account_edit_form.php msgid "Create" msgstr "Δημιουργήστε" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Επαναφορά" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Δε βρέθηκε αποτέλεσμα που να ικανοποιεί τα κριτήρια αναζήτησης." +#: template/account_search_results.php msgid "Edit Account" msgstr "Τροποποίηση Λογαριασμού" +#: template/account_search_results.php msgid "Suspended" msgstr "Έχει ανασταλεί" +#: template/account_search_results.php msgid "Edit" msgstr "Επεξεργασία" +#: template/account_search_results.php msgid "Less" msgstr "Λιγότερο" +#: template/account_search_results.php msgid "More" msgstr "Περισσότερα" +#: template/account_search_results.php msgid "No more results to display." msgstr "Δεν υπάρχουν άλλα αποτελέσματα για να δείτε." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Τα πακέτα μου" +#: template/header.php msgid " My Account" msgstr "Ο λογαριασμός μου" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ενέργειες Πακέτου" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Δείτε το PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Επισημάνθηκε ως παρωχημένο" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Επισημάνετε ως παρωχημένο" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Αποχαρακτηρίστε ως παρωχημένο" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Αφαιρέστε ψήφο" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Ψηφίστε για αυτό το πακέτο" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Απενεργοποιήστε τις ειδοποιήσεις" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Ειδοποίησε για νέα σχόλια" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Διαγράψτε πακέτο" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Συγχώνευση πακέτου" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Υιοθετήστε το Πακέτο" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "άγνωστο" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Λέξεις κλειδιά" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Υποβάλλων" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Συντηρητής" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Ψήφοι" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Πρώτη Υποβολή" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Τελευταία Ενημέρωση" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Προσθέστε σχόλιο" -msgid "Comment has been added." -msgstr "Το σχόλιο έχει προστεθεί." - +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Τελευταία σχόλια" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Διαγράψτε το σχόλιο" -#, php-format -msgid "Comment by %s" -msgstr "Σχόλιο από %s" - -msgid "Anonymous comment" -msgstr "Ανώνυμο σχόλιο" - -msgid "deleted" -msgstr "" - +#: template/pkg_comments.php msgid "All comments" msgstr "Όλα τα σχόλια" +#: template/pkg_details.php msgid "Package Details" msgstr "Πληροφορίες Πακέτου" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Περιγραφή" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Επισκεφτείτε την ιστοσελίδα για " +#: template/pkg_details.php msgid "Licenses" msgstr "" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "" +#: template/pkg_details.php msgid "Replaces" msgstr "" +#: template/pkg_details.php msgid "Dependencies" msgstr "Εξαρτήσεις" +#: template/pkg_details.php msgid "Required by" msgstr "Απαιτείται από" +#: template/pkg_details.php msgid "Sources" msgstr "Πηγές" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Δεκτός" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Απορριπτέος" -msgid "Comments" -msgstr "" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Συγχώνευση σε" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Όνομα, Περιγραφή" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Όνομα μόνο" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Όλα" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Σημειωμένα" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Μη Σημειωμένα" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Όνομα" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Ψηφισμένο" -msgid "Age" -msgstr "Ηλικία" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Αύξουσα" +#: template/pkg_search_form.php msgid "Descending" msgstr "Φθίνουσα" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Εισάγετε κριτήρια αναζήτησης" +#: template/pkg_search_form.php msgid "Search by" msgstr "Αναζήτηση κατά" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Παρωχημένα" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ταξινόμηση κατά" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Σειρά ταξινόμησης" +#: template/pkg_search_form.php msgid "Per page" msgstr "Ανά σελίδα" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Πήγαινε" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Ορφανά" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Σφάλμα κατά τη λήψη της λίστας πακέτων." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Κανένα πακέτο δεν ικανοποιεί τα κριτήρια αναζήτησης σας." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +#: template/pkg_search_results.php msgid "Version" msgstr "Έκδοση" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ναι" +#: template/pkg_search_results.php msgid "orphan" msgstr "ορφανό" +#: template/pkg_search_results.php msgid "Actions" msgstr "Ενέργειες" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Επισημάνετε ως Παρωχημένο" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Αποχαρακτηρίστε το πακέτο ως Παρωχημένο" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Υιοθετήστε Πακέτα" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Aποδεσμεύστε Πακέτα" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Διαγράψτε Πακέτα" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Επιβεβαιώστε" +#: template/search_accounts_form.php msgid "Any type" msgstr "Κάθε είδος" +#: template/search_accounts_form.php msgid "Search" msgstr "Αναζήτηση" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Στατιστικά" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Ορφανά Πακέτα" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Πακέτα που προστέθηκαν τις τελευταίες 7 ημέρες" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Πακέτα που ενημερώθηκαν τις τελευταίες 7 ημέρες" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Πακέτα που ενημερώθηκαν κατά το παρελθόν έτος" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Πακέτα που δεν ενημερώθηκαν ποτέ" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Εγγεγραμμένοι Χρήστες" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Πρόσφατες Ανανεώσεις" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Τα στατιστικά μου" -msgid "Packages in unsupported" -msgstr "Μη υποστηριζόμενα πακέτα" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Πληροφορίες Πρότασης" +#: template/tu_details.php msgid "This vote is still running." msgstr "Η ψηφοφορία αυτή βρίσκεται ακόμη σε εξέλιξη." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Υποβλήθηκε: %s από %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Τέλος" +#: template/tu_details.php msgid "Result" msgstr "Αποτέλεσμα" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Όχι" +#: template/tu_details.php msgid "Abstain" msgstr "Απέχουν" +#: template/tu_details.php msgid "Total" msgstr "Σύνολο" +#: template/tu_details.php msgid "Participation" msgstr "Συμμετοχή" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Κανένα αποτέλεσμα δεν βρέθηκε." +#: template/tu_list.php msgid "Start" msgstr "Ξεκινήστε" +#: template/tu_list.php msgid "Back" msgstr "Πίσω" diff --git a/po/es.po b/po/es.po index 8861a548..77bb9992 100644 --- a/po/es.po +++ b/po/es.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Adolfo Jayme Barrientos, 2015 # Angel Velasquez , 2011 @@ -15,1400 +15,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-21 21:28+0000\n" -"Last-Translator: Pablo Roberto Francisco Lezaeta Reyes \n" -"Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" -"es/)\n" -"Language: es\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página no encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "La página solicitada no existe." +#: html/503.php msgid "Service Unavailable" msgstr "Servicio no disponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"¡No se asuste! El sitio está desactivado por tareas de mantenimiento. " -"Volveremos pronto." +msgstr "¡No te asustes! El sitio está desactivado por tareas de mantenimiento. Volveremos pronto." +#: html/account.php msgid "Account" msgstr "Cuenta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." -msgstr "No está autorizado a acceder a esta área." +msgstr "No estás autorizado para acceder a esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No se pudo obtener la información del usuario especificado." +#: html/account.php msgid "You do not have permission to edit this account." -msgstr "No tiene permisos para editar esta cuenta." +msgstr "No tienes los permisos para editar esta cuenta." +#: html/account.php msgid "Use this form to search existing accounts." -msgstr "Use este formulario para buscar cuentas existentes." +msgstr "Usa este formulario para buscar cuentas existentes." +#: html/account.php msgid "You must log in to view user information." -msgstr "Debe autentificarse para ver la información del usuario." +msgstr "Debes autentificarte para ver la información del usuario." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Añadir propuesta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "La ficha no es válida para la acción de usuario." +#: html/addvote.php msgid "Username does not exist." msgstr "El nombre de usuario no existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ya tiene una propuesta activa." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo no válido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta no puede estar vacía." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nueva propuesta enviada." +#: html/addvote.php msgid "Submit a proposal to vote on." -msgstr "Envíe una propuesta a la cual votar." +msgstr "Envía una propuesta a la cual votar." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/Usuario de confianza (TU)" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Agregar a un nuevo usuario de confianza" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remover a un usuario de confianza" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remover a un usuario de confianza (no declarado inactivo)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Enmienda a los Estatutos" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" +#: html/addvote.php msgid "Submit" msgstr "Subir" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Administrar coencargados" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Inicio" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"¡Bienvenido al repositorio de usuarios de Arch! Lea las %sDirectrices del " -"usuario del AUR%s y las %sDirectrices del usuario de confianza del AUR%s " -"para mayor información." +msgstr "¡Bienvenido al repositorio de usuarios de Arch! Léase las %sDirectrices del usuario del AUR%s y las %sDirectrices del usuario de confianza del AUR%s para mayor información." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de " -"empaquetado de Arch%s de otra forma serán eliminados." +msgstr "Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de empaquetado de Arch%s de otra forma serán eliminados." +#: html/home.php msgid "Remember to vote for your favourite packages!" -msgstr "¡Recuerde votar sus paquetes favoritos!" +msgstr "¡Recuerda votar tus paquetes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Algunos paquetes pueden estar provistos de forma binaria en [community]." +msgstr "Algunos paquetes pueden estar provistos de forma binaria en [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Los paquetes no soportados son producidos por los usuarios. Cualquier uso de " -"los archivos de estos es a su propio riesgo." +#: html/home.php msgid "Learn more..." msgstr "Más información…" +#: html/home.php msgid "Support" msgstr "Ayuda" +#: html/home.php msgid "Package Requests" msgstr "Solicitudes para los paquetes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Hay tres tipos de solicitudes que puede presentar en el cuadro %sAcciones " -"del paquete%s en la página de detalles del paquete:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Hay tres tipos de solicitudes que puedes presentar en el cuadro %sAcciones del paquete%s en la página de detalles del paquete:" +#: html/home.php msgid "Orphan Request" msgstr "Solicitud de orfandad" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está " -"inactivo y el paquete se ha marcado como desactualizado por un largo tiempo." +msgstr "Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está inactivo y el paquete se ha marcado como desactualizado por un largo tiempo." +#: html/home.php msgid "Deletion Request" msgstr "Solicitud de eliminación" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Solicitar la eliminación de un paquete del repositorio de usuarios de Arch. " -"No utilice esta opción si un paquete está roto pero puede ser arreglado " -"fácilmente. En cambio, contacte al encargado del paquete y presentar " -"solicitud orfandad si es necesario." +msgstr "Solicitar la eliminación de un paquete del repositorio de usuarios de Arch. No utilices esta opción si un paquete está roto pero puede ser arreglado fácilmente. En cambio, contacta al encargado del paquete y presenta una solicitud de orfandad si es necesario." +#: html/home.php msgid "Merge Request" msgstr "Solicitud de unión" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Solicitar que un paquete sea unido con otro. Puede ser utilizado cuando un " -"paquete tiene que ser cambiado de nombre o sustituido por un paquete " -"dividido." +msgstr "Solicitar que un paquete sea unido con otro. Puede ser utilizado cuando un paquete tiene que ser cambiado de nombre o sustituido por un paquete dividido." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Si quiere discutir una solicitud, puede utilizar la lista de correo %saur-" -"requests%s. Sin embargo, por favor no utilice esa lista para presentar " -"solicitudes." +msgstr "Si quieres discutir una solicitud, puedes utilizar la lista de correo %saur-requests%s. Sin embargo, por favor no utilices esa lista para presentar solicitudes." +#: html/home.php msgid "Submitting Packages" msgstr "Subir paquetes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Ahora se utiliza Git sobre SSH para subir paquetes al AUR. Vea la sección " -"%sSubir paquetes%s de la wiki del repositorio de usuarios de Arch para más " -"detalles." +msgstr "Ahora se utiliza Git sobre SSH para subir paquetes al AUR. Véase la sección %sSubir paquetes%s de la wiki del repositorio de usuarios de Arch para más detalles." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Las siguientes huellas SSH están en uso para AUR." +#: html/home.php msgid "Discussion" msgstr "Debate" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"La discusión general sobre el repositorio de usuarios de Arch (AUR) y la " -"estructura de usuarios de confianza se realiza en la lista de correos %saur-" -"general%s. Para la discusión en relación con el desarrollo de la interfaz " -"web del AUR, utilice la lista de correo %saur-dev%s." +msgstr "La discusión general sobre el repositorio de usuarios de Arch (AUR) y la estructura de usuarios de confianza se realiza en la lista de correos %saur-general%s. Para la discusión en relación con el desarrollo de la interfaz web del AUR, utiliza la lista de correo %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Informe de errores" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Si encuentra un error en la interfaz web del AUR, llene un informe de error " -"en nuestro %srastreador de errores o «bug tracker»%s. Use este para reportar " -"%súnicamente%s errores del AUR. Para reportar errores de empaquetado debe " -"contactar al encargado o deje un comentario en la página respectiva del " -"paquete." +#: html/home.php msgid "Package Search" msgstr "Buscar paquetes" +#: html/index.php msgid "Adopt" msgstr "Adoptar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Retirar voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Quitar notificación" -msgid "Flag" -msgstr "Marcar" - +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" -msgstr "Autentificarse" +msgstr "Autentificarte" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificado como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Salir" +#: html/login.php msgid "Enter login credentials" -msgstr "Proporcione sus datos de acceso" +msgstr "Proporciona tus datos de acceso" -msgid "Username" -msgstr "Nombre de usuario" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" +#: html/login.php msgid "Remember me" msgstr "Recordarme" +#: html/login.php msgid "Forgot Password" -msgstr "¿Olvidó su contraseña?" +msgstr "¿Olvidaste tu contraseña?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"La autentificación por HTTP está deshabilitada. %scambie a HTTPS%s si desea " -"autentificarse" +msgstr "La autentificación por HTTP está deshabilitada. %scambia a HTTPS%s si deseas autentificarte" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criterio de búsqueda" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "No se pudieron recuperar correctamente los detalles del paquete." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campo obligatorio." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Los campos de la contraseña no coinciden." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." -msgstr "Su contraseña debe tener como mínimo %s letras." +msgstr "Tu contraseña debe tener como mínimo %s letras." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Dirección de correo no válida." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Una solicitud de restablecimiento de contraseña se presentó para la cuenta " -"%s asociado a su dirección de correo electrónico. Si desea restablecer su " -"contraseña siga el enlace de abajo, si no ignore este mensaje y no pasará " -"nada." - +#: html/passreset.php msgid "Password Reset" msgstr "Restablecer la contraseña" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "Compruebe su correo para ver el enlace de confirmación." +msgstr "Comprueba tu correo para ver el enlace de confirmación." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Se ha restablecido la contraseña correctamente." +#: html/passreset.php msgid "Confirm your e-mail address:" -msgstr "Confirme su dirección de correo:" +msgstr "Confirma tu dirección de correo:" +#: html/passreset.php msgid "Enter your new password:" -msgstr "Escriba su contraseña nueva:" +msgstr "Escribe tu contraseña nueva:" +#: html/passreset.php msgid "Confirm your new password:" -msgstr "Confirme la contraseña nueva:" +msgstr "Confirma la contraseña nueva:" +#: html/passreset.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje " -"a la %slista de correo aur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si olvidaste la dirección de correo que usaste para registrarte, envía un mensaje a la %slista de correo aur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" -msgstr "Introduzca su dirección de correo:" +msgstr "Introduce tu dirección de correo:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Los paquetes seleccionados no se han abandonado, marque la casilla de " -"confirmación." +msgstr "Los paquetes seleccionados no se han abandonado, marca la casilla de confirmación." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"No se puede encontrar el paquete para unir los votos y comentarios en él." +msgstr "No se puede encontrar el paquete para unir los votos y comentarios en él." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "No se puede unir un paquete base consigo mismo." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Los paquetes seleccionados no han sido eliminados, compruebe la casilla de " -"confirmación." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Los paquetes seleccionados no han sido eliminados, comprueba la casilla de confirmación." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminación de paquetes" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Eliminar paquete: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Use este formulario para eliminar el paquete base %s%s%s y los siguientes " -"paquetes en el AUR:" +msgstr "Usa este formulario para eliminar el paquete base %s%s%s y los siguientes paquetes en el AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El eliminado de un paquete es permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Selecciona la casilla para confirmar la acción." +#: html/pkgdel.php msgid "Confirm package deletion" -msgstr "Confirme la eliminación del paquete" +msgstr "Confirma la eliminación del paquete" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Eliminar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Solamente usuarios de confianza y desarrolladores pueden eliminar paquetes." +msgstr "Solamente usuarios de confianza y desarrolladores pueden eliminar paquetes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar paquete" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Abandonar paquete: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Utilice este formulario para abandonar el paquete base %s %s %s que incluye " -"los siguientes paquetes:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Utiliza este formulario para abandonar el paquete base %s %s %s que incluye los siguientes paquetes:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Al seleccionar la casilla de verificación, confirma que desea abandonar el " -"paquete y transferir su propiedad a %s%s%s." +msgstr "Al seleccionar la casilla de verificación, confirmas que deseas abandonar el paquete y transferir su propiedad a %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Al seleccionar la casilla de verificación, confirma que desea abandonar el " -"paquete." +msgstr "Al seleccionar la casilla de verificación, confirmas que deseas abandonar el paquete." +#: html/pkgdisown.php msgid "Confirm to disown the package" -msgstr "Confirme para abandonar el paquete" +msgstr "Confirma para abandonar el paquete" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Solamente usuarios de confianza y desarrolladores puede forzar el abandono " -"de paquetes." +msgstr "Solamente usuarios de confianza y desarrolladores puede forzar el abandono de paquetes." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Comentario" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Marcar" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Unión de paquetes" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Unir paquete: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Este formulario es para unir el paquete base %s%s%s en otro paquete." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Los siguientes paquetes serán eliminados:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vez unido el paquete este no puede ser separado." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Introduzca el nombre del paquete que desea unir." +msgstr "Introduce el nombre del paquete que deseas unir." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Unir dentro:" +#: html/pkgmerge.php msgid "Confirm package merge" -msgstr "Confirmar unión de paquetes" +msgstr "Confirma la unión de paquetes" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Unión" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Solamente usuarios de confianza y desarrolladores pueden unir paquetes." +msgstr "Solamente usuarios de confianza y desarrolladores pueden unir paquetes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Solicitud para el paquete" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Cerrar solicitud" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Solicitud" +#: html/register.php template/header.php msgid "Register" msgstr "Registro" +#: html/register.php msgid "Use this form to create an account." -msgstr "Use este formulario para crear una cuenta." +msgstr "Usa este formulario para crear una cuenta." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuario de confianza" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No se han podido recuperar los detalles de la propuesta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Las votaciones para esta propuesta están cerradas." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solamente usuarios de confianza pueden votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." -msgstr "No puede votar en una propuesta sobre usted." +msgstr "No puedes votar en una propuesta sobre ti." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ya ha votado en esta propuesta." +#: html/tu.php msgid "Vote ID not valid." msgstr "El identificador del voto no es válido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" +#: html/tu.php msgid "Past Votes" msgstr "Últimos votos" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El registro de nuevas cuentas está desabilitado para su dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdone los " -"inconvenientes" +msgstr "El registro de nuevas cuentas está desabilitado para tu dirección IP, probablemente debido a numerosos ataque de correo basura. Perdona los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta el identificador de usuario" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nombre de usuario no es válido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Debe tener entre %s y %s letras" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comenzar y acabar con una letra o número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Solamente puede contener un punto, guion bajo o guion." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave pública SSH no es válida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No se puede incrementar los permisos de la cuenta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La dirección, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error tratando de crear la cuenta, %s%s%s" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, fue creada satisfactoriamente." -msgid "Click on the Login link above to use your account." -msgstr "Pulse en el enlace de acceso anterior para utilizar la cuenta." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"¡Bienvenido/a a %s! En orden para crear su contraseña para su nueva cuenta, " -"haga clic en el enlace inferior. Si este no funciona, copie y pegue este en " -"la barra de direcciones de su navegador web." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Se envió una clave de restablecimiento de contraseña a su dirección de " -"correo electrónico." +msgstr "Se envió una clave de restablecimiento de contraseña a tu dirección de correo electrónico." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Pulsa en el enlace de acceso anterior para utilizar la cuenta." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No se realizaron cambios a la cuenta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, fue modificada satisfactoriamente" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El formulario de registro ha sido deshabilitado para su dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdone los " -"inconvenientes" +msgstr "El formulario de registro ha sido deshabilitado para tu dirección IP, probablemente debido a numerosos ataque de correo basura. Perdona los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Su contraseña ha sido reiniciada, si creó una nueva cuenta, utilice el " -"enlace inferior para confirmar el correo y así crear su contraseña inicial. " -"En caso contrario, pida una reinicio de contraseña en la página para " -"%sReiniciar las contraseñas%s." +msgstr "Tu contraseña ha sido reinicializada, si creaste una nueva cuenta, utiliza el enlace inferior para confirmar el correo y así crear tu contraseña inicial. En caso contrario, pide un reinicialización de contraseña en la página para %sReinicializar las contraseñas%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Contraseña o nombre de usuario erróneos." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Un error ocurrió intentando generar la sesión." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." -msgstr "Combinación de dirección de correo y clave no válida." +msgstr "Combinación de dirección de correo y clave no válidos." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nada" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver información de la cuenta para %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Se ha añadido el comentario." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Los detalles del paquete no se han podido encontrar." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." -msgstr "Debe autentificarse antes de poder marcar paquetes." +msgstr "Debes autentificarte antes de poder marcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." -msgstr "No seleccionó ningún paquete para marcar." +msgstr "No seleccionaste ningún paquete a marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Los paquetes seleccionados han sido marcados como desactualizados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "Debe autentificarse antes de poder desmarcar paquetes." +msgstr "Debes autentificarte antes de poder desmarcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." -msgstr "No seleccionó ningún paquete para desmarcar." +msgstr "No seleccionaste ningún paquete a desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Los paquetes seleccionados han sido desmarcados." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." -msgstr "No posee los permisos para eliminar paquetes." +msgstr "No posees los permisos para eliminar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." -msgstr "No seleccionó ningún paquete para eliminar." +msgstr "No seleccionaste ningún paquete a eliminar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Los paquetes seleccionados se han eliminado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." -msgstr "Debe autentificarse antes de poder adoptar paquetes." +msgstr "Debes autentificarte antes de poder adoptar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." -msgstr "Debe autentificarse antes de poder abandonar paquetes." +msgstr "Debes autentificarte antes de poder abandonar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." -msgstr "No ha seleccionado ningún paquete para ser adoptado." +msgstr "No haz seleccionado ningún paquete para ser adoptado." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." -msgstr "No seleccionó ningún paquete para ser abandonado." +msgstr "No seleccionaste ningún paquete para ser abandonado." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Los paquetes seleccionados han sido adoptados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Los paquetes seleccionados han sido abandonados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." -msgstr "Debe autentificarse antes de poder votar paquetes." +msgstr "Debes autentificarte antes de poder votar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "Debe autentificarse antes de poder quitar votos a los paquetes" +msgstr "Debes autentificarte antes de poder quitar votos a los paquetes" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." -msgstr "No seleccionó ningún paquete para votarlo." +msgstr "No seleccionaste ningún paquete a votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." -msgstr "Sus votos han sido eliminados de los paquetes seleccionados." +msgstr "Tus votos han sido eliminados de los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." -msgstr "Sus votos han sido computados para los paquetes seleccionados." +msgstr "Tus votos han sido computados para los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No se pudo añadir a la lista de notificaciones." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "Ha sido añadido a la lista de notificaciones de comentarios de %s." +msgstr "Haz sido añadido a la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "Ha sido eliminado de la lista de notificaciones de comentarios de %s." +msgstr "Haz sido eliminado de la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "Debe autentificarse antes de editar la información del paquete." +msgstr "Debes autentificarte antes de editar la información del paquete." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Falta el identificador del comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Comentario eliminado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." -msgstr "No está autorizado a eliminar este comentario." +msgstr "No estás autorizado para eliminar este comentario." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "No está autorizado a editar las palabras clave de este paquete base." +msgstr "No estás autorizado para editar las palabras clave de este paquete base." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Las palabras clave del paquete base se han actualizado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "No se le permite administrar los coencargados de este paquete base." +msgstr "No se te permite administrar los coencargados de este paquete base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nombre de usuario no válido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Los coencargados del paquete base han sido actualizados." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles del paquete para" -msgid "You must be logged in to file package requests." -msgstr "Debe estar identificado para realizar solicitudes para el paquete." +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" +#: lib/pkgreqfuncs.inc.php +msgid "You must be logged in to file package requests." +msgstr "Debes estar identificado para realizar solicitudes para el paquete." + +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nombre no válido: solamente se permiten letras minúsculas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campo de comentarios no debe estar vacío." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de solicitud no válida." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Solicitud agregada con éxito." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón no válida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Solamente los usuarios de confianza y desarrolladores pueden cerrar una " -"solicitud." +msgstr "Solamente los usuarios de confianza y desarrolladores pueden cerrar una solicitud." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Solicitud cerrada exitosamente" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Puede usar este formulario para eliminar la cuenta de %s en AUR " -"permanentemente." +msgstr "Puedes usar este formulario para eliminar la cuenta de %s en AUR permanentemente." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVERTENCIA%s: Esta acción no puede deshacerse." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar borrado" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nombre de usuario" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de cuenta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuario" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desarrollador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Usuarios de confianza y desarrolladores" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Dirección de correo" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nombre real" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alias de IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Huella digital PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estado" +#: template/account_details.php msgid "Inactive since" msgstr "Inactivo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" +#: template/account_details.php msgid "Last Login" msgstr "Última autentificación" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Ver los paquetes de este usuario" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "Haga clic %saquí%s si desea eliminar permanentemente esta cuenta." +msgstr "Haz clic %saquí%s si deseas eliminar permanentemente esta cuenta." +#: template/account_edit_form.php msgid "required" msgstr "obligatorio" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuario normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuario de confianza" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivo" -msgid "Re-type password" -msgstr "Reescriba la contraseña" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Reescribe la contraseña" + +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La siguiente información únicamente es necesaria si desea subir paquetes al " -"repositorio de usuarios de Arch." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La siguiente información únicamente es necesaria si deseas subir paquetes al repositorio de usuarios de Arch." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave pública SSH" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Crear" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Limpiar" +#: template/account_search_results.php msgid "No results matched your search criteria." -msgstr "" -"No se encontraron resultados que coincidan con su criterio de búsqueda." +msgstr "No se encontraron resultados que coincidan con tu criterio de búsqueda." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar cuenta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendido" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Más" +#: template/account_search_results.php msgid "No more results to display." msgstr "No hay más resultados que mostrar." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Administrar coencargados: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Utilice este formulario para agregar coencargados para %s%s%s (un nombre de " -"usuario por línea):" +msgstr "Utiliza este formulario para agregar coencargados para %s%s%s (un nombre de usuario por línea):" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuarios" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Guardar" +#: template/header.php msgid "My Packages" msgstr "Mis paquetes" +#: template/header.php msgid " My Account" msgstr "Mi cuenta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Acciones del paquete" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver cambios" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Descargar instantánea" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Buscar en la wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marcado como desactualizado" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar paquete como desactualizado" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar paquete" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Eliminar voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar por este paquete" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Deshabilitar notificaciones" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "Hay %d solicitud pendiente" msgstr[1] "Hay %d solicitudes pendientes" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Eliminar paquete" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Unir paquete" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar paquete" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconocido" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Dirección URL de clonado con Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "Solamente lectura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palabras claves" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Primer encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Encargado" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularidad" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Fecha de creación" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualización" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Agregar comentario" -msgid "Comment has been added." -msgstr "Se ha añadido el comentario." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos los comentarios" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos comentarios" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Eliminar comentario" -#, php-format -msgid "Comment by %s" -msgstr "Comentario por %s" - -msgid "Anonymous comment" -msgstr "Comentario anónimo" - -msgid "deleted" -msgstr "eliminado" - +#: template/pkg_comments.php msgid "All comments" msgstr "Todos los comentarios" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Desarrollador principal" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita el sitio web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencias" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflictos" +#: template/pkg_details.php msgid "Provides" msgstr "Proveen" +#: template/pkg_details.php msgid "Replaces" msgstr "Remplazan" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencias" +#: template/pkg_details.php msgid "Required by" msgstr "Requerido por" +#: template/pkg_details.php msgid "Sources" msgstr "Fuentes" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Cerrar solicitud: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Use este formulario para cerrar la solicitud para el paquete base %s%s%s." +msgstr "Usa este formulario para cerrar la solicitud para el paquete base %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda " -"encarecidamente añadir un comentario al rechazar una solicitud." +msgstr "El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda encarecidamente añadir un comentario al rechazar una solicitud." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceptado" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rechazado" -msgid "Comments" -msgstr "Comentario" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Solicitud para el paquete: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Use este formulario para presentar una solicitud para el paquete base %s%s%s " -"el cual incluye los siguientes paquetes:" +msgstr "Usa este formulario para presentar una solicitud para el paquete base %s%s%s el cual incluye los siguientes paquetes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de solicitud" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Borrado" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfandad" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Unir en" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Se encontró %d solicitud para el paquete." msgstr[1] "Se encontraron %d solicitudes para el paquete." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Solicitado por" +#: template/pkgreq_results.php msgid "Date" msgstr "Fecha" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Aprox. %d días restantes" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Aprox. %d hora restante" msgstr[1] "Aprox. %d horas restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 hora restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceptar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloqueada" +#: template/pkgreq_results.php msgid "Close" msgstr "Cerrar" +#: template/pkgreq_results.php msgid "Closed" msgstr "Cerrada" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nombre, descripción" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Solamente nombre" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nombre exacto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exacto" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No marcados" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nombre" -msgid "Popularity" -msgstr "Popularidad" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" -msgid "Age" -msgstr "Antigüedad" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" +#: template/pkg_search_form.php msgid "Search by" msgstr "Buscar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Orden" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Huérfanos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Error al recuperar la lista de paquetes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ningún paquete coincide con su criterio de búsqueda." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquete fue encontrado." msgstr[1] "%d paquetes fueron encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versión" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"La popularidad se calcula como la suma de todos los votos con cada voto " -"ponderado con un factor de 0,98 por día desde la creación del paquete." +msgstr "La popularidad se calcula como la suma de todos los votos con cada voto ponderado con un factor de 0,98 por día desde la creación del paquete." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "huérfano" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acciones" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marcar como desactualizado" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Marcar como actualizado" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar paquetes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar paquetes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Eliminar paquetes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Cualquier tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Buscar" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes huérfanos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes añadidos en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes actualizados en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes actualizados el último año" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes que no han sido nunca actualizados" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios registrados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios de confianza" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizaciones recientes" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mis estadísticas" -msgid "Packages in unsupported" -msgstr "Paquetes no soportados" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalles de la propuesta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Aún se puede votar." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Subido: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Abstenerse" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participación" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Último voto del usuario de confianza" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No se han encontrado resultados." +#: template/tu_list.php msgid "Start" msgstr "Inicio" +#: template/tu_list.php msgid "Back" msgstr "Atrás" diff --git a/po/es_419.po b/po/es_419.po index 057e27c0..c0d8deca 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Angel Velasquez , 2011 # juantascon , 2011 @@ -13,1394 +13,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 22:12+0000\n" -"Last-Translator: Pablo Roberto Francisco Lezaeta Reyes \n" -"Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" -"aur/language/es_419/)\n" -"Language: es_419\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/aur/language/es_419/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: es_419\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página no encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Disculpe, la página que solicitó no existe." +#: html/503.php msgid "Service Unavailable" msgstr "Servicio no disponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"¡No se asustes! El sitio está desactivado por mantenimiento. Pronto " -"volveremos." +msgstr "¡No se asustes! El sitio está desactivado por mantenimiento. Pronto volveremos." +#: html/account.php msgid "Account" msgstr "Cuenta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No está autorizado a acceder a esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No se pudo obtener la información del usuario especificado." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "No tiene permisos para editar esta cuenta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Use este formulario para buscar cuentas existentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Debe autentificarse para ver la información del usuario." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Añadir propuesta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Elemento inválido para la acción del usuario." +#: html/addvote.php msgid "Username does not exist." msgstr "El nombre de usuario no existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ya tiene una propuesta activa." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo no válido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta no puede estar vacía." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nueva propuesta enviada." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Envíe una propuesta a la cual votar." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/Usuario de confianza (TU)" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Agregar a un nuevo usuario de confianza" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remover a un usuario de confianza" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remover a un usuario de confianza (no declarado inactivo)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Enmienda a las Bylaws (Reglas de los TU)" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" +#: html/addvote.php msgid "Submit" msgstr "Subir" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Administrar coencargados" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Inicio" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"¡Bienvenido al repositorio de usuarios de Arch! Lea la %sGuía del usuario " -"del AUR%s y la %sGuía del usuario de confianza del AUR%s para mayor " -"información." +msgstr "¡Bienvenido al repositorio de usuarios de Arch! Lea la %sGuía del usuario del AUR%s y la %sGuía del usuario de confianza del AUR%s para mayor información." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de " -"empaquetado de Arch%s de otra forma serán borrados." +msgstr "Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de empaquetado de Arch%s de otra forma serán borrados." +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerde votar sus paquetes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Algunos paquetes pueden estar disponibles de forma binaria en [community]." +msgstr "Algunos paquetes pueden estar disponibles de forma binaria en [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Los paquetes en AUR son producidos por los usuarios. Cualquier uso de ellos " -"o sus archivos es a su propio riesgo." +#: html/home.php msgid "Learn more..." msgstr "Aprenda más..." +#: html/home.php msgid "Support" msgstr "Soporte" +#: html/home.php msgid "Package Requests" msgstr "Peticiones para los paquetes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Existen tres tipos de peticiones que pueden presentarse en el recuadro " -"%sAcciones del paquete%s en la página de detalles del paquete:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Existen tres tipos de peticiones que pueden presentarse en el recuadro %sAcciones del paquete%s en la página de detalles del paquete:" +#: html/home.php msgid "Orphan Request" msgstr "Petición de Orfandad" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Pedir la orfandad de un paquete, por ejemplo, cuando el encargado está " -"inactivo y el paquete fue marcado como desactualizado un largo tiempo." +msgstr "Pedir la orfandad de un paquete, por ejemplo, cuando el encargado está inactivo y el paquete fue marcado como desactualizado un largo tiempo." +#: html/home.php msgid "Deletion Request" msgstr "Petición de Borrado" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Pedir que un paquete sea borrado del Repositorio Usuarios de Arch. Por " -"favor, no use esta opción si un paquete está roto y se puede arreglar " -"fácilmente. En cambio, contacte con el encargado del paquete y presentar " -"solicitud orfandad si es necesario." +msgstr "Pedir que un paquete sea borrado del Repositorio Usuarios de Arch. Por favor, no use esta opción si un paquete está roto y se puede arreglar fácilmente. En cambio, contacte con el encargado del paquete y presentar solicitud orfandad si es necesario." +#: html/home.php msgid "Merge Request" msgstr "Petición de Fusión" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Pedir que se fusione un paquete en otro. Puede usarla cuando un paquete " -"tiene que ser cambiado de nombre o sustituido por un paquete dividido." +msgstr "Pedir que se fusione un paquete en otro. Puede usarla cuando un paquete tiene que ser cambiado de nombre o sustituido por un paquete dividido." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Si quiere discutir una petición, puede usar la lista de correo %saur-" -"peticiones%s. Sin embargo, por favor no utilice esa lista para presentar " -"solicitudes." +msgstr "Si quiere discutir una petición, puede usar la lista de correo %saur-peticiones%s. Sin embargo, por favor no utilice esa lista para presentar solicitudes." +#: html/home.php msgid "Submitting Packages" msgstr "Subir paquetes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Ahora se usa Git sobre SSH para subir paquetes al AUR. Véase la sección " -"%sSubir paquetes%s de la wiki del Repositorio de Usuarios de Arch para más " -"información." +msgstr "Ahora se usa Git sobre SSH para subir paquetes al AUR. Véase la sección %sSubir paquetes%s de la wiki del Repositorio de Usuarios de Arch para más información." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Las siguientes huellas SSH están en uso para AUR." +#: html/home.php msgid "Discussion" msgstr "Debate" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"La discusión general acerca del Repositorio de Usuarios de Arch (AUR) y la " -"estructura de Usuarios de Confianza se realiza en la lista de correos %saur-" -"general%s. Para discusiones relacionadas con el desarrollo de la interfaz " -"web del AUR, utilice la lista de correo %saur-dev%s." +msgstr "La discusión general acerca del Repositorio de Usuarios de Arch (AUR) y la estructura de Usuarios de Confianza se realiza en la lista de correos %saur-general%s. Para discusiones relacionadas con el desarrollo de la interfaz web del AUR, utilice la lista de correo %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Informe de errores" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Si encuentra un error en la interfaz web del AUR, llene un informe de fallo " -"en nuestro %s«bug tracker»%s. Use este para reportar %súnicamente%s errores " -"del AUR. Para reportar errores de empaquetado debe contactar con el " -"encargado o dejar un comentario en la página respectiva del paquete." +#: html/home.php msgid "Package Search" msgstr "Buscar paquetes" +#: html/index.php msgid "Adopt" msgstr "Adoptar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Retirar voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Quitar notificación" -msgid "Flag" -msgstr "Marcar" - +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Autentificarse" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificado como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Salir" +#: html/login.php msgid "Enter login credentials" msgstr "Introduce las credenciales de autentificación" -msgid "Username" -msgstr "Nombre de usuario" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" +#: html/login.php msgid "Remember me" msgstr "Recordarme" +#: html/login.php msgid "Forgot Password" msgstr "Olvidó su cotraseña" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"La autentificación por HTTP está deshabilitada. %scambie a HTTPS%s si desea " -"autentificarse" +msgstr "La autentificación por HTTP está deshabilitada. %scambie a HTTPS%s si desea autentificarse" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criterio de búsqueda" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "No se pudieron recuperar los detalles del paquete." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campo obligatorio." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Los campos de la contraseña no coinciden." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Su contraseña debe tener como mínimo %s letras." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Dirección de correo no válida." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Una petición de restablecimiento de contraseña se presentó para la cuenta %s " -"asociado a su dirección de correo. Si desea restablecer su contraseña siga " -"el enlace de abajo, si no ignore este mensaje y no pasará nada." - +#: html/passreset.php msgid "Password Reset" msgstr "Reiniciar la contraseña" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Compruebe su correo para ver el enlace de confirmación." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Su contraseña ha sido reiniciada con éxito." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme su dirección de correo:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Ingrese su nueva contraseña:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme su nueva contraseña:" +#: html/passreset.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje " -"a la %slista de correo aur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje a la %slista de correo aur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduzca su dirección de correo:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Los paquetes seleccionados no fueron abandonados, marque la casilla de " -"confirmación." +msgstr "Los paquetes seleccionados no fueron abandonados, marque la casilla de confirmación." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"No se puede encontrar el paquete para fusionar sus votos y comentarios." +msgstr "No se puede encontrar el paquete para fusionar sus votos y comentarios." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "No se puede fusionar un paquete base consigo mismo." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Los paquetes seleccionados no se borraron, compruebe la casilla de " -"confirmación." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Los paquetes seleccionados no se borraron, compruebe la casilla de confirmación." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminación de paquetes" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Borrar paquete: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Use este formulario para borrar el paquete base %s%s%s y los siguientes " -"paquetes en el AUR:" +msgstr "Use este formulario para borrar el paquete base %s%s%s y los siguientes paquetes en el AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El borrado de un paquete es permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Selecciona la casilla para confirmar la acción." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirme el borrado del paquete" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Borrar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Solo Usuarios de Confianza y Desarrolladores pueden borrar paquetes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar paquete" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Abandonar paquete: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Use este formulario para abandonar el paquete base %s %s %s que incluye los " -"siguientes paquetes:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Use este formulario para abandonar el paquete base %s %s %s que incluye los siguientes paquetes:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Al seleccionar la casilla de verificación, confirma que desea abandonar el " -"paquete y transferir su propiedad a %s %s %s." +msgstr "Al seleccionar la casilla de verificación, confirma que desea abandonar el paquete y transferir su propiedad a %s %s %s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Al seleccionar la casilla de verificación, confirma que desea abandonar el " -"paquete." +msgstr "Al seleccionar la casilla de verificación, confirma que desea abandonar el paquete." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirme para abandonar el paquete" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Solo Usuarios de Confianza y Desarrolladores pueden forzar el abandono de " -"paquetes." +msgstr "Solo Usuarios de Confianza y Desarrolladores pueden forzar el abandono de paquetes." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Comentario" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Marcar" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusión de paquetes" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Fusionar paquete: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Este formulario es para fusionar el paquete base %s%s%s en otro paquete." +msgstr "Este formulario es para fusionar el paquete base %s%s%s en otro paquete." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Los siguientes paquetes serán borrados:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vez fusionado el paquete este no se puede separar." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduzca el nombre del paquete que desea fusionar." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionar dentro:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmar fusión de paquetes" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusión" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo Usuarios de Confianza y Desarrolladores pueden fusionar paquetes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Petición para el paquete" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Cerrar Petición" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Petición" +#: html/register.php template/header.php msgid "Register" msgstr "Registro" +#: html/register.php msgid "Use this form to create an account." msgstr "Use este formulario para crear una cuenta." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuario de Confianza" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No se han podido recuperar los detalles de la propuesta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Las votaciones para esta propuesta están cerradas." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solo Usuarios de Confianza pueden votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No puede votar en una propuesta sobre usted." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ya ha votado en esta propuesta." +#: html/tu.php msgid "Vote ID not valid." msgstr "El identificador del voto no es válido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" +#: html/tu.php msgid "Past Votes" msgstr "Últimos votos" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El registro de nuevas cuentas está desabilitado para su dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdone los " -"inconvenientes" +msgstr "El registro de nuevas cuentas está desabilitado para su dirección IP, probablemente debido a numerosos ataque de correo basura. Perdone los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta el identificador de usuario" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nombre de usuario no es válido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Debe tener entre %s y %s letras" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comenzar y acabar con una letra o número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Solo puede contener un punto, guion bajo o guion." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave pública SSH no es válida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No se puede incrementar los permisos de la cuenta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La dirección, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error tratando de crear la cuenta, %s%s%s" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, fue creada satisfactoriamente." -msgid "Click on the Login link above to use your account." -msgstr "Haz clic en el enlace de autentificación para usar su cuenta." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"¡Bienvenido/a a %s! En orden para crear su contraseña para su nueva cuenta, " -"haga clic en el enlace inferior. Si no funciona, copie y pegue el enlace en " -"la barra de direcciones de su navegador web." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Una llave para reiniciar su contraseña a sido enviada a su correo." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Haz clic en el enlace de autentificación para usar su cuenta." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No se realizaron cambios a la cuenta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, fue modificada satisfactoriamente" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El formulario de registro ha sido deshabilitado para su dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdone los " -"inconvenientes" +msgstr "El formulario de registro ha sido deshabilitado para su dirección IP, probablemente debido a numerosos ataque de correo basura. Perdone los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Su contraseña ha sido reiniciada, si creó una nueva cuenta, use el enlace " -"inferior para confirmar el correo y así crear su contraseña inicial. En caso " -"contrario, pida un reinicio de contraseña en la página para %sreiniciar las " -"contraseñas%s." +msgstr "Su contraseña ha sido reiniciada, si creó una nueva cuenta, use el enlace inferior para confirmar el correo y así crear su contraseña inicial. En caso contrario, pida un reinicio de contraseña en la página para %sreiniciar las contraseñas%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Contraseña o nombre de usuario erróneos." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Un error ocurrió intentando generar la sesión." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinación de dirección de correo y clave no válida." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nada" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver información de la cuenta para %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Se ha añadido el comentario." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Los detalles del paquete no se pudieron encontrar." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Debe autentificarse antes de poder marcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No seleccionó ningún paquete para marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Los paquetes seleccionados han sido marcados como desactualizados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Debe autentificarse antes de poder desmarcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No seleccionó ningún paquete para desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Los paquetes seleccionados han sido desmarcados." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No posee los permisos para borrar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No seleccionó ningún paquete para borrar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Los paquetes seleccionados se han borrado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Debe autentificarse antes de poder adoptar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Debe autentificarse antes de poder abandonar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No seleccionó ningún paquete para adoptar." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No seleccionó ningún paquete para ser abandonado." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Los paquetes seleccionados han sido adoptados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Los paquetes seleccionados han sido abandonados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Debe autentificarse antes de poder votar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Debe autentificarse antes de poder quitar votos a los paquetes" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No seleccionó ningún paquete para votarlo." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Sus votos han sido eliminados de los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Sus votos se añadieron a los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No se pudo añadir a la lista de notificaciones." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Ha sido añadido a la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Ha sido eliminado de la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Debe autentificarse antes de editar la información del paquete." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Falta el identificador del comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Comentario borrado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No está autorizado a borrar este comentario." -msgid "You are not allowed to edit the keywords of this package base." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." msgstr "" -"No está autorizado para editar las palabras clave de este paquete base." +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit the keywords of this package base." +msgstr "No está autorizado para editar las palabras clave de este paquete base." + +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Las palabras clave del paquete base actualizaron ." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "No tiene permitido administrar los coencargados de este paquete base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nombre de usuario no válido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Los coencargados del paquete base fueron actualizados." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles del paquete para" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Debe estar identificado para realizar peticiones para el paquete." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nombre no válido: solo se permiten letras minúsculas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campo de comentarios no debe estar vacío." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de petición no válida." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Petición agregada con éxito." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón no válida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Solo Usuarios de Confianza y Desarrolladores pueden cerrar una petición." +msgstr "Solo Usuarios de Confianza y Desarrolladores pueden cerrar una petición." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Petición cerrada exitosamente" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Puede usar este formulario para borrar la cuenta de %s en AUR " -"permanentemente." +msgstr "Puede usar este formulario para borrar la cuenta de %s en AUR permanentemente." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVERTENCIA%s: Esta acción no puede deshacerse." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar borrado" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nombre de usuario" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de cuenta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuario" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desarrollador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Usuarios de Confianza y desarrolladores" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Dirección de correo" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nombre real" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alias de IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Huella digital PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estado" +#: template/account_details.php msgid "Inactive since" msgstr "Inactivo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" +#: template/account_details.php msgid "Last Login" msgstr "Última autentificación" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Ver los paquetes de este usuario" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Haga clic %saquí%s si desea borrar permanentemente esa cuenta." +#: template/account_edit_form.php msgid "required" msgstr "obligatorio" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuario normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuario de Confianza" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivo" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Reescriba la contraseña" +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La siguiente información es necesaria únicamente si quiere subir paquetes al " -"Repositorio de Usuarios de Arch." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La siguiente información es necesaria únicamente si quiere subir paquetes al Repositorio de Usuarios de Arch." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave pública SSH" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Crear" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Limpiar" +#: template/account_search_results.php msgid "No results matched your search criteria." -msgstr "" -"No se encontraron resultados que coincidan con su criterio de búsqueda." +msgstr "No se encontraron resultados que coincidan con su criterio de búsqueda." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar cuenta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendido" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Más" +#: template/account_search_results.php msgid "No more results to display." msgstr "No hay más resultados que mostrar." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Administrar coencargados: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Use este formulario para agregar coencargados para %s%s%s (un nombre de " -"usuario por línea):" +msgstr "Use este formulario para agregar coencargados para %s%s%s (un nombre de usuario por línea):" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuarios" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Guardar" +#: template/header.php msgid "My Packages" msgstr "Mis paquetes" +#: template/header.php msgid " My Account" msgstr "Mi cuenta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Acciones del paquete" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver cambios" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Descargar instantánea" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Buscar en la wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marcado como desactualizado" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar paquete como desactualizado" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar paquete" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Eliminar voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar por este paquete" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Deshabilitar notificaciones" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "Hay %d petición pendiente" msgstr[1] "Hay %d peticiones pendientes" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Borrar paquete" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Fusionar paquete" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar paquete" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconocido" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL de clonado con Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "Solo lectura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palabras claves" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Primer encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Encargado" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularidad" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Fecha de creación" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualización" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Agregar comentario" -msgid "Comment has been added." -msgstr "Se ha añadido el comentario." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos los comentarios" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos comentarios" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Borrar comentario" -#, php-format -msgid "Comment by %s" -msgstr "Comentario por %s" - -msgid "Anonymous comment" -msgstr "Comentario anónimo" - -msgid "deleted" -msgstr "borrado" - +#: template/pkg_comments.php msgid "All comments" msgstr "Todos los comentarios" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Desarrollador principal" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita el sitio web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencias" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflictos" +#: template/pkg_details.php msgid "Provides" msgstr "Proveen" +#: template/pkg_details.php msgid "Replaces" msgstr "Remplazan" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencias" +#: template/pkg_details.php msgid "Required by" msgstr "Requerido por" +#: template/pkg_details.php msgid "Sources" msgstr "Fuentes" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Cerrar petición: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Use este formulario para cerrar la petición para el paquete base %s%s%s." +msgstr "Use este formulario para cerrar la petición para el paquete base %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda " -"encarecidamente añadir un comentario al rechazar una petición." +msgstr "El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda encarecidamente añadir un comentario al rechazar una petición." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceptado" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rechazado" -msgid "Comments" -msgstr "Comentario" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Petición para el paquete: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Use este formulario para presentar una petición para el paquete base %s%s%s " -"el cual incluye los siguientes paquetes:" +msgstr "Use este formulario para presentar una petición para el paquete base %s%s%s el cual incluye los siguientes paquetes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de petición" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Borrado" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfandad" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fusionar en" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Se encontró %d solicitud para el paquete." msgstr[1] "Se encontraron %d solicitudes para el paquete." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Solicitado por" +#: template/pkgreq_results.php msgid "Date" msgstr "Fecha" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Aprox. %d días restantes" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Aprox. %d hora restante" msgstr[1] "Aprox. %d horas restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 hora restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceptar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloqueada" +#: template/pkgreq_results.php msgid "Close" msgstr "Cerrar" +#: template/pkgreq_results.php msgid "Closed" msgstr "Cerrada" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nombre, descripción" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Solo nombre" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nombre exacto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exacto" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No marcados" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nombre" -msgid "Popularity" -msgstr "Popularidad" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" -msgid "Age" -msgstr "Antigüedad" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" +#: template/pkg_search_form.php msgid "Search by" msgstr "Buscar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Orden" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Huérfanos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Error al recuperar la lista de paquetes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ningún paquete coincide con su criterio de búsqueda." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquete fue encontrado." msgstr[1] "%d paquetes fueron encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versión" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"La Popularidad es calculada como la suma de todos los votos ponderados con " -"un factor de 0,98 por día desde la creación del paquete." +msgstr "La Popularidad es calculada como la suma de todos los votos ponderados con un factor de 0,98 por día desde la creación del paquete." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "huérfano" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acciones" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marcar como desactualizado" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Marcar como actualizado" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar paquetes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar paquetes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Borrar paquetes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Cualquier tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Buscar" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes huérfanos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes nuevos en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes actualizados en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes actualizados el último año" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes que nunca se han actualizado" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios registrados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios de Confianza" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizaciones recientes" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mis estadísticas" -msgid "Packages in unsupported" -msgstr "Sus paquetes en AUR" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalles de la propuesta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Aún se puede votar." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Subido: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Abstenerse" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participación" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Último voto del usuario de confianza" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No se han encontrado resultados." +#: template/tu_list.php msgid "Start" msgstr "Inicio" +#: template/tu_list.php msgid "Back" msgstr "Atrás" diff --git a/po/fi.po b/po/fi.po index 803ef9ea..409546eb 100644 --- a/po/fi.po +++ b/po/fi.po @@ -1,623 +1,777 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Jesse Jaara , 2011-2012,2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-20 23:09+0000\n" -"Last-Translator: Jesse Jaara \n" -"Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" -"fi/)\n" -"Language: fi\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: fi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "Käyttäjätilit" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Sinulla ei ole oikeuksia tämän osion käyttämiseen." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Valitun käyttäjän tietoja ei voitu noutaa." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Sinulla ei ole oikeuksia tämän käyttäjätlin muokkaamiseen." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Etsi käyttäjätilejä." +#: html/account.php msgid "You must log in to view user information." msgstr "Sinun pitää kirjautua sisään tarkastellaksesi käyttäjien tietoja." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Lisää ehdotus" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "Käyttäjänimeä ei ole olemassa." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "" +#: html/addvote.php msgid "Invalid type." msgstr "" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Ehdotus ei voi olla tyhjä." +#: html/addvote.php msgid "New proposal submitted." msgstr "Uusi ehdotus lisätty." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Lisää ehdotus äänestettäväksi." +#: html/addvote.php msgid "Applicant/TU" msgstr "Ehdokas/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tyhjä jos ei tiettyä henkilöä)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tyyppi" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Ehdotus" +#: html/addvote.php msgid "Submit" msgstr "Lisää" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Etusivu" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Tervetuloa AURiin! Luethan %sAURin käyttäjä ohjeen%s sekä %sTU-käyttäjän " -"oppaan%s, kun tarvitset lisätietoa." +msgstr "Tervetuloa AURiin! Luethan %sAURin käyttäjä ohjeen%s sekä %sTU-käyttäjän oppaan%s, kun tarvitset lisätietoa." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Lisättyjen PKGBUILD tiedostojen %stulee%s olla %sArchin pakettistandardien%s " -"mukaisia, muuten ne saatetaan poistaa!" +msgstr "Lisättyjen PKGBUILD tiedostojen %stulee%s olla %sArchin pakettistandardien%s mukaisia, muuten ne saatetaan poistaa!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Muista äänestää suosikki pakettejasi!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Jotkin paketit saattavat olla tarjolla valmiina paketteina [community] " -"varastossa. :)" +msgstr "Jotkin paketit saattavat olla tarjolla valmiina paketteina [community] varastossa. :)" +#: html/home.php msgid "DISCLAIMER" msgstr "Vastuuvapauslauseke" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Nämä paketit eivät ole virallisesti tuettuja. Tämän sivun paketit ovat " -"käyttäjien tuotosta. Näiden käyttäminen on omalla vastuullaasi" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "Pakettienhallintapyydöt" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Pakettien sivuilta löytyvän %spakettitoiminnot%s -laatikon kautta voi " -"lähettää TU-käyttäjille kolme erilaista pakettienhallintapyyntöä." +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Pakettien sivuilta löytyvän %spakettitoiminnot%s -laatikon kautta voi lähettää TU-käyttäjille kolme erilaista pakettienhallintapyyntöä." +#: html/home.php msgid "Orphan Request" msgstr "Hylkäämispyyntö" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Hallintapyyntö paketin poistamiseksi sen nykyiseltä ylläpitäjältä, esimerksi " -"jos ylläpitäjä ei vastaa kommentteihin eikä sähköpostiin ja paketti on " -"merkitty vanhentuneeksi jo kauan sitten." +msgstr "Hallintapyyntö paketin poistamiseksi sen nykyiseltä ylläpitäjältä, esimerksi jos ylläpitäjä ei vastaa kommentteihin eikä sähköpostiin ja paketti on merkitty vanhentuneeksi jo kauan sitten." +#: html/home.php msgid "Deletion Request" msgstr "Poistopyyntö" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Hallintapyyntö paketin poistamiseksi AUR:ista. Jos paketti on jollain tapaa " -"rikki tai huono, mutta helposti korjattavissa, tulisi ensisijaisesti olla " -"yhteydessä paketin ylläpitäjään ja viimekädessä pistää paketin " -"hylkäämispyyntö menemään." +msgstr "Hallintapyyntö paketin poistamiseksi AUR:ista. Jos paketti on jollain tapaa rikki tai huono, mutta helposti korjattavissa, tulisi ensisijaisesti olla yhteydessä paketin ylläpitäjään ja viimekädessä pistää paketin hylkäämispyyntö menemään." +#: html/home.php msgid "Merge Request" msgstr "Yhdistämispyyntö" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Hallintapyyntö kahden eri paketin yhdistämiseksi. Voidaan käyttää muun " -"muassa silloin kun jokin paketti on nimettyuudelleen tai korvattu " -"monipaketilla (split package)." +msgstr "Hallintapyyntö kahden eri paketin yhdistämiseksi. Voidaan käyttää muun muassa silloin kun jokin paketti on nimettyuudelleen tai korvattu monipaketilla (split package)." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Pakettienhallintapyynnöistä voi keskustella niin yleisellä- kuin myös " -"tiettyyn pyyntöön littyvällä tasolla %saur-requests%s -postituslistalla. Älä " -"kuitenkaan lähetä hallintapyyntöjä postituslistalle." +msgstr "Pakettienhallintapyynnöistä voi keskustella niin yleisellä- kuin myös tiettyyn pyyntöön littyvällä tasolla %saur-requests%s -postituslistalla. Älä kuitenkaan lähetä hallintapyyntöjä postituslistalle." +#: html/home.php msgid "Submitting Packages" msgstr "Paketien lisääminen ja päivittäminen" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Pakettien lisääminen ja päivittäminen uudessa AUR versiossa tapahtuu SSH-" -"yhteyden yli Git-versionhallinan avulla. Tarkemman ohjeet löytyvät Arch " -"Linuxin wiki-oppaan AUR-sivulta kohdasta %sPakettien lisääminen%s." +msgstr "Pakettien lisääminen ja päivittäminen uudessa AUR versiossa tapahtuu SSH-yhteyden yli Git-versionhallinan avulla. Tarkemman ohjeet löytyvät Arch Linuxin wiki-oppaan AUR-sivulta kohdasta %sPakettien lisääminen%s." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR käyttää seuraavia SSH-tunnisteita:" +#: html/home.php msgid "Discussion" msgstr "Keskustelu" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Virheiden raportointi" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Jos löydät AUR:in verkkokäyttöliittymästä jonkin virheen, niin voit " -"raportoida sen %svirheidenhallinta%s -sivulla. Virheidenhallinta -sivulle " -"tulee raportoida vain ja ainoastaan %sitsessään%s AUR:iin liittyviä " -"virheitä, jos virhe liittyy johonkin tiettyyn pakettiin tulee ensisijaisesti " -"ottaa yhteyttä paketin ylläpitäjään tai kirjoittaa kommentti paketin sivulle." +#: html/home.php msgid "Package Search" msgstr "Pakettihaku" +#: html/index.php msgid "Adopt" msgstr "" +#: html/index.php msgid "Vote" msgstr "Äänestä" +#: html/index.php msgid "UnVote" msgstr "Peru ääni" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Lähetä ilmoituksia" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "En halua ilmoituksia" -msgid "Flag" -msgstr "" - +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "Kirjaudu" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Nykyinen käyttäjä: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Kirjaudu ulos" +#: html/login.php msgid "Enter login credentials" msgstr "Kirjautumistiedot" -msgid "Username" -msgstr "Käyttäjänimi" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Salasana" +#: html/login.php msgid "Remember me" msgstr "Muista minut" +#: html/login.php msgid "Forgot Password" msgstr "Unohditko salasanasi?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP:n kautta kirjoutuminen ei ole käytössä. Ole hyvä ja %svaihda HTTPS " -"yhteyteen%s kirjautuaksesi." +msgstr "HTTP:n kautta kirjoutuminen ei ole käytössä. Ole hyvä ja %svaihda HTTPS yhteyteen%s kirjautuaksesi." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Haku kriteerit" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketit" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Valitun paketin tietoja ei löytynyt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Jokin vaadituista kentistä on puutteellinen." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Salasanakentät eivät täsmää." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Salasanan pitää olla vähintään %s merkkiä pitkä." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Epäkelvollinen sähköpostiosoite." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Salasanan palautus" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Sähköpostiisi on nyt lähetetty varmistus linkki." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Salasanasi on palautettu onnistuneesti." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Vahvista sähköpostiositteesi:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Uuusi salasana:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Vahvista uusi salasana:" +#: html/passreset.php msgid "Continue" msgstr "Jatka" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." msgstr "" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Sähköpostiosoitteesi:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Pakettia, johon haluat siirtää äänet ja kommentit, ei löydy." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Valittuja paketteja ei ole poistettu. Muistitko laittaa raksin varmistus " -"ruutuun?" +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Valittuja paketteja ei ole poistettu. Muistitko laittaa raksin varmistus ruutuun?" +#: html/pkgdel.php msgid "Package Deletion" msgstr "" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Poista paketti: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Pakettin poistaminen on lopullista, sitä ei voi peruuttaa." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Vahvista paketin poisto" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Poista" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Vain Trusted- statuksen omaavat käyttäjät, sekä kehittäjät voivat poistaa " -"paketteja." +msgstr "Vain Trusted- statuksen omaavat käyttäjät, sekä kehittäjät voivat poistaa paketteja." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "" + +#: html/pkgflag.php +msgid "Flag" +msgstr "" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakettien yhdistäminen" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Yhdistä paketit: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "Yhdistä tähän pakettiin:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Vahvista pakettien yhdistäminen" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Liitä" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Vain Trusted-statuksen omaavat käyttäjät, sekä kehittäjät voivat yhdistää " -"paketteja." +msgstr "Vain Trusted-statuksen omaavat käyttäjät, sekä kehittäjät voivat yhdistää paketteja." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Ensimmäinen" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Edellinen" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seuraava" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Viimeinen" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "Rekisteröidy" +#: html/register.php msgid "Use this form to create an account." msgstr "Käytä tätä lomaketta uuden käyttäjätilin luomiseen." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Luotettu käyttäjä (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Ehdotuksen tietoja ei voitu noutaa." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Tämän ehdoksen äänestys on päättynyt." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Et voi äänestää itseäsi koskevassa äänestyksessä." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Olet jo antanut äänesi tälle ehdotukselle." +#: html/tu.php msgid "Vote ID not valid." msgstr "" +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Avoimet äänestykset." +#: html/tu.php msgid "Past Votes" msgstr "Sulkeutuneet äänestykset." +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Äänestäjät" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Käyttäjän tunnus puuttuu" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Käyttäjänimi ei ole kelvollinen." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Sen pitää olla %s-%s kirjaintapitkä" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Alkaa ja loppua kirjaimeen tai numeroon" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Voi sisältää vain yhden väliviivan, alaviivan tai pisteen." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Sähköpostiosoite ei ole kelvollinen." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Kieli ei ole vielä tuettuna." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -msgid "Click on the Login link above to use your account." -msgstr "" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -625,730 +779,1028 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Virheellinen käyttäjänimi tai salasana." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Epäkelvollinen sähköposti ja palautusavain yhdistelmä." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Kommentti lisätty." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Virhe haettaessa paketin tietoja." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paketin tietoja ei löydetty." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Sinun pitää kirjautua, ennen kuin voit muuttaa merkintöjä." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Et valinnut yhtään pakettia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Valitut paketit on merkitty vanhentuneiksi." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Sinun pitää kirjautua, ennen kuin voit muuttaa merkintöjä." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Et valinnut yhtään pakettia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Valittuilta paketeilta on poistettu merkintä." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Et valinnut yhtään pakettia poistettavaksi." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Valitut paketit on nyt poistettu." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Sinun pitää kirjautua, ennen kuin voit adoptoida paketteja." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Sinun pitää kirjautua, ennen kuin voit hylätä paketteja." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Et valinnut yhtään pakettia adoptoitavaksi." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Et valinnut yhtään pakettia hylättäväksi." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Valitut paketit on nyt adoptoitu." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Valitut paketiti on nyt hylätty." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Sinun pitää kirjautua, ennen kuin voit äänestää paketteja." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Sinun pitää kirjautua, ennen kuin voit perua äänesi." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Et valinnut yhtään pakettia äänestettäväksi." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Valittuille paketeille antamasi äänet on nyt peruttu." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Äänesi on nyt annettu valituille paketeille." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ei kyetty lisäämään ilmoituslistaan." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Saat nyt ilmoituksen paketin %s uusista kommenteista." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Et saa enää ilmoituksia paketin %s uusista kommenteista." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Sinun pitää kirjautua, ennen kuin voit muokata paketin tietoja." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Kommentin tunnus puuttuu." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentti on poistettu." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Sinulla ei ole oikeuksia tämän kommentin poistamiseen." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Virheellinen nimi: vain pienet kirjaimet ovat sallittuja." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Käyttäjänimi" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "TIlin tyyppi" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Käyttäjä" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Kehittäjä" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Sähköpostiosoite" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Oikea nimi" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC nikki" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Tila" +#: template/account_details.php msgid "Inactive since" msgstr "" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiivinen" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Ei koskaan" +#: template/account_details.php msgid "View this user's packages" msgstr "Näytä käyttäjän paketit" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "vaaditaan" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Tavallinen käyttäjä" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Luotettu käyttäjä (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Käyttäjätili hyllytetty" +#: template/account_edit_form.php msgid "Inactive" msgstr "" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Salasana uudelleen:" +#: template/account_edit_form.php msgid "Language" msgstr "Kieli" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Julkinen SSH avain" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Päivitä" +#: template/account_edit_form.php msgid "Create" msgstr "Luo" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Tyhjennä" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Hakuasi vastaavia paketteja ei löydy." +#: template/account_search_results.php msgid "Edit Account" msgstr "Muokkaa käyttäjätiliä" +#: template/account_search_results.php msgid "Suspended" msgstr "Hyllytä" +#: template/account_search_results.php msgid "Edit" msgstr "Muokkaa" +#: template/account_search_results.php msgid "Less" msgstr "Vähemmän" +#: template/account_search_results.php msgid "More" msgstr "Enemmän" +#: template/account_search_results.php msgid "No more results to display." msgstr "Ei enempää tuloksia" +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Omat paketit" +#: template/header.php msgid " My Account" msgstr "Omat tiedot" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakettitoiminnot" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Näytö PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Näytä muutoshistoria" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Lataa tuorein versio" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Etsi wikistä" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Merkitty vanhentuneeksi" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Merkitse paketti vanhentuneeksi" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Poista merkintä" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Poista ääneni" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Äännestä pakettia" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "En halua enää ilmoituksia" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Lähetä ilmoitus uusista kommnteista" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Hallitse ylläpitäjäkumppaneita" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d käsittelemätön hallintapyyntö" msgstr[1] "%d käsittelemätöntä hallintapyyntöä" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Poista paketti" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Yhdistä toiseen pakettiin" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Ryhdy ylläpitäjäksi" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "tuntematon" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git kopionti osoite" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "vain luku" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Avainsanat" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Lisääjä" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ylläpitäjä" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Uusimman versionn luoja" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Äänet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Lisättiin" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Päivitettiin" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Lisää kommentti" -msgid "Comment has been added." -msgstr "Kommentti lisätty." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Näytä kaikki kommentit" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Uusimmat kommentit" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Poista kommentti" -#, php-format -msgid "Comment by %s" -msgstr "Kommentin kirjoitti %s" - -msgid "Anonymous comment" -msgstr "Tuntematon kommentoija" - -msgid "deleted" -msgstr "poistettu" - +#: template/pkg_comments.php msgid "All comments" msgstr "Kaikki kommentit" +#: template/pkg_details.php msgid "Package Details" msgstr "Paketin tiedot" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Ylipaketti" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Kuvaus" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Kotisivu" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "Lisenssit" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "Ristiriidat" +#: template/pkg_details.php msgid "Provides" msgstr "Tarjoaa paketit" +#: template/pkg_details.php msgid "Replaces" msgstr "Korvaa paketit" +#: template/pkg_details.php msgid "Dependencies" msgstr "Riippuvuudet" +#: template/pkg_details.php msgid "Required by" msgstr "Riippuvuutena paketeille" +#: template/pkg_details.php msgid "Sources" msgstr "Lähdetiedostot" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "" -msgid "Comments" -msgstr "" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Yhdistä pakettiin" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nimi, kuvaus" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Pelkkä nimi" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Kaikki" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Merkitty" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Ei merkitty" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nimi" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Äänestin" -msgid "Age" -msgstr "Ikä" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Nouseva" +#: template/pkg_search_form.php msgid "Descending" msgstr "Laskeva" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Etsintäperuste" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Vanhentunut" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Järjestelyperuste" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Järjestelyperuste" +#: template/pkg_search_form.php msgid "Per page" msgstr "Sivua kohden" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Etsi" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orvot" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Virhe pakettilistaa noudettaessa." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Hakuasi vastaavia paketteja ei löydy." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +#: template/pkg_search_results.php msgid "Version" msgstr "Versio" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Kyllä" +#: template/pkg_search_results.php msgid "orphan" msgstr "orpo" +#: template/pkg_search_results.php msgid "Actions" msgstr "Toiminnot" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Merkitse vanhentuneeksi" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Ei vanhentunut" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptoi paketit" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Hylkää paketit" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Poista paketit" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Vahvista" +#: template/search_accounts_form.php msgid "Any type" msgstr "Mikä tahansa" +#: template/search_accounts_form.php msgid "Search" msgstr "Etsi" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Tilastoja" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Hylättyjä paketteja" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Uudet paketit 7 päivän sisällä" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paketteja päivitetty 7 päivän sisällä" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Vuoden aikana päivitettyjä paketteja" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paketteja ei ole koskaan päivitetty" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Rekisteröityjä käyttäjiä" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Luotettuja käyttäjiä" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Viimeisimmät päivitykset" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Tilastoni" -msgid "Packages in unsupported" -msgstr "Pakettieni määrä" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Ehdotuksen tiedot" +#: template/tu_details.php msgid "This vote is still running." msgstr "Tätä ehdotusta voi vielä äänestää." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Lisätty: %s Lisääjä: %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Loppu" +#: template/tu_details.php msgid "Result" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ei" +#: template/tu_details.php msgid "Abstain" msgstr "" +#: template/tu_details.php msgid "Total" msgstr "Yhteensä" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ei tuloksia." +#: template/tu_list.php msgid "Start" msgstr "Alku" +#: template/tu_list.php msgid "Back" msgstr "Takaisin" diff --git a/po/fr.po b/po/fr.po index a9b9172a..a8f31b0f 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Antoine Lubineau , 2012 # Antoine Lubineau , 2012-2014 @@ -15,1412 +15,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-19 21:40+0000\n" -"Last-Translator: Xorg \n" -"Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" -"fr/)\n" -"Language: fr\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: French (http://www.transifex.com/lfleischer/aur/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Page non trouvée" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Désolé, la page que vous avez demandée n’existe pas." +#: html/503.php msgid "Service Unavailable" msgstr "Service indisponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Ne paniquez pas ! Le site est fermé pour maintenance. Nous serons bientôt de " -"retour." +msgstr "Ne paniquez pas ! Le site est fermé pour maintenance. Nous serons bientôt de retour." +#: html/account.php msgid "Account" msgstr "Compte" +#: html/account.php template/header.php msgid "Accounts" msgstr "Comptes" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Vous n’avez pas la permission d’accéder à cet espace." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Impossible de trouver l’information pour l’utilisateur spécifié." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Vous n’avez pas la permission d’éditer ce compte." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilisez ce formulaire pour rechercher des comptes existants." +#: html/account.php msgid "You must log in to view user information." -msgstr "" -"Vous devez vous authentifier pour voir les informations de l’utilisateur." +msgstr "Vous devez vous authentifier pour voir les informations de l’utilisateur." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Ajoutez une proposition" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Action invalide." +#: html/addvote.php msgid "Username does not exist." msgstr "Le nom d'utilisateur n’existe pas." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s a déjà une proposition en cours à son sujet." +#: html/addvote.php msgid "Invalid type." msgstr "Type invalide." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Une proposition ne peut être vide." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nouvelle proposition enregistrée." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Soumettre une proposition à laquelle voter." +#: html/addvote.php msgid "Applicant/TU" msgstr "Requérant/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vide si non applicable)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "Ajout d’un utilisateur de confiance." +#: html/addvote.php msgid "Removal of a TU" msgstr "Suppression d’un utilisateur de confiance" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Suppression d’un utilisateur de confiance (inactivité non prévenue)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendement du règlement" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposition" +#: html/addvote.php msgid "Submit" msgstr "Soumettre" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gérer les co-mainteneurs" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Accueil" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bienvenue sur AUR ! Veuillez lire les %sconsignes pour les utilisateurs d’AUR" -"%s et les %sconsignes pour les utilisateurs de confiance%s pour plus " -"d’information." +msgstr "Bienvenue sur AUR ! Veuillez lire les %sconsignes pour les utilisateurs d’AUR%s et les %sconsignes pour les utilisateurs de confiance%s pour plus d’information." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Les PKGBUILD proposés %sdoivent%s respecter les %sstandards d’empaquetage " -"d’Arch%s, sinon ils seront supprimés !" +msgstr "Les PKGBUILD proposés %sdoivent%s respecter les %sstandards d’empaquetage d’Arch%s, sinon ils seront supprimés !" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Pensez à voter pour vos paquets favoris !" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Certains paquets peuvent être disponibles sous forme binaire dans le dépôt " -"[community]." +msgstr "Certains paquets peuvent être disponibles sous forme binaire dans le dépôt [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVERTISSEMENT" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Les paquets non supportés sont produits par des utilisateurs. Toute " -"utilisation des fichiers fournis se fait à vos propres risques." +#: html/home.php msgid "Learn more..." msgstr "En apprendre plus..." +#: html/home.php msgid "Support" msgstr "Soutien" +#: html/home.php msgid "Package Requests" msgstr "Requêtes de paquet" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Il existe trois types de requêtes qui peuvent être soumises dans la boîte " -"%sActions du paquet%s sur la page des détails d'un paquet :" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Il existe trois types de requêtes qui peuvent être soumises dans la boîte %sActions du paquet%s sur la page des détails d'un paquet :" +#: html/home.php msgid "Orphan Request" msgstr "Requête de destitution" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Demande qu'un paquet soit destitué, c'est-à-dire quand le mainteneur est " -"inactif et que le paquet a été marqué comme périmé depuis un long moment." +msgstr "Demande qu'un paquet soit destitué, c'est-à-dire quand le mainteneur est inactif et que le paquet a été marqué comme périmé depuis un long moment." +#: html/home.php msgid "Deletion Request" msgstr "Requête de suppression" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Demande qu'un paquet soit supprimé d'AUR. Prière de ne pas l'utiliser si un " -"paquet est cassé et que le problème peut être réglé facilement. À la place, " -"contactez le mainteneur du paquet, et soumettez une requête de destitution " -"si nécessaire." +msgstr "Demande qu'un paquet soit supprimé d'AUR. Prière de ne pas l'utiliser si un paquet est cassé et que le problème peut être réglé facilement. À la place, contactez le mainteneur du paquet, et soumettez une requête de destitution si nécessaire." +#: html/home.php msgid "Merge Request" msgstr "Requête de fusion" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Demande que le paquet soit fusionné dans un autre. Peut être utilisé quand " -"un paquet a besoin d'être renommé ou bien remplacé par un paquet splitté." +msgstr "Demande que le paquet soit fusionné dans un autre. Peut être utilisé quand un paquet a besoin d'être renommé ou bien remplacé par un paquet splitté." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Si vous voulez débattre d'une requête, vous pouvez utiliser la mailing-list " -"%saur-requests%s. Cependant, merci de ne pas utiliser cette liste pour " -"soumettre des requêtes." +msgstr "Si vous voulez débattre d'une requête, vous pouvez utiliser la mailing-list %saur-requests%s. Cependant, merci de ne pas utiliser cette liste pour soumettre des requêtes." +#: html/home.php msgid "Submitting Packages" msgstr "Soumission de paquets" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git par-dessus SSH est maintenant utilisé pour soumettre des paquets sur " -"AUR. Voir la section %sSoumettre des paquets%s sur la page Arch User " -"Repository du wiki pour plus de détails." +msgstr "Git par-dessus SSH est maintenant utilisé pour soumettre des paquets sur AUR. Voir la section %sSoumettre des paquets%s sur la page Arch User Repository du wiki pour plus de détails." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Les empreintes SSH suivantes sont utilisées pour AUR :" +#: html/home.php msgid "Discussion" msgstr "Discussion" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Les discussions générales en rapport avec AUR (Arch User Repository, dépôt " -"des utilisateurs d’Arch Linux) et les TU (Trusted User, utilisateurs de " -"confiance) ont lieu sur %saur-general%s. Pour les discussions en rapport " -"avec le développement de l'interface web d'AUR, utilisez la mailing-list " -"%saur-dev.%s" +msgstr "Les discussions générales en rapport avec AUR (Arch User Repository, dépôt des utilisateurs d’Arch Linux) et les TU (Trusted User, utilisateurs de confiance) ont lieu sur %saur-general%s. Pour les discussions en rapport avec le développement de l'interface web d'AUR, utilisez la mailing-list %saur-dev.%s" +#: html/home.php msgid "Bug Reporting" msgstr "Rapports de bug" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Si vous trouvez un bug dans l'interface web d'AUR, merci de remplir un " -"rapport de bug sur le %sbug tracker%s. N’utilisez le tracker %sque%s pour " -"les bugs de AUR. Pour signaler un bug dans un paquet, contactez directement " -"le mainteneur du paquet, ou laissez un commentaire sur la page du paquet." +#: html/home.php msgid "Package Search" msgstr "Recherche d'un paquet" +#: html/index.php msgid "Adopt" msgstr "Adopter" +#: html/index.php msgid "Vote" msgstr "Voter" +#: html/index.php msgid "UnVote" msgstr "Retirer le vote" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notifier" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne plus notifier" -msgid "Flag" -msgstr "Marquer comme périmé" - +#: html/index.php msgid "UnFlag" msgstr "Ne plus marquer comme périmé" +#: html/login.php template/header.php msgid "Login" msgstr "Se connecter" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Connecté en tant que : %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Déconnexion" +#: html/login.php msgid "Enter login credentials" msgstr "Entrez vos identifiants" -msgid "Username" -msgstr "Nom d'utilisateur" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Mot de passe" +#: html/login.php msgid "Remember me" msgstr "Se souvenir de moi" +#: html/login.php msgid "Forgot Password" msgstr "Mot de passe oublié" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"La connexion HTTP est désactivée. Veuillez %sbasculer en HTTPS%s pour " -"pouvoir vous connecter." +msgstr "La connexion HTTP est désactivée. Veuillez %sbasculer en HTTPS%s pour pouvoir vous connecter." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critères de recherche" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquets" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erreur en essayant de retrouver les détails du paquets." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Il manque un champ requis." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Les champs du mot de passe ne correspondent pas." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Votre mot de passe doit comprendre au moins %s caractères." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail invalide" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"La demande de réinitialisation de mot de passe a été envoyée au compte %s " -"associé à votre adresse e-mail. Si vous voulez réinitialiser votre mot de " -"passe, cliquez sur le lien ci-dessous, sinon ignorez ce message et aucune " -"modification sera effectuée." - +#: html/passreset.php msgid "Password Reset" msgstr "Réinitialisation de mot de passe" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Vérifiez votre e-mail pour le lien de confirmation." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Votre mot de passe a été réinitialisé avec succès." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirmez votre adresse e-mail :" +#: html/passreset.php msgid "Enter your new password:" msgstr "Entrez votre nouveau mot de passe :" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirmez votre nouveau mot de passe :" +#: html/passreset.php msgid "Continue" msgstr "Continuer" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si vous avez oublié avec quelle adresse e-mail vous vous êtes inscrit, " -"veuillez envoyer un message sur la mailing-list %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si vous avez oublié avec quelle adresse e-mail vous vous êtes inscrit, veuillez envoyer un message sur la mailing-list %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Entrez votre adresse e-mail :" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Les paquets sélectionnés n'ont pas été destitués, vérifiez la boîte de " -"confirmation." +msgstr "Les paquets sélectionnés n'ont pas été destitués, vérifiez la boîte de confirmation." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Impossible de trouver le paquet dans lequel fusionner les votes et les " -"commentaires." +msgstr "Impossible de trouver le paquet dans lequel fusionner les votes et les commentaires." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Impossible de fusionner un paquet de base avec lui-même" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Les paquets sélectionnés n'ont pas été supprimés, cochez la case de " -"confirmation." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Les paquets sélectionnés n'ont pas été supprimés, cochez la case de confirmation." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Suppression de paquet" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Supprimer le paquet : %s." +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Utilisez ce formulaire pour supprimer le paquet de base %s%s%s et les " -"paquets suivants de AUR :" +msgstr "Utilisez ce formulaire pour supprimer le paquet de base %s%s%s et les paquets suivants de AUR :" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "La suppression d’un paquet est permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Cochez la case pour confirmer l’action." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmer la suppression du paquet" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Supprimer" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Seuls les Utilisateur de Confiance et les Développeurs peuvent effacer des " -"paquets." +msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent effacer des paquets." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Destituer le paquet" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Destituer le paquet : %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Utilisez ce formulaire pour destituer le paquet de base %s%s%s qui inclut " -"les paquets suivants : " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Utilisez ce formulaire pour destituer le paquet de base %s%s%s qui inclut les paquets suivants : " +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"En cochant la case, vous confirmez que vous voulez destituer le paquet et " -"transférer sa propriété à %s%s%s." +msgstr "En cochant la case, vous confirmez que vous voulez destituer le paquet et transférer sa propriété à %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"En cochant la case, vous confirmez que vous voulez destituer le paquet." +msgstr "En cochant la case, vous confirmez que vous voulez destituer le paquet." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirmer la destitution du paquet" +#: html/pkgdisown.php msgid "Disown" msgstr "Destituer" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Seuls les Utilisateur de Confiance et les Développeurs peuvent destituer des " -"paquets." +msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent destituer des paquets." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Commentaires" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Marquer comme périmé" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusion de paquet" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Fusionner le paquet : %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Utilisez ce formulaire pour fusionner ce paquet de base %s%s%s dans un autre " -"paquet." +msgstr "Utilisez ce formulaire pour fusionner ce paquet de base %s%s%s dans un autre paquet." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Les paquets suivants vont être supprimés :" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "La fusion du paquet est une opération irréversible." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Saisissez le nom du paquet dans lequel vous souhaitez fusionner ce paquet." +msgstr "Saisissez le nom du paquet dans lequel vous souhaitez fusionner ce paquet." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionner dans :" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmer la fusion du paquet" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusionner" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Seuls les Utilisateur de Confiance et les Développeurs peuvent fusionner des " -"paquets." +msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent fusionner des paquets." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Requête de Fichier" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fermer la requête" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Première" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Précédente" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Suivant" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Dernière" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Requêtes" +#: html/register.php template/header.php msgid "Register" msgstr "S’inscrire" +#: html/register.php msgid "Use this form to create an account." msgstr "Utilisez ce formulaire pour créer un compte." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Utilisateur de confiance (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Impossible d’obtenir le détail de la proposition." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Le vote est clos pour cette proposition." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Seuls les Utilisateurs de Confiance sont autorisés à voter." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Vous ne pouvez pas voter dans une proposition à votre sujet." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Vous avez déjà voté pour cette proposition." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID de vote non valide." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votes en cours" +#: html/tu.php msgid "Past Votes" msgstr "Votes passés" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votants" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"La création de compte est désactivée pour votre adresse IP, probablement à " -"cause d’attaques de spammeurs. Désolé pour le désagrément." +msgstr "La création de compte est désactivée pour votre adresse IP, probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID d'utilisateur manquant" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Le nom d'utilisateur choisi n'est pas valide." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Il doit être compris entre %s et %s caractères," +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "doit débuter et se terminer par une lettre ou un chiffre." +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "ne peut contenir qu'un seul point, tiret bas ou virgule," +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adresse email n'est pas valide." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "L’empreinte de clé PGP est invalide." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clé SSH publique est invalide." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Ne peut pas augmenter les autorisations du compte." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Cette langue n'est pas supportée pour le moment." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Le nom d’utilisateur %s%s%s, est déjà utilisé." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L’adresse %s%s%s est déjà utilisée." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clé SSH publique, %s%s%s, est déjà utilisée." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erreur en essayant de créer le compte %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Le compte %s%s%s a été créé avec succès." +#: lib/acctfuncs.inc.php +msgid "A password reset key has been sent to your e-mail address." +msgstr "Une clé de réinitialisation de mot de passe vous a été envoyée par e-mail." + +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Cliquez sur le lien de connexion ci-dessus pour utiliser votre compte." -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Bienvenue sur %s ! Afin de générer un mot de passe pour votre nouveau " -"compte, veuillez suivre le lien ci-dessous. Si le lien ne fonctionne pas, " -"copiez-le et collez-le dans votre navigateur web." - -msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Une clé de réinitialisation de mot de passe vous a été envoyée par e-mail." - +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Aucun changement n'ont été fait au compte, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Le compte %s%s%s a été modifié avec succès." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Le formulaire de connexion est actuellement désactivé pour votre adresse IP, " -"probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +msgstr "Le formulaire de connexion est actuellement désactivé pour votre adresse IP, probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Compte suspendu." +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Votre mot de passe a été réinitialisé. Si vous venez de créer un nouveau " -"compte, veuillez utiliser le lien présent dans l’e-mail de confirmation pour " -"modifier le mot de passe. Sinon, demandez une clé de réinitialisation depuis " -"la page « %sRéinitialisation de mot de passe%s »." +msgstr "Votre mot de passe a été réinitialisé. Si vous venez de créer un nouveau compte, veuillez utiliser le lien présent dans l’e-mail de confirmation pour modifier le mot de passe. Sinon, demandez une clé de réinitialisation depuis la page « %sRéinitialisation de mot de passe%s »." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Mauvais nom d'utilisateur ou mot de passe." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "" -"Une erreur est survenue en essayant de générer une session utilisateur." +msgstr "Une erreur est survenue en essayant de générer une session utilisateur." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinaison entre l'e-mail et la clef de réinitialisation invalides." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Aucun" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Voir les informations du compte pour %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Le commentaire a été ajouté." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Erreur en recherchant les détails du paquet." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Les détails du paquet ne peuvent pas être trouvés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Vous devez être authentifié avant de pouvoir étiqueter des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Vous n'avez sélectionné aucun paquet à étiqueter." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Les paquets sélectionnés ont été étiquetés comme périmés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Vous devez être authentifié avant de pouvoir retirer l'étiquetage des " -"paquets." +msgstr "Vous devez être authentifié avant de pouvoir retirer l'étiquetage des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Vous n'avez sélectionné aucun paquet auquel retirer l'étiquetage." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Les paquets sélectionnés ne sont plus étiquetés." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Vous n’avez pas la permission de supprimer des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Vous n'avez sélectionné aucun paquet à supprimer." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Les paquets sélectionnés ont été supprimés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Vous devez être authentifié avant de pouvoir adopter des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Vous devez être authentifié avant de pouvoir abandonner des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Vous n'avez pas sélectionné de paquet à adopter." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Vous n'avez sélectionné aucun paquet à abandonner." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Les paquets sélectionnés ont été adoptés." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Les paquets sélectionnés ont été abandonnés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Vous devez être authentifié avant de pouvoir voter pour des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "" -"Vous devez être authentifié avant de pouvoir retirer votre vote sur des " -"paquets." +msgstr "Vous devez être authentifié avant de pouvoir retirer votre vote sur des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Vous n'avez sélectionné aucun paquet pour lequel vous souhaitez voter." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vos votes ont été retirés des paquets sélectionnés." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Vos votes ont été distribués aux paquets sélectionnés." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ajout impossible à la liste de notification." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "" -"Vous avez été ajouté à la liste des notifications de commentaire pour %s." +msgstr "Vous avez été ajouté à la liste des notifications de commentaire pour %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "" -"Vous avez été retiré de la liste des notifications de commentaire pour %s." +msgstr "Vous avez été retiré de la liste des notifications de commentaire pour %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Vous devez vous identifier avant de pouvoir éditer les informations du " -"paquet." +msgstr "Vous devez vous identifier avant de pouvoir éditer les informations du paquet." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "ID de commentaire manquant." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Le commentaire a été supprimé." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Vous n'êtes pas autorisé(e) à supprimer ce commentaire." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Vous n'êtes pas autorisé à éditer les mots-clés de ce paquet de base." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Les mots-clés du paquet de base ont été mis à jour." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Vous n'êtes pas autorisé à gérer les co-mainteneurs de ce paquet de base." +msgstr "Vous n'êtes pas autorisé à gérer les co-mainteneurs de ce paquet de base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nom d'utilisateur invalide : %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Les co-mainteneurs du paquet de base ont été mis à jour." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Voir le paquet" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Vous devez être identifié pour soumette des requêtes sur des paquets." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nom invalide : seules les lettres minuscules sont autorisées." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "La zone de commentaire ne doit pas être vide." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Type de requête invalide." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Requête ajouté avec succès." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Raison incorrecte." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Seuls les utilisateurs de confiance et les développeurs peuvent fermer les " -"requêtes." +msgstr "Seuls les utilisateurs de confiance et les développeurs peuvent fermer les requêtes." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Requête fermée avec succès." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Vous ne pouvez pas utiliser ce formulaire pour effacer le compte AUR %s de " -"façon permanente." +msgstr "Vous ne pouvez pas utiliser ce formulaire pour effacer le compte AUR %s de façon permanente." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sATTENTION%s: cette action ne peut être annulée" +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmer la suppression" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nom d'utilisateur" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Type de compte" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilisateur" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Développeur" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Utilisateur de confiance (TU) et Développeur" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresse e-mail" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nom réel" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Pseudo IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Empreinte de clé PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "État" +#: template/account_details.php msgid "Inactive since" msgstr "Inactif depuis" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actif" +#: template/account_details.php msgid "Last Login" msgstr "Dernière connexion." +#: template/account_details.php msgid "Never" msgstr "Jamais" +#: template/account_details.php msgid "View this user's packages" msgstr "Visualiser les paquets de cet utilisateur." +#: template/account_details.php msgid "Edit this user's account" msgstr "Éditer le compte de cet utilisateur." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Cliquez %sici%s si vous voulez effacer ce compte de façon définitive." +#: template/account_edit_form.php msgid "required" msgstr "requis" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilisateur normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Utilisateur de confiance (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Compte suspendu" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactif" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Retapez le mot de passe" +#: template/account_edit_form.php msgid "Language" msgstr "Langue" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"L'information suivante est requise uniquement si vous voulez soumettre des " -"paquets sur AUR" +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "L'information suivante est requise uniquement si vous voulez soumettre des paquets sur AUR" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clé SSH publique" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Mise à jour" +#: template/account_edit_form.php msgid "Create" msgstr "Créer" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Réinitialiser" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Aucun résultat ne correspond à vos critères de recherche." +#: template/account_search_results.php msgid "Edit Account" msgstr "Éditer le compte" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendu" +#: template/account_search_results.php msgid "Edit" msgstr "Éditer" +#: template/account_search_results.php msgid "Less" msgstr "Moins" +#: template/account_search_results.php msgid "More" msgstr "Plus" +#: template/account_search_results.php msgid "No more results to display." msgstr "Plus de résultats à afficher." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Gérer les co-mainteneurs : %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Utilisez ce formulaire pour ajouter des co-mainteneurs pour %s%s%s (un nom " -"d'utilisateur par ligne) :" +msgstr "Utilisez ce formulaire pour ajouter des co-mainteneurs pour %s%s%s (un nom d'utilisateur par ligne) :" +#: template/comaintainers_form.php msgid "Users" msgstr "Utilisateurs" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Sauvegarder" +#: template/header.php msgid "My Packages" msgstr "Mes paquets" +#: template/header.php msgid " My Account" msgstr "Mon compte" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Actions du paquet" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Voir le PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Voir les changements" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Télécharger un instantané" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Rechercher sur le wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marqué comme périmé" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marquer le paquet comme périmé" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Ne plus marquer le paquet comme périmé" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Retirer le vote" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Voter pour ce paquet" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Désactiver les notifications" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Avertir des nouveaux commentaires" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Gérer les co-mainteneurs" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requête en attente" msgstr[1] "%d requêtes en attente" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Supprimer le paquet" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Fusionner le paquet" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter ce paquet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "inconnu" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Détails du paquet de base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL de clone (Git)" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "lecture seule" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Mots-clés" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Contributeur" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mainteneur" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Dernier packageur" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votes" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularité" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Première soumission" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Dernière mise à jour" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Ajouter un commentaire" -msgid "Comment has been added." -msgstr "Le commentaire a été ajouté." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Voir tous les commentaires" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Derniers commentaires" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Effacer le commentaire" -#, php-format -msgid "Comment by %s" -msgstr "Commentaire de %s" - -msgid "Anonymous comment" -msgstr "Commentaire anonyme" - -msgid "deleted" -msgstr "supprimé" - +#: template/pkg_comments.php msgid "All comments" msgstr "Tous les commentaires" +#: template/pkg_details.php msgid "Package Details" msgstr "Détails du paquet" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquet de base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Description" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Lien" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Accéder au site web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licences" +#: template/pkg_details.php msgid "Groups" msgstr "Groupes" +#: template/pkg_details.php msgid "Conflicts" msgstr "En conflit avec" +#: template/pkg_details.php msgid "Provides" msgstr "Fournit" +#: template/pkg_details.php msgid "Replaces" msgstr "Remplace" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dépendances" +#: template/pkg_details.php msgid "Required by" msgstr "Requis par" +#: template/pkg_details.php msgid "Sources" msgstr "Sources" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Fermer la requête : %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Utiliser ce formulaire pour fermer la requête pour le paquet de base %s%s%s." +msgstr "Utiliser ce formulaire pour fermer la requête pour le paquet de base %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Note" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Le champ commentaires peut être laissé vide. Cependant, il est fortement " -"recommandé d'ajouter un commentaire lors du rejet d'une requête." +msgstr "Le champ commentaires peut être laissé vide. Cependant, il est fortement recommandé d'ajouter un commentaire lors du rejet d'une requête." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Raison" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Accepté" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rejeté" -msgid "Comments" -msgstr "Commentaires" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Requête de Fichier: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Utilisez ce formulaire pour soumettre une requête concernant le paquet de " -"base %s%s%s contenant les paquets suivant:" +msgstr "Utilisez ce formulaire pour soumettre une requête concernant le paquet de base %s%s%s contenant les paquets suivant:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Type de requête" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Suppression" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Rendre orphelin" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fusionner dans" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d paquet demandé trouvé." msgstr[1] "%d paquets demandés trouvés." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Page %d sur %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Soumise par" +#: template/pkgreq_results.php msgid "Date" msgstr "Date" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d jours restants" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d heure restante" msgstr[1] "%d heures restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 heure restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accepter" +#: template/pkgreq_results.php msgid "Locked" msgstr "Verrouillé" +#: template/pkgreq_results.php msgid "Close" msgstr "Fermer" +#: template/pkgreq_results.php msgid "Closed" msgstr "Fermé" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nom, Description" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Noms seulement" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nom exact" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquet de base exact" +#: template/pkg_search_form.php msgid "All" msgstr "Tout" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Étiqueté" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Non étiqueté" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nom" -msgid "Popularity" -msgstr "Popularité" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Voté" -msgid "Age" -msgstr "Âge" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendant" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendant" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Saisissez les critères de recherche" +#: template/pkg_search_form.php msgid "Search by" msgstr "Rechercher par" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Périmé" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Trier par" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordre de tri" +#: template/pkg_search_form.php msgid "Per page" msgstr "Par page" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Aller" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orphelins" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erreur en récupérant la liste des paquets." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Aucun paquet ne correspond à vos critères de recherche." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquet trouvé." msgstr[1] "%d paquets trouvés." +#: template/pkg_search_results.php msgid "Version" msgstr "Version" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"La popularité est calculée à partir de la somme de tous les votes, chacun " -"étant pondéré par un facteur de 0.98 par jour depuis sa création." +msgstr "La popularité est calculée à partir de la somme de tous les votes, chacun étant pondéré par un facteur de 0.98 par jour depuis sa création." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Oui" +#: template/pkg_search_results.php msgid "orphan" msgstr "orphelin" +#: template/pkg_search_results.php msgid "Actions" msgstr "Actions" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Étiqueter comme périmé" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Retirer l'étiquette « périmé »" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter des paquets" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonner les paquets" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Supprimer des paquets" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmer" +#: template/search_accounts_form.php msgid "Any type" msgstr "Tout type" +#: template/search_accounts_form.php msgid "Search" msgstr "Rechercher" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiques" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquets orphelins" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquets ajoutés au cours des 7 derniers jours" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquets mis à jour au cours des 7 derniers jours" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquets mis à jour dans l'année écoulée" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquets jamais mis à jour" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilisateurs enregistrés" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Utilisateurs de confiance (TU)" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Mises à jour récentes" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mes statistiques" -msgid "Packages in unsupported" -msgstr "Paquets non supportés" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Détails de la proposition" +#: template/tu_details.php msgid "This vote is still running." msgstr "Ce vote est toujours en cours." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Soumission: %s par %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Résultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Non" +#: template/tu_details.php msgid "Abstain" msgstr "Abstention" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participation" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Derniers votes de TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Dernier vote" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Aucun résultat trouvé." +#: template/tu_list.php msgid "Start" msgstr "Début" +#: template/tu_list.php msgid "Back" msgstr "Retour" diff --git a/po/he.po b/po/he.po index 853c887e..fb98fe69 100644 --- a/po/he.po +++ b/po/he.po @@ -1,584 +1,777 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" -"he/)\n" -"Language: he\n" +"Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: he\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "חשבונות" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "אין לך גישה לאזור זה." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "לא ניתן לקבל נתונים עבור המשתמש שנבחר." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "אין לך הרשאה לערוך חשבון זה." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "נא להשתמש בטופס על מנת לחפש אחר חשבונות קיימים." +#: html/account.php msgid "You must log in to view user information." msgstr "עליך להתחבר על מנת לצפות בנתוני משתמש." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "הוספת הצעה" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "שם המשתמש לא קיים." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s יש כבר הצעה קיימת." +#: html/addvote.php msgid "Invalid type." msgstr "" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "הצעה לא יכולה להיות ריקה." +#: html/addvote.php msgid "New proposal submitted." msgstr "הצעה חדשה נשלחה." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "שליחת הצבעה עבור הפעלת הצבעה." +#: html/addvote.php msgid "Applicant/TU" msgstr "" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(ריק אם אינה מתאימה)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "סוג" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "הצעה" +#: html/addvote.php msgid "Submit" msgstr "שליחה" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "בית" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" +#: html/home.php msgid "DISCLAIMER" msgstr "" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "דיון" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "" +#: html/index.php msgid "Adopt" msgstr "" +#: html/index.php msgid "Vote" msgstr "הצבעה" +#: html/index.php msgid "UnVote" msgstr "ביטול הצבעה" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "התרעה" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "ביטול התרעה" -msgid "Flag" -msgstr "" - +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "כניסה" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "נכנסת בשם: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "ניתוק" +#: html/login.php msgid "Enter login credentials" msgstr "" -msgid "Username" -msgstr "שם משתמש" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "ססמה" +#: html/login.php msgid "Remember me" msgstr "שמירת הפרטים" +#: html/login.php msgid "Forgot Password" msgstr "" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "קריטריונים לחיפוש" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "חבילות" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "ארעה שגיאה בזמן קבלת נתוני חבילה." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "שדה הכרחי חסר." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "שדות הססמה לא תואמים." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "הססמה חייבת להיות באורך של %s אותיות לפחות." +#: html/passreset.php msgid "Invalid e-mail." msgstr "" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "איפוס ססמה" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "אישור כתובת הדוא״ל שלך" +#: html/passreset.php msgid "Enter your new password:" msgstr "הזנת ססמה חדשה:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "אישור הססמה החדשה:" +#: html/passreset.php msgid "Continue" msgstr "" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." msgstr "" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "נא להזין את כתובת הדוא״ל שלך:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "החבילות שנבחרו לא נמחקו, נא לבחור בתיבת האישור." +#: html/pkgdel.php msgid "Package Deletion" msgstr "" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "" + +#: html/pkgflag.php +msgid "Flag" +msgstr "" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "הבא" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "" +#: html/register.php msgid "Use this form to create an account." msgstr "ניתן להשתמש בטופס זה על מנת ליצור חשבון." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "משתמש אמין" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "לא ניתן לקבל נתוני הצעה." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "ההצבעה סגורה עבור הצעה זו." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "אין באפשרותך להצביע עבור הצעה הקשורה בך." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "כבר הצבעת עבור הצעה זו." +#: html/tu.php msgid "Vote ID not valid." msgstr "מס׳ הזיהוי של ההצבעה אינו תקין." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "הצבעות נוכחיות" +#: html/tu.php msgid "Past Votes" msgstr "" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "חסר מס׳ הזיהוי של המשתמש" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "שם המשתמש אינו חוקי." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "חייב להיות בין %s ל־%s אותיות" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "יש להתחיל ולסיים עם תו או מספר" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "יכול הכיל רק נקודה אחת, קו תחתון או מקף." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "כתובת הדוא״ל שהוזנה אינה תקינה." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "שפה כרגע לא נתמכת." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -msgid "Click on the Login link above to use your account." -msgstr "" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -586,730 +779,1028 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "" + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "שגיאה בקבלת נתוני חבילה." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "נתוני חבילה לא נמצאו." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לסמן חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "לא בחרת שום חבילות לסימון." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "החבילות שנבחרו מסומנות כלא עדכניות." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "עליך להתחבר לפני שיהיה באפשרותך לבטל סימוני חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "לא בחרת שום חבילות לביטול סימון." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "החבילות שנבחרו בוטלו מהסימון." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "לא בחרת שום חבילות למחיקה." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "החבילות המסומנות נמחקו." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לאמץ חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לבטל בעלות מחבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "לא בחרת שום חבילות לאימוץ." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "לא בחרת שום חבילות להסרת בעלותך מהן." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "החבילות שנבחרו אומצו." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "החבילות המסומנות ננטשו" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "עליך להיכנס לפני שתהיה באפשרותך להצביע לחבילות." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "עליך להתחבר לפני ביטול הצבעה עבור חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "לא בחרת שום חבילות להצביע עבורן." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "ההצבעות שלך הוסרו מהחבילות המסומנות." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "ההצבעות שלך נקלטו עבור החבילות המסומנות." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "לא ניתן לצרף את רשימת ההתרעות." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "צורפת אל רשימת ההתרעות עבור %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "הוסרת מרשימה ההתרעות עבור ההערות של %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "עליך להיכנס לפני שיהיה באפשרותך לערוך נתוני חבילה." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "חסר מס׳ זיהוי להערה." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "הערה נמחקה." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "אין לך הרשאה למחוק הערה זו." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "שם לא חוקי: רק אותיות קטנות מותרות." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "שם משתמש" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "סוג חשבון" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "משתמש" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "מפתח" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "כתובת דוא״ל" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "שם אמתי" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "כינוי ב־IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "מצב" +#: template/account_details.php msgid "Inactive since" msgstr "" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "פעיל" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "לעולם" +#: template/account_details.php msgid "View this user's packages" msgstr "צפייה בחבילות המשתמש" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "נדרש" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "משתמש רגיל" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "משתמשים אמינים" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "חשבון מושעה" +#: template/account_edit_form.php msgid "Inactive" msgstr "" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "הקלדת הססמה מחדש" +#: template/account_edit_form.php msgid "Language" msgstr "שפה" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "עדכון" +#: template/account_edit_form.php msgid "Create" msgstr "יצירה" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "איפוס" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "אין תוצאות עבור נתוני החיפוש שלך." +#: template/account_search_results.php msgid "Edit Account" msgstr "עריכת חשבון" +#: template/account_search_results.php msgid "Suspended" msgstr "השעייה" +#: template/account_search_results.php msgid "Edit" msgstr "" +#: template/account_search_results.php msgid "Less" msgstr "פחות" +#: template/account_search_results.php msgid "More" msgstr "עוד" +#: template/account_search_results.php msgid "No more results to display." msgstr "אין יותר תוצאות להצגה." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "החבילות שלי" +#: template/header.php msgid " My Account" msgstr "" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "מתחזק" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "הצבעות" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "" -msgid "Comment has been added." -msgstr "" - +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "מחיקת הערה" -#, php-format -msgid "Comment by %s" -msgstr "" - -msgid "Anonymous comment" -msgstr "" - -msgid "deleted" -msgstr "" - +#: template/pkg_comments.php msgid "All comments" msgstr "" +#: template/pkg_details.php msgid "Package Details" msgstr "נתוני חבילה" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "תיאור" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "" +#: template/pkg_details.php msgid "Replaces" msgstr "" +#: template/pkg_details.php msgid "Dependencies" msgstr "תלות" +#: template/pkg_details.php msgid "Required by" msgstr "נדרש על ידי" +#: template/pkg_details.php msgid "Sources" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "" -msgid "Comments" -msgstr "" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "" +#: template/pkg_search_form.php msgid "Name Only" msgstr "" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "" +#: template/pkg_search_form.php msgid "Flagged" msgstr "" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "שם" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "הצביעו" -msgid "Age" +#: template/pkg_search_form.php +msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "" +#: template/pkg_search_form.php msgid "Descending" msgstr "" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "חיפוש לפי" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "סידור לפי" +#: template/pkg_search_form.php msgid "Sort order" msgstr "סדר המיון" +#: template/pkg_search_form.php msgid "Per page" msgstr "לפי דף" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "מעבר" +#: template/pkg_search_form.php msgid "Orphans" msgstr "יתומות" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "שגיאה בעת קבלת רשימת החבילות." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "אין חבילות התואמות לנתוני החיפוש שלך." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +#: template/pkg_search_results.php msgid "Version" msgstr "" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "כן" +#: template/pkg_search_results.php msgid "orphan" msgstr "יתומה" +#: template/pkg_search_results.php msgid "Actions" msgstr "פעולות" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "סימון כלא עדכני" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "ביטול סימון כלא מעודכן" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "אימוץ חבילות" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "שחרור בעלות על חבילות" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "מחיקת חבילות" +#: template/pkg_search_results.php msgid "Confirm" msgstr "אישור" +#: template/search_accounts_form.php msgid "Any type" msgstr "כל סוג" +#: template/search_accounts_form.php msgid "Search" msgstr "חיפוש" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "" -msgid "Packages in unsupported" -msgstr "" - +#: template/tu_details.php msgid "Proposal Details" msgstr "פרטי הצעה" +#: template/tu_details.php msgid "This vote is still running." msgstr "ההצבעה עדיין קיימת." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "נשלח: %s על ידי %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "סוף" +#: template/tu_details.php msgid "Result" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "לא" +#: template/tu_details.php msgid "Abstain" msgstr "הימנעות" +#: template/tu_details.php msgid "Total" msgstr "סך הכול" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "תוצאות לא נמצאו." +#: template/tu_list.php msgid "Start" msgstr "התחלה" +#: template/tu_list.php msgid "Back" msgstr "חזרה" diff --git a/po/hr.po b/po/hr.po index ef5e289d..9aa50369 100644 --- a/po/hr.po +++ b/po/hr.po @@ -1,585 +1,777 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" -"hr/)\n" -"Language: hr\n" +"Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"Language: hr\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +#: html/404.php msgid "Page Not Found" msgstr "" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "Računi" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nije vam dozvoljen pristup ovom području." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nije moguće naći informacije o zadanom korisniku." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemate ovlasti da bi mjenjali ovaj račun." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Koristite ovaj formular za pretraživanj postoječih računa." +#: html/account.php msgid "You must log in to view user information." msgstr "Morate se logirati kako bi pregledali informacije o korisniku." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "Korisničko ime ne postoji." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s već ima prijedlog." +#: html/addvote.php msgid "Invalid type." msgstr "" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Prijedlog nemože biti prazan." +#: html/addvote.php msgid "New proposal submitted." msgstr "Novi prijedlog je poslan." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Pošalji prijedlog za glasanje." +#: html/addvote.php msgid "Applicant/TU" msgstr "" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prazno ako nije prikladno)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tip" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Prijedlog" +#: html/addvote.php msgid "Submit" msgstr "Pošalji" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Početna" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" +#: html/home.php msgid "DISCLAIMER" msgstr "" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Rasprava" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "" +#: html/index.php msgid "Adopt" msgstr "" +#: html/index.php msgid "Vote" msgstr "Glasaj" +#: html/index.php msgid "UnVote" msgstr "Makni glas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Obavijesti" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne obavještavaj" -msgid "Flag" -msgstr "" - +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "Login" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Logirani ste kao: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Logout" +#: html/login.php msgid "Enter login credentials" msgstr "" -msgid "Username" -msgstr "Korisničko ime" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" +#: html/login.php msgid "Remember me" msgstr "Zapamti me" +#: html/login.php msgid "Forgot Password" msgstr "" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kriteriji traženja" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketi" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Došlo je do greške prilikom dobivanja detalja o paketu." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Nedostaje Vam obvezno polje." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Lozinke nisu jednake." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Lozinka mora sadržavati najmanje %s znakova." +#: html/passreset.php msgid "Invalid e-mail." msgstr "" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "" +#: html/passreset.php msgid "Enter your new password:" msgstr "" +#: html/passreset.php msgid "Confirm your new password:" msgstr "" +#: html/passreset.php msgid "Continue" msgstr "" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." msgstr "" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "" + +#: html/pkgflag.php +msgid "Flag" +msgstr "" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sljedeći" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "" +#: html/register.php msgid "Use this form to create an account." msgstr "Koristite ovaj formular za kreiranje računa." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Pouzdan korisnik" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nemogu pronaći detalje o prijedlogu." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Glasanje je zaključeno za ovaj prijedlog" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemožete glasati o prijedlogu koji se tiće Vas." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Već ste glasali za ovaj prijedlog." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID glasa je neispravan." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Trenutno glasova" +#: html/tu.php msgid "Past Votes" msgstr "" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Nedostaje ID korisnika" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Korisničko ime je neispravno." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Mora biti najmanje %s a najviše %s znakova" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Zapični i završi sa slovom ili brojkom" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržavati samo jednu točku, donju crticu ili povlaku." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Email adresa je neispravna." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -msgid "Click on the Login link above to use your account." -msgstr "" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -587,333 +779,497 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Komentar je dodan." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Došlo je do greške prilikom preuzimanja detalja o paketu." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nije moguće naći detalje o paketu." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Morate se logirati da bi obilježavali pakete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Niste odabrali pakete koje želite obilježiti." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Odabrani paketi su obilježeni kao zastarijeli." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Morate se logirati da bi mogli obilježiti pakete kao ažurirane." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Niste odabrali pakete koje želite obilježiti kao ažurirane." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Odabrani paketu su postavljeni kao ažurirani." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Niste odabrali pakete koje želite izbrisati." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Odabrani paketi su izbrisani." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Morate se logirati da bi posvojili pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Morate se logirati da bi se mogli odreknuti paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Niste odabrali pakete koje želite posvojiti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Niste odabrali pakete kojih se želite odreči." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Posvojili ste odabrane pakete." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Odrekli ste se odabranih paketa." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Morate se logirati da bi glasali za pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Morate se logirati da bi mogli maknuti svoje glasove s paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Niste odabrali pakete za koje želite glasati." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaši su glasovi maknuti s odabranih paketa." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Glasovi su dodijeljeni odabranim paketima." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nemogu dodati u listu za obavještavanje." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Dodani ste u listu za obavještavanje o novim komentarima za %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Niste više na listi za obavježtavanje o novim komentarima za %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Morate biti logirani da biste mogli mijenjati informacije o paketu." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Nedostaje ID komentara." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentar je izbrisan." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Brisanje ovog komentara Vam nije dozvoljeno." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neispravno ime: Dozvoljena su samo mala slova (kurenti)." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Korisničko ime" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip računa" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Korisnik" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Developer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Email adresa" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Vaše stvarno ime" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nadimak na IRC-u" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stanje" +#: template/account_details.php msgid "Inactive since" msgstr "" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivan" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Nikad" +#: template/account_details.php msgid "View this user's packages" msgstr "Pregledaj pakete ovog korisnika" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "obvezno" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Običan korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Pouzdan korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Račun je suspendiran" +#: template/account_edit_form.php msgid "Inactive" msgstr "" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Ponovno upišite lozinku" +#: template/account_edit_form.php msgid "Language" msgstr "Jezik" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Ažuriraj" +#: template/account_edit_form.php msgid "Create" msgstr "Kreiraj" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetiraj" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nema rezultata pretrage." +#: template/account_search_results.php msgid "Edit Account" msgstr "Podesi račun" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendiran" +#: template/account_search_results.php msgid "Edit" msgstr "" +#: template/account_search_results.php msgid "Less" msgstr "Manje" +#: template/account_search_results.php msgid "More" msgstr "Više" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nema više rezultata za prikaz." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Moji paketi" +#: template/header.php msgid " My Account" msgstr "" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -921,165 +1277,232 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "nepoznato" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Održavatelj" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Glasovi" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvi put poslan" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Posljednji put ažuriran" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "" -msgid "Comment has been added." -msgstr "Komentar je dodan." - +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Briši komentar" -#, php-format -msgid "Comment by %s" -msgstr "" - -msgid "Anonymous comment" -msgstr "" - -msgid "deleted" -msgstr "" - +#: template/pkg_comments.php msgid "All comments" msgstr "" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalji o paketu" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "" +#: template/pkg_details.php msgid "Replaces" msgstr "" +#: template/pkg_details.php msgid "Dependencies" msgstr "Ovisi o" +#: template/pkg_details.php msgid "Required by" msgstr "Potreban za" +#: template/pkg_details.php msgid "Sources" msgstr "Izvor" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "" -msgid "Comments" -msgstr "" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1087,23 +1510,29 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1111,90 +1540,116 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "" +#: template/pkg_search_form.php msgid "Name Only" msgstr "" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "" +#: template/pkg_search_form.php msgid "Flagged" msgstr "" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Ime" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Glasao" -msgid "Age" +#: template/pkg_search_form.php +msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "" +#: template/pkg_search_form.php msgid "Descending" msgstr "" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Traži po" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastario" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortiraj po" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Način sortiranja" +#: template/pkg_search_form.php msgid "Per page" msgstr "Po stranici" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Traži" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Napušteni" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Došlo je do greške prilikom stvaranja liste paketa." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nijedan paket ne odgovara kriterijima traženja." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1202,119 +1657,154 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkg_search_results.php msgid "Version" msgstr "" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Da" +#: template/pkg_search_results.php msgid "orphan" msgstr "napušten" +#: template/pkg_search_results.php msgid "Actions" msgstr "Radnje" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Obilježi kao zastario" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Obilježi kao ažuriran" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Posvoji paket" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odrekni se paketa" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Izbriši pakete" +#: template/pkg_search_results.php msgid "Confirm" msgstr "" +#: template/search_accounts_form.php msgid "Any type" msgstr "Bilo koji tip" +#: template/search_accounts_form.php msgid "Search" msgstr "Traži" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "" -msgid "Packages in unsupported" -msgstr "" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalji prijedloga" +#: template/tu_details.php msgid "This vote is still running." msgstr "Ovaj glas još vrijedi." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Poslan: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Kraj" +#: template/tu_details.php msgid "Result" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" +#: template/tu_details.php msgid "Abstain" msgstr "Suzdržan" +#: template/tu_details.php msgid "Total" msgstr "Ukupno" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nema rezultata." +#: template/tu_list.php msgid "Start" msgstr "Početak" +#: template/tu_list.php msgid "Back" msgstr "Natrag" diff --git a/po/hu.po b/po/hu.po index d7046a8a..b0104b8a 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # György Balló , 2013 # György Balló , 2011,2013-2015 @@ -10,1391 +10,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-07-18 23:05+0000\n" -"Last-Translator: György Balló \n" -"Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" -"hu/)\n" -"Language: hu\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Az oldal nem található" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Sajnálom, a megtekinteni kívánt oldal nem létezik." +#: html/503.php msgid "Service Unavailable" msgstr "Szolgáltatás nem elérhető" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Nyugalom! Ez a webhely karbantartás miatt nem üzemel. Hamarosan visszajövünk." +msgstr "Nyugalom! Ez a webhely karbantartás miatt nem üzemel. Hamarosan visszajövünk." +#: html/account.php msgid "Account" msgstr "Fiók" +#: html/account.php template/header.php msgid "Accounts" msgstr "Fiókok" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nincs engedélyed hozzáférni ehhez a területhez." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nem sikerült letölteni a megadott felhasználó információit." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nincs engedélyed ennek a fióknak a szerkesztéséhez." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Már meglévő felhasználói fiókok kereséséhez használd ezt az űrlapot." +#: html/account.php msgid "You must log in to view user information." msgstr "A felhasználói információ megtekintéshez be kell jelentkezned." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Indítvány hozzáadása" +#: html/addvote.php msgid "Invalid token for user action." msgstr "A token érvénytelen a felhasználói művelethez." +#: html/addvote.php msgid "Username does not exist." msgstr "Ez a felhasználói név nem létezik." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s már megpályázta őket." +#: html/addvote.php msgid "Invalid type." msgstr "Érvénytelen típus." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Az indítvány nem lehet üres." +#: html/addvote.php msgid "New proposal submitted." msgstr "Új indítvány benyújtva." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Indítvány szavazásra bocsátása." +#: html/addvote.php msgid "Applicant/TU" msgstr "Jelölt/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(üres, ha nem alkalmazható)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Típus" +#: html/addvote.php msgid "Addition of a TU" msgstr "TU hozzáadása" +#: html/addvote.php msgid "Removal of a TU" msgstr "TU eltávolítása" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU eltávolítása (be nem jelentett inaktivitás)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Szabályzat módosítása" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Indítvány" +#: html/addvote.php msgid "Submit" msgstr "Feltöltés" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Társkarbantartók kezelése" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Honlap" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Üdvözlünk az AUR-ban! További információért olvasd el az %sAUR felhasználói " -"irányelveket%s és az %sAUR TU irányelveket%s." +msgstr "Üdvözlünk az AUR-ban! További információért olvasd el az %sAUR felhasználói irányelveket%s és az %sAUR TU irányelveket%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"A beküldött PKGBUILD-eknek meg %skell%s felelniük az %sArch csomagolási " -"szabályoknak%s, különben törlésre kerülnek!" +msgstr "A beküldött PKGBUILD-eknek meg %skell%s felelniük az %sArch csomagolási szabályoknak%s, különben törlésre kerülnek!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ne felejts el szavazni kedvenc csomagjaidra!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Néhány csomagot lehet, hogy a [community] binárisként szolgáltat." +#: html/home.php msgid "DISCLAIMER" msgstr "NYILATKOZAT" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"A nem támogatott csomagok felhasználók által készített tartalmak. A " -"szolgáltatott fájlok bármilyen felhasználása csak saját felelősségre " -"történik." +#: html/home.php msgid "Learn more..." msgstr "Tudj meg többet..." +#: html/home.php msgid "Support" msgstr "Támogatás" +#: html/home.php msgid "Package Requests" msgstr "Csomagkérelmek" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Háromfajta kérelem tölthető ki a %sCsomagműveletek%s dobozban a csomag " -"részletei oldalon:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Háromfajta kérelem tölthető ki a %sCsomagműveletek%s dobozban a csomag részletei oldalon:" +#: html/home.php msgid "Orphan Request" msgstr "Megtagadási kérelem" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Egy csomag megtagadásának kérése, pl. amikor a karbantartó inaktív, és a " -"csomag régóta elavultnak lett jelölve." +msgstr "Egy csomag megtagadásának kérése, pl. amikor a karbantartó inaktív, és a csomag régóta elavultnak lett jelölve." +#: html/home.php msgid "Deletion Request" msgstr "Törlési kérelem" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Egy csomag Arch User Repositoriból való törlésének kérése. Kérünk, ne " -"használd ezt, ha a csomag törött, és könnyen javítható. Ehelyett vedd fel a " -"kapcsolatot a csomag karbantartójával, és tölts ki megtagadási kérelmet, ha " -"szükséges." +msgstr "Egy csomag Arch User Repositoriból való törlésének kérése. Kérünk, ne használd ezt, ha a csomag törött, és könnyen javítható. Ehelyett vedd fel a kapcsolatot a csomag karbantartójával, és tölts ki megtagadási kérelmet, ha szükséges." +#: html/home.php msgid "Merge Request" msgstr "Beolvasztási kérelem" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Egy csomag másik csomagba történő beolvasztásának kérése. Akkor használható, " -"amikor egy csomagot át kell nevezni, vagy lecserélésre kerül egy osztott " -"csomagra." +msgstr "Egy csomag másik csomagba történő beolvasztásának kérése. Akkor használható, amikor egy csomagot át kell nevezni, vagy lecserélésre kerül egy osztott csomagra." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Ha meg szeretnél tárgyalni egy kérelmet, használd az %saur-requests%s " -"levelezőlistát. Azonban ne használd ezt a listát kérvények beadására." +msgstr "Ha meg szeretnél tárgyalni egy kérelmet, használd az %saur-requests%s levelezőlistát. Azonban ne használd ezt a listát kérvények beadására." +#: html/home.php msgid "Submitting Packages" msgstr "Csomagok beküldése" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Jelenleg SSH-n keresztüli Git használandó a csomagok beküldéséhez az AUR-ba. " -"További részletekért lásd a %sCsomagok beküldése%s szakaszt az Arch User " -"Repository ArchWiki oldalon." +msgstr "Jelenleg SSH-n keresztüli Git használandó a csomagok beküldéséhez az AUR-ba. További részletekért lásd a %sCsomagok beküldése%s szakaszt az Arch User Repository ArchWiki oldalon." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Az alábbi SSH ujjlenyomatokat használjuk az AUR-hoz:" +#: html/home.php msgid "Discussion" msgstr "Megbeszélés" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Az Arch User Repositoryval (AUR) és a Trusted User struktúrával kapcsolatos " -"általános tanácskozás helye az %saur-general%s. Az AUR webes felületének " -"fejlesztésével kapcsolatos tanácskozáshoz az %saur-dev%s levelezőlista " -"használandó." +msgstr "Az Arch User Repositoryval (AUR) és a Trusted User struktúrával kapcsolatos általános tanácskozás helye az %saur-general%s. Az AUR webes felületének fejlesztésével kapcsolatos tanácskozáshoz az %saur-dev%s levelezőlista használandó." +#: html/home.php msgid "Bug Reporting" msgstr "Hibajelentés" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Ha hibát találsz az AUR webes felületén, kérjük, tölts ki egy hibajelentést " -"a %shibabejelentőnkön%s. %sCsak%s az AUR-ban lévő hibák jelentésére használd " -"a bejelentőt. Csomagolási hibák jelentéséhez vedd fel a kapcsolatot a csomag " -"karbantartójával, vagy hagyj egy hozzászólást a megfelelő csomag oldalán." +#: html/home.php msgid "Package Search" msgstr "Csomag keresése" +#: html/index.php msgid "Adopt" msgstr "Örökbe fogadás" +#: html/index.php msgid "Vote" msgstr "Szavazás" +#: html/index.php msgid "UnVote" msgstr "Szavazat visszavonása" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Értesítés" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Értesítés kikapcsolása" -msgid "Flag" -msgstr "Megjelölés" - +#: html/index.php msgid "UnFlag" msgstr "Megjelölés visszavonása" +#: html/login.php template/header.php msgid "Login" msgstr "Bejelentkezés" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Bejelentkezve mint: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Kijelentkezés" +#: html/login.php msgid "Enter login credentials" msgstr "Bejelentkezési adatok megadása" -msgid "Username" -msgstr "Felhasználónév" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Jelszó" +#: html/login.php msgid "Remember me" msgstr "Maradjak bejelentkezve" +#: html/login.php msgid "Forgot Password" msgstr "Elfelejtett jelszó" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"A HTTP bejelentkezés letiltásra került. Ha be szeretnél jelentkezni, akkor " -"kérünk, hogy %sválts át HTTPs-re%s." +msgstr "A HTTP bejelentkezés letiltásra került. Ha be szeretnél jelentkezni, akkor kérünk, hogy %sválts át HTTPs-re%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Keresési feltételek" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Csomagok" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Egy kötelező mező megadása hiányzik." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "A jelszó mezők nem egyeznek." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "A jelszónak legalább %s karakter hosszúságúnak kell lennie." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Érvénytelen e-mail." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Egy jelszó-visszaállítási kérelem került beküldésre az e-mail címedhez " -"tartozó %s felhasználói fiókhoz. Ha szeretnéd visszaállítani a jelszavad, " -"kövesd az alábbi hivatkozást, egyébként hagyd figyelmen kívül ezt az " -"üzenetet, és nem történik semmi." - +#: html/passreset.php msgid "Password Reset" msgstr "Jelszó visszaállítása" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Ellenőrizd az e-mailjeidet a megerősítő hivatkozáshoz." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Jelszavad sikeresen visszaállításra került." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Erősíts meg az e-mail címedet:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Add meg az új jelszavad:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Erősítsd meg az új jelszavad:" +#: html/passreset.php msgid "Continue" msgstr "Folytatás" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Ha elfelejtetted az e-mail címet, amit a regisztrációhoz használtál, akkor " -"küldj egy üzenetet az %saur-general%s levelezőlistára." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Ha elfelejtetted az e-mail címet, amit a regisztrációhoz használtál, akkor küldj egy üzenetet az %saur-general%s levelezőlistára." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Add meg az e-mail címedet:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"A kiválasztott csomagok nem kerültek megtagadásra, ellenőrizd a megerősítő " -"jelölőnégyzetet." +msgstr "A kiválasztott csomagok nem kerültek megtagadásra, ellenőrizd a megerősítő jelölőnégyzetet." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Nem található csomag, amelybe a szavazatok és megjegyzések beolvaszthatók " -"lennének." +msgstr "Nem található csomag, amelybe a szavazatok és megjegyzések beolvaszthatók lennének." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Egy alapcsomag nem olvasztható önmagába." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"A kiválasztott csomagok nem kerültek törlésre, ellenőrizd a megerősítő " -"jelölőnégyzetet." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "A kiválasztott csomagok nem kerültek törlésre, ellenőrizd a megerősítő jelölőnégyzetet." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Csomag törlése" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Csomag törlése: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomag és az alábbi csomagok " -"törléséhez az AUR-ból:" +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag és az alábbi csomagok törléséhez az AUR-ból:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Egy csomag törlése végleges. " +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "A művelet megerősítéséhez jelöld be a jelölőnégyzetet." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Csomag törlésének megerősítése" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Törlés" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Csak megbízható felhasználók és fejlesztők tudnak csomagokat törölni." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Csomag megtagadása" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Csomag megtagadása: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomag megtagadásához, amely a " -"következő csomagokat tartalmazza:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag megtagadásához, amely a következő csomagokat tartalmazza:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " -"csomagot, és átadni a tulajdonjogot neki: %s%s%s." +msgstr "A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a csomagot, és átadni a tulajdonjogot neki: %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " -"csomagot." +msgstr "A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a csomagot." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Csomag megtagadásának megerősítése." +#: html/pkgdisown.php msgid "Disown" msgstr "Megtagadás" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." +msgstr "Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Megjegyzések" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Megjelölés" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Csomag beolvasztása" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Csomag beolvasztása: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomag másik csomagba történő " -"beolvasztásához." +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag másik csomagba történő beolvasztásához." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "A következő csomagok törlésre kerülnek:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Ha egyszer egy csomag beolvasztásra került, többé nem lehet visszaállítani. " +msgstr "Ha egyszer egy csomag beolvasztásra került, többé nem lehet visszaállítani. " +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Add meg a csomag nevét, amibe szeretnéd beolvasztani a csomagot." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Beolvasztás ebbe:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Csomag beolvasztásának megerősítése" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Beolvasztás" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Csak megbízható felhasználók és fejlesztők tudnak csomagokat beolvasztani." +msgstr "Csak megbízható felhasználók és fejlesztők tudnak csomagokat beolvasztani." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Kérelem beadása" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Kérelem lezárása" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Első" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Előző" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Következő" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Utolsó" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Kérelmek" +#: html/register.php template/header.php msgid "Register" msgstr "Regisztráció" +#: html/register.php msgid "Use this form to create an account." msgstr "Használd ezt a űrlapot felhasználói fiók létrehozására." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Megbízható felhasználó" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nem sikerült az indítvány részletes információinak letöltése." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A szavazás lezárult erre az indítványra." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "A szavazás csak megbízható felhasználóknak engedélyezett." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nem szavazhatsz egy rólad szóló indítványra." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Már szavaztál erre az indítványra." +#: html/tu.php msgid "Vote ID not valid." msgstr "Érvénytelen szavazatazonosító." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Jelenlegi szavazatok" +#: html/tu.php msgid "Past Votes" msgstr "Korábbi szavazatok" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Szavazók" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"A felhasználói regisztráció jelenleg letiltásra került az IP címedre, " -"valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +msgstr "A felhasználói regisztráció jelenleg letiltásra került az IP címedre, valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Hiányzó felhasználóazonosító" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "A felhasználónév érvénytelen." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "%s és %s közötti karakterhosszúságúnak kell lennie" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Betűvel vagy számjeggyel kezdődjön és végződjön" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Csak egyetlen pontot, aláhúzást vagy kötőjelet tartalmazhat." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Érvénytelen e-mail cím." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A PGP kulcs ujjlenyomata érvénytelen." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "A nyilvános SSH kulcs érvénytelen." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nem lehet megnövelni a fiók jogosultságait." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "A nyelv jelenleg nem támogatott." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "A(z) %s%s%s felhasználónév már használatban van." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "A(z) %s%s%s cím már használatban van." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "A(z) %s%s%s nyilvános SSH kulcs már használatban van." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Hiba történt a(z) %s%s%s fiók létrehozása során." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A(z) %s%s%s fiók sikeresen létrejött." -msgid "Click on the Login link above to use your account." -msgstr "A fiókod használatához kattints a Bejelentkezés hivatkozásra feljebb." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Köszöntünk az %s-ban! Fiókodhoz tartozó kezdeti jelszó beállításához " -"kattints az alábbi hivatkozásra. Ha nem működik a hivatkozás, akkor próbáld " -"kimásolni és beilleszteni a böngészőbe." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Egy jelszó-visszaállító kulcs kiküldésre került az e-mail címedre." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "A fiókod használatához kattints a Bejelentkezés hivatkozásra feljebb." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "A(z) %s%s%s fiók nem módosult." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A(z) %s%s%s fiók sikeresen módosítva." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"A bejelentkező űrlap jelenleg letiltásra került az IP címedre, valószínűleg " -"rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +msgstr "A bejelentkező űrlap jelenleg letiltásra került az IP címedre, valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Fiók felfüggesztve" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"A jelszavad visszaállításra került. Ha most regisztráltál, akkor a " -"megerősítő e-mailben található hivatkozással beállíthatsz egy kezdeti " -"jelszót. Egyéb esetben kérj egy visszaállító kulcsot a %sJelszó " -"visszaállítása%s oldalon." +msgstr "A jelszavad visszaállításra került. Ha most regisztráltál, akkor a megerősítő e-mailben található hivatkozással beállíthatsz egy kezdeti jelszót. Egyéb esetben kérj egy visszaállító kulcsot a %sJelszó visszaállítása%s oldalon." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Hibás felhasználónév vagy jelszó." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Hiba történt a felhasználói munkamenet létrehozásának megkísérlésekor." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Érvénytelen e-mail és visszaállító kulcs kombináció." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nincs" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Fiók információinak megtekintése – %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "A megjegyzés hozzáadva." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "A csomag részletes információi nem találhatók." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Csomagok megjelöléséhez be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nem választottál ki egyetlen csomagot sem megjelölésre." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "A kiválasztott csomagok elavultnak lettek jelölve." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Csomagok megjelölésének visszavonásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nem választottál ki egyetlen csomagot sem megjelölés visszavonására." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "A kiválasztott csomagok bejelölése visszavonva." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Csomagok törléséhez nincs jogosultságod." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nem választottál ki egyetlen törlendő csomagot sem." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "A kiválasztott csomagok törlése megtörtént." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Csomagok örökbefogadásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Csomagok megtagadásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nem választottál ki egyetlen örökbe fogadandó csomagot sem." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nem választottál ki egyetlen csomagot sem megtagadásra." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Sikeresen örökbe fogadtad a kiválasztott csomagokat." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "A kiválasztott csomagok megtagadva." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Csomagokra történő szavazáshoz be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Csomagokra adott szavazatok visszavonásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nem választottál ki egyetlen csomagot sem, amire szavaznál." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Szavazatod eltávolításra került a kiválasztott csomagokról." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Leadtad a szavazatod a kiválasztott csomagokra." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nem sikerült hozzáadni az értesítési listához." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "" -"Sikeresen fel lettél véve a(z) %s csomag megjegyzésértesítési listájára." +msgstr "Sikeresen fel lettél véve a(z) %s csomag megjegyzésértesítési listájára." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "El lettél távolítva a(z) %s csomag megjegyzésértesítési listájáról." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "A csomag információinak szerkesztéséhez be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Hiányzó megjegyzésazonosító." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Megjegyzés törölve." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nem törölheted ezt a megjegyzést." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nem szerkesztheted ennek az alapcsomagnak a kulcsszavait." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Az alapcsomag kulcsszavai frissítve lettek." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nem szerkesztheted ennek az alapcsomagnak a társkarbantartóit." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Érvénytelen felhasználónév: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Az alapcsomag társkarbantartói frissítve lettek." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Csomag részleteinek megtekintése –" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Csomagkérelmek beküldéséhez be kell jelentkezned." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Érvénytelen név: csak kisbetűk használata engedélyezett." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "A megjegyzés mező nem lehet üres." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Érvénytelen kérelemtípus." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Kérelem sikeresen hozzáadva." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Érvénytelen ok." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Csak megbízható felhasználók és fejlesztők tudnak kérelmeket lezárni." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Kérelem sikeresen lezárva." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ez az űrlap %s AUR fiókjának végleges törléséhez használható." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sFIGYELMEZTETÉS%s: ez a művelet nem visszavonható." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Törlés megerősítése" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Felhasználónév" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Fióktípus" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Felhasználó" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Fejlesztő" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Megbízható felhasználó és fejlesztő" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail cím" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Valós név" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC becenév" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP kulcs ujjlenyomata" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Állapot" +#: template/account_details.php msgid "Inactive since" msgstr "Ezóta inaktív:" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktív" +#: template/account_details.php msgid "Last Login" msgstr "Legutóbbi bejelentkezés" +#: template/account_details.php msgid "Never" msgstr "Soha" +#: template/account_details.php msgid "View this user's packages" msgstr "A felhasználó csomagjainak megtekintése" +#: template/account_details.php msgid "Edit this user's account" msgstr "Ezen felhasználó fiókjának szerkesztése" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kattints %side%s, ha véglegesen törölni szeretnéd ezt a fiókot." +#: template/account_edit_form.php msgid "required" msgstr "kötelező" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normál felhasználó" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Megbízható felhasználó" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Felhasználói fiók felfüggesztve" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktív" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Megismételt jelszó" +#: template/account_edit_form.php msgid "Language" msgstr "Nyelv" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Az alábbi információ csak akkor szükséges, ha csomagokat szeretnél beküldeni " -"az Arch User Repositoryba." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Az alábbi információ csak akkor szükséges, ha csomagokat szeretnél beküldeni az Arch User Repositoryba." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Nyilvános SSH kulcs" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Frissítés" +#: template/account_edit_form.php msgid "Create" msgstr "Létrehozás" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Visszaállítás" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nincs a keresési feltételeknek megfelelő találat." +#: template/account_search_results.php msgid "Edit Account" msgstr "Felhasználói fiók szerkesztése" +#: template/account_search_results.php msgid "Suspended" msgstr "Felfüggesztve" +#: template/account_search_results.php msgid "Edit" msgstr "Szerkesztés" +#: template/account_search_results.php msgid "Less" msgstr "Kevesebb" +#: template/account_search_results.php msgid "More" msgstr "Több" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nincs több kijelezhető eredmény." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Társkarbantartók kezelése: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Használd ezt az űrlapot társszerkesztők hozzáadásához a(z) %s%s%s csomaghoz " -"(soronként egy felhasználónév):" +msgstr "Használd ezt az űrlapot társszerkesztők hozzáadásához a(z) %s%s%s csomaghoz (soronként egy felhasználónév):" +#: template/comaintainers_form.php msgid "Users" msgstr "Felhasználók" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Mentés" +#: template/header.php msgid "My Packages" msgstr "Csomagjaim" +#: template/header.php msgid " My Account" msgstr " Fiókom" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Csomagműveletek" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD megtekintése" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Módosítások megtekintése" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Pillanatkép letöltése" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Keresés wikiben" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Elavultnak jelölve" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Csomag elavultnak jelölése" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Csomag jelölésének visszavonása" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Szavazat eltávolítása" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Szavazás erre a csomagra" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Értesítések kikapcsolása" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Értesítés új hozzászólásról" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Társszerkesztők kezelése" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d függő kérelem" msgstr[1] "%d függő kérelem" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Csomag törlése" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Csomag beolvasztása" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Csomag örökbe fogadása" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "ismeretlen" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Alapcsomag részletei" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git klónozási URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "csak olvasható" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Kulcsszavak" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Beküldő" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Karbantartó" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Legutóbbi csomagoló" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Szavazatok" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Népszerűség" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Először beküldve" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Legutóbb frissítve" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Hosszászólás" -msgid "Comment has been added." -msgstr "A megjegyzés hozzáadva." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Összes megjegyzés megjelenítése" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Legújabb hozzászólások" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Hozzászólás törlése" -#, php-format -msgid "Comment by %s" -msgstr "%s hozzászólása" - -msgid "Anonymous comment" -msgstr "Névtelen megjegyzés" - -msgid "deleted" -msgstr "törölve" - +#: template/pkg_comments.php msgid "All comments" msgstr "Összes hozzászólás" +#: template/pkg_details.php msgid "Package Details" msgstr "Részletes csomaginformáció" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Alapcsomag" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Leírás" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "A webhely meglátogatása –" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencek" +#: template/pkg_details.php msgid "Groups" msgstr "Csoportok" +#: template/pkg_details.php msgid "Conflicts" msgstr "Ütközik" +#: template/pkg_details.php msgid "Provides" msgstr "Szolgáltatja" +#: template/pkg_details.php msgid "Replaces" msgstr "Lecseréli" +#: template/pkg_details.php msgid "Dependencies" msgstr "Függőségek" +#: template/pkg_details.php msgid "Required by" msgstr "Igényli" +#: template/pkg_details.php msgid "Sources" msgstr "Források" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Kérelem lezárása: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem " -"lezárásához." +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem lezárásához." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Megjegyzés" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"A megjegyzések mező üresen hagyható. Viszont kérelem elutasításakor erősen " -"javasolt megjegyzés hozzáadása." +msgstr "A megjegyzések mező üresen hagyható. Viszont kérelem elutasításakor erősen javasolt megjegyzés hozzáadása." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Ok" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Elfogadva" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Elutasítva" -msgid "Comments" -msgstr "Megjegyzések" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Kérelem benyújtása: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem " -"benyújtásához, amely a következő csomagokat tartalmazza:" +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem benyújtásához, amely a következő csomagokat tartalmazza:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Kérelem típusa" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Törlés" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Megtagadás" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Beolvasztás ebbe:" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d csomagokkal kapcsolatos kérelem található." msgstr[1] "%d csomagokkal kapcsolatos kérelem található." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "%d. oldal, összesen: %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Csomag" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Kitöltő" +#: template/pkgreq_results.php msgid "Date" msgstr "Dátum" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d nap van hátra" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d óra van hátra" msgstr[1] "~%d óra van hátra" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 óra van hátra" +#: template/pkgreq_results.php msgid "Accept" msgstr "Elfogadás" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zárolva" +#: template/pkgreq_results.php msgid "Close" msgstr "Lezárás" +#: template/pkgreq_results.php msgid "Closed" msgstr "Lezárva" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Név, leírás" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Csak név" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Pontos név" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pontos alapcsomag" +#: template/pkg_search_form.php msgid "All" msgstr "Összes" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Jelölt" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nem jelölt" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Név" -msgid "Popularity" -msgstr "Népszerűség" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Szavazva" -msgid "Age" -msgstr "Kor" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Növekvő" +#: template/pkg_search_form.php msgid "Descending" msgstr "Csökkenő" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Keresési feltételek megadása" +#: template/pkg_search_form.php msgid "Search by" msgstr "Keresés eszerint" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Elavult" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Rendezés" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Rendezési sorrend" +#: template/pkg_search_form.php msgid "Per page" msgstr "Laponként" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Mehet" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Árvák" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Hiba történt a csomaglista letöltése közben." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nincs a keresési feltételeknek megfelelő csomag." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d csomag található." msgstr[1] "%d csomag található." +#: template/pkg_search_results.php msgid "Version" msgstr "Verzió" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat " -"súlyozásra kerül naponta 0,98-as faktorral a létrehozása óta." +msgstr "A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat súlyozásra kerül naponta 0,98-as faktorral a létrehozása óta." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Igen" +#: template/pkg_search_results.php msgid "orphan" msgstr "árva" +#: template/pkg_search_results.php msgid "Actions" msgstr "Tevékenységek" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Elavultnak jelölés" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Elavultság visszavonása" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Csomagok örökbefogadása" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Csomagok megtagadása" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Csomagok törlése" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Megerősítés" +#: template/search_accounts_form.php msgid "Any type" msgstr "Bármilyen típus" +#: template/search_accounts_form.php msgid "Search" msgstr "Keresés" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statisztika" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Árva csomagok" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "A legutóbbi 7 napban hozzáadott csomagok" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "A legutóbbi 7 napban frissített csomagok" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Az utóbbi évben frissített csomagok" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Soha nem frissített csomagok" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Regisztrált felhasználók" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Megbízható felhasználók" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Legutóbbi frissítések" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Statisztikám" -msgid "Packages in unsupported" -msgstr "Csomagok az „unsupported”-ben" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Indítvány részletes információi" +#: template/tu_details.php msgid "This vote is still running." msgstr "A szavazás még zajlik." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Benyújtva: %s (%s által)" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Vége" +#: template/tu_details.php msgid "Result" msgstr "Eredmény" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nem" +#: template/tu_details.php msgid "Abstain" msgstr "Tartózkodik" +#: template/tu_details.php msgid "Total" msgstr "Összesen" +#: template/tu_details.php msgid "Participation" msgstr "Részvétel" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Legutóbbi szavazatok TU szerint" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Legutóbbi szavazat" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nincs találat." +#: template/tu_list.php msgid "Start" msgstr "Kezdés" +#: template/tu_list.php msgid "Back" msgstr "Vissza" diff --git a/po/it.po b/po/it.po index ef222dd5..3e97e59e 100644 --- a/po/it.po +++ b/po/it.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Giovanni Scafora , 2011-2015 # Lorenzo Porta , 2014 @@ -10,1403 +10,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-23 09:15+0000\n" -"Last-Translator: Giovanni Scafora \n" -"Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" -"it/)\n" -"Language: it\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Impossibile trovare la pagina" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Spiacenti, la pagina richiesta non esiste." +#: html/503.php msgid "Service Unavailable" msgstr "Servizio non disponibile" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Niente panico! Il sito è fuori servizio per lavori di manutenzione. " -"Torneremo presto." +msgstr "Niente panico! Il sito è fuori servizio per lavori di manutenzione. Torneremo presto." +#: html/account.php msgid "Account" msgstr "Account" +#: html/account.php template/header.php msgid "Accounts" msgstr "Account" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Non sei autorizzato ad accedere a quest'area." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Impossibile recuperare le informazioni dell'utente specificato." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Non hai i permessi necessari per modificare questo account." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa questo modulo per cercare gli account esistenti." +#: html/account.php msgid "You must log in to view user information." msgstr "Devi autenticarti per visualizzare le informazioni dell'utente." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Aggiungi una proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Il token non è valido per l'intervento da parte dell'utente." +#: html/addvote.php msgid "Username does not exist." msgstr "Il nome utente non esiste." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ha già avviato una proposta per loro." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo non valido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La proposta non può essere vuota." +#: html/addvote.php msgid "New proposal submitted." msgstr "La nuova proposta è stata inviata." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Invia una proposta da votare." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vuoto se non applicabile)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Aggiunta di un TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Rimozione di un TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Rimozione di un TU (inattività non dichiarata)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Modifica dello statuto" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Invia" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gestisci i co-manutentori" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Home" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Benvenuto in AUR! Per maggiori informazioni, leggi le %sAUR User Guidelines" -"%s e le %sAUR TU Guidelines%s." +msgstr "Benvenuto in AUR! Per maggiori informazioni, leggi le %sAUR User Guidelines%s e le %sAUR TU Guidelines%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"I PKGBUILD inviati %sdevono%s essere conformi agli %sArch Packaging Standards" -"%s altrimenti saranno eliminati!" +msgstr "I PKGBUILD inviati %sdevono%s essere conformi agli %sArch Packaging Standards%s altrimenti saranno eliminati!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ricorda di votare i tuoi pacchetti preferiti!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Alcuni pacchetti potrebbero essere disponibili come precompilati in " -"[community]." +msgstr "Alcuni pacchetti potrebbero essere disponibili come precompilati in [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVVISO" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"i pacchetti presenti in AUR sono stati inviati dagli utenti. Usali a tuo " -"rischio e pericolo." +#: html/home.php msgid "Learn more..." msgstr "Ulteriori informazioni..." +#: html/home.php msgid "Support" msgstr "Supporto" +#: html/home.php msgid "Package Requests" msgstr "Richieste dei pacchetti" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Ci sono tre tipi di richieste che si possono effettuare dal riquadro " -"%sAzioni del pacchetto%s presente nella pagina dei dettagli del pacchetto:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Ci sono tre tipi di richieste che si possono effettuare dal riquadro %sAzioni del pacchetto%s presente nella pagina dei dettagli del pacchetto:" +#: html/home.php msgid "Orphan Request" msgstr "Richiesta di un pacchetto orfano" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"richiesta di un pacchetto che si vuole abbandonare, ad esempio, quando il " -"manutentore è inattivo ed il pacchetto è stato contrassegnato come non " -"aggiornato da molto tempo." +msgstr "richiesta di un pacchetto che si vuole abbandonare, ad esempio, quando il manutentore è inattivo ed il pacchetto è stato contrassegnato come non aggiornato da molto tempo." +#: html/home.php msgid "Deletion Request" msgstr "Richiesta di rimozione di un pacchetto" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usare " -"questo tipo di richiesta se un pacchetto non funziona e se può essere " -"sistemato facilmente. Contatta il manutentore del pacchetto e, se " -"necessario, invia una richiesta per renderlo orfano." +msgstr "richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usare questo tipo di richiesta se un pacchetto non funziona e se può essere sistemato facilmente. Contatta il manutentore del pacchetto e, se necessario, invia una richiesta per renderlo orfano." +#: html/home.php msgid "Merge Request" msgstr "Richiesta di unione di un pacchetto" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"richiesta di un pacchetto da unire con un altro. Può essere usata quando un " -"pacchetto necessita di essere rinominato o rimpiazzato da un pacchetto " -"suddiviso" +msgstr "richiesta di un pacchetto da unire con un altro. Può essere usata quando un pacchetto necessita di essere rinominato o rimpiazzato da un pacchetto suddiviso" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Se vuoi discutere una richiesta, puoi usare la lista di discussione %saur-" -"requests%s. Non usare questa lista per inoltrare richieste." +msgstr "Se vuoi discutere una richiesta, puoi usare la lista di discussione %saur-requests%s. Non usare questa lista per inoltrare richieste." +#: html/home.php msgid "Submitting Packages" msgstr "Invio dei pacchetti" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Per inviare i pacchetti in AUR, adesso, si utilizza Git via SSH. Per " -"maggiori informazioni, vedi la sezione %sInviare i pacchetti%s della pagina " -"Arch User Repository dell'ArchWiki." +msgstr "Per inviare i pacchetti in AUR, adesso, si utilizza Git via SSH. Per maggiori informazioni, vedi la sezione %sInviare i pacchetti%s della pagina Arch User Repository dell'ArchWiki." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Per AUR si usano le seguenti fingerprint SSH:" +#: html/home.php msgid "Discussion" msgstr "Discussione" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"La discussione generale sull'Arch User Repository (AUR) e sulla struttura " -"dei TU avviene in %saur-general%s. Per la discussione relativa allo sviluppo " -"dell'interfaccia web di AUR, utilizza la lista di discussione %saur-dev%s." +msgstr "La discussione generale sull'Arch User Repository (AUR) e sulla struttura dei TU avviene in %saur-general%s. Per la discussione relativa allo sviluppo dell'interfaccia web di AUR, utilizza la lista di discussione %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Segnalazione di un bug" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Se trovi un bug nell'interfaccia web di AUR, invia un report al nostro %sbug " -"tracker%s. Usa il tracker %ssolo%s per inviare i bug di AUR. Per segnalare " -"bug inerenti alla pacchettizzazione, contatta il manutentore oppure lascia " -"un commento nella pagina del pacchetto." +#: html/home.php msgid "Package Search" msgstr "Ricerca dei pacchetti" +#: html/index.php msgid "Adopt" msgstr "Adotta" +#: html/index.php msgid "Vote" msgstr "Vota" +#: html/index.php msgid "UnVote" msgstr "Rimuovi il voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Abilita le notifiche" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Disabilita le notifiche" -msgid "Flag" -msgstr "Seleziona" - +#: html/index.php msgid "UnFlag" msgstr "Deseleziona" +#: html/login.php template/header.php msgid "Login" msgstr "Accedi" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Connesso con il nome utente: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Esci" +#: html/login.php msgid "Enter login credentials" msgstr "Inserisci le credenziali di accesso" -msgid "Username" -msgstr "Nome utente" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Password" +#: html/login.php msgid "Remember me" msgstr "Ricordami" +#: html/login.php msgid "Forgot Password" msgstr "Password dimenticata" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"L'accesso tramite HTTP è stato disabilitato. Se vuoi accedere, %spassa ad " -"HTTPs%s." +msgstr "L'accesso tramite HTTP è stato disabilitato. Se vuoi accedere, %spassa ad HTTPs%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteri di ricerca" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacchetti" +#: html/packages.php msgid "Error trying to retrieve package details." -msgstr "" -"Si è verificato un errore durante il recupero dei dettagli del pacchetto." +msgstr "Si è verificato un errore durante il recupero dei dettagli del pacchetto." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Manca un campo obbligatorio." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "I campi password non corrispondono." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La password deve contenere almeno %s caratteri." +#: html/passreset.php msgid "Invalid e-mail." msgstr "L'e-mail inserita non è valida." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"È stata inviata una richiesta per ripristinare la password dell'account %s " -"associato al tuo indirizzo e-mail. Se desideri ripristinare la tua password, " -"clicca sul link sottostante, altrimenti ignora questo messaggio e non " -"succederà nulla." - +#: html/passreset.php msgid "Password Reset" msgstr "Ripristina la password" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Controlla la tua e-mail per il link di conferma." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La tua password è stata ripristinata con successo." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Conferma il tuo indirizzo e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Inserisci la tua nuova password:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Conferma la tua nuova password:" +#: html/passreset.php msgid "Continue" msgstr "Continua" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un " -"messaggio nella mailing list %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un messaggio nella mailing list %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Inserisci il tuo indirizzo email:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"I pacchetti selezionati non sono stati abbandonati, conferma la tua scelta " -"inserendo un segno di spunta nell'apposita casella di controllo." +msgstr "I pacchetti selezionati non sono stati abbandonati, conferma la tua scelta inserendo un segno di spunta nell'apposita casella di controllo." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Impossibile trovare il pacchetto da unire al suo interno i voti ed i " -"commenti." +msgstr "Impossibile trovare il pacchetto da unire al suo interno i voti ed i commenti." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Impossibile unire un pacchetto base con se stesso." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"I pacchetti selezionati non sono stati eliminati, conferma la tua scelta " -"inserendo un segno di spunta nell'apposita casella di controllo." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "I pacchetti selezionati non sono stati eliminati, conferma la tua scelta inserendo un segno di spunta nell'apposita casella di controllo." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminazione del pacchetto" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Elimina il pacchetto: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Usa questo modulo per eliminare il pacchetto base %s%s%s e i seguenti " -"pacchetti da AUR:" +msgstr "Usa questo modulo per eliminare il pacchetto base %s%s%s e i seguenti pacchetti da AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "La rimozione di un pacchetto è permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Seleziona la casella di controllo per confermare l'azione richiesta." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Conferma di voler rimuovere il pacchetto" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Elimina" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Solo i TU e gli sviluppatori possono eliminare i pacchetti." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abbandona il pacchetto" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Abbandona il pacchetto: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Usa questo modulo per abbandonare il pacchetto base %s%s%s che contiene i " -"seguenti pacchetti:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Usa questo modulo per abbandonare il pacchetto base %s%s%s che contiene i seguenti pacchetti:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Selezionando la casella di controllo, confermi che vuoi abbandonare il " -"pacchetto e trasferirlo a %s%s%s." +msgstr "Selezionando la casella di controllo, confermi che vuoi abbandonare il pacchetto e trasferirlo a %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Selezionando la casella di controllo, confermi che vuoi abbandonare il " -"pacchetto." +msgstr "Selezionando la casella di controllo, confermi che vuoi abbandonare il pacchetto." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Conferma di voler abbandonare il pacchetto" +#: html/pkgdisown.php msgid "Disown" msgstr "Abbandona" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Solo i TU e gli sviluppatori possono abbandonare i pacchetti." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Commenti" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Seleziona" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Unione dei pacchetti" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Unisci il pacchetto: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Usa questo modulo per unire il pacchetto base %s%s%s con un altro pacchetto." +msgstr "Usa questo modulo per unire il pacchetto base %s%s%s con un altro pacchetto." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "I seguenti pacchetti saranno eliminati:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Una volta che il pacchetto è stato unito, non può essere più recuperato." +msgstr "Una volta che il pacchetto è stato unito, non può essere più recuperato." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Digita il nome del pacchetto che desideri unire all'interno del pacchetto." +msgstr "Digita il nome del pacchetto che desideri unire all'interno del pacchetto." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Unisci con:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Conferma di voler unire il pacchetto" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Unisci" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo i TU e gli sviluppatori possono unire i pacchetti." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Invia richiesta" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Chiudi la richiesta" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primo" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedente" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Successivo" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Richieste" +#: html/register.php template/header.php msgid "Register" msgstr "Registrati" +#: html/register.php msgid "Use this form to create an account." msgstr "Usa questo modulo per creare un account." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "TU" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Impossibile recuperare i dettagli della proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Non puoi più votare per questa proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solo i TU possono votare." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Non puoi votare per una proposta che ti riguarda in prima persona." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Hai già votato per questa proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "L'ID del voto non è valido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Voti attuali" +#: html/tu.php msgid "Past Votes" msgstr "Vecchi voti" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votanti" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"La registrazione dell'account è stata disabilitata per il tuo indirizzo IP, " -"probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per " -"l'inconveniente." +msgstr "La registrazione dell'account è stata disabilitata per il tuo indirizzo IP, probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per l'inconveniente." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manca l'ID dell'utente" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Il nome utente non è valido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Deve contenere un minino di %s ed un massimo di %s caratteri" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Inizia e termina con una lettera o un numero" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Può contenere solo un punto, un trattino basso o un trattino." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'indirizzo email non risulta valido." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La fingerprint della chiave PGP non è valida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La chiave pubblica SSH non è valida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Non è possibile incrementare i permessi dell'account." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Lingua attualmente non supportata." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Il nome utente %s%s%s è già in uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L'indirizzo %s%s%s è già in uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La chiave pubblica SSH %s%s%s, è già in uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Si è verificato un errore durante la creazione dell'account %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "L'account %s%s%s è stato creato con successo." +#: lib/acctfuncs.inc.php +msgid "A password reset key has been sent to your e-mail address." +msgstr "È stata inviata una chiave di ripristino della password al tuo indirizzo e-mail." + +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Per utilizzare il tuo account, clicca sul link Accedi." -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Benvenuto in %s! Per impostare una password iniziale del tuo nuovo account, " -"clicca sul link sottostante. Se il link non dovesse funzionare, prova a " -"copiarlo e ad incollarlo nella barra degli indirizzi del tuo browser." - -msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"È stata inviata una chiave di ripristino della password al tuo indirizzo e-" -"mail." - +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Non sono state apportate modifiche all'account %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "L'account %s%s%s è stato modificato con successo." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Il modulo d'accesso è attualmente disabilitato per il tuo indirizzo IP, " -"probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per " -"l'inconveniente." +msgstr "Il modulo d'accesso è attualmente disabilitato per il tuo indirizzo IP, probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per l'inconveniente." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Account sospeso" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"La tua password è stata ripristinata. Se hai creato da poco un nuovo " -"account, usa il link presente nell'email di conferma, per impostare una " -"password iniziale. Altrimenti, richiedi il ripristino della password dalla " -"pagina %sRipristina la password%s." +msgstr "La tua password è stata ripristinata. Se hai creato da poco un nuovo account, usa il link presente nell'email di conferma, per impostare una password iniziale. Altrimenti, richiedi il ripristino della password dalla pagina %sRipristina la password%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nome utente o password errati." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "" -"Si è verificato un errore provando a generare una sessione dell'utente." +msgstr "Si è verificato un errore provando a generare una sessione dell'utente." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "La combinazione e-mail e chiave di ripristino non è valida." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nessuno" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Mostra le informazioni dell'account %s" -msgid "Error retrieving package details." +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." msgstr "" -"Si è verificato un errore durante il recupero dei dettagli del pacchetto." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Il commento è stato inserito." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "Error retrieving package details." +msgstr "Si è verificato un errore durante il recupero dei dettagli del pacchetto." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Impossibile trovare i dettagli del pacchetto." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Devi autenticarti prima di poter contrassegnare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." -msgstr "" -"Non hai selezionato nessun pacchetto da contrassegnare come non aggiornato." +msgstr "Non hai selezionato nessun pacchetto da contrassegnare come non aggiornato." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "I pacchetti selezionati sono stati contrassegnati come non aggiornati." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Devi autenticarti prima di poter rimuovere il contrassegno ai pacchetti." +msgstr "Devi autenticarti prima di poter rimuovere il contrassegno ai pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." -msgstr "" -"Non hai selezionato nessun pacchetto da contrassegnare come aggiornato." +msgstr "Non hai selezionato nessun pacchetto da contrassegnare come aggiornato." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "I pacchetti selezionati non sono più contrassegnati." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Non hai il permesso per eliminare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Non hai selezionato nessun pacchetto da eliminare." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "I pacchetti selezionati sono stati eliminati." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Devi autenticarti prima di poter adottare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Devi autenticarti prima di poter abbandonare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Non hai selezionato nessun pacchetto da adottare." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Non hai selezionato nessun pacchetto da abbandonare." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "I pacchetti selezionati sono stati adottati." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "I pacchetti selezionati sono stati abbandonati." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Devi autenticarti prima di poter votare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Devi autenticarti prima di poter rimuovere il voto dai pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Non hai selezionato nessun pacchetto a cui assegnare il voto." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "I voti sono stati rimossi dai pacchetti selezionati." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "I voti sono stati assegnati ai pacchetti selezionati." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Impossibile aggiungere alla lista delle notifiche." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Sei stato aggiunto alla lista delle notifiche dei commenti di %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Sei stato rimosso dalla lista delle notifiche dei commenti di %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Devi autenticarti prima di poter modificare le informazioni del pacchetto." +msgstr "Devi autenticarti prima di poter modificare le informazioni del pacchetto." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Manca l'ID del commento." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Il commento è stato rimosso." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Non sei autorizzato a rimuovere questo commento." -msgid "You are not allowed to edit the keywords of this package base." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." msgstr "" -"Non sei autorizzato a modificare le parole chiave di questo pacchetto base." +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Non sei autorizzato a modificare le parole chiave di questo pacchetto base." + +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Le parole chiave del pacchetto base sono state aggiornate." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Non sei autorizzato a gestire i co-manutentori di questo pacchetto base." +msgstr "Non sei autorizzato a gestire i co-manutentori di questo pacchetto base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Il nome utente non è valido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "I co-menutentori del pacchetto base sono stati aggiornati." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Mostra i dettagli dei pacchetti di" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Devi autenticarti per richiedere i pacchetti." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Il nome non è valido: sono consentite solo le lettere minuscole." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Il campo dei commenti non deve essere vuoto." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Il tipo di richiesta non è valido." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "La richiesta è stata aggiunta con successo." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Il motivo non è valido." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Solo i TU e gli sviluppatori possono chiudere le richieste." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "La richiesta è stata chiusa con successo." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Puoi usare questo modulo per eliminare definitivamente da AUR l'account %s." +msgstr "Puoi usare questo modulo per eliminare definitivamente da AUR l'account %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sATTENZIONE%s: questa azione non può essere incompiuta." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Conferma la rimozione" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nome utente" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo di account" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utente" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Sviluppatore" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "TU e sviluppatore" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Indirizzo email" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome reale" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Fingerprint della chiave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stato" +#: template/account_details.php msgid "Inactive since" msgstr "Inattivo da" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Attivo" +#: template/account_details.php msgid "Last Login" msgstr "Ultimo accesso" +#: template/account_details.php msgid "Never" msgstr "Mai" +#: template/account_details.php msgid "View this user's packages" msgstr "Mostra i pacchetti di quest'utente" +#: template/account_details.php msgid "Edit this user's account" msgstr "Modifica l'account di quest'utente" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clicca %squi%s se vuoi eliminare definitivamente questo account." +#: template/account_edit_form.php msgid "required" msgstr "obbligatorio" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utente normale" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "TU" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Account sospeso" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inattivo" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Riscrivi la password" +#: template/account_edit_form.php msgid "Language" msgstr "Lingua" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La seguente informazione è richiesta solo se vuoi inviare i pacchetti " -"nell'Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La seguente informazione è richiesta solo se vuoi inviare i pacchetti nell'Arch User Repository." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Chiave pubblica SSH" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aggiorna" +#: template/account_edit_form.php msgid "Create" msgstr "Crea" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Cancella" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nessun risultato corrisponde ai tuoi criteri di ricerca." +#: template/account_search_results.php msgid "Edit Account" msgstr "Modifica l'account" +#: template/account_search_results.php msgid "Suspended" msgstr "Sospeso" +#: template/account_search_results.php msgid "Edit" msgstr "Modifica" +#: template/account_search_results.php msgid "Less" msgstr "Precedente" +#: template/account_search_results.php msgid "More" msgstr "Successivo" +#: template/account_search_results.php msgid "No more results to display." msgstr "Non vi sono ulteriori risultati da mostrare." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Gestisci i co-manutentori: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Usa questo modulo per aggiungere i co-manutentori di %s%s%s (un nome utente " -"per linea):" +msgstr "Usa questo modulo per aggiungere i co-manutentori di %s%s%s (un nome utente per linea):" +#: template/comaintainers_form.php msgid "Users" msgstr "Utenti" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Salva" +#: template/header.php msgid "My Packages" msgstr "I miei pacchetti" +#: template/header.php msgid " My Account" msgstr "Il mio account" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Azioni del pacchetto" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Mostra il PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Mostra le modifiche" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Scarica lo snapshot" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Cerca nel wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Il pacchetto non è aggiornato" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Segnala che il pacchetto non è aggiornato" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Rimuovi la segnalazione del pacchetto" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Rimuovi il voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Vota per questo pacchetto" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Disabilita le notifiche" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notifica dei nuovi commenti" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Gestisci i co-manutentori" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d richiesta in attesa" msgstr[1] "%d richieste in attesa" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Elimina il pacchetto" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Unisci il pacchetto" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotta il pacchetto" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "sconosciuta" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Dettagli del pacchetto base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "sola lettura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Parole chiave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Contributore" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Manutentore" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ultimo pacchettizzatore" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Voti" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popolarità" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Data del primo invio" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ultimo aggiornamento" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Aggiungi un commento" -msgid "Comment has been added." -msgstr "Il commento è stato inserito." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Mostra tutti i commenti" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Ultimi commenti" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Rimuovi il commento" -#, php-format -msgid "Comment by %s" -msgstr "Commento inviato da %s" - -msgid "Anonymous comment" -msgstr "Commento anonimo" - -msgid "deleted" -msgstr "eliminato" - +#: template/pkg_comments.php msgid "All comments" msgstr "Tutti i commenti" +#: template/pkg_details.php msgid "Package Details" msgstr "Dettagli del pacchetto" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacchetto base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrizione" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL dell'upstream" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita il sito web di" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenze" +#: template/pkg_details.php msgid "Groups" msgstr "Gruppi" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitti" +#: template/pkg_details.php msgid "Provides" msgstr "Fornisce" +#: template/pkg_details.php msgid "Replaces" msgstr "Rimpiazza" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dipendenze" +#: template/pkg_details.php msgid "Required by" msgstr "Richiesto da" +#: template/pkg_details.php msgid "Sources" msgstr "Sorgenti" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Chiudi la richiesta: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa questo modulo per chiudere la richiesta del pacchetto base %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Il campo dei commenti può essere lasciato vuoto. Tuttavia, è consigliabile " -"aggiungere un commento quando non si accetta una richiesta." +msgstr "Il campo dei commenti può essere lasciato vuoto. Tuttavia, è consigliabile aggiungere un commento quando non si accetta una richiesta." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motivo" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Accettato" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rifiutato" -msgid "Comments" -msgstr "Commenti" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Invia una richiesta per: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Usa questo modulo per inviare una richiesta per il pacchetto base %s%s%s che " -"include i seguenti pacchetti:" +msgstr "Usa questo modulo per inviare una richiesta per il pacchetto base %s%s%s che include i seguenti pacchetti:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo di richiesta" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Elimina" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Abbandona" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Unisci con" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d di %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pacchetto" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Inviato da" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d giorni rimanenti" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d ora rimanente" msgstr[1] "~%d ore rimanenti" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 ora rimanente" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accetta" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloccato" +#: template/pkgreq_results.php msgid "Close" msgstr "Chiudi" +#: template/pkgreq_results.php msgid "Closed" msgstr "Chiuso" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descrizione" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Solo il nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome esatto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacchetto base esatto" +#: template/pkg_search_form.php msgid "All" msgstr "Tutti" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Non aggiornati" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Aggiornati" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -msgid "Popularity" -msgstr "Popolarità" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votato" -msgid "Age" -msgstr "Data" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Discendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Seleziona i criteri di ricerca" +#: template/pkg_search_form.php msgid "Search by" msgstr "Cerca per" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Non aggiornati" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordina per" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordina in modo" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Cerca" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfani" +#: template/pkg_search_results.php msgid "Error retrieving package list." -msgstr "" -"Si è verificato un errore durante il recupero della lista dei pacchetti." +msgstr "Si è verificato un errore durante il recupero della lista dei pacchetti." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nessun pacchetto corrisponde ai tuoi criteri di ricerca." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." +#: template/pkg_search_results.php msgid "Version" msgstr "Versione" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"La popolarità viene calcolata come la somma di tutti i voti con ogni voto " -"ponderato con un fattore di 0,98 al giorno dalla sua creazione." +msgstr "La popolarità viene calcolata come la somma di tutti i voti con ogni voto ponderato con un fattore di 0,98 al giorno dalla sua creazione." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sì" +#: template/pkg_search_results.php msgid "orphan" msgstr "orfano" +#: template/pkg_search_results.php msgid "Actions" msgstr "Azioni" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Il pacchetto non è aggiornato" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Il pacchetto è aggiornato" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adotta il pacchetto" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abbandona il pacchetto" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Elimina il pacchetto" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Conferma" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualsiasi tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Cerca" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiche" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacchetti orfani" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacchetti aggiunti negli ultimi 7 giorni" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacchetti aggiornati negli ultimi 7 giorni" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacchetti aggiornati nell'ultimo anno" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacchetti mai aggiornati" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utenti registrati" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "TU" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Aggiornamenti recenti" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Le mie statistiche" -msgid "Packages in unsupported" -msgstr "Pacchetti in unsupported" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Dettagli della proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Questa votazione è ancora in corso." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Inviato: %s da %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fine" +#: template/tu_details.php msgid "Result" msgstr "Risultato" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Astenuto" +#: template/tu_details.php msgid "Total" msgstr "Totale" +#: template/tu_details.php msgid "Participation" msgstr "Partecipazione" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ultimi voti dei TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ultimo voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "La ricerca non ha prodotto nessun risultato." +#: template/tu_list.php msgid "Start" msgstr "Home" +#: template/tu_list.php msgid "Back" msgstr "Precedente" diff --git a/po/ja.po b/po/ja.po index d95ee440..4b0417b0 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # kusakata , 2013 # kusakata , 2013 @@ -10,1376 +10,1795 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-08-04 12:23+0000\n" -"Last-Translator: kusakata \n" -"Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" -"ja/)\n" -"Language: ja\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: ja\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: html/404.php msgid "Page Not Found" msgstr "ページが見つかりませんでした" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "あなたがリクエストしたページは存在しませんでした。" +#: html/503.php msgid "Service Unavailable" msgstr "Service Unavailable" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"落ち着いて下さい!このサイトはメンテナンスのためにダウンしています。すぐに復" -"帰する予定です。" +msgstr "落ち着いて下さい!このサイトはメンテナンスのためにダウンしています。すぐに復帰する予定です。" +#: html/account.php msgid "Account" msgstr "アカウント" +#: html/account.php template/header.php msgid "Accounts" msgstr "アカウント" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "このページへのアクセスは許可されていません。" +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "指定のユーザーの情報が取得できませんでした。" +#: html/account.php msgid "You do not have permission to edit this account." msgstr "あなたはこのアカウントを編集する権利を持っていません。" +#: html/account.php msgid "Use this form to search existing accounts." msgstr "アカウントの検索はこのフォームを使って下さい。" +#: html/account.php msgid "You must log in to view user information." msgstr "ユーザー情報を見るにはログインする必要があります。" +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "提案を追加する" +#: html/addvote.php msgid "Invalid token for user action." msgstr "アクションの不正なトークン。" +#: html/addvote.php msgid "Username does not exist." msgstr "ユーザー名が存在しません。" +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s はすでにその提案を持っています。" +#: html/addvote.php msgid "Invalid type." msgstr "不正なタイプ。" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "提案が空です。" +#: html/addvote.php msgid "New proposal submitted." msgstr "新しい提案が投稿されました。" +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "採決する提案を提出してください。" +#: html/addvote.php msgid "Applicant/TU" msgstr "候補者/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(適当なものがない場合は空に)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "タイプ" +#: html/addvote.php msgid "Addition of a TU" msgstr "TU の追加" +#: html/addvote.php msgid "Removal of a TU" msgstr "TU の削除" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU の削除 (undeclared inactivity)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "規約の修正" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "提案" +#: html/addvote.php msgid "Submit" msgstr "投稿" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "共同メンテナの管理" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "ホーム" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"AUR にようこそ!AUR についての詳しい情報は %sAUR User Guidelines%s や %sAUR " -"TU Guidelines%s を読んで下さい。" +msgstr "AUR にようこそ!AUR についての詳しい情報は %sAUR User Guidelines%s や %sAUR TU Guidelines%s を読んで下さい。" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"PKGBUILD を投稿するつもりならば%s必ず%s %sArch Packaging Standards%s に従って" -"下さい。従っていないパッケージは削除されます!" +msgstr "PKGBUILD を投稿するつもりならば%s必ず%s %sArch Packaging Standards%s に従って下さい。従っていないパッケージは削除されます!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "お気に入りのパッケージに投票しましょう!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"パッケージがバイナリとして [community] で提供されることになるかもしれません。" +msgstr "パッケージがバイナリとして [community] で提供されることになるかもしれません。" +#: html/home.php msgid "DISCLAIMER" msgstr "免責事項" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"ユーザーが作成したパッケージにサポートはありません。それぞれのファイルの利用" -"は自己責任でお願いします。" +#: html/home.php msgid "Learn more..." msgstr "詳細..." +#: html/home.php msgid "Support" msgstr "サポート" +#: html/home.php msgid "Package Requests" msgstr "パッケージリクエスト" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"各パッケージの詳細ページにある%sパッケージアクション%sボックスから送信するこ" -"とができるリクエストは3種類あります:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "各パッケージの詳細ページにある%sパッケージアクション%sボックスから送信することができるリクエストは3種類あります:" +#: html/home.php msgid "Orphan Request" msgstr "孤児リクエスト" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"パッケージを孤児にするようにリクエストします。メンテナが活動を停止していて" -"パッケージが長い間 out-of-date のまま放置されている場合などに使います。" +msgstr "パッケージを孤児にするようにリクエストします。メンテナが活動を停止していてパッケージが長い間 out-of-date のまま放置されている場合などに使います。" +#: html/home.php msgid "Deletion Request" msgstr "削除リクエスト" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Arch User Repository からパッケージを削除するようにリクエストします。パッケー" -"ジが壊れていて、その不具合を簡単に修正できるような場合、このリクエストは使わ" -"ないで下さい。代わりに、パッケージのメンテナに連絡したり、必要に応じて孤児リ" -"クエストを送りましょう。" +msgstr "Arch User Repository からパッケージを削除するようにリクエストします。パッケージが壊れていて、その不具合を簡単に修正できるような場合、このリクエストは使わないで下さい。代わりに、パッケージのメンテナに連絡したり、必要に応じて孤児リクエストを送りましょう。" +#: html/home.php msgid "Merge Request" msgstr "マージリクエスト" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"あるパッケージを他のパッケージとマージするようにリクエストします。パッケージ" -"の名前を変更する必要があるときや分割パッケージによって置き換えるときに使用し" -"ます。" +msgstr "あるパッケージを他のパッケージとマージするようにリクエストします。パッケージの名前を変更する必要があるときや分割パッケージによって置き換えるときに使用します。" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"リクエストについて議論したい場合、%saur-requests%s メーリングリストを使いま" -"す。ただし、このメーリングリスト宛にリクエストを送るのは止めて下さい。" +msgstr "リクエストについて議論したい場合、%saur-requests%s メーリングリストを使います。ただし、このメーリングリスト宛にリクエストを送るのは止めて下さい。" +#: html/home.php msgid "Submitting Packages" msgstr "パッケージの投稿" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"現在 AUR にパッケージを送信するときは SSH を介して Git を使うことになっていま" -"す。詳しくは ArchWiki の Arch User Repository のページの%sパッケージの投稿%s" -"セクションを見て下さい。" +msgstr "現在 AUR にパッケージを送信するときは SSH を介して Git を使うことになっています。詳しくは ArchWiki の Arch User Repository のページの%sパッケージの投稿%sセクションを見て下さい。" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR では以下の SSH フィンガープリントが使われます:" +#: html/home.php msgid "Discussion" msgstr "議論" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Arch User Repository (AUR) や Trusted User に関する一般的な議論は %saur-" -"general%s で行って下さい。AUR ウェブインターフェイスの開発に関しては、%saur-" -"dev%s メーリングリストを使用します。" +msgstr "Arch User Repository (AUR) や Trusted User に関する一般的な議論は %saur-general%s で行って下さい。AUR ウェブインターフェイスの開発に関しては、%saur-dev%s メーリングリストを使用します。" +#: html/home.php msgid "Bug Reporting" msgstr "バグレポート" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"AUR ウェブインターフェイスにバグを発見した場合、私たちの%sバグトラッカー%sに" -"バグを報告してください。AUR のバグを報告するとき%sのみ%sにこのトラッカーを" -"使って下さい。パッケージのバグについては、パッケージメンテナに連絡するか適切" -"なパッケージページにコメントを残して下さい。" +#: html/home.php msgid "Package Search" msgstr "パッケージ検索" +#: html/index.php msgid "Adopt" msgstr "承継" +#: html/index.php msgid "Vote" msgstr "投票" +#: html/index.php msgid "UnVote" msgstr "投票を削除" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "通知を削除" -msgid "Flag" -msgstr "フラグ" - +#: html/index.php msgid "UnFlag" msgstr "フラグを降ろす" +#: html/login.php template/header.php msgid "Login" msgstr "ログイン" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "ログイン中: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "ログアウト" +#: html/login.php msgid "Enter login credentials" msgstr "ログイン情報を入力してください" -msgid "Username" -msgstr "ユーザー名" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "パスワード" +#: html/login.php msgid "Remember me" msgstr "ログインしたままにする" +#: html/login.php msgid "Forgot Password" msgstr "パスワードを忘れた" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP ログインはできません。ログインするには %sHTTPs%s に切り替えてください。" +msgstr "HTTP ログインはできません。ログインするには %sHTTPs%s に切り替えてください。" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "検索条件" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "パッケージ" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "パッケージの詳細の取得エラー。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "必須項目が埋められていません。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "パスワードが一致しません。" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "パスワードは最低でも %s 文字以上必要です。" +#: html/passreset.php msgid "Invalid e-mail." msgstr "不正なメールアドレス。" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"あなたのメールアドレスと関連付けられたアカウント %s のパスワードのリセットリ" -"クエストが送信されました。パスワードをリセットしたいときは下のリンクを開いて" -"下さい、そうでない場合はこのメッセージは無視して下さい。" - +#: html/passreset.php msgid "Password Reset" msgstr "パスワードのリセット" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "メールをチェックして確認リンクを開いて下さい。" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "パスワードのリセットが成功しました。" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "メールアドレスの確認:" +#: html/passreset.php msgid "Enter your new password:" msgstr "新しいパスワードを入力:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "新しいパスワードを再入力:" +#: html/passreset.php msgid "Continue" msgstr "続行" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"登録したメールアドレスを忘れてしまった場合は、%saur-general%s メーリングリス" -"トにメッセージを送って下さい。" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "登録したメールアドレスを忘れてしまった場合は、%saur-general%s メーリングリストにメッセージを送って下さい。" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "メールアドレスを入力:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"選択されたパッケージは孤児になっていません。確認チェックボックスにチェックを" -"入れて下さい。" +msgstr "選択されたパッケージは孤児になっていません。確認チェックボックスにチェックを入れて下さい。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "投票やコメントのマージをするパッケージが見つかりません。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "パッケージベースをそれ自体とマージすることはできません。" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"選択されたパッケージは削除されませんでした、確認チェックボックスにチェックを" -"入れてください。" +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "選択されたパッケージは削除されませんでした、確認チェックボックスにチェックを入れてください。" +#: html/pkgdel.php msgid "Package Deletion" msgstr "パッケージの削除" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "削除するパッケージ: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"AUR からパッケージベース %s%s%s と以下のパッケージを削除するにはこのフォーム" -"を使って下さい:" +msgstr "AUR からパッケージベース %s%s%s と以下のパッケージを削除するにはこのフォームを使って下さい:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "パッケージの削除は戻すことができません。" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "アクションを確認するためにチェックボックスを選択してください。" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "パッケージ削除の確認" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "削除" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Trusted User と開発者だけがパッケージを削除できます。" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "パッケージの放棄" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "孤児にするパッケージ: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"このフォームを使って以下のパッケージを含むパッケージベース %s%s%s を孤児にす" -"ることができます:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "このフォームを使って以下のパッケージを含むパッケージベース %s%s%s を孤児にすることができます:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"チェックボックスを選択して、パッケージを孤児にして所有権を %s%s%s に移すこと" -"を確定して下さい。" +msgstr "チェックボックスを選択して、パッケージを孤児にして所有権を %s%s%s に移すことを確定して下さい。" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"チェックボックスを選択して、パッケージを孤児にすることを確定してください。" +msgstr "チェックボックスを選択して、パッケージを孤児にすることを確定してください。" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "パッケージを孤児にすることの確認" +#: html/pkgdisown.php msgid "Disown" msgstr "放棄" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Trusted User と開発者だけがパッケージを孤児にできます。" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "コメント" + +#: html/pkgflag.php +msgid "Flag" +msgstr "フラグ" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "パッケージのマージ" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "マージするパッケージ: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"他のパッケージにパッケージベース %s%s%s をマージするにはこのフォームを使って" -"下さい。" +msgstr "他のパッケージにパッケージベース %s%s%s をマージするにはこのフォームを使って下さい。" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "次のパッケージが削除されます:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "一度パッケージがマージされると戻すことはできません。" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "このパッケージをマージしたいパッケージ名を入力してください。" +#: html/pkgmerge.php msgid "Merge into:" msgstr "マージ先:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "パッケージマージの確認" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "マージ" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Trusted User と開発者だけがパッケージをマージできます。" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "リクエストを送る" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "リクエストをクローズ" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "最初" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "前へ" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "次へ" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "リクエスト" +#: html/register.php template/header.php msgid "Register" msgstr "登録" +#: html/register.php msgid "Use this form to create an account." msgstr "このフォームを使ってアカウントを作成してください。" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "提案内容が取得できませんでした。" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "この提案への投票は締め切られています。" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Trusted User だけが投票できます。" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "あなたについての提案に投票することはできません。" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "既にこの提案に投票しています。" +#: html/tu.php msgid "Vote ID not valid." msgstr "投票 ID が不正です。" +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "現在の投票" +#: html/tu.php msgid "Past Votes" msgstr "過去の投票" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票者" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"スパムのために、あなたのIPアドレスからアカウント登録はできません。ご迷惑をお" -"かけして申し訳ございません。" +msgstr "スパムのために、あなたのIPアドレスからアカウント登録はできません。ご迷惑をおかけして申し訳ございません。" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ユーザー ID の消失" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "ユーザー名が不正です。" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "文字の長さは %s から %s の間である必要があります" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "最初と最後の文字は英数字にしてください" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "ピリオド、アンダーライン、ハイフンはひとつだけ含めることができます。" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "メールアドレスが不正です。" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 鍵のフィンガープリントが不正です。" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH 公開鍵が不正です。" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "アカウント権限を増やすことはできません。" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "言語は現在サポートされていません。" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "%s%s%s というユーザー名は既に使われています。" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "%s%s%s というメールアドレスは既に使われています。" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開鍵、%s%s%s は既に使われています。" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "アカウントの作成エラー、%s%s%s。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "アカウント %s%s%s の作成が完了しました。" -msgid "Click on the Login link above to use your account." -msgstr "あなたのアカウントを使うには上のログインリンクをクリックして下さい。" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"%s にようこそ!アカウントのパスワードを設定するために、下のリンクをクリックし" -"てください。リンクを押せないときは、一旦ブラウザにURLをコピーしてください。" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "パスワードのリセットキーがあなたのメールアドレスに送られました。" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "あなたのアカウントを使うには上のログインリンクをクリックして下さい。" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "アカウントに変更は加えられませんでした、%s%s%s。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "アカウント %s%s%s の修正が完了しました。" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"スパムのために、現在あなたのIPアドレスからはログインフォームが無効になってい" -"ます。ご迷惑をおかけして申し訳ございません。" +msgstr "スパムのために、現在あなたのIPアドレスからはログインフォームが無効になっています。ご迷惑をおかけして申し訳ございません。" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "休眠アカウント" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"あなたのパスワードはリセットされました。新しいアカウントを作成したときは、確" -"認メールにあるリンクからパスワードを設定してください。もしくは、%sPassword " -"Reset%s ページでリセットキーを申請してください。" +msgstr "あなたのパスワードはリセットされました。新しいアカウントを作成したときは、確認メールにあるリンクからパスワードを設定してください。もしくは、%sPassword Reset%s ページでリセットキーを申請してください。" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "不正なユーザー名またはパスワードです。" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "ユーザーセッションの生成時にエラーが発生しました。" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "メールアドレスとリセットキーの不正な組み合わせ。" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "なし" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "%s のアカウント情報を見る" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "コメントが追加されました。" + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "パッケージの詳細の取得エラー。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "パッケージの詳細が見つかりませんでした。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "パッケージのフラグを立てるにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "フラグを立てるパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "選択されたパッケージの out-of-date フラグが立てられました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "パッケージのフラグを降ろすにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "フラグを降ろすパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "選択されたパッケージのフラグが降ろされました。" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "あなたはパッケージを削除する許可を持っていません。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "削除するパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "選択されたパッケージが削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "パッケージを承継するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "パッケージを放棄するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "承継するパッケージが選択されていません。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "放棄するパッケージが選択されていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "選択されたパッケージを承継しました。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "選択されたパッケージを放棄しました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "パッケージに投票するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "パッケージへの投票を取り消すにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "投票するパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "選択されたパッケージからあなたの投票が削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "選択されたパッケージに投票しました。" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "通知リストに追加できませんでした。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "%s がコメントの通知リストに追加されました。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "%s がコメントの通知リストから削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "パッケージの情報を編集するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "コメント ID が見つかりません。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "コメントが削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "このコメントを削除することはできません。" +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "このパッケージベースのキーワードを編集することはできません。" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "パッケージベースのキーワードは更新されました。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "このパッケージベースの共同メンテナを管理することはできません。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "不正なユーザー名: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "パッケージベースの共同メンテナが更新されました。" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "パッケージの詳細を見る" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "パッケージリクエストを送るにはログインする必要があります。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "不正な名前です: 小文字だけが使用できます。" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "コメント欄には何か記入して下さい。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "不正なリクエストの種類。" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "リクエストの追加が完了しました。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "不正な理由。" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "TU と開発者だけがリクエストをクローズできます。" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "リクエストのクローズが完了しました。" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"このフォームを使って AUR アカウント %s を恒久的に削除することができます。" +msgstr "このフォームを使って AUR アカウント %s を恒久的に削除することができます。" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s: この操作は元に戻すことができません。" +#: template/account_delete.php msgid "Confirm deletion" msgstr "削除の確認" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "ユーザー名" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "アカウントタイプ" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "ユーザー" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "開発者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & 開発者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "メールアドレス" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "本名" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC ニックネーム" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 鍵のフィンガープリント" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "状態" +#: template/account_details.php msgid "Inactive since" msgstr "休止開始" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "活動中" +#: template/account_details.php msgid "Last Login" msgstr "最後のログイン" +#: template/account_details.php msgid "Never" msgstr "Never" +#: template/account_details.php msgid "View this user's packages" msgstr "ユーザーのパッケージを見る" +#: template/account_details.php msgid "Edit this user's account" msgstr "このユーザーのアカウントを編集" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "このアカウントを恒久的に削除したい場合は%sこちら%sをクリック。" +#: template/account_edit_form.php msgid "required" msgstr "必須" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "ノーマルユーザー" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "休眠アカウント" +#: template/account_edit_form.php msgid "Inactive" msgstr "活動休止" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "パスワードの再入力" +#: template/account_edit_form.php msgid "Language" msgstr "言語" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"以下の情報は Arch User Repository にパッケージを送信したい場合にのみ必要にな" -"ります。" +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "以下の情報は Arch User Repository にパッケージを送信したい場合にのみ必要になります。" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH 公開鍵" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "更新" +#: template/account_edit_form.php msgid "Create" msgstr "作成" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "リセット" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "検索条件に一致する結果が見つかりませんでした。" +#: template/account_search_results.php msgid "Edit Account" msgstr "アカウントを編集" +#: template/account_search_results.php msgid "Suspended" msgstr "休止" +#: template/account_search_results.php msgid "Edit" msgstr "編集" +#: template/account_search_results.php msgid "Less" msgstr "Less" +#: template/account_search_results.php msgid "More" msgstr "More" +#: template/account_search_results.php msgid "No more results to display." msgstr "表示する結果はもうありません。" +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "共同メンテナの管理: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"このフォームを使って %s%s%s の共同メンテナを追加することができます (一行につ" -"き一人のユーザー名を入力):" +msgstr "このフォームを使って %s%s%s の共同メンテナを追加することができます (一行につき一人のユーザー名を入力):" +#: template/comaintainers_form.php msgid "Users" msgstr "ユーザー" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "保存" +#: template/header.php msgid "My Packages" msgstr "自分のパッケージ" +#: template/header.php msgid " My Account" msgstr "アカウント" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "パッケージアクション" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD を見る" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "変更履歴" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "スナップショットのダウンロード" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "wiki を検索" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "out-of-date フラグを立てる" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "パッケージの out-of-date フラグを立てる" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "パッケージのフラグを降ろす" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "投票を削除する" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "このパッケージに投票する" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "通知を止める" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "新しいコメントを通知" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "共同メンテナの管理" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 個の保留リクエスト。" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "パッケージを削除" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "パッケージのマージ" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "パッケージを承継する" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "不明" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "パッケージベースの詳細" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git クローン URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "リードオンリー" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "キーワード" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "投稿者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "メンテナ" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最後のパッケージ作成者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "投票数" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "人気度" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "最初の投稿" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最終更新" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "コメントを投稿する" -msgid "Comment has been added." -msgstr "コメントが追加されました。" - +#: template/pkg_comments.php msgid "View all comments" msgstr "全てのコメントを表示" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "最新のコメント" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "コメントを削除" -#, php-format -msgid "Comment by %s" -msgstr "%s によるコメント" - -msgid "Anonymous comment" -msgstr "匿名のコメント" - -msgid "deleted" -msgstr "削除済み" - +#: template/pkg_comments.php msgid "All comments" msgstr "全てのコメント" +#: template/pkg_details.php msgid "Package Details" msgstr "パッケージの詳細" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "パッケージベース" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "説明" +#: template/pkg_details.php msgid "Upstream URL" msgstr "上流 URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "ウェブサイトを見る" +#: template/pkg_details.php msgid "Licenses" msgstr "ライセンス" +#: template/pkg_details.php msgid "Groups" msgstr "グループ" +#: template/pkg_details.php msgid "Conflicts" msgstr "衝突" +#: template/pkg_details.php msgid "Provides" msgstr "提供" +#: template/pkg_details.php msgid "Replaces" msgstr "置換" +#: template/pkg_details.php msgid "Dependencies" msgstr "依存パッケージ" +#: template/pkg_details.php msgid "Required by" msgstr "必要としているパッケージ" +#: template/pkg_details.php msgid "Sources" msgstr "ソース" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "クローズリクエスト: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"このフォームを使ってパッケージベース %s%s%s のリクエストをクローズすることが" -"できます。" +msgstr "このフォームを使ってパッケージベース %s%s%s のリクエストをクローズすることができます。" +#: template/pkgreq_close_form.php msgid "Note" msgstr "ノート" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"コメント欄は空でもかまいません。ただし、リクエストを却下されたときはコメント" -"を追加することを強く推奨します。" +msgstr "コメント欄は空でもかまいません。ただし、リクエストを却下されたときはコメントを追加することを強く推奨します。" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "理由" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "承認されました" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "却下されました" -msgid "Comments" -msgstr "コメント" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "リクエストを送る: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"このフォームを使って以下のパッケージを含むパッケージベース %s%s%s にリクエス" -"トを送ることができます:" +msgstr "このフォームを使って以下のパッケージを含むパッケージベース %s%s%s にリクエストを送ることができます:" +#: template/pkgreq_form.php msgid "Request type" msgstr "リクエストの種類" +#: template/pkgreq_form.php msgid "Deletion" msgstr "削除" +#: template/pkgreq_form.php msgid "Orphan" msgstr "孤児" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "マージ" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "パッケージリクエストが %d 個見つかりました。" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "ページ %d / %d。" +#: template/pkgreq_results.php msgid "Package" msgstr "パッケージ" +#: template/pkgreq_results.php msgid "Filed by" msgstr "送信者" +#: template/pkgreq_results.php msgid "Date" msgstr "日付" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "残り ~%d 日" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "残り ~%d 時間" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "残り <1 時間" +#: template/pkgreq_results.php msgid "Accept" msgstr "承認" +#: template/pkgreq_results.php msgid "Locked" msgstr "ロックされています" +#: template/pkgreq_results.php msgid "Close" msgstr "クローズ" +#: template/pkgreq_results.php msgid "Closed" msgstr "クローズされました" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "名前、説明" +#: template/pkg_search_form.php msgid "Name Only" msgstr "名前のみ" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "名前完全一致" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "パッケージベース完全一致" +#: template/pkg_search_form.php msgid "All" msgstr "全て" +#: template/pkg_search_form.php msgid "Flagged" msgstr "フラグ付き" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "フラグなし" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名前" -msgid "Popularity" -msgstr "人気度" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "投票済" -msgid "Age" -msgstr "年齢" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "昇順" +#: template/pkg_search_form.php msgid "Descending" msgstr "降順" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "検索条件を入力" +#: template/pkg_search_form.php msgid "Search by" msgstr "検索対象" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Out of Date" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "ソート" +#: template/pkg_search_form.php msgid "Sort order" msgstr "ソート順" +#: template/pkg_search_form.php msgid "Per page" msgstr "表示件数" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "検索" +#: template/pkg_search_form.php msgid "Orphans" msgstr "孤児のパッケージ" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "パッケージリスト取得エラー。" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "検索条件に一致するパッケージがありません。" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "パッケージが %d 個見つかりました。" +#: template/pkg_search_results.php msgid "Version" msgstr "バージョン" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"人気度は各投票に作成日からの日数を0.98倍した全投票の合計で計算されます。" +msgstr "人気度は各投票に作成日からの日数を0.98倍した全投票の合計で計算されます。" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "はい" +#: template/pkg_search_results.php msgid "orphan" msgstr "孤児" +#: template/pkg_search_results.php msgid "Actions" msgstr "アクション" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Out-of-date フラグを立てる" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Out-of-date フラグを降ろす" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "パッケージの承継" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "パッケージの放棄" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "パッケージの削除" +#: template/pkg_search_results.php msgid "Confirm" msgstr "確認" +#: template/search_accounts_form.php msgid "Any type" msgstr "全てのタイプ" +#: template/search_accounts_form.php msgid "Search" msgstr "検索" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "統計" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "孤児のパッケージ" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "過去7日間で追加されたパッケージ" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "過去7日間で更新されたパッケージ" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "過去1年間で更新されたパッケージ" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "更新されたことがないパッケージ" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "登録ユーザー" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted User" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最近のアップデート" +#: template/stats/user_table.php msgid "My Statistics" msgstr "自分の統計" -msgid "Packages in unsupported" -msgstr "unsupported のパッケージ" - +#: template/tu_details.php msgid "Proposal Details" msgstr "提案の詳細" +#: template/tu_details.php msgid "This vote is still running." msgstr "投票が実行されています。" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "投稿: %s by %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "終了" +#: template/tu_details.php msgid "Result" msgstr "結果" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "いいえ" +#: template/tu_details.php msgid "Abstain" msgstr "Abstain" +#: template/tu_details.php msgid "Total" msgstr "合計" +#: template/tu_details.php msgid "Participation" msgstr "参加" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "TU による最後の投票" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最後の投票" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "結果が見つかりませんでした。" +#: template/tu_list.php msgid "Start" msgstr "開始" +#: template/tu_list.php msgid "Back" msgstr "前へ" diff --git a/po/nb.po b/po/nb.po index e7f2398f..4277ae5a 100644 --- a/po/nb.po +++ b/po/nb.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Alexander F Rødseth , 2015 # Alexander F Rødseth , 2011,2013-2014 @@ -10,1339 +10,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" -"language/nb/)\n" -"Language: nb\n" +"Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/language/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: nb\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Finner ikke siden" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Den ønskede siden finnes ikke." +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Kontoer" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Du har ikke adgang til dette området." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kunne ikke motta informasjon for den valgte brukeren." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du har ikke adgang til å endre denne kontoen." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Bruk dette skjemaet for å lete etter eksisterende kontoer." +#: html/account.php msgid "You must log in to view user information." msgstr "Du må logge inn for å se brukerinformasjon." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Legg til forslag" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Ugyldig billett for brukerens handling." +#: html/addvote.php msgid "Username does not exist." msgstr "Brukernavn finnes ikke." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s har allerede et forslag på gang." +#: html/addvote.php msgid "Invalid type." msgstr "Ugyldig type." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Forslag kan ikke være tomme." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nytt forslag innsendt." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Send inn et forslag for å stemme over." +#: html/addvote.php msgid "Applicant/TU" msgstr "Søker/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tomt hvis det ikke gjelder her)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "Oppnevnelse av TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Fjerning av TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Fjerning av TU (uannonsert inaktivitet)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Endring av vedtekter" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Forslag" +#: html/addvote.php msgid "Submit" msgstr "Send inn" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Hjem" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Velkommen til AUR! Vennligst les %sAUR Brukerveiledning%s og %sAUR TU " -"Veiledning%s for mer informasjon." +msgstr "Velkommen til AUR! Vennligst les %sAUR Brukerveiledning%s og %sAUR TU Veiledning%s for mer informasjon." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Innsendte PKGBUILD-filer %små%s følge %sStandarden for Arch Pakker%s ellers " -"vil de bli slettet!" +msgstr "Innsendte PKGBUILD-filer %små%s følge %sStandarden for Arch Pakker%s ellers vil de bli slettet!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Husk å stemme på dine favorittpakker!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Noen pakker finnes som binærfiler i [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ANSVARSFRASKRIVELSE" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Uoffisielle pakker har innhold produsert av andre brukere. All bruk av de " -"tilgjengelige filene er på eget ansvar." +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Diskusjon" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Feilrapportering" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Pakkesøk" +#: html/index.php msgid "Adopt" msgstr "Adopter" +#: html/index.php msgid "Vote" msgstr "Stem" +#: html/index.php msgid "UnVote" msgstr "Fjern stemme" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Påminnelse" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Fjern påminnelse" -msgid "Flag" -msgstr "Markering" - +#: html/index.php msgid "UnFlag" msgstr "Fjern markering" +#: html/login.php template/header.php msgid "Login" msgstr "Logg inn" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Logget inn som: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Logg ut" +#: html/login.php msgid "Enter login credentials" msgstr "Fyll ut innloggingsinformasjon" -msgid "Username" -msgstr "Brukernavn" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Passord" +#: html/login.php msgid "Remember me" msgstr "Husk meg" +#: html/login.php msgid "Forgot Password" msgstr "Glemt passord" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "HTTP-innlogging er deaktivert. %sBytt til HTTPs%s for å logge inn." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Søkekriterier" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakker" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Feil oppstod ved uthenting av pakkedetaljer." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Mangler et nødvendig felt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Passord-feltene stemmer ikke overens." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Passordet ditt må være minst %s tegn." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ugyldig e-post." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Tilbakestill passord" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "" -"Sjekk e-posten din og bruk den tilsendte lenken for å bekrefte " -"registreringen." +msgstr "Sjekk e-posten din og bruk den tilsendte lenken for å bekrefte registreringen." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Passordet ditt har blitt tilbakestilt." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bekreft din e-post addresse:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Skriv inn ditt nye passord:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bekreft ditt nye passord:" +#: html/passreset.php msgid "Continue" msgstr "Fortsett" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Hvis du har glemt e-post adressen du brukte for å registrere deg, så kan du " -"sende en e-post til listen %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Hvis du har glemt e-post adressen du brukte for å registrere deg, så kan du sende en e-post til listen %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Fyll ut e-post adressen din:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Kunne ikke finne pakke for å flette stemmer og kommentarer inn i." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Kan ikke slå sammen en basispakke med seg selv." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Den valgte pakken har ikke blitt slettet, kryss av i boksen for å bekrefte." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Den valgte pakken har ikke blitt slettet, kryss av i boksen for å bekrefte." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Sletting av pakke" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Slett pakke: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Bruk dette skjemaet for å slette grunnpakken %s%s%s og følgende pakker fra " -"AUR:" +msgstr "Bruk dette skjemaet for å slette grunnpakken %s%s%s og følgende pakker fra AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Slettingen av en pakke er permanent. " +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Kryss av i boksen for å bekrefte." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bekreft sletting av pakke" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Slett" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Bare betrodde brukere og utviklere kan slette pakker." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Gjør foreldreløs" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "Gjør foreldreløs" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Kommentarer" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Markering" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakkesammenslåing" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Slå sammen pakke: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Bruk dette skjemaet for å slå sammen grunnpakken %s%s%s med en annen pakke." +msgstr "Bruk dette skjemaet for å slå sammen grunnpakken %s%s%s med en annen pakke." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Følgende pakker vil slettes:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Når pakken har blitt sammenslått, så kan det ikke angres. " +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Fyll ut navnet på pakken du ønsker å slå sammen denne pakken til." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Slå sammen til:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Bekreft sammenslåing" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Slå sammen" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Bare betrodde brukere og utviklere kan slå sammen pakker." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Send inn forespørsel" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Lukk forespørsel" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Forrige" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Neste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Siste" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Forespørsler" +#: html/register.php template/header.php msgid "Register" msgstr "Registrer" +#: html/register.php msgid "Use this form to create an account." msgstr "Bruk dette feltet for å opprette en konto." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Betrodd bruker" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Kan ikke finne detaljer om forslaget." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Avstemningen er ferdig for dette forslaget." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Bare betrodde brukere har stemmerett." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Du kan ikke stemme på et forslag som gjelder deg." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du har allerede stemt på dette forslaget." +#: html/tu.php msgid "Vote ID not valid." msgstr "Stemme-ID ikke gyldig." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Foreløpige stemmer" +#: html/tu.php msgid "Past Votes" msgstr "Tidligere stemmer" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Velgere" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Funksjonen for registrering av nye kontoer har blitt slått av for din IP " -"adresse, sannsynligvis på grunn av vedvarende spam-angrep. Vi beklager " -"ulempen dette medfører." +msgstr "Funksjonen for registrering av nye kontoer har blitt slått av for din IP adresse, sannsynligvis på grunn av vedvarende spam-angrep. Vi beklager ulempen dette medfører." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Mangler bruker-ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Brukernavnet er ugyldig." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Det må være mellom %s og %s tegn langt" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Start og slutt med en bokstav eller et siffer" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun innehold ett punktum, en understrek, eller en bindestrek." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-postadressen er ugyldig." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP fingeravtrykket er ikke gyldig." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Kan ikke gi flere tillatelser til kontoen." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Språket støttes ikke på dette tidspunktet." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Brukernavnet, %s%s%s, er allerede i bruk." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adressen, %s%s%s, er allerede i bruk." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Feil ved oppretting av konto, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Kontoen, %s%s%s, har nå blitt laget." -msgid "Click on the Login link above to use your account." -msgstr "Klikk på Logg inn lenken over for å bruke kontoen." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Velkommen til %s! Lag et passord for din nye konto ved å trykke på lenken " -"nedenfor. Dersom lenken ikke virker, kopier og lim adressen inn i " -"nettleseren din." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Nullstillingskode har blitt sendt til e-post adressen din." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Klikk på Logg inn lenken over for å bruke kontoen." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Ingen endringer ble utført på kontoen, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Kontoen, %s%s%s, har nå blitt endret." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Inlogging er slått av for din IP adresse, sannsynligvis på grunn av " -"vedvarende spam-angrep. Beklager ulempen dette medfører." +msgstr "Inlogging er slått av for din IP adresse, sannsynligvis på grunn av vedvarende spam-angrep. Beklager ulempen dette medfører." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Kontoen er stengt" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Passordet har blitt nullstilt. Dersom du akkurat laget en ny konto, " -"vennligst følg lenken som ble sendt på e-post og sett så et nytt passord. " -"Ellers kan du bruke %sNullstill Passord% siden til å få tilsendt en " -"nullstillingskode." +msgstr "Passordet har blitt nullstilt. Dersom du akkurat laget en ny konto, vennligst følg lenken som ble sendt på e-post og sett så et nytt passord. Ellers kan du bruke %sNullstill Passord% siden til å få tilsendt en nullstillingskode." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Ugyldig brukernavn eller passord." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Feil oppstod ved generering av sesjon for bruker." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ugyldig kombinasjon av e-post og nullstillingsnøkkel." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Ingen" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Vis kontoinformasjon for %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Kommentar har blitt lagt til." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Kunne ikke finne frem pakkedetaljer." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Kunne ikke finne pakkedetaljer." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du må være logget inn for å kunne markere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Ingen pakker ble valgt for å bli markert." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "De valgte pakkene har nå blitt markert som utdaterte." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Du må være logget inn for å kunne fjerne \"utdatert\"-markeringen fra pakker." +msgstr "Du må være logget inn for å kunne fjerne \"utdatert\"-markeringen fra pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Ingen pakker ble valgt for å fjerne markeringer fra." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De valgte pakkene har nå fått fjernet markeringen." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du har ikke rettighetene som skal til for å kunne slette pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du valgte ingen pakker for sletting." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De valgte pakkene har blitt slettet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du må være logget inn for å kunne adoptere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du må være logget inn for å kunne gjøre pakker foreldreløse." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du valgte ingen pakker for adopsjon." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du valgte ingen pakker for å gjøre de foreldreløse." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Den valgte pakken har blitt adoptert." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De valgte pakkene er nå foreldreløse." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du må være logget inn for å kunne stemme på pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du må være logget inn for å kunne trekke tilbake stemmer på pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du valgte ingen pakker å stemme på." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Stemmene dine har blitt trukket tilbake fra de valgte pakkene." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Du har nå stemt på de valgte pakkene." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kunne ikke legge til i påminnelseslisten." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du har blitt lagt til påminnelselisten for kommentarer for %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du har blitt fjernet fra kommentarpåminnelselisten for %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Du må være logget inn for å kunne redigere pakkeinformasjon." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Mangler kommentar-ID." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentar slettet." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du har ikke tilgang til å slette denne kommentaren." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vis pakkedetaljer for" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Du må være logget inn for å kunne sende inn forespørsler om pakker." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ugyldig navn: kun små bokstaver er lov." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Kommentarfeltet kan ikke være tomt." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ugyldig type forspørsel." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Forespørsel er registrert." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ugyldig grunn." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Bare betrodde brukere og utviklere kan lukke forespørsler." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Forespørselen ble lukket." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Dette skjemaet kan brukes for å permanent slette AUR kontoen %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVARSEL%s: Denne handlingen kan ikke angres." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bekreft sletting" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Brukernavn" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Konto-type" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Bruker" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Utvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Betrodd bruker & Utvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-postadresse" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Ekte navn" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC-kallenavn" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP-nøkkel/fingeravtrykk" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Inaktiv siden" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" +#: template/account_details.php msgid "Last Login" msgstr "Sist logget inn" +#: template/account_details.php msgid "Never" msgstr "Aldri" +#: template/account_details.php msgid "View this user's packages" msgstr "Vis pakkene til denne brukereren" +#: template/account_details.php msgid "Edit this user's account" msgstr "Endre brukerkonto" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klikk %sher%s hvis du vil slette denne kontoen, for alltid." +#: template/account_edit_form.php msgid "required" msgstr "trengs" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Vanlig bruker" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Betrodd bruker" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto suspendert" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Skriv inn passordet på nytt" +#: template/account_edit_form.php msgid "Language" msgstr "Språk" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Oppdater" +#: template/account_edit_form.php msgid "Create" msgstr "Opprett" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Omstart" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Ingen treff for de oppgitte søkekriteriene." +#: template/account_search_results.php msgid "Edit Account" msgstr "Endre brukerkonto" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendert" +#: template/account_search_results.php msgid "Edit" msgstr "Rediger" +#: template/account_search_results.php msgid "Less" msgstr "Færre" +#: template/account_search_results.php msgid "More" msgstr "Flere" +#: template/account_search_results.php msgid "No more results to display." msgstr "Ingen flere resultater å vise." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Mine pakker" +#: template/header.php msgid " My Account" msgstr " Min konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakkehandlinger" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Vis PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Søk wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Markert som utdatert" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marker pakke som utdatert" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Fjern markering" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Angre stemme" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem på denne pakken" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Slå av beskjeder" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Gi beskjed om nye kommentarer" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d ventende forespørsel" msgstr[1] "%d ventende forespørsler" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Slett pakke" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Slå sammen pakke" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter pakke" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "ukjent" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Grunnpakkedetaljer" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Nøkkelord" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Innsender" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Vedlikeholder" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Siste innpakker" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmer" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Først innsendt" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Sist oppdatert" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Legg til kommentar" -msgid "Comment has been added." -msgstr "Kommentar har blitt lagt til." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Vis alle kommentarer" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Siste kommentarer" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Slett kommentar" -#, php-format -msgid "Comment by %s" -msgstr "Kommentert av %s" - -msgid "Anonymous comment" -msgstr "Anonym kommentar" - -msgid "deleted" -msgstr "slettet" - +#: template/pkg_comments.php msgid "All comments" msgstr "Alle kommentarer" +#: template/pkg_details.php msgid "Package Details" msgstr "Pakkedetaljer" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Grunnpakke" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beskrivelse" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Prosjektets URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Besøk nettsiden til" +#: template/pkg_details.php msgid "Licenses" msgstr "Lisenser" +#: template/pkg_details.php msgid "Groups" msgstr "Grupper" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikter" +#: template/pkg_details.php msgid "Provides" msgstr "Tilbyr" +#: template/pkg_details.php msgid "Replaces" msgstr "Erstatter" +#: template/pkg_details.php msgid "Dependencies" msgstr "Avhengigheter" +#: template/pkg_details.php msgid "Required by" msgstr "Trengs av" +#: template/pkg_details.php msgid "Sources" msgstr "Kilder" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Lukk forespørsel: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Bruk dette skjemaet for å lukke forespørselen for grunnpakken %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "OBS" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Kommentarfeltet kan stå tomt, men det anbefales å legge igjen en melding når " -"en forespørsel avvises." +msgstr "Kommentarfeltet kan stå tomt, men det anbefales å legge igjen en melding når en forespørsel avvises." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Begrunnelse" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Akseptert" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Avvist" -msgid "Comments" -msgstr "Kommentarer" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Send inn forespørsel: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Bruk dette skjemaet for å registrere en forespørsel for grunnpakken %s%s%s " -"som inkluderer følgende pakker:" +msgstr "Bruk dette skjemaet for å registrere en forespørsel for grunnpakken %s%s%s som inkluderer følgende pakker:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Type forespørsel" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Sletting" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Foreldreløs" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Flett med" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Fant %d pakkeforespørsel." msgstr[1] "Fant %d pakkeforespørsler." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Side %d av %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakke" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Registrert av" +#: template/pkgreq_results.php msgid "Date" msgstr "Dato" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dager igjen" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d time igjen" msgstr[1] "~%d timer igjen" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 time igjen" +#: template/pkgreq_results.php msgid "Accept" msgstr "Godta" +#: template/pkgreq_results.php msgid "Locked" msgstr "Låst" +#: template/pkgreq_results.php msgid "Close" msgstr "Lukk" +#: template/pkgreq_results.php msgid "Closed" msgstr "Lukket" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Navn, beskrivelse" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Bare navn" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Eksakt navn" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Eksakt grunnpakke" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Markert" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Umarkert" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Navn" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Stemt" -msgid "Age" -msgstr "Alder" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Stigende" +#: template/pkg_search_form.php msgid "Descending" msgstr "Synkende" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Fyll ut søkekriterier" +#: template/pkg_search_form.php msgid "Search by" msgstr "Søk etter" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Foreldet" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sorter etter" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorteringsrekkefølge" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per side" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Utfør" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Foreldreløse" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Feil ved mottagelse av pakkeliste." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ingen pakker passer til dine søkekriterier." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Fant %d pakke." msgstr[1] "Fant %d pakker." +#: template/pkg_search_results.php msgid "Version" msgstr "Versjon" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "foreldreløs" +#: template/pkg_search_results.php msgid "Actions" msgstr "Handlinger" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marker som utdatert" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Fjern markering" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter pakker" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Gjør pakker foreldreløse" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Slett pakker" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Bekreft" +#: template/search_accounts_form.php msgid "Any type" msgstr "Hvilken som helst type" +#: template/search_accounts_form.php msgid "Search" msgstr "Søk" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistikk" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Foreldreløse pakker" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Lagt til de siste 7 dagene" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Oppdaterte pakker de siste 7 dagene" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Oppdaterte pakker det siste året" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Aldri oppdaterte pakker" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrerte brukere" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Betrodde Brukere" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nylige oppdateringer" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Min statistikk" -msgid "Packages in unsupported" -msgstr "Uoffisielle pakker" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Forslagsdetaljer" +#: template/tu_details.php msgid "This vote is still running." msgstr "Avstemningen pågår fortsatt." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Innsendt: %s av %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Slutt" +#: template/tu_details.php msgid "Result" msgstr "Resultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nei" +#: template/tu_details.php msgid "Abstain" msgstr "Blank stemme" +#: template/tu_details.php msgid "Total" msgstr "Totalt" +#: template/tu_details.php msgid "Participation" msgstr "Deltagelse" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Siste stemmer fra TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Siste stemme" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ingen resultater." +#: template/tu_list.php msgid "Start" msgstr "Start" +#: template/tu_list.php msgid "Back" msgstr "Tilbake" diff --git a/po/nl.po b/po/nl.po index c85a2a37..2471e622 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Heimen Stoffels , 2015 # jelly , 2011 @@ -12,1391 +12,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" -"Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "De pagina kon niet worden gevonden" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Sorry, de pagina die u heeft aangevraagd bestaat niet." +#: html/503.php msgid "Service Unavailable" msgstr "De dienst is niet beschikbaar" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Raak niet in paniek! De website is uit de lucht wegens werkzaamheden. We " -"zullen snel weer terug in de lucht zijn." +msgstr "Raak niet in paniek! De website is uit de lucht wegens werkzaamheden. We zullen snel weer terug in de lucht zijn." +#: html/account.php msgid "Account" msgstr "Account" +#: html/account.php template/header.php msgid "Accounts" msgstr "Accounts" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "U heeft geen toegang tot dit gebied." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kon geen informatie ophalen voor de opgegeven gebruiker." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "U heeft geen toestemming om dit account te bewerken." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Gebruik dit formulier om bestaande accounts te zoeken." +#: html/account.php msgid "You must log in to view user information." msgstr "U moet inloggen om de gebruikersinformatie te bekijken." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Voorstel toevoegen" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Ongeldige token voor gebruikersactie." +#: html/addvote.php msgid "Username does not exist." msgstr "De gebruikersnaam bestaat niet." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s heeft al een voorstel ervoor lopen." +#: html/addvote.php msgid "Invalid type." msgstr "Ongeldig type." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Het voorstel mag niet leeg worden gelaten." +#: html/addvote.php msgid "New proposal submitted." msgstr "Het nieuwe voorstel is ingediend." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Een voorstel indienen om op te stemmen." +#: html/addvote.php msgid "Applicant/TU" msgstr "Aanvrager/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(laat leeg indien niet van toepassing)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "Toevoeging van een TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Verwijdering van een TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Verwijdering van een TU (onverklaarbare inactiviteit)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Wijziging van de statuten" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Voorstel" +#: html/addvote.php msgid "Submit" msgstr "Versturen" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Mede-onderhouders beheren" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Startgedeelte" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Welkom bij de AUR! Lees de %sAUR-gebruikersrichtlijnen%s en de %sAUR-" -"ontwikkelaarsrichtlijnen%s voor meer informatie." +msgstr "Welkom bij de AUR! Lees de %sAUR-gebruikersrichtlijnen%s en de %sAUR-ontwikkelaarsrichtlijnen%s voor meer informatie." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Bijgedragen PKGBUILDs %smoeten%s voldoen aan de %sArch-pakketstandaarden%s, " -"anders zullen ze worden verwijderd!" +msgstr "Bijgedragen PKGBUILDs %smoeten%s voldoen aan de %sArch-pakketstandaarden%s, anders zullen ze worden verwijderd!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Vergeet niet te stemmen op uw favoriete pakketten!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Sommige pakketten kunnen worden geleverd als uitvoerbare bestanden in " -"[community]." +msgstr "Sommige pakketten kunnen worden geleverd als uitvoerbare bestanden in [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "DISCLAIMER" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Niet-ondersteunde pakketten zijn door gebruikers geproduceerde inhoud. Elk " -"gebruik van de geleverde bestanden is op eigen risico." +#: html/home.php msgid "Learn more..." msgstr "Meer leren..." +#: html/home.php msgid "Support" msgstr "Ondersteuning" +#: html/home.php msgid "Package Requests" msgstr "Pakketaanvragen" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Er zijn drie typen aanvragen die kunnen worden ingedeeld in het " -"%sPakketacties%s-veld op de pakketdetails-pagina:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Er zijn drie typen aanvragen die kunnen worden ingedeeld in het %sPakketacties%s-veld op de pakketdetails-pagina:" +#: html/home.php msgid "Orphan Request" msgstr "Weesaanvraag" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Vragen om het pakket te markeren als wees, bijv. wanneer de onderhouder " -"inactief is en het pakket langere tijd als verouderd gemarkeerd is." +msgstr "Vragen om het pakket te markeren als wees, bijv. wanneer de onderhouder inactief is en het pakket langere tijd als verouderd gemarkeerd is." +#: html/home.php msgid "Deletion Request" msgstr "Verwijderaanvraag" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Verzoek om een pakket uit de Arch User Repository te laten verwijderen. " -"Gebruik dit niet als een pakket niet naar behoren functioneert en eenvoudig " -"gerepareerd kan worden. Neem in zo'n geval contact op met de " -"pakketontwikkelaar en open zo nodig een weesverzoek." +msgstr "Verzoek om een pakket uit de Arch User Repository te laten verwijderen. Gebruik dit niet als een pakket niet naar behoren functioneert en eenvoudig gerepareerd kan worden. Neem in zo'n geval contact op met de pakketontwikkelaar en open zo nodig een weesverzoek." +#: html/home.php msgid "Merge Request" msgstr "Aanvraag samenvoegen" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Verzoek om een pakket samen te laten voegen met een ander pakket. Dit kan " -"gebruikt worden als een pakket hernoemd moet worden of vervangen wordt door " -"een opgesplitst pakket." +msgstr "Verzoek om een pakket samen te laten voegen met een ander pakket. Dit kan gebruikt worden als een pakket hernoemd moet worden of vervangen wordt door een opgesplitst pakket." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Indien je het verzoek wilt bediscussiëren, dan kun je de %saur-requests%s " -"maillijst gebruiken. Gebruik deze lijst niet om verzoeken in te dienen." +msgstr "Indien je het verzoek wilt bediscussiëren, dan kun je de %saur-requests%s maillijst gebruiken. Gebruik deze lijst niet om verzoeken in te dienen." +#: html/home.php msgid "Submitting Packages" msgstr "Het bijdragen van pakketten" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git via SSA is nu in gebruik om pakketten bij te dragen aan de AUR. Zie de " -"%sHet bijdragen van pakketten%s-gedeelte van de Arch User Repository " -"ArchWiki-pagina voor meer details." +msgstr "Git via SSA is nu in gebruik om pakketten bij te dragen aan de AUR. Zie de %sHet bijdragen van pakketten%s-gedeelte van de Arch User Repository ArchWiki-pagina voor meer details." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "De volgende SSH-vingerafdrukken worden gebruikt voor de AUR:" +#: html/home.php msgid "Discussion" msgstr "Discussie" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Algemene discussies met betrekking tot de Arch User Repository (AUR) en de " -"opzet van Trusted Users vinden plaats op %saur-general%s. Voor discussies " -"gerelateerd aan de ontwikkeling van de AUR web interface, gebruik de %saur-" -"dev%s mailinglijst." +msgstr "Algemene discussies met betrekking tot de Arch User Repository (AUR) en de opzet van Trusted Users vinden plaats op %saur-general%s. Voor discussies gerelateerd aan de ontwikkeling van de AUR web interface, gebruik de %saur-dev%s mailinglijst." +#: html/home.php msgid "Bug Reporting" msgstr "Bug-rapportage" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Als u een bug tegenkomt in de AUR web interface, maak dan een melding in " -"onze %sbugtracker%s. Gebruik de bugtracker %salléén%s om bugs over AUR te " -"melden. Om fouten in de pakketsamenstelling te melden, neem contact op met " -"de pakketontwikkelaar of laat commentaar achter op de relevante pakketpagina." +#: html/home.php msgid "Package Search" msgstr "Pakketten zoeken" +#: html/index.php msgid "Adopt" msgstr "Adopteren" +#: html/index.php msgid "Vote" msgstr "Stemmen" +#: html/index.php msgid "UnVote" msgstr "Stem verwijderen" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Informeren" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Niet informeren" -msgid "Flag" -msgstr "Markeren" - +#: html/index.php msgid "UnFlag" msgstr "De-markeren" +#: html/login.php template/header.php msgid "Login" msgstr "Inloggen" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Ingelogd als: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Uitloggen" +#: html/login.php msgid "Enter login credentials" msgstr "Vul uw inloggegevens in" -msgid "Username" -msgstr "Gebruikersnaam" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Wachtwoord" +#: html/login.php msgid "Remember me" msgstr "Onthoud mij" +#: html/login.php msgid "Forgot Password" msgstr "Wachtwoord vergeten" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP-inloggen is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." +msgstr "HTTP-inloggen is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Zoekcriteria" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakketten" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Fout bij het ophalen van pakket details." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Er ontbreekt een verplicht veld." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Wachtwoordvelden komen niet overeen." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Uw wachtwoord moet minimaal %s karakters lang zijn." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ongeldig e-mailadres." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Een verzoek om het wachtwoord te resetten was ingediend voor het account %s " -"wat geassocieerd is met uw e-mailadres. Indien u uw wachtwoord wilt resetten " -"volg dan onderstaande link. Als u uw wachtwoord niet wilt wijzigen kunt u " -"deze mail negeren, er gebeurt dan niets." - +#: html/passreset.php msgid "Password Reset" msgstr "Wachtwoordherstel" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Controleer uw e-mail voor de bevestigingslink." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Uw wachtwoord is met succes teruggezet." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bevestig uw e-mailadres:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Voer uw nieuwe wachtwoord in:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bevestig uw nieuwe wachtwoord:" +#: html/passreset.php msgid "Continue" msgstr "Doorgaan" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Als je het e-mail adres waarmee je geregistreerd hebt vergeten bent, stuur " -"dan een bericht naar de %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Als je het e-mail adres waarmee je geregistreerd hebt vergeten bent, stuur dan een bericht naar de %saur-general%s mailing list." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Vul uw e-mail adres in:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"De geselecteerde pakketten zijn niet onteigend, vink het bevestigingsvakje " -"aan." +msgstr "De geselecteerde pakketten zijn niet onteigend, vink het bevestigingsvakje aan." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Kan geen pakket vinden om stemmen en comments mee samen te voegen" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Het basispakket kan niet met zichzelf worden samengevoegd." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"De geselecteerde pakketten zijn niet gewist, vink het bevestigingsvakje aan." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "De geselecteerde pakketten zijn niet gewist, vink het bevestigingsvakje aan." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Pakketverwijdering" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Pakket verwijderen: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Gebruik dit formulier om basispakket %s%s%s te verwijderen van AUR met " -"inbegrip van de volgende pakketten:" +msgstr "Gebruik dit formulier om basispakket %s%s%s te verwijderen van AUR met inbegrip van de volgende pakketten:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Verwijdering van een pakket is permanent." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Vink het veld aan om de actie te bevestigen." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bevestig pakketverwijdering" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Verwijderen" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten verwijderen." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Pakket onteigenen" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Pakket onteigenen: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Gebruik dit formulier om basispakket %s%s%s te onteigenen met inbegrip van " -"de volgende pakketten:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Gebruik dit formulier om basispakket %s%s%s te onteigenen met inbegrip van de volgende pakketten:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen het " -"pakket en het eigendom over te dragen aan %s%s%s." +msgstr "Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen het pakket en het eigendom over te dragen aan %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen van " -"het pakket." +msgstr "Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen van het pakket." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Bevestig de onteigening van het pakket" +#: html/pkgdisown.php msgid "Disown" msgstr "Onteigenen" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Alleen Vertouwde Gebruikers en ontwikkelaars kunnen pakketten onteigenen." +msgstr "Alleen Vertouwde Gebruikers en ontwikkelaars kunnen pakketten onteigenen." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Commentaar" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Markeren" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakketsamenvoeging" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Pakket samenvoegen: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Gebruik dit formulier om basispakkete %s%s%s samen te voegen met een ander " -"pakket." +msgstr "Gebruik dit formulier om basispakkete %s%s%s samen te voegen met een ander pakket." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "De volgende pakketten zullen worden verwijderd:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Als dit pakket samengevoegd is kan dit niet teruggedraaid worden." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Geef de naam van het pakket waarmee dit pakket samengevoegd moet worden." +msgstr "Geef de naam van het pakket waarmee dit pakket samengevoegd moet worden." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Samenvoegen naar:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Samenvoeging bevestigen" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Samenvoegen" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten samen voegen." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Aanvraag indienen" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Aanvraag sluiten" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Eerste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Vorige" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Volgende" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Laatste" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Aanvragen" +#: html/register.php template/header.php msgid "Register" msgstr "Registreren" +#: html/register.php msgid "Use this form to create an account." msgstr "Gebruik dit formulier om een ​​account aan te maken." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Voorsteldetails kunnen niet opgehaald worden." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Stemmen is gesloten voor dit voorstel." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Alleen Trusted Users kunnen stemmen." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "U kunt niet stemmen op een voorstel over u." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "U heeft al gestemd op dit voorstel." +#: html/tu.php msgid "Vote ID not valid." msgstr "Uw stem-ID is ongeldig." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Huidig aantal stemmen" +#: html/tu.php msgid "Past Votes" msgstr "Eerdere stemmen" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Stemmers" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Registratie is uitgeschakeld voor jouw IP adres, waarschijnlijk vanwege " -"langdurige spam aanvallen. Excuses voor het ongemak." +msgstr "Registratie is uitgeschakeld voor jouw IP adres, waarschijnlijk vanwege langdurige spam aanvallen. Excuses voor het ongemak." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Gebruikers-ID ontbreekt" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "De gebruikersnaam is ongeldig." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Het moet tussen de %s en %s karakters lang zijn" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Beginnen en eindigen met een letter of nummer" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan maar één punt, komma of koppelteken bevatten." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Het e-mailadres is ongeldig." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "De vingerafdruk van de PGP sleutel is ongeldig." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "De publieke SSH-sleutel is ongeldig." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Kan de account permissies niet verhogen." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Taal wordt momenteel niet ondersteund." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "De gebruikersnaam %s%s%s is al in gebruik." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Het adres %s%s%s is al in gebruik." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "De SSH publieke sleutel, %s%s%s, is al ingebruik." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Fout bij het aanmaken van account %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Het account %s%s%s is met succes aangemaakt." +#: lib/acctfuncs.inc.php +msgid "A password reset key has been sent to your e-mail address." +msgstr "Een sleutel voor het resetten van je wachtwoord is verstuurd naar je e-mail adres." + +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klik op de Login link hierboven om je account te gebruiken" -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Welkom bij %s! Om een nieuw wachtwoord voor je account in te stellen, klik " -"de link hier onder. Als de link niet werkt, probeer dan om het te kopiëren " -"en te plakken in je browser." - -msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Een sleutel voor het resetten van je wachtwoord is verstuurd naar je e-mail " -"adres." - +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Geen veranderingen zijn gemaakt aan het account, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Het account %s%s%s is met succes aangepast." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Het log-in formulier is uitgeschakeld voor je IP adres, waarschijnlijk " -"vanwege langdurige spam-aanvallen. Excuses voor het ongemak." +msgstr "Het log-in formulier is uitgeschakeld voor je IP adres, waarschijnlijk vanwege langdurige spam-aanvallen. Excuses voor het ongemak." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Account is geschorst" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Je wachtwoord is gereset. Als je net een nieuwe account hebt aangemaakt, " -"gebruik dan de link uit de bevestigingsmail om een wachtwoord te genereren. " -"In andere gevallen, vraag een herstelsleutel aan op de %sPassword Reset%s " -"pagina." +msgstr "Je wachtwoord is gereset. Als je net een nieuwe account hebt aangemaakt, gebruik dan de link uit de bevestigingsmail om een wachtwoord te genereren. In andere gevallen, vraag een herstelsleutel aan op de %sPassword Reset%s pagina." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Verkeerd gebruiker of wachtwoord" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Er is een fout opgetreden bij het aanmaken van een gebruikerssessie." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ongeldige e-mail en reset-toets combinatie." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Geen" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Toon accountinformatie voor %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Opmerking is toegevoegd." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Fout bij het ophalen van pakketdetails." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Pakketdetails kunnen niet gevonden worden." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt markeren." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Je hebt geen pakketten geselecteerd om te markeren." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "De geselecteerde pakketten zijn gemarkeerd als verouderd." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Je moet ingelogd zijn voordat je een markering voor een pakket kunt " -"verwijderen." +msgstr "Je moet ingelogd zijn voordat je een markering voor een pakket kunt verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." -msgstr "" -"Je hebt geen pakketten geselecteerd om de markering van te verwijderen." +msgstr "Je hebt geen pakketten geselecteerd om de markering van te verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De markering voor de geselecteerde pakketten is verwijderd." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Je hebt geen toestemming om pakketten te verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Je hebt geen pakketten geselecteerd om te verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De geselecteerde pakketten zijn verwijderd." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt adopteren." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt onteigenen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Je hebt geen pakketten geselecteerd om te adopteren." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Je hebt geen pakketten geselecteerd om te onteigenen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "De geselecteerde pakketten zijn geadopteerd." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De geselecteerde pakketten zijn onteigend." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Je moet ingelogd zijn voordat je kunt stemmen op pakketten." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Je moet ingelogd zijn voordat je je stem kunt verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Je hebt geen pakketten geselecteerd om op te stemmen." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Je stem is verwijderd voor de geselecteerde pakketten." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Je hebt gestemd voor de geselecteerde pakketten." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kon niet toevoegen aan notificatielijst." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Je bent toegevoegd aan de comment notificatielijst voor %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Je bent verwijderd van de comment notificatielijst voor %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Je moet ingelogd zijn voordat je pakketinformatie kunt bewerken." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Missende comment ID." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Comment is verwijderd." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Je hebt geen toestemming deze comment te verwijderen." -msgid "You are not allowed to edit the keywords of this package base." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." msgstr "" -"Je hebt geen toestemming de sleutelwoorden van dit basispakket aan te passen." +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Je hebt geen toestemming de sleutelwoorden van dit basispakket aan te passen." + +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "De sleutelwoorden van het basispakket zijn bijgewerkt." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Je hebt geen toestemming om de mede-eigenaren van dit basispakket aan te " -"passen." +msgstr "Je hebt geen toestemming om de mede-eigenaren van dit basispakket aan te passen." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ongeldige gebruikersnaam: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "De mede-onderhouders van het basispakket zijn bijgewerkt." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Toon pakketdetails voor" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Je moet ingelogd zijn voordat je pekketverzoeken kunt indienen." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ongeldige naam: alleen kleine letters zijn toegestaan." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Het commentaarveld mag niet leeg zijn." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ongeldig verzoektype." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Verzoek succesvol toegevoegd." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ongeldige reden." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Alleen TUs en ontwikkelaars mogen verzoeken sluiten." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Verzoek succesvol gesloten." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Gebruik dit formulier om permanent AUR account %s te verwijderen." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWAARSCHUWING%s: Deze actie kan niet ongedaan worden gemaakt." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bevestig verwijdering" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Gebruikersnaam" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Account Type" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Gebruiker" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Ontwikkelaar" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & Ontwikkelaar" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail adres" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Echte naam" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Nick" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP sleutel vingerafdruk" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Geen activiteit sinds" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actief" +#: template/account_details.php msgid "Last Login" msgstr "Laatste Login" +#: template/account_details.php msgid "Never" msgstr "Nooit" +#: template/account_details.php msgid "View this user's packages" msgstr "Bekijk gebruiker zijn pakketten" +#: template/account_details.php msgid "Edit this user's account" msgstr "Bewerk account van deze gebruiker" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klik %shier%s als u dit account permanent wilt verwijderen." +#: template/account_edit_form.php msgid "required" msgstr "verplicht" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normale gebruiker" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Account Geschorst" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactief" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Voer wachtwoord opnieuw in" +#: template/account_edit_form.php msgid "Language" msgstr "Taal" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"De volgende informatie is alleen verplicht als u pakketten aan de Arch User " -"Repository wilt toevoegen." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "De volgende informatie is alleen verplicht als u pakketten aan de Arch User Repository wilt toevoegen." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH Publieke Sleutel" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Update" +#: template/account_edit_form.php msgid "Create" msgstr "Aanmaken" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reset" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Geen resultaten die voldoen aan je zoekcriteria." +#: template/account_search_results.php msgid "Edit Account" msgstr "Bewerk account" +#: template/account_search_results.php msgid "Suspended" msgstr "Geschorst" +#: template/account_search_results.php msgid "Edit" msgstr "Bewerken" +#: template/account_search_results.php msgid "Less" msgstr "Minder" +#: template/account_search_results.php msgid "More" msgstr "Meer" +#: template/account_search_results.php msgid "No more results to display." msgstr "Geen andere resultaten gevonden " +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Beheer mede-onderhouders: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Gebruik dit formulier om mede-onderhouders voor %s%s%s toe te voegen (een " -"gebruikersnaam per regel):" +msgstr "Gebruik dit formulier om mede-onderhouders voor %s%s%s toe te voegen (een gebruikersnaam per regel):" +#: template/comaintainers_form.php msgid "Users" msgstr "Gebruikers" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Bewaren" +#: template/header.php msgid "My Packages" msgstr "Mijn pakketten" +#: template/header.php msgid " My Account" msgstr "Mijn Account" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakket Acties" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Toon PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Bekijk Wijzigingen" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Download momentopname" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Doorzoek wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Markeer als verouderd" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Markeer pakket als verouderd" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Verwijder markering" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Verwijder stem" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem voor dit pakket" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Schakel notificaties uit" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificatie bij nieuwe comment" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Beheer mede-onderhouders" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d verzoek in wachtrij" msgstr[1] "%d verzoeken in wachtrij" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Verwijder Pakket" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Voeg Pakket Samen" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopteer Pakket" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "onbekend" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Details van Basispakket" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Sleutelwoorden" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Inzender" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Beheerder" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Laatste Packager" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Populariteit" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Toegevoegd" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Laatste Update" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Voeg Comment Toe" -msgid "Comment has been added." -msgstr "Opmerking is toegevoegd." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Bekijk alle commentaar" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Nieuwste Comments" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Verwijder opmerking" -#, php-format -msgid "Comment by %s" -msgstr "Comment door %s" - -msgid "Anonymous comment" -msgstr "Anoniem commentaar" - -msgid "deleted" -msgstr "verwijderd" - +#: template/pkg_comments.php msgid "All comments" msgstr "Alle comments" +#: template/pkg_details.php msgid "Package Details" msgstr "Pakketdetails" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Basispakket" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Omschrijving" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Bezoek de website voor" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenties" +#: template/pkg_details.php msgid "Groups" msgstr "Groepen" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflicten" +#: template/pkg_details.php msgid "Provides" msgstr "Voorziet in" +#: template/pkg_details.php msgid "Replaces" msgstr "Vervangt" +#: template/pkg_details.php msgid "Dependencies" msgstr "Afhankelijkheden" +#: template/pkg_details.php msgid "Required by" msgstr "Vereist door" +#: template/pkg_details.php msgid "Sources" msgstr "Bronnen" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Sluit Verzoek: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." +msgstr "Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Notitie" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Het commentaarveld mag leeg blijven. Echter, het wordt sterk aanbevolen om " -"een afwijzing van commentaar te voorzien." +msgstr "Het commentaarveld mag leeg blijven. Echter, het wordt sterk aanbevolen om een afwijzing van commentaar te voorzien." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Reden" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Geaccepteerd" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Afgewezen" -msgid "Comments" -msgstr "Commentaar" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Nieuw Verzoek: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Gebruik dit formulier om een verzoek in te dienen voor basispakket %s%s%s " -"welke de volgende pakketten omvat:" +msgstr "Gebruik dit formulier om een verzoek in te dienen voor basispakket %s%s%s welke de volgende pakketten omvat:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Verzoektype" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Verwijdering" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Wees" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Voeg samen met" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d pakketverzoek gevonden" msgstr[1] "%d pakketverzoeken gevonden" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d van %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Ingediend door" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dagen resterend" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d uur resterend" msgstr[1] "~%d uur resterend" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 uur resterend" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accepteer" +#: template/pkgreq_results.php msgid "Locked" msgstr "Vergrendeld" +#: template/pkgreq_results.php msgid "Close" msgstr "Sluit" +#: template/pkgreq_results.php msgid "Closed" msgstr "Gesloten" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Naam, omschrijving" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Alleen de naam" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Exacte Naam" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Exact Basispakket" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Gemarkeerd" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Ongemarkeerd" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Naam" -msgid "Popularity" -msgstr "Populariteit" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Gestemd" -msgid "Age" -msgstr "Leeftijd" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Oplopend" +#: template/pkg_search_form.php msgid "Descending" msgstr "Aflopend" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Voer zoekcriteria in" +#: template/pkg_search_form.php msgid "Search by" msgstr "Zoek op" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Verouderd" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sorteer Op" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorteervolgorde" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ga" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Wezen" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fout bij het ophalen van pakkettenlijst" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Geen pakketen gevonden die aan uw zoekcriteria voldoen" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pakket gevonden" msgstr[1] "%d pakketten gevonden" +#: template/pkg_search_results.php msgid "Version" msgstr "Versie" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "wees" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acties" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Markeer Verouderd" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Hef Out-of-Date markering op" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopteer Pakketten" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Onteigen Pakketten" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Verwijder pakketten" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Bevestig" +#: template/search_accounts_form.php msgid "Any type" msgstr "Elk type" +#: template/search_accounts_form.php msgid "Search" msgstr "Zoek" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistieken" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Weespakketten" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakketten toegevoegd in de laatste 7 dagen" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakketten geüpdatet in de laatste 7 dagen" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakketen geüpdatet in het laatste jaar" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nooit geüpdate pakketten" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Geregistreerde Gebruikers" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Recente updates" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mijn statistieken" -msgid "Packages in unsupported" -msgstr "Pakketten in AUR" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Voorsteldetails" +#: template/tu_details.php msgid "This vote is still running." msgstr "Dit voorstel is nog bezig" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Opgestuurd: %s door %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Einde" +#: template/tu_details.php msgid "Result" msgstr "Resultaat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nee" +#: template/tu_details.php msgid "Abstain" msgstr "Onthouden" +#: template/tu_details.php msgid "Total" msgstr "Totaal" +#: template/tu_details.php msgid "Participation" msgstr "Participatie" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Laatste stemmen door TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Laatste stem" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Geen resultaten gevonden." +#: template/tu_list.php msgid "Start" msgstr "Start " +#: template/tu_list.php msgid "Back" msgstr "Terug" diff --git a/po/pl.po b/po/pl.po index a0a671b1..342d05c1 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Bartłomiej Piotrowski , 2011 # Bartłomiej Piotrowski , 2014 @@ -15,943 +15,1268 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-30 13:02+0000\n" -"Last-Translator: Piotr Strębski \n" -"Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" -"pl/)\n" -"Language: pl\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2);\n" +"Language: pl\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +#: html/404.php msgid "Page Not Found" msgstr "Nie znaleziono strony" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Przepraszamy, strona o którą prosiłeś nie istnieje." +#: html/503.php msgid "Service Unavailable" msgstr "Usługa niedostępna" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Nie panikuj! W związku z przeprowadzanymi pracami technicznymi strona jest " -"chwilowo niedostępna. Już wkrótce wrócimy." +msgstr "Nie panikuj! W związku z przeprowadzanymi pracami technicznymi strona jest chwilowo niedostępna. Już wkrótce wrócimy." +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Konta" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nie masz uprawnień do oglądania tej strony." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Uzyskanie informacji o podanym użytkowniku nie powiodło się." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nie masz uprawnień do edycji tego konta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Przy użyciu tego formularza możesz przeszukać istniejące konta." +#: html/account.php msgid "You must log in to view user information." msgstr "Musisz być zalogowany aby móc oglądać informacje o użytkownikach." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Dodaj Propozycję" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Nieprawidłowy token dla akcji użytkownika." +#: html/addvote.php msgid "Username does not exist." msgstr "Nazwa użytkownika nie istnieje." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ma już propozycję dla nich." +#: html/addvote.php msgid "Invalid type." msgstr "Nieprawidłowy rodzaj." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Propozycja nie może być pusta." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nowa propozycja wysłana." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Wyślij propozycję do głosowania." +#: html/addvote.php msgid "Applicant/TU" msgstr "Wnioskodawca/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(puste jeśli nie dotyczy)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Rodzaj" +#: html/addvote.php msgid "Addition of a TU" msgstr "Dodanie ZU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Usunięcie ZU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Usunięcie ZU (niezadeklarowana nieaktywność)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Zmiana Regulaminu" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propozycja" +#: html/addvote.php msgid "Submit" msgstr "Wyślij" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Zarządzanie współutrzymującymi" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Start" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Witamy w AUR! Aby uzyskać więcej informacji, przeczytaj %sInstrukcję " -"Użytkownika AUR%s oraz %sInstrukcję Zaufanego Użytkownika%s." +msgstr "Witamy w AUR! Aby uzyskać więcej informacji, przeczytaj %sInstrukcję Użytkownika AUR%s oraz %sInstrukcję Zaufanego Użytkownika%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Pliki PKGBUILD %smuszą%s być zgodne ze %sStandardami Pakietów Archa%s, " -"inaczej będą usuwane!" +msgstr "Pliki PKGBUILD %smuszą%s być zgodne ze %sStandardami Pakietów Archa%s, inaczej będą usuwane!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nie zapomnij zagłosować na swoje ulubione pakiety!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Część pakietów może być dostępna w formie binarnej w [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ZRZECZENIE" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Zamieszczone pakiety są niewspierane i utworzone przez użytkowników. Używasz " -"ich na własne ryzyko." +#: html/home.php msgid "Learn more..." msgstr "Dowiedz się więcej..." +#: html/home.php msgid "Support" msgstr "Wsparcie" +#: html/home.php msgid "Package Requests" msgstr "Prośby o pakiet" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "Prośba o usunięcie" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "Prośba o połączenie" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "Przesyłanie pakietów" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Dyskusja" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Zgłaszanie błędów" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Wyszukiwanie pakietów" +#: html/index.php msgid "Adopt" msgstr "Przejmij" +#: html/index.php msgid "Vote" msgstr "Głosuj" +#: html/index.php msgid "UnVote" msgstr "Cofnij głos" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Włącz powiadamianie" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Rezygnuj z powiadamiania" -msgid "Flag" -msgstr "Oznacz" - +#: html/index.php msgid "UnFlag" msgstr "Odznacz" +#: html/login.php template/header.php msgid "Login" msgstr "Zaloguj się" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Zalogowany jako: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Wyloguj się" +#: html/login.php msgid "Enter login credentials" msgstr "Podaj poświadczenia logowania" -msgid "Username" -msgstr "Użytkownik" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Hasło" +#: html/login.php msgid "Remember me" msgstr "Zapamiętaj mnie" +#: html/login.php msgid "Forgot Password" msgstr "Zapomniałem hasła" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Logowanie w HTTP jest wyłączone. %sPrzełącz się na HTTPs%s aby się " -"zalogować." +msgstr "Logowanie w HTTP jest wyłączone. %sPrzełącz się na HTTPs%s aby się zalogować." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kryteria wyszukiwania" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakiety" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Błąd podczas pobierania informacji o pakiecie." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Brakuje wymaganego pola." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Hasła nie zgadzają się." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Twoje hasło musi mieć składać się z conajmniej %s znaków." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Nieprawidłowy e-mail." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Resetowanie hasła" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "" -"Na Twój adres został wysłany e-mail z instrukcją dotyczącą resetowania hasła." +msgstr "Na Twój adres został wysłany e-mail z instrukcją dotyczącą resetowania hasła." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Twoje hasło zostało pomyślnie zresetowane." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potwierdź swój adres e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Wpisz nowe hasło:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Wpisz ponownie hasło:" +#: html/passreset.php msgid "Continue" msgstr "Kontynuuj" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Jeśli zapomniałeś adresu e-mail, którego użyłeś do rejestracji, prosimy o " -"wysłanie wiadomości na naszą listę dyskusyjną %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Jeśli zapomniałeś adresu e-mail, którego użyłeś do rejestracji, prosimy o wysłanie wiadomości na naszą listę dyskusyjną %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Wpisz swój adres e-mail:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Nie można znaleźć pakietu do scalenia głosów i komentarzy." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nie można połączyć bazowego pakietu z nim samym." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Wybrane pakiety nie zostały usunięte, sprawdź pole wyboru potwierdzenia." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Wybrane pakiety nie zostały usunięte, sprawdź pole wyboru potwierdzenia." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Usuwanie pakietów" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Usuń pakiet: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Użyj tego formularza, aby usunąć bazę pakietu %s%s%s i następujące pakiety z " -"AUR:" +msgstr "Użyj tego formularza, aby usunąć bazę pakietu %s%s%s i następujące pakiety z AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Usunięcie pakietu jest nieodwracalne." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaznacz pole aby potwierdzić akcję." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potwierdź usunięcie pakietu" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Usuń" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą usuwać pakiety." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Porzuć pakiet" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "Porzuć" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Kommentarze" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Oznacz" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Scalanie pakietów" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Scal pakiet: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Użyj tego formularza, aby scalić bazę pakietu %s%s%s w inny pakiet." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Następujące pakiety zostaną usunięte:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Gdy pakiet zostanie scalony to nie będzie możliwości odwrócenia tej " -"czynności." +msgstr "Gdy pakiet zostanie scalony to nie będzie możliwości odwrócenia tej czynności." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Podaj nazwę pakietu, pod którą chcesz dokonać scalenia pakietu." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Scal z:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potwierdź scalenie pakietu" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Scal" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą scalać pakiety." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Złóż propozycję" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zamknij propozycję" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Pierwsza" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Poprzednia" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Następna" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ostatnia" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Propozcje" +#: html/register.php template/header.php msgid "Register" msgstr "Zarejestruj się" +#: html/register.php msgid "Use this form to create an account." msgstr "Przy użyciu tego formularza możesz utworzyć konto." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Zaufany Użytkownik" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nie można odczytać szczegółów propozycji." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Głosowanie na tą propozycję jest zamknięte." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Tylko Zaufani Użytkownicy mogą głosować." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nie możesz głosować w propozycji o tobie." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Już zagłosowałeś na tą propozycję" +#: html/tu.php msgid "Vote ID not valid." msgstr "ID głosowania nieprawidłowe." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Obecne Głosy" +#: html/tu.php msgid "Past Votes" msgstr "Poprzednie Głosy" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Głosujących" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Rejestracja konta została wyłączona dla Twojego adresu IP, " -"najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. " -"Przepraszamy za niedogodności." +msgstr "Rejestracja konta została wyłączona dla Twojego adresu IP, najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. Przepraszamy za niedogodności." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Brakujące ID użytkownika." +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Nazwa użytkownika jest nieprawidłowa." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Długość musi być pomiędzy %s a %s" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Zacznij i zakończ literą lub cyfrą" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Może zawierać tylko jedną kropkę, podkreślnik lub myślnik." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adres e-mail jest nieprawidłowy." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Odcisk palca klucza PGP jest nieprawidłowy." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." -msgstr "" +msgstr "Klucz publiczny SSH jest nieprawidłowy." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nie można zwiększyć uprawnień konta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Język nie jest obecnie obsługiwany." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Nazwa użytkownika, %s%s%s, jest już używana." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adres, %s%s%s, jest już używany." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Wystąpił błąd podczas tworzenia konta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Konto %s%s%s zostało pomyślnie utworzone." -msgid "Click on the Login link above to use your account." -msgstr "Kliknij na link Zaloguj się powyżej aby się zalogować." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Witamy w %s! Aby ustawić hasło początkowe dla swojego nowego konta prosimy o " -"kliknięcie poniższego odnośnika. Jeśli odnośnik nie zadziała spróbuj " -"skopiować go i wkleić w oknie swojej przeglądarki internetowej." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Klucz resetujący hasło został przesłany na Twój adres e-mail." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Kliknij na link Zaloguj się powyżej aby się zalogować." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nie zostały dokonane żadne zmiany na koncie, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Konto %s%s%s zostało pomyślnie zaktualizowane." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Formularz logowania jest obecnie wyłączony dla Twojego adresu IP, " -"najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. " -"Przepraszamy za niedogodności." +msgstr "Formularz logowania jest obecnie wyłączony dla Twojego adresu IP, najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. Przepraszamy za niedogodności." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto zawieszone" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Twoje hasło zostało zresetowane. Jeśli dopiero co utworzyłeś nowe konto, " -"prosimy o użycie odnośnika z e-maila potwierdzającego rejestrację, aby " -"ustawić hasło początkowe. W innym przypadku, prosimy o wnioskowanie o klucz " -"resetujący na stronie %sresetowania hasła%s." +msgstr "Twoje hasło zostało zresetowane. Jeśli dopiero co utworzyłeś nowe konto, prosimy o użycie odnośnika z e-maila potwierdzającego rejestrację, aby ustawić hasło początkowe. W innym przypadku, prosimy o wnioskowanie o klucz resetujący na stronie %sresetowania hasła%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nieprawidłowa nazwa użytkownika lub hasło." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Wystąpił błąd przy próbie utworzenia sesji użytkownika." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Nieprawidłowy e-mail i klucz do resetowania." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Żaden" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Wyświetl informacje o koncie %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Komentarz został dodany." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Błąd podczas pobierania informacji o pakiecie." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nie odnaleziono informacji o pakiecie." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Musisz być zalogowany aby móc oznaczyć pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nie wybrałeś żadnych pakietów do oznaczenia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Wybrane pakiety zostały oznaczone jako nieaktualne." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musisz być zalogowany aby móc odznaczyć pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nie wybrałeś żadnych pakietów do odznaczenia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Wybrane pakiety zostały odznaczone." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nie masz uprawnień do usuwania pakietów." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nie wybrałeś żadnych pakietów do usunięcia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Wybrane pakiety zostały usunięte." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musisz być zalogowany aby móc przejmować pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musisz być zalogowany aby móc porzucać pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nie wybrałeś żadnych pakietów do przejęcia." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nie wybrałeś żadnych pakietów do porzucenia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Wybrane pakiety zostały przejęte." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Wybrane pakiety zostały porzucone." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Musisz być zalogowany aby móc głosować na pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musisz być zalogowany aby móc anulować głosy na pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nie wybrałeś żadnych pakietów do zagłosowania." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Twoje głosy zostały odebrane wybranym pakietom." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Twoje głosy zostały przyznane wybranym pakietom." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Dodanie do listy powiadamiania nie powiodło się." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Zostałeś dodany do listy powiadamiania o nowych komentarzach dla %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Zostałeś usunięty z listy powiadamiania o komentarzach dla %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Musisz być zalogowany aby móc edytować informacje o pakiecie." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Brakuje identyfikatora komentarza." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentarz został usunięty." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nie masz uprawnień do usunięcia tego komentarza." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Niepoprawna nazwa użytkownika: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Wyświetl informacje o pakiecie" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nieprawidłowa nazwa: tylko małe litery są dozwolone." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Pole komentarzy nie może pozostać pustę." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Nieprawidłowy rodzaj propozycji." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Pomyślnie dodano propozycję." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Nieprawidłowy powód." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą zamykać propozycje." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Pomyślnie zamknięto propozycję." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Możesz użyć tego formularza, aby nieodwracalnie usunąć konto %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUWAGA%s: Ta czynność nie może zostać cofnięta." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Potwierdź usunięcie" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Użytkownik" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Rodzaj konta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Użytkownik" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Deweloper" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Zaufany Użytkownik i Developer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adres e-mail" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Imię i nazwisko" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick na IRC-u" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Odcisk palca klucza PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stan" +#: template/account_details.php msgid "Inactive since" msgstr "Nieaktywny od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktywne" +#: template/account_details.php msgid "Last Login" msgstr "Ostatnie logowanie" +#: template/account_details.php msgid "Never" msgstr "Nigdy" +#: template/account_details.php msgid "View this user's packages" msgstr "Wyświetl pakiety tego użytkownika" +#: template/account_details.php msgid "Edit this user's account" msgstr "Edycja tego konta użytkownika" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknij %stutaj%s jeśli chcesz nieodwracalnie usunąć to konto." +#: template/account_edit_form.php msgid "required" msgstr "wymagane" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Zwykły użytkownik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Zaufany Użytkownik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto zablokowane" +#: template/account_edit_form.php msgid "Inactive" msgstr "Nieaktywny" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Hasło (ponownie)" +#: template/account_edit_form.php msgid "Language" msgstr "Język" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Klucz publiczny SSH" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualizuj" +#: template/account_edit_form.php msgid "Create" msgstr "Utwórz" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Wyczyść" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Wyszukiwanie nie przyniosło rezultatu." +#: template/account_search_results.php msgid "Edit Account" msgstr "Edytuj konto" +#: template/account_search_results.php msgid "Suspended" msgstr "Zablokowane" +#: template/account_search_results.php msgid "Edit" msgstr "Edytuj" +#: template/account_search_results.php msgid "Less" msgstr "Poprzednie" +#: template/account_search_results.php msgid "More" msgstr "Następne" +#: template/account_search_results.php msgid "No more results to display." msgstr "Brak wyników do wyświetlenia." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "Użytkownicy" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Zapisz" +#: template/header.php msgid "My Packages" msgstr "Moje pakiety" +#: template/header.php msgid " My Account" msgstr "Moje konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Działania na pakietach" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Pokaż PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Zobacz zmiany" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Przeszukaj wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Oznaczony jako nieaktualny" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Oznacz pakiet jako nieaktualny" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Odznacz pakiet" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Usuń głos" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Zagłosuj na ten pakiet" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Wyłącz powiadomienia" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Powiadom o nowych komentarzach" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -959,167 +1284,232 @@ msgstr[0] "%d propozycja w toku" msgstr[1] "%d propozycje w toku" msgstr[2] "%d propozycji w toku" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Usuń pakiet" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Scal pakiet" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Przejmij pakiet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "nieznana" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Szczegóły bazy pakietu" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Słowa kluczowe" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Nadesłał" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Opiekun" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ostatni pakujący" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Głosy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularność" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Wysłany" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ostatnia aktualizacja" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Dodaj komentarz" -msgid "Comment has been added." -msgstr "Komentarz został dodany." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Pokaż wszystkie komentarze" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Ostatnie komentarze" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Usuń komentarz" -#, php-format -msgid "Comment by %s" -msgstr "Komentarz użytkownika %s" - -msgid "Anonymous comment" -msgstr "Anonimowy komentarz" - -msgid "deleted" -msgstr "usunięty" - +#: template/pkg_comments.php msgid "All comments" msgstr "Wszystkie komentarze" +#: template/pkg_details.php msgid "Package Details" msgstr "Informacje o pakiecie" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Baza pakietu" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL upstreamu" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Odwiedź stronę pakietu" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencje" +#: template/pkg_details.php msgid "Groups" msgstr "Grupy" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikty" +#: template/pkg_details.php msgid "Provides" msgstr "Zapewnia" +#: template/pkg_details.php msgid "Replaces" msgstr "Zastępuje" +#: template/pkg_details.php msgid "Dependencies" msgstr "Zależności" +#: template/pkg_details.php msgid "Required by" msgstr "Wymagane przez" +#: template/pkg_details.php msgid "Sources" msgstr "Źródła" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "Uwaga" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Powód" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Zaakceptowany" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Odrzucony" -msgid "Comments" -msgstr "Kommentarze" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Propozycja Pliku: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Użyj tego formularza, aby złożyć propozycję na bazę pakietu %s%s%s i " -"następujące pakiety:" +msgstr "Użyj tego formularza, aby złożyć propozycję na bazę pakietu %s%s%s i następujące pakiety:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Rodzaj Propozycji" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Usunięcie" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Bez opiekuna" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Scal z" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1127,23 +1517,29 @@ msgstr[0] "%d propozycje znaleziono" msgstr[1] "%d propozycje znaleziono." msgstr[2] "%d propozycji znaleziono." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Strona %d z %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakiet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Złożone przez" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "pozostało ~%d dni" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1151,90 +1547,116 @@ msgstr[0] "pozostała ~%d godzina" msgstr[1] "pozostały ~%d godziny" msgstr[2] "pozostało ~%d godzin" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "pozostała <1 godzina" +#: template/pkgreq_results.php msgid "Accept" msgstr "Akceptuj" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zablokowane" +#: template/pkgreq_results.php msgid "Close" msgstr "Zamknij" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zamknięte" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nazwa, Opis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Tylko nazwa" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Dokładna nazwa" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Dokładna baza pakietu" +#: template/pkg_search_form.php msgid "All" msgstr "Wszystkie" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Oznaczony" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nieoznaczony" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nazwa" -msgid "Popularity" -msgstr "Popularność" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Głos" -msgid "Age" -msgstr "Wiek" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Rosnąco" +#: template/pkg_search_form.php msgid "Descending" msgstr "Malejąco" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Podaj kryteria wyszukiwania" +#: template/pkg_search_form.php msgid "Search by" msgstr "Szukaj według" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Nieaktualny" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortuj według" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Porządek" +#: template/pkg_search_form.php msgid "Per page" msgstr "Na stronie" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Wykonaj" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Bez opiekuna" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Błąd podczas pobierania listy pakietów." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Żaden pakiet nie spełnia podanych kryteriów." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1242,119 +1664,154 @@ msgstr[0] "%d pakiet znaleziono" msgstr[1] "%d pakiety znaleziono" msgstr[2] "%d pakietów znaleziono" +#: template/pkg_search_results.php msgid "Version" msgstr "Wersja" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Tak" +#: template/pkg_search_results.php msgid "orphan" msgstr "bez opiekuna" +#: template/pkg_search_results.php msgid "Actions" msgstr "Działania" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Oznacz jako nieaktualny" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Usuń flagę nieaktualności" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Przejmij pakiety" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Porzuć pakiety" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Usuń pakiety" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potwierdź" +#: template/search_accounts_form.php msgid "Any type" msgstr "Dowolny rodzaj" +#: template/search_accounts_form.php msgid "Search" msgstr "Szukaj" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statystyki" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Osierocone" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Dodane przez ostatnie 7 dni" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Zaktualizowane przez ostatnie 7 dni" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Zaktualizowane przez ostatni rok" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nigdy nieaktualizowane" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Zarejestrowani użytkownicy" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Zaufani Użytkownicy" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Ostatnie aktualizacje" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moje statystyki" -msgid "Packages in unsupported" -msgstr "Pakietów w unsupported" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Szczegóły propozycji" +#: template/tu_details.php msgid "This vote is still running." msgstr "Głosowanie ciągle trwa." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Wysłane: %s przez %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Koniec" +#: template/tu_details.php msgid "Result" msgstr "Wynik" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nie" +#: template/tu_details.php msgid "Abstain" msgstr "Wstrzymaj się od głosu" +#: template/tu_details.php msgid "Total" msgstr "Suma" +#: template/tu_details.php msgid "Participation" msgstr "Uczestnictwo" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ostatnie głosy ZU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ostatni głos" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Brak wyników." +#: template/tu_list.php msgid "Start" msgstr "Początek" +#: template/tu_list.php msgid "Back" msgstr "Wstecz" diff --git a/po/pt_BR.po b/po/pt_BR.po index a9664486..d0c7e044 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1,1397 +1,1810 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Albino Biasutti Neto Bino , 2011 # Rafael Fontenelle , 2012-2015 +# Rafael Fontenelle , 2015 # Rafael Fontenelle , 2011 # Sandro , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-20 15:11+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 10:30+0000\n" "Last-Translator: Rafael Fontenelle \n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" -"language/pt_BR/)\n" -"Language: pt_BR\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página não encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Desculpe, a página que você solicitou não existe." +#: html/503.php msgid "Service Unavailable" msgstr "Serviço Indisponível" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Sem pânico! Este site está fechado para manutenção. Voltaremos às atividades " -"em breve." +msgstr "Sem pânico! Este site está fechado para manutenção. Voltaremos às atividades em breve." +#: html/account.php msgid "Account" msgstr "Conta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Contas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Você não tem permissão para acessar esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Não foi possível obter informações para o usuário especificado." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Você não tem permissão para editar esta conta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Você precisa fazer login para ver as informações do usuário." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adicionar proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Token inválido para a ação de usuário." +#: html/addvote.php msgid "Username does not exist." msgstr "Usuário não existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s já tem uma proposta aberta para eles." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo inválido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Proposta não pode ser vazia." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta foi enviada." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Enviar uma proposta para ser votada." +#: html/addvote.php msgid "Applicant/TU" msgstr "Requerente/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vazio se não aplicável)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Adição de um TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remoção de um TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remoção de um TU (inatividade não declarada)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Emenda ao Estatuto" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Enviar" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gerenciar co-mantenedores" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "Editar comentário" + +#: html/home.php template/header.php msgid "Home" msgstr "Início" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bem-vindo ao AUR! Por favor, leia as %sDiretrizes de Usuário do AUR%s e " -"%sDiretrizes de TU do AUR%s para mais informações." +msgstr "Bem-vindo ao AUR! Por favor, leia as %sDiretrizes de Usuário do AUR%s e %sDiretrizes de TU do AUR%s para mais informações." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"PKGBUILDs contribuídos %sdevem%s estar em conformidade com os %sPadrões de " -"Empacotamento do Arch%s, do contrário eles serão excluídos!" +msgstr "PKGBUILDs contribuídos %sdevem%s estar em conformidade com os %sPadrões de Empacotamento do Arch%s, do contrário eles serão excluídos!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Lembre-se de votar nos seus pacotes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Alguns pacotes podem ser fornecidos como binários no repositório [community]." +msgstr "Alguns pacotes podem ser fornecidos como binários no repositório [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVISO LEGAL" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." -msgstr "" -"Pacotes sem suporte são pacotes produzidos pelos usuários. Qualquer uso dos " -"arquivos fornecidos é de sua própria conta e risco." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." +msgstr "Os pacotes do AUR são conteúdos produzidos por usuários. Qualquer uso dos arquivos fornecidos é de sua própria conta e risco." +#: html/home.php msgid "Learn more..." msgstr "Aprenda mais..." +#: html/home.php msgid "Support" msgstr "Suporte" +#: html/home.php msgid "Package Requests" msgstr "Requisições de pacote" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Há três tipos de requisições que podem ser realizadas na caixa %sAções do " -"pacote%s na página de detalhes do pacote:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Há três tipos de requisições que podem ser realizadas na caixa %sAções do pacote%s na página de detalhes do pacote:" +#: html/home.php msgid "Orphan Request" msgstr "Requisição para tornar o pacote órfão" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Requisite que seja desvinculado um pacote de seu mantenedor, de forma que o " -"pacote fique órfão, quando, por exemplo, o mantenedor está inativo e o " -"pacote foi marcado como desatualizado há muito tempo." +msgstr "Requisite que seja desvinculado um pacote de seu mantenedor, de forma que o pacote fique órfão, quando, por exemplo, o mantenedor está inativo e o pacote foi marcado como desatualizado há muito tempo." +#: html/home.php msgid "Deletion Request" msgstr "Requisição de exclusão" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Requisite que um pacote seja removido do Arch User Repository. Por favor, " -"não use esta opção se um pacote está quebrado, mas que pode ser corrigido " -"facilmente. Ao invés disso, contate o mantenedor do pacote e, se necessário, " -"preencha uma requisição para tornar esse pacote órfão." +msgstr "Requisite que um pacote seja removido do Arch User Repository. Por favor, não use esta opção se um pacote está quebrado, mas que pode ser corrigido facilmente. Ao invés disso, contate o mantenedor do pacote e, se necessário, preencha uma requisição para tornar esse pacote órfão." +#: html/home.php msgid "Merge Request" msgstr "Requisição de mesclagem" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Requisite que um pacote seja mesclado com outro. Pode ser usado quando um " -"pacote precisa ser renomeado ou substituído por um pacote dividido." +msgstr "Requisite que um pacote seja mesclado com outro. Pode ser usado quando um pacote precisa ser renomeado ou substituído por um pacote dividido." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Se você quiser discutir uma requisição, você pode user a lista de discussão " -"%saur-request%s. Porém, por favor não use essa lista para fazer requisições." +msgstr "Se você quiser discutir uma requisição, você pode user a lista de discussão %saur-request%s. Porém, por favor não use essa lista para fazer requisições." +#: html/home.php msgid "Submitting Packages" msgstr "Enviando pacotes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git sobre SSH agora é usado para enviar pacotes para o AUR. Veja a seção " -"%sEnviando pacotes%s da página wiki do Arch User Repository para mais " -"detalhes." +msgstr "Git sobre SSH agora é usado para enviar pacotes para o AUR. Veja a seção %sEnviando pacotes%s da página wiki do Arch User Repository para mais detalhes." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "As seguintes fingeprints SSH são usadas para o AUR:" +#: html/home.php msgid "Discussion" msgstr "Discussão" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) " -"e do Trusted User acontecem no %saur-general%s. Para discussão relacionada " -"ao desenvolvimento do AUR web, use a lista de discussão do %saur-dev%s" +msgstr "Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) e do Trusted User acontecem no %saur-general%s. Para discussão relacionada ao desenvolvimento do AUR web, use a lista de discussão do %saur-dev%s" +#: html/home.php msgid "Bug Reporting" msgstr "Relatório de erros" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." -msgstr "" -"Se você encontrar um erro na interface web do AUR, por favor preencha um " -"relatório de erro no nosso %sbug tracker%s. Use o tracker para relatar erros " -"encontrados no AUR, %ssomente%s. Para relatar erros de empacotamento, " -"contate o mantenedor do pacote ou deixe um comentário na página de pacote " -"apropriada." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Se você encontrar um erro na interface web do AUR, por favor preencha um relatório de erro no nosso %sbug tracker%s. Use o tracker para relatar erros encontrados no AUR web, %ssomente%s. Para relatar erros de empacotamento, contate o mantenedor do pacote ou deixe um comentário na página de pacote apropriada." +#: html/home.php msgid "Package Search" msgstr "Pesquisar pacote" +#: html/index.php msgid "Adopt" msgstr "Adotar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Desfazer voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Não notificar" -msgid "Flag" -msgstr "Marcar" - +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Login" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Conectado como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Sair" +#: html/login.php msgid "Enter login credentials" msgstr "Digite as credenciais de login" -msgid "Username" -msgstr "Usuário" +#: html/login.php +msgid "User name or email address" +msgstr "Nome de usuário ou endereço de e-mail" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Senha" +#: html/login.php msgid "Remember me" msgstr "Lembrar de mim" +#: html/login.php msgid "Forgot Password" msgstr "Esqueci minha senha" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Login via HTTP está desabilitado. Favor %sacesse via HTTPs%s caso queira " -"fazer login." +msgstr "Login via HTTP está desabilitado. Favor %sacesse via HTTPs%s caso queira fazer login." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critérios de pesquisa" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacotes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erro ao tentar obter detalhes do pacote." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Preencha todos os campos obrigatórios." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Campos de senha não correspondem." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Sua senha deve conter pelo menos %s caracteres." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail inválido." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Um pedido de redefinição de senha foi solicitado para a conta %s associada " -"com seu endereço de e-mail. Se deseja redefinir sua senha acesse o link " -"abaixo, do contrário ignore essa mensagem e nada vai acontecer." - +#: html/passreset.php msgid "Password Reset" msgstr "Redefinição de senha" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifique no seu e-mail pelo link de confirmação." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Sua senha foi redefinida com sucesso." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme seu endereço de e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Informe com sua senha:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme sua nova senha:" +#: html/passreset.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Se você esqueceu o endereço de e-mail que você usou para registrar, por " -"favor envie uma mensagem para a lista de e-mail do %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Se você esqueceu o endereço de e-mail que você usou para registrar, por favor envie uma mensagem para a lista de e-mail do %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Digite o seu endereço de e-mail:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Os pacotes selecionados não foram marcados como desatualizados, por favor insira um comentário." + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Os pacotes selecionados não foram abandonados, marque a caixa de confirmação." +msgstr "Os pacotes selecionados não foram abandonados, marque a caixa de confirmação." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Não foi possível encontrar pacote para nele fundir votos e comentários." +msgstr "Não foi possível encontrar pacote para nele fundir votos e comentários." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Não é possível mesclar um pacote base com ele mesmo" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Exclusão de pacotes" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Excluir pacote: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Use este formulário para excluir o pacote base %s%s%s e os seguintes pacotes " -"do AUR: " +msgstr "Use este formulário para excluir o pacote base %s%s%s e os seguintes pacotes do AUR: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "A exclusão de pacote um pacote é permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Marque a caixa de seleção para confirmar a ação." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmar exclusão de pacote" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Excluir" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Somente Trusted Users e Desenvolvedores podem excluir pacotes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar pacote" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Abandonar pacote: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Use esse formulário para abandonar o pacote base %s%s%s que incluem os " -"seguintes pacotes:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Use esse formulário para abandonar o pacote base %s%s%s que incluem os seguintes pacotes:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote e " -"transferir a responsabilidade para %s%s%s." +msgstr "Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote e transferir a responsabilidade para %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote." +msgstr "Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirme para abandonar o pacote" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Apenas Trusted Users e Desenvolvedores podem abandonar pacotes." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "Marcar pacote desatualizado" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "Marcar pacote desatualizado: %s" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Use este formulário para marcar o pacote base %s%s%s e os seguintes pacotes como desatualizados: " + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "Por favor, %snão%s use esse formulário para relatar erros. Para isto, use os comentários do pacote." + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "Insira detalhes sobre o motivo do pacote estar desatualizado abaixo, preferivelmente incluindo links para o anúncio de lançamento ou um novo tarball de lançamento." + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Comentários" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Marcar" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "Apenas usuários registrados podem marcar pacotes como desatualizados." + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Mesclagem de pacotes" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Mesclar pacote: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Use este formulário para mesclar o pacote base %s%s%s em outro pacote. " +msgstr "Use este formulário para mesclar o pacote base %s%s%s em outro pacote. " +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Os seguintes pacotes serão excluídos: " +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Assim que o pacote tiver sido mesclado, não é possível reverter a ação." +msgstr "Assim que o pacote tiver sido mesclado, não é possível reverter a ação." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Digite o nome do pacote para o qual você deseja mesclar o pacote." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Mesclar em:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmar a mesclagem de pacotes" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Mesclar" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Somente Trusted Users e Desenvolvedores podem mesclar pacotes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Fazer requisição" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fechar requisição" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Próxima" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Última" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Requisições" +#: html/register.php template/header.php msgid "Register" msgstr "Registrar" +#: html/register.php msgid "Use this form to create an account." msgstr "Utilize este formulário para criar uma conta." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Não foi possível adquirir detalhes da proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A votação está encerrada para esta proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Apenas Trusted Users têm permissão para votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Você não pode votar em uma proposta sobre você." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Você já votou nessa proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID de voto inválido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos atuais" +#: html/tu.php msgid "Past Votes" msgstr "Votos anteriores" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Eleitores" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O registro de conta foi desabilitado para seu endereço IP, provavelmente por " -"causa de ataques continuados de spam. Desculpe a inconveniência." +msgstr "O registro de conta foi desabilitado para seu endereço IP, provavelmente por causa de ataques continuados de spam. Desculpe a inconveniência." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Faltando ID de usuário" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "O usuário é inválido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Deve conter entre %s e %s caracteres" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Começo e fim com uma letra ou um número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Pode conter somente um ponto, traço inferior ou hífen." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "A chave pública de SSH é inválida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Não foi possível aumentar as permissões da conta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Idioma sem suporte no momento." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de usuário, %s%s%s, já está sendo usado." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "O endereço, %s%s%s, já está sendo usado." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "A chave pública de SSH, %s%s%s, já está em uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erro ao tentar criar uma conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A conta, %s%s%s, foi criada com sucesso." +#: lib/acctfuncs.inc.php +msgid "A password reset key has been sent to your e-mail address." +msgstr "Uma chave de redefinição de senha foi enviada para seu endereço de e-mail." + +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clique no link de Login acima para usar a sua conta." -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Bem-vindo ao %s! Para definir uma senha inicial para sua nova conta, por " -"favor clique no link abaixo. Se o link não funciona, tente copiar e colá-lo " -"no seu navegador." - -msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Uma chave de redefinição de senha foi enviada para seu endereço de e-mail." - +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nenhuma alteração foi feita na conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A conta, %s%s%s, foi modificada com sucesso." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O formulário de login está desabilitado momento para seu endereço IP, " -"provavelmente por causa de ataques continuados de spam. Desculpe a " -"inconveniência." +msgstr "O formulário de login está desabilitado momento para seu endereço IP, provavelmente por causa de ataques continuados de spam. Desculpe a inconveniência." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Conta suspensa" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Sua senha foi redefinida. Se você acabou de criar uma conta, por favor use o " -"link do e-mail de confirmação para definir uma senha inicial. Do contrário, " -"por favor requisite uma chave de senha na página de %sRedefinição de senha%s." +msgstr "Sua senha foi redefinida. Se você acabou de criar uma conta, por favor use o link do e-mail de confirmação para definir uma senha inicial. Do contrário, por favor requisite uma chave de senha na página de %sRedefinição de senha%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Usuário ou senha inválida." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ocorreu um erro ao tentar gerar uma sessão de usuário." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinação entre email e chave de redefinição é inválida" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nenhum" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver informações da conta para %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "Faltando ID ou nome do pacote base." + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "Você não tem permissão para editar este comentário." + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "Comentário não existe." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "Comentário não pode estar vazio." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Comentário adicionado." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Erro ao obter detalhes do pacote." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Não foi possível encontrar os detalhes do pacote." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Você deve estar conectado para marcar os pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Você não selecionou nenhum pacote para marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "O pacote selecionado foi marcado como desatualizado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Você deve estar conectado para desmarcar os pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Você não selecionou nenhum pacote para desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "O pacote selecionado foi desmarcado." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Você não tem permissão para excluir pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Você selecionou nenhum pacote para excluir." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Os pacotes selecionados foram excluídos." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Você deve estar conectado para adotar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Você deve estar conectado para abandonar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Você não selecionou pacote para adotar." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Você não selecionou pacote para abandonar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Os pacotes selecionados foram adotados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Os pacotes selecionados foram abandonados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Você deve estar conectado para votar nos pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Você deve estar conectado para desfazer o voto dos pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Você não selecionou nenhum pacote para votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Seus votos foram removidos dos pacotes selecionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Seus votos foram enviados para os pacotes selecionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Não foi possível adicionar à lista de notificação." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Você foi adicionado à lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Você foi removido da lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Você tem que estar conectado para poder editar informações do pacote." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Faltando ID de comentário." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "O comentário foi excluído." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Você não tem permissão para excluir esse comentário." -msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"Você não tem permissão para editar as palavras-chaves deste pacote base." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "Comentário foi editado." +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Você não tem permissão para editar as palavras-chaves deste pacote base." + +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "As palavras-chave do pacote base foram atualizadas." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Você não tem permissão para gerenciar comantenedores deste pacote base." +msgstr "Você não tem permissão para gerenciar comantenedores deste pacote base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nome de usuário inválido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Os comantenedores do pacote base foram atualizados." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalhes de pacotes para" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "requer %s" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Você deve estar conectado para preencher requisições de pacotes." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nome inválido: apenas letras minúsculas são permitidas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "O campo de comentário não pode estar vazio" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de requisição inválida" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Requisição adicionada com sucesso" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Motivo inválido" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Apenas TUs e desenvolvedores podem fechar requisições" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Requisição fechada com sucesso" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Você pode usar esse formulário para excluir permanentemente a conta %s do " -"AUR." +msgstr "Você pode usar esse formulário para excluir permanentemente a conta %s do AUR." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sAVISO%s: Essa ação não pode ser desfeita." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar exclusão" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Usuário" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de conta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuário" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolvedor" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & Desenvolvedor" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Endereço de e-mail" +#: template/account_details.php +msgid "hidden" +msgstr "oculto" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Apelido no IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Impressão digital de chave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Inativo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Ativa" +#: template/account_details.php msgid "Last Login" msgstr "Último login" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Visualizar pacotes deste usuário" +#: template/account_details.php msgid "Edit this user's account" msgstr "Edite a conta desse usuário" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clique %saqui%s se você deseja excluir permanentemente esta conta." +#: template/account_edit_form.php msgid "required" msgstr "obrigatório" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuário normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Conta suspensa" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inativo" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "Por favor, certifique-se de que você informou seu endereço de e-mail, do contrário você perderá acesso." + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "Ocultar endereço de e-mail" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Re-digite a senha" +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"A informação a seguir é necessária apenas se você deseja enviar pacotes para " -"o Repositório de Usuário do Arch." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "A informação a seguir é necessária apenas se você deseja enviar pacotes para o Repositório de Usuário do Arch." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Chave pública de SSH" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Atualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Criar" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Limpar" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nenhum resultado correspondeu aos seus critérios de pesquisa." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar conta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspensa" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Mais" +#: template/account_search_results.php msgid "No more results to display." msgstr "Não há mais resultados para serem exibidos." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Gerenciar comantenedores: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Use este formulário para adicionar comantenedores para %s%s%s (um nome de " -"usuário por linha):" +msgstr "Use este formulário para adicionar comantenedores para %s%s%s (um nome de usuário por linha):" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuários" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Salvar" +#: template/header.php msgid "My Packages" msgstr "Meus pacotes" +#: template/header.php msgid " My Account" msgstr " Minha conta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ações do pacote" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Visualizar PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver alterações" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Baixar snapshot" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Pesquisar no wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marcado como desatualizado" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar como desatualizado" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar desatualização" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Remover voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar neste pacote" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Desabilitar notificações" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificar sobre novos comentários" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Gerenciar comantenedores" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requisição pentende" msgstr[1] "%d requisições pentendes" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Excluir pacote" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Mesclar pacote" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotar pacote" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconhecido" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalhes do pacote base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "somente leitura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palavras-chave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Criado por" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mantenedor" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último empacotador" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularidade" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Criado em" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última atualização" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "Editar comentário para: %s" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adicionar comentário" -msgid "Comment has been added." -msgstr "Comentário adicionado." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos os comentários" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos comentários" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "%s comentou em %s" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "Comentário anônimo em %s" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "excluído em %s por %s" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "última edição em %s por %s" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Excluir comentário" -#, php-format -msgid "Comment by %s" -msgstr "Comentário de %s" - -msgid "Anonymous comment" -msgstr "Comentário anônimo" - -msgid "deleted" -msgstr "excluída" - +#: template/pkg_comments.php msgid "All comments" msgstr "Todos os comentários" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do pacote" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacote base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrição" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visitar o site para" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenças" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitos" +#: template/pkg_details.php msgid "Provides" msgstr "Provê" +#: template/pkg_details.php msgid "Replaces" msgstr "Substitui" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependências" +#: template/pkg_details.php msgid "Required by" msgstr "Necessário para" +#: template/pkg_details.php msgid "Sources" msgstr "Fontes" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Fechar requisição: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Use esse formulário para fechar a requisição para o pacote base %s%s%s." +msgstr "Use esse formulário para fechar a requisição para o pacote base %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"O campo de comentários pode ser deixado vazio. Porém, é fortemente " -"recomendado adicionar um comentário ao rejeitar uma requisição." +msgstr "O campo de comentários pode ser deixado vazio. Porém, é fortemente recomendado adicionar um comentário ao rejeitar uma requisição." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motivo" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceito" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rejeitado" -msgid "Comments" -msgstr "Comentários" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Fazer requisição: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Use esse formulário para fazer uma requisição sobre o pacote base %s%s%s que " -"inclui os seguintes pacotes:" +msgstr "Use esse formulário para fazer uma requisição sobre o pacote base %s%s%s que inclui os seguintes pacotes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de requisição" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Excluir" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Tornar órfão" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Mesclar em" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d requisição de pacote encontrada." msgstr[1] "%d requisições de pacotes encontradas." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pacote" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Criada por" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dias restantes" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d hora restante" msgstr[1] "~%d horas restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 hora restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceitar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Travado" +#: template/pkgreq_results.php msgid "Close" msgstr "Fechar" +#: template/pkgreq_results.php msgid "Closed" msgstr "Fechada" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descrição" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Somente nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exato" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacote base exato" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcado" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Não marcado" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -msgid "Popularity" -msgstr "Popularidade" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" -msgid "Age" -msgstr "Antiguidade" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "Última modificação" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Crescente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Decrescente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Digite os critérios de pesquisa" +#: template/pkg_search_form.php msgid "Search by" msgstr "Pesquisar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desatualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordem de classificação" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Pesquisar" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Órfãos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erro ao obter a lista de pacotes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nenhum pacote correspondeu aos seus critérios de pesquisa." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versão" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"Popularidade é calculada como a soma de todos os votos, sendo cada voto " -"pesado com um fator de 0.98 por dia desde sua criação." +msgstr "Popularidade é calculada como a soma de todos os votos, sendo cada voto pesado com um fator de 0.98 por dia desde sua criação." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sim" +#: template/pkg_search_results.php msgid "orphan" msgstr "órfão" +#: template/pkg_search_results.php msgid "Actions" msgstr "Ações" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marcar como desatualizado" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar desatualizado" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adotar pacotes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar pacotes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Excluir pacotes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualquer tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Pesquisa" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estatísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacotes órfãos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacotes adicionados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacotes atualizados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacotes atualizados no último ano" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacotes nunca atualizados" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuários registrados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Atualizações recentes" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Minhas estatísticas" -msgid "Packages in unsupported" -msgstr "Pacotes no repositório sem suporte" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalhes da proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Essa votação ainda está aberta." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Enviado: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fim" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Não" +#: template/tu_details.php msgid "Abstain" msgstr "Abster" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participação" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Últimos votos por TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nenhum resultado encontrado." +#: template/tu_list.php msgid "Start" msgstr "Iniciar" +#: template/tu_list.php msgid "Back" msgstr "Voltar" diff --git a/po/pt_PT.po b/po/pt_PT.po index 0024e72c..627d88cc 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Gaspar Santos , 2011 # R00KIE , 2013 @@ -12,1353 +12,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" -"aur/language/pt_PT/)\n" -"Language: pt_PT\n" +"Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/aur/language/pt_PT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: pt_PT\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página Não Encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "As nossas desculpas, a página que pediu não existe." +#: html/503.php msgid "Service Unavailable" msgstr "Serviço não disponível" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Não entre em pânico! Esta página encontra-se em baixo devido a manutenção. " -"Voltaremos brevemente." +msgstr "Não entre em pânico! Esta página encontra-se em baixo devido a manutenção. Voltaremos brevemente." +#: html/account.php msgid "Account" msgstr "Conta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Contas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Não tem autorização para aceder a esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Não foi possível obter informações para o utilizador especificado." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Não tem autorização para editar esta conta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Necessita iniciar sessão para visualizar a informação do utilizador." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adicionar Proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Token inválido para acção de utilizador." +#: html/addvote.php msgid "Username does not exist." msgstr "O utilizador não existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s já tem uma proposta a decorrer." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo inválido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "A proposta não pode estar vazia." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta submetida." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Submeta uma proposta para votação." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vazio se não aplicável)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Adição de um TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remoção de um TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remoção de um TU (inatividade não declarada)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Alterações ao Estatutos" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Enviar" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gerir responsáveis" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Início" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bem-vindo ao AUR! Por favor leia as %sOrientações de Utilizador do AUR%s e " -"%sOrientações de TU do AUR%s para mais informações." +msgstr "Bem-vindo ao AUR! Por favor leia as %sOrientações de Utilizador do AUR%s e %sOrientações de TU do AUR%s para mais informações." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"As contribuições de PKGBUILDs %sdevem%s obedecer aos %sPadrões de " -"Empacotamento Arch%s ou serão eliminadas!" +msgstr "As contribuições de PKGBUILDs %sdevem%s obedecer aos %sPadrões de Empacotamento Arch%s ou serão eliminadas!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Lembre-se de votar nos seus pacotes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Alguns dos pacotes podem ser fornecidos como binários no repositório " -"[community]." +msgstr "Alguns dos pacotes podem ser fornecidos como binários no repositório [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVISO LEGAL" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Os pacotes não suportados são produzidos por utilizadores. O seu uso é por " -"sua conta e risco." +#: html/home.php msgid "Learn more..." msgstr "Saber mais..." +#: html/home.php msgid "Support" msgstr "Suporte" +#: html/home.php msgid "Package Requests" msgstr "Pedidos de Pacotes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Existem três tipos de pedidos que podem ser preenchidos na caixa " -"%sPackageActions%s na página de detalhes de um pacote." +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Existem três tipos de pedidos que podem ser preenchidos na caixa %sPackageActions%s na página de detalhes de um pacote." +#: html/home.php msgid "Orphan Request" msgstr "Pedido para Tornar Orfão" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Pedido para que um pacote dique sem dono, por exemplo, quando o atual " -"responsável se encontra inativo e o pacote foi marcado como desatualizado há " -"muito tempo." +msgstr "Pedido para que um pacote dique sem dono, por exemplo, quando o atual responsável se encontra inativo e o pacote foi marcado como desatualizado há muito tempo." +#: html/home.php msgid "Deletion Request" msgstr "Pedido para Apagar" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Pedido para que um pacote seja removido do Arch User Repository. Por favor " -"não use este pedido se um pacote está danificado e pode ser resolvido " -"facilmente. Contacte o responsável pelo mesmo e faça um Pedido para Tornar " -"Orfão se necessário." +msgstr "Pedido para que um pacote seja removido do Arch User Repository. Por favor não use este pedido se um pacote está danificado e pode ser resolvido facilmente. Contacte o responsável pelo mesmo e faça um Pedido para Tornar Orfão se necessário." +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Discussão" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Reportar um Bug" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Pesquisa de Pacotes" +#: html/index.php msgid "Adopt" msgstr "Adoptar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Retirar voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Não Notificar" -msgid "Flag" -msgstr "Marcar" - +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Iniciar sessão" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Sessão iniciada como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Terminar sessão" +#: html/login.php msgid "Enter login credentials" msgstr "Introduza as credenciais para login" -msgid "Username" -msgstr "Nome de utilizador" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Palavra-passe" +#: html/login.php msgid "Remember me" msgstr "Lembrar-se de mim" +#: html/login.php msgid "Forgot Password" msgstr "Esqueceu-se da palavra-passe" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Início de sessão em HTTP está desactivado. Por favor %smude para HTTPs%s se " -"pretende iniciar sessão." +msgstr "Início de sessão em HTTP está desactivado. Por favor %smude para HTTPs%s se pretende iniciar sessão." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critérios de Pesquisa" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacotes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erro ao tentar obter os detalhes do pacote." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Em falta um campo obrigatório." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Campos de palavra-passe não correspondem." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "A sua palavra-passe tem de ter pelo menos %s caracteres." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail inválido." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Reiniciar a Palavra-passe" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifique o seu e-mail para o link de confirmação." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "A palavra-passe foi reiniciada com êxito." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme o endereço de e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Introduza a nova palavra-passe:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme a nova palavra-passe:" +#: html/passreset.php msgid "Continue" msgstr "Continue" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Se se esqueceu do endereço de e-mail que utilizou para efectuar o registo, " -"por favor envie uma mensagem para a lista de discussão %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Se se esqueceu do endereço de e-mail que utilizou para efectuar o registo, por favor envie uma mensagem para a lista de discussão %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduza o endereço de e-mail:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Não é possível encontrar o pacote onde juntar os votos e os comentários." +msgstr "Não é possível encontrar o pacote onde juntar os votos e os comentários." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminar Pacote" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Eliminar Pacote: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Use este formulário para eliminar o pacote base %s%s%s e os seguintes " -"pacotes do AUR:" +msgstr "Use este formulário para eliminar o pacote base %s%s%s e os seguintes pacotes do AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "A eliminação de um pacote é permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Seleccione a caixa para confirmar a acção." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmar eliminação do pacote" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Eliminar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Apenas Utilizadores de Confiança e Programadores podem eliminar pacotes." +msgstr "Apenas Utilizadores de Confiança e Programadores podem eliminar pacotes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Renunciar Pacote" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "Renunciar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Comentários" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Marcar" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusão de Pacotes" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Fundir o pacote: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Use este formulário para fundir o pacote base %s%s%s num outro pacote." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Os pacotes listados serão eliminados:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Uma vez feita a fusão do pacote não há como reverter o processo." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduza o nome do pacote com o qual deseja realizar a fusão." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fundir com:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confimar fusão de pacote" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fundir" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Apenas Utilizadores de Confiança e Programadores podem fundir pacotes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Pedido de Ficheiro" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fechar Pedido" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seguinte" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo." +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Pedidos" +#: html/register.php template/header.php msgid "Register" msgstr "Registar" +#: html/register.php msgid "Use this form to create an account." msgstr "Para criar uma conta utilize este formulário." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Utilizador de Confiança" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Não foi possível obter detalhes da proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A votação está fechada para esta proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Apenas Utilizadores de Confiança podem votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Não pode votar numa proposta acerca de si." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Já votou nesta proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID de voto não é válido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos Actuais" +#: html/tu.php msgid "Past Votes" msgstr "Votos Passados" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O registo de contas encontra-se inibido para pedidos do seu IP, " -"provavelmente devido a continuados ataques de spam. Lamentamos o " -"inconveniente." +msgstr "O registo de contas encontra-se inibido para pedidos do seu IP, provavelmente devido a continuados ataques de spam. Lamentamos o inconveniente." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID de utilizador em falta" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "O nome de utilizador é inválido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Tem de ter entre %s e %s caracteres de comprimento" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Começar e acabar com uma letra ou um número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Apenas pode conter um ponto, underscore ou hífen." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Incapaz de aumentar as permissões da conta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Língua não suportada actualmente." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de utilizador, %s%s%s, já se encontra a ser utilizado." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "O endereço, %s%s%s, já está a ser utilizado." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erro ao tentar criar a conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A conta, %s%s%s, foi criada com sucesso." +#: lib/acctfuncs.inc.php +msgid "A password reset key has been sent to your e-mail address." +msgstr "Uma chave de reinicialização da sua palavra-passe foi enviada para o seu endereço de e-mail." + +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clique no link Login acima para iniciar sessão." -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Bem vindo ao %s! Por favor clique no link abaixo para definir a palavra-" -"passe para a sua nova conta. Se o link não funcionar experimente copia-lo e " -"cola-lo no seu navegador web." - -msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Uma chave de reinicialização da sua palavra-passe foi enviada para o seu " -"endereço de e-mail." - +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nenhuma alterações foi realizada à conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A conta, %s%s%s, foi modificada com sucesso." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O formulário de início de sessão encontra-se inibido para pedidos do seu IP, " -"provavelmente devido a continuados ataques de spam. Lamentamos o " -"inconveniente." +msgstr "O formulário de início de sessão encontra-se inibido para pedidos do seu IP, provavelmente devido a continuados ataques de spam. Lamentamos o inconveniente." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Conta Suspensa" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"A sua palavra passe foi reiniciada. Se criou uma nova conta agora, por favor " -"siga a ligação do email de confirmação para definir uma palavra passe. Caso " -"contrário, por favor peça um reinicio à chave na pagina %sReiniciar Password" -"%s." +msgstr "A sua palavra passe foi reiniciada. Se criou uma nova conta agora, por favor siga a ligação do email de confirmação para definir uma palavra passe. Caso contrário, por favor peça um reinicio à chave na pagina %sReiniciar Password%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Mau nome de utilizador ou palavra-passe." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ocorreu um erro ao tentar gerar uma sessão de utilizador." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinação de e-mail e chave de recuperação inválidos." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nenhum" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver informação de conta de %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "O comentário foi adicionado." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Erro ao obter os detalhes do pacote." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Não foi possivel encontrar detalhes acerca do pacote." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Tem de iniciar sessão antes de poder marcar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Não seleccionou nenhum pacote a marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Os pacotes seleccionados foram marcados como desactualizados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Tem de iniciar sessão antes de poder desmarcar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Não seleccionou nenhum pacote a desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Os pacotes seleccionados foram desmarcados." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Não tem permissão para eliminar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Não seleccionou nenhum pacote a apagar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Os pacotes seleccionados foram apagados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Tem de iniciar se sessão antes de poder adoptar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Tem de iniciar se sessão antes de poder renunciar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Não seleccionou nenhum pacote a adoptar." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Não seleccionou nenhum pacote a renunciar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Os pacotes seleccionados foram adoptados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Os pacotes seleccionados foram renunciados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Tem de iniciar sessão antes de poder votar em pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Tem de ter sessão iniciada antes de poder retirar votos dos pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Não seleccionou nenhuns pacotes nos quais votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Os seus votos foram retirados dos pacotes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Os seus votos foram lançados para os pacotes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Não foi possível adicionar à lista de notificações." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Foi adicionado à lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Foi removido da lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Tem de ter sessão iniciada antes de poder as informações de um pacote." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "ID de comentário em falta." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "O comentário foi apagado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Não tem permissão para apagar este comentário." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalhes do pacote de" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nome inválido: apenas são permitidas letras minúsculas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "O campo \"comentários\" não pode ficar vazio." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de pedido inválido." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Pedido adicionado com sucesso." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razão inválida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Apenas programadores e TUs podem fechar pedidos." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Pedido fechado com sucesso." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nome de utilizador" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de conta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilizador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolvedor" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Endereço de E-mail" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Impressão digital da chave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estado" +#: template/account_details.php msgid "Inactive since" msgstr "Inativo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" +#: template/account_details.php msgid "Last Login" msgstr "Última sessão" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Ver os pacotes deste utilizador" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editar a conta deste utilizador" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "necessário" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilizador normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Utilizador de confiança" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Conta Suspensa" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inativo" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Reintroduza a palavra-passe" +#: template/account_edit_form.php msgid "Language" msgstr "Língua" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Criar" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reiniciar" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Não existem resultados que correspondam aos seus critérios de procura." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar Conta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspenso" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Mais" +#: template/account_search_results.php msgid "No more results to display." msgstr "Não existem mais resultados para mostrar." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Os meus pacotes" +#: template/header.php msgid " My Account" msgstr "A minha Conta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ações sobre Pacotes" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Pesquisar na Wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marcado como desatualizado." +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar como desatualizado" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar pacote" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Remover voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar neste pacote" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Desativar notificações" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificar-me sobre novos comentários" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d pedido por atender" msgstr[1] "%d pedidos por atender" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Eliminar Pacote" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Fundir Pacote" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotar Pacote" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconhecido" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Pacote Base Detalhes" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palavras-chave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Submissor" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Responsável pela manutenção" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último Responsável" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Primeira Submissão" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última Actualização" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adicionar comentário" -msgid "Comment has been added." -msgstr "O comentário foi adicionado." - +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos Comentários" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Pagar comentário" -#, php-format -msgid "Comment by %s" -msgstr "Comentador por %s" - -msgid "Anonymous comment" -msgstr "Comentário anónimo" - -msgid "deleted" -msgstr "" - +#: template/pkg_comments.php msgid "All comments" msgstr "Todos os comentários" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do Pacote" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacote Base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrição" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL a montante" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visitar a página web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenças" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitos" +#: template/pkg_details.php msgid "Provides" msgstr "Fornece" +#: template/pkg_details.php msgid "Replaces" msgstr "Substitui" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependências" +#: template/pkg_details.php msgid "Required by" msgstr "Exigido por" +#: template/pkg_details.php msgid "Sources" msgstr "Fontes" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "Note" msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceite" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rejeitado" -msgid "Comments" -msgstr "Comentários" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Pedido de Ficheiro: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Use este formulário para enviar um pedido sobre o pacote base %s%s%s que " -"inclui os seguintes pacotes:" +msgstr "Use este formulário para enviar um pedido sobre o pacote base %s%s%s que inclui os seguintes pacotes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de pedido" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Apagar" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfão" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Juntar em" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d pedido de pacote encontrado." msgstr[1] "%d pedidos de pacotes encontrados." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pacote" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Enviado por" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceitar" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "Fechar" +#: template/pkgreq_results.php msgid "Closed" msgstr "Fechado" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, Descrição" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Só Nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exacto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacote Base Exacto" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Não marcados" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votou" -msgid "Age" -msgstr "Idade" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzir critério de pesquisa" +#: template/pkg_search_form.php msgid "Search by" msgstr "Procurar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordem de ordenação" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Órfãos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erro ao obter lista de pacotes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nenhum pacote corresponde aos critérios de procura." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versão" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sim" +#: template/pkg_search_results.php msgid "orphan" msgstr "Órfão" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acções" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marcar como desactualizado." +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar como Desactualizado" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar Pacotes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Renunciar Pacotes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Apagar Pacotes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualquer tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Procurar" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estatísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacotes Órfãos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacotes adicionados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacotes actualizados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacotes actualizados no último ano" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacotes nunca actualizados" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilizadores Registados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Utilizadores de Confiança" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizações recentes" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Minhas Estatísticas" -msgid "Packages in unsupported" -msgstr "Pacotes em não suportado" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalhes da Proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Este votação ainda está a decorrer." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Submetido: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fim" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Não" +#: template/tu_details.php msgid "Abstain" msgstr "Abster-se" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participação" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Últimos votos de TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Não foram encontrados resultados." +#: template/tu_list.php msgid "Start" msgstr "Inicio" +#: template/tu_list.php msgid "Back" msgstr "Anterior" diff --git a/po/ro.po b/po/ro.po index f4f93d6b..4ff7db4e 100644 --- a/po/ro.po +++ b/po/ro.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Arthur Țițeică , 2013-2015 # Lukas Fleischer , 2011 @@ -10,945 +10,1268 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" -"ro/)\n" -"Language: ro\n" +"Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?" -"2:1));\n" +"Language: ro\n" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" +#: html/404.php msgid "Page Not Found" msgstr "Pagina nu a fost găsită" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Din păcate, pagina solicitată nu există." +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "Cont" +#: html/account.php template/header.php msgid "Accounts" msgstr "Conturi" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nu îți este permis accesul la această secțiune." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nu s-au putut prelua informații despre utilizatorul specificat." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nu ai permisiune pentru a modifica acest cont." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Folosește acest formular pentru a căuta conturi existente." +#: html/account.php msgid "You must log in to view user information." -msgstr "" -"Trebuie să fi autentificat pentru a putea vedea informații despre " -"utilizatori." +msgstr "Trebuie să fi autentificat pentru a putea vedea informații despre utilizatori." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adaugă o propunere" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Jeton nevalid pentru acțiunea utilizatorului." +#: html/addvote.php msgid "Username does not exist." msgstr "Nume de utilizator inexistent." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Pentru %s exista o propunere în desfășurare." +#: html/addvote.php msgid "Invalid type." msgstr "Tip nevalid." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Propunerea nu poate fi goală." +#: html/addvote.php msgid "New proposal submitted." msgstr "Propunerea nouă a fost trimisă." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Trimite o propunere pentru a putea fi votată." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidat/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(gol dacă nu este cazul)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tip" +#: html/addvote.php msgid "Addition of a TU" msgstr "Adăugarea unui TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Înlăturarea unui TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Înlăturarea unui TU (inactivitate nedeclarată)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendamentul Statutului" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propunere" +#: html/addvote.php msgid "Submit" msgstr "Trimite" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Acasă" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bine ai venit la AUR! Te rog citește %sGhidul utilizatorului AUR%s și " -"%sGhidul AUR TU%s pentru mai multe informații." +msgstr "Bine ai venit la AUR! Te rog citește %sGhidul utilizatorului AUR%s și %sGhidul AUR TU%s pentru mai multe informații." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"PKGBUILDurile contribuite %strebuie%s să fie conforme cu %sStandardele de " -"Împachetare Arch%s, altfel vor fi șterse!" +msgstr "PKGBUILDurile contribuite %strebuie%s să fie conforme cu %sStandardele de Împachetare Arch%s, altfel vor fi șterse!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nu uita să votezi pentru pachetele tale favorite!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Unele pachete pot fi furnizate ca binare în [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "DECLARAȚIE DE NEASUMARE A RESPONSABILITĂȚII" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Pachetele fără suport sunt conținut produs de utilizatori. Orice folosire a " -"fișierelor oferite este pe risc propriu!" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Discuție" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Semnalare buguri" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Căutare pachete" +#: html/index.php msgid "Adopt" msgstr "Adoptă" +#: html/index.php msgid "Vote" msgstr "Vot" +#: html/index.php msgid "UnVote" msgstr "EliminăVot" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificare" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "DeNotificare" -msgid "Flag" -msgstr "Marchează" - +#: html/index.php msgid "UnFlag" msgstr "Elimină marcaj" +#: html/login.php template/header.php msgid "Login" msgstr "Autentificare" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificat ca: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "De-autentificare" +#: html/login.php msgid "Enter login credentials" msgstr "Introdu datele de autentificare" -msgid "Username" -msgstr "Nume utilizator" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Parolă" +#: html/login.php msgid "Remember me" msgstr "Ține-mă minte" +#: html/login.php msgid "Forgot Password" msgstr "Parolă uitată" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Autentificarea prin HTTP este dezactivată. %sSchimbă pe HTTPS%s dacă vrei să " -"te autentifici." +msgstr "Autentificarea prin HTTP este dezactivată. %sSchimbă pe HTTPS%s dacă vrei să te autentifici." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteriul de căutare" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pachete" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Eroare la încercarea de a prelua detaliile pachetului." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Lipsește un câmp necesar." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Câmpurile parolei nu sunt potrivesc." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Parola trebuie să fie de cel puțin %s caractere." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail nevalid" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Resetare parolă" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifică e-mailul pentru legătura de confirmare." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Parola ta a fost restabilită cu succes." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirmă adresa de e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Introdu noua parolă:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirmă noua parolă." +#: html/passreset.php msgid "Continue" msgstr "Continuă" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Dacă ai uitat adresa de email folosită la înregistrare, trimite un mesaj la " -"lista de discuții %saur-general%s" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Dacă ai uitat adresa de email folosită la înregistrare, trimite un mesaj la lista de discuții %saur-general%s" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introdu adresa ta de e-mail:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Nu s-a putut găsi pachet pentru fuzionare voturi și comentarii." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nu se poate fuziona un pachet cu el însuși." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Pachetele selectate nu au fost șterse; verifică căsuța de bifare." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Ștergere pachet" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Șterge pachetul: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Folosește acest formular pentru a șterge pachetul de bază %s%s%s și " -"următoarele pachete din AUR: " +msgstr "Folosește acest formular pentru a șterge pachetul de bază %s%s%s și următoarele pachete din AUR: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Ștergerea unui pachet este permanentă." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Bifează căsuța pentru a confirma acțiunea." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmă ștergerea pachetului" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Șterge" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Numai Dezvoltatorii și Trusted Users pot șterge pachete." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonează pachet" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonează" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Comentarii" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Marchează" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fuzionare pachet" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Fuzionează pachetul: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Folosește acest formular pentru a îmbina pachetul de bază %s%s%s cu alt " -"pachet." +msgstr "Folosește acest formular pentru a îmbina pachetul de bază %s%s%s cu alt pachet." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Următoarele pachete vor fi șterse:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Odată ce pachetul a fuzionat, acțiunea nu este reversibilă." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introdu numele pachetului cu care vrei să fie fuzionat acest pachet." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fuzionează cu:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmă fuzionarea pachetului" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fuzionare" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Numai Dezvoltatorii și Trusted Users pot fuziona pachete." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Depune cerere" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Închide cererea" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prim" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedent" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Înainte" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultim" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Cereri" +#: html/register.php template/header.php msgid "Register" msgstr "Înregistrare" +#: html/register.php msgid "Use this form to create an account." msgstr "Folosește acest formular pentru a crea un cont." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nu am putut prelua detaliile propunerii." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Votarea este închisă pentru această propunere." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Doar Trusted Users au permisiunea să voteze." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nu poți vota într-o propunere despre tine." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ai votat deja pentru această propunere." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID-ul votului nu este valid." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Voturi curente" +#: html/tu.php msgid "Past Votes" msgstr "Voturi precedente" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votanți" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Înregistrarea de conturi noi a fost dezactivată pentru adresa ta IP, " -"probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru " -"inconveniență." +msgstr "Înregistrarea de conturi noi a fost dezactivată pentru adresa ta IP, probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID-ul utilizatorului lipsește" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Numele de utilizator nu este valid." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Trebuie să fie între %s și %s caractere lungime" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Începe și sfârșește cu o literă sau un număr." +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Poate conține doar o virgulă, linie joasă sau cratimă." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adresa de email nu este validă." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Amprenta cheii PGP este nevalidă." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Permisiunile contului nu pot fi ridicate." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Limba nu este încă suportată." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Numele de utilizator %s%s%s este deja folosit." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s este deja folosită." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Eroare la încercarea de a crea contul, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Contul %s%s%s a fost creat cu succes." -msgid "Click on the Login link above to use your account." -msgstr "Clic pe legătura către Autentificare pentru a-ți folosi contul." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Bun venit la %s! Pentru a seta o parolă inițială pentru cont, apasă pe " -"legătura de jos. Dacă nu funcționează, încearcă să copiezi adresa și să o " -"lipești în bara de adrese a navigatorului." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "O cheie de resetare a parolei a fost trimisă la adresa ta de e-mail." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Clic pe legătura către Autentificare pentru a-ți folosi contul." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nu a fost efectuată nicio modificare asupra contului, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Contul %s%s%s a fost modificat cu succes." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Formularul de autentificare a fost dezactivat pentru adresa ta IP, probabil " -"datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +msgstr "Formularul de autentificare a fost dezactivat pentru adresa ta IP, probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cont suspendat" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Parola ta a fost resetată. Dacă tocmai ai creat un cont nou, folosește " -"legătura din e-mailul de confirmare pentru a seta o parolă inițială. Altfel, " -"cere o resetare a parolei din pagina %sResetare parolă%s." +msgstr "Parola ta a fost resetată. Dacă tocmai ai creat un cont nou, folosește legătura din e-mailul de confirmare pentru a seta o parolă inițială. Altfel, cere o resetare a parolei din pagina %sResetare parolă%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nume de utilizator sau parolă greșite." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "A apărut o eroare în timp ce se genera sesiunea de utilizator." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinație e-mail și cheie pentru resetare nevalidă." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nimic" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Vezi informații despre contul lui %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Comentariul a fost adăugat." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Eroare la preluarea detaliilor pachetului." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Detaliile pachetului nu pot fi găsite." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Trebuie să fi autentificat înainte de a putea marca pachetele." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nu ai selectat niciun pachet pentru a fi marcat" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Pachetele selectate au fost marcate ca fiind Neactualizate." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Trebuie să fi autentificat înainte de a putea elimina marcajul de " -"Neactualizat al pachetelor." +msgstr "Trebuie să fi autentificat înainte de a putea elimina marcajul de Neactualizat al pachetelor." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nu ai selectat niciun pachet pentru a-i fi eliminat marcajul." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "La pachetele selectate a fost eliminat marcajul de Neactualizat." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nu ai permisiune pentru a șterge pachete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nu ai selectat niciun pachet pentru a fi șters." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Pachetele selectate au fost șterse." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Trebuie să fi autentificat înainte de a putea adopta pachete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Trebuie să te autentifici înainte de a abandona pachete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nu ai selectat niciun pachet pentru a-l adopta." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nu ai selectat niciun pachet pentru a-l abandona." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Pachetele selectate au fost adoptate." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Pachetele selectate au fost abandonate." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Trebuie să fi autentificat înainte de a putea vota pentru pachete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "" -"Trebuie să fi autentificat înainte de a putea șterge voturile pachetelor." +msgstr "Trebuie să fi autentificat înainte de a putea șterge voturile pachetelor." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nu ai selectat niciun pachet pentru a vota." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Voturile tale au fost șterse de la pachetele selectate." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Voturile au fost exprimate pentru pachetele selectate." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nu am putut adăuga la lista de notificări." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Ai fost adăugat în lista de notificare a comentariilor pentru %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "" -"Ai fost șters din lista de notificare pentru comentarii pentru pachetul %s." +msgstr "Ai fost șters din lista de notificare pentru comentarii pentru pachetul %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Trebuie să fi autentificat înainte de a putea modifica informațiile " -"pachetului." +msgstr "Trebuie să fi autentificat înainte de a putea modifica informațiile pachetului." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "ID-ul comentariului lipsește" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Comentariul a fost șters." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nu ai voie să ștergi acest comentariu." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vezi detaliile pachetelor pentru" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Trebuie să fi autentificat pentru a înregistra cereri pentru pachet." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Numele nu este valid: doar litere mici sunt permise." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Câmpul pentru comentariu nu trebuie lăsat necompletat." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tip de cerere nevalidă." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Cererea a fost adăugată cu succes." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Motiv nevalid." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Doar TU și dezvoltatorii pot închide cererile." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Cerere închisă cu succes." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Poți folosi acest formular pentru a șterge permanent contul AUR %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWARNING%s: Acestă acțiune nu poate fi anulată." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmă ștergerea" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Nume utilizator" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip cont" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilizator" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Dezvoltator" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Utilizator de încredere (TU) & Dezvoltator" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresă email" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nume real" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Pseudonim IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Amprentă cheie PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stare" +#: template/account_details.php msgid "Inactive since" msgstr "Inactiv din" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activ" +#: template/account_details.php msgid "Last Login" msgstr "Ultima autentificare" +#: template/account_details.php msgid "Never" msgstr "Niciodată" +#: template/account_details.php msgid "View this user's packages" msgstr "Vezi pachetele acestui utilizator" +#: template/account_details.php msgid "Edit this user's account" msgstr "Modifică contul acestui utilizator" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clic %saici%s dacă dorești să ștergi definitiv acest cont." +#: template/account_edit_form.php msgid "required" msgstr "cerut" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilizator obișnuit" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cont suspendat" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactiv" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Rescrie parola" +#: template/account_edit_form.php msgid "Language" msgstr "Limbă" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizare" +#: template/account_edit_form.php msgid "Create" msgstr "Creează" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetează" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nici un rezultat nu s-a încadrat în criteriile de căutare." +#: template/account_search_results.php msgid "Edit Account" msgstr "Modificare cont" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendat" +#: template/account_search_results.php msgid "Edit" msgstr "Modifică" +#: template/account_search_results.php msgid "Less" msgstr "Mai puțin" +#: template/account_search_results.php msgid "More" msgstr "Mai mult" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nu mai sunt rezultate de afișat." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "Pachetele mele" +#: template/header.php msgid " My Account" msgstr "Contul meu" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Operațiuni" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Examinează PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Caută în wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Marcat ca Neactualizat" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marchează pachetul ca Neactualizat" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Elimină marcaj pachet" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Elimină vot" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votează acest pachet" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Dezactivează notificări" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notifică pentru comentarii noi" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -956,171 +1279,232 @@ msgstr[0] "%d cerere în așteptare" msgstr[1] "%d cereri în așteptare" msgstr[2] "%d de cereri în așteptare" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Șterge pachet" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Fuzionează pachet" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptă pachet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "necunoscut" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalii pachet de bază" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Cuvinte cheie" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Autor" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Responsabil" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ultimul autor de pachet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Voturi" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prima trimitere" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ultima actualizare" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adaugă comentariu" -msgid "Comment has been added." -msgstr "Comentariul a fost adăugat." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Vizualizează toate comentariile" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Ultimele comentarii" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Șterge comentariu" -#, php-format -msgid "Comment by %s" -msgstr "Comentariu de %s" - -msgid "Anonymous comment" -msgstr "Comentariu anonim" - -msgid "deleted" -msgstr "șters" - +#: template/pkg_comments.php msgid "All comments" msgstr "Toate comentariile" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalii pachet" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pachet de bază" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descriere" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL upstream" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Vizitează pagina web pentru" +#: template/pkg_details.php msgid "Licenses" msgstr "Licențe" +#: template/pkg_details.php msgid "Groups" msgstr "Grupuri" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflicte" +#: template/pkg_details.php msgid "Provides" msgstr "Furnizează" +#: template/pkg_details.php msgid "Replaces" msgstr "Înlocuiește" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependențe" +#: template/pkg_details.php msgid "Required by" msgstr "Cerut de" +#: template/pkg_details.php msgid "Sources" msgstr "Surse" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Închide cererea: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Folosește acest formular pentru a închide cererea pentru pachetul de bază %s" -"%s%s." +msgstr "Folosește acest formular pentru a închide cererea pentru pachetul de bază %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Notă" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Câmpul pentru comentarii poate fi lăsat necompletat. Este totuși foarte " -"recomandat să adaugi un comentariu când respingi o cerere." +msgstr "Câmpul pentru comentarii poate fi lăsat necompletat. Este totuși foarte recomandat să adaugi un comentariu când respingi o cerere." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motiv" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Acceptat" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Respins" -msgid "Comments" -msgstr "Comentarii" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Înregistrează cerere: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Folosește acest formular pentru a înregistra o cerere pentru pachetul de " -"bază %s%s%s care cuprinde următoarele pachete:" +msgstr "Folosește acest formular pentru a înregistra o cerere pentru pachetul de bază %s%s%s care cuprinde următoarele pachete:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipul de cerere" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Ștergere" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfan" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fuzionează" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1128,23 +1512,29 @@ msgstr[0] "%d cerere pentru pachet găsită" msgstr[1] "%d cereri pentru pachet găsite" msgstr[2] "%d de cereri pentru pachet găsite" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d din %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pachet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Depusă de" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d zile rămase" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1152,90 +1542,116 @@ msgstr[0] "~%d oră rămasă" msgstr[1] "~%d ore rămase" msgstr[2] "~%d de ore rămase" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 oră a rămas" +#: template/pkgreq_results.php msgid "Accept" msgstr "Acceptă" +#: template/pkgreq_results.php msgid "Locked" msgstr "Blocat" +#: template/pkgreq_results.php msgid "Close" msgstr "Închide" +#: template/pkgreq_results.php msgid "Closed" msgstr "Închis" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nume, Descriere" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Doar nume" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nume exact" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pachet de bază exact" +#: template/pkg_search_form.php msgid "All" msgstr "Toate" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcate" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nemarcate" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nume" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votat" -msgid "Age" -msgstr "Vârstă" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Crescător" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descrescător" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introdu criteriul de căutare" +#: template/pkg_search_form.php msgid "Search by" msgstr "Caută după" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Neactualizate" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortează după" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordinea sortării" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagină" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Înainte" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfane" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Eroare la preluarea listei de pachete." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Niciun pachet nu s-a potrivit criteriului de căutare." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1243,119 +1659,154 @@ msgstr[0] "%d pachet găsit" msgstr[1] "%d pachete găsite" msgstr[2] "%d de pachete găsite" +#: template/pkg_search_results.php msgid "Version" msgstr "Versiune" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Da" +#: template/pkg_search_results.php msgid "orphan" msgstr "orfan" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acțiuni" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Marchează ca Neactualizat" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Elimină marcajul de Neactualizat" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptă pachete" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonează pachete" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Șterge pachete" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmare" +#: template/search_accounts_form.php msgid "Any type" msgstr "Orice tip" +#: template/search_accounts_form.php msgid "Search" msgstr "Caută" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistici" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pachete orfane" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pachete adăugate în ultimele 7 zile" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pachete actualizate în ultimele 7 zile" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pachete actualizate în ultimul an" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pachete niciodată actualizate" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilizatori înregistrați" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted users" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizări recente" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Statisticile mele" -msgid "Packages in unsupported" -msgstr "Pachete în depozitul fără suport" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaliile propunerii." +#: template/tu_details.php msgid "This vote is still running." msgstr "Această votare este încă în desfășurare." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Trimis: %s de %s " +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Sfârșit" +#: template/tu_details.php msgid "Result" msgstr "Rezultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nu" +#: template/tu_details.php msgid "Abstain" msgstr "Abținere" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participare" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ultimele voturi de la un TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ultimul vot" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Niciun rezultat găsit" +#: template/tu_list.php msgid "Start" msgstr "Start" +#: template/tu_list.php msgid "Back" msgstr "Înapoi" diff --git a/po/ru.po b/po/ru.po index 4341702c..061f2ab8 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,9 +1,9 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: -# Evgeniy Alekseev , 2014 +# Evgeniy Alekseev , 2014-2015 # Kyrylo Silin , 2011 # Kyrylo Silin , 2011 # Lukas Fleischer , 2011 @@ -13,942 +13,1268 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" -"ru/)\n" -"Language: ru\n" +"Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" -"%100>=11 && n%100<=14)? 2 : 3);\n" +"Language: ru\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" +#: html/404.php msgid "Page Not Found" msgstr "Страница не найдена" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Извините, запрошенная страница не существует." +#: html/503.php msgid "Service Unavailable" -msgstr "" +msgstr "Сервис недоступен" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "Не паниковать! Сайт недоступен из-за работ. Скоро мы вернемся назад." +#: html/account.php msgid "Account" -msgstr "" +msgstr "Аккаунт" +#: html/account.php template/header.php msgid "Accounts" msgstr "Учетные записи" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "У вас нет доступа сюда." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Не удалось получить информацию об указанном пользователе." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Вы не имеете права редактировать эту учетную запись." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Используйте эту форму для поиска существующих учетных записей." +#: html/account.php msgid "You must log in to view user information." -msgstr "" -"Вы должны представиться для того, чтобы посмотреть информацию о пользователе." +msgstr "Вы должны представиться для того, чтобы посмотреть информацию о пользователе." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Добавить предложение" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Неверная метка для действия пользователя." +#: html/addvote.php msgid "Username does not exist." msgstr "Имя пользователя не существует." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "За %s уже идет голосование." +#: html/addvote.php msgid "Invalid type." msgstr "Неправильный тип" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Предложение не может быть пустым." +#: html/addvote.php msgid "New proposal submitted." msgstr "Новое предложение принято." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Отправить предложение." +#: html/addvote.php msgid "Applicant/TU" msgstr "Кандидат/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(пусто если не нужно)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Тип" +#: html/addvote.php msgid "Addition of a TU" msgstr "Добавление TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Удаление TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Удаление TU (неактивность без уведомлений)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Внесение изменений в Устав" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Предложение" +#: html/addvote.php msgid "Submit" msgstr "Прислать" +#: html/comaintainers.php msgid "Manage Co-maintainers" +msgstr "Управление ответственными" + +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Главная" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Добро пожаловать в AUR! Пожалуйста, ознакомьтесь с %sРуководством " -"пользователя AUR%s и с %sРуководством доверенного пользователя AUR%s, чтобы " -"узнать больше." +msgstr "Добро пожаловать в AUR! Пожалуйста, ознакомьтесь с %sРуководством пользователя AUR%s и с %sРуководством доверенного пользователя AUR%s, чтобы узнать больше." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Присланные пэкиджбилды (англ. PKGBUILD) %sдолжны%s соответствовать " -"%sстандартам создания пакетов для Арча%s, иначе они будут удалены!" +msgstr "Присланные пэкиджбилды (англ. PKGBUILD) %sдолжны%s соответствовать %sстандартам создания пакетов для Арча%s, иначе они будут удалены!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Не забывайте голосовать за понравившиеся вам пакеты!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"В хранилище [community] некоторые пакеты могут быть представлены в бинарном " -"виде." +msgstr "В хранилище [community] некоторые пакеты могут быть представлены в бинарном виде." +#: html/home.php msgid "DISCLAIMER" msgstr "Отказ от ответственности" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Неподдерживаемые пакеты — это пакеты, созданные пользователями. Любой способ " -"их использования осуществляется на ваш страх и риск." +#: html/home.php msgid "Learn more..." -msgstr "" +msgstr "Больше..." +#: html/home.php msgid "Support" -msgstr "" +msgstr "Поддержка" +#: html/home.php msgid "Package Requests" -msgstr "" +msgstr "Запросы по пакету" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Три типа запросов могут быть посланы с использованием %sДействия над пакетом%s на странице пакета:" +#: html/home.php msgid "Orphan Request" -msgstr "" +msgstr "Запрос на сброс сопровождающего" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" +msgstr "Запросить, чтобы пакет быть лишен сопровождающего, например, если текущий сопровождающий неактивен и пакет давно помечен, как устаревший." +#: html/home.php msgid "Deletion Request" -msgstr "" +msgstr "Запрос на удаление" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" +msgstr "Запросить удаление пакета из AUR. Пожалуйста, не используйте это действие, если пакет не собирается и это может быть легко исправлено. Вместо этого, свяжитесь с сопровождающим и отправьте запрос на смену сопровождающего, если необходимо." +#: html/home.php msgid "Merge Request" -msgstr "" +msgstr "Запрос объединения" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" +msgstr "Запросить объединение пакета с другим. Может быть использовано, когда пакет необходимо переименовать или заменить другим." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" +msgstr "Если вы хотите обсудить запрос, вы можете использовать список рассылки %saur-requests%s. Однако, пожалуйста, не используйте список рассылки для отправки запросов." +#: html/home.php msgid "Submitting Packages" -msgstr "" +msgstr "Загрузка пакетов" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" +msgstr "На текущий момент для загрузки пакетов в AUR используется Git через SSH. Смотри %sЗагрузка пакетов%s в ArchWiki для более подробной информации." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "Следующие отпечатки ключей используются AUR:" +#: html/home.php msgid "Discussion" msgstr "Обсуждение" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" +msgstr "Общее обсуждение Пользовательского Репозитория ArchLinux (AUR) и структуры Доверенных Пользователей ведется в %saur-general%s. Для обсуждение разработки веб-интерфейса AUR используйте %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Отчет об ошибке" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Поиск пакетов" +#: html/index.php msgid "Adopt" msgstr "Усыновить" +#: html/index.php msgid "Vote" msgstr "Голосовать" +#: html/index.php msgid "UnVote" msgstr "Убрать голос" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Извещать" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Не извещать" -msgid "Flag" -msgstr "Пометить" - +#: html/index.php msgid "UnFlag" msgstr "Снять метку" +#: html/login.php template/header.php msgid "Login" msgstr "Войти" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Вы вошли как: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Выход" +#: html/login.php msgid "Enter login credentials" msgstr "Введите учётные данные" -msgid "Username" -msgstr "Имя пользователя" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Пароль" +#: html/login.php msgid "Remember me" msgstr "Запомнить меня" +#: html/login.php msgid "Forgot Password" msgstr "Забыли пароль?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Вход через HTTP отключен. Пожалуйста, %sпереключитесь на HTTPs%s, чтобы " -"войти." +msgstr "Вход через HTTP отключен. Пожалуйста, %sпереключитесь на HTTPs%s, чтобы войти." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Критерии поиска" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Пакеты" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Ошибка получения информации о пакете." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Отсутствует обязательное значение." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Пароли не совпадают." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Пароль должен быть не менее %s символов." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Неверная электронная почта." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "Сброс пароля" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Проверьте свою электронную почту на наличие ссылки подтверждения." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Ваш пароль был успешно переустановлен." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Подтвердите адрес своей электронной почты:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Введите ваш новый пароль:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Подтвердите ваш новый пароль:" +#: html/passreset.php msgid "Continue" msgstr "Продолжить" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Если вы забыли электронный адрес, который вы использовали для регистрации, " -"пожалуйста, отошлите сообщение в список рассылки %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Если вы забыли электронный адрес, который вы использовали для регистрации, пожалуйста, отошлите сообщение в список рассылки %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Введите свой адрес электронной почты:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" +msgstr "Выбранные пакеты будут брошены." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Не могу найти пакет для объединения с ним голосов и комментариев." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Невозможно объединить группу пакетов с самой собой." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Выбранные пакеты не были удалены. Поставьте галочку для подтверждения." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Удаление пакета" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Удалить пакет: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "Используйте эту форму, чтобы удалить группу пакетов %s%s%s из AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Удаление пакета необратимо." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Активируйте чекбокс для подтверждения действия." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Подтвердите удаление пакета" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Удалить" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Только Доверенные Пользователи и Разработчики могут удалять пакеты." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Бросить пакет" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" -msgstr "" +msgstr "Бросить пакет: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Используйте данную форму, чтобы бросить группу пакетов %s%s%s, которая включает в себя следующие пакеты:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" +msgstr "Ставя галочку, вы подтверждаете, что хотите бросить пакеты и сделать сопровождающим %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" +msgstr "Ставя галочку, вы подтверждаете, что хотите бросить пакет." +#: html/pkgdisown.php msgid "Confirm to disown the package" -msgstr "" +msgstr "Подтвердите отказ от пакета" +#: html/pkgdisown.php msgid "Disown" msgstr "Бросить" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." +msgstr "Только Доверенные Пользователи или разработчики могут бросить пакеты." + +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Комментарии" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Пометить" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Объединение пакетов" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Объединить пакет: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Используйте эту форму, чтобы объединить группу пакетов %s%s%s с другим " -"пакетом." +msgstr "Используйте эту форму, чтобы объединить группу пакетов %s%s%s с другим пакетом." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Следующие пакеты будут удалены:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Объединение пакетов — необратимое действие." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Введите имя пакета, с которым вы хотите объединить этот пакет." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Объединить с:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Подтвердить объединение пакетов" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Объединить" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Только Доверенные Пользователи и Разработчики могут объединять пакеты." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Запрос действия" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Закрыть запрос" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Первый" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Назад" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далее" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Последний" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Запросы" +#: html/register.php template/header.php msgid "Register" msgstr "Регистрация" +#: html/register.php msgid "Use this form to create an account." msgstr "Используйте эту форму для создания учетной записи." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Доверенный пользователь" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Не получилось показать предложение." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Голосование закрыто." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Только Доверенные Пользователи имеют право голоса." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Нельзя голосовать за себя." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Вы уже проголосовали." +#: html/tu.php msgid "Vote ID not valid." msgstr "Идентификатор голосование неверный." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Сейчас голосов" +#: html/tu.php msgid "Past Votes" msgstr "Прошлые голоса" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Голосовавшие" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Регистрация аккаунтов с вашего IP адреса запрещена, возможная причина " -"проблемы — спам-атаки. Извините за неудобства." +msgstr "Регистрация аккаунтов с вашего IP адреса запрещена, возможная причина проблемы — спам-атаки. Извините за неудобства." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Отсутствует идентификатор пользователя" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Неверное имя пользователя." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Длина должна быть от %s до %s символов" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Начинаются и заканчиваются цифрой или буквой" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Может содержать только одну запятую, подчёркивание или тире." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Неправильный адрес электронной почты." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Неверный отпечаток ключа PGP." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." -msgstr "" +msgstr "Публичный SSH ключ неправильный." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Невозможно повысить привилегии." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Язык пока не поддерживается." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Имя пользователя, %s%s%s, уже используется." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Адрес %s%s%s уже используется." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "Публичный SSH ключ %s%s%s уже используется." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Ошибка при создании аккаунта %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Учетная запись %s%s%s была успешно создана." -msgid "Click on the Login link above to use your account." -msgstr "Нажмите на ссылку для входа вверху чтобы зайти." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Добро пожаловать в %s! Для того чтобы установить начальный пароль для " -"нового аккаунта, пожалуйста нажмите на ссылку ниже. Если ссылка не работает, " -"скопируйте и вставьте её в веб-браузер." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ключ для смены пароля был отправлен на ваш электронный адрес." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Нажмите на ссылку для входа вверху чтобы зайти." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "С аккаунтом %s%s%s не произведено никаких действий." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Учетная запись %s%s%s успешно изменена." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Доступ к форме входа с вашего IP адреса запрещен, возможная причина проблемы " -"— спам-атаки. Извините за неудобства." +msgstr "Доступ к форме входа с вашего IP адреса запрещен, возможная причина проблемы — спам-атаки. Извините за неудобства." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Действие аккаунта приостановлено." +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Ваш пароль был сброшен. Если вы только что создали аккаунт, пожалуйста " -"используйте ссылку из письма подтверждения чтобы установить начальный " -"пароль. В противном случае, запросите ключ для сброса на странице %sСброс " -"пароля%s." +msgstr "Ваш пароль был сброшен. Если вы только что создали аккаунт, пожалуйста используйте ссылку из письма подтверждения чтобы установить начальный пароль. В противном случае, запросите ключ для сброса на странице %sСброс пароля%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Неверно указаны имя пользователя или пароль." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Произошла ошибка при создании пользовательской сессии." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Неверная электронная почта и комбинация сброса ключа." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Нет" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Просмотр информации об аккаунте %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Комментарий добавлен." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Ошибка получения информации о пакете." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Не найдена информация о пакете." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Вы должны войти прежде чем расставлять флажки на пакеты." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Вы не выбрали ни одного пакета для пометки." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Выбранные пакеты помечены как устаревшие." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Вы должны войти прежде чем снимать флажки." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Вы не выбрали ни одного пакета для снятия пометки." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "С выбранных пакетов пометка снята." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "У вас нет права на удаление пакетов." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Вы не выбрали ни одного пакета для удаления." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Выбранные пакеты удалены." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Вы должны войти прежде чем усыновлять пакеты." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Вы должны войти прежде чем бросать пакеты." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Вы не выбрали ни одного пакета для усыновления." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Вы не выбрали ни одного пакета чтобы бросить." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Выбранные пакеты усыновлены." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Выбранные пакеты брошены." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Вы должны войти прежде чем голосовать." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Вы должны войти прежде чем снимать голос с пакета." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Вы не выбрали ни одного пакета для голосования." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Ваш голос убран с выбранного пакета." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Вы проголосовали за выбранные пакеты." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Невозможно добавить в список получателей извещений." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Вы добавлены в список извещений для %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Вам больше не будут приходить извещения от %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Вы должны представиться прежде чем редактировать информацию о пакете." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Идентификатор комментария отсутствует." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Комментарий удален." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "У вас нет прав для удаления этого комментария." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" +msgstr "Вы не можете редактировать ключевые слова данной группы пакетов." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." -msgstr "" +msgstr "Ключевые слова были обновлены." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "Вы не можете управлять сопровождающими данной группы пакетов." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Неправильное имя пользователя: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "Сопровождающие пакета были обновлены." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Просмотреть информацию о пакете" -msgid "You must be logged in to file package requests." +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php +msgid "You must be logged in to file package requests." +msgstr "Вы должны войти, чтобы отправить запрос по пакету." + +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Неверное имя: только нижний регистр допустим." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Поле комментариев должно быть заполнено." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Неправильный тип запроса." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Запрос добавлен успешно." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Неправильная причина." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Только Доверенные пользователи или разработчики могут закрывать запросы." +msgstr "Только Доверенные пользователи или разработчики могут закрывать запросы." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Запрос закрыт успешно." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Вы можете использовать данную форму, чтобы удалить следующий аккаунт AUR: %s." +msgstr "Вы можете использовать данную форму, чтобы удалить следующий аккаунт AUR: %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sПРЕДУПРЕЖДЕНИЕ%s: Данное действие не может быть отменено." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Подтвердите удаление" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Имя пользователя" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Тип учетной записи" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Пользователь" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Разработчик" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Доверенные пользователи и Разработчики" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Адрес электронной почты" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Настоящее имя" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Ник" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Отпечаток ключа PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Статус" +#: template/account_details.php msgid "Inactive since" msgstr "Неактивен с" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Активный" +#: template/account_details.php msgid "Last Login" msgstr "Последний вход" +#: template/account_details.php msgid "Never" msgstr "Никогда" +#: template/account_details.php msgid "View this user's packages" msgstr "Посмотреть пакеты этого пользователя" +#: template/account_details.php msgid "Edit this user's account" msgstr "Отредактировать этот аккаунт" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Нажмите %sздесь%s, если Вы хотите удалить данный аккаунт насовсем." +#: template/account_edit_form.php msgid "required" msgstr "необходимо" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Обычный пользователь" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Доверенный пользователь" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Действие учетной записи приостановлено" +#: template/account_edit_form.php msgid "Inactive" msgstr "Неактивен" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Введите пароль еще раз" +#: template/account_edit_form.php msgid "Language" msgstr "Язык" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Только следующая необходима, если вы хотите загрузить пакеты в AUR." +#: template/account_edit_form.php msgid "SSH Public Key" -msgstr "" +msgstr "Публичный SSH ключ" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Обновить" +#: template/account_edit_form.php msgid "Create" msgstr "Создать" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Очистить" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "По вашему запросу ничего не найдено." +#: template/account_search_results.php msgid "Edit Account" msgstr "Изменить учетную запись" +#: template/account_search_results.php msgid "Suspended" msgstr "Приостановлена" +#: template/account_search_results.php msgid "Edit" msgstr "Редактировать" +#: template/account_search_results.php msgid "Less" msgstr "Назад" +#: template/account_search_results.php msgid "More" msgstr "Далее" +#: template/account_search_results.php msgid "No more results to display." msgstr "Больше нет результатов." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" -msgstr "" +msgstr "Управление сопровождающими: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" +msgstr "Используйте данную форму, чтобы добавить сопровождающих для %s%s%s (используйте одно имя на строку):" +#: template/comaintainers_form.php msgid "Users" -msgstr "" +msgstr "Пользователи" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" -msgstr "" +msgstr "Сохранить" +#: template/header.php msgid "My Packages" msgstr "Мои пакеты" +#: template/header.php msgid " My Account" msgstr "Моя учётная запись" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Действия над пакетом" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Просмотреть PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" -msgstr "" +msgstr "Посмотреть изменения" +#: template/pkgbase_actions.php msgid "Download snapshot" -msgstr "" +msgstr "Загрузить снимок" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Искать в Wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Помечен как устаревший" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Пометить пакет как устаревший" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Снять пометку" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Удалить голос" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Проголосовать за пакет" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Выключить уведомления" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Уведомлять о новых комментариях" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" -msgstr "" +msgstr "Управление сопровождающими" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -957,169 +1283,232 @@ msgstr[1] "%d запроса в обработке" msgstr[2] "%d запросов в обработке" msgstr[3] "%d запросов в обработке" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Удалить пакет" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Объединить пакеты" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Усыновить пакет" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "неизвестно" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Информация по группе пакетов" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" -msgstr "" +msgstr "URL для git clone" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" -msgstr "" +msgstr "только чтение" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Ключевые слова" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Автор" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ответственный" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Последний приславший" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Голосов" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Популярность" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Впервые послан" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Последнее обновление" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Добавить комментарий" -msgid "Comment has been added." -msgstr "Комментарий добавлен." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Посмотреть все комментарии" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Последние комментарии" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Удалить комментарий" -#, php-format -msgid "Comment by %s" -msgstr "Комментарий %s" - -msgid "Anonymous comment" -msgstr "Анонимный комментарий" - -msgid "deleted" -msgstr "удален" - +#: template/pkg_comments.php msgid "All comments" msgstr "Все комментарии" +#: template/pkg_details.php msgid "Package Details" msgstr "Информация о пакете" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Группа пакетов" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Описание" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL апстрима" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Посетить сайт" +#: template/pkg_details.php msgid "Licenses" msgstr "Лицензия" +#: template/pkg_details.php msgid "Groups" msgstr "Группы" +#: template/pkg_details.php msgid "Conflicts" msgstr "Конфликтует" +#: template/pkg_details.php msgid "Provides" msgstr "Предоставляет" +#: template/pkg_details.php msgid "Replaces" msgstr "Заменяет" +#: template/pkg_details.php msgid "Dependencies" msgstr "Зависимости" +#: template/pkg_details.php msgid "Required by" msgstr "Требуется пакетами" +#: template/pkg_details.php msgid "Sources" msgstr "Исходники" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Закрыть запрос %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Используйте эту форму, чтобы закрыть запрос о группе пакетов %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Примечание" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"При отклонении запроса рекомендуется заполнить поле комментарий (не " -"обязательно)." +msgstr "При отклонении запроса рекомендуется заполнить поле комментарий (не обязательно)." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Причина" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Принято" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Отклонено" -msgid "Comments" -msgstr "Комментарии" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Запрос: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Используйте данную форму, чтобы послать запрос по поводу группы пакетов %s%s" -"%s, которая включает следующие пакеты:" +msgstr "Используйте данную форму, чтобы послать запрос по поводу группы пакетов %s%s%s, которая включает следующие пакеты:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Тип запроса" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Удаление" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Сделать сиротой" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Объединить с" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1128,23 +1517,29 @@ msgstr[1] "Найдены запросы для %d пакетов." msgstr[2] "Найдены запросы для %d пакетов." msgstr[3] "Найдены запросы для %d пакетов." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Страница %d из %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Пакет" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Послан" +#: template/pkgreq_results.php msgid "Date" msgstr "Дата" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "осталось ~%d дней" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1153,90 +1548,116 @@ msgstr[1] "осталось ~%d часа" msgstr[2] "осталось ~%d часов" msgstr[3] "осталось ~%d часов" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "осталось меньше часа" +#: template/pkgreq_results.php msgid "Accept" msgstr "Принять" +#: template/pkgreq_results.php msgid "Locked" msgstr "Заблокировано" +#: template/pkgreq_results.php msgid "Close" msgstr "Закрыть" +#: template/pkgreq_results.php msgid "Closed" msgstr "Закрыт" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Название, описание" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Только название" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Точное имя" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Точное имя группы" +#: template/pkg_search_form.php msgid "All" msgstr "Все" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Отмеченные" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Неотмеченные" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Имя" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Мой голос" -msgid "Age" -msgstr "Возраст" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "По возрастанию" +#: template/pkg_search_form.php msgid "Descending" msgstr "По убыванию" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Введите критерии поиска" +#: template/pkg_search_form.php msgid "Search by" msgstr "Искать по" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Устарел" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Сортировать по" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Порядок сортировки" +#: template/pkg_search_form.php msgid "Per page" msgstr "Постранично" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Поехали" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Сироты" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Ошибка получения списка пакетов." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Нет пакетов по выбранному критерию поиска." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1245,119 +1666,154 @@ msgstr[1] "Найдено %d пакета." msgstr[2] "Найдено %d пакетов." msgstr[3] "Найдено %d пакетов." +#: template/pkg_search_results.php msgid "Version" msgstr "Версия" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" +msgstr "Популярность считается, как сумма всех голосов, где каждый голос взвешен с коэффициентом 0.98 за каждый день разницы между днем голосования и днем загрузки пакета." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Да" +#: template/pkg_search_results.php msgid "orphan" msgstr "сирота" +#: template/pkg_search_results.php msgid "Actions" msgstr "Действия" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Пометить как Устаревший" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Убрать флаг Устаревший" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Усыновить пакеты" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Бросить пакеты" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Удалить пакеты" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Подтвердить" +#: template/search_accounts_form.php msgid "Any type" msgstr "Любой тип" +#: template/search_accounts_form.php msgid "Search" msgstr "Поиск" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Статистика" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Пакеты-сироты" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Пакеты, добавленные за прошедшие 7 дней" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Пакеты, обновленные за прошедшие 7 дней" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Пакеты, обновленные за прошедший год" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Пакеты, которые никогда не обновлялись" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Зарегистрированных пользователей" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Доверенных пользователей" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Последние обновления" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Моя статистика" -msgid "Packages in unsupported" -msgstr "Пакетов в [unsupported]" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Подробнее о предложении" +#: template/tu_details.php msgid "This vote is still running." msgstr "Голосование продолжается." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Получено: %s %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Конец" +#: template/tu_details.php msgid "Result" msgstr "Результат" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Нет" +#: template/tu_details.php msgid "Abstain" msgstr "Воздерживаюсь" +#: template/tu_details.php msgid "Total" msgstr "Всего" +#: template/tu_details.php msgid "Participation" msgstr "Участие" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Последний голос TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Последний голос" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Нет результатов." +#: template/tu_list.php msgid "Start" msgstr "Начало" +#: template/tu_list.php msgid "Back" msgstr "Назад" diff --git a/po/sk.po b/po/sk.po index 6e3de984..2f00a1b9 100644 --- a/po/sk.po +++ b/po/sk.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # archetyp , 2013-2015 # Matej Ľach , 2011 @@ -9,974 +9,1268 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-07-22 19:39+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-28 17:44+0000\n" "Last-Translator: archetyp \n" -"Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" -"sk/)\n" -"Language: sk\n" +"Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: sk\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +#: html/404.php msgid "Page Not Found" msgstr "Stránka nebola nájdená" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Mrzí nás to, ale stránka, ktorú ste zadali, neexistuje." +#: html/503.php msgid "Service Unavailable" msgstr "Služba nie je dostupná" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Zachovajte pokoj. Na stránke momentálne prebieha údržba. Vrátime sa čoskoro." +msgstr "Zachovajte pokoj. Na stránke momentálne prebieha údržba. Vrátime sa čoskoro." +#: html/account.php msgid "Account" msgstr "Účet" +#: html/account.php template/header.php msgid "Accounts" msgstr "Účty" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nemáte potrebné práva pre prístup do tejto oblasti." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nemožno získať informácie pre špecifikovaného užívateľa. " +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemáte potrebné oprávnenia, pre úpravu tohoto účtu. " +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Použite tento formulár pre vyhľadávanie v existujúcich účtoch." +#: html/account.php msgid "You must log in to view user information." msgstr "Musíte sa prihlásiť, pre zobrazenie užívateľských informácií. " +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Pridať návrh" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Neplatný znak pre užívateľskú akciu." +#: html/addvote.php msgid "Username does not exist." msgstr "Užívateľské meno neexistuje." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "O %s už návrh beží." +#: html/addvote.php msgid "Invalid type." msgstr "Neplatný typ." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Návrch nemôže byť prázdny." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nový návrh bol odoslaný." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Odošli návrh na hlasovanie." +#: html/addvote.php msgid "Applicant/TU" msgstr "Adept/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prázdne ak nemožno uplatniť)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Typ" +#: html/addvote.php msgid "Addition of a TU" msgstr "Pridanie TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Odobranie TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Odobranie TU (neohlásená neaktivita)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Zmena stanov" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Návrh" +#: html/addvote.php msgid "Submit" msgstr "Odoslať" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Manažovať spolupracovníkov" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "Editovať komentár" + +#: html/home.php template/header.php msgid "Home" msgstr "Domov" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Vitajte v AUR! Prečítajte si prosím %sAUR smernicu pre užívateľov%s a %sAUR " -"smernicu pre TU%s pre ďalšie informácie." +msgstr "Vitajte v AUR! Prečítajte si prosím %sAUR smernicu pre užívateľov%s a %sAUR smernicu pre TU%s pre ďalšie informácie." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Prispené PKGBUILDy sa %smusia%s riadiť %sArch podmienkami pre balíčky%s, " -"inak budú vymazané!" +msgstr "Prispené PKGBUILDy sa %smusia%s riadiť %sArch podmienkami pre balíčky%s, inak budú vymazané!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nezabudnite hlasovať za svoje obľúbené balíčky!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Niektoré balíčky môžu byť poskytnuté ako binárky v [community]. " +#: html/home.php msgid "DISCLAIMER" msgstr "UPOZORNENIE" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." -msgstr "" -"Nepodporované balíčky sú vytvárané užívateľmi. Akékoľvek použitie " -"poskytnutých súborov je na vaše vlastné riziko. " +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." +msgstr "Balíčky v AUR sú výsledkom práce užívateľov. Akékoľvek použitie týchto súborov je na vlastnú zodpovednosť." +#: html/home.php msgid "Learn more..." msgstr "Dozvedieť sa viac..." +#: html/home.php msgid "Support" msgstr "Podpora" +#: html/home.php msgid "Package Requests" msgstr "Žiadosti ohľadom balíčkov" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"V súčasnosti existujú tri typy žiadostí, ktoré možno vyplniť v časti %sAkcie " -"balíčka%s na stránke s detailami balíčka, a to:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "V súčasnosti existujú tri typy žiadostí, ktoré možno vyplniť v časti %sAkcie balíčka%s na stránke s detailami balíčka, a to:" +#: html/home.php msgid "Orphan Request" msgstr "Žiadosť o osirenie" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Žiadosť o odobratie vlastníctva balíčka, napr. ak správca balíčka nie je " -"aktívny a balíček bol dlhšiu dobu označený ako neaktuálny." +msgstr "Žiadosť o odobratie vlastníctva balíčka, napr. ak správca balíčka nie je aktívny a balíček bol dlhšiu dobu označený ako neaktuálny." +#: html/home.php msgid "Deletion Request" msgstr "Žiadosť o vymazanie" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Žiadosť o odstránenie balíčka z AUR. Nepoužívajte prosím túto možnosť v " -"prípade, že balíček je pokazený a možno ho ľahko opraviť. Namiesto toho " -"radšej kontaktujte jeho správcu alebo v prípade nutnosti požiadajte o jeho " -"osirenie." +msgstr "Žiadosť o odstránenie balíčka z AUR. Nepoužívajte prosím túto možnosť v prípade, že balíček je pokazený a možno ho ľahko opraviť. Namiesto toho radšej kontaktujte jeho správcu alebo v prípade nutnosti požiadajte o jeho osirenie." +#: html/home.php msgid "Merge Request" msgstr "Žiadosť o zlúčenie" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Žiadosť o zlúčenie balíčka do iného. Možno použiť tiež v prípade, že balíček " -"potrebuje byť premenovaný alebo nahradený rozdeleným balíčkom." +msgstr "Žiadosť o zlúčenie balíčka do iného. Možno použiť tiež v prípade, že balíček potrebuje byť premenovaný alebo nahradený rozdeleným balíčkom." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Ak potrebujete prediskutovať nejakú požiadavku, kedykoľvek môžete napísať na " -"mailing list %saur-requests%s. Nepoužívajte však tento mailing list na " -"posielanie požiadaviek." +msgstr "Ak potrebujete prediskutovať nejakú požiadavku, kedykoľvek môžete napísať na mailing list %saur-requests%s. Nepoužívajte však tento mailing list na posielanie požiadaviek." +#: html/home.php msgid "Submitting Packages" msgstr "Podanie balíčkov" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git cez SSH sa teraz používa na podanie balíčkov do AUR. Pre ďalšie " -"informácie pozri tiež sekciu %sPodanie balíčkov%s na AUR stránke v ArchWiki." +msgstr "Git cez SSH sa teraz používa na podanie balíčkov do AUR. Pre ďalšie informácie pozri tiež sekciu %sPodanie balíčkov%s na AUR stránke v ArchWiki." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Uvedené SSH fingerprints sa používajú pre AUR:" +#: html/home.php msgid "Discussion" msgstr "Diskusia" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Všeobecná diskusia týkajúca sa Arch Užívateľského Repozitára (AUR) a " -"štruktúry dôverovaných užívateľov (TU) je na %saur-general%s. Na diskusiu " -"týkajúcu sa vývoja AUR webu použite %saur-dev%s mailing list." +msgstr "Všeobecná diskusia týkajúca sa Arch Užívateľského Repozitára (AUR) a štruktúry dôverovaných užívateľov (TU) je na %saur-general%s. Na diskusiu týkajúcu sa vývoja AUR webu použite %saur-dev%s mailing list." +#: html/home.php msgid "Bug Reporting" msgstr "Ohlasovanie chýb" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." -msgstr "" -"Ak nájdete chybu na AUR webe, napíšte prosím správu o chybe na náš %sbug " -"tracker%s. Používajte ho %slen%s na chyby AUR webu. Ohľadom chýb balíčka " -"kontaktujte prosím jeho spravovateľa alebo zanechajte komentár na stránke " -"balíčka." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Ak nájdete chybu vo webovom rozhradní AUR, pošlite prosím správu o chybe na náš %sbug tracker%s. Posielajte sem %slen%s chyby webového rozhrania AUR. Pre nahlásenie chýb balíčkov kontaktujte správcu balíčka alebo zanechate komentár na príslušnej stránke balíčka." +#: html/home.php msgid "Package Search" msgstr "Hľadanie balíčka" +#: html/index.php msgid "Adopt" msgstr "Adoptovať" +#: html/index.php msgid "Vote" msgstr "Hlasuj" +#: html/index.php msgid "UnVote" msgstr "Odober hlas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Upozorni" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Zruš upozornenie" -msgid "Flag" -msgstr "Označ" - +#: html/index.php msgid "UnFlag" msgstr "Odznač" +#: html/login.php template/header.php msgid "Login" msgstr "Prihlásiť" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Prihlásený ako: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Odhlásiť" +#: html/login.php msgid "Enter login credentials" msgstr "Zadajte prihlasovacie údaje" -msgid "Username" -msgstr "Užívateľské meno" +#: html/login.php +msgid "User name or email address" +msgstr "Užívateľské meno alebo emailová adresa" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Heslo" +#: html/login.php msgid "Remember me" msgstr "Zapamätaj si ma" +#: html/login.php msgid "Forgot Password" msgstr "Zabudnuté heslo" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP prihlasovanie je zablokované. Pre prihlásenie prosím %sprepnite na HTTPs" -"%s." +msgstr "HTTP prihlasovanie je zablokované. Pre prihlásenie prosím %sprepnite na HTTPs%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Vyhľadávacie kritériá" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Balíčky" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Pri pokuse o získanie podrobností o balíčku nastala chyba." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Povinné pole nie je vyplnené." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Heslá sa nezhodujú. " +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Heslo musí mať aspoň %s znakov." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Neplatný e-mail." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Na účet %s spojený s Vašou emailovou adresou bola zaslaná požiadava na " -"resetovanie hesla. Ak si želáte heslo resetovať, kliknite na odkaz nižšie, " -"inak môžete túto správu ignorovať, žiadna zmena sa nestane." - +#: html/passreset.php msgid "Password Reset" msgstr "Obnova hesla" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Skontrolujte si svoj e-mail pre potvrdzujúci odkaz." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Heslo bolo úspešne obnovené." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrďte svoju e-mailovú adresu:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Zadajte nové heslo:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrďte nové heslo:" +#: html/passreset.php msgid "Continue" msgstr "Pokračuj" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Ak ste zabudli e-mailovú adresu, ktorú ste použili pri registrácii, pošlite " -"prosím správu na %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Ak ste zabudli e-mailovú adresu, ktorú ste použili pri registrácii, pošlite prosím správu na %saur-general%s mailing list." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Zadajte svoju e-mailovú adresu:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Vybrané balíčky neboli označené, zanechajte prosím komentár." + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Vybrané balíčky neboli vyvlastnené, pozrite potvrdzovacie zaškrtávacie " -"políčko." +msgstr "Vybrané balíčky neboli vyvlastnené, pozrite potvrdzovacie zaškrtávacie políčko." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Nepodarilo sa nájsť balíček, do ktorého sa mali zlúčiť hlasy a komentáre." +msgstr "Nepodarilo sa nájsť balíček, do ktorého sa mali zlúčiť hlasy a komentáre." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nemožno zlúčiť základňu balíčka so sebou samou." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Vybrané balíčky neboli odstránené, začiarknite potvrdzujúce políčko." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Vymazanie balíčka" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Vymazať balíček: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Použite tento formulár pre vymazanie základne balíčka %s%s%s a nasledovných " -"balíčkov z AUR: " +msgstr "Použite tento formulár pre vymazanie základne balíčka %s%s%s a nasledovných balíčkov z AUR: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Vymazanie balíčka je nevratné." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaškrtnite políčko pre potvrdenie akcie." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrďte vymazanie balíčka" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Vymazať" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Len dôverovaní užívatelia a vývojári môžu vymazať balíčky." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Vyvlastni balíček" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Vyvlastni balíček: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Použite tento formulár na vyvlastnenie základne balíčka %s%s%s, ktorá " -"zahrňuje nasledujúce balíčky:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Použite tento formulár na vyvlastnenie základne balíčka %s%s%s, ktorá zahrňuje nasledujúce balíčky:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček " -"a presunúť vlastníctvo na %s%s%s." +msgstr "Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček a presunúť vlastníctvo na %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček." +msgstr "Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Potvrďte na vyvlastnenie balíčka" +#: html/pkgdisown.php msgid "Disown" msgstr "Vyvlastniť" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Len dôverovaní užívatelia a vývojári môžu vyvlastňovať balíčky." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "Označ balíček ako zastaranú verziu" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "Označ balíček ako zastaranú verziu: %s" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Použite tento formulár na označenie základne balíčka %s%s%s a nasledujúcich balíčkov ako zastarané verzie:" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "Tento formulár %sneslúži%s na nahlasovanie chýb. Na to použite komentár k balíčku." + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "Uveďte nižšie podrobnosti o tom prečo je balíček zastaraný, podľa možnosti pridajte tiež link na oznam k novej verzii alebo nový tarball." + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Komentáre" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Označ" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "Označiť zastaranú verziu balíčka môžu iba registrovaní užívatelia." + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Zlúčenie balíčkov" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Zlúčiť balíček: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Použite tento formulár pre zlúčenie základne balíčka %s%s%s do iného " -"balíčka. " +msgstr "Použite tento formulár pre zlúčenie základne balíčka %s%s%s do iného balíčka. " +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Nasledujúce balíčky budú vymazané:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Operácia zlúčenia balíčkov je nevratná." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Zadajte meno balíčka, do ktorého chcete zlúčiť uvedený balíček." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Zlúčiť do:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrďte zlúčenie balíčka" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Zlúčiť" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Len dôverovaní užívatelia a vývojári môžu zlúčiť balíčky." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Vyplniť žiadosť" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zatvorit žiadosť" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prvý" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Predchádzajúci" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Ďaľej " +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Posledný" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Žiadosti" +#: html/register.php template/header.php msgid "Register" msgstr "Registrovať" +#: html/register.php msgid "Use this form to create an account." msgstr "Použite tento formulár pre vytvorenie účtu. " +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Dôverovaný užívateľ (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nepodarilo sa načítať údaje o návrhu." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Hlasovanie o tomto návrhu bolo ukončené." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Práve hlasovať majú len dôverovaní užívatelia" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemôžete hlasovať v návrhu o Vás." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "O tomto návrhu ste už hlasovali." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID hlasu nie je platné." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Súčasné hlasy" +#: html/tu.php msgid "Past Votes" msgstr "Minulé hlasy" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Hlasujúci" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Registrácia účtu bolo zablokovaná pre vašu IP adresu, pravdepodobne z dôvodu " -"stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +msgstr "Registrácia účtu bolo zablokovaná pre vašu IP adresu, pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Chýba ID užívateľa" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Užívateľké meno je neplatné." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Musí mať dĺžku medzi %s a %s znakmi" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Začínať a končiť s písmenom alebo číslom" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Môže obsahovať len jednu bodku, podčiarkovník alebo pomlčku." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mailová adresa nie je platná." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP otlačok kľúča je neplatný." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Verejný SSH kľúč nie je platný." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nepodarilo sa rozšíriť práva účtu." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jazyk nie je momentálne podporovaný." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Užívateľské meno %s%s%s sa už používa." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s sa už používa." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Verejný SSH kľúč %s%s%s sa už používa." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Chyba pri vytváraní účtu, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Účer %s%s%s bol úspešne vytvorený." -msgid "Click on the Login link above to use your account." -msgstr "Kliknite na Prihlásenie pre použitie svojho účtu." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Vitajte na %s! Pre zadanie prvotného hesla pre nový účet, kliknite prosím na " -"link nižšie. Ak link nefunguje, skúste ho skopírovať a vložiť do vašeho " -"prehliadača." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Obnovovacie heslo vám bolo zaslané na vašu e-mailovú adresu." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Kliknite na Prihlásenie pre použitie svojho účtu." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Žiadne zmeny neboli vykonané na účte %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Účet %s%s%s bol úspešne zmenený." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Prihlasovací formulár je v súčasnosti zablokovaný pre vašu IP adresu, " -"pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa " -"ospravedlňujeme." +msgstr "Prihlasovací formulár je v súčasnosti zablokovaný pre vašu IP adresu, pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Účet bol pozastavený" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Vaše heslo bolo obnovené. Ak ste si práve vytvorili nový účet, použite " -"prosím link z potvrdzovacieho emailu na nastavenie prvotného hesla. Inak " -"prosím zašlite požiadavku na obnovenie hesla na stránku %sObnova hesla%s." +msgstr "Vaše heslo bolo obnovené. Ak ste si práve vytvorili nový účet, použite prosím link z potvrdzovacieho emailu na nastavenie prvotného hesla. Inak prosím zašlite požiadavku na obnovenie hesla na stránku %sObnova hesla%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nesprávne užívateľské meno alebo heslo." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Pri vytváraní užívateľského sedenia sa vyskytla chyba." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Neplatný email a kombinácia obnovovacích znakov." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Žiadny" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Pozri informácie o účte pre %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "Chyba ID alebo meno základne balíčka." + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "Nemáte oprávnenie na editovanie tohoto komentára." + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "Komentár neexistuje." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "Komentár nemôže byť prázdny." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Komentár bol pridaný." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Chyba pri získavaní informácií o balíčku." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Informácie o balíčku sa nepodarilo nájsť." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Musíte byť prihlásený ak chcete označovať balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nebol vybraný žiadny balíček na označenie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Vybrané balíčky boli označené ako zastarané." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musíte byť prihlásený ak chcete odznačiť balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nebol vybraný žiadny balíček na odznačenie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Vybrané balíčky boli odznačené." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nemáte práve vymazať balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nebol vybraný žiadny balíček na vymazanie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Vybrané balíčky boli vymazané." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musíte byť prihlásený ak chcete adoptovať balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musíte byť prihlásený ak chcete vyvlastniť balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nebol vybraný žiadny balíček na adopciu." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Neoznačili ste žiadne balíčky na vyvlastnenie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Vybrané balíčky boli adoptované." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Vybrané balíčky boli vyvlastnené." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Musíte byť prihlásený ak chcete hlasovať za balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musíte byť prihlásený ak chcete odobrať hlas balíčkom." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nebol vybraný žiadny balíček pre hlasovanie." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Váš hlas bol odobratý z vyznačených balíčkov." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Váš hlas bol pridaný vyznačeným balíčkom." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Pridanie do zoznamu upozornení bolo neúspešné." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Boli ste pridaný na notifikačný zoznam komentárov pre %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Boli ste odobraný z notifikačného zoznamu komentárov pre %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Musíte byť prihlásený ak chcete editovať informácie o balíčku." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Chýba ID komentára." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentár bol vymazaný." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nemáte práva na vymazanie tohto komentára." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "Komentár bol editovaný." + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nemáte oprávnenie na editovanie kľúčových slov tejto základne balíčka." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Kľúčové slová základne balíčka boli aktualizované." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nie ste oprávnený manažovať spolupracovníkov tejto základne balíčka." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Neplatné užívateľské meno: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Spolupracovníci základne balíčka boli aktualizovaní." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Pozri detaily balíčky pre" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "vyžaduje %s" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Musíte byť prihlásený ak chcete posielať žiadosti o balíčkoch." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neplatné meno: povolené sú iba malé písmená." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Pole s komentárom nemôže byť prázdne." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Neplatný typ žiadosti." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Požiadavka bola úspešne pridaná." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Neplatný dôvod." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Len Dôverovaní Užívatelia (TU) a vývojári môžu zatvárať žiadosti." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Žiadosť bola úspešne uzavretá." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Tento formulár môžete použiť na trvalé vymazanie AUR účtu %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUPOZORNENIE%s: Túto akciu nemožno vrátiť." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Potvrdiť vymazanie" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Užívateľské meno" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Typ účtu" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Užívateľ" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Vývojár" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Dôverovaný užívateľ & Vývojár" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mailová adresa" +#: template/account_details.php +msgid "hidden" +msgstr "skrytý" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Skutočné meno" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC prezývka" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP otlačok kľúča" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Neaktívny od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktívny" +#: template/account_details.php msgid "Last Login" msgstr "Posledné prihlásenie" +#: template/account_details.php msgid "Never" msgstr "Nikdy" +#: template/account_details.php msgid "View this user's packages" msgstr "Pozrieť balíčky tohto užívateľa" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editovať účet tohto užívateľa" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %ssem%s ak chcete natrvalo vymazať tento účet." +#: template/account_edit_form.php msgid "required" msgstr "povinný" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normálny užívateľ" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Dôverovaný užívateľ (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Účet bol pozastavený" +#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktívny" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "Overte prosím, že ste emailovú adresu zadali správne, inak budete vymknutý." + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "Skryť emailovú adresu" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Potvrďte heslo" +#: template/account_edit_form.php msgid "Language" msgstr "Jazyk" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Nasledujúca informácia je dôležitá iba v prípade, že chcete podať balíčky do " -"AUR." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Nasledujúca informácia je dôležitá iba v prípade, že chcete podať balíčky do AUR." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Verejný SSH kľúč" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualizácia" +#: template/account_edit_form.php msgid "Create" msgstr "Vytvoriť" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reset" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Pre vaše vyhľadávacie kritériá neboli nájdené žiadne výsledky." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editovať účet" +#: template/account_search_results.php msgid "Suspended" msgstr "Pozastavený" +#: template/account_search_results.php msgid "Edit" msgstr "Editovať" +#: template/account_search_results.php msgid "Less" msgstr "Menej" +#: template/account_search_results.php msgid "More" msgstr "Viac" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nie sú ďalšie výsledky na zobrazenie." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Manažovať spolupracovníkov: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno " -"užívateľké meno na riadok):" +msgstr "Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno užívateľké meno na riadok):" +#: template/comaintainers_form.php msgid "Users" msgstr "Užívatelia" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Uložiť" +#: template/header.php msgid "My Packages" msgstr "Moje balíčky" +#: template/header.php msgid " My Account" msgstr "Môj účet" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Akcie balíčka" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Pozrieť PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Prezrieť zmeny" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Stiahnuť snapshot" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Prehľadať wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Označený ako neaktuálny" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Označ balíček ako neaktuálny" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Odznač balíček" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Odober hlas" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Hlasuj za tento balíček" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Vypni upozornenia" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Upozorni na nové komentáre" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Manažovať spolupracovníkov" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -984,170 +1278,232 @@ msgstr[0] "%d ostávajúcich žiadostí" msgstr[1] "%d ostávajúce žiadosti" msgstr[2] "%d ostávajúcich žiadostí" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Vymaž balíček" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Zlúč balíček" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptuj balíček" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "neznámy" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detaily základne balíčka" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "len na čítanie" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Kľúčové slová" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Prispievateľ" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Spravovateľ" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Naposledy zabalil" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Hlasy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularita" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvý príspevok" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Posledná aktualizácia" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "Editovať komentár k: %s" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Pridať komentár" -msgid "Comment has been added." -msgstr "Komentár bol pridaný." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Pozrieť všetky komentáre" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Posledné komentáre" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "%s dal komentár k %s" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "Anonymný komentár k %s" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "vymazal %s %s" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "naposledy editoval %s %s" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Vymaž komentár" -#, php-format -msgid "Comment by %s" -msgstr "Komentár od %s" - -msgid "Anonymous comment" -msgstr "Anonymný komentár" - -msgid "deleted" -msgstr "vymazaný" - +#: template/pkg_comments.php msgid "All comments" msgstr "Všetky komentáre" +#: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčka" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Základňa balíčka" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Popis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Navštív web stránku pre" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencie" +#: template/pkg_details.php msgid "Groups" msgstr "Skupiny" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikt s" +#: template/pkg_details.php msgid "Provides" msgstr "Poskytuje" +#: template/pkg_details.php msgid "Replaces" msgstr "Nahrádza" +#: template/pkg_details.php msgid "Dependencies" msgstr "Závislosti" +#: template/pkg_details.php msgid "Required by" msgstr "Vyžadovaný" +#: template/pkg_details.php msgid "Sources" msgstr "Zdroje" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Uzavrieť požiadavku: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Použite tento formulár pre zatvorenie požiadavky na základňu balíčka %s%s%s." +msgstr "Použite tento formulár pre zatvorenie požiadavky na základňu balíčka %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Poznámka" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Políčko pre komentár možno nechať prázdne. Napriek tomu sa odporúča zanechať " -"komentár pri zamietnutí požiadavky." +msgstr "Políčko pre komentár možno nechať prázdne. Napriek tomu sa odporúča zanechať komentár pri zamietnutí požiadavky." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Dôvod" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Prijatý" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Zamietnutý" -msgid "Comments" -msgstr "Komentáre" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Vyplniť žiadosť: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Použite tento formulár na vyplnenie požiadavky ohľadom základne balíčka %s%s" -"%s ktorá zahrňuje nasledovné balíčky:" +msgstr "Použite tento formulár na vyplnenie požiadavky ohľadom základne balíčka %s%s%s ktorá zahrňuje nasledovné balíčky:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Typ žiadosti" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Vymazanie" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Vyvlastniť" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Zlúčiť do" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1155,23 +1511,29 @@ msgstr[0] "Bola nájdená %d požiadavka ohľadom balíčkov." msgstr[1] "Boli nájdené %d požiadavky ohľadom balíčkov." msgstr[2] "Bolo nájdených %d požiadaviek ohľadom balíčkov." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Strana %d z %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Balíček" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Vyplnil" +#: template/pkgreq_results.php msgid "Date" msgstr "Dátum" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dní ostáva" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1179,90 +1541,116 @@ msgstr[0] "ostáva ~%d hodina" msgstr[1] "ostávajú ~%d hodiny" msgstr[2] "ostáva ~%d hodín" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "ostáva < 1 hodina" +#: template/pkgreq_results.php msgid "Accept" msgstr "Prijať" +#: template/pkgreq_results.php msgid "Locked" msgstr "Uzamknuté" +#: template/pkgreq_results.php msgid "Close" msgstr "Zatvoriť" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zatvorené" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "meno, popis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "iba meno" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Presné meno" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Presná základňa balíčka" +#: template/pkg_search_form.php msgid "All" msgstr "Všetky" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Označené" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Neoznačené" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Meno" -msgid "Popularity" -msgstr "Popularita" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Hlasoval" -msgid "Age" -msgstr "vek" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "Naposledy zmenený" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Vzostupne" +#: template/pkg_search_form.php msgid "Descending" msgstr "Zostupne" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Zadaj kritériá pre vyhľadávanie" +#: template/pkg_search_form.php msgid "Search by" msgstr "Vyhľadávať podľa" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Neaktuálny" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Zotriediť podľa" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Zotriediť" +#: template/pkg_search_form.php msgid "Per page" msgstr "Na stránku" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Choď" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Osirené" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Chyba pri získavaní zoznamu balíčkov." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Žiadne balíčky nezodpovedajú vaším vyhľadávacím kritériám." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1270,121 +1658,154 @@ msgstr[0] "%d nájdených balíčkov." msgstr[1] "%d nájdené balíčky." msgstr[2] "%d nájdených balíčkov." +#: template/pkg_search_results.php msgid "Version" msgstr "Verzia" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"Popularita sa počíta ako suma všetkých hlasov, pričom každý hlas je násobený " -"váhovým faktorom 0.98 za deň od dátumu vzniku." +msgstr "Popularita sa počíta ako suma všetkých hlasov, pričom každý hlas je násobený váhovým faktorom 0.98 za deň od dátumu vzniku." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Áno" +#: template/pkg_search_results.php msgid "orphan" msgstr "osirelý" +#: template/pkg_search_results.php msgid "Actions" msgstr "Akcie" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Označ ako neaktuálny." +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Odznač ako neaktuálny" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptuj balíčky" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Vyvlastni balíčky" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Vymaž balíčky" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrď" +#: template/search_accounts_form.php msgid "Any type" msgstr "Ľub. typ" +#: template/search_accounts_form.php msgid "Search" msgstr "Hľadaj" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Štatistika" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Osirelé balíčky" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Balíčky pridané za posledných 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Balíčky aktualiz. za uplynulých 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Balíčky aktualiz. za posledný rok" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nikdy neaktualizované balíčky" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovaní užívatelia" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Dôverovaní užívatelia (TU)" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedávne aktualizácie" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moja štatistika" -msgid "Packages in unsupported" -msgstr "Nepodporované balíčky" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaily o návrhu" +#: template/tu_details.php msgid "This vote is still running." msgstr "Hlasovanie stále prebieha." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Prispené: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Koniec" +#: template/tu_details.php msgid "Result" msgstr "Výsledok" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nie" +#: template/tu_details.php msgid "Abstain" msgstr "Zdržalo sa" +#: template/tu_details.php msgid "Total" msgstr "Celkom" +#: template/tu_details.php msgid "Participation" msgstr "Účasť" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Posledné hlasy od TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Posledný hlas" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Žiadne výsledky neboli nájdené." +#: template/tu_list.php msgid "Start" msgstr "Začiatok" +#: template/tu_list.php msgid "Back" msgstr "Späť" diff --git a/po/sr.po b/po/sr.po index 89b34444..4aa146bc 100644 --- a/po/sr.po +++ b/po/sr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Lukas Fleischer , 2011 # Slobodan Terzić , 2011-2012,2015 @@ -10,966 +10,1268 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 12:30+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 12:23+0000\n" "Last-Translator: Slobodan Terzić \n" -"Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" -"sr/)\n" -"Language: sr\n" +"Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Language: sr\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +#: html/404.php msgid "Page Not Found" msgstr "Stranica nije nađena" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Stranica koju ste zahtevali ne postoji." +#: html/503.php msgid "Service Unavailable" msgstr "Servis nije dostupan" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Ne paničite! Sajt je van mreže usled održavanja. Povratak se očekuje uskoro." +msgstr "Ne paničite! Sajt je van mreže usled održavanja. Povratak se očekuje uskoro." +#: html/account.php msgid "Account" msgstr "Nalog" +#: html/account.php template/header.php msgid "Accounts" msgstr "Nalozi" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nije vam dozvoljen pristup ovoj oblasti." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Ne mogu da dobavim podatke o izabranom korisniku." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemate dozvole za uređivanje ovog naloga." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Ovim obrascem pretražujete postojeće naloge." +#: html/account.php msgid "You must log in to view user information." msgstr "Morate se prijaviti da bi videli podatke o korisniku." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Dodavanje predloga" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Neispravan token korisničke radnje." +#: html/addvote.php msgid "Username does not exist." msgstr "Korisničko ime ne postoji." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Predlog za %s već postoji." +#: html/addvote.php msgid "Invalid type." msgstr "Nedozvoljen tip." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Predlog ne može biti prazan." +#: html/addvote.php msgid "New proposal submitted." msgstr "Novi predlog je poslat." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Pošaljite predlog za glasanje." +#: html/addvote.php msgid "Applicant/TU" msgstr "Podnosioc/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prazno ako je nevažeće)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Vrsta" +#: html/addvote.php msgid "Addition of a TU" msgstr "Dodavanje TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Uklanjanje TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Uklanjanje TU (nedeklarisana neaktivnost)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Dopuna o podzakonskim aktima" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Predlog" +#: html/addvote.php msgid "Submit" msgstr "Slanje" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Upravljanje koodržavaocima" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "Uređivanje komentara" + +#: html/home.php template/header.php msgid "Home" msgstr "Početna" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Dobrodošli u AUR! Molimo pročitajte %sSmernice za korisnike AUR-a%s i " -"%sSmernice za poverljive korinike%s za više informacija." +msgstr "Dobrodošli u AUR! Molimo pročitajte %sSmernice za korisnike AUR-a%s i %sSmernice za poverljive korinike%s za više informacija." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Priloženi PKGBUILD-ovi %smoraju%s biti u skladu sa %sArčovim standardima " -"pakiranja%s ili će biti obrisani!" +msgstr "Priloženi PKGBUILD-ovi %smoraju%s biti u skladu sa %sArčovim standardima pakiranja%s ili će biti obrisani!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ne zaboravite da glasate za omiljene pakete!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Neki paketi se dostavljaju u binarnom obliku u riznici [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "UPOZORENJE" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." -msgstr "" -"Paketi označeni sa [unsupported] su sadržaj koji stvaraju korisnici. " -"Upotrebljavate ih na sopstvenu odgovornost." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." +msgstr "Paketi u AUR-u su sadržaj koji stvaraju korisnici. Upotrebljavate ih na sopstvenu odgovornost." +#: html/home.php msgid "Learn more..." msgstr "Saznajte više..." +#: html/home.php msgid "Support" msgstr "Podrška" +#: html/home.php msgid "Package Requests" msgstr "Zahtevi za pakete" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Postoje tri vrste zahteva koji mogu biti podneti kroz kućicu %sRadnje nad " -"paketima%s na stranici sa detaljima o paketu:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Postoje tri vrste zahteva koji mogu biti podneti kroz kućicu %sRadnje nad paketima%s na stranici sa detaljima o paketu:" +#: html/home.php msgid "Orphan Request" msgstr "Zahtevi za odricanje" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"zahtev za odricanje od paketa, npr. kada je održavalac neaktivan a paket je " -"predugo označen kao zastareo." +msgstr "zahtev za odricanje od paketa, npr. kada je održavalac neaktivan a paket je predugo označen kao zastareo." +#: html/home.php msgid "Deletion Request" msgstr "Zahtevi za brisanje" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"zahtev za brisanje paketa iz Arčove Korisničke Riznice. Ne koristite ovo ako " -"je paket polomljen i može se lako ispraviti. Umesto toga, kontaktirajte " -"održavaoca paketa i podnesite zahtev za odricanje ukoliko je potreban." +msgstr "zahtev za brisanje paketa iz Arčove Korisničke Riznice. Ne koristite ovo ako je paket polomljen i može se lako ispraviti. Umesto toga, kontaktirajte održavaoca paketa i podnesite zahtev za odricanje ukoliko je potreban." +#: html/home.php msgid "Merge Request" msgstr "Zahtevi za spajanje" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"tahtev za spajanje paketa sa drugim paketom. Koristi se kada je paketu " -"potrebno novo ime ili ga je potrebno razdeliti ma manje pakete." +msgstr "tahtev za spajanje paketa sa drugim paketom. Koristi se kada je paketu potrebno novo ime ili ga je potrebno razdeliti ma manje pakete." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Ukoliko želite da diskutujete o zahtevu, možete koristiti dopisnu listu " -"%saur-requests%s. Međutim, molimo da ne koristite tu listu za podnošenje " -"zahteva." +msgstr "Ukoliko želite da diskutujete o zahtevu, možete koristiti dopisnu listu %saur-requests%s. Međutim, molimo da ne koristite tu listu za podnošenje zahteva." +#: html/home.php msgid "Submitting Packages" msgstr "Prilaganje paketa" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Za prilaganje paketa u AUR sada se koristi Git reko SSH. Pogledajte sekciju " -"%sPrilaganje paketa%s na stranici or AUR-u na Arčovom wikiju." +msgstr "Za prilaganje paketa u AUR sada se koristi Git preko SSH. Pogledajte sekciju %sPrilaganje paketa%s na stranici o AUR-u na Arčovom wikiju." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Sledeći SSH otisci se koriste za AUR:" +#: html/home.php msgid "Discussion" msgstr "Diskusija" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Opšta diskusija vezana za Arčovu Korisničku Riznicu (AUR) i strukturu " -"Poverljivih korisnika se vodi na dopisnoj listi %saur-general%s.Za diskusiju " -"o razvoju samog web sučelja AUR-a, pogedajte dopisnu listu %saur-dev%s." +msgstr "Opšta diskusija vezana za Arčovu Korisničku Riznicu (AUR) i strukturu Poverljivih korisnika se vodi na dopisnoj listi %saur-general%s.Za diskusiju o razvoju samog web sučelja AUR-a, pogedajte dopisnu listu %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Prijavljivanje grešaka" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." -msgstr "" -"Ukoliko nađete grešku u web sučelju AUR-a. molimo da je prijavite na našem " -"%sbubolovcu%s. Bubolovac koristite %sisključivo%s za prjavljivanje grešaka u " -"samom AUR-u. Za prijavu grešaka u samim paketima kontaktirajte održavaoce " -"paketa ili ostavite komentar na odgovarajućoj stranici paketa." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Ukoliko nađete grešku u web sučelju AUR-a. molimo da je prijavite na našem %sbubolovcu%s. Bubolovac koristite %sisključivo%s za prjavljivanje grešaka u samom AUR-u. Za prijavu grešaka u samim paketima kontaktirajte održavaoce paketa ili ostavite komentar na odgovarajućoj stranici paketa." +#: html/home.php msgid "Package Search" msgstr "Pretraga paketa" +#: html/index.php msgid "Adopt" msgstr "Usvoji" +#: html/index.php msgid "Vote" msgstr "Daj glas" +#: html/index.php msgid "UnVote" msgstr "Ukloni glas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Obaveštavaj" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne obaveštavaj" -msgid "Flag" -msgstr "Označi" - +#: html/index.php msgid "UnFlag" msgstr "Odznači" +#: html/login.php template/header.php msgid "Login" msgstr "Prijava" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Prijavljeni ste kao: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Odjava" +#: html/login.php msgid "Enter login credentials" msgstr "Unesite podatke za prijavu" -msgid "Username" -msgstr "Korisničko ime" +#: html/login.php +msgid "User name or email address" +msgstr "Korisničko ime ili adresa e-pošte" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" +#: html/login.php msgid "Remember me" msgstr "Pamti me" +#: html/login.php msgid "Forgot Password" msgstr "Zaboravljena lozinka" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Prijavljivanje preko HTTP je isključeno. Koristite %sHTTPs%s da bi se " -"prijavili." +msgstr "Prijavljivanje preko HTTP je isključeno. Koristite %sHTTPs%s da bi se prijavili." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kriterijum pretrage" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketi" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Greška pri dobavljanju detalja paketa." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Nedostaje neophodno polje." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Polja lozinke se ne poklapaju." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Lozinka mora imati najmanje %s znaka." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Neispravna e-pošta." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Zahtev za resetovanje lozinke za nalog %s je poslat na adresu e-pošte. " -"Ukoliko želite da resetujete lozinku, ispratite vezu ispod; u suprotnom " -"ignorišite ovu poruku i ništa se neće desiti." - +#: html/passreset.php msgid "Password Reset" msgstr "Resetovanje lozinke" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Proverite e-poštu za vezu za potvrđivanje." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Vaša lozinka je uspešno resetovana." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrdite adresu e-pošte:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Unesite novu lozinku:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrdite novu lozinku:" +#: html/passreset.php msgid "Continue" msgstr "Nastavi" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Ukoliko ste zaboravili registracionu adresu e-pošte, molimo pošaljite poruku " -"na dopisnu listu %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Ukoliko ste zaboravili registracionu adresu e-pošte, molimo pošaljite poruku na dopisnu listu %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Unesite adresu e-pošte:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Izabrani paketi nisu označeni, molimo unesite komentar." + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Izabrani paketi nisu odreknuti, pogledajte kućicu za potvrdu." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Ne mogu da nađem paket kako bih stopio glasove i komentare." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Ne mogu da spojim osnovu paketa sa samom sobom." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Izabrani paketi nisu obrisani; pogledajte kućicu za potvrđivanje." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Brisanje paketa" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Obriši paket: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Ovim formularom brišete osnovu paketa %s%s%s i sledeće pakete iz AUR-a:" +msgstr "Ovim formularom brišete osnovu paketa %s%s%s i sledeće pakete iz AUR-a:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Brisanje paketa je trajno." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Označite kućicu za potvrdu." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrdite brisanje paketa" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Obriši" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Samo Poverljivi korisnici i Programeri mogu brisati pakete." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Odrekni se paketa" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Odricanje paketa: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Ovim formularom se odričete osnove paketa %s%s%s i sledećih pripadajučih " -"pakete:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Ovim formularom se odričete osnove paketa %s%s%s i sledećih pripadajučih pakete:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Označavanjem kućice potvrđujete odricanje prenos vlasništva paketa na %s%s%s." +msgstr "Označavanjem kućice potvrđujete odricanje prenos vlasništva paketa na %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Označavanjem kućice potvrđujete da želite da se odreknete od paketa." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Potvrdite odricanje od paketa" +#: html/pkgdisown.php msgid "Disown" msgstr "Odrekni se" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Samo Poverljivi korisnici i Programeri mogu vršiti odricanje paketa." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "Označi paket kao zastareo" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "Označavanje paketa zastarelim: %s" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Ovim formularom označavate osnovu paketa %s%s%s i sledeće pakete kao zastarele:" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "Molimo da ovim formularom %sNE%s prijavljujete greške. Umesto toga koristite komentare o paketu." + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "Ispod unesite razloge zbog kojih je paket zastareo, poželjno i veze ka objavi novog izdanja ili izvornom kodu nove verzije." + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Komentari" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Označi" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "Samo registrovani korisnici mogu označavati pakete zastarelim." + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Spajanje paketa" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Spajanje paketa: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Ovim formularom spajate osnovu paketa %s%s%s sa drugim paketom." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Sledeći paketi će biti obrisani:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Kada se jednom spoje, paketi ne mogu više biti razdvojeni." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Unesite ime paketa sa kojim želite da spojite ovaj paket." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Spoji sa:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrdite spajanje" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Spoji" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Samo Poverljivi korisnici i Programeri mogu da spajaju pakete." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Podnesi zahtev" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zatvori zahtev" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prva" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Prethodna" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sledeća" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Zadnja" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Zahtevi" +#: html/register.php template/header.php msgid "Register" msgstr "Registracija" +#: html/register.php msgid "Use this form to create an account." msgstr "Ovim formularom pravite nalog." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Poverljivi korisnik" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Ne mogu da dobavim detalje o predlogu." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Glasanje o ovom predlogu je završeno." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Samo poverljivi korisnici mogu da glasaju." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Ne možete glasati za predlog koji se odnosi na vas." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Već ste glasali za ovaj predlog." +#: html/tu.php msgid "Vote ID not valid." msgstr "Neispravan ID glasa." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Trenutno glasova" +#: html/tu.php msgid "Past Votes" msgstr "Prethodni glasovi" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Glasači" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Registrovanje naloga sa vaše IP adrese je onemogućeno, najverovatnije usled " -"napada spama. Oprostite na neprijatnosti." +msgstr "Registrovanje naloga sa vaše IP adrese je onemogućeno, najverovatnije usled napada spama. Oprostite na neprijatnosti." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Nedostaje ID korisnika" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Neispravno korisničko ime." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Mora imati između %s i %s znakova." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Počnje i završava slovom ili brojem" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržati samo jedan razmak, podvlaku ili crticu." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Neispravna adresa e-pošte." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Otisak PGP ključa nije ispravan." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Neispravan javni SSH ključ." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Ne mogu da uvećam dozvole naloga." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Korisničko ime %s%s%s je već u upotrebi." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s je već u upotrebi." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Javni SSH ključ %s%s%s je već u upotrebi." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Greška pri pravljenju naloga %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Nalog %s%s%s je uspešno napravljen." -msgid "Click on the Login link above to use your account." -msgstr "Kliknite iznad na vezu Prijava da bi koristili svoj nalog." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Dobrodošli u %s! Da bi postavili početnu lozinku za vaš novi nalog, kliknite " -"na vezu ispod. Ukoliko veza ne radi, probate da je iskopirate u vaš veb " -"pregledač." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ključ za resetovanje lozinke je poslat na vašu adresu e-pošte." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Kliknite iznad na vezu Prijava da bi koristili svoj nalog." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nisu izvršene nikakve izmene naloga %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Nalog %s%s%s je uspešno izmenjen." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Formular za prijavljivanje je trenutno onemogućen za vašu IP adresu, " -"najverovatnije usled napada spama. Oprostite na neprijatnosti." +msgstr "Formular za prijavljivanje je trenutno onemogućen za vašu IP adresu, najverovatnije usled napada spama. Oprostite na neprijatnosti." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Nalog je suspendovan" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Vaša lozinka je resetovana. Ukoliko ste tek napravili nov nalog, molimo " -"upotrebite vezu iz e-pisma za potvrdu kako bi postavili početnu lozinku. U " -"suprotnom, zatražite resetovajne ključa putem stranice %sResetovanje lozinke" -"%s." +msgstr "Vaša lozinka je resetovana. Ukoliko ste tek napravili nov nalog, molimo upotrebite vezu iz e-pisma za potvrdu kako bi postavili početnu lozinku. U suprotnom, zatražite resetovajne ključa putem stranice %sResetovanje lozinke%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Loše korisničko ime ili lozinka." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Došlo je do greške pri pravljenju korisničke sesije." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Neispravna kombinacija e-pošte i ključa za resetovanje." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nema" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Prikaži podatke o nalogu za %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "Nedostaje ID ili ime baze paketa." + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "Nemate dozvolu za uređivanje ovog komentara." + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "Komentar ne postoji." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "Komentar ne sme biti prazan." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Komentar je dodat." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Greška pri dobavaljanju podataka o paketu." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Ne mogu naći podatke o paketu." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Morate se prijaviti pre označavanja paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Niste izabrali pakete za označavanje." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Izabrani paketi su označeni kao zastareli." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Morate se prijaviti da bi uklonili oznake." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Niste izabrali paket za uklanjanje oznake." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Označenim paketima je uklonjena oznaka." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nemate dozvole za brisanje paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Niste izabrali pakete za brisanje." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Izbrani paketi su obrisani." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Morate se prijaviti da bi usvojili pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Morate se prijaviti da bi ste se odrekli paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Niste izabrali paketa za usvajanje." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Niste izabrali pakete kojih bi da se odreknete." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Izabrani paketi su usvojeni." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Odrekli ste se izabranog paketa." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Morate se prijaviti da bi glasali za pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Morate se prijaviti da bi uklonili glasove za pakete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Niste izabrali pakete za koje glasate." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaši glasovi su uklonjeni za izabrane paketa." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Dali ste glas izabranim paketima." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ne mogu da dodam na spisak za obaveštenja." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Dodati ste na spisak za obaveštenja o %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Uklonjeni ste sa spiska obaveštavanja o komentarima za %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Morate se prijaviti da bi ste uređivali podatke o paketu." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Nedostaje ID komentara." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentar je obrisan." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nije vam dozvoljeno brisanje ovog komentara." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "Komentar je uređen." + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nije vam dozvoljeno da uređujete ključne reči za ovu osnovu paketa." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ključne reči baze paketa su ažurirane." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nije vam dozvvoljeno da upravljate koodržavaocima ove osnove paketa." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Neispravno korisničko ime: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Koodržavaoci osnove baze paketa su ažurirani." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Prikaži detalje paketa za" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "zahteva %s" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Morate se prijaviti da bi slali zahteve za pakete." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neispravno ime: dozvoljena su samo mala slova." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Polje komentara ne sme biti prazno." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Neispravan tip zahteva" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Zahtev je uspešno dodat." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Neispravan razlog." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Samo Poverljivi korisnici i programeri mogu zatvarati zahteve." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Zahtev je uspešno zatvoren." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ovim možete trajno obrisati nalog %s iz AUR-a." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUPOZORENJE%s: ova radnja se ne može opozvati" +#: template/account_delete.php msgid "Confirm deletion" msgstr "Potvrda brisanja" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Korisničko ime" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip naloga" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Korisnik" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Programer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Poverljivi korisnik i programer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresa e-pošte" +#: template/account_details.php +msgid "hidden" +msgstr "skrivena" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Pravo ime" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC nadimak" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Otisak PGP ključa" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Neaktivan od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivan" +#: template/account_details.php msgid "Last Login" msgstr "Poslednje prijavljivanje" +#: template/account_details.php msgid "Never" msgstr "Nikad" +#: template/account_details.php msgid "View this user's packages" msgstr "Pregledaj korisnikove pakete" +#: template/account_details.php msgid "Edit this user's account" msgstr "Uređivanje naloga ovog korisnika" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %sovde%s ako želite trajno brisanje ovog naloga." +#: template/account_edit_form.php msgid "required" msgstr "neophodno" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Običan korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Poverljivi korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Nalog je suspendovan" +#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktivan" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "Proverite da li ste ispravno uneli adresu e-pošte, inače će vam pristup biti odbijen." + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "Skrij adresu e-pošte" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Ponovo unesite lozinku" +#: template/account_edit_form.php msgid "Language" msgstr "Jezik" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Sledeće informacije su neophodne ako želite da prilažete pakete u Arčovu " -"korisničku riznicu." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Sledeće informacije su neophodne ako želite da prilažete pakete u Arčovu korisničku riznicu." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Javni SSH ključ" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Ažuriraj" +#: template/account_edit_form.php msgid "Create" msgstr "Napravi" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetuj" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nema rezultata koji se poklapaju sa kriterijumom pretrage." +#: template/account_search_results.php msgid "Edit Account" msgstr "Uredi nalog" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendovan" +#: template/account_search_results.php msgid "Edit" msgstr "Uredi" +#: template/account_search_results.php msgid "Less" msgstr "Manje" +#: template/account_search_results.php msgid "More" msgstr "Više" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nema daljih rezultata." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Upravljanje koodržavaocima: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Ovim formularom dodajete koodržavaoce za %s%s%s (jedno korisničko ime po " -"liniji):" +msgstr "Ovim formularom dodajete koodržavaoce za %s%s%s (jedno korisničko ime po liniji):" +#: template/comaintainers_form.php msgid "Users" msgstr "Korisnici" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Sačuvaj" +#: template/header.php msgid "My Packages" msgstr "Moji paketi" +#: template/header.php msgid " My Account" msgstr "Moj nalog" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Radnje nad paketom" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Prikaži PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Prikaz izmena" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Preuzimanje snimka" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Pretraži wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Označen kao zastareo" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Označi kao zastareo" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Odznači paket" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Ukloni glas" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Glasajte za paket" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Ugasi obaveštenja" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Obavesti o novim komentarima" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Upravljanje koodržavaocima" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -977,169 +1279,232 @@ msgstr[0] "%d zahtev na čekanju" msgstr[1] "%d zahteva na čekanju" msgstr[2] "%d zahteva na čekanju" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Obriši paket" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Spoji paket" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Usvoji paket" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "nepoznata" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Podaci o bazi paketa" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL za git kloniranje" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "samo za čitanje" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Ključne reči" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Pošiljalac" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Održavalac" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Poslednji paketar" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Glasova" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Popularnost" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvi put priloženo" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Poslednje ažuriranje" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "Uređivanje komentara za: %s" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Dodaj komentar" -msgid "Comment has been added." -msgstr "Komentar je dodat." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Prikaži sve komentare" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Poslednji komentari" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "%s postavi komentar za %s" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "Anoniman komentar za %s" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "%s obrisa %s" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "poslednja izmena %s od %s" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Obriši komentar" -#, php-format -msgid "Comment by %s" -msgstr "Komentar od %s" - -msgid "Anonymous comment" -msgstr "Anoniman komentar" - -msgid "deleted" -msgstr "obrisan" - +#: template/pkg_comments.php msgid "All comments" msgstr "Svi komentari" +#: template/pkg_details.php msgid "Package Details" msgstr "Podaci o paketu" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Osnova paketa" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Uzvodni URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Poseti sajt za" +#: template/pkg_details.php msgid "Licenses" msgstr "Licence" +#: template/pkg_details.php msgid "Groups" msgstr "Grupe" +#: template/pkg_details.php msgid "Conflicts" msgstr "Sukobi" +#: template/pkg_details.php msgid "Provides" msgstr "Dostavlja" +#: template/pkg_details.php msgid "Replaces" msgstr "Smenjuje" +#: template/pkg_details.php msgid "Dependencies" msgstr "Zavisnosti" +#: template/pkg_details.php msgid "Required by" msgstr "Zahteva ga" +#: template/pkg_details.php msgid "Sources" msgstr "Izvori" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Zatvaranje zahteva: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Ovim formularom zatvarate zahteve za osnovu paketa %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Beleška" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Polje komentara može ostati prazno. Međutim, preporučujemo da uvek dodate " -"komentar pri odbijanju zahteva." +msgstr "Polje komentara može ostati prazno. Međutim, preporučujemo da uvek dodate komentar pri odbijanju zahteva." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razlog" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Prihvaćeno" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Odbijeno" -msgid "Comments" -msgstr "Komentari" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Slanje zahteva: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Ovim formularom pošaljite zahtev vezan za osnovu paketa %s%s%s koja sadrži " -"sledeće pakete:" +msgstr "Ovim formularom pošaljite zahtev vezan za osnovu paketa %s%s%s koja sadrži sledeće pakete:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tip zahteva" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Brisanje" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Siročić" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Stopi sa" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1147,23 +1512,29 @@ msgstr[0] "%d zahtev za paket." msgstr[1] "%d zahteva za paket." msgstr[2] "%d zahteva za paket." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Stranica %d od %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Posla" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Preostalo dana: ~%d" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1171,90 +1542,116 @@ msgstr[0] "Preostao ~%d čas" msgstr[1] "Preostala ~%d časa" msgstr[2] "Preostalo ~%d časova" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 sata preostalo" +#: template/pkgreq_results.php msgid "Accept" msgstr "Prihvati" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zaključano" +#: template/pkgreq_results.php msgid "Close" msgstr "Zatvori" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zatvoreno" +#: template/pkg_search_form.php msgid "Name, Description" -msgstr "ime, opis" +msgstr "Ime, opis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "samo ime" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Tačno ime" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Tačna osnova paketa" +#: template/pkg_search_form.php msgid "All" msgstr "svi" +#: template/pkg_search_form.php msgid "Flagged" msgstr "označeni" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "neoznačeni" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Ime" -msgid "Popularity" -msgstr "Popularnost" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Dat glas" -msgid "Age" -msgstr "Starost" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "Poslednja izmena" +#: template/pkg_search_form.php msgid "Ascending" msgstr "rastući" +#: template/pkg_search_form.php msgid "Descending" msgstr "opadajući" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Unesite kriterijum pretrage" +#: template/pkg_search_form.php msgid "Search by" msgstr "Traži se" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastareli paketi" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Složi prema" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Način ređanja" +#: template/pkg_search_form.php msgid "Per page" msgstr "Po stranici" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Idi" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Siročići" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Greška pri pruzimanju spiska paketa." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nijedan paket ne odgovara kriterijumu pretrage." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1262,121 +1659,154 @@ msgstr[0] "Nađen %d paket." msgstr[1] "Nađena %d paketa." msgstr[2] "Nađeno %d paketa." +#: template/pkg_search_results.php msgid "Version" msgstr "Verzija" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"Popularnost se izračunava kao suma svih glasova, gde glas ima faktor težine " -"0,98 za svaki dan od njegovog nastanka." +msgstr "Popularnost se izračunava kao suma svih glasova, gde glas ima faktor težine 0,98 za svaki dan od njegovog nastanka." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Da" +#: template/pkg_search_results.php msgid "orphan" msgstr "sirčoić" +#: template/pkg_search_results.php msgid "Actions" msgstr "Radnje" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Označi kao zastareo" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Ukloni oznaku zastarelosti" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Usvoji paket" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odrekni se paketa" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Obriši pakete" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrdi" +#: template/search_accounts_form.php msgid "Any type" msgstr "Bilo koji tip" +#: template/search_accounts_form.php msgid "Search" msgstr "Pretraži" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistika" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paketa siročića" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paketa dodato u zadnjih 7 dana" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paketa ažurirano u zadnjih 7 dana" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paketa ažurirano prethodne godine" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paketa koji nikad nisu ažurirani" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovanih korisnika" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Poverljivih korisnika" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedavno ažurirano" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moja statistika" -msgid "Packages in unsupported" -msgstr "Paketa u [unsupported]" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalji predloga" +#: template/tu_details.php msgid "This vote is still running." msgstr "Glasanje u toku." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Priloženo: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Ističe" +#: template/tu_details.php msgid "Result" msgstr "Rezultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" +#: template/tu_details.php msgid "Abstain" msgstr "Uzdržan" +#: template/tu_details.php msgid "Total" msgstr "Ukupno" +#: template/tu_details.php msgid "Participation" msgstr "Učešće" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Poslednji glasovi od TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Poslednji glas" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nema rezultata." +#: template/tu_list.php msgid "Start" msgstr "Pokrenut" +#: template/tu_list.php msgid "Back" msgstr "Nazad" diff --git a/po/tr.po b/po/tr.po index 35f44145..cf04d40d 100644 --- a/po/tr.po +++ b/po/tr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Atilla Öntaş , 2011,2013-2015 # Atilla Öntaş , 2012,2014 @@ -14,1384 +14,1799 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:45+0000\n" -"Last-Translator: Atilla Öntaş \n" -"Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" -"tr/)\n" -"Language: tr\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: tr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Sayfa Bulunamadı" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Üzgünüz, talep ettiğiniz sayfa bulunamadı." +#: html/503.php msgid "Service Unavailable" msgstr "Hizmete Erişilemiyor" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Paniklemeyin! Bu site bakım çalışmaları nedeniyle erişime kapatıldı. Kısa " -"süre sonra yeniden çalışmaya başlayacak" +msgstr "Paniklemeyin! Bu site bakım çalışmaları nedeniyle erişime kapatıldı. Kısa süre sonra yeniden çalışmaya başlayacak" +#: html/account.php msgid "Account" msgstr "Hesap" +#: html/account.php template/header.php msgid "Accounts" msgstr "Hesaplar" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Bu alana erişim izniniz yok." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Belirtilen kullanıcı verileri alınamadı." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Bu hesap üzerinde değişiklik yapma izniniz yok." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Mevcut hesaplar içinde arama yapmak için bu formu kullanın." +#: html/account.php msgid "You must log in to view user information." msgstr "Kullanıcı bilgilerini görmek için giriş yapmalısınız." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Öneri ekle" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Kullanıcı işlemi için geçersiz anahtar." +#: html/addvote.php msgid "Username does not exist." msgstr "Kullanıcı adı bulunamadı." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s için yürürlükte olan bir öneri var." +#: html/addvote.php msgid "Invalid type." msgstr "Geçersiz tür." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Öneri boş olamaz." +#: html/addvote.php msgid "New proposal submitted." msgstr "Yeni öneri gönderildi." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Oylanması için öneri gönder." +#: html/addvote.php msgid "Applicant/TU" msgstr "İstekli/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(uygulanabilir değilse boş)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tür" +#: html/addvote.php msgid "Addition of a TU" msgstr "Bir GK ekleme" +#: html/addvote.php msgid "Removal of a TU" msgstr "Bir GK çıkartma" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Bir GK çıkartma (bildirilmemiş hareketsizlik)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendment of Bylaws" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Öneri" +#: html/addvote.php msgid "Submit" msgstr "Gönder" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Yardımcı bakımcıları Yönet" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "Anasayfa" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"AUR'a hoş geldiniz! Bilgi almak için lütfen %sAUR Kullanıcı Rehberi%s ve " -"%sGK Rehberini%s okuyun." +msgstr "AUR'a hoş geldiniz! Bilgi almak için lütfen %sAUR Kullanıcı Rehberi%s ve %sGK Rehberini%s okuyun." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Eklenen PKGBUILD dosyaları %smutlaka%s %sArch Paket Standartlarına%s " -"uymalıdır aksi takdirde silinecektir. " +msgstr "Eklenen PKGBUILD dosyaları %smutlaka%s %sArch Paket Standartlarına%s uymalıdır aksi takdirde silinecektir. " +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Beğendiğiniz paketleri oylamayı unutmayın!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Burada listelenen paketlerin bazıları [community] deposunda yer almaktadır." +msgstr "Burada listelenen paketlerin bazıları [community] deposunda yer almaktadır." +#: html/home.php msgid "DISCLAIMER" msgstr "FERAGATNAME" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "" -"Desteklenmeyen paketler kullanıcılar tarafından üretilen içeriğe " -"sahiptirler. Bu paketlerin kullanımından doğan risk kullanıcının kendisine " -"aittir." +#: html/home.php msgid "Learn more..." msgstr "Daha fazlasını öğrenin..." +#: html/home.php msgid "Support" msgstr "Destek" +#: html/home.php msgid "Package Requests" msgstr "Paket Talepleri" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Paket ayrıntıları sayfasındaki %sPaket Eylemleri%s kutusunda " -"doldurulabilecek üç tür talep vardır:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Paket ayrıntıları sayfasındaki %sPaket Eylemleri%s kutusunda doldurulabilecek üç tür talep vardır:" +#: html/home.php msgid "Orphan Request" msgstr "Sahipsiz Bırakma Talebi" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Bir paketin sahipliğinin bırakılması talebi, mesela bakımcısının etkin " -"olmaması ve paketin uzun zamandır güncel değil olarak işaretlenmiş olması." +msgstr "Bir paketin sahipliğinin bırakılması talebi, mesela bakımcısının etkin olmaması ve paketin uzun zamandır güncel değil olarak işaretlenmiş olması." +#: html/home.php msgid "Deletion Request" msgstr "Silme Talebi" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Bir paketin Arch Kullanıcı Deposundan kaldırılması talebidir. Lütfen bunu, " -"bir paket çalışmıyor fakat kolayca düzeltilebiliyorsa kullanmayın. Bunun " -"yerine, paket bakımcısı ile iletişim kurun ve mecbur kalınırsa paketin " -"sahipsiz bırakılması talebinde bulunun." +msgstr "Bir paketin Arch Kullanıcı Deposundan kaldırılması talebidir. Lütfen bunu, bir paket çalışmıyor fakat kolayca düzeltilebiliyorsa kullanmayın. Bunun yerine, paket bakımcısı ile iletişim kurun ve mecbur kalınırsa paketin sahipsiz bırakılması talebinde bulunun." +#: html/home.php msgid "Merge Request" msgstr "Birleştirme Talebi" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Bir paketin bir başkası ile birleştirilmesi talebidir. Bir paketin yeniden " -"adlandırılması veya bir ayrılmış paketle değiştirilmesi gerekiyorsa " -"kullanılabilir." +msgstr "Bir paketin bir başkası ile birleştirilmesi talebidir. Bir paketin yeniden adlandırılması veya bir ayrılmış paketle değiştirilmesi gerekiyorsa kullanılabilir." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Bir talep hakkında tartışmak istiyorsanız, %saur-requests%s e-posta " -"listesini kullanabilirsiniz. Bununla birlikte o e-posta listesini dosya " -"talepleri için kullanmamalısınız." +msgstr "Bir talep hakkında tartışmak istiyorsanız, %saur-requests%s e-posta listesini kullanabilirsiniz. Bununla birlikte o e-posta listesini dosya talepleri için kullanmamalısınız." +#: html/home.php msgid "Submitting Packages" msgstr "Paketleri göndermek" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Artık AUR' a paket göndermek için SSH üzerinden Git kullanılmaktadır. Daha " -"fazla bilgi için Arch Kullanıcı Deposu ArchWiki sayfasındaki %sPaketleri " -"Göndermek%s bölümüne bakın." +msgstr "Artık AUR' a paket göndermek için SSH üzerinden Git kullanılmaktadır. Daha fazla bilgi için Arch Kullanıcı Deposu ArchWiki sayfasındaki %sPaketleri Göndermek%s bölümüne bakın." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR için şu SSH parmak izleri kullanılmaktadır:" +#: html/home.php msgid "Discussion" msgstr "Tartışma" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Arch Kullanıcı Deposu (AUR) ve Güvenilir Kullanıcı yapısı ile ilgili genel " -"tartışmalar %saur-general%s üzerinde yapılır. AUR web arayüzü geliştirme " -"süreci ilgili tartışmalar %saur-dev%s listesinde yapılmaktadır." +msgstr "Arch Kullanıcı Deposu (AUR) ve Güvenilir Kullanıcı yapısı ile ilgili genel tartışmalar %saur-general%s üzerinde yapılır. AUR web arayüzü geliştirme süreci ilgili tartışmalar %saur-dev%s listesinde yapılmaktadır." +#: html/home.php msgid "Bug Reporting" msgstr "Hata Bildirimi" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" -"Eğer AUR'da bir hata ile karşılaştırsanız lütfen %shata takip sistemine%s " -"bildirin. Hata takip sistemini lütfen %ssadece%s AUR sistemi için kullanın. " -"Paketleme hatalarını paket bakımcısı ile iletişime geçerek bildirebilir veya " -"paketle ilgili görüşlerinizi ilgili paketin sayfasında iletebilirsiniz." +#: html/home.php msgid "Package Search" msgstr "Paket Ara" +#: html/index.php msgid "Adopt" msgstr "Sorumluluğunu Al" +#: html/index.php msgid "Vote" msgstr "Oy ver" +#: html/index.php msgid "UnVote" msgstr "Oyu kaldır" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Bilgilendirme" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Bildirimi iptal et" -msgid "Flag" -msgstr "İşaretle" - +#: html/index.php msgid "UnFlag" msgstr "İşareti Kaldır" +#: html/login.php template/header.php msgid "Login" msgstr "Giriş" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "%s olarak giriş yapıldı" +#: html/login.php template/header.php msgid "Logout" msgstr "Çıkış" +#: html/login.php msgid "Enter login credentials" msgstr "Giriş bilgilerinizi doldurun" -msgid "Username" -msgstr "Kullanıcı Adı" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Parola" +#: html/login.php msgid "Remember me" msgstr "Beni hatırla" +#: html/login.php msgid "Forgot Password" msgstr "Parolamı Unuttum" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP oturum açma devredışı. Lütfen oturum açmak için %sHTTPS kullanın%s." +msgstr "HTTP oturum açma devredışı. Lütfen oturum açmak için %sHTTPS kullanın%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Arama Ölçütü" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketler" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Paket ayrıntılarını almaya çalışırken hata oluştu." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Gerekli bir alan doldurulmamış." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Parolalar eşleşmiyor." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Şifreniz en az %s karakterden oluşmalıdır." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Geçersiz e-posta adresi" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"E-posta hesabınızla ilişkilendirilmiş bir %s hesabı için parola sıfırlama " -"isteği gönderilmiş. Parolanızı sıfırlamak istiyorsanız aşağıdaki bağlantıyı " -"izleyin; aksi takdirde bu iletiyi yok sayın ve herhangi bir işlem yapılmasın." - +#: html/passreset.php msgid "Password Reset" msgstr "Parola sıfırlama" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Onaylama bağlantısı için e-posta hesabınızı denetleyin." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Parolanız başarıyla sıfırlandı." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "E-posta adresinizi onaylayın:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Yeni parolanızı girin:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Yeni parolanızı onaylayın:" +#: html/passreset.php msgid "Continue" msgstr "Devam" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Kayıt olurken kullandığınız e-posta adresini hatırlamıyorsanız lütfen %saur-" -"general%s posta listesine mesaj gönderin." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Kayıt olurken kullandığınız e-posta adresini hatırlamıyorsanız lütfen %saur-general%s posta listesine mesaj gönderin." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "E-posta adresinizi girin:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Seçilen paketler için sahiplik bırakılamadı. Onaylama kutucuğunu işaretleyin." +msgstr "Seçilen paketler için sahiplik bırakılamadı. Onaylama kutucuğunu işaretleyin." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Oyların ve yorumların ilişkilendirilebileceği herhangi bir paket bulunamadı." +msgstr "Oyların ve yorumların ilişkilendirilebileceği herhangi bir paket bulunamadı." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Paket temeli kendisi ile birleştirilemiyor." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Seçilen paketler silinmedi. Onaylama kutucuğunu işaretleyin." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Paket Silimi" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Paketi sil: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Bu formu paket temeli %s%s%s ve şu paketleri AUR üzerinden silmek için " -"kullanın: " +msgstr "Bu formu paket temeli %s%s%s ve şu paketleri AUR üzerinden silmek için kullanın: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Paket silme işlemi kalıcıdır." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "İşlemi onaylamak için kutucuğu işaretleyin." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Paket silmeyi onaylayın" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Sil" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paket silebilir." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Paket Sahipliğini Bırak" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Paketi sahiplenmeyi bırak: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Şu paketleri içeren %s%s%s paket temelinin sahipliğini bırakmak için bu " -"formu kullanın:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Şu paketleri içeren %s%s%s paket temelinin sahipliğini bırakmak için bu formu kullanın:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"İşaretleme kutucuğunu seçerek paketin sahipliğini bırakmayı ve sahipliği %s%s" -"%s üzerine geçirmeyi kabul ediyorsunuz." +msgstr "İşaretleme kutucuğunu seçerek paketin sahipliğini bırakmayı ve sahipliği %s%s%s üzerine geçirmeyi kabul ediyorsunuz." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Kutucuğu işaretleyerek paketin sahipliğini bırakmayı kabul ediyorsunuz." +msgstr "Kutucuğu işaretleyerek paketin sahipliğini bırakmayı kabul ediyorsunuz." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Paket sahipliğini bırakmayı onayla" +#: html/pkgdisown.php msgid "Disown" msgstr "Sorumluluğunu bırak" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Sadece geliştiriciler ve güvenilir kullanıcılar paketleri sahipsiz " -"bırakabilir." +msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paketleri sahipsiz bırakabilir." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Yorumlar" + +#: html/pkgflag.php +msgid "Flag" +msgstr "İşaretle" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Paket birleştirme" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Paket Birleştir: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Bu formu paket temeli %s%s%s ile bir başka paketi birleştirmek için " -"kullanın. " +msgstr "Bu formu paket temeli %s%s%s ile bir başka paketi birleştirmek için kullanın. " +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Şu paketler silinecek: " +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Paket birleştirme işlemi geri alınamaz." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Birleştirmek istediğiniz paketin ismini girin." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Şununla birleştir:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Paket birleştirme onayı" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Birleştir" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paket birleştirebilir." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Bir talep doldur" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Kapama Talebi" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "İlk" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Önceki" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "İleri" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Son" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Talepler" +#: html/register.php template/header.php msgid "Register" msgstr "Kayıt ol" +#: html/register.php msgid "Use this form to create an account." msgstr "Yeni bir hesap oluşturmak için bu formu kullanın." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Güvenilen Kullanıcı" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Öneri detayları alınamadı." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Bu öneri için oylama kapanmıştır." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Sadece Güvenilir Kullanıcılar oy kullanabilir." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Sizin hakkınızdaki bir öneride oy kullanamazsınız." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Bu öneri için zaten oy vermişsiniz." +#: html/tu.php msgid "Vote ID not valid." msgstr "Oy kimliği geçersiz." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Mevcut Oylar" +#: html/tu.php msgid "Past Votes" msgstr "Geçmiş Oylar" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Oy verenler" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden hesap " -"oluşturma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +msgstr "Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden hesap oluşturma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Kullanıcı kimliği eksik" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Bu kullanıcı adı geçersizdir." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Uzunluğu %s ve %s karakter arasında olabilir." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Bir rakam veya harf ile başlatıp bitirmelisiniz" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Sadece bir nokta, alt çizgi veya tire barındırabilir." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-posta adresi geçerli değil." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP anahtarı parmak izi hatalı." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH kamu anahtarı geçersiz." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Hesap izinleri yükseltilemiyor." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Dil henüz desteklenmiyor." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Kullanıcı adı, %s%s%s, zaten kullanılıyor." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adres, %s%s%s, zaten kullanılıyor." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH kamu anahtarı, %s%s%s, zaten kullanımda." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Hesap oluşturulurken hata oluştu, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Hesap, %s%s%s, başarıyla oluşturuldu." -msgid "Click on the Login link above to use your account." -msgstr "Hesabınızı kullanmak için Giriş bağlantısını kullanın." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"%s hoş geldiniz! Hesabınız için parolayı ilk kez oluşturmak için lütfen " -"aşağıdaki bağlanıtıyı tıklayın. Bağlantı çalışmazsa onu kopyalayıp " -"tarayıcınıza yapıştırmayı deneyin." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Bir parola sıfırlama anahtarı e-posta adresinize gönderildi." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Hesabınızı kullanmak için Giriş bağlantısını kullanın." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Hesapta değişiklik yapılmadı, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Hesap, %s%s%s, başarıyla düzenlendi." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden giriş " -"yapma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +msgstr "Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden giriş yapma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Hesap donduruldu" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Parolanız sıfırlandı. Kısa süre önce yeni hesap oluşturduysanız lütfen, ilk " -"parolanızı ayarlamak için onaylama e-postasındaki bağlantıyı kullanın. Aksi " -"takdirde, %sParola Sıfırlama%s sayfasında bir sıfırlama anahtarı talep edin." +msgstr "Parolanız sıfırlandı. Kısa süre önce yeni hesap oluşturduysanız lütfen, ilk parolanızı ayarlamak için onaylama e-postasındaki bağlantıyı kullanın. Aksi takdirde, %sParola Sıfırlama%s sayfasında bir sıfırlama anahtarı talep edin." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Yanlış kullanıcı adı veya şifresi." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Bir kullanıcı oturumu üretilmeye çalışılırken sorun oluştu." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Geçersiz e-posta adresi ve sıfırlama anahtarı bileşimi" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Yok" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "%s için hesap bilgilerini görüntüle" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Yorum eklendi." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Paket bilgileri alınırken hata oluştu." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paket ayrıntıları bulunamadı." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Paketleri işaretleyebilmek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "İşaretlenecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Seçilen paketler güncelliğini yitirmiş olarak işaretlendi." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Paketlerin işaretini kaldırabilmek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "İşareti kaldırılacak paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Seçilen paketlerin işareti kaldırıldı." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Paket silmek için gerekli izne sahip değilsiniz." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Silinecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Seçilen paketler silindi." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Paketleri sahiplenmek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Paketlerin sahipliğini bırakmak için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Sahiplenilecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Sahipliği bırakılacak paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Seçilen paketler sahiplenildi." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Seçilen paketlerin sahipliği bırakıldı." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Paketlere oy vermeden önce giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Oy iptali için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Oy verilecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Seçtiğiniz paketlerden oyunuz geri alındı." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Seçtiğiniz paketlere oyunuz eklendi." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Bildirim listesine ekleme işlemi başarısız oldu." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "%s bildirim listesine başarıyla eklendiniz." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "%s bildirim listesinden başarıyla çıktınız." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Paket bilgilerini güncellemek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Yorum kimliği bulunamadı." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Yorum silindi." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Bu yorumu silme yetkiniz yok." -msgid "You are not allowed to edit the keywords of this package base." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." msgstr "" -"Bu paket temelinin anahtar kelimelerini düzenleme yetkisine sahip değilsiniz." +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Bu paket temelinin anahtar kelimelerini düzenleme yetkisine sahip değilsiniz." + +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Paket temeli anahtar kelimeleri güncellendi." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Bu paket temelinin yardımcı bakımcılarını yönetme yetkisine sahip değilsiniz." +msgstr "Bu paket temelinin yardımcı bakımcılarını yönetme yetkisine sahip değilsiniz." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Geçersiz kullanıcı adı: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Paket temeli yardımcı bakımcıları güncellendi." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Paket detaylarını görüntüle" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Paket gereksinimlerinin kaydını tutmalısın." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Geçersiz isim: yalnızca küçük harf kullanılabilir." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Yorum alanı boş olmamalı." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Geçersiz talep türü." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Talep başarıyla eklendi." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Geçersiz sebep." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Sadece GK'lar ve geliştiriciler talepleri kapatabilirler." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Talep başarıyla kapatıldı." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Bu formu kullanarak %s AUR hesabını temelli silebilirsiniz." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUYARI%s: Bu eylem geri döndürülemez." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Silmeyi onayla" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Kullanıcı Adı" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Hesap Türü" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Kullanıcı" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Geliştirici" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Güvenilir Kullanıcı & Geliştirici" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-posta adresi" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Gerçek İsim" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Rumuzu" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP Anahtar Parmak İzi" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Durum" +#: template/account_details.php msgid "Inactive since" msgstr "Şu tarihten beri etkin değil:" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Etkin" +#: template/account_details.php msgid "Last Login" msgstr "Son giriş" +#: template/account_details.php msgid "Never" msgstr "Hiç" +#: template/account_details.php msgid "View this user's packages" msgstr "Bu kullanıcı tarafından hazırlanan paketleri göster" +#: template/account_details.php msgid "Edit this user's account" msgstr "Bu kullanıcının hesabını düzenleyin" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Bu hesabı temelli olarak silmek istiyorsanız %sburaya%s tıklayın." +#: template/account_edit_form.php msgid "required" msgstr "gerekli" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normal kullanıcı" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Güvenilen kullanıcı" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Hesap Donduruldu" +#: template/account_edit_form.php msgid "Inactive" msgstr "Etkin değil" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Parolayı tekrar girin" +#: template/account_edit_form.php msgid "Language" msgstr "Dil" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Aşağıdaki bilgi sadece Arch Kullanıcı Deposu' na paket göndermek " -"istiyorsanız gereklidir." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Aşağıdaki bilgi sadece Arch Kullanıcı Deposu' na paket göndermek istiyorsanız gereklidir." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH Kamu Anahtarı" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Güncelle" +#: template/account_edit_form.php msgid "Create" msgstr "Oluştur" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Sıfırla" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Arama ölçütünzle eşleşen bir sonuç bulunamadı." +#: template/account_search_results.php msgid "Edit Account" msgstr "Hesap Bilgilerini Düzenle" +#: template/account_search_results.php msgid "Suspended" msgstr "Donduruldu" +#: template/account_search_results.php msgid "Edit" msgstr "Düzenle" +#: template/account_search_results.php msgid "Less" msgstr "Az" +#: template/account_search_results.php msgid "More" msgstr "Fazla" +#: template/account_search_results.php msgid "No more results to display." msgstr "Gösterilecek daha fazla sonuç yok." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Yardımcı bakımcıları yönet: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"%s%s%s için yardımcı bakımcı eklemek istiyorsanız bu formu kullannı (her " -"satırda bir kullanıcı adı):" +msgstr "%s%s%s için yardımcı bakımcı eklemek istiyorsanız bu formu kullannı (her satırda bir kullanıcı adı):" +#: template/comaintainers_form.php msgid "Users" msgstr "Kullanıcılar" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Kaydet" +#: template/header.php msgid "My Packages" msgstr "Paketlerim" +#: template/header.php msgid " My Account" msgstr "Hesabım" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Paket Eylemleri" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD görüntüle" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Değişiklikleri Görüntüle" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Anlık görüntüsünü indir" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Wikide ara" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Güncelliğini yitirmiş olarak işaretlendi" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Güncelliğini yitirmiş olarak işaretle" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "İşareti kaldır" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Oyu kaldır" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Pakete oy ver" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Bildirimleri kapat" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Yeni yorumları bildir" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Yardımcı Bakımcıları Yönet" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d adet bekleyen talep" msgstr[1] "%d adet bekleyen talep" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Paketi Sil" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Paketi Birleştir" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Paketi Sahiplen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "bilinmiyor" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Paket Temeli Ayrıntıları" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "salt okunur" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Anahtar kelimeler" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Yükleyen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Sorumlu" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Son Paketleyici" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Oy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Beğenilme" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "İlk Yükleme" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Son Güncelleme" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Yorum Ekle" -msgid "Comment has been added." -msgstr "Yorum eklendi." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Tüm yorumları görünüle" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Son Yorumlar" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Yorumu sil" -#, php-format -msgid "Comment by %s" -msgstr "%s yorumu" - -msgid "Anonymous comment" -msgstr "İsimsiz yorum" - -msgid "deleted" -msgstr "silindi" - +#: template/pkg_comments.php msgid "All comments" msgstr "Tüm yorumlar" +#: template/pkg_details.php msgid "Package Details" msgstr "Paket Ayrıntıları" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paket Temeli" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Açıklama" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Geliştiricinin Bağlantısı" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Web sayfasını görüntüle" +#: template/pkg_details.php msgid "Licenses" msgstr "Lisanslar" +#: template/pkg_details.php msgid "Groups" msgstr "Gruplar" +#: template/pkg_details.php msgid "Conflicts" msgstr "Çakışır" +#: template/pkg_details.php msgid "Provides" msgstr "Sunar" +#: template/pkg_details.php msgid "Replaces" msgstr "Yerini alır" +#: template/pkg_details.php msgid "Dependencies" msgstr "Bağımlılıklar" +#: template/pkg_details.php msgid "Required by" msgstr "İhtiyaç duyanlar" +#: template/pkg_details.php msgid "Sources" msgstr "Kaynak kodlar" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Kapatma Talebi: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Bu formu %s%s%s paket temeli için yapılan talebi kapatmak için kullanın." +msgstr "Bu formu %s%s%s paket temeli için yapılan talebi kapatmak için kullanın." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Not" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Yorum alanı boş bırakılabilir. Ancak, bir talebi reddederken bir yorum " -"eklemeniz şiddetle önerilir." +msgstr "Yorum alanı boş bırakılabilir. Ancak, bir talebi reddederken bir yorum eklemeniz şiddetle önerilir." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Sebep" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Kabul edildi" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Reddedildi" -msgid "Comments" -msgstr "Yorumlar" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Dosya Talebi: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Bu formu kullanarak aşağıdaki paketleri içeren paket temeli %s%s%s için " -"talep doldurun:" +msgstr "Bu formu kullanarak aşağıdaki paketleri içeren paket temeli %s%s%s için talep doldurun:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Talep türü" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Silme" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Öksüz" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Şununla ilişkilendir:" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d adet paket talebi bulundu." msgstr[1] "%d adet paket talebi bulundu." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Sayfa %d / %d" +#: template/pkgreq_results.php msgid "Package" msgstr "Paket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Dolduran" +#: template/pkgreq_results.php msgid "Date" msgstr "Tarih" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d gün kaldı" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d saat kaldı" msgstr[1] "~%d saat kaldı" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 saat kaldı" +#: template/pkgreq_results.php msgid "Accept" msgstr "Kabul" +#: template/pkgreq_results.php msgid "Locked" msgstr "Kilitli" +#: template/pkgreq_results.php msgid "Close" msgstr "Kapat" +#: template/pkgreq_results.php msgid "Closed" msgstr "Kapandı" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "İsim, Açıklama" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Sadece İsim" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Tam Ad" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Tam Paket Temeli" +#: template/pkg_search_form.php msgid "All" msgstr "Tümü" +#: template/pkg_search_form.php msgid "Flagged" msgstr "İşaretlenmiş" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "İşaretlenmemiş" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "İsim" -msgid "Popularity" -msgstr "Beğenilme" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Oylanmış" -msgid "Age" -msgstr "Tarih" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Eskiden yeniye" +#: template/pkg_search_form.php msgid "Descending" msgstr "Yeniden eskiye" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Arama kriteri girin" +#: template/pkg_search_form.php msgid "Search by" msgstr "Buna göre ara" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Güncelliğini Yitirmiş" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sırala" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sıralama düzeni" +#: template/pkg_search_form.php msgid "Per page" msgstr "Her sayfa" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Git" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Sahipsiz" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Paket listesi alınırken hata oluştu." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Arama ölçütünüz ile eşleşen paket bulunamadı." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d adet paket bulundu." msgstr[1] "%d adet paket bulundu." +#: template/pkg_search_results.php msgid "Version" msgstr "Sürüm" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"Beğenilirlik, oluşturulmasından itibaren günlük 0.98 oranı ile çarpılarak " -"bulunan her oyun toplamı ile ölçülür." +msgstr "Beğenilirlik, oluşturulmasından itibaren günlük 0.98 oranı ile çarpılarak bulunan her oyun toplamı ile ölçülür." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Evet" +#: template/pkg_search_results.php msgid "orphan" msgstr "sahipsiz" +#: template/pkg_search_results.php msgid "Actions" msgstr "Eylemler" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Güncelliğini yitirmiş olarak işaretle" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "\"Güncelliğini Yitirmiş\" İşaretini Kaldır" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Paketleri Sahiplen" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Paketleri sahiplenmeyi bırak" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Paketleri Sil" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Onayla" +#: template/search_accounts_form.php msgid "Any type" msgstr "Herhangi bir tür" +#: template/search_accounts_form.php msgid "Search" msgstr "Ara" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "İstatistikler" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Sahipsiz Paketler" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Son 7 günde eklenen paketler" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Son 7 günde güncellenen paketler" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Geçtiğimiz yıl güncellenen paketler" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Hiç güncellenmemiş paketler" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Kayıtlı Kullanıcılar" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Güvenilen Kullanıcılar" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Son Güncellemeler" +#: template/stats/user_table.php msgid "My Statistics" msgstr "İstatistiklerim" -msgid "Packages in unsupported" -msgstr "Desteklenmeyen paketler" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Öneri Detayları" +#: template/tu_details.php msgid "This vote is still running." msgstr "Bu oylama hala yürürlükte." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Yüklendi: %s %s tarafından" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Son" +#: template/tu_details.php msgid "Result" msgstr "Sonuç" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Hayır" +#: template/tu_details.php msgid "Abstain" msgstr "Çekimser" +#: template/tu_details.php msgid "Total" msgstr "Toplam" +#: template/tu_details.php msgid "Participation" msgstr "Katkı" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "GK tarafından verilen son oylar" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Son Oy" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Sonuç bulunamadı." +#: template/tu_list.php msgid "Start" msgstr "Başlangıç" +#: template/tu_list.php msgid "Back" msgstr "Geri" diff --git a/po/uk.po b/po/uk.po index 078b3887..ce607299 100644 --- a/po/uk.po +++ b/po/uk.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Lukas Fleischer , 2011 # Rax Garfield , 2012 @@ -12,977 +12,1268 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:54+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 06:13+0000\n" "Last-Translator: Yarema aka Knedlyk \n" -"Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" -"uk/)\n" -"Language: uk\n" +"Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Language: uk\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +#: html/404.php msgid "Page Not Found" msgstr "Сторінку не знайдено" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "На жаль, запитаної сторінки не існує." +#: html/503.php msgid "Service Unavailable" msgstr "Сервіс недоступний" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Не панікуйте! Сторінка закрита на технічне обслуговування. Ми швидко " -"повернемося." +msgstr "Не панікуйте! Сторінка закрита на технічне обслуговування. Ми швидко повернемося." +#: html/account.php msgid "Account" msgstr "Обліковий запис" +#: html/account.php template/header.php msgid "Accounts" msgstr "Облікові записи" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "У вас недостатньо прав доступу." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Не вдалося отримати інформацію про вказаного користувача." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "У вас недостатньо прав для редагування цього облікового запису." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Шукайте облікові записи за допомогою цієї форми." +#: html/account.php msgid "You must log in to view user information." msgstr "Ви повинні увійти в систему для перегляду даних користувача." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Додати пропозицію" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Невірний маркер для дій користувача." +#: html/addvote.php msgid "Username does not exist." msgstr "Користувача не існує." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s вже мають зареєстровану на себе пропозицію." +#: html/addvote.php msgid "Invalid type." msgstr "Неправильний тип." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Пропозиція не може бути порожньою." +#: html/addvote.php msgid "New proposal submitted." msgstr "Нову пропозицію надіслано." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Надіслати пропозицію для голосування." +#: html/addvote.php msgid "Applicant/TU" msgstr "Претендент/Довірений користувач" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(Порожньо, якщо не застосовується)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Тип" +#: html/addvote.php msgid "Addition of a TU" msgstr "Додавання довіреного користувача" +#: html/addvote.php msgid "Removal of a TU" msgstr "Вилучення довіреного користувача" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Вилучення довіреного користувача (неоголошена бездіяльність)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Поправки до Статуту" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Пропозиція" +#: html/addvote.php msgid "Submit" msgstr "Надіслати пакунок" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Керування супровідниками" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "Редагувати коментар" + +#: html/home.php template/header.php msgid "Home" msgstr "Початкова сторінка" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Раді вітати вас в «AUR» — у сховищі користувацьких пакунків. Розширена " -"довідка надана в %sінструкції користувача AUR%s та %sінструкції довіреного " -"користувача (TU) AUR%s." +msgstr "Раді вітати вас в «AUR» — у сховищі користувацьких пакунків. Розширена довідка надана в %sінструкції користувача AUR%s та %sінструкції довіреного користувача (TU) AUR%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Надіслані PKGBUILD %sповинні%s задовольняти %sстандарти пакування%s, інакше " -"вони вилучаються." +msgstr "Надіслані PKGBUILD %sповинні%s задовольняти %sстандарти пакування%s, інакше вони вилучаються." +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Не забудьте проголосувати за улюблені пакунки!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Деякі пакунки можуть бути в бінарному вигляді у сховищі [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ВІДМОВА ВІД ВІДПОВІДАЛЬНОСТІ" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." -msgstr "" -"Пакунки, що не підтримуються - це пакунки, створені користувачами. Ви можете " -"використовувати їх тільки на Ваш власний страх і ризик." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." +msgstr "Пакунки у сховищі AUR - це пакунки, створені користувачами. Ви можете використовувати їх тільки на Ваш власний страх і ризик." +#: html/home.php msgid "Learn more..." msgstr "Дізнатись більше..." +#: html/home.php msgid "Support" msgstr "Підтримка" +#: html/home.php msgid "Package Requests" msgstr "Запит пакунку" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Існують три типи запитів, які можна заповнити в полі %sДія над пакунком%s на " -"сторінці подробиць пакунку:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Існують три типи запитів, які можна заповнити в полі %sДія над пакунком%s на сторінці подробиць пакунку:" +#: html/home.php msgid "Orphan Request" msgstr "Запит на покинення пакунку" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Запит на позбавлення пакунка власника, наприклад, коли супровідник пакунку " -"неактивний і пакунок позначений як застарілий вже довгий період часу." +msgstr "Запит на позбавлення пакунка власника, наприклад, коли супровідник пакунку неактивний і пакунок позначений як застарілий вже довгий період часу." +#: html/home.php msgid "Deletion Request" msgstr "Запит на вилучення" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Запит на вилучення пакунку зі Сховища Користувацьких Пакунків AUR. Будь " -"ласка, не використовуйте це, якщо пакунок є зламаний і його можна легко " -"направити. Для цього зв’яжіться з супровідником пакунку і заповніть форму на " -"покинення пакунку в разі необхідності." +msgstr "Запит на вилучення пакунку зі Сховища Користувацьких Пакунків AUR. Будь ласка, не використовуйте це, якщо пакунок є зламаний і його можна легко направити. Для цього зв’яжіться з супровідником пакунку і заповніть форму на покинення пакунку в разі необхідності." +#: html/home.php msgid "Merge Request" msgstr "Запит на злиття" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Запит на злиття пакунку з іншим пакунком. Цей запит можна використати, коли " -"потрібно перейменувати пакунок або замінити на розділений пакунок." +msgstr "Запит на злиття пакунку з іншим пакунком. Цей запит можна використати, коли потрібно перейменувати пакунок або замінити на розділений пакунок." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Якщо Ви бажаєте обговорити запит, використайте список розсилки %saur-requests" -"%s. Будь ласка, не використовуйте цю розсилку для подання запитів." +msgstr "Якщо Ви бажаєте обговорити запит, використайте список розсилки %saur-requests%s. Будь ласка, не використовуйте цю розсилку для подання запитів." +#: html/home.php msgid "Submitting Packages" msgstr "Надсилання пакунків" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git через SSH тепер використовується для надсилання пакунків до AUR. Для " -"деталей дивіться розділ %sНадсилання пакунків%s на сторінці ArchWiki про " -"Сховище Користувацьких Пакунків AUR." +msgstr "Git через SSH тепер використовується для надсилання пакунків до AUR. Для деталей дивіться розділ %sНадсилання пакунків%s на сторінці ArchWiki про Сховище Користувацьких Пакунків AUR." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Наступні відбитки ключів SSH використовуються в AUR:" +#: html/home.php msgid "Discussion" msgstr "Обговорення" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Загальне обговорення сховища користувацьких пакунків (AUR) та структури " -"довірених користувачів відбувається в %saur-general%s. Для дискусій про " -"розробку AUR використовуйте список розсилання %saur-dev%s." +msgstr "Загальне обговорення сховища користувацьких пакунків (AUR) та структури довірених користувачів відбувається в %saur-general%s. Для дискусій про розробку AUR використовуйте список розсилання %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Повідомлення про вади" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." -msgstr "" -"Якщо Ви знайдете ваду в AUR, %sповідомте нам%s. Таким чином слід сповіщати " -"%sлише%s про проблеми AUR. При виявленні вади конкретного пакунка зв’яжіться " -"з його супровідником або залиште коментар на сторінці цього пакунка." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Якщо Ви знайдете ваду у веб-інтерфейсі AUR, повідомте про це нас на нашому %sтрекері вад%s. Таким чином слід сповіщати %sлише%s про проблеми у веб-інтерфейсі AUR. Про вади пакунка зв’яжіться з його супровідником або залиште коментар на відповідній сторінці цього пакунка." +#: html/home.php msgid "Package Search" msgstr "Пошук пакунків" +#: html/index.php msgid "Adopt" msgstr "Прийняти" +#: html/index.php msgid "Vote" msgstr "Проголосувати" +#: html/index.php msgid "UnVote" msgstr "Забрати голос" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Сповіщати" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Не сповіщати" -msgid "Flag" -msgstr "Позначити" - +#: html/index.php msgid "UnFlag" msgstr "Зняти позначку" +#: html/login.php template/header.php msgid "Login" msgstr "Увійти" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Ввійшов як: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Вийти" +#: html/login.php msgid "Enter login credentials" msgstr "Увійдіть, ввівши облікові дані." -msgid "Username" -msgstr "Користувач" +#: html/login.php +msgid "User name or email address" +msgstr "Назва користувача або адреса електронної пошти" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Пароль" +#: html/login.php msgid "Remember me" msgstr "Запам'ятати мене" +#: html/login.php msgid "Forgot Password" msgstr "Забули пароль?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Реєстрування через HTTP вимкнено. Будь-ласка, %sперейдіть на HTTPs%s для " -"входу." +msgstr "Реєстрування через HTTP вимкнено. Будь-ласка, %sперейдіть на HTTPs%s для входу." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Критерії пошуку" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Пакунки" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Стався збій під час пошуку інформації про пакунок." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Бракує обов’язкового рядка." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Паролі не збігаються." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Ваш пароль має містити щонайменше %s символів." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Неправильна електронна адреса." -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"Запит на скинення паролю для облікового запису %s надісланий на пов’язану з " -"ним адресу електронної пошти. Щоб скинути пароль, натисніть на посилання " -"нижче; щоб залишити все як є, проігноруйте це повідомлення." - +#: html/passreset.php msgid "Password Reset" msgstr "Скидання паролю" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Перевірте свою електронну пошту для підтвердження." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Ваш пароль успішно скинуто." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Підтвердьте адресу електронної пошти:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Введіть новий пароль:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Підтвердження нового паролю:" +#: html/passreset.php msgid "Continue" msgstr "Продовжити" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Якщо Ви забули електронну адресу, використану при реєстрації, зверніться до " -"списку розсилання %saur-general%s" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Якщо Ви забули електронну адресу, використану при реєстрації, зверніться до списку розсилання %saur-general%s" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Введіть адресу електронної пошти:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Вибрані пакунки не мають міток, подайте коментар, будь ласка." + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Вибрані пакунки все ще мають власника, підтвердіть дію." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Не вдалося знайти пакунок для об’єднання голосів та коментарів." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Неможливо злити пакунок з самим собою." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Обрані пакунки не вилучено, перевірте, чи поставлено галочку в полі " -"підтвердження." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Обрані пакунки не вилучено, перевірте, чи поставлено галочку в полі підтвердження." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Вилучення пакунку" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "Вилучити пакунок: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "Використовуйте цю форму для вилучення пакунку %s%s%s з AUR. " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Вилучення пакунку є безповоротне." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Встановіть галочку, щоб підтвердити дію." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Підтвердити вилучення пакунку" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Вилучити" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Тільки Довірені Користувачі та Розробники можуть вилучати пакунки." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Зректися пакунку" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "Позбавлення пакунка власника: %s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Використайте ці форму для позбавлення базового пакунка %s%s%s власника, який " -"містить наступні пакунки:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Використайте ці форму для позбавлення базового пакунка %s%s%s власника, який містить наступні пакунки:" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника і " -"перенести права власності до %s%s%s." +msgstr "Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника і перенести права власності до %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Підтвердіть позбавлення пакунка власника" +#: html/pkgdisown.php msgid "Disown" msgstr "Відректися" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Тільки Довірені Користувачі та Розробники можуть забирати права власності на " -"пакунок." +msgstr "Тільки Довірені Користувачі та Розробники можуть забирати права власності на пакунок." +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "Позначити пакунок як застарілий" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "Позначити пакунок як застарілий: %s" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Використовуйте цю форму для позначення базового пакунку %s%s%s і наступні пакунки як застарілі:" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "Будь ласка, %sне%s використовуйте цю форму для повідомлення про вади. Використовуйте для цього коментарі до пакунку." + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "Введіть нижче деталі, чому пакунок є застарілим, по можливості подайте посилання до оголошення про новий випуск або архів оновленого випуску." + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "Коментарі" + +#: html/pkgflag.php +msgid "Flag" +msgstr "Позначити" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "Тільки зареєстровані користувачі можуть позначати пакунки як застарілі." + +#: html/pkgmerge.php msgid "Package Merging" msgstr "Об’єднання пакунків" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "Об’єднати пакунки: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Використовуйте цю форму для злиття пакунку %s%s%s з іншим пакунком." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Наступні пакунки будуть вилучені:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Як тільки пакунок буде об’єднаний, його вже неможливо повернути." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Введіть назву пакунка, до якого потрібно приєднати цей." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Об’єднати з:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Підтвердити об’єднання пакунків" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Об’єднати" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Тільки Довірені Користувачі та Розробники можуть об’єднувати пакунки." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "Запит файлу" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Замкнути запит" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Перший" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Попередній" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далі" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Останній" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Запити" +#: html/register.php template/header.php msgid "Register" msgstr "Зареєструватись" +#: html/register.php msgid "Use this form to create an account." msgstr "Створіть обліковий запис за допомогою цієї форми." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Довірений користувач" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Не вдалось отримати подробиць пропозиції." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Голосування на цю пропозицію закрито." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Тільки Довірені Користувачі мають право голосу." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Ви не можете голосувати за свою пропозицію." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ви вже проголосували за цю пропозицію." +#: html/tu.php msgid "Vote ID not valid." msgstr "Ідентифікатор голосу неправильний." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Поточні голосування" +#: html/tu.php msgid "Past Votes" msgstr "Минулі голосування" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Проголосували" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Реєстрація рахунку закрита для Вашої адреси IP, можливо із-за інтенсивної " -"спам-атаки. Вибачте за незручності." +msgstr "Реєстрація рахунку закрита для Вашої адреси IP, можливо із-за інтенсивної спам-атаки. Вибачте за незручності." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Бракує ідентифікатора користувача" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Користувач неправильний." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Кількість символів повинна бути від %s до %s" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Початок та кінець з літери або цифри" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Може містити тільки один період, підкреслення або дефіс." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Адреса електронної пошти неправильна." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Відбиток ключа PGP недійсний." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Неправильний публічний ключ SSH." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Неможливо збільшити дозволи рахунку." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Наразі ця мова не підтримується." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Назва користувача %s%s%s вже використовується." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Адрес %s%s%s вже використовується." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Публічний ключ SSH, %s%s%s, вже використовується." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Помилка при спробі створити рахунок %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Рахунок %s%s%s успішно створено." -msgid "Click on the Login link above to use your account." -msgstr "" -"Використовуйте обліковий запис, увійшовши за допомогою посилання " -"«Увійти» (згори)." - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"Вітаємо в %s! Щоб встановити початковий пароль для Вашого рахунку натисніть " -"на посилання зверху. Якщо посилання не спрацьовує, скопіюйте його і вставте " -"у Ваш переглядач інтернету." - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ключ скидання пароля висланий на Вашу адресу електронної пошти." +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "Використовуйте обліковий запис, увійшовши за допомогою посилання «Увійти» (згори)." + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Ніяких змін не внесено до рахунку, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Рахунок %s%s%s успішно змінено." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Форма логування зараз заборонена для Вашої адреси IP, можливо із-за " -"інтенсивної спам-атаки. Вибачте за незручності." +msgstr "Форма логування зараз заборонена для Вашої адреси IP, можливо із-за інтенсивної спам-атаки. Вибачте за незручності." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Рахунок вилучено" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Ваш пароль скинуто. Якщо Ви щойно створили новий рахунок, тоді використайте " -"посилання електронного листа-підтвердження для встановлення початкового " -"пароля. В протилежному випадку використайте запит на скидання паролю на " -"сторінці %sPassword Reset%s." +msgstr "Ваш пароль скинуто. Якщо Ви щойно створили новий рахунок, тоді використайте посилання електронного листа-підтвердження для встановлення початкового пароля. В протилежному випадку використайте запит на скидання паролю на сторінці %sPassword Reset%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Неправильний користувач або пароль. " +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Сталася помилка під час створення сесії користувача." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Неприпустима адреса електронної пошти й комбінація клавіш скидання." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Немає" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Показати інформацію про рахунок для %s" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "ID базового пакунку або ж назва базового пакунку пропущена." + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "У вас немає прав, щоб редагувати цей коментар." + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "Коментаря не існує." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "Коментар не може бути порожнім." + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "Коментар додано." + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Помилка пошуку інформації про пакунок." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Інформації про пакунок не знайдено." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Для встановлення мітки слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Ви не вибрали жодного пакунку для мітки." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Для вибраних пакунків призначено мітку «застарілий»." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Для зняття мітки слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Не вибрано жодного пакунку, щоб зняти мітку." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "З вибраних пакунків було знято мітку." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "У Вас немає прав для вилучення пакунків." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Не вибрано жодного пакунку для вилучення." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Вибрані пакунки вилучено." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Для перейняття пакунків слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Для зречення пакунків слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Ви не вибрали жодного пакунку для переймання." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Не вибрано жодного пакунку, щоб зректись." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Вибрані пакунки перейнято." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Ви зреклись вибраних пакунків." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Для голосування слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Для скасування голосу слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Ви не вибрали жодного пакунка для голосування." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Ваші голоси вилучено з вибраних пакунків." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Ви проголосували за вибрані пакунки." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Неможливо долучити до списку соповіщень." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Вас долучено до списку сповіщень про коментарі для %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Вас вилучено із списку сповіщень про коментарі для %s." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Ви повинні увійти у систему, щоб мати можливість редагувати інформацію про " -"пакунок." +msgstr "Ви повинні увійти у систему, щоб мати можливість редагувати інформацію про пакунок." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Немає ідентифікатора коментаря." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Коментар вилучено." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "У вас немає прав, щоб вилучити цей коментар." -msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"Ви не маєте прав для редагування ключових слів для цього базового пакунку." +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "Коментар редаговано." +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit the keywords of this package base." +msgstr "Ви не маєте прав для редагування ключових слів для цього базового пакунку." + +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ключові слова базового пакунку оновлено." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Ви не має прав для керування супровідниками цього базового пакунку." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Неправильна назва користувача: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Оновлено супровідників базового пакунку." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Показати деталі пакунку для " +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "вимагається %s" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Ви повинні увійти, щоб робити запит пакунків." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Неправильна назва: дозволено тільки малі літери." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Поле коментаря не повинно пустувати." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Неправильний тип запиту." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Запит успішно додано." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Неправильна причина." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Тільки TU (довірені користувачі) і розробники можуть закривати запити." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Запит успішно закритий." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ви можете використати цю форму для вилучення рахунку в AUR %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sУВАГА%s: Цю дію неможливо відмінити." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Підтвердити вилучення" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "Користувач" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Тип облікового запису" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Користувач" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Розробник" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Довірений користувач & Розробник" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Адреса електронної пошти" +#: template/account_details.php +msgid "hidden" +msgstr "приховано" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Справжнє ім'я" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Псевдонім IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Відбиток ключа PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Статус" +#: template/account_details.php msgid "Inactive since" msgstr "Неактивний з" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Активний" +#: template/account_details.php msgid "Last Login" msgstr "Останній вхід" +#: template/account_details.php msgid "Never" msgstr "Ніколи" +#: template/account_details.php msgid "View this user's packages" msgstr "Переглянути пакунки цього користувача" +#: template/account_details.php msgid "Edit this user's account" msgstr "Редагування рахунку цього користувача" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Натисніть %sтут%s, якщо Ви бажаєте безповоротно вилучити цей рахунок." +#: template/account_edit_form.php msgid "required" msgstr "обов'язково" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Звичайний користувач" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Довіренний користувач" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Обліковий запис призупинено" +#: template/account_edit_form.php msgid "Inactive" msgstr "Неактивний" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "Будь ласка переконайтесь, що Ви правильно ввели Вашу адресу електронної пошти, інакше Ви будете заблоковані." + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "Приховати адресу електронної пошти" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "Введіть пароль ще раз" +#: template/account_edit_form.php msgid "Language" msgstr "Мова" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Наступну інформацію потрібно, якщо Ви бажаєте надіслати пакунки до Сховища " -"Користувацьких Пакунків AUR." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Наступну інформацію потрібно, якщо Ви бажаєте надіслати пакунки до Сховища Користувацьких Пакунків AUR." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Публічний ключ SSH" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Оновити" +#: template/account_edit_form.php msgid "Create" msgstr "Створити" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Очистити" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "За вашим запитом нічого не знайдено." +#: template/account_search_results.php msgid "Edit Account" msgstr "Редагувати обліковий запис" +#: template/account_search_results.php msgid "Suspended" msgstr "Призупинено" +#: template/account_search_results.php msgid "Edit" msgstr "Редагувати" +#: template/account_search_results.php msgid "Less" msgstr "Менше" +#: template/account_search_results.php msgid "More" msgstr "Більше" +#: template/account_search_results.php msgid "No more results to display." msgstr "Більше немає результатів." +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "Керування супровідниками: %s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Використайте цю форму для додавання супровідника для %s%s%s (одна назва " -"користувача в одній стрічці):" +msgstr "Використайте цю форму для додавання супровідника для %s%s%s (одна назва користувача в одній стрічці):" +#: template/comaintainers_form.php msgid "Users" msgstr "Користувачі" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Зберегти" +#: template/header.php msgid "My Packages" msgstr "Мої пакунки" +#: template/header.php msgid " My Account" msgstr "Мій рахунок" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Дії над пакунком" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Переглянути PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Переглянути зміни" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Звантажити поточну версію" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Шукати у Вікі" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "Позначено як застарілий" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Позначити пакунок як застарілий" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Відмінити позначення" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Вилучити голос" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Голосувати за цей пакунок" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Відключити сповіщення" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Сповіщати про нові коментарі" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Керування Супровідниками" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -990,169 +1281,232 @@ msgstr[0] "%d запит в обробці" msgstr[1] "%d запитів в обробці" msgstr[2] "%d запитів в обробці" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "Вилучити пакунок" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "Об’єднати пакунок" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Прийняти пакунок" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "невідомо" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Деталі бази пакунків" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Адреса URL для клонування Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "тільки для читання" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Ключові слова" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Подавач" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Супровідник" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Останній збирач пакунку" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Голоси" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "Популярність" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Вперше надіслано" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Останній раз оновлено" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "Редагувати коментар для: %s" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Додати коментар" -msgid "Comment has been added." -msgstr "Коментар додано." - +#: template/pkg_comments.php msgid "View all comments" msgstr "Переглянути всі коментарі" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Останні коментарі" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "%s коментував про %s" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "Анонімний коментар про %s" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "вилучено на %s через %s" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "востаннє редагувалося на %s через %s" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "Вилучити коментар" -#, php-format -msgid "Comment by %s" -msgstr "Автор коментаря — %s" - -msgid "Anonymous comment" -msgstr "Анонімний коментар" - -msgid "deleted" -msgstr "вилучено" - +#: template/pkg_comments.php msgid "All comments" msgstr "Всі коментарі" +#: template/pkg_details.php msgid "Package Details" msgstr "Подробиці пакунку" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "База пакунків" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Опис" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Посилання" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Відвідати веб-сторінку для" +#: template/pkg_details.php msgid "Licenses" msgstr "Ліцензії" +#: template/pkg_details.php msgid "Groups" msgstr "Групи" +#: template/pkg_details.php msgid "Conflicts" msgstr "Конфлікти" +#: template/pkg_details.php msgid "Provides" msgstr "Забезпечує" +#: template/pkg_details.php msgid "Replaces" msgstr "Замінює" +#: template/pkg_details.php msgid "Dependencies" msgstr "Залежності" +#: template/pkg_details.php msgid "Required by" msgstr "Потрібен для" +#: template/pkg_details.php msgid "Sources" msgstr "Сирці" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "Закрити запит: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Використайте цю форму для закриття запиту бази пакетів %s%s%s." +#: template/pkgreq_close_form.php msgid "Note" msgstr "Примітка" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Поле коментарів може залишатися пустим. Тим не менше, рекомендовано залишити " -"коментар при відкиданні запиту." +msgstr "Поле коментарів може залишатися пустим. Тим не менше, рекомендовано залишити коментар при відкиданні запиту." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Причина" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Прийнято" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Відхилено" -msgid "Comments" -msgstr "Коментарі" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "Запит файлу: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Використайте цю форму для запиту файлу з бази пакунків %s%s%s, який містить " -"наступні пакунки:" +msgstr "Використайте цю форму для запиту файлу з бази пакунків %s%s%s, який містить наступні пакунки:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Тип запиту" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Вилучення" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Позначити застарілим" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Об'єднати в" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1160,23 +1514,29 @@ msgstr[0] "Знайдено %d запит пакунку." msgstr[1] "Знайдено %d запитів пакунку." msgstr[2] "Знайдено %d запитів пакунку." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Сторінка %d з %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Пакунок" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Запаковано через" +#: template/pkgreq_results.php msgid "Date" msgstr "Дата" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d днів залишилося" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1184,90 +1544,116 @@ msgstr[0] "~%d година залишилася" msgstr[1] "~%d годин залишилося" msgstr[2] "~%d годин залишилося" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 години залишилося" +#: template/pkgreq_results.php msgid "Accept" msgstr "Прийняти" +#: template/pkgreq_results.php msgid "Locked" msgstr "Замкнено" +#: template/pkgreq_results.php msgid "Close" msgstr "Закрити" +#: template/pkgreq_results.php msgid "Closed" msgstr "Замкнено" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Назва, опис" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Назва" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Точна назва" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Точна база пакунків" +#: template/pkg_search_form.php msgid "All" msgstr "Всі" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Позначені" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Не позначені" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Назва" -msgid "Popularity" -msgstr "Популярність" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Проголосовано" -msgid "Age" -msgstr "Вік" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "Востаннє змінювалося" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Висхідний" +#: template/pkg_search_form.php msgid "Descending" msgstr "Спадний" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Введіть критерії пошуку" +#: template/pkg_search_form.php msgid "Search by" msgstr "Де шукати" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Застарілих" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Упорядкувати за" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Порядок упорядкування" +#: template/pkg_search_form.php msgid "Per page" msgstr "Результатів на сторінку" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Перейти" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Покинуті" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Помилка отримання списку пакунків." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "За вашим запитом не знайдено пакунків." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1275,121 +1661,154 @@ msgstr[0] "Знайдено %d пакунок." msgstr[1] "Знайдено %d пакунків." msgstr[2] "Знайдено %d пакунків." +#: template/pkg_search_results.php msgid "Version" msgstr "Версія" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "" -"Популярність розраховується як сума всіх голосувань, де кожен голос береться " -"з ваговим коефіцієнтом 0.98 за кожен день з часу створення." +msgstr "Популярність розраховується як сума всіх голосувань, де кожен голос береться з ваговим коефіцієнтом 0.98 за кожен день з часу створення." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Так" +#: template/pkg_search_results.php msgid "orphan" msgstr "покинутий" +#: template/pkg_search_results.php msgid "Actions" msgstr "Дії" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "Призначити мітку «застарілий»" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Зняти мітку «застарілий»" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Прийняти пакунки" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Зректися пакунків" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Вилучити пакунки" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Підтвердити" +#: template/search_accounts_form.php msgid "Any type" msgstr "Будь-який тип" +#: template/search_accounts_form.php msgid "Search" msgstr "Пошук" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Статистика" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Покинуті пакунки" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Пакунки, додані за останні 7 днів" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Пакунки, оновлені за останні 7 днів" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Пакунки, оновлені за останній рік" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Пакунки, що ніколи не оновлювалися" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Зареєстровані користувачі" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Довірені користувачі" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Останні зміни" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Моя статистика" -msgid "Packages in unsupported" -msgstr "Пакунки в AUR" - +#: template/tu_details.php msgid "Proposal Details" msgstr "Подробиці пропозиції" +#: template/tu_details.php msgid "This vote is still running." msgstr "Це голосування все ще доречне." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Подано: %s з %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Кінець" +#: template/tu_details.php msgid "Result" msgstr "Результат" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ні" +#: template/tu_details.php msgid "Abstain" msgstr "Утриматися" +#: template/tu_details.php msgid "Total" msgstr "Всього" +#: template/tu_details.php msgid "Participation" msgstr "Участь" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Останні голосування через TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Останнє голосування" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Результатів не знайдено." +#: template/tu_list.php msgid "Start" msgstr "Початок" +#: template/tu_list.php msgid "Back" msgstr "Назад" diff --git a/po/zh_CN.po b/po/zh_CN.po index 279b0c74..cce8e13d 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # leonfeng , 2015 # dongfengweixiao , 2015 @@ -13,1315 +13,1795 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 08:16+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-26 05:50+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" -"language/zh_CN/)\n" -"Language: zh_CN\n" +"Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: html/404.php msgid "Page Not Found" msgstr "页面未找到" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "请求的页面不存在。" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "帐户" +#: html/account.php template/header.php msgid "Accounts" msgstr "帐户" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "您无权访问此区域。" +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "无法获取指定用户的信息。" +#: html/account.php msgid "You do not have permission to edit this account." msgstr "您没有权限编辑此帐户。" +#: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表单查找存在的帐户。" +#: html/account.php msgid "You must log in to view user information." msgstr "您需要登录后才能察看用户信息。" +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "添加提议" +#: html/addvote.php msgid "Invalid token for user action." msgstr "用户操作使用了无效的令牌。" +#: html/addvote.php msgid "Username does not exist." msgstr "此用户不存在。" +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s 已经有了关于他们的提议。" +#: html/addvote.php msgid "Invalid type." msgstr "无效的类别。" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "提议不能为空。" +#: html/addvote.php msgid "New proposal submitted." msgstr "新提议已被提交。" +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "提交一个提议用于投票。" +#: html/addvote.php msgid "Applicant/TU" msgstr "申请人/信任用户(TU)" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(如果不符合可以留空)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "类别" +#: html/addvote.php msgid "Addition of a TU" msgstr "添加受信用户" +#: html/addvote.php msgid "Removal of a TU" msgstr "移除受信用户" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "移除受信用户(无故不活跃)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "修订章程" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "提议" +#: html/addvote.php msgid "Submit" msgstr "提交" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "" + +#: html/home.php template/header.php msgid "Home" msgstr "首页" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"欢迎来到 AUR!想了解更多信息,请阅读 %sAUR 用户指南%s和 %sAUR 受信用户指" -"南%s。" +msgstr "欢迎来到 AUR!想了解更多信息,请阅读 %sAUR 用户指南%s和 %sAUR 受信用户指南%s。" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "提交的 PKGBUILD %s必须%s遵守 %sArch 软件包规范%s,否则它们将被删除!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "记得为您喜欢的软件包投票!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "部分软件包将在 [community] 仓库以二进制包的形式提供。" +#: html/home.php msgid "DISCLAIMER" msgstr "免责声明" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." -msgstr "位于 unsupported 的软件包为用户产生的内容。使用它们造成的后果自负。" +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." +msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "邮件列表" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Bug 报告" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "软件包搜索" +#: html/index.php msgid "Adopt" msgstr "接管" +#: html/index.php msgid "Vote" msgstr "投票" +#: html/index.php msgid "UnVote" msgstr "取消投票" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "取消通知" -msgid "Flag" -msgstr "标记" - +#: html/index.php msgid "UnFlag" msgstr "取消标记" +#: html/login.php template/header.php msgid "Login" msgstr "登录" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "登录为: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "退出" +#: html/login.php msgid "Enter login credentials" msgstr "输入账户信息" -msgid "Username" -msgstr "用户名" +#: html/login.php +msgid "User name or email address" +msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "密码" +#: html/login.php msgid "Remember me" msgstr "记住我" +#: html/login.php msgid "Forgot Password" msgstr "找回密码" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "HTTP 登陆已被禁用,请使用%s切换到HTTPS%s。" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "搜索标准" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "软件包" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "尝试重新获取软件包详情时发生错误。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "缺少必填项。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "密码字段不匹配。" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "密码至少要 %s 个字符。" +#: html/passreset.php msgid "Invalid e-mail." msgstr "电子邮箱不正确。" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" - +#: html/passreset.php msgid "Password Reset" msgstr "密码重置" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "请进入您的邮箱查看确认邮件。" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "密码已经成功重置。" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "确认邮箱地址:" +#: html/passreset.php msgid "Enter your new password:" msgstr "输入新密码:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "确认新密码:" +#: html/passreset.php msgid "Continue" msgstr "继续" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"如果您忘记了注册账号时使用的邮件地址,请向 %saur-general%s 邮件列表寻求帮助。" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "如果您忘记了注册账号时使用的邮件地址,请向 %saur-general%s 邮件列表寻求帮助。" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "输入您的邮箱地址:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "找不到合并投票与评论的目标包。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "无法将一个包基础合并到它自己。" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "选中的软件包未被删除,请检查确认复选框。" +#: html/pkgdel.php msgid "Package Deletion" msgstr "软件包删除" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "删除包:%s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "使用这个表单将包基础 %s%s%s 和以下包从 AUR 中移除:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "删除软件包是一个永久性的操作" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "选中复选框以确认操作。" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "确认删除包" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "删除" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "只有受信用户和开发人员能删除软件包。" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "弃置软件包" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "弃置" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "评论" + +#: html/pkgflag.php +msgid "Flag" +msgstr "标记" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "软件包合并" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "合并软件包: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "使用这个表单将包基础 %s%s%s 合并到另一个包。" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "下面这些软件包将被删除:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "一旦包被合并,这个操作将是不可逆的。" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "请输入合并的目标包名。" +#: html/pkgmerge.php msgid "Merge into:" msgstr "合并到:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "确认合并包" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "合并" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "只有受信用户和开发人员才能删除软件包。" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "提交请求" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "关闭请求" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一页" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一页" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一页" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "末页" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "请求" +#: html/register.php template/header.php msgid "Register" msgstr "注册" +#: html/register.php msgid "Use this form to create an account." msgstr "使用此表单创建帐号。" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "受信用户" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "无法获取提议详情。" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "该提议的投票已被关闭。" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "只有受信用户可以投票。" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "您不能在关于您的提议里投票。" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "您已经在这个提议上投票了。" +#: html/tu.php msgid "Vote ID not valid." msgstr "非法的投票标识" +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "当前的投票" +#: html/tu.php msgid "Past Votes" msgstr "历史投票" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"账户注册目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引" -"起的不便表示抱歉。" +msgstr "账户注册目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引起的不便表示抱歉。" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "缺少用户标识" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "用户名需要符合以下条件:" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "在 %s 到 %s 个字符之间" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "开头和结尾是数字/英文字母" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一个“.”,“_”,或“-”" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "错误的 Email 地址。" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 密钥指纹无效。" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "不能提高账户权限。" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "目前不支持此语言。" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "用户名 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "该地址 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "尝试创建帐户 %s%s%s 失败。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "帐户 %s%s%s 创建成功。" -msgid "Click on the Login link above to use your account." -msgstr "点击上方的登陆链接以使用你的帐号。" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"欢迎来到 %s!想要为你的新账户设置初始密码,请点击下面的链接。如果链接不工作," -"请尝试复制它到你的浏览器中打开。" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "一个密码重置密钥已经发送到你的电子邮箱。" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "点击上方的登陆链接以使用你的帐号。" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "账户 %s%s%s 没有被修改。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "帐号 %s%s%s 已被成功修改。" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"登陆表单目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引" -"起的不便表示抱歉。" +msgstr "登陆表单目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引起的不便表示抱歉。" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "帐号被停用" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"你的密码已经成功被重置。如果你刚刚创建了一个新账户,请使用确认邮件中的链接来" -"设置一个初始密码。否则,请在 %s重置密码%s 页面申请一个重置密码密钥。" +msgstr "你的密码已经成功被重置。如果你刚刚创建了一个新账户,请使用确认邮件中的链接来设置一个初始密码。否则,请在 %s重置密码%s 页面申请一个重置密码密钥。" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "用户名或密码错误。" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "在创建用户会话的过程中出现了一个错误。" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "邮箱和重置 key 不匹配。" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "无" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "查看 %s 的账户信息" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "已经添加评论。" + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "获取软件包详情时发生错误。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "无法找到软件包的详细信息。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "您需要登录后才能标记软件包。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "您没有选择要标记的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "选择的软件包已被标记为过期。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "您需要登录后才能移除软件包标记。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "您没有选择要取消标记的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "选中的软件包的标记已被移除。" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "您没有删除软件包的权限。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "您没有选择要删除的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "选中的软件包已经被删除。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "登陆后才能接管软件包" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "您需要登录后才能弃置软件包。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "您没有选择要接管的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "您没有选择要弃置的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "选择的软件包已经被接管。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "选中的软件包已经被弃置。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "您需要登录后才能为软件包投票。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "您需要登录后才能为软件包取消投票。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "您没有选择要投票的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "您对所选软件包的投票已被取消。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "您对所选软件包的投票已被记录。" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "无法将您添加到通知列表。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "您已被成功添加到 %s 的评论通知列表。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "您将不再收到 %s 的评论通知。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "您需要登录后才能编辑软件包信息。" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "评论标识丢失。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "评论已被删除。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "您没有权限删除此评论。" +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "查看软件包详细信息" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "登录之后才能提交软件包需求。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "无效的名称: 只允许小写字母。" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "评论内容不能为空。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "无效的请求类型。" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "请求提交成功。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "无效的理由。" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "只有受信用户和开发者可以关闭请求。" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "请求关闭成功。" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "你可以使用这个表单来彻底删除 AUR 帐号 %s。" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s:这个操作无法被撤销" +#: template/account_delete.php msgid "Confirm deletion" msgstr "确认删除" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "用户名" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "帐户类别" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "用户" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "开发人员" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "受信用户 & 开发者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Email" +#: template/account_details.php +msgid "hidden" +msgstr "" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "真实名字" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC昵称" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 密钥指纹" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "状态" +#: template/account_details.php msgid "Inactive since" msgstr "不活跃自" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "激活" +#: template/account_details.php msgid "Last Login" msgstr "最后登陆" +#: template/account_details.php msgid "Never" msgstr "从不" +#: template/account_details.php msgid "View this user's packages" msgstr "查看这个用户提交的软件包" +#: template/account_details.php msgid "Edit this user's account" msgstr "编辑此用户的帐号" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果你想要彻底删除这个帐号,请点击%s这里%s。" +#: template/account_edit_form.php msgid "required" msgstr "必填" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "普通用户" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "受信用户" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "帐户被暂停" +#: template/account_edit_form.php msgid "Inactive" msgstr "不活跃" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "确认密码" +#: template/account_edit_form.php msgid "Language" msgstr "语言" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "更新" +#: template/account_edit_form.php msgid "Create" msgstr "创建" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "重填" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "没有结果符合您的搜索条件。" +#: template/account_search_results.php msgid "Edit Account" msgstr "编辑帐户" +#: template/account_search_results.php msgid "Suspended" msgstr "暂停" +#: template/account_search_results.php msgid "Edit" msgstr "编辑" +#: template/account_search_results.php msgid "Less" msgstr "更少" +#: template/account_search_results.php msgid "More" msgstr "更多" +#: template/account_search_results.php msgid "No more results to display." msgstr "没有更多的结果供显示。" +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/header.php msgid "My Packages" msgstr "我的软件包" +#: template/header.php msgid " My Account" msgstr "我的帐户" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "软件包操作" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "查看 PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "搜索 Wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "已标记为过期" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "将软件包标记为过期" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "取消标记软件包" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "移除投票" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "为这个软件包投票" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "禁用通知" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "当有新评论的时候提醒我" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 个未处理的请求" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "删除软件包" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "合并软件包" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "接管软件包" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "未知" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "包基础详情" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "关键字" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "提交人" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "维护者" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最近一次打包者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "得票" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "首次提交" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最后更新" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "添加评论" -msgid "Comment has been added." -msgstr "已经添加评论。" - +#: template/pkg_comments.php msgid "View all comments" msgstr "查看所有评论" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "最新的评论" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "删除评论" -#, php-format -msgid "Comment by %s" -msgstr "%s 的评论" - -msgid "Anonymous comment" -msgstr "匿名评论" - -msgid "deleted" -msgstr "已删除" - +#: template/pkg_comments.php msgid "All comments" msgstr "全部评论" +#: template/pkg_details.php msgid "Package Details" msgstr "软件包详情" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "包基础" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "描述" +#: template/pkg_details.php msgid "Upstream URL" msgstr "上游 URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "访问网站" +#: template/pkg_details.php msgid "Licenses" msgstr "许可协议" +#: template/pkg_details.php msgid "Groups" msgstr "组" +#: template/pkg_details.php msgid "Conflicts" msgstr "冲突" +#: template/pkg_details.php msgid "Provides" msgstr "提供" +#: template/pkg_details.php msgid "Replaces" msgstr "取代" +#: template/pkg_details.php msgid "Dependencies" msgstr "依赖于:" +#: template/pkg_details.php msgid "Required by" msgstr "被需要:" +#: template/pkg_details.php msgid "Sources" msgstr "源代码:" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "关闭请求:%s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "使用这个表单来关闭对包基础 %s%s%s 的请求。" +#: template/pkgreq_close_form.php msgid "Note" msgstr "提示" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "评论可以留空。不过,当拒绝一个请求的时候,强烈推荐提供一条评论。" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "原因" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "已接受" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "已拒绝" -msgid "Comments" -msgstr "评论" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "提交请求:%s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "使用这个表格,提交一个针对包基础 %s%s%s 的请求,其中包括下列软件包:" +#: template/pkgreq_form.php msgid "Request type" msgstr "请求类型" +#: template/pkgreq_form.php msgid "Deletion" msgstr "删除" +#: template/pkgreq_form.php msgid "Orphan" msgstr "弃置" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "合并到" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "找到了 %d 个软件包请求。" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "第 %d 页,共 %d 页。" +#: template/pkgreq_results.php msgid "Package" msgstr "软件包" +#: template/pkgreq_results.php msgid "Filed by" msgstr "提交者是" +#: template/pkgreq_results.php msgid "Date" msgstr "日期" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "剩余~%d天" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "剩余~%d小时" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "剩余<1小时" +#: template/pkgreq_results.php msgid "Accept" msgstr "接受" +#: template/pkgreq_results.php msgid "Locked" msgstr "已锁定" +#: template/pkgreq_results.php msgid "Close" msgstr "关闭" +#: template/pkgreq_results.php msgid "Closed" msgstr "已关闭" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "名称和描述" +#: template/pkg_search_form.php msgid "Name Only" msgstr "名称" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "确切的名字" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "准确包基础" +#: template/pkg_search_form.php msgid "All" msgstr "全部" +#: template/pkg_search_form.php msgid "Flagged" msgstr "已标记" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "未标记" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名称" -msgid "Popularity" -msgstr "" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "已投票" -msgid "Age" -msgstr "时间" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "从小到大" +#: template/pkg_search_form.php msgid "Descending" msgstr "从大到小" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "输入搜索条件" +#: template/pkg_search_form.php msgid "Search by" msgstr "搜索" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "过期状态" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "排列依据" +#: template/pkg_search_form.php msgid "Sort order" msgstr "排列方式" +#: template/pkg_search_form.php msgid "Per page" msgstr "每页显示" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Go" +#: template/pkg_search_form.php msgid "Orphans" msgstr "孤儿包" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "无法获取包列表。" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "没有相关的软件包符合您的搜索条件。" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "找到了 %d 个软件包。" +#: template/pkg_search_results.php msgid "Version" msgstr "版本" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "是" +#: template/pkg_search_results.php msgid "orphan" msgstr "孤儿包" +#: template/pkg_search_results.php msgid "Actions" msgstr "操作" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "标记为过期" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "移除过期标记" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "接管软件包" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "弃置软件包" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "删除软件包" +#: template/pkg_search_results.php msgid "Confirm" msgstr "确认" +#: template/search_accounts_form.php msgid "Any type" msgstr "所有类别" +#: template/search_accounts_form.php msgid "Search" msgstr "搜索" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "统计" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "无人维护的软件包" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "7天内新增的软件包" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "7天内更新的软件包" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "一年内更新的软件包" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "从未更新的软件包" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "注册用户" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "受信用户" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最新更新" +#: template/stats/user_table.php msgid "My Statistics" msgstr "我的统计" -msgid "Packages in unsupported" -msgstr "位于 unsupported 的软件包" - +#: template/tu_details.php msgid "Proposal Details" msgstr "提议详情" +#: template/tu_details.php msgid "This vote is still running." msgstr "投票仍在继续。" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "已提交 %s 由 %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "结束" +#: template/tu_details.php msgid "Result" msgstr "结果" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "否" +#: template/tu_details.php msgid "Abstain" msgstr "弃权" +#: template/tu_details.php msgid "Total" msgstr "总数" +#: template/tu_details.php msgid "Participation" msgstr "参与" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "受信用户的最后投票" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最后投票" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "没有找到结果。" +#: template/tu_list.php msgid "Start" msgstr "开始" +#: template/tu_list.php msgid "Back" msgstr "返回" diff --git a/po/zh_TW.po b/po/zh_TW.po index 16c89dfc..7ff5aec7 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1,1342 +1,1802 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# +# This file is distributed under the same license as the AUR package. +# # Translators: # Jeff Huang , 2014-2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-06-28 10:09+0200\n" -"PO-Revision-Date: 2015-06-18 10:37+0000\n" +"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"PO-Revision-Date: 2015-09-27 03:45+0000\n" "Last-Translator: Jeff Huang \n" -"Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" -"language/zh_TW/)\n" -"Language: zh_TW\n" +"Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: html/404.php msgid "Page Not Found" msgstr "頁面找不到" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "抱歉,您所請求的頁面不存在。" +#: html/503.php msgid "Service Unavailable" msgstr "服務不可用" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "別緊張!這個頁面因維護而暫時下線。我們很快就會回來。" +#: html/account.php msgid "Account" msgstr "帳號" +#: html/account.php template/header.php msgid "Accounts" msgstr "帳號" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "您不被允許存取此區域。" +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "無法擷取指定使用者的資訊。" +#: html/account.php msgid "You do not have permission to edit this account." msgstr "您沒有權限編輯此帳號。" +#: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表單來搜尋已有的帳號。" +#: html/account.php msgid "You must log in to view user information." msgstr "您必須登入以檢視使用者資訊。" +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "添加建議" +#: html/addvote.php msgid "Invalid token for user action." msgstr "無效的使用者動作標誌。" +#: html/addvote.php msgid "Username does not exist." msgstr "使用者名稱不存在。" +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s 已經有了關於他們的建議。" +#: html/addvote.php msgid "Invalid type." msgstr "無效的類型。" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "建議不能為空。" +#: html/addvote.php msgid "New proposal submitted." msgstr "已提交新的建議。" +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "提交一個建議用於投票。" +#: html/addvote.php msgid "Applicant/TU" msgstr "申請人/受信使用者" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(如果不符合可以留空)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "類型" +#: html/addvote.php msgid "Addition of a TU" msgstr "添加受信使用者" +#: html/addvote.php msgid "Removal of a TU" msgstr "移除受信使用者" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "移除受信使用者(無故不活躍)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "修定規則" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "建議" +#: html/addvote.php msgid "Submit" msgstr "提交" +#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "管理共同維護者" +#: html/commentedit.php template/pkg_comments.php +msgid "Edit comment" +msgstr "編輯評論" + +#: html/home.php template/header.php msgid "Home" msgstr "首頁" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"歡迎來到 AUR!請閱讀 %sAUR 使用者指導方針%s 和 %sAUR 受信使用者指導方針%s 以" -"獲取更多的詳細資訊。" +msgstr "歡迎來到 AUR!請閱讀 %sAUR 使用者指導方針%s 和 %sAUR 受信使用者指導方針%s 以獲取更多的詳細資訊。" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"所貢獻的 PKGBUILDs 和 PKGINFOs %s必須%s 符合 %sArch 打包標準%s 否則將被被刪" -"除! " +msgstr "所貢獻的 PKGBUILDs 和 PKGINFOs %s必須%s 符合 %sArch 打包標準%s 否則將被被刪除! " +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "記得投一票給您喜愛的套件!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "某些套件可能會在 [community] 提供二進位檔案。" +#: html/home.php msgid "DISCLAIMER" msgstr "免責聲明" +#: html/home.php template/footer.php msgid "" -"Unsupported packages are user produced content. Any use of the provided " -"files is at your own risk." +"AUR packages are user produced content. Any use of the provided files is at " +"your own risk." msgstr "AUR 上的檔案是使用者產生的內容。任何使用檔案的風險由您自行承擔。" +#: html/home.php msgid "Learn more..." msgstr "了解更多..." +#: html/home.php msgid "Support" msgstr "支援" +#: html/home.php msgid "Package Requests" msgstr "套件請求" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "有三種您可以在套件細節頁面中的 %s套件動作%s 中使用的請求:" +#: html/home.php msgid "Orphan Request" msgstr "棄置請求" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"請求一個套件被解除擁有權,例如:當維護者不活躍且套件已經被標記為過期很長一段" -"時間。" +msgstr "請求一個套件被解除擁有權,例如:當維護者不活躍且套件已經被標記為過期很長一段時間。" +#: html/home.php msgid "Deletion Request" msgstr "刪除請求" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"請求套件從 Arch 使用者套件庫中移除。如果套件損毀但可以很容易的被修復,請不要" -"使用這個請求。您應該聯絡套件維護者,並在必要時提出棄置請求。" +msgstr "請求套件從 Arch 使用者套件庫中移除。如果套件損毀但可以很容易的被修復,請不要使用這個請求。您應該聯絡套件維護者,並在必要時提出棄置請求。" +#: html/home.php msgid "Merge Request" msgstr "合併請求" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"請求將一個套件合併到另一個。可以使用在需要重新命名或是由分裂的套件所取代的套" -"件。" +msgstr "請求將一個套件合併到另一個。可以使用在需要重新命名或是由分裂的套件所取代的套件。" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"如果您想要討論某一個請求,您可以使用 %saur-requests%s 郵件列表。但請不要使用" -"這個列表來提出請求。" +msgstr "如果您想要討論某一個請求,您可以使用 %saur-requests%s 郵件列表。但請不要使用這個列表來提出請求。" +#: html/home.php msgid "Submitting Packages" msgstr "遞交套件" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"現在透過 SSH 的 Git 開始用於遞交套件到 AUR 上。參見 ArchWiki 上的 Arch User " -"Repository 頁面之 %s遞交套件%s 章節以取得更多資訊。" +msgstr "現在透過 SSH 的 Git 開始用於遞交套件到 AUR 上。參見 ArchWiki 上的 Arch User Repository 頁面之 %s遞交套件%s 章節以取得更多資訊。" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "下列 SSH 指紋被用於 AUR:" +#: html/home.php msgid "Discussion" msgstr "討論" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"與 Arch 使用者套件庫(AUR)及受信使用者結構相關的一般性討論請見 %saur-general" -"%s 。討論關於 AUR 網頁介面的開發,請使用 %saur-dev%s 郵件列表。" +msgstr "與 Arch 使用者套件庫(AUR)及受信使用者結構相關的一般性討論請見 %saur-general%s 。討論關於 AUR 網頁介面的開發,請使用 %saur-dev%s 郵件列表。" +#: html/home.php msgid "Bug Reporting" msgstr "臭蟲回報" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR %sonly%s. To " -"report packaging bugs contact the package maintainer or leave a comment on " -"the appropriate package page." -msgstr "" -"如果您在 AUR 網頁介面中發現了臭蟲,請在我們的 %s臭蟲追蹤系統%s 中回報。請%s" -"只%s回報 AUR 本身的臭蟲。要回報打包臭蟲,請連絡套件的維護者或是在對應的套件頁" -"面中留下評論。" +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "如果您在 AUR 網頁介面中發現了臭蟲,請在我們的 %s臭蟲追蹤系統%s 中回報。請%s只%s回報 AUR 網頁介面本身的臭蟲。要回報打包臭蟲,請連絡套件的維護者或是在對應的套件頁面中留下評論。" +#: html/home.php msgid "Package Search" msgstr "搜尋套件" +#: html/index.php msgid "Adopt" msgstr "接管" +#: html/index.php msgid "Vote" msgstr "投票" +#: html/index.php msgid "UnVote" msgstr "取消投票" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "取消通知" -msgid "Flag" -msgstr "標記" - +#: html/index.php msgid "UnFlag" msgstr "取消標記" +#: html/login.php template/header.php msgid "Login" msgstr "登入" +#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "已登入為: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "登出" +#: html/login.php msgid "Enter login credentials" msgstr "輸入登入資訊" -msgid "Username" -msgstr "使用者名稱" +#: html/login.php +msgid "User name or email address" +msgstr "使用者名稱或電子郵件地址" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "密碼" +#: html/login.php msgid "Remember me" msgstr "記住我" +#: html/login.php msgid "Forgot Password" msgstr "忘記密碼" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "HTTP 登入已被停用。如果您想要登入的話,請 %s切換至HTTPs%s 。" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "搜尋條件" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "套件" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "嘗試擷取套件細節時發生錯誤。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "缺少必填項目。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "密碼不符合。" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "您的密碼必須至少 %s 個字節。" +#: html/passreset.php msgid "Invalid e-mail." msgstr "無效的電子郵件。" -#, php-format -msgid "" -"A password reset request was submitted for the account %s associated with " -"your e-mail address. If you wish to reset your password follow the link " -"below, otherwise ignore this message and nothing will happen." -msgstr "" -"一個關聯到您的電子郵件地址的帳號 %s 已遞交了密碼重置請求。如果您想要重置您的" -"密碼,請使用以下的連結,否則您可以忽略這則訊息,且不會發生任何事情。" - +#: html/passreset.php msgid "Password Reset" msgstr "密碼重置" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "請檢查您的電子郵件信箱裡是否有確認連結。" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "您的密碼已成功重置。" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "確認您的電子郵件位置:" +#: html/passreset.php msgid "Enter your new password:" msgstr "輸入您的新密碼:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "確認您的新密碼:" +#: html/passreset.php msgid "Continue" msgstr "繼續" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"如果您忘了您用來註冊的電子郵件地址,請寄一封訊息到 %saur-general%s 郵件列表" -"中。" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "如果您忘了您用來註冊的電子郵件地址,請寄一封訊息到 %saur-general%s 郵件列表中。" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "輸入您的電子郵件地址:" +#: html/pkgbase.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "選定的套件尚未被標記,請輸入評論。" + +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "選取的套件未被棄置,請檢查確認的核取方塊。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "找不到合併投票與評論的目標套件。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "無法將一個套件基礎與它自己合併。" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "選取的套件未被刪除,請檢查確認的核取方塊。" +#: html/pkgdel.php msgid "Package Deletion" msgstr "套件刪除" +#: html/pkgdel.php #, php-format msgid "Delete Package: %s" msgstr "刪除套件: %s" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "使用這個表單以從 AUR 刪除套件基礎 %s%s%s 以及以下的套件。" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "套件刪除是永久性的操作。" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "選取核取方塊以確認動作。" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "確認套件刪除" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "刪除" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "只有受信使用者和開發者可以刪除套件。" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "棄置套件" +#: html/pkgdisown.php #, php-format msgid "Disown Package: %s" msgstr "棄置套件:%s" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "使用這個表單以棄置一個包含以下套件的套件基礎 %s%s%s :" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "透過選取核取方塊,您就會確認您想要棄置此套件並轉移所有權給 %s%s%s。" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "透過選取核取方塊,您就會確認您想要棄置此套件。" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "確認棄置此套件" +#: html/pkgdisown.php msgid "Disown" msgstr "棄置" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "只有受信使用者和開發者可以棄置套件。" +#: html/pkgflag.php +msgid "Flag Package Out-Of-Date" +msgstr "將套件標記為過期" + +#: html/pkgflag.php +#, php-format +msgid "Flag Package Out-Of-Date: %s" +msgstr "將套件標記為過期:%s" + +#: html/pkgflag.php +#, php-format +msgid "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "使用這個表單來標記套件基礎 %s%s%s 以及以下的套件已過期:" + +#: html/pkgflag.php +#, php-format +msgid "" +"Please do %snot%s use this form to report bugs. Use the package comments " +"instead." +msgstr "請 %s不要%s 使用此表單來回報臭蟲。使用套件的評論來代替。" + +#: html/pkgflag.php +msgid "" +"Enter details on why the package is out-of-date below, preferably including " +"links to the release announcement or the new release tarball." +msgstr "在下面輸入關於套件要被標記為過期的細節,最好包括釋出公告或是新版 tarball 的連結。" + +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php +msgid "Comments" +msgstr "評論" + +#: html/pkgflag.php +msgid "Flag" +msgstr "標記" + +#: html/pkgflag.php +msgid "Only registered users can flag packages out-of-date." +msgstr "只有已註冊的使用者可以標記套件為過期。" + +#: html/pkgmerge.php msgid "Package Merging" msgstr "套件合併" +#: html/pkgmerge.php #, php-format msgid "Merge Package: %s" msgstr "合併套件:: %s" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "使用這個表單以合併套件基礎 %s%s%s 以及其他套件。" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "以下套件將會被刪除:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "套件一經合併即無法回復。" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "請輸入您想要合併到該套件的套件名稱。" +#: html/pkgmerge.php msgid "Merge into:" msgstr "合併到:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "確認套件合併" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "合併" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "只有受信使用者和開發者可以合併套件。" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "File Request" msgstr "提交請求" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "關閉請求" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一頁" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一頁" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一頁" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後一頁" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "請求" +#: html/register.php template/header.php msgid "Register" msgstr "註冊" +#: html/register.php msgid "Use this form to create an account." msgstr "使用此表單來新建一個帳號。" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "受信使用者" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "無法取得建議的細節。" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "這個建議的投票已被關閉。" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "只有受信使用者可以投票。" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "您不能在關於您的建議中投票。" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "您已經在此建議上投過票了。" +#: html/tu.php msgid "Vote ID not valid." msgstr "投票的 ID 無效。" +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "目前的投票" +#: html/tu.php msgid "Past Votes" msgstr "過去投票" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票者" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"帳號註冊在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們" -"為您的不便致歉。" +msgstr "帳號註冊在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們為您的不便致歉。" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "遺失使用者 ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "使用者名稱無效。" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "使用者名稱的長度必須在 %s 到 %s 個字節間。" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "以字母或數字當做開頭或結尾" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一個「.」、「_」或「-」。" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "電子郵件地址無效。" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 密鑰指紋無效。" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH 公開金鑰無效。" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "無法提升帳號權限。" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "目前不支援此語言。" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "使用者名稱 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "該位址 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開金鑰,%s%s%s,已在使用中。" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "嘗試建立帳號 %s%s%s 時發生錯誤。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "帳號 %s%s%s 已成功建立。" -msgid "Click on the Login link above to use your account." -msgstr "點擊上面的登入連結以使用您的帳號。" - -#, php-format -msgid "" -"Welcome to %s! In order to set an initial password for your new account, " -"please click the link below. If the link does not work try copying and " -"pasting it into your browser." -msgstr "" -"歡迎來到 %s !為了幫您的新帳號設定一個初始密碼,請點擊下面的連結。如果該連結" -"無法運作,請嘗試複置它並將其貼到您瀏覽器的網址列中。" - +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "一個密碼重置密鑰已寄到您的電子郵件信箱中。" +#: lib/acctfuncs.inc.php +msgid "Click on the Login link above to use your account." +msgstr "點擊上面的登入連結以使用您的帳號。" + +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "帳號 %s%s%s 沒有被修改。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "帳號 %s%s%s 已成功修改。" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"登入表單在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們" -"為您的不便致歉。" +msgstr "登入表單在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們為您的不便致歉。" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "帳號被暫停" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"您的密碼已成功重置。如果您剛建立了一個新帳號,請使用確認郵件中的連結來設定一" -"個初始密碼。否則,請在 %s密碼重置%s 頁面上請求一個重置密鑰。" +msgstr "您的密碼已成功重置。如果您剛建立了一個新帳號,請使用確認郵件中的連結來設定一個初始密碼。否則,請在 %s密碼重置%s 頁面上請求一個重置密鑰。" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "使用者名稱或密碼錯誤。" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "嘗試生成使用者工作階段時發生錯誤。" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "無效的電子郵件與密鑰組合。" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "無" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "檢視 %s 的帳號資訊" +#: lib/aurjson.class.php +msgid "Package base ID or package base name missing." +msgstr "套件基礎的 ID 或套件基礎的名稱遺失。" + +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php +msgid "You are not allowed to edit this comment." +msgstr "您不被允許編輯此評論。" + +#: lib/aurjson.class.php +msgid "Comment does not exist." +msgstr "評論不存在。" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment cannot be empty." +msgstr "評論不能為空。" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been added." +msgstr "評論已新增。" + +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "擷取套件細節時發生錯誤。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "找不到套件的詳細資訊。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "您必須先登入才能標記套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "您沒有選擇任何要標記的套件。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "選定的套件已被標記為過期。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "您必須先登入才能取消標記套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "您沒有選擇任何要取消標記的套件。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "選定的套件已被取消標記。" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "您沒有權限刪除套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "您無法選取任何套件刪除。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "選取的套件已刪除。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "您必須先登入才能接管套件。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "您必須先登入才能棄置套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "您沒有選擇任何要接管的套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "您沒有選擇任何要棄置的套件。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "選定的套件已接管。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "選定的套件已棄置。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "您必須先登入才能對套件投票。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "您必須先登入才能對套件取消投票。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "您沒有選擇任何要投票的套件。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "您的投票已從選定的套件中被移除。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "您的投票已加入選定的套件中。" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "無法加入到通知清單中。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "您已經成功加入到 %s 的評論通知列表。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "您已經成功從 %s 的評論通知列表移除。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "您必須先登入才能編輯套件資訊。" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "遺失評論 ID。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "評論已被刪除。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "您不被允許刪除此則評論。" +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been edited." +msgstr "評論已被編輯。" + +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "您不被允許編輯此套件基礎的關鍵字。" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "套件基礎關鍵字已更新。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "您不被允許管理此套件基礎的共同維護者。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "無效的使用者名稱:%s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "套件基礎共同維護者已更新。" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "檢視套件的詳細資訊" +#: lib/pkgfuncs.inc.php +#, php-format +msgid "requires %s" +msgstr "需要 %s" + +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "您必須先登入才能匯報套件請求。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "無效的名稱:只允許小寫字母。" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "評論區域不能為空。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "無效的請求類型。" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "成功加入請求。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "無效的理由。" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "只有受信使用者和開發者可以關閉請求。" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "請求關閉成功。" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "您可以使用這個表單來永久刪除 AUR 帳號 %s 。" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s :此動作無法回復。" +#: template/account_delete.php msgid "Confirm deletion" msgstr "確認刪除" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php +msgid "Username" +msgstr "使用者名稱" + +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "帳號類型" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "使用者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "開發者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "受信使用者 & 開發者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "電子郵件地址" +#: template/account_details.php +msgid "hidden" +msgstr "已隱藏" + +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "真實名稱" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC 暱稱" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 密鑰指紋" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "狀態" +#: template/account_details.php msgid "Inactive since" msgstr "不活躍自" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "活躍" +#: template/account_details.php msgid "Last Login" msgstr "最後登入" +#: template/account_details.php msgid "Never" msgstr "從未" +#: template/account_details.php msgid "View this user's packages" msgstr "檢視此使用者的套件" +#: template/account_details.php msgid "Edit this user's account" msgstr "編輯此使用者的帳號" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果您想要永久刪除此帳號,請點擊 %s這裡%s 。" +#: template/account_edit_form.php msgid "required" msgstr "必填" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "一般使用者" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "受信使用者" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "帳號被暫停" +#: template/account_edit_form.php msgid "Inactive" msgstr "不活躍" +#: template/account_edit_form.php +msgid "" +"Please ensure you correctly entered your email address, otherwise you will " +"be locked out." +msgstr "請確保您正確的輸入了您的電子郵件地址,否則您將會被鎖定。" + +#: template/account_edit_form.php +msgid "Hide Email Address" +msgstr "隱藏電子郵件地址" + +#: template/account_edit_form.php msgid "Re-type password" msgstr "重新輸入密碼" +#: template/account_edit_form.php msgid "Language" msgstr "語言" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "以下的資訊僅在您想要遞交套件到 Arch 使用者套件庫時是必須的。" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH 公開金鑰" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "更新" +#: template/account_edit_form.php msgid "Create" msgstr "建立" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "重置" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "沒有符合您搜尋條件的搜尋結果。" +#: template/account_search_results.php msgid "Edit Account" msgstr "編輯帳號" +#: template/account_search_results.php msgid "Suspended" msgstr "暫停" +#: template/account_search_results.php msgid "Edit" msgstr "編輯" +#: template/account_search_results.php msgid "Less" msgstr "更少" +#: template/account_search_results.php msgid "More" msgstr "更多" +#: template/account_search_results.php msgid "No more results to display." msgstr "無更多結果可顯示。" +#: template/comaintainers_form.php #, php-format msgid "Manage Co-maintainers: %s" msgstr "管理共同維護者:%s" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "使用此表單來加入 %s%s%s 的共同維護者(每個使用者名稱一行):" +#: template/comaintainers_form.php msgid "Users" msgstr "使用者" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "儲存" +#: template/header.php msgid "My Packages" msgstr "我的套件" +#: template/header.php msgid " My Account" msgstr "我的帳號" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "套件動作" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "檢視 PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "檢視變更" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "下載快照" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "搜尋 wiki" +#: template/pkgbase_actions.php msgid "Flagged out-of-date" msgstr "已標記為過期" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "將套件標記為過期" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "取消標記套件" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "移除投票" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "為此套件投票" +#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "停用通知" +#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "新評論通知" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "管理共同維護者" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 個擱置的請求" +#: template/pkgbase_actions.php msgid "Delete Package" msgstr "刪除套件" +#: template/pkgbase_actions.php msgid "Merge Package" msgstr "合併套件" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "接管套件" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "未知" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "套件基礎詳細資訊" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "唯讀" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "關鍵字" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "提交人" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "維護者" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最近一次打包者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "得票" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php +msgid "Popularity" +msgstr "人氣" + +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "首次提交" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最後更新" +#: template/pkg_comment_box.php +#, php-format +msgid "Edit comment for: %s" +msgstr "編輯評論:%s" + +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "新增評論" -msgid "Comment has been added." -msgstr "評論已新增。" - +#: template/pkg_comments.php msgid "View all comments" msgstr "檢視所有評論" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "最新的評論" +#: template/pkg_comments.php +#, php-format +msgid "%s commented on %s" +msgstr "%s 在 %s 上評論" + +#: template/pkg_comments.php +#, php-format +msgid "Anonymous comment on %s" +msgstr "在 %s 上的匿名評論" + +#: template/pkg_comments.php +#, php-format +msgid "deleted on %s by %s" +msgstr "在 %s 由 %s 刪除" + +#: template/pkg_comments.php +#, php-format +msgid "last edited on %s by %s" +msgstr "在 %s 最後由 %s 編輯" + +#: template/pkg_comments.php msgid "Delete comment" msgstr "刪除評論" -#, php-format -msgid "Comment by %s" -msgstr "%s 的評論" - -msgid "Anonymous comment" -msgstr "匿名評論" - -msgid "deleted" -msgstr "已刪除" - +#: template/pkg_comments.php msgid "All comments" msgstr "所有評論" +#: template/pkg_details.php msgid "Package Details" msgstr "套件詳細資訊" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "套件基礎" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "描述" +#: template/pkg_details.php msgid "Upstream URL" msgstr "上游 URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "參觀網頁" +#: template/pkg_details.php msgid "Licenses" msgstr "授權條款" +#: template/pkg_details.php msgid "Groups" msgstr "軟體群組" +#: template/pkg_details.php msgid "Conflicts" msgstr "衝突" +#: template/pkg_details.php msgid "Provides" msgstr "它提供" +#: template/pkg_details.php msgid "Replaces" msgstr "它會取代" +#: template/pkg_details.php msgid "Dependencies" msgstr "它依賴" +#: template/pkg_details.php msgid "Required by" msgstr "需要它" +#: template/pkg_details.php msgid "Sources" msgstr "來源" +#: template/pkgreq_close_form.php #, php-format msgid "Close Request: %s" msgstr "關閉請求: %s" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "使用這個表單以關閉請求套件基礎 %s%s%s 。" +#: template/pkgreq_close_form.php msgid "Note" msgstr "注意" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "評論區域可以留空。但強烈建議在拒絕一個請求時加入一些評論。" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "理由" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "已接受" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "已拒絕" -msgid "Comments" -msgstr "評論" - +#: template/pkgreq_form.php #, php-format msgid "File Request: %s" msgstr "檔案請求: %s" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "使用這個表單以提交一個針對包含以下套件的套件基礎 %s%s%s :" +#: template/pkgreq_form.php msgid "Request type" msgstr "請求類型" +#: template/pkgreq_form.php msgid "Deletion" msgstr "刪除" +#: template/pkgreq_form.php msgid "Orphan" msgstr "棄置" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "合併到" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "找到了 %d 個套件請求。" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "第 %d 頁,共 %d 頁。" +#: template/pkgreq_results.php msgid "Package" msgstr "套件" +#: template/pkgreq_results.php msgid "Filed by" msgstr "提交人為" +#: template/pkgreq_results.php msgid "Date" msgstr "日期" +#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "剩餘 ~%d 天" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "剩餘 ~%d 小時" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "剩餘 <1 小時" +#: template/pkgreq_results.php msgid "Accept" msgstr "接受" +#: template/pkgreq_results.php msgid "Locked" msgstr "已鎖定" +#: template/pkgreq_results.php msgid "Close" msgstr "關閉" +#: template/pkgreq_results.php msgid "Closed" msgstr "已關閉" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "名稱,描述" +#: template/pkg_search_form.php msgid "Name Only" msgstr "只有名稱" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "確切的名稱" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "確切的套件基礎" +#: template/pkg_search_form.php msgid "All" msgstr "全部" +#: template/pkg_search_form.php msgid "Flagged" msgstr "已標記" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "未標記" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名稱" -msgid "Popularity" -msgstr "人氣" - +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "已投票" -msgid "Age" -msgstr "時間" +#: template/pkg_search_form.php +msgid "Last modified" +msgstr "最後修改" +#: template/pkg_search_form.php msgid "Ascending" msgstr "遞增" +#: template/pkg_search_form.php msgid "Descending" msgstr "遞減" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "輸入搜尋條件" +#: template/pkg_search_form.php msgid "Search by" msgstr "以何種方式搜尋" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "過期狀態" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "排列依據" +#: template/pkg_search_form.php msgid "Sort order" msgstr "排列方式" +#: template/pkg_search_form.php msgid "Per page" msgstr "每頁顯示" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "到" +#: template/pkg_search_form.php msgid "Orphans" msgstr "被棄置的套件" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "擷取套件列表時發生錯誤。" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "沒有套件符合您的搜尋條件。" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "找到 %d 個套件。" +#: template/pkg_search_results.php msgid "Version" msgstr "版本" +#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "人氣的計算方式為,將所有票數加總,且每一票自建立以來每天乘上 0.98。" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "是" +#: template/pkg_search_results.php msgid "orphan" msgstr "被棄置的套件" +#: template/pkg_search_results.php msgid "Actions" msgstr "動作" +#: template/pkg_search_results.php msgid "Flag Out-of-date" msgstr "標記為過期" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "取消過期標誌" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "接管套件" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "棄置套件" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "刪除套件" +#: template/pkg_search_results.php msgid "Confirm" msgstr "確認" +#: template/search_accounts_form.php msgid "Any type" msgstr "任何類型" +#: template/search_accounts_form.php msgid "Search" msgstr "搜尋" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "統計" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "棄置套件" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "過去 7 天內加入的套件" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "過去 7 天內更新的套件" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "過去一年內更新的套件" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "從未更新過的套件" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "已註冊的使用者" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "受信使用者" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最近更新" +#: template/stats/user_table.php msgid "My Statistics" msgstr "我的統計" -msgid "Packages in unsupported" -msgstr "不支援的套件" - +#: template/tu_details.php msgid "Proposal Details" msgstr "建議詳情" +#: template/tu_details.php msgid "This vote is still running." msgstr "此投票仍在繼續。" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "已提交 %s 由 %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "結束" +#: template/tu_details.php msgid "Result" msgstr "結果" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "否" +#: template/tu_details.php msgid "Abstain" msgstr "棄權" +#: template/tu_details.php msgid "Total" msgstr "總數" +#: template/tu_details.php msgid "Participation" msgstr "參與" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "受信使用者的最後投票" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最後投票" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "沒有找到結果。" +#: template/tu_list.php msgid "Start" msgstr "開始" +#: template/tu_list.php msgid "Back" msgstr "返回" From c7fc6e6d33749f0a4cbf25f328f2f695905a91c1 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 09:28:18 +0200 Subject: [PATCH 0081/1891] Release 4.1.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 099c8a7a..a376fcd3 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Sat, 3 Oct 2015 11:07:39 +0200 Subject: [PATCH 0082/1891] Fix parameter processing in parse_multiinfo_args() Fixes a regression introduced in 94aeead (aurjson: Pass http_data array to all functions, 2015-06-28). Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index db9cc547..8ca028ae 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -324,12 +324,11 @@ class AurJSON { * IDs and package names are valid; sort them into the relevant arrays and * escape/quote the names. * - * @param array $http_data Query parameters. + * @param array $args Query parameters. * * @return mixed An array containing 'ids' and 'names'. */ - private function parse_multiinfo_args($http_data) { - $args = $http_data['arg']; + private function parse_multiinfo_args($args) { if (!is_array($args)) { $args = array($args); } From d18a9638c6212eeb29cd52ab312ea716be4179cc Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 11:12:18 +0200 Subject: [PATCH 0083/1891] Fix dependency sorting Fixes a regression introduced in 9d2d8f1 (Honor virtual provisions in package requirements, 2015-09-17). Signed-off-by: Lukas Fleischer --- web/template/pkg_details.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index b9fd51ba..8b038b9b 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -40,6 +40,8 @@ $out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : gmdate("Y-m-d", intval($ $lics = pkg_licenses($row["ID"]); $grps = pkg_groups($row["ID"]); +$deps = pkg_dependencies($row["ID"]); + usort($deps, function($x, $y) { if ($x[1] != $y[1]) { if ($x[1] == "depends") { @@ -80,7 +82,6 @@ foreach ($rels as $rel) { } } -$deps = pkg_dependencies($row["ID"]); $requiredby = pkg_required($row["Name"], $rels_p); # $sources[0] = 'src'; From d0f8b285e4b87743bc6795dac6a7b4875649aed6 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 11:15:33 +0200 Subject: [PATCH 0084/1891] Fix a PHP "Undefined index" notice Signed-off-by: Lukas Fleischer --- web/html/packages.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/html/packages.php b/web/html/packages.php index 38a2e296..1b892781 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -21,7 +21,11 @@ if (!isset($pkgid) || !isset($pkgname)) { $details = array(); if (isset($pkgid)) { $details = pkg_get_details($pkgid); - $pkgname = $details['Name']; + if (isset($details['Name'])) { + $pkgname = $details['Name']; + } else { + $pkgname = null; + } } else { unset($pkgname); } From 90e96e3728b727f2318fb119a2ca165e81b11608 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 11:28:04 +0200 Subject: [PATCH 0085/1891] Redirect to details pages after performing actions After performing a package base action on a separate page, return to the corresponding package base details page. Partly fixes FS#46545. Signed-off-by: Lukas Fleischer --- web/html/pkgdel.php | 2 +- web/html/pkgdisown.php | 2 +- web/html/pkgflag.php | 2 +- web/html/pkgmerge.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/html/pkgdel.php b/web/html/pkgdel.php index eb20967f..c522e25b 100644 --- a/web/html/pkgdel.php +++ b/web/html/pkgdel.php @@ -26,7 +26,7 @@ if (has_credential(CRED_PKGBASE_DELETE)): ?>

    -
    +
    diff --git a/web/html/pkgdisown.php b/web/html/pkgdisown.php index 48429396..7ca6e6a1 100644 --- a/web/html/pkgdisown.php +++ b/web/html/pkgdisown.php @@ -33,7 +33,7 @@ if (has_credential(CRED_PKGBASE_DISOWN, $maintainer_uids)): ?>

    - +
    diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php index bfe89e03..b1ca03b2 100644 --- a/web/html/pkgflag.php +++ b/web/html/pkgflag.php @@ -27,7 +27,7 @@ if (has_credential(CRED_PKGBASE_FLAG)): ?> '', ''); ?>

    - +
    diff --git a/web/html/pkgmerge.php b/web/html/pkgmerge.php index f6e951b5..35113902 100644 --- a/web/html/pkgmerge.php +++ b/web/html/pkgmerge.php @@ -28,7 +28,7 @@ if (has_credential(CRED_PKGBASE_DELETE)): ?>

    - +
    From 4fe513d838373575cf173fafbd0bc6e7ce30090a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 11:56:01 +0200 Subject: [PATCH 0086/1891] Do not redirect to details page after deletion When deleting a package base from the package base deletion form, do not try to redirect to the package base details page afterwards. Instead, jump to the package overview. Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index a241c749..b98dc648 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -77,6 +77,7 @@ if (check_token()) { if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) { list($ret, $output) = pkgbase_delete($ids, NULL, $via); unset($_GET['ID']); + unset($base_id); } else { $merge_base_id = pkgbase_from_name($_POST['merge_Into']); @@ -89,6 +90,7 @@ if (check_token()) { } else { list($ret, $output) = pkgbase_delete($ids, $merge_base_id, $via); unset($_GET['ID']); + unset($base_id); } } } From 62c13e2c0c55dfee703245b3a210f8d0e2eb5c5e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 12:02:43 +0200 Subject: [PATCH 0087/1891] Do not show ".SRCINFO unchanged" warning on restore Since 612300b (Show a warning if .SRCINFO is unchanged, 2015-09-29), the git-update script displays a warning when a ref update does not affect the content of the package base meta data. We also invoke git-update to rebuild the package base details in the aurweb database when a package base is restored via the SSH interface. In that case, fake information is passed to the update hook: Both the old and the new object IDs refer to the current HEAD. Check for such "Everything up-to-date" updates and not display the ".SRCINFO unchanged" in these cases. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index b4185251..6e09517f 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -286,7 +286,7 @@ for commit in walker: die_commit('missing source file: {:s}'.format(fname), str(commit.id)) # Display a warning if .SRCINFO is unchanged. -if sha1_old != "0000000000000000000000000000000000000000": +if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): srcinfo_id_old = repo[sha1_old].tree['.SRCINFO'].id srcinfo_id_new = repo[sha1_new].tree['.SRCINFO'].id if srcinfo_id_old == srcinfo_id_new: From eb3b0d537d9be33934f9cf8c57e17c3127fa41bf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 3 Oct 2015 12:12:03 +0200 Subject: [PATCH 0088/1891] Release 4.1.1 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index a376fcd3..7241c3ef 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Sat, 3 Oct 2015 16:58:46 +0200 Subject: [PATCH 0089/1891] notify: Do not wrap references When sending notifications, do not wrap lines from the references section. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 60 ++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index f6bf6ffb..56c15d57 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -26,8 +26,9 @@ sender = config.get('notifications', 'sender') reply_to = config.get('notifications', 'reply-to') -def send_notification(to, subject, body, cc=None, reference=None): - body = str.join('\n', [textwrap.fill(line) for line in body.splitlines()]) +def send_notification(to, subject, body, refs, cc=None, reference=None): + body = '\n'.join([textwrap.fill(line) for line in body.splitlines()]) + body += '\n\n' + refs for recipient in to: msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') @@ -91,10 +92,9 @@ def send_resetkey(cur, uid): 'associated with your email address. If you wish to reset your ' \ 'password follow the link [1] below, otherwise ignore this ' \ 'message and nothing will happen.' % (username) - body += '\n\n' - body += '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey + refs = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey - send_notification([to], subject, body) + send_notification([to], subject, body, refs) def welcome(cur, uid): cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', @@ -106,10 +106,9 @@ def welcome(cur, uid): 'password for your new account, please click the link [1] below. ' \ 'If the link does not work, try copying and pasting it into your ' \ 'browser.' - body += '\n\n' - body += '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey + body = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey - send_notification([to], subject, body) + send_notification([to], subject, body, refs) def comment(cur, uid, pkgbase_id): user = username_from_id(cur, uid) @@ -128,12 +127,11 @@ def comment(cur, uid, pkgbase_id): body += 'If you no longer wish to receive notifications about this ' \ 'package, please go to the package page [2] and select "%s".' % \ ('Disable notifications') - body += '\n\n' - body += '[1] ' + user_uri + '\n' - body += '[2] ' + pkgbase_uri + refs = '[1] ' + user_uri + '\n' + refs += '[2] ' + pkgbase_uri thread_id = '' - send_notification(to, subject, body, reference=thread_id) + send_notification(to, subject, body, refs, reference=thread_id) def flag(cur, uid, pkgbase_id): user = username_from_id(cur, uid) @@ -170,19 +168,17 @@ def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): 'If you no longer wish receive notifications about the new ' \ 'package, please go to [3] and click "%s".' %\ (user, old_pkgbase, new_pkgbase, 'Disable notifications') - body += '\n\n' - body += '[1] ' + user_uri + '\n' - body += '[2] ' + pkgbase_uri + '\n' - body += '[3] ' + new_pkgbase_uri + refs = '[1] ' + user_uri + '\n' + refs += '[2] ' + pkgbase_uri + '\n' + refs += '[3] ' + new_pkgbase_uri else: body = '%s [1] deleted %s [2].\n\n' \ 'You will no longer receive notifications about this ' \ 'package.' % (user, old_pkgbase) - body += '\n\n' - body += '[1] ' + user_uri + '\n' - body += '[2] ' + pkgbase_uri + refs = '[1] ' + user_uri + '\n' + refs += '[2] ' + pkgbase_uri - send_notification(to, subject, body) + send_notification(to, subject, body, refs) def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): user = username_from_id(cur, uid) @@ -200,19 +196,19 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): merge_into_uri = aur_location + '/pkgbase/' + merge_into + '/' body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \ (user, pkgbase, merge_into) - body += '\n\n' + text + '\n\n' - body += '[1] ' + user_uri + '\n' - body += '[2] ' + pkgbase_uri + '\n' - body += '[3] ' + merge_into_uri + body += '\n\n' + text + refs = '[1] ' + user_uri + '\n' + refs += '[2] ' + pkgbase_uri + '\n' + refs += '[3] ' + merge_into_uri else: body = '%s [1] filed a %s request for %s [2]:' % \ (user, reqtype, pkgbase) - body += '\n\n' + text + '\n\n' - body += '[1] ' + user_uri + '\n' - body += '[2] ' + pkgbase_uri + '\n' + body += '\n\n' + text + refs = '[1] ' + user_uri + '\n' + refs += '[2] ' + pkgbase_uri + '\n' thread_id = '' - send_notification(to, subject, body, cc, thread_id) + send_notification(to, subject, body, refs, cc, thread_id) def request_close(cur, uid, reqid, reason): user = username_from_id(cur, uid) @@ -226,13 +222,13 @@ def request_close(cur, uid, reqid, reason): subject = '[PRQ#%d] Request %s' % (int(reqid), reason.title()) body = 'Request #%d has been %s by %s [1]' % (int(reqid), reason, user) if text.strip() == '': - body += '.\n\n' + body += '.' else: - body += ':\n\n' + text + '\n\n' - body += '[1] ' + user_uri + body += ':\n\n' + text + refs = '[1] ' + user_uri thread_id = '' - send_notification(to, subject, body, cc, thread_id) + send_notification(to, subject, body, refs, cc, thread_id) if __name__ == '__main__': From bc2ee0c63fcb18c0ab6494b167803a0b25a4a158 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 4 Oct 2015 09:27:28 +0200 Subject: [PATCH 0090/1891] Add documentation of the RPC interface Convert the RPC interface documentation from web/html/rpc.php to AsciiDoc and add it to the documentation directory. Signed-off-by: Lukas Fleischer --- doc/rpc.txt | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 doc/rpc.txt diff --git a/doc/rpc.txt b/doc/rpc.txt new file mode 100644 index 00000000..b3795155 --- /dev/null +++ b/doc/rpc.txt @@ -0,0 +1,33 @@ +aurweb RPC interface +==================== + +Allowed methods +--------------- + +* `search` +* `info` +* `multiinfo` +* `msearch` + +Each method requires the following HTTP GET syntax: ++type=_methodname_&arg=_data_+ + +Where _methodname_ is the name of an allowed method, and _data_ is the argument +to the call. + +If you need jsonp type callback specification, you can provide an additional +variable _callback_. + +Examples +-------- + +`search`:: + `http://aur-url/rpc.php?type=search&arg=foobar` +`info`:: + `http://aur-url/rpc.php?type=info&arg=foobar` +`multiinfo`:: + `http://aur-url/rpc.php?type=multiinfo&arg[]=foo&arg[]=bar` +`msearch`:: + `http://aur-url/rpc.php?type=msearch&arg=john` +Callback:: + `http://aur-url/rpc.php?type=search&arg=foobar&callback=jsonp1192244621103` From 261c7f74dd17ad277fc9e1a1478983749578f133 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 4 Oct 2015 09:50:05 +0200 Subject: [PATCH 0091/1891] aurjson: Add "maintainer" search type Deprecate the msearch command and add a new search type to the search command. Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 43 ++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 8ca028ae..f4d5b3e6 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -17,7 +17,7 @@ class AurJSON { 'suggest-pkgbase', 'get-comment-form' ); private static $exposed_fields = array( - 'name', 'name-desc' + 'name', 'name-desc', 'maintainer' ); private static $fields_v1 = array( 'Packages.ID', 'Packages.Name', @@ -358,23 +358,32 @@ class AurJSON { */ private function search($http_data) { $keyword_string = $http_data['arg']; + if (isset($http_data['search_by'])) { $search_by = $http_data['search_by']; } else { $search_by = 'name-desc'; } - if (strlen($keyword_string) < 2) { - return $this->json_error('Query arg too small'); - } + if ($search_by === 'name' || $search_by === 'name-desc') { + if (strlen($keyword_string) < 2) { + return $this->json_error('Query arg too small'); + } + $keyword_string = $this->dbh->quote("%" . addcslashes($keyword_string, '%_') . "%"); - $keyword_string = $this->dbh->quote("%" . addcslashes($keyword_string, '%_') . "%"); - - if ($search_by === 'name') { - $where_condition = "(Packages.Name LIKE $keyword_string)"; - } else if ($search_by === 'name-desc') { - $where_condition = "(Packages.Name LIKE $keyword_string OR "; - $where_condition .= "Description LIKE $keyword_string)"; + if ($search_by === 'name') { + $where_condition = "(Packages.Name LIKE $keyword_string)"; + } else if ($search_by === 'name-desc') { + $where_condition = "(Packages.Name LIKE $keyword_string OR "; + $where_condition .= "Description LIKE $keyword_string)"; + } + } else if ($search_by === 'maintainer') { + if (empty($keyword_string)) { + $where_condition = "Users.ID is NULL"; + } else { + $keyword_string = $this->dbh->quote($keyword_string); + $where_condition = "Users.Username = $keyword_string "; + } } return $this->process_query('search', $where_condition); @@ -443,16 +452,8 @@ class AurJSON { * @return mixed Returns an array of value data containing the package data */ private function msearch($http_data) { - $maintainer = $http_data['arg']; - - if (empty($maintainer)) { - $where_condition = "Users.ID is NULL"; - } else { - $maintainer = $this->dbh->quote($maintainer); - $where_condition = "Users.Username = $maintainer "; - } - - return $this->process_query('msearch', $where_condition); + $http_data['search_by'] = 'maintainer'; + return $this->search($http_data); } /* From 3c06716c729580f28c20d7b7522a3382ed857322 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 4 Oct 2015 09:57:35 +0200 Subject: [PATCH 0092/1891] aurjson: Merge info and multiinfo commands Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index f4d5b3e6..2bf2e7a3 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -76,7 +76,7 @@ class AurJSON { if (isset($http_data['v'])) { $this->version = intval($http_data['v']); } - if ($this->version < 1 || $this->version > 4) { + if ($this->version < 1 || $this->version > 5) { return $this->json_error('Invalid version specified.'); } @@ -93,6 +93,9 @@ class AurJSON { $this->dbh = DB::connect(); $type = str_replace('-', '_', $http_data['type']); + if ($type == 'info' && $this->version >= 5) { + $type = 'multiinfo'; + } $json = call_user_func(array(&$this, $type), $http_data); $etag = md5($json); @@ -250,7 +253,7 @@ class AurJSON { } elseif ($this->version >= 2) { if ($this->version == 2 || $this->version == 3) { $fields = implode(',', self::$fields_v2); - } else if ($this->version == 4) { + } else if ($this->version == 4 || $this->version == 5) { $fields = implode(',', self::$fields_v4); } $query = "SELECT {$fields} " . From a8552f5444d4f42c2d81db60fce837b3c3d62501 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 4 Oct 2015 10:34:49 +0200 Subject: [PATCH 0093/1891] Update RPC interface documentation Signed-off-by: Lukas Fleischer --- doc/rpc.txt | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/doc/rpc.txt b/doc/rpc.txt index b3795155..ee1fa1ec 100644 --- a/doc/rpc.txt +++ b/doc/rpc.txt @@ -1,33 +1,36 @@ -aurweb RPC interface +aurweb RPC Interface ==================== -Allowed methods +Package Search +-------------- + +Package searches can be performed by issuing HTTP GET requests of the form ++/rpc/?v=5&type=search&search_by=_by_&arg=_keywords_+ where _by_ is either +`name` (search by package name only), `name-desc` (search by package name and +description) or `maintainer` (search by package maintainer) and _keywords_ is +the search argument. The _search_by_ parameter can be skipped and defaults to +`name-desc`. + +If a maintainer search is performed and the search argument is left empty, a +list of orphan packages is returned. + +Package Details --------------- -* `search` -* `info` -* `multiinfo` -* `msearch` - -Each method requires the following HTTP GET syntax: -+type=_methodname_&arg=_data_+ - -Where _methodname_ is the name of an allowed method, and _data_ is the argument -to the call. - -If you need jsonp type callback specification, you can provide an additional -variable _callback_. +Package information can be obtained by issuing HTTP GET requests of the form ++/rpc/?v=5&type=info&arg[]=_pkg1_&arg[]=_pkg2_&...+ where _pkg1_, _pkg2_, ... +are the names of packages to retrieve package details for. Examples -------- `search`:: - `http://aur-url/rpc.php?type=search&arg=foobar` + `/rpc/?v=5&type=search&arg=foobar` +`search` by maintainer:: + `/rpc/?v=5&type=search&search_by=maintainer&arg=john` +`search` with callback:: + `/rpc/?v=5&type=search&arg=foobar&callback=jsonp1192244621103` `info`:: - `http://aur-url/rpc.php?type=info&arg=foobar` -`multiinfo`:: - `http://aur-url/rpc.php?type=multiinfo&arg[]=foo&arg[]=bar` -`msearch`:: - `http://aur-url/rpc.php?type=msearch&arg=john` -Callback:: - `http://aur-url/rpc.php?type=search&arg=foobar&callback=jsonp1192244621103` + `/rpc/?v=5&type=info&arg[]=foobar` +`info` with multiple packages:: + `/rpc/?v=5&type=info&arg[]=foo&arg[]=bar` From a99c0fe5d33101a2c4753a350f5bf63f8c93dc68 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 4 Oct 2015 10:40:59 +0200 Subject: [PATCH 0094/1891] Add documentation Makefile Signed-off-by: Lukas Fleischer --- doc/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/Makefile diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..df54c5d8 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,9 @@ +all: rpc.html + +clean: + rm -rf *.html + +%.html: %.txt + asciidoc $< + +.PHONY: all clean From 9d8345d4e09a16f0d4067638560e2e8318727d03 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 4 Oct 2015 10:43:38 +0200 Subject: [PATCH 0095/1891] rpc.php: Display generated documentation Instead of hardcoding the RPC interface documentation in rpc.php, include the HTML code of the documentation page generated by AsciiDoc. Signed-off-by: Lukas Fleischer --- web/html/rpc.php | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/web/html/rpc.php b/web/html/rpc.php index 415dcb82..64c95622 100644 --- a/web/html/rpc.php +++ b/web/html/rpc.php @@ -12,33 +12,6 @@ if ( isset($_GET['type']) ) { echo $rpc_o->handle($_GET); } else { - // dump a simple usage output for people to use. - // this could be moved to an api doc in the future, or generated from - // the AurJSON class directly with phpdoc. For now though, just putting it - // here. -?> - -

    Allowed methods

    -
      -
    • search
    • -
    • info
    • -
    • multiinfo
    • -
    • msearch
    • -
    -

    Each method requires the following HTTP GET syntax:

    -
    type=methodname&arg=data
    -

    Where methodname is the name of an allowed method, and data is the argument to the call.

    -

    If you need jsonp type callback specification, you can provide an additional variable callback.

    -

    Examples

    -
    -
    search
    http://aur-url/rpc.php?type=search&arg=foobar
    -
    info
    http://aur-url/rpc.php?type=info&arg=foobar
    -
    multiinfo
    http://aur-url/rpc.php?type=multiinfo&arg[]=foo&arg[]=bar
    -
    msearch
    http://aur-url/rpc.php?type=msearch&arg=john
    -
    Callback
    http://aur-url/rpc.php?type=search&arg=foobar&callback=jsonp1192244621103
    -
    - - From 1f6237ffa73f1cc931ec7cb2abbdd6ff54e1581a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 9 Oct 2015 17:35:29 +0200 Subject: [PATCH 0096/1891] aurjson: Rename the search_by parameter to "by" This parameter is only supported by the search command. We do not need to repeat ourselves. Signed-off-by: Lukas Fleischer --- doc/rpc.txt | 13 ++++++++----- web/lib/aurjson.class.php | 14 +++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/doc/rpc.txt b/doc/rpc.txt index ee1fa1ec..f353ff01 100644 --- a/doc/rpc.txt +++ b/doc/rpc.txt @@ -5,11 +5,14 @@ Package Search -------------- Package searches can be performed by issuing HTTP GET requests of the form -+/rpc/?v=5&type=search&search_by=_by_&arg=_keywords_+ where _by_ is either -`name` (search by package name only), `name-desc` (search by package name and -description) or `maintainer` (search by package maintainer) and _keywords_ is -the search argument. The _search_by_ parameter can be skipped and defaults to -`name-desc`. ++/rpc/?v=5&type=search&by=_field_&arg=_keywords_+ where _keywords_ is the +search argument and _field_ is one of the following values: + +* `name` (search by package name only) +* `name-desc` (search by package name and description) +* `maintainer` (search by package maintainer) + +The _by_ parameter can be skipped and defaults to `name-desc`. If a maintainer search is performed and the search argument is left empty, a list of orphan packages is returned. diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 2bf2e7a3..15482327 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -86,8 +86,12 @@ class AurJSON { if (!in_array($http_data['type'], self::$exposed_methods)) { return $this->json_error('Incorrect request type specified.'); } - if (isset($http_data['search_by']) && !in_array($http_data['search_by'], self::$exposed_fields)) { - return $this->json_error('Incorrect search_by field specified.'); + + if (isset($http_data['search_by']) && !isset($http_data['by'])) { + $http_data['by'] = $http_data['search_by']; + } + if (isset($http_data['by']) && !in_array($http_data['by'], self::$exposed_fields)) { + return $this->json_error('Incorrect by field specified.'); } $this->dbh = DB::connect(); @@ -362,8 +366,8 @@ class AurJSON { private function search($http_data) { $keyword_string = $http_data['arg']; - if (isset($http_data['search_by'])) { - $search_by = $http_data['search_by']; + if (isset($http_data['by'])) { + $search_by = $http_data['by']; } else { $search_by = 'name-desc'; } @@ -455,7 +459,7 @@ class AurJSON { * @return mixed Returns an array of value data containing the package data */ private function msearch($http_data) { - $http_data['search_by'] = 'maintainer'; + $http_data['by'] = 'maintainer'; return $this->search($http_data); } From c76499993f37976f14e8e30eb8bb06d53166d5f4 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 10 Oct 2015 17:25:03 +0200 Subject: [PATCH 0097/1891] notify: Split out email header generation Signed-off-by: Lukas Fleischer --- scripts/notify.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 56c15d57..4e042347 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -26,7 +26,13 @@ sender = config.get('notifications', 'sender') reply_to = config.get('notifications', 'reply-to') -def send_notification(to, subject, body, refs, cc=None, reference=None): +def headers_cc(cclist): + return {'Cc': str.join(', ', cclist)} + +def headers_reply(thread_id): + return {'In-Reply-To': thread_id, 'References': thread_id} + +def send_notification(to, subject, body, refs, headers={}): body = '\n'.join([textwrap.fill(line) for line in body.splitlines()]) body += '\n\n' + refs @@ -37,12 +43,8 @@ def send_notification(to, subject, body, refs, cc=None, reference=None): msg['Reply-to'] = reply_to msg['To'] = recipient - if cc: - msg['Cc'] = str.join(', ', cc) - - if reference: - msg['In-Reply-To'] = reference - msg['References'] = reference + for key, value in headers.items(): + msg[key] = value p = subprocess.Popen([sendmail, '-t', '-oi'], stdin=subprocess.PIPE) p.communicate(msg.as_bytes()) @@ -130,8 +132,9 @@ def comment(cur, uid, pkgbase_id): refs = '[1] ' + user_uri + '\n' refs += '[2] ' + pkgbase_uri thread_id = '' + headers = headers_reply(thread_id) - send_notification(to, subject, body, refs, reference=thread_id) + send_notification(to, subject, body, refs, headers) def flag(cur, uid, pkgbase_id): user = username_from_id(cur, uid) @@ -207,8 +210,9 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): refs = '[1] ' + user_uri + '\n' refs += '[2] ' + pkgbase_uri + '\n' thread_id = '' + headers = headers_reply(thread_id) + headers_cc(cc) - send_notification(to, subject, body, refs, cc, thread_id) + send_notification(to, subject, body, refs, headers) def request_close(cur, uid, reqid, reason): user = username_from_id(cur, uid) @@ -227,8 +231,9 @@ def request_close(cur, uid, reqid, reason): body += ':\n\n' + text refs = '[1] ' + user_uri thread_id = '' + headers = headers_reply(thread_id) + headers_cc(cc) - send_notification(to, subject, body, refs, cc, thread_id) + send_notification(to, subject, body, refs, headers) if __name__ == '__main__': From 092e00f4687dced8f4174891dd4cabd6d4c2617d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 10 Oct 2015 17:26:26 +0200 Subject: [PATCH 0098/1891] notify: Fix references in request notifications When sending notifications upon request creation, set an initial message ID instead of setting the Reply-To and References headers. This used to work but the behavior was unintentionally changed in 9746a65 (Port notification routines to Python, 2015-06-27). Fixes FS#46645. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/notify.py b/scripts/notify.py index 4e042347..42a657ec 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -29,6 +29,9 @@ reply_to = config.get('notifications', 'reply-to') def headers_cc(cclist): return {'Cc': str.join(', ', cclist)} +def headers_msgid(thread_id): + return {'Message-ID': thread_id} + def headers_reply(thread_id): return {'In-Reply-To': thread_id, 'References': thread_id} @@ -210,7 +213,7 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): refs = '[1] ' + user_uri + '\n' refs += '[2] ' + pkgbase_uri + '\n' thread_id = '' - headers = headers_reply(thread_id) + headers_cc(cc) + headers = headers_msgid(thread_id) + headers_cc(cc) send_notification(to, subject, body, refs, headers) From 34800e5ecf985cb22987ed8acbd0584c3bb4a4fa Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 16 Oct 2015 16:37:35 +0200 Subject: [PATCH 0099/1891] notify: Fix welcome/flag notifications Fixes two regressions introduced in commit 6681e56 (notify: Do not wrap references, 2015-10-03). Fixes FS#46742. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 42a657ec..ab652772 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -111,7 +111,7 @@ def welcome(cur, uid): 'password for your new account, please click the link [1] below. ' \ 'If the link does not work, try copying and pasting it into your ' \ 'browser.' - body = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey + refs = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey send_notification([to], subject, body, refs) @@ -151,11 +151,11 @@ def flag(cur, uid, pkgbase_id): subject = 'AUR Out-of-date Notification for %s' % (pkgbase) body = 'Your package %s [1] has been flagged out-of-date by %s [2]:' % \ (pkgbase, user) - body += '\n\n' + text + '\n\n' - body += '[1] ' + pkgbase_uri + '\n' - body += '[2] ' + user_uri + body += '\n\n' + text + refs = '[1] ' + pkgbase_uri + '\n' + refs += '[2] ' + user_uri - send_notification(to, subject, body) + send_notification(to, subject, body, refs) def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): user = username_from_id(cur, uid) From fd6ba76431c428679f964fef8f82912efad680f5 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 17 Oct 2015 11:58:27 +0200 Subject: [PATCH 0100/1891] Make copyright notice translatable Fixes FS#46747. Signed-off-by: Lukas Fleischer --- web/template/footer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/footer.php b/web/template/footer.php index 1b3c9363..7e505a33 100644 --- a/web/template/footer.php +++ b/web/template/footer.php @@ -5,7 +5,7 @@

    aurweb

    -

    Copyright © 2004- aurweb Development Team.

    +

    From 2f6471b0b1c039e653a8787e5faeaa13dabb2e46 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 17 Oct 2015 12:13:22 +0200 Subject: [PATCH 0101/1891] Refactor pkgbase_set_comaintainers() This makes the code slightly more efficient and allows for easily determining the users that were added/removed to the co-maintainer list. Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index cb756f61..bb9d2415 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -1023,7 +1023,7 @@ function pkgbase_set_comaintainers($base_id, $users) { $dbh = DB::connect(); - $uids = array(); + $uids_new = array(); foreach($users as $user) { $q = "SELECT ID FROM Users "; $q .= "WHERE UserName = " . $dbh->quote($user); @@ -1034,18 +1034,32 @@ function pkgbase_set_comaintainers($base_id, $users) { return array(false, __("Invalid user name: %s", $user)); } - $uids[] = $uid; + $uids_new[] = $uid; } - $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id); - $dbh->exec($q); + $q = sprintf("SELECT UsersID FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id); + $result = $dbh->query($q); + $uids_old = $result->fetchAll(PDO::FETCH_COLUMN, 0); + + $uids_add = array_diff($uids_new, $uids_old); + $uids_rem = array_diff($uids_old, $uids_new); $i = 1; - foreach ($uids as $uid) { - $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i); + foreach ($uids_new as $uid) { + if (in_array($uid, $uids_add)) { + $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i); + } else { + $q = sprintf("UPDATE PackageComaintainers SET Priority = %d WHERE PackageBaseID = %d AND UsersID = %d", $i, $base_id, $uid); + } + $dbh->exec($q); $i++; } + foreach ($uids_rem as $uid) { + $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d AND UsersID = %d", $base_id, $uid); + $dbh->exec($q); + } + return array(true, __("The package base co-maintainers have been updated.")); } From 4411a55ec9a131619e8e8f33c2fe2b8d3da21ee2 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 17 Oct 2015 14:48:10 +0200 Subject: [PATCH 0102/1891] Send notifications when changing co-maintainership Implements FS#45590. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 31 +++++++++++++++++++++++++++++++ web/lib/pkgbasefuncs.inc.php | 2 ++ 2 files changed, 33 insertions(+) diff --git a/scripts/notify.py b/scripts/notify.py index ab652772..4832baf7 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -65,6 +65,10 @@ def pkgbase_from_pkgreq(cur, reqid): [reqid]) return cur.fetchone()[0] +def get_user_email(cur, uid): + cur.execute('SELECT Email FROM Users WHERE ID = %s', [uid]) + return cur.fetchone()[0] + def get_maintainer_email(cur, pkgbase_id): cur.execute('SELECT Users.Email FROM Users ' + 'INNER JOIN PackageBases ' + @@ -157,6 +161,31 @@ def flag(cur, uid, pkgbase_id): send_notification(to, subject, body, refs) +def comaintainer_add(cur, pkgbase_id, uid): + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = [get_user_email(cur, uid)] + + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase) + body = 'You were added to the co-maintainer list of %s [1].' % (pkgbase) + refs = '[1] ' + pkgbase_uri + '\n' + + send_notification(to, subject, body, refs) + +def comaintainer_remove(cur, pkgbase_id, uid): + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = [get_user_email(cur, uid)] + + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase) + body = 'You were removed from the co-maintainer list of %s [1].' % \ + (pkgbase) + refs = '[1] ' + pkgbase_uri + '\n' + + send_notification(to, subject, body, refs) + def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): user = username_from_id(cur, uid) old_pkgbase = pkgbase_from_id(cur, old_pkgbase_id) @@ -246,6 +275,8 @@ if __name__ == '__main__': 'welcome': welcome, 'comment': comment, 'flag': flag, + 'comaintainer-add': comaintainer_add, + 'comaintainer-remove': comaintainer_remove, 'delete': delete, 'request-open': request_open, 'request-close': request_close, diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index bb9d2415..aad9d14d 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -1048,6 +1048,7 @@ function pkgbase_set_comaintainers($base_id, $users) { foreach ($uids_new as $uid) { if (in_array($uid, $uids_add)) { $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i); + notify(array('comaintainer-add', $base_id, $uid)); } else { $q = sprintf("UPDATE PackageComaintainers SET Priority = %d WHERE PackageBaseID = %d AND UsersID = %d", $i, $base_id, $uid); } @@ -1059,6 +1060,7 @@ function pkgbase_set_comaintainers($base_id, $users) { foreach ($uids_rem as $uid) { $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d AND UsersID = %d", $base_id, $uid); $dbh->exec($q); + notify(array('comaintainer-remove', $base_id, $uid)); } return array(true, __("The package base co-maintainers have been updated.")); From 16765d553233e50b326456393108729b1f3828bf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Oct 2015 18:41:43 +0200 Subject: [PATCH 0103/1891] Track providers in the official repositories Maintain a list of virtual provisions of packages from the official binary package repositories. The list can be updated using the aurblup script, e.g. via a cronjob. This allows for adding proper links to package dependencies: If an AUR package depends on a package from the official repositories (or on a name provided by a package from the official repositories), add a link to the corresponding archweb package details page. If an AUR package depends on another AUR package (or on a name provided by another AUR package), add a link to the corresponding aurweb package details page. Otherwise, just display the name and do not add a link at all. Fixes FS#46549. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 10 +++++++ scripts/aurblup.py | 13 ++++++++ upgrading/4.2.0.txt | 11 +++++++ web/lib/pkgfuncs.inc.php | 64 ++++++++++++++++++++++++++++++---------- 4 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 upgrading/4.2.0.txt diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 53dc468b..0a0c8069 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -301,6 +301,16 @@ CREATE TABLE PackageBlacklist ( UNIQUE (Name) ) ENGINE = InnoDB; +-- Providers in the official repositories +-- +CREATE TABLE OfficialProviders ( + ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + Name VARCHAR(64) NOT NULL, + Provides VARCHAR(64) NOT NULL, + PRIMARY KEY (ID) +) ENGINE = InnoDB; +CREATE UNIQUE INDEX ProviderNameProvides ON OfficialProviders (Name, Provides); + -- Define package request types -- CREATE TABLE RequestTypes ( diff --git a/scripts/aurblup.py b/scripts/aurblup.py index d6d0c3cd..5397528e 100755 --- a/scripts/aurblup.py +++ b/scripts/aurblup.py @@ -18,6 +18,7 @@ sync_dbs = config.get('aurblup', 'sync-dbs').split(' ') servers = config.get('aurblup', 'servers').split(' ') blacklist = set() +providers = set() h = pyalpm.Handle("/", db_path) for sync_db in sync_dbs: @@ -30,6 +31,8 @@ for sync_db in sync_dbs: for pkg in repo.pkgcache: blacklist.add(pkg.name) [blacklist.add(x) for x in pkg.replaces] + providers.add((pkg.name, pkg.name)) + [providers.add((pkg.name, x)) for x in pkg.provides] db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, @@ -44,5 +47,15 @@ for pkg in blacklist.difference(oldblacklist): for pkg in oldblacklist.difference(blacklist): cur.execute("DELETE FROM PackageBlacklist WHERE Name = %s", [pkg]) +cur.execute("SELECT Name, Provides FROM OfficialProviders") +oldproviders = set(cur.fetchall()) + +for pkg, provides in providers.difference(oldproviders): + cur.execute("INSERT INTO OfficialProviders (Name, Provides) " + "VALUES (%s, %s)", [pkg, provides]) +for pkg, provides in oldproviders.difference(providers): + cur.execute("DELETE FROM OfficialProviders " + "WHERE Name = %s AND Provides = %s", [pkg, provides]) + db.commit() db.close() diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt new file mode 100644 index 00000000..37cbeae1 --- /dev/null +++ b/upgrading/4.2.0.txt @@ -0,0 +1,11 @@ +1. Add a new table to store providers from official packages: + +---- +CREATE TABLE OfficialProviders ( + ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + Name VARCHAR(64) NOT NULL, + Provides VARCHAR(64) NOT NULL, + PRIMARY KEY (ID) +) ENGINE = InnoDB; +CREATE UNIQUE INDEX ProviderNameProvides ON OfficialProviders (Name, Provides); +---- diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 66bc249d..717085d2 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -168,6 +168,9 @@ function pkg_providers($name) { $q.= "INNER JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; $q.= "WHERE rt.Name = 'provides' "; $q.= "AND pr.RelName = " . $dbh->quote($name); + $q.= "UNION "; + $q.= "SELECT 0, Name FROM OfficialProviders "; + $q.= "WHERE Provides = " . $dbh->quote($name); $result = $dbh->query($q); if (!$result) { @@ -280,6 +283,29 @@ function pkg_deplink_annotation($type, $arch, $desc=false) { return $link; } +/** + * Get the HTML code to display a package provider link + * + * @param string $name The name of the provider + * @param bool $official True if the package is in the official repositories + * + * @return string The HTML code of the link to display + */ +function pkg_provider_link($name, $official) { + $link = ''; + $link .= htmlspecialchars($name) . ''; + + return $link; +} + /** * Get the HTML code to display a package dependency link * @@ -312,31 +338,37 @@ function pkg_depend_link($name, $type, $cond, $arch, $pkg_id) { $providers = pkg_providers($name); } + $link = htmlspecialchars($name); + foreach ($providers as $provider) { + if ($provider[1] == $name) { + $is_official = ($provider[0] == 0); + $name = $provider[1]; + $link = pkg_provider_link($name, $is_official); + break; + } + } + $link .= ' ' . htmlspecialchars($cond); + + foreach ($providers as $key => $provider) { + if ($provider[1] == $name) { + unset($providers[$key]); + } + } + if (count($providers) > 0) { - $link = htmlspecialchars($name) . ' '; $link .= '('; foreach ($providers as $provider) { + $is_official = ($provider[0] == 0); $name = $provider[1]; - $link .= ''; - $link .= htmlspecialchars($name) . ', '; + $link .= pkg_provider_link($name, $is_official) . ', '; } $link = substr($link, 0, -2); $link .= ')'; - } else { - $link = ''; - $link .= htmlspecialchars($name) . ''; - $link .= htmlspecialchars($cond); } - return $link . pkg_deplink_annotation($type, $arch, $desc); + $link .= pkg_deplink_annotation($type, $arch, $desc); + + return $link; } /** From 9c70e10aeb9b07981345e5af86350140753a7707 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Oct 2015 22:29:40 +0200 Subject: [PATCH 0104/1891] Check comment length in the backend Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 7 +------ web/lib/pkgbasefuncs.inc.php | 4 ++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index b98dc648..cbbf3cc4 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -49,12 +49,7 @@ $output = ""; $fragment = ""; if (check_token()) { if (current_action("do_Flag")) { - if (strlen($_POST['comments']) >= 3) { - list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); - } else { - $output = __("The selected packages have not been flagged, please enter a comment."); - $ret = false; - } + list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); } elseif (current_action("do_UnFlag")) { list($ret, $output) = pkgbase_unflag($ids); } elseif (current_action("do_Adopt")) { diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index aad9d14d..afccc7de 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -330,6 +330,10 @@ function pkgbase_flag($base_ids, $comment) { return array(false, __("You did not select any packages to flag.")); } + if (strlen($comment) < 3) { + return array(false, __("The selected packages have not been flagged, please enter a comment.")); + } + $uid = uid_from_sid($_COOKIE['AURSID']); $dbh = DB::connect(); From ca954fe95ad9537ad626e16dfec9512f9403e3ca Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Oct 2015 22:32:37 +0200 Subject: [PATCH 0105/1891] Do not redirect when showing errors during flagging Fixes FS#46545. Signed-off-by: Lukas Fleischer --- web/html/pkgflag.php | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php index b1ca03b2..e6e7c647 100644 --- a/web/html/pkgflag.php +++ b/web/html/pkgflag.php @@ -8,6 +8,37 @@ include_once("pkgfuncs.inc.php"); set_lang(); check_sid(); +/* Grab the list of package base IDs to be operated on. */ +$ids = array(); +if (isset($_POST['IDs'])) { + foreach ($_POST['IDs'] as $id => $i) { + $id = intval($id); + if ($id > 0) { + $ids[] = $id; + } + } +} + +/* Perform package base actions. */ +$ret = false; +$output = ""; +if (check_token()) { + if (current_action("do_Flag")) { + list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); + } + + if ($ret) { + header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); + exit(); + } +} + +/* Get default comment. */ +$comment = ''; +if (isset($_POST['comments'])) { + $comment = $_POST['comments']; +} + html_header(__("Flag Package Out-Of-Date")); if (has_credential(CRED_PKGBASE_FLAG)): ?> @@ -27,14 +58,19 @@ if (has_credential(CRED_PKGBASE_FLAG)): ?> '', ''); ?>

    - + + +
    + + +

    - +

    " />

    From 8c87b1df0c0273006892d5947aad64034ee8ec9d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 22 Oct 2015 18:56:59 +0200 Subject: [PATCH 0106/1891] git-serve: Add support for setting keywords This allows for setting keywords using the SSH interface. The syntax is `config keywords ...`. Implements FS#45627. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 57 ++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 45c9a01b..8bd6aa8d 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -25,17 +25,19 @@ ssh_cmdline = config.get('serve', 'ssh-cmdline') enable_maintenance = config.getboolean('options', 'enable-maintenance') maintenance_exc = config.get('options', 'maintenance-exceptions').split() -def pkgbase_exists(pkgbase): +def pkgbase_from_name(pkgbase): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, unix_socket=aur_db_socket) cur = db.cursor() - - cur.execute("SELECT COUNT(*) FROM PackageBases WHERE Name = %s ", - [pkgbase]) - + cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) db.close() - return (cur.fetchone()[0] > 0) + + row = cur.fetchone() + return row[0] if row else None + +def pkgbase_exists(pkgbase): + return (pkgbase_from_name(pkgbase) > 0) def list_repos(user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, @@ -81,6 +83,25 @@ def create_pkgbase(pkgbase, user): db.commit() db.close() +def pkgbase_config_keywords(pkgbase, keywords): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + + db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket) + cur = db.cursor() + + cur.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = %s", + [pkgbase_id]) + for keyword in keywords: + cur.execute("INSERT INTO PackageKeywords (PackageBaseID, Keyword) " + "VALUES (%s, %s)", [pkgbase_id, keyword]) + + db.commit() + db.close() + def check_permissions(pkgbase, user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, @@ -143,6 +164,17 @@ if action == 'git-upload-pack' or action == 'git-receive-pack': os.environ["GIT_NAMESPACE"] = pkgbase cmd = action + " '" + repo_path + "'" os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd) +elif action == 'config': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) < 3: + die_with_help("{:s}: missing option name".format(action)) + pkgbase = cmdargv[1] + option = cmdargv[2] + + if option == 'keywords': + pkgbase_config_keywords(pkgbase, cmdargv[3:]) + elif action == 'list-repos': if len(cmdargv) > 1: die_with_help("{:s}: too many arguments".format(action)) @@ -172,11 +204,12 @@ elif action == 'restore': os.execl(git_update_cmd, git_update_cmd, 'restore') elif action == 'help': die("Commands:\n" + - " help Show this help message and exit.\n" + - " list-repos List all your repositories.\n" + - " restore Restore a deleted package base.\n" + - " setup-repo Create an empty repository.\n" + - " git-receive-pack Internal command used with Git.\n" + - " git-upload-pack Internal command used with Git.") + " config ... Change package base settings.\n" + + " help Show this help message and exit.\n" + + " list-repos List all your repositories.\n" + + " restore Restore a deleted package base.\n" + + " setup-repo Create an empty repository.\n" + + " git-receive-pack Internal command used with Git.\n" + + " git-upload-pack Internal command used with Git.") else: die_with_help("invalid command: {:s}".format(action)) From a2cbc7f646a54cc2c19adc5f76a2ba1003e25c3c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 24 Oct 2015 18:03:19 +0200 Subject: [PATCH 0107/1891] aurjson: Allow underscores in JSONP callback names Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 15482327..9097035f 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -119,7 +119,7 @@ class AurJSON { if (isset($http_data['callback'])) { $callback = $http_data['callback']; - if (!preg_match('/^[a-zA-Z0-9().]{1,128}$/D', $callback)) { + if (!preg_match('/^[a-zA-Z0-9()_.]{1,128}$/D', $callback)) { return $this->json_error('Invalid callback name.'); } header('content-type: text/javascript'); From d7cba28ad2a6ad30219784349b8d327d84dd3dc3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 24 Oct 2015 18:04:26 +0200 Subject: [PATCH 0108/1891] Disable mass unflagging This currently does not work. Disable it until we have proper support for flagging multiple packages on the flag page. Fixes FS#46780. Signed-off-by: Lukas Fleischer --- web/template/pkg_search_results.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index cce533c3..3046c253 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -109,7 +109,6 @@ if (!$result): ?>

    () + ()

    Date: Sun, 25 Oct 2015 10:52:30 +0100 Subject: [PATCH 0116/1891] Support long email addresses According to RFC 3696 (and the associated errata), an email address can be up to 256 characters long. Change the database field and the length limit on all input fields accordingly. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.2.0.txt | 6 ++++++ web/html/login.php | 2 +- web/template/account_edit_form.php | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 0a0c8069..98e8be04 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -25,7 +25,7 @@ CREATE TABLE Users ( AccountTypeID TINYINT UNSIGNED NOT NULL DEFAULT 1, Suspended TINYINT UNSIGNED NOT NULL DEFAULT 0, Username VARCHAR(32) NOT NULL, - Email VARCHAR(64) NOT NULL, + Email VARCHAR(256) NOT NULL, HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0, Passwd CHAR(32) NOT NULL, Salt CHAR(32) NOT NULL DEFAULT '', diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index 37cbeae1..c195f41b 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -9,3 +9,9 @@ CREATE TABLE OfficialProviders ( ) ENGINE = InnoDB; CREATE UNIQUE INDEX ProviderNameProvides ON OfficialProviders (Name, Provides); ---- + +2. Resize the email address field: + +---- +ALTER TABLE Users MODIFY Email VARCHAR(256) NOT NULL; +---- diff --git a/web/html/login.php b/web/html/login.php index cef9be48..0a2a1c97 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -29,7 +29,7 @@ html_header('AUR ' . __("Login"));

    - +

    diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index b25ff397..28da2032 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -69,7 +69,7 @@

    - () + ()

    From 81bfb367c84b6a66b93a5ef7577622ec23b1882b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 26 Oct 2015 20:31:35 +0100 Subject: [PATCH 0117/1891] footer: Close short open tag Fixes a regression introduced in fd6ba76 (Make copyright notice translatable, 2015-10-17). Signed-off-by: Lukas Fleischer --- web/template/footer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/footer.php b/web/template/footer.php index 7e505a33..f5dc2d06 100644 --- a/web/template/footer.php +++ b/web/template/footer.php @@ -5,7 +5,7 @@

    aurweb

    -

    +

    From d87b138a89f734995d33fa91ebdccca59f848673 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 26 Oct 2015 20:34:41 +0100 Subject: [PATCH 0118/1891] notify: Fix merging of header dicts Fixes another regression introduced in c764999 (notify: Split out email header generation, 2015-10-10). Signed-off-by: Lukas Fleischer --- scripts/notify.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 4832baf7..d3d9cb0c 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -242,7 +242,8 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): refs = '[1] ' + user_uri + '\n' refs += '[2] ' + pkgbase_uri + '\n' thread_id = '' - headers = headers_msgid(thread_id) + headers_cc(cc) + headers = headers_reply(thread_id) + headers.update(headers_cc(cc)) send_notification(to, subject, body, refs, headers) @@ -263,7 +264,8 @@ def request_close(cur, uid, reqid, reason): body += ':\n\n' + text refs = '[1] ' + user_uri thread_id = '' - headers = headers_reply(thread_id) + headers_cc(cc) + headers = headers_reply(thread_id) + headers.update(headers_cc(cc)) send_notification(to, subject, body, refs, headers) From 24734d06cefdeeb30c58beb52614a8498a089cb6 Mon Sep 17 00:00:00 2001 From: Stefan Auditor Date: Thu, 12 Nov 2015 09:34:23 +0100 Subject: [PATCH 0119/1891] Shorten Email column to 254 characters Using unique indexes on VARCHAR fields with a character count of more than 255 produces an error in MySQL with InnoDB tables and UTF-8 encoding. Also, as per https://www.rfc-editor.org/errata_search.php?eid=1690, the maximum length for email addresses is limited to 254 characters. Fixes FS#47038. Signed-off-by: Stefan Auditor Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.2.0.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 98e8be04..315a75cb 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -25,7 +25,7 @@ CREATE TABLE Users ( AccountTypeID TINYINT UNSIGNED NOT NULL DEFAULT 1, Suspended TINYINT UNSIGNED NOT NULL DEFAULT 0, Username VARCHAR(32) NOT NULL, - Email VARCHAR(256) NOT NULL, + Email VARCHAR(254) NOT NULL, HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0, Passwd CHAR(32) NOT NULL, Salt CHAR(32) NOT NULL DEFAULT '', diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index c195f41b..1f92ec55 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -13,5 +13,5 @@ CREATE UNIQUE INDEX ProviderNameProvides ON OfficialProviders (Name, Provides); 2. Resize the email address field: ---- -ALTER TABLE Users MODIFY Email VARCHAR(256) NOT NULL; +ALTER TABLE Users MODIFY Email VARCHAR(254) NOT NULL; ---- From 0c599b39b0cead26550cea73194e950718a03d4a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 10 Nov 2015 19:55:34 +0100 Subject: [PATCH 0120/1891] Remove redundant code This code is no longer needed since 9746a65 (Port notification routines to Python, 2015-06-27). Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index afccc7de..3c199d66 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -91,21 +91,7 @@ function pkgbase_add_comment($base_id, $uid, $comment) { $q.= $dbh->quote($comment) . ", UNIX_TIMESTAMP())"; $dbh->exec($q); - /* - * Send e-mail notifications. - * TODO: Move notification logic to separate function where it belongs. - */ - $q = "SELECT CommentNotify.*, Users.Email "; - $q.= "FROM CommentNotify, Users "; - $q.= "WHERE Users.ID = CommentNotify.UserID "; - $q.= "AND CommentNotify.UserID != " . $uid . " "; - $q.= "AND CommentNotify.PackageBaseID = " . intval($base_id); - $result = $dbh->query($q); - $bcc = array(); - - if ($result) { - notify(array('comment', $uid, $base_id), $comment); - } + notify(array('comment', $uid, $base_id), $comment); return array(true, __('Comment has been added.')); } From a114476e8134f27d2dd33b1f023535e3cc8bd094 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 10 Nov 2015 20:21:22 +0100 Subject: [PATCH 0121/1891] Make the notification script configurable Add a configuration option to set the path of the notification script. Signed-off-by: Lukas Fleischer --- conf/config.proto | 1 + web/lib/acctfuncs.inc.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/conf/config.proto b/conf/config.proto index de9acdf7..2390dfa8 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -32,6 +32,7 @@ enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 [notifications] +notify-cmd = /srv/http/aurweb/scripts/notify.py sendmail = /usr/bin/sendmail sender = notify@aur.archlinux.org reply-to = noreply@aur.archlinux.org diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index a2009988..a166d65c 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -1282,7 +1282,7 @@ function account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints) { * @return void */ function notify($params, $text='') { - $cmd = realpath('../../scripts/notify.py'); + $cmd = config_get('notifications', 'notify-cmd'); foreach ($params as $param) { $cmd .= ' ' . escapeshellarg($param); } From 002d348d903c9f46e8fef453279eec5482eb43bf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 14 Nov 2015 13:39:21 +0100 Subject: [PATCH 0122/1891] Describe how to omit "have" lines A new feature in Git allows for omitting "have" lines corresponding to refs outside the current Git namespace. Explain how to enable this feature in the INSTALL instructions and in the Git interface documentation. Signed-off-by: Lukas Fleischer --- INSTALL | 2 ++ doc/git-interface.txt | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/INSTALL b/INSTALL index d68fa269..d9569112 100644 --- a/INSTALL +++ b/INSTALL @@ -46,6 +46,8 @@ Setup on Arch Linux # mkdir /srv/http/aurweb/aur.git/ # cd /srv/http/aurweb/aur.git/ # git init --bare + # git config --local transfer.hideRefs '^refs/' + # git config --local transfer.hideRefs '!refs/' # ln -s ../../git-interface/git-update.py hooks/update # chown -R aur . diff --git a/doc/git-interface.txt b/doc/git-interface.txt index 9ded20f6..4a24eeff 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -80,3 +80,16 @@ request. An example configuration for nginx and fcgiwrap can be found in the INSTALL instructions in the top-level directory. + +Further Configuration +--------------------- + +When using Git namespaces, Git advertises refs outside the current namespace as +so-called "have" lines. This is normally used to reduce traffic but it has the +opposite effect in the case of aurweb: Many essentially useless lines are +transferred to the Git client during `git push` operations. + +In order to omit these advertisements, add the strings "^refs/" and "!refs/" to +the transfer.hideRefs configuration setting. Note that the order of these +patterns is important ("^refs/" must come first) and that Git 2.7 or newer is +required for them to work. From ecb746971c47d5748a554b63922c238bf9cb2fd1 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 25 Nov 2015 01:51:08 -0500 Subject: [PATCH 0123/1891] Change "File Request" to "Submit Request" Apparently the reference to "files" can be confusing. Fixes FS#47167. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/html/pkgreq.php | 2 +- web/template/pkgbase_actions.php | 2 +- web/template/pkgreq_form.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/html/pkgreq.php b/web/html/pkgreq.php index 1e671d00..8348a4f3 100644 --- a/web/html/pkgreq.php +++ b/web/html/pkgreq.php @@ -13,7 +13,7 @@ if (isset($base_id)) { header('Location: /'); exit(); } - html_header(__("File Request")); + html_header(__("Submit Request")); include('pkgreq_form.php'); } elseif (isset($pkgreq_id)) { if (!has_credential(CRED_PKGREQ_CLOSE)) { diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php index 198f7ab4..f8968fb2 100644 --- a/web/template/pkgbase_actions.php +++ b/web/template/pkgbase_actions.php @@ -32,7 +32,7 @@
  • 0) { echo _n('%d pending request', '%d pending requests', $row["RequestCount"]); } ?>
  • -
  • +
  • diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php index 623c2472..6cf8588d 100644 --- a/web/template/pkgreq_form.php +++ b/web/template/pkgreq_form.php @@ -1,5 +1,5 @@
    -

    +

    ', htmlspecialchars($pkgbase_name), ''); ?> @@ -58,7 +58,7 @@

    - " /> + " />

    From 39280152ea66077d20acc795b72105fd38e362f8 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Thu, 26 Nov 2015 10:22:47 -0500 Subject: [PATCH 0124/1891] git-serve: Fix pkgbase_exists() Fixes a regression introduced in 8c87b1d (git-serve: Add support for setting keywords, 2015-10-22). Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 8bd6aa8d..62410e98 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -37,7 +37,7 @@ def pkgbase_from_name(pkgbase): return row[0] if row else None def pkgbase_exists(pkgbase): - return (pkgbase_from_name(pkgbase) > 0) + return pkgbase_from_name(pkgbase) is not None def list_repos(user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, From a9048bb07ff71e992cefaccb6898e6b993bad99b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 25 Nov 2015 08:13:57 +0100 Subject: [PATCH 0125/1891] Dedupe translatable strings Signed-off-by: Lukas Fleischer --- web/html/pkgdel.php | 2 +- web/html/pkgdisown.php | 2 +- web/html/pkgflag.php | 2 +- web/html/pkgmerge.php | 2 +- web/template/comaintainers_form.php | 2 +- web/template/pkgreq_close_form.php | 2 +- web/template/pkgreq_form.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/web/html/pkgdel.php b/web/html/pkgdel.php index c522e25b..21a2677c 100644 --- a/web/html/pkgdel.php +++ b/web/html/pkgdel.php @@ -12,7 +12,7 @@ html_header(__("Package Deletion")); if (has_credential(CRED_PKGBASE_DELETE)): ?>
    -

    +

    :

    ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/html/pkgdisown.php b/web/html/pkgdisown.php index 7ca6e6a1..f24a2d6d 100644 --- a/web/html/pkgdisown.php +++ b/web/html/pkgdisown.php @@ -15,7 +15,7 @@ $comaintainers = pkgbase_get_comaintainers($base_id); if (has_credential(CRED_PKGBASE_DISOWN, $maintainer_uids)): ?>

    -

    +

    :

    ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php index e6e7c647..f50c2085 100644 --- a/web/html/pkgflag.php +++ b/web/html/pkgflag.php @@ -43,7 +43,7 @@ html_header(__("Flag Package Out-Of-Date")); if (has_credential(CRED_PKGBASE_FLAG)): ?>

    -

    +

    :

    ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/html/pkgmerge.php b/web/html/pkgmerge.php index 35113902..c0ce655c 100644 --- a/web/html/pkgmerge.php +++ b/web/html/pkgmerge.php @@ -12,7 +12,7 @@ html_header(__("Package Merging")); if (has_credential(CRED_PKGBASE_DELETE)): ?>

    -

    +

    :

    ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/template/comaintainers_form.php b/web/template/comaintainers_form.php index 050f2550..70a74645 100644 --- a/web/template/comaintainers_form.php +++ b/web/template/comaintainers_form.php @@ -1,5 +1,5 @@

    -

    +

    :

    ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/template/pkgreq_close_form.php b/web/template/pkgreq_close_form.php index 00efafef..59e9c8f4 100644 --- a/web/template/pkgreq_close_form.php +++ b/web/template/pkgreq_close_form.php @@ -1,5 +1,5 @@

    -

    +

    :

    ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php index 6cf8588d..5bd2bfe9 100644 --- a/web/template/pkgreq_form.php +++ b/web/template/pkgreq_form.php @@ -1,5 +1,5 @@

    -

    +

    :

    ', htmlspecialchars($pkgbase_name), ''); ?> From 3088fd0f389dbe4be1c7e62931ed18658ca6d7a2 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Fri, 11 Dec 2015 19:01:30 -0500 Subject: [PATCH 0126/1891] Remove reassignment of base_id in pkg_comments.php Removes reassignment of $base_id in web/template/pkg_comments.php as it is assigned in both pkgbase_display_details() and pkg_display_details(). Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/template/pkg_comments.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 21ce16f4..15547cef 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -1,11 +1,4 @@ From 7d4c0c9ffa55ca60aea24b6aa64417783a15ea80 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Fri, 11 Dec 2015 19:01:31 -0500 Subject: [PATCH 0127/1891] Implement capability to pin comments above others Adds capability to pin comments before others. Implements FS#10863. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 1 + upgrading/4.2.0.txt | 6 +++ web/html/css/aurweb.css | 6 +-- web/html/images/pin.min.svg | 1 + web/html/images/pin.svg | 3 ++ web/html/images/unpin.min.svg | 1 + web/html/images/unpin.svg | 4 ++ web/html/index.php | 2 + web/html/pkgbase.php | 4 ++ web/lib/credentials.inc.php | 2 + web/lib/pkgbasefuncs.inc.php | 80 ++++++++++++++++++++++++++++++++--- web/lib/pkgfuncs.inc.php | 51 +++++++++++++++++++++- web/template/pkg_comments.php | 40 +++++++++++++++--- 13 files changed, 187 insertions(+), 14 deletions(-) create mode 100644 web/html/images/pin.min.svg create mode 100644 web/html/images/pin.svg create mode 100644 web/html/images/unpin.min.svg create mode 100644 web/html/images/unpin.svg diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 315a75cb..55612782 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -261,6 +261,7 @@ CREATE TABLE PackageComments ( EditedTS BIGINT UNSIGNED NULL DEFAULT NULL, EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, DelUsersID INTEGER UNSIGNED NULL DEFAULT NULL, + PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (ID), INDEX (UsersID), INDEX (PackageBaseID), diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index 1f92ec55..1450d5e1 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -15,3 +15,9 @@ CREATE UNIQUE INDEX ProviderNameProvides ON OfficialProviders (Name, Provides); ---- ALTER TABLE Users MODIFY Email VARCHAR(254) NOT NULL; ---- + +3. Add new column in PackageComments for pinning system. + +---- +ALTER TABLE PackageComments ADD COLUMN PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0; +---- diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 11af7471..82b83d9e 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -101,7 +101,7 @@ color: #999; } -.delete-comment-form, .edit-comment { +.delete-comment-form, .pin-comment-form, .edit-comment { float: right; margin-left: 8px; } @@ -112,13 +112,13 @@ top: 1px; } -.delete-comment, .edit-comment { +.delete-comment, .edit-comment, .pin-comment { -webkit-filter: grayscale(100%); filter: grayscale(100%); opacity: 0.6; } -.delete-comment:hover, .edit-comment:hover { +.delete-comment:hover, .edit-comment:hover, .pin-comment:hover { -webkit-filter: none; filter: none; opacity: 1; diff --git a/web/html/images/pin.min.svg b/web/html/images/pin.min.svg new file mode 100644 index 00000000..ac08903d --- /dev/null +++ b/web/html/images/pin.min.svg @@ -0,0 +1 @@ + diff --git a/web/html/images/pin.svg b/web/html/images/pin.svg new file mode 100644 index 00000000..b4ee9eb7 --- /dev/null +++ b/web/html/images/pin.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/html/images/unpin.min.svg b/web/html/images/unpin.min.svg new file mode 100644 index 00000000..3cf2413c --- /dev/null +++ b/web/html/images/unpin.min.svg @@ -0,0 +1 @@ + diff --git a/web/html/images/unpin.svg b/web/html/images/unpin.svg new file mode 100644 index 00000000..de897152 --- /dev/null +++ b/web/html/images/unpin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/web/html/index.php b/web/html/index.php index ec99bb72..e99d22f8 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -182,6 +182,8 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { break; case "/images/x.min.svg": case "/images/pencil.min.svg": + case "/images/pin.min.svg": + case "/images/unpin.min.svg": header("Content-Type: image/svg+xml"); readfile("./$path"); break; diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index cbbf3cc4..45b8084b 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -99,6 +99,10 @@ if (check_token()) { list($ret, $output) = pkgbase_notify($ids, false); } elseif (current_action("do_DeleteComment")) { list($ret, $output) = pkgbase_delete_comment(); + } elseif (current_action("do_PinComment")) { + list($ret, $output) = pkgbase_pin_comment(); + } elseif (current_action("do_UnpinComment")) { + list($ret, $output) = pkgbase_pin_comment(true); } elseif (current_action("do_SetKeywords")) { list($ret, $output) = pkgbase_set_keywords($base_id, preg_split("/[\s,;]+/", $_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY)); } elseif (current_action("do_FileRequest")) { diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index 648d78c8..71bf5ffb 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -8,6 +8,7 @@ define("CRED_ACCOUNT_SEARCH", 5); define("CRED_COMMENT_DELETE", 6); define("CRED_COMMENT_VIEW_DELETED", 22); define("CRED_COMMENT_EDIT", 25); +define("CRED_COMMENT_PIN", 26); define("CRED_PKGBASE_ADOPT", 7); define("CRED_PKGBASE_SET_KEYWORDS", 8); define("CRED_PKGBASE_DELETE", 9); @@ -60,6 +61,7 @@ function has_credential($credential, $approved_users=array()) { case CRED_COMMENT_DELETE: case CRED_COMMENT_VIEW_DELETED: case CRED_COMMENT_EDIT: + case CRED_COMMENT_PIN: case CRED_PKGBASE_ADOPT: case CRED_PKGBASE_SET_KEYWORDS: case CRED_PKGBASE_DELETE: diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 3c199d66..7076c315 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -7,10 +7,11 @@ include_once("pkgreqfuncs.inc.php"); * * @param string $base_id The package base ID to get comment count for * @param bool $include_deleted True if deleted comments should be included + * @param bool $only_pinned True if only pinned comments should be included * * @return string The number of comments left for a specific package */ -function pkgbase_comments_count($base_id, $include_deleted) { +function pkgbase_comments_count($base_id, $include_deleted, $only_pinned=false) { $base_id = intval($base_id); if (!$base_id) { return null; @@ -22,6 +23,9 @@ function pkgbase_comments_count($base_id, $include_deleted) { if (!$include_deleted) { $q.= "AND DelUsersID IS NULL"; } + if ($only_pinned) { + $q.= "AND NOT PinnedTS = 0"; + } $result = $dbh->query($q); if (!$result) { return null; @@ -36,10 +40,11 @@ function pkgbase_comments_count($base_id, $include_deleted) { * @param int $base_id The package base ID to get comments for * @param int $limit Maximum number of comments to return (0 means unlimited) * @param bool $include_deleted True if deleted comments should be included + * @param bool $only_pinned True when only pinned comments are to be included * * @return array All package comment information for a specific package base */ -function pkgbase_comments($base_id, $limit, $include_deleted) { +function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false) { $base_id = intval($base_id); $limit = intval($limit); if (!$base_id) { @@ -48,15 +53,20 @@ function pkgbase_comments($base_id, $limit, $include_deleted) { $dbh = DB::connect(); $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; - $q.= "CommentTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName FROM PackageComments "; + $q.= "PackageBaseID, CommentTS, EditedTS, B.UserName AS EditUserName, "; + $q.= "DelUsersID, C.UserName AS DelUserName, "; + $q.= "PinnedTS FROM PackageComments "; $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; $q.= "WHERE PackageBaseID = " . $base_id . " "; + if (!$include_deleted) { $q.= "AND DelUsersID IS NULL "; } + if ($only_pinned) { + $q.= "AND NOT PinnedTS = 0 "; + } $q.= "ORDER BY CommentTS DESC"; if ($limit > 0) { $q.=" LIMIT " . $limit; @@ -97,6 +107,58 @@ function pkgbase_add_comment($base_id, $uid, $comment) { } /** + * Pin/unpin a package comment + * + * @param bool $unpin True if unpinning rather than pinning + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_pin_comment($unpin=false) { + $uid = uid_from_sid($_COOKIE["AURSID"]); + + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + if (!$unpin) { + if (pkgbase_comments_count($_POST['package_base'], false, true) >= 5){ + return array(false, __("No more than 5 comments can be pinned.")); + } + } + + if (!can_pin_comment($comment_id)) { + if (!$unpin) { + return array(false, __("You are not allowed to pin this comment.")); + } else { + return array(false, __("You are not allowed to unpin this comment.")); + } + } + + $dbh = DB::connect(); + $q = "UPDATE PackageComments "; + if (!$unpin) { + $q.= "SET PinnedTS = UNIX_TIMESTAMP() "; + } else { + $q.= "SET PinnedTS = 0 "; + } + $q.= "WHERE ID = " . intval($comment_id); + $dbh->exec($q); + + if (!$unpin) { + return array(true, __("Comment has been pinned.")); + } else { + return array(true, __("Comment has been unpinned.")); + } +} + +/** + * Get a list of all packages a logged-in user has voted for * * @param string $sid The session ID of the visitor @@ -183,8 +245,16 @@ function pkgbase_display_details($base_id, $row, $SID="") { include('pkg_comment_box.php'); } - $limit = isset($_GET['comments']) ? 0 : 10; $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); + if (!empty($pinned)) { + include('pkg_comments.php'); + unset($pinned); + } + + $limit = isset($_GET['comments']) ? 0 : 10; $comments = pkgbase_comments($base_id, $limit, $include_deleted); if (!empty($comments)) { include('pkg_comments.php'); diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index cedc360e..c2bbe387 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -82,6 +82,47 @@ function can_edit_comment_array($comment) { return has_credential(CRED_COMMENT_EDIT, array($comment['UsersID'])); } +/** + * Determine if the user can pin a specific package comment + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the backend side of comment pinning. + * + * @param string $comment_id The comment ID in the database + * + * @return bool True if the user can pin the comment, otherwise false + */ +function can_pin_comment($comment_id=0) { + $dbh = DB::connect(); + + $q = "SELECT MaintainerUID FROM PackageBases AS pb "; + $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment_id); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_PIN, array($uid)); +} + +/** + * Determine if the user can edit a specific package comment using an array + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the frontend side of comment pinning. + * + * @param array $comment All database information relating a specific comment + * + * @return bool True if the user can edit the comment, otherwise false + */ +function can_pin_comment_array($comment) { + return can_pin_comment($comment['ID']); +} + /** * Check to see if the package name already exists in the database * @@ -582,8 +623,16 @@ function pkg_display_details($id=0, $row, $SID="") { include('pkg_comment_box.php'); } - $limit = isset($_GET['comments']) ? 0 : 10; $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); + if (!empty($pinned)) { + include('pkg_comments.php'); + unset($pinned); + } + + $limit = isset($_GET['comments']) ? 0 : 10; $comments = pkgbase_comments($base_id, $limit, $include_deleted); if (!empty($comments)) { include('pkg_comments.php'); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 15547cef..20463645 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -1,11 +1,18 @@

    - - + + + + + + + +

    @@ -49,6 +56,29 @@ $count = pkgbase_comments_count($base_id, $include_deleted); <?= __('Edit comment') ?> + + = 5)): ?> +
    +
    + + + + + +
    + + + + +
    +
    + + + + +
    + +

    @@ -57,7 +87,7 @@ $count = pkgbase_comments_count($base_id, $include_deleted);

    - 10 && !isset($_GET['comments'])): ?> + 10 && !isset($_GET['comments']) && !isset($pinned)): ?>

    From c085be8c0d0e0c391f49baf44c895f015d329c73 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 13:05:02 +0100 Subject: [PATCH 0128/1891] Only show "last edited" to logged in users Signed-off-by: Lukas Fleischer --- web/template/pkg_comments.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 20463645..4f3ee3d4 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -25,7 +25,7 @@ if (!isset($count)) { $heading = __('Anonymous comment on %s', $date_fmtd); } - if ($row['EditedTS']) { + if ($uid && $row['EditedTS']) { $date_fmtd = gmdate('Y-m-d H:i', $row['EditedTS']); $heading .= ' ('; if ($row['DelUsersID']) { From b8c1cd7cc3270563ef0c4abed930a9f63e1eefce Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 15:12:41 +0100 Subject: [PATCH 0129/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 116 ++++++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 59 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index f2160406..c214761a 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.0.0\n" +"Project-Id-Version: AUR v4.1.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" +"POT-Creation-Date: 2015-12-12 15:11+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -133,7 +133,7 @@ msgstr "" msgid "Submit" msgstr "" -#: html/comaintainers.php +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" @@ -411,10 +411,6 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - #: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " @@ -438,9 +434,8 @@ msgstr "" msgid "Package Deletion" msgstr "" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" +#: html/pkgdel.php template/pkgbase_actions.php +msgid "Delete Package" msgstr "" #: html/pkgdel.php @@ -474,11 +469,6 @@ msgstr "" msgid "Disown Package" msgstr "" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - #: html/pkgdisown.php #, php-format msgid "" @@ -514,11 +504,6 @@ msgstr "" msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - #: html/pkgflag.php #, php-format msgid "" @@ -556,9 +541,8 @@ msgstr "" msgid "Package Merging" msgstr "" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" +#: html/pkgmerge.php template/pkgbase_actions.php +msgid "Merge Package" msgstr "" #: html/pkgmerge.php @@ -595,7 +579,7 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "" #: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" +msgid "Submit Request" msgstr "" #: html/pkgreq.php template/pkgreq_close_form.php @@ -819,6 +803,34 @@ msgstr "" msgid "Comment has been added." msgstr "" +#: lib/pkgbasefuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Missing comment ID." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "No more than 5 comments can be pinned." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to pin this comment." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "You are not allowed to unpin this comment." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been pinned." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been unpinned." +msgstr "" + #: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "" @@ -835,6 +847,10 @@ msgstr "" msgid "You did not select any packages to flag." msgstr "" +#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + #: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "" @@ -921,14 +937,6 @@ msgstr "" msgid "You have been removed from the comment notification list for %s." msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "" - -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "" - #: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "" @@ -1189,11 +1197,6 @@ msgstr "" msgid "No more results to display." msgstr "" -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - #: template/comaintainers_form.php #, php-format msgid "" @@ -1208,6 +1211,11 @@ msgstr "" msgid "Save" msgstr "" +#: template/footer.php +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + #: template/header.php msgid "My Packages" msgstr "" @@ -1275,14 +1283,6 @@ msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "" - #: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" @@ -1354,6 +1354,10 @@ msgstr "" msgid "View all comments" msgstr "" +#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + #: template/pkg_comments.php msgid "Latest Comments" msgstr "" @@ -1382,6 +1386,14 @@ msgstr "" msgid "Delete comment" msgstr "" +#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +#: template/pkg_comments.php +msgid "Unpin comment" +msgstr "" + #: template/pkg_comments.php msgid "All comments" msgstr "" @@ -1438,11 +1450,6 @@ msgstr "" msgid "Sources" msgstr "" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - #: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." @@ -1472,11 +1479,6 @@ msgstr "" msgid "Rejected" msgstr "" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - #: template/pkgreq_form.php #, php-format msgid "" @@ -1674,10 +1676,6 @@ msgstr "" msgid "Actions" msgstr "" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "" - #: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "" From 5931d5ceec133ad1eee33faee96be061e011dacd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 18:25:10 +0100 Subject: [PATCH 0130/1891] Save comment when closing requests Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 1 + upgrading/4.2.0.txt | 7 +++++++ web/lib/pkgreqfuncs.inc.php | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 55612782..f99833a5 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -333,6 +333,7 @@ CREATE TABLE PackageRequests ( MergeBaseName VARCHAR(255) NULL, UsersID INTEGER UNSIGNED NULL DEFAULT NULL, Comments TEXT NOT NULL DEFAULT '', + ClosureComment TEXT NOT NULL DEFAULT '', RequestTS BIGINT UNSIGNED NOT NULL DEFAULT 0, Status TINYINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (ID), diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index 1450d5e1..7482204d 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -21,3 +21,10 @@ ALTER TABLE Users MODIFY Email VARCHAR(254) NOT NULL; ---- ALTER TABLE PackageComments ADD COLUMN PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0; ---- + + +3. Add new column to store the closure comment of package requests: + +---- +ALTER TABLE PackageRequests ADD COLUMN ClosureComment TEXT NOT NULL DEFAULT ''; +---- diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index 3ea46926..c1a49311 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -227,7 +227,8 @@ function pkgreq_close($id, $reason, $comments, $auto_close=false) { return array(false, __("Only TUs and developers can close requests.")); } - $q = "UPDATE PackageRequests SET Status = " . intval($status) . " "; + $q = "UPDATE PackageRequests SET Status = " . intval($status) . ", "; + $q.= "ClosureComment = " . $dbh->quote($comments) . " "; $q.= "WHERE ID = " . intval($id); $dbh->exec($q); From e45609cf6645e650b8bafccd6860dec6aa9bb547 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 18:28:42 +0100 Subject: [PATCH 0131/1891] notify: Do not pass notification texts via pipes Directly retrieve comments from the database instead of additionally passing them via stdin. Fixes FS#46742. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 29 ++++++++++++++++++++++++----- web/lib/acctfuncs.inc.php | 4 +--- web/lib/pkgbasefuncs.inc.php | 5 +++-- web/lib/pkgreqfuncs.inc.php | 4 ++-- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index d3d9cb0c..9a9cc299 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -91,6 +91,25 @@ def get_request_recipients(cur, pkgbase_id, uid): 'Users.ID = %s OR PackageBases.ID = %s', [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] +def get_comment(cur, comment_id): + cur.execute('SELECT Comments FROM PackageComments WHERE ID = %s', + [comment_id]) + return cur.fetchone()[0] + +def get_flagger_comment(cur, pkgbase_id): + cur.execute('SELECT FlaggerComment FROM PackageBases WHERE ID = %s', + [pkgbase_id]) + return cur.fetchone()[0] + +def get_request_comment(cur, reqid): + cur.execute('SELECT Comments FROM PackageRequests WHERE ID = %s', [reqid]) + return cur.fetchone()[0] + +def get_request_closure_comment(cur, reqid): + cur.execute('SELECT ClosureComment FROM PackageRequests WHERE ID = %s', + [reqid]) + return cur.fetchone()[0] + def send_resetkey(cur, uid): cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', [uid]) @@ -119,11 +138,11 @@ def welcome(cur, uid): send_notification([to], subject, body, refs) -def comment(cur, uid, pkgbase_id): +def comment(cur, uid, pkgbase_id, comment_id): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) to = get_recipients(cur, pkgbase_id, uid) - text = sys.stdin.read() + text = get_comment(cur, comment_id) uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -147,7 +166,7 @@ def flag(cur, uid, pkgbase_id): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) to = [get_maintainer_email(cur, pkgbase_id)] - text = sys.stdin.read() + text = get_flagger_comment(cur, pkgbase_id) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -220,7 +239,7 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): pkgbase = pkgbase_from_id(cur, pkgbase_id) to = [aur_request_ml] cc = get_request_recipients(cur, pkgbase_id, uid) - text = sys.stdin.read() + text = get_request_comment(cur, reqid) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -252,7 +271,7 @@ def request_close(cur, uid, reqid, reason): pkgbase_id = pkgbase_from_pkgreq(cur, reqid) to = [aur_request_ml] cc = get_request_recipients(cur, pkgbase_id, uid) - text = sys.stdin.read() + text = get_request_closure_comment(cur, reqid); user_uri = aur_location + '/account/' + user + '/' diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index a166d65c..6fb2b407 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -1277,11 +1277,10 @@ function account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints) { * Invoke the email notification script. * * @param string $params Command line parameters for the script. - * @param string $text Text to pass via stdin. * * @return void */ -function notify($params, $text='') { +function notify($params) { $cmd = config_get('notifications', 'notify-cmd'); foreach ($params as $param) { $cmd .= ' ' . escapeshellarg($param); @@ -1299,7 +1298,6 @@ function notify($params, $text='') { return false; } - fwrite($pipes[0], $text); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 7076c315..7b744d59 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -100,8 +100,9 @@ function pkgbase_add_comment($base_id, $uid, $comment) { $q.= intval($base_id) . ", " . $uid . ", "; $q.= $dbh->quote($comment) . ", UNIX_TIMESTAMP())"; $dbh->exec($q); + $comment_id = $dbh->lastInsertId(); - notify(array('comment', $uid, $base_id), $comment); + notify(array('comment', $uid, $base_id, $comment_id)); return array(true, __('Comment has been added.')); } @@ -401,7 +402,7 @@ function pkgbase_flag($base_ids, $comment) { $dbh->exec($q); foreach ($base_ids as $base_id) { - notify(array('flag', $uid, $base_id), $comment); + notify(array('flag', $uid, $base_id)); } return array(true, __("The selected packages have been flagged out-of-date.")); diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index c1a49311..cf56663b 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -158,7 +158,7 @@ function pkgreq_file($ids, $type, $merge_into, $comments) { if ($type === 'merge') { $params[] = $merge_into; } - notify($params, $comments); + notify($params); $auto_orphan_age = config_get('options', 'auto_orphan_age'); $auto_delete_age = config_get('options', 'auto_delete_age'); @@ -233,7 +233,7 @@ function pkgreq_close($id, $reason, $comments, $auto_close=false) { $dbh->exec($q); /* Send e-mail notifications. */ - notify(array('request-close', $uid, $id, $reason), $comments); + notify(array('request-close', $uid, $id, $reason)); return array(true, __("Request closed successfully.")); } From 8f870cc5f4e4810e3fdb2346275a2d7f7e3e91e0 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 18:36:04 +0100 Subject: [PATCH 0132/1891] notify: Do not break overly long words Fixes FS#46937. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 9a9cc299..b5bf518b 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -36,8 +36,10 @@ def headers_reply(thread_id): return {'In-Reply-To': thread_id, 'References': thread_id} def send_notification(to, subject, body, refs, headers={}): - body = '\n'.join([textwrap.fill(line) for line in body.splitlines()]) - body += '\n\n' + refs + wrapped = '' + for line in body.splitlines(): + wrapped += textwrap.fill(line, break_long_words=False) + '\n' + body = wrapped + '\n' + refs for recipient in to: msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') From 1f179c9fbc5fc4bb7d94e53a52f519110d0b660e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 17:35:29 +0100 Subject: [PATCH 0133/1891] aurjson: Do not search by ID when argument is numeric When performing info or multiinfo queries, one can currently either pass package names or package IDs as parameters. As a consequence, it is impossible to search for packages with a numeric package name because numeric arguments are always treated as IDs. Since package IDs are not public anymore these days, simply remove the possibility to search by ID in revision 5 of the RPC interface. Fixes FS#47324. Suggested-by: Dave Reisner Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 9097035f..51a7c64d 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -346,7 +346,7 @@ class AurJSON { if (!$arg) { continue; } - if (is_numeric($arg)) { + if ($this->version < 5 && is_numeric($arg)) { $id_args[] = intval($arg); } else { $name_args[] = $this->dbh->quote($arg); @@ -405,7 +405,7 @@ class AurJSON { */ private function info($http_data) { $pqdata = $http_data['arg']; - if (is_numeric($pqdata)) { + if ($this->version < 5 && is_numeric($pqdata)) { $where_condition = "Packages.ID = $pqdata"; } else { $where_condition = "Packages.Name = " . $this->dbh->quote($pqdata); From edfeea8d7462876bf64e948d8c2c4f287d63b269 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Sat, 12 Dec 2015 20:12:03 -0500 Subject: [PATCH 0134/1891] Add instructions to install needed python modules Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- INSTALL | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/INSTALL b/INSTALL index d9569112..d5664d27 100644 --- a/INSTALL +++ b/INSTALL @@ -51,12 +51,16 @@ Setup on Arch Linux # ln -s ../../git-interface/git-update.py hooks/update # chown -R aur . -7) Install the git-auth wrapper script: +7) Install needed Python modules: + + # pacman -S python-mysql-connector python-pygit2 + +8) Install the git-auth wrapper script: # cd /srv/http/aurweb/git-interface/ # make && make install -8) Configure sshd(8) for the AUR. Add the following lines at the end of your +9) Configure sshd(8) for the AUR. Add the following lines at the end of your sshd_config(5) and restart the sshd. Note that OpenSSH 6.9 or newer is needed! @@ -65,8 +69,8 @@ Setup on Arch Linux AuthorizedKeysCommand /usr/local/bin/aur-git-auth "%t" "%k" AuthorizedKeysCommandUser aur -9) If you want to enable smart HTTP support with nginx and fcgiwrap, you can - use the following directives: +10) If you want to enable smart HTTP support with nginx and fcgiwrap, you can + use the following directives: location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { fastcgi_pass unix:/run/fcgiwrap.sock; From ff798420b5edd003758adb45864070b6339eba3c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 11:59:27 +0100 Subject: [PATCH 0135/1891] Add the Open Iconic license The new SVG icons used in aurweb are taken from the Open Iconic project. Add their license to our source tree. Signed-off-by: Lukas Fleischer --- web/html/images/ICON-LICENSE | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 web/html/images/ICON-LICENSE diff --git a/web/html/images/ICON-LICENSE b/web/html/images/ICON-LICENSE new file mode 100644 index 00000000..6b39f6fd --- /dev/null +++ b/web/html/images/ICON-LICENSE @@ -0,0 +1,26 @@ +The icons used in aurweb originate from the Open Iconic project and are +licensed under the following terms: + +---- +The MIT License (MIT) + +Copyright (c) 2014 Waybury + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +---- From 256a343b187b8a9435e208562f3bb5d55a082b05 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 12:03:13 +0100 Subject: [PATCH 0136/1891] Remove old logos Remove some very old and outdated logos. Update the RSS feed to use the new logo. Signed-off-by: Lukas Fleischer --- web/html/images/AUR-logo-80.png | Bin 2229 -> 0 bytes web/html/images/AUR-logo.png | Bin 5477 -> 0 bytes web/html/index.php | 2 -- web/html/rss.php | 2 +- 4 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 web/html/images/AUR-logo-80.png delete mode 100644 web/html/images/AUR-logo.png diff --git a/web/html/images/AUR-logo-80.png b/web/html/images/AUR-logo-80.png deleted file mode 100644 index 9554f7e741f774f638a66df180a045a6e27e871a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2229 zcmZ{m`#%$k8^>p}u}NlZ$SqWg5uw92mBg-wR zRfbrtbI|G}hOb;Et&mG<$N2-!>v=xU=kKdI?WNl~ zB@fxYsxh;1+Xe|B;T-|ef9Gyb-OX(Ry+rVi1ppLO{*?@%tU`So%3UU&z{!n3-~fQh z#822T03dHqbUf~n@b~A+D-l|w$jqm0+J?`d=9A}Y($iE4^5(nC5J>rS&s_ccsI+7B zGP;HffcEN4%OY}(%4_Vx*uVS1=rCC6a07j%mDJ^SAG zbGibV(K~)6WQqSeL136aMX=y-)_#2&ixnJQL#t<;`;VPGe(%{GtjwG&hJKJ9$vyp3 zXcnFCtl4tVOwL->`i!)SRlN)QJnjxKd?jJ$8E7N8{%sIzxE`ayPwk}8Uob4_(+m)U zWsVKM4qHTti2nQMQJ?3V79nKg(wr~%CEnUxpnq7G$5k_~NgZecQZOQwBHoz~ZdifL zycCbAnGp-2+#v3LnTRf3rql4WPZrt0n2Ufj~I1yT?oqU z^AA2ShpR;YqfJFByPg$J^Dl!1=t#7Yp2C*clFw5-wg%muadWl1pf{5{|H)ACATN9Hrvvi#++?V&yf;jwt|^Kr zBFlcU4x~K@b|mVKTn1s3wO`|J-L zITw<0-|2~CQ?P|MJ9Tl<}w*!>YZbzr-R8!IYAz|^- zO!SY3;>Hl87JQmOyHGa5FZ|FDQ+0?w>a8Lqyxx-I!uAY4L97eRqE`*RR+V*r0)znT z8s?}r{2eZ4O93lcDGO6&JNTzaD^)r3-bcrq1I;1y6G>YN3BXQm=#57%l_CF|@N5cf zR?$nlT;3gNXj;5XB#yZYJ!yCz-ek16|@`B+B;B`>zw_kP$^Qw&AhbVnb z_3wEXy1v=@ke$sO5>nG&&_Yk7qGS@>&3z(Dac@r<0_c}9! zVdte27&*p@-jI_Nl4J|6peYv|7#c-PV}!nTVo$W#cF7OS?mM^|h)&n&OPdMH{>u9v zZ`-lsvGSxvyNpm4Mdo~pof(X2Gx#77n*+A&`j&fYU9MGSc7J_^Sx^}=2NwXVRK zDTQK-BR(UK;J#1_+rGr_afy0mRfeCLBPh!)c@X(v$N=2uz7Z*2G)RQ9ABu5A!tM6`7P|jMsZMkqBM;cpD{b z*cEmuNajYrZ}6;TWxUARKf5Y6!v53K9BF)gE`ub7Hr90N zxfIo}o2!@u>dkiEV`(osE(2S-3gk^?qVnI^7#AhgT-1L_s~j-m=@BA_6MF@HzGqF5 zh0(S&RBNyp!GEG;Z5SEd#=EMyl&8lw-2&#_OHgLH{yDj!uU&)J$$T`nSE1U0OVZGo z@-CRpD`_Jn!@7RS1<0o z^t67{$xxpqAU>`nd30X4S?sQTK(&Gtr3QQ?G_hBemmYwK2wP~UJZsnr@uAr2HS8Nn z>1-Q(uqMEh7pLszhlWBB2=X&mk8*n9E2 z&hhj$Oe-!@(akR|aHNAnHTrAV$2)b)tv5d{Hz*SS)}wB>RsVwbyxpFMDy4!^<{5@Z z$l{BOQhU?>bs|AF`P%)Ks7y*t;X|3Xc~i}CdV3ED5qIH>ggJ!ZCAW|fDDjDC_RgUd zGjn~0YNmeMj$K^rOSWpCSNOBP6qn`2B;owLs(t+WPOhZ;WXonv3=Eo0keTaOafda% zr_uTfOLDETar2b3KDysH(SlI?HHs-Re2tQa9&7e6Z*uw$j;OCxDb6O8h%?Wxl*XN) yE~Pe%!oI4O<2I;P-csfOErFaSiHizD0KKlLAhl@2!m diff --git a/web/html/images/AUR-logo.png b/web/html/images/AUR-logo.png deleted file mode 100644 index e1ddd98dbdbad3b514a905fb5447c1dd6780121c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5477 zcmcgwi9eKU*q+5027?G;jHFaZi+vkICCM(yI;fOw#<5MtGB~Alj8unCiV;QGD|=?% z7L>@?r(>CkWH2!pOQYeN&i6Nb-}C#u>+gA=`@XODy080ro|~@D_A&@n1PBC@aX59{ z9Rva=itay1h>OnOhYtFPE@CmZ4xSRCmLzfEhUi&7_Jnt=2mVrQLeL)ftbWP-q@kln#=Z`fs_NOt zPIkdwhO~y^YT}g_suoMbCl#iqjlza5S7vuO>YB?(zG*#MLcBSt?=^Ts6M=ZRwbZ>N zP52!2*=%K@jn$S~RDY>h?|vwBW$XJtR-5B$$N%5k=_|Jv!S@DnIK#u@-Ze{8_d9y4 zK-OZ`mwz=0QVqoNn$a(Al%B@YpSpm3!K2_&Ij-p zW%*g>IV?t=dH1YcayYKMZ0R+4OlA!EONXc9G9{OLqg0WfLH>~@OcSc+IJHsA6LiVV z-W(Rvav{M~t3Q1=(30J`pAEw`kI2iXGIC%P5E8l;`78Cj6=IOAR%Zgv4Y+tUS>iBE z#jC<=Va2Kttnyd#zZ0mklS~p_h`Var$}rv|>9H=AU^LGLUqZ>)k9lng5eG9ko4dCG~XyilC>&XPuAAe7;V!cg< z)aNXq?~*8=8ue;q;cFeXLQOptI0@w$E*>O>ddk?zZ4DYgRd+^fDsczWdZeDm=oaP}K8pa9$ihEg*7Q_lyWd!H9u!+g6Qyy{S!`0QQl0$l@Jk9U?W_4VP~ z9~3WavQ};ZId$~j$Nme{lb;m%(JD~CYi+kH0Q;28fmTsS9f!8Q<5=DERLGs_)n10t z&J`HWj=pE^r9ZhdN%rwaPqsRBvU~!-liG^8py~ z4GpDbp?|&H6A=!uwa2>5bs%raVKYK<>@!JJ3jVw3_&4fq2Qm4$j}}4jwboCp0B1Y(ctp8QRHx5Lf_uHZ!e3I;6Z&!TR)M| zg}1Dp+&7hv@Jb$x&5avMEg5M8NwT)DZwa%X40y87ZH!igIh3Rjf)N5#lB}j{Xo%yo zpNBn~qWCnbK|Cs?$KtYo3)q`mmy#2VNbKoNz)KMH55JA}hb6c8!G)*TO1}*3WELEm z&Io~F1o+`MlH8;d*TW<~c(Z?lFUDgPb~5(BlFglA9cGnf6l?!OEN^EqO0;*4j`F64 z4L(>>PzQ8~yl?6QW@+%<0q@Q2Q?&`S5}&rKvc6xHD!tPK#*@M?LDbBiKcNI=Xk`XFM?0;gSVF(zv!{e zSQ*|0qM^b$zKseE7bE%x`!e@*P^=Y|e`?t121_Q!@skza9)v~fJYmPp?u3j|nsknc z2~Rfp8>?hoL57u=xSTtP*TZyDq@@F-u{BY&#rVe?Lna6T;qu&5VIDaDr^fLLMgEVv zdjL|^`_|`}V<$>equ#TW*vU%oQurs}!U{mjDQ70_Ct!9*(BKC(p=ZiR(1=x|Gk?np}w(8TP!#Xu%8ws9;>EMBBr zK;YE2^Mt8g4FEKmQJ}9~7^H2`ge@n|fUIGwJFM>qif#nij;eq(nd9t1DxD zA*#}mE=ByZ;*D@yqq3woWVz^aMUpdr(vMxiY|gJvLKb{Jn4TVB+n{d2TGauj3On7K zUciOVXmGMqS}bm50a^$7KxWCr+9bR3m0#=-kK_C21-Ci{kb6Md#awLQJuGwi9ZD_d zBlGLNc}R&DDRv8Ws3VF>lqxuyxYPGz42I`^D{iqfFNPA?iGB<_F@dTO@wQl8n894A zT1k?9Zv<;=+g}DD1^Gf_#YurKcNe9%zOT+6Q^U}}W0^heENt&)NG0I>0z=EG-wZD= zF`qnF{${@GDEkccq{G_ND~+BRDfGFgnxL}wz%%QCN*G&pY>mj? z?zTEhsQR_>V|Oc6)>^I%onq@Uzfh!V_j(>XVEye}qZvWG;jj74%3TdBD9Q!`yNJqq-xzW(RFepr#+EzBJtfE-UJd5Mg!ARJ|x+MkoUWKm)JqOAG+j~$j zQ{LRC*?ZJShVtvKoI1dn3EDg*6Wbi)*(H}=rFy-}E>)v^l3u~7_{tpY|B4J(`Vv=B zqCAop)OjI=P0}pBd65#Y6`wy^O@kk`$*9|lt5$3tJcC73Jk13Ir`U%^wr&)cV35Rn z%b7_!`Dz7wo1c0kX7+Gqa0#uaO}fj`!B`=)E zrJ>dB!|jgS&r0%DUjG#twcl!g2qOoyg))7=Zlgst2pNzg*{8~f`6QlgprR3DS>qDB zp=H#3ttO;E4K9)32D%2GCEt!rwPN*&K)ALSIqdsn>blH9|1&J&3v^tyZQ94vh=p=A+!{7lfp>-T3ktEy304tBd2C`*>r3Z4^no8v$g z{$SuUHX}(MC5N5uy5Cfc5TtC80uKpNQon^ic{b~3_LFR^!QMg6S3K*PpF3A!#K99W9nNZt#W;z~L~b{yWxlu?!OG$ zNzRl`0L9@{jrEP_PQ4bcbDRMx#X7neCUnK2UFy-`r=UQ7sh(x4>U|KpQp^N9v30~JJ46uB5v{bRpytMpDYKh6*d|&TOKL$ z-NoYgX%1E#JmB?SFTt%toA^#5sU7{Q0WnTH^?%gyDv0Rk%GDqNT z0ipU5`Wzke=P%Vw#aks0iY z>+wogeUMYL7l=g8KPy?^v*s}noDy>2$?f!s6DG0^c&867qncIw5g{1kct4jI{!OU^ z9Di=<&)vMN40Gtx^LIXT93k`lI!If8H%#abH!9ro3*^q|bU`I=a^i;5MdP$9iQ&!5 zkGR%}wZ-oFH2;pgiptM6<2-@whPBc6>gJAEr8YumoS zmABIP&I=hns};TIDr+<(Lb{ZiIoT?ZXEs;w9{o2+KaRhE`auFA%S&X>T*lJhW3&C$ z2UTu(ndDfo^t|jzgFpWc!bH88WD$!7&nx*uo65qhA z{0M6O)2L6JUR38(%0#Ycmeh`XxQ<07Pr6GBih)4$@&UAtS#{ar_|Sdvo|h1YA}<-~ zDYO#vR7awtehws_;CHNnl42)oG;;9Myc#H!sGe@l{m-s>Vr}xGL4s$+&bwq0J+k#V z{&cs7Id~J@;raP)50g2LubdB~b&N5OW8>9_=RfXeUmA;?8`f*Mb)i$Q2EO{>^Rl21 zxJm2$dfyr=wy*paga{^%2DM4?VxW#?Ux7FvzHqK{xUWW*J5wCh_~Lbn1i@&l<`@h= znM4P*9_tLMimQzhd_soD|Et)fY}#%2!}-MZr7TEMt4Sy6d25zl&Ehqb_OZcrZ%f9Y z6V6>WksJhMGy6}Ti+}gIa{OIT&w}FB+}9rLnDy@)dNnRXg zwpTV-{B_6(4*l|$B{fNmXUEm#$$1GCck!hVNedIw;6uD4=ZdCRbI%9R73aT=#Q0-0 zf6GiT10$C7?b%v1a2MDOvs`xrEZMOUUHiq3h+6?zAje;+ds(mml>B*hrv5jaDtt$> zh1D?Yv0EyVU!k``csE$#^JT)f)GQ)9e%O^eAJscEN_pP9a1 zUhnpw#%Qp8SWwU!Bn4`DZJhf;r%ITd4W}W$c{7EI%sT23q-T(_LzT~Yq@~y3N+ajB zUJdKP^lAfMH+Om!DgsuAXG)NcLN+WKhy?F*yIGYmT9;>CTfLYD8ij@$YotOnIv~Hc zRktzXDx*Yh)@bB)I}^3-K+{x7qKFrvkaL62|CZfc(LNs#h-RWq$Mv&!N`C( zzP^MJ2LrTR$=40?sRPHCoYl*sow@`qQ}ip@IaTZ8HDlPq`vM$eCac{dw|m=LS1&PZ zXFGd?!E~vwDG;PnH(u|FVi*JJ=Rm}w3m#`|rQr5{75gSC#}=7bYc%7ot~}288yR+L@wcAvsdSj{$f0&ZbnX~PFV@xm zZLygE_)~+A0x$xN`DZTvQaG3ThV$kzt$tMw9PL-dz;-<7<==#AY7D8thKXE;zsN` z7W&3lw0=FIODGi%TE3#5!O|h7JBU4^YC0*<`bZ$9-&cv_-_-SBWc)CQF?~>D@WiKn z85tCDQ?tEaJsH=f#K&1^Y2=Li7(l0fX+1luOBb7~p5Nz;il6LK;p22R9+K%X4*mz1 zWqQt;@b!N!oHb~77cu08xD~T6)m{OQi^b`lUC?d19wYMmJe6mM{ig7s#KrHQ42{Z{ zMU+RUciue#0CeT`HuR+eCKc;{%KrMOE-neX@E&jb5i^J~nTI;4@Xezu+PI?x`FIBLvIcZZ-4vOy zS#QwcoMevPkYXF#$BjJqs)`k{RUz%4CZXq^AId9gjtAOR`Hu>rG-$+i*tS$kCe#~1 zr}eaNHvr~RbuN+^Fa^9198#N6?b4A~MmviWrih@&K-b>W?os+i0Xs@~hoL=Pu1UcZ zYO2yy3HbC${3P(=eg1Ts_LERYBq`s&-YUiRj|dco*ZxQx6-KY1*lz6Hr|7_l7@1HJ z$_nQLin4^H9-dX9vA}4U_zTrQ1pbyq4TqH>xiYEF10fm@s%Kw%rqev&#{SW2hr#8b zP4Fhfx4wB8O>SnkCtL8`3JMdz72<*t;8SGc0`7N0lIf!TjA@`5n6Z+*qPYOwqIp$~ z$=;s6wg9SwSfs3gxvM71#D)*);~YG+UQR6`v>XF^JyMN*qE}DF8>2s{$Ig6Q2 zs0iu5VAt1|)phG~Ch?FO9Qq?V!gAuufN3any?-aSrg8SFW3g9NH*8I$>gVc0_BO6s zmePpQrfnjVZn$g{4uandyvsImDDsgMAR~4~$24w9&kaiz8#oO|X)A4nq(x^JkzOtl z3k=srC2jLY;6X)iFX4Q>YNis7k0+v=G{QB%i-Iyr*Znj<17*#3#u&6u@MiisOcBL& zp(^2SDWHe-|Ms?ZJ{WI7W+!M*Q)p)$RdeJF%1aGxS2Wm#dNp`*mG=WMmlKCu`xu2J zz<3ot_5IcQW&sz5qJ&Ew?t@1;)xIN?mxbje`Te5Jq3_K6d3cCPVfMT*LE0P6Q_MC& zu_r{|Ec^W-ixLJ$%q`x<)tuFRQvRH6ekQ ztZ!9q5S56fURC_f(n`IWA}RH^&&LG=+4{SW|Lcr3`1oO2upg&bduVOkaVE!(^WbrK uir(|Hx<7pMhb$>?5OMPV_br$C3!{4yX5ycLjTh~cf*ejbAFsB>rT-5z;Z*_v diff --git a/web/html/index.php b/web/html/index.php index e99d22f8..b9ab1ff9 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -171,8 +171,6 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { break; case "/css/archnavbar/archlogo.png": case "/css/archnavbar/aurlogo.png": - case "/images/AUR-logo-80.png": - case "/images/AUR-logo.png": case "/images/favicon.ico": case "/images/feed-icon-14x14.png": case "/images/titlelogo.png": diff --git a/web/html/rss.php b/web/html/rss.php index 2470d994..8585d81d 100644 --- a/web/html/rss.php +++ b/web/html/rss.php @@ -32,7 +32,7 @@ $rss->link = "${protocol}://{$host}"; $rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); $image = new FeedImage(); $image->title = "AUR"; -$image->url = "{$protocol}://{$host}/images/AUR-logo-80.png"; +$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; $image->link = $rss->link; $image->description = "AUR Newest Packages Feed"; $rss->image = $image; From a35dc4022aea91a7be945222d7430a93276a6ee4 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 12:22:06 +0100 Subject: [PATCH 0137/1891] Replace RSS feed icon Use a flat icon from the Open Iconic collection for the RSS feed. Signed-off-by: Lukas Fleischer --- web/html/images/feed-icon-14x14.png | Bin 689 -> 0 bytes web/html/images/rss.svg | 3 +++ web/html/index.php | 2 +- web/template/stats/updates_table.php | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 web/html/images/feed-icon-14x14.png create mode 100644 web/html/images/rss.svg diff --git a/web/html/images/feed-icon-14x14.png b/web/html/images/feed-icon-14x14.png deleted file mode 100644 index b3c949d2244f2c0c81d65e74719af2a1b56d06a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 689 zcmV;i0#5yjP)(tky!*UETcH-TCU7SrqEjJM#?B`_A)!p7(kFf9-P@=@15kkTkGK zgFusyy#KECqZzRdBLb=P?$(kUP;>kYTDeG&{|a+iOiRbI6nbQ)j#7bOf>iF=C+|_py<&Fo1F5cC*iEM?zZGC{ejNg4LWYp=S$L6Qaby6y zp$+F`250{%tU{Lg$5*ROH}y!1UKJS4*xqd7P(Y3JQF?lrnf?yerr%&6yGXLG1ur*B z{$&R1@Oj)yl@%rY5rh?j(j10Yz_DBs`AKFU_QnB;)(aqQmGi&ieOS|21^NP9UMpa< zU&p!f6RZ6Owp^X!EXA=0SbN&h?CrQK%Q3(=YBqqHD^9ZUM0Hxt-6-KT;>lf@j?Z+v zHm(}`>85I&E<7e}oz?6UwjAogowzGO8kSN7+2`b^$Az9L{K5*ko87EV45LT-`_##3 z>d3AGh@>=mbg34|6}+-gT9N+6Dr@44VEl44O&{&|w=qpbzC#iWMKa?5)>tI+KLQK@ Xq0QFqn(9Yl00000NkvXXu0mjfZ8t + + diff --git a/web/html/index.php b/web/html/index.php index b9ab1ff9..817c20b3 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -172,7 +172,6 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { case "/css/archnavbar/archlogo.png": case "/css/archnavbar/aurlogo.png": case "/images/favicon.ico": - case "/images/feed-icon-14x14.png": case "/images/titlelogo.png": case "/images/x.png": header("Content-Type: image/png"); @@ -182,6 +181,7 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { case "/images/pencil.min.svg": case "/images/pin.min.svg": case "/images/unpin.min.svg": + case "/images/rss.svg": header("Content-Type: image/svg+xml"); readfile("./$path"); break; diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index 775d7073..b783bd85 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -1,6 +1,6 @@

    -RSS Feed +RSS Feed
    - +
    From 41b6cff7c0e8459ef3783b9c3447ff43c0672a13 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Tue, 21 Jul 2015 22:53:54 +0200 Subject: [PATCH 0032/1891] pkg_comments.php: Merge two DIVs with same ID Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/pkg_comments.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 26fddfd5..bb006b9f 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -63,12 +63,10 @@ $count = pkgbase_comments_count($base_id, $include_deleted);

    - 10 && !isset($_GET['comments'])): ?> -

    -
    + From c7025054c686f1f1a877e2d2938c39c79fb62580 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Tue, 21 Jul 2015 22:53:55 +0200 Subject: [PATCH 0033/1891] Split pkg_comment_form.php so the outer box is not always included For use in the new RPC interface to edit comments, the form shouldn't always print a header. Create a new template pkg_comment_box.php that prints form and box, change template pkg_comment_form.php to only print the form. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/commentedit.php | 2 +- web/lib/pkgbasefuncs.inc.php | 2 +- web/lib/pkgfuncs.inc.php | 2 +- web/template/pkg_comment_box.php | 4 ++++ web/template/pkg_comment_form.php | 4 ---- 5 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 web/template/pkg_comment_box.php diff --git a/web/html/commentedit.php b/web/html/commentedit.php index 83d86dd5..2a0628e3 100644 --- a/web/html/commentedit.php +++ b/web/html/commentedit.php @@ -17,5 +17,5 @@ if (!isset($base_id) || !has_credential(CRED_COMMENT_EDIT, array($user_id)) || i } html_header(__("Edit comment")); -include('pkg_comment_form.php'); +include('pkg_comment_box.php'); html_footer(AURWEB_VERSION); diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 2d1969be..ccab635a 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -187,7 +187,7 @@ function pkgbase_display_details($base_id, $row, $SID="") { include('pkgbase_details.php'); if ($SID) { - include('pkg_comment_form.php'); + include('pkg_comment_box.php'); } $limit = isset($_GET['comments']) ? 0 : 10; diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index bcadf54a..f4034718 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -481,7 +481,7 @@ function pkg_display_details($id=0, $row, $SID="") { include('pkg_details.php'); if ($SID) { - include('pkg_comment_form.php'); + include('pkg_comment_box.php'); } $limit = isset($_GET['comments']) ? 0 : 10; diff --git a/web/template/pkg_comment_box.php b/web/template/pkg_comment_box.php new file mode 100644 index 00000000..22f90d4a --- /dev/null +++ b/web/template/pkg_comment_box.php @@ -0,0 +1,4 @@ +
    +

    + +
    diff --git a/web/template/pkg_comment_form.php b/web/template/pkg_comment_form.php index 16a92b1b..7c16eb73 100644 --- a/web/template/pkg_comment_form.php +++ b/web/template/pkg_comment_form.php @@ -1,5 +1,3 @@ -
    -

    -
    - From 8328223a5e4670fbeb62c13ef89aa345f3ccc4c8 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Tue, 21 Jul 2015 22:53:56 +0200 Subject: [PATCH 0034/1891] aurjson.class.php: Add method get_comment_form() This method will be used by the JavaScript comment editing and produces a form containing the comment. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 49 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 8ead253a..4e4d5dc8 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -14,7 +14,7 @@ class AurJSON { private $version = 1; private static $exposed_methods = array( 'search', 'info', 'multiinfo', 'msearch', 'suggest', - 'suggest-pkgbase' + 'suggest-pkgbase', 'get-comment-form' ); private static $exposed_fields = array( 'name', 'name-desc' @@ -477,5 +477,52 @@ class AurJSON { return json_encode($result_array); } + + /** + * Get the HTML markup of the comment form. + * + * @param array $http_data Query parameters. + * + * @return string The JSON formatted response data. + */ + private function get_comment_form($http_data) { + if (!isset($http_data['base_id']) || !isset($http_data['pkgbase_name'])) { + $output = array( + 'success' => 0, + 'error' => __('Package base ID or package base name missing.') + ); + return json_encode($output); + } + + $comment_id = intval($http_data['arg']); + $base_id = intval($http_data['base_id']); + $pkgbase_name = $http_data['pkgbase_name']; + + list($user_id, $comment) = comment_by_id($comment_id); + + if (!has_credential(CRED_COMMENT_EDIT, array($user_id))) { + $output = array( + 'success' => 0, + 'error' => __('You do not have the right to edit this comment.') + ); + return json_encode($output); + } elseif (is_null($comment)) { + $output = array( + 'success' => 0, + 'error' => __('Comment does not exist.') + ); + return json_encode($output); + } + + ob_start(); + include('pkg_comment_form.php'); + $html = ob_get_clean(); + $output = array( + 'success' => 1, + 'form' => $html + ); + + return json_encode($output); + } } From 54d812ec791de4b36d45cdcb853d01dc72d78669 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Tue, 21 Jul 2015 22:53:57 +0200 Subject: [PATCH 0035/1891] pkg_comments.php: Add JavaScript function to edit comments Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 6 ++++++ web/html/images/ajax-loader.gif | Bin 0 -> 723 bytes web/html/index.php | 4 ++++ web/template/pkg_comments.php | 35 ++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 web/html/images/ajax-loader.gif diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index b33726c4..4fb256f9 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -124,6 +124,12 @@ opacity: 1; } +.ajax-loader { + float: right; + position: relative; + top: 4px; +} + legend { padding: 1em 0; } diff --git a/web/html/images/ajax-loader.gif b/web/html/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..df07e7ec2076177c99b53d4d29a45f0db6b06a9a GIT binary patch literal 723 zcmZ?wbhEHb6kyWo5uik&V|NP^(AHU+;_dI&}>C3lYM=m|vboAbp zdv88|`N04KivPL&TtkAL9RpmA^bD98f#Qn)q@0UV6H8K46v{J8G87WC5-W1@6I1ju z^V0Ge6o0aCasyTAfJ^{6l7UrML7^`tbKa5#T#rsMt#c4)wm4&2aJl;4?H%*^*q;ct zZ+YZ!f=91--8C-PwbPuinV^!8D8ZUAZ$+j|`^0?*ZXH_r=F;-s=Wq7D-W{Q@F^9F$ zTCh`s37bYUpw-=pI*&V4IF+P$l9wbc(l{x7eoOCbBdG(^nGZDWjsAGTTd?u$#mhT{ z{bn8t<<=6J=66T{n^C4fqn2>E3WhNCJ~l~G@x1uTreFAcY2|b4S-i`cPqf%2ZE*i3 z+J9zZu_cRC + From 080b6f3d123c465f70a8f9f1e724111dd1b3cf56 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 22 Jul 2015 07:19:01 +0200 Subject: [PATCH 0036/1891] aurjson.class.php: Add missing PHPDoc Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 4e4d5dc8..7d94daba 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -139,6 +139,7 @@ class AurJSON { * Returns a JSON formatted result data. * * @param $type The response method type. + * @param $count The number of results to return * @param $data The result data to return * @param $error An error message to include in the response * @@ -159,6 +160,13 @@ class AurJSON { return json_encode($json_array); } + /* + * Get extended package details (for info and multiinfo queries). + * + * @param $pkgid The ID of the package to retrieve details for. + * + * @return array An array containing package details. + */ private function get_extended_fields($pkgid) { $query = "SELECT DependencyTypes.Name AS Type, " . "PackageDepends.DepName AS Name, " . @@ -208,6 +216,15 @@ class AurJSON { return $data; } + /* + * Retrieve package information (used in info, multiinfo, search and + * msearch requests). + * + * @param $type The request type. + * @param $where_condition An SQL WHERE-condition to filter packages. + * + * @return mixed Returns an array of package matches. + */ private function process_query($type, $where_condition) { $max_results = config_get_int('options', 'max_rpc_results'); From ab2577525970e415f9ad2439ae1bb2c51f479c8a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 22 Jul 2015 13:49:51 +0200 Subject: [PATCH 0037/1891] Move documentation to a subdirectory Create a new subdirectory doc/ that contains documentation. Signed-off-by: Lukas Fleischer --- AUTHORS | 4 ++-- README | 5 ++++- HACKING => doc/CodingGuidelines | 10 ++++++---- TRANSLATING => doc/i18n.txt | 0 4 files changed, 12 insertions(+), 7 deletions(-) rename HACKING => doc/CodingGuidelines (96%) rename TRANSLATING => doc/i18n.txt (100%) diff --git a/AUTHORS b/AUTHORS index a21fef7b..4462cab8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -23,8 +23,8 @@ Use `git shortlog -s` for a list of aurweb contributors. Translations ------------ -Our translations are currently maintained in Transifex; please read TRANSLATING -for more details. +Our translations are currently maintained in Transifex; please read +doc/i18n.txt for more details. Below is a list of past translators before we switched to Transifex; more can be found by looking in the Git history. diff --git a/README b/README index 228358aa..71e84818 100644 --- a/README +++ b/README @@ -24,6 +24,9 @@ Functionality Directory Layout ---------------- +doc:: + aurweb documentation. + po:: Translation files for strings in the aurweb interface. @@ -40,7 +43,7 @@ Links ----- * The repository is hosted at git://projects.archlinux.org/aurweb.git -- see - HACKING for information on submitting patches. + doc/CodingGuidelines for information on submitting patches. * Discovered bugs can be submitted to the aurweb bug tracker: https://bugs.archlinux.org/index.php?project=2 diff --git a/HACKING b/doc/CodingGuidelines similarity index 96% rename from HACKING rename to doc/CodingGuidelines index 291da1f3..46537bb2 100644 --- a/HACKING +++ b/doc/CodingGuidelines @@ -1,11 +1,13 @@ -HACKING +Coding Guidelines +================= DISCLAIMER: We realise the code doesn't necessarily follow all the rules. This is an attempt to establish a standard coding style for future development. -Coding style guidelines ------------------------ +Coding style +------------ + Column width: 79 columns or less within reason. Indentation: tabs (standard eight column width) @@ -28,6 +30,7 @@ MySQL queries should generally go into functions. Submitting patches ------------------ + !!! PLEASE TEST YOUR PATCHES BEFORE SUBMITTING !!! Submit uncompressed git-formatted patches to aur-dev@archlinux.org. @@ -49,4 +52,3 @@ Glossary git-formatted patch: A patch that is produced via `git format-patch` and is sent via `git send-email` or as an inline attachment of an email. - diff --git a/TRANSLATING b/doc/i18n.txt similarity index 100% rename from TRANSLATING rename to doc/i18n.txt From e8a6fe1efc3f4e546dd777babbb0264b6d073088 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 22 Jul 2015 15:52:58 +0200 Subject: [PATCH 0038/1891] Document the Git/SSH interface Add a document describing how the Git/SSH interface works internally. Signed-off-by: Lukas Fleischer --- doc/git-interface.txt | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 doc/git-interface.txt diff --git a/doc/git-interface.txt b/doc/git-interface.txt new file mode 100644 index 00000000..b34e112e --- /dev/null +++ b/doc/git-interface.txt @@ -0,0 +1,81 @@ +The aurweb Git and SSH interface +================================ + +Git storage +----------- + +Since release 4.0.0, aurweb uses Git repositories to store packages. Git +namespaces (see gitnamespaces(7)) are used to share the object database, such +that delta compression can be applied across package base boundaries. + +Internally, all packages are stored in a single Git repository. Special refs, +so-called namespaced branches, are used to refer to the commits corresponding +to the actual package bases. For convenience, we also create a branch for each +package repository that carries the name of the corresponding package base, +such that one can easily access the history of a given package base by running +`git log `. To the end-user, the individual namespaced branches are +presented as separate Git repositories. + +Authentication: git-auth +------------------------ + +Pushing to package repositories is possible via SSH. In order to access the SSH +interface, users first need to add an SSH public key to their account using the +web interface. Authentication is performed by the git-auth +AuthorizedKeysCommand script (see sshd_config(5) for details) that looks up the +public key in the AUR user table. Using this concept of "virtual users", there +is no need to create separate UNIX accounts for each registered AUR user. + +If the public key is found, the corresponding authorized_keys line is printed +to stdout. If the public key does not exist, the login is denied. The +authorized_keys line also contains a forced command such that authenticated +users cannot access anything on the server except for the aurweb SSH interface. +The forced command can be configured in the aurweb configuration file and +usually points to the git-serve program. + +The INSTALL file in the top-level directory contains detailed instructions on +how to configure sshd(8) to use git-auth for authentication. + +The Shell: git-serve +-------------------- + +The git-serve command, the "aurweb shell", provides different subcommands: + +* The help command shows a list of available commands. +* The list-repos command lists all repositories of the authenticated user. +* The setup-repo command can be used to create a new repository. +* The git-{receive,upload}-pack commands are redirected to git-shell(1). + +The requested command is extracted from the SSH_ORIGINAL_COMMAND environment +variable which is usually set by the SSH daemon. If no command is specified, +git-serve displays a message that aurweb does not provide an interactive shell. + +When invoking git-shell(1), the git-serve command also redirects all paths to +the shared Git repository and sets up the GIT_NAMESPACE environment variable +such that Git updates the right namespaced branch. + +The Update Hook: git-update +--------------------------- + +The Git update hook, called git-update, performs several subtasks: + +* Prevent from creating branches or tags other than master. +* Deny non-fast-forwards, except for Trusted Users and Developers. +* Check each new commit (validate meta data, impose file size limits, ...) +* Update package base information and package information in the database. +* Update the named branch and the namespaced HEAD ref of the package. + +It needs to be added to the shared Git repository, see INSTALL in the top-level +directory for further information. + +Accessing Git repositories via HTTP +----------------------------------- + +Git repositories can also be accessed via HTTP by configuring the web server to +forward specific requests to git-http-backend(1). Note that, since Git +namespaces are used internally, the web server also needs to rewrite URIs and +setup the GIT_NAMESPACE environment variable accordingly before forwarding a +request. + +An example configuration for nginx and fcgiwrap can be found in the INSTALL +instructions in the top-level directory. From da1153857f63babd0080c0d8ebd75d5f8400e6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sun, 9 Aug 2015 16:05:39 +0200 Subject: [PATCH 0039/1891] rpc: msearch: Give orphans on empty maintainer argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 7d94daba..e102fed4 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -437,9 +437,13 @@ class AurJSON { */ private function msearch($http_data) { $maintainer = $http_data['arg']; - $maintainer = $this->dbh->quote($maintainer); - $where_condition = "Users.Username = $maintainer "; + if (empty($maintainer)) { + $where_condition = "Users.ID is NULL"; + } else { + $maintainer = $this->dbh->quote($maintainer); + $where_condition = "Users.Username = $maintainer "; + } return $this->process_query('msearch', $where_condition); } From 4bc6c55d988e508613afafbb7f8173cf1ed3270f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 14 Aug 2015 12:45:01 +0200 Subject: [PATCH 0040/1891] git-update: Move blacklist reading further down Since c4870a9 (git-update: Only check HEAD for blacklisted packages, 2015-06-04), only the HEAD commit package name is looked up in the blacklist. This means that we no longer need to read the blacklist before running the commit walker. Moving the blacklist reading code further down makes the code easier to read. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 935fa5bb..de6ceb49 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -212,9 +212,6 @@ walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) if sha1_old != "0000000000000000000000000000000000000000": walker.hide(sha1_old) -cur.execute("SELECT Name FROM PackageBlacklist") -blacklist = [row[0] for row in cur.fetchall()] - for commit in walker: for fname in ('.SRCINFO', 'PKGBUILD'): if not fname in commit.tree: @@ -293,6 +290,9 @@ pkgbase = srcinfo._pkgbase['pkgname'] cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) pkgbase_id = cur.fetchone()[0] +cur.execute("SELECT Name FROM PackageBlacklist") +blacklist = [row[0] for row in cur.fetchall()] + for pkgname in srcinfo.GetPackageNames(): pkginfo = srcinfo.GetMergedPackage(pkgname) pkgname = pkginfo['pkgname'] From 80e06e5fc3b2ec0e862638852f2b786ed9b01424 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 14 Aug 2015 12:50:35 +0200 Subject: [PATCH 0041/1891] git-update: Remove superfluous assignment The pkgbase variable already contains the package base name at this point, no need to reassign it. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 1 - 1 file changed, 1 deletion(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index de6ceb49..8e695051 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -286,7 +286,6 @@ srcinfo_pkgbase = srcinfo._pkgbase['pkgname'] if srcinfo_pkgbase != pkgbase: die('invalid pkgbase: {:s}, expected {:s}'.format(srcinfo_pkgbase, pkgbase)) -pkgbase = srcinfo._pkgbase['pkgname'] cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) pkgbase_id = cur.fetchone()[0] From da875276d477c344358f1ba1fa82dcb269fdb138 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 14 Aug 2015 12:52:32 +0200 Subject: [PATCH 0042/1891] git-update: Add comments Add some comments to explain the major steps performed in the update hook. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 8e695051..d2583859 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -212,6 +212,7 @@ walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) if sha1_old != "0000000000000000000000000000000000000000": walker.hide(sha1_old) +# Validate all new commits. for commit in walker: for fname in ('.SRCINFO', 'PKGBUILD'): if not fname in commit.tree: @@ -278,14 +279,17 @@ for commit in walker: if not fname in commit.tree: die_commit('missing source file: {:s}'.format(fname), str(commit.id)) +# Read .SRCINFO from the HEAD commit. srcinfo_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode() srcinfo_raw = srcinfo_raw.split('\n') srcinfo = aurinfo.ParseAurinfoFromIterable(srcinfo_raw) +# Ensure that the package base name matches the repository name. srcinfo_pkgbase = srcinfo._pkgbase['pkgname'] if srcinfo_pkgbase != pkgbase: die('invalid pkgbase: {:s}, expected {:s}'.format(srcinfo_pkgbase, pkgbase)) +# Ensure that packages are neither blacklisted nor overwritten. cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) pkgbase_id = cur.fetchone()[0] @@ -304,6 +308,7 @@ for pkgname in srcinfo.GetPackageNames(): if cur.fetchone()[0] > 0: die('cannot overwrite package: {:s}'.format(pkgname)) +# Store package base details in the database. save_srcinfo(srcinfo, db, cur, user) db.close() From 4112e572aadbbc552749398010257be3a3ba802b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 14 Aug 2015 13:09:57 +0200 Subject: [PATCH 0043/1891] Add a restore command to the SSH interface Implement a new command that can be used to restore deleted package bases without having to push a new commit. Signed-off-by: Lukas Fleischer --- conf/config.proto | 1 + doc/git-interface.txt | 1 + git-interface/git-serve.py | 19 +++++++++++++++++++ git-interface/git-update.py | 21 ++++++++++++--------- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index 52da7967..2c798b74 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -51,6 +51,7 @@ ssh-options = no-port-forwarding,no-X11-forwarding,no-pty repo-path = /srv/http/aurweb/aur.git/ repo-regex = [a-z0-9][a-z0-9.+_-]*$ git-shell-cmd = /usr/bin/git-shell +git-update-cmd = /srv/http/aurweb/git-interface/git-update.py ssh-cmdline = ssh aur@aur.archlinux.org [aurblup] diff --git a/doc/git-interface.txt b/doc/git-interface.txt index b34e112e..9ded20f6 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -44,6 +44,7 @@ The git-serve command, the "aurweb shell", provides different subcommands: * The help command shows a list of available commands. * The list-repos command lists all repositories of the authenticated user. * The setup-repo command can be used to create a new repository. +* The restore command can be used to restore a deleted package base. * The git-{receive,upload}-pack commands are redirected to git-shell(1). The requested command is extracted from the SSH_ORIGINAL_COMMAND environment diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 8316cf7d..45c9a01b 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -19,6 +19,7 @@ aur_db_socket = config.get('database', 'socket') repo_path = config.get('serve', 'repo-path') repo_regex = config.get('serve', 'repo-regex') git_shell_cmd = config.get('serve', 'git-shell-cmd') +git_update_cmd = config.get('serve', 'git-update-cmd') ssh_cmdline = config.get('serve', 'ssh-cmdline') enable_maintenance = config.getboolean('options', 'enable-maintenance') @@ -152,10 +153,28 @@ elif action == 'setup-repo': if len(cmdargv) > 2: die_with_help("{:s}: too many arguments".format(action)) create_pkgbase(cmdargv[1], user) +elif action == 'restore': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) + + pkgbase = cmdargv[1] + if not re.match(repo_regex, pkgbase): + die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) + + if pkgbase_exists(pkgbase): + die('{:s}: package base exists: {:s}'.format(action, pkgbase)) + create_pkgbase(pkgbase, user) + + os.environ["AUR_USER"] = user + os.environ["AUR_PKGBASE"] = pkgbase + os.execl(git_update_cmd, git_update_cmd, 'restore') elif action == 'help': die("Commands:\n" + " help Show this help message and exit.\n" + " list-repos List all your repositories.\n" + + " restore Restore a deleted package base.\n" + " setup-repo Create an empty repository.\n" + " git-receive-pack Internal command used with Git.\n" + " git-upload-pack Internal command used with Git.") diff --git a/git-interface/git-update.py b/git-interface/git-update.py index d2583859..5ff8b285 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -176,22 +176,25 @@ def die_commit(msg, commit): sys.stderr.write("error: {:s}\n".format(msg)) exit(1) -if len(sys.argv) != 4: - die("invalid arguments") - -refname = sys.argv[1] -sha1_old = sys.argv[2] -sha1_new = sys.argv[3] +repo = pygit2.Repository(repo_path) user = os.environ.get("AUR_USER") pkgbase = os.environ.get("AUR_PKGBASE") privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1') +if len(sys.argv) == 2 and sys.argv[1] == "restore": + if 'refs/heads/' + pkgbase not in repo.listall_references(): + die('{:s}: repository not found: {:s}'.format(sys.argv[1], pkgbase)) + refname = "refs/heads/master" + sha1_old = sha1_new = repo.lookup_reference('refs/heads/' + pkgbase).target +elif len(sys.argv) == 4: + refname, sha1_old, sha1_new = sys.argv[1:3] +else: + die("invalid arguments") + if refname != "refs/heads/master": die("pushing to a branch other than master is restricted") -repo = pygit2.Repository(repo_path) - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, unix_socket=aur_db_socket, buffered=True) @@ -291,7 +294,7 @@ if srcinfo_pkgbase != pkgbase: # Ensure that packages are neither blacklisted nor overwritten. cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) -pkgbase_id = cur.fetchone()[0] +pkgbase_id = cur.fetchone()[0] if cur.rowcount == 1 else 0 cur.execute("SELECT Name FROM PackageBlacklist") blacklist = [row[0] for row in cur.fetchall()] From 7eaab632162e6691ce30f21080650c1239a90d71 Mon Sep 17 00:00:00 2001 From: Stefan Auditor Date: Sun, 16 Aug 2015 20:13:58 +0200 Subject: [PATCH 0044/1891] Update translation documentation Update the link to the project page on Transifex and remove an outdated link to the Arch Wiki. Fixes FS#45966. Signed-off-by: Stefan Auditor Signed-off-by: Lukas Fleischer --- doc/i18n.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/i18n.txt b/doc/i18n.txt index e450640f..d5b67644 100644 --- a/doc/i18n.txt +++ b/doc/i18n.txt @@ -1,12 +1,11 @@ aurweb Translation ================== -This document describes how to create and maintain aurweb translations. It was -originally derived from https://wiki.archlinux.org/index.php/aurweb_Translation +This document describes how to create and maintain aurweb translations. Creating an aurweb translation requires a Transifex (http://www.transifex.com/) account. You will need to register with a translation team on the aurweb -project page (http://www.transifex.com/projects/p/aurweb/). +project page (http://www.transifex.com/projects/p/aur/). Creating a New Translation From ff659fa05c3da5acde9c22c406daab807c22db51 Mon Sep 17 00:00:00 2001 From: Stefan Auditor Date: Sun, 16 Aug 2015 14:18:42 +0200 Subject: [PATCH 0045/1891] Remove trailing slash from git urls Circumvents the temporary regression in git that clones a repository as foo-git.git instead of foo-git and matches the format used by other commonly used git hosting providers. Fixes FS#45834. Signed-off-by: Stefan Auditor Signed-off-by: Lukas Fleischer --- conf/config.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index 2c798b74..de9acdf7 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -18,8 +18,8 @@ persistent_cookie_timeout = 2592000 max_filesize_uncompressed = 8388608 disable_http_login = 1 aur_location = https://aur.archlinux.org -git_clone_uri_anon = https://aur.archlinux.org/%s.git/ -git_clone_uri_priv = ssh+git://aur@aur.archlinux.org/%s.git/ +git_clone_uri_anon = https://aur.archlinux.org/%s.git +git_clone_uri_priv = ssh+git://aur@aur.archlinux.org/%s.git max_rpc_results = 5000 aur_request_ml = aur-requests@archlinux.org request_idle_time = 1209600 From 60433a930d6701cef1133cdb344fc76f24693636 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Mon, 17 Aug 2015 00:08:51 +0200 Subject: [PATCH 0046/1891] Remove success message from comment form To be more flexible with messages, we shouldn't always output this message when a comment has been sent. Moreover, currently it is not displayed due to the POST-Redirect-GET pattern, where the comment parameter is lost after redirection. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/pkg_comment_form.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/template/pkg_comment_form.php b/web/template/pkg_comment_form.php index 7c16eb73..c450c4b3 100644 --- a/web/template/pkg_comment_form.php +++ b/web/template/pkg_comment_form.php @@ -1,10 +1,5 @@
    -' . __('Comment has been added.') . '

    '; -} -?>
    " /> From 095986b44974c569b36d34dd26902e910ccc7d8b Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Mon, 17 Aug 2015 00:08:52 +0200 Subject: [PATCH 0047/1891] Do not allow empty comments Fixes FS#45870. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 3 +-- web/lib/pkgbasefuncs.inc.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 15818699..bc32e43c 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -107,8 +107,7 @@ if (check_token()) { list($ret, $output) = pkgbase_set_comaintainers($base_id, explode("\n", $_POST['users'])); } elseif (current_action("do_AddComment")) { $uid = uid_from_sid($_COOKIE["AURSID"]); - pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); - $ret = true; + list($ret, $output) = pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); $fragment = '#news'; } elseif (current_action("do_EditComment")) { list($ret, $output) = pkgbase_edit_comment($_REQUEST['comment']); diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index ccab635a..677ae6b8 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -81,6 +81,10 @@ function pkgbase_comments($base_id, $limit, $include_deleted) { function pkgbase_add_comment($base_id, $uid, $comment) { $dbh = DB::connect(); + if (trim($comment) == '') { + return array(false, __('Comment cannot be empty.')); + } + $q = "INSERT INTO PackageComments "; $q.= "(PackageBaseID, UsersID, Comments, CommentTS) VALUES ("; $q.= intval($base_id) . ", " . $uid . ", "; @@ -102,6 +106,8 @@ function pkgbase_add_comment($base_id, $uid, $comment) { if ($result) { notify(array('comment', $uid, $base_id), $comment); } + + return array(true, __('Comment has been added.')); } /** @@ -860,6 +866,10 @@ function pkgbase_edit_comment($comment) { return array(false, __("Missing comment ID.")); } + if (trim($comment) == '') { + return array(false, __('Comment cannot be empty.')); + } + $dbh = DB::connect(); if (can_edit_comment($comment_id)) { $q = "UPDATE PackageComments "; From 85b54157ea94ec48c0669d4e0fe1e6cd79865efb Mon Sep 17 00:00:00 2001 From: Stefan Auditor Date: Sun, 16 Aug 2015 22:50:22 +0200 Subject: [PATCH 0048/1891] Display sources count on package details page Show item count on sources section just like it is done for dependencies and required by. Fixes FS#45881. Signed-off-by: Stefan Auditor Signed-off-by: Lukas Fleischer --- web/template/pkg_details.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 9730d7e6..f4eed514 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -290,7 +290,7 @@ endif;
    -

    +

    0): ?>
    From e9e9b41484fe138f22d1452c98b7386f224517ec Mon Sep 17 00:00:00 2001 From: Stefan Auditor Date: Sun, 16 Aug 2015 22:09:04 +0200 Subject: [PATCH 0049/1891] Update link to package submission documentation Fixes FS#45942. Signed-off-by: Stefan Auditor Signed-off-by: Lukas Fleischer --- web/html/home.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/home.php b/web/html/home.php index 23f37fe2..7e9a00fe 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -77,7 +77,7 @@ html_header( __("Home") ); ', + '', '' ); ?> From e1f6de68a2faf585958823ccee35a4f6540c18b8 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Tue, 18 Aug 2015 17:55:45 +0200 Subject: [PATCH 0050/1891] account_edit_form.php: Warn users to correctly enter their email address Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/account_edit_form.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 0aadb9dc..83aedb0d 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -72,6 +72,10 @@ ()

    +

    + +

    +

    From 57250a164172672f26c763e8453855f74d72c191 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Wed, 19 Aug 2015 09:47:10 +0200 Subject: [PATCH 0051/1891] updates_table.php: Fix identification of new packages Currently, package creation has to be done separately from first submission, so ModifiedTS will never be the same as SubmittedTS. Consider all packages that are submitted within an hour from package creation as new. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/stats/updates_table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index a4b31c51..775d7073 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -10,7 +10,7 @@ " title="">

    - + New!
    "> + " . __("hidden") . ""; + else: + ?> + "> + +
    From 9c98523494a9f533cc2a8ee873c96db02a1a6d4e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 12:55:37 +0100 Subject: [PATCH 0138/1891] Replace new package icon Use a flat icon from the Open Iconic collection to mark new packages. Signed-off-by: Lukas Fleischer --- web/html/images/new.png | Bin 378 -> 0 bytes web/html/images/new.svg | 3 +++ web/html/index.php | 2 +- web/template/stats/updates_table.php | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 web/html/images/new.png create mode 100644 web/html/images/new.svg diff --git a/web/html/images/new.png b/web/html/images/new.png deleted file mode 100644 index 6a9bf0370708a165d3e49047c09e110e02074a53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 378 zcmV-=0fqjFP)Q51$RwCw?WgWe;0fi^vY%UagXRhyB(O=1wVPFJlYqlK$kNFcaSBrLFKHcpU( zVj5rP+%se7wuRup#~J3_|C@8?jsx6(aN8gV+_?~^wID=7QAmWo&=P9GzK~Bj7P?xU z4^LybJ-~;P$nL)ri2Lx-f?f?uyKtX3G(76UWeycgm{0H$eX9nWr+ASHH8>r~vom;o zFz$}vYpDI9TZYLgxm?Z}9nS!RQHI8Y*b~3AE}I>k|Ynq_|_kL0z^} zg`YWG?`i*VRiHt=)+fle*{;CjiLD9r5bPAPFRr!h8&+rODTKm>mjte|vSwTU#7zr+ Y0SIdSJYsEaB>(^b07*qoM6N<$g6XKB5dZ)H diff --git a/web/html/images/new.svg b/web/html/images/new.svg new file mode 100644 index 00000000..87f1a4cc --- /dev/null +++ b/web/html/images/new.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/html/index.php b/web/html/index.php index 817c20b3..8b5cb621 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -165,7 +165,6 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { readfile("./$path"); break; case "/css/archnavbar/archlogo.gif": - case "/images/new.png": header("Content-Type: image/png"); readfile("./$path"); break; @@ -182,6 +181,7 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { case "/images/pin.min.svg": case "/images/unpin.min.svg": case "/images/rss.svg": + case "/images/new.svg": header("Content-Type: image/svg+xml"); readfile("./$path"); break; diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index b783bd85..7cad3fa4 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -11,7 +11,7 @@ - From aaa138cd38d919072fd56d58b1eb32d5e3bc1e80 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 6 Feb 2016 16:12:15 +0100 Subject: [PATCH 0154/1891] config.proto: Do not use the ssh+git scheme Signed-off-by: Lukas Fleischer --- conf/config.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.proto b/conf/config.proto index 2390dfa8..560c705e 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -19,7 +19,7 @@ max_filesize_uncompressed = 8388608 disable_http_login = 1 aur_location = https://aur.archlinux.org git_clone_uri_anon = https://aur.archlinux.org/%s.git -git_clone_uri_priv = ssh+git://aur@aur.archlinux.org/%s.git +git_clone_uri_priv = ssh://aur@aur.archlinux.org/%s.git max_rpc_results = 5000 aur_request_ml = aur-requests@archlinux.org request_idle_time = 1209600 From f8b3cb97e54f9de73c6c2fca0cfade7e1657f1e4 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 6 Feb 2016 16:23:01 +0100 Subject: [PATCH 0155/1891] Fix issues reported by pyflakes Fix several style issues and remove unneeded imports/assignments. Signed-off-by: Lukas Fleischer --- git-interface/git-auth.py | 2 +- git-interface/git-serve.py | 11 ++++++++++- git-interface/git-update.py | 37 +++++++++++++++++++++++++------------ scripts/notify.py | 34 +++++++++++++++++++++++++++------- 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/git-interface/git-auth.py b/git-interface/git-auth.py index c7de777f..83bd20c0 100755 --- a/git-interface/git-auth.py +++ b/git-interface/git-auth.py @@ -39,7 +39,7 @@ ssh_opts = config.get('auth', 'ssh-options') keytype = sys.argv[1] keytext = sys.argv[2] -if not keytype in valid_keytypes: +if keytype not in valid_keytypes: exit(1) db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 62410e98..85815903 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -25,6 +25,7 @@ ssh_cmdline = config.get('serve', 'ssh-cmdline') enable_maintenance = config.getboolean('options', 'enable-maintenance') maintenance_exc = config.get('options', 'maintenance-exceptions').split() + def pkgbase_from_name(pkgbase): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, @@ -36,9 +37,11 @@ def pkgbase_from_name(pkgbase): row = cur.fetchone() return row[0] if row else None + def pkgbase_exists(pkgbase): return pkgbase_from_name(pkgbase) is not None + def list_repos(user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, @@ -56,6 +59,7 @@ def list_repos(user): print((' ' if row[1] else '*') + row[0]) db.close() + def create_pkgbase(pkgbase, user): if not re.match(repo_regex, pkgbase): die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) @@ -83,6 +87,7 @@ def create_pkgbase(pkgbase, user): db.commit() db.close() + def pkgbase_config_keywords(pkgbase, keywords): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: @@ -102,6 +107,7 @@ def pkgbase_config_keywords(pkgbase, keywords): db.commit() db.close() + def check_permissions(pkgbase, user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, @@ -120,13 +126,16 @@ def check_permissions(pkgbase, user): "WHERE Name = %s AND Username = %s", [pkgbase, user]) return cur.fetchone()[0] > 0 + def die(msg): sys.stderr.write("{:s}\n".format(msg)) exit(1) + def die_with_help(msg): die(msg + "\nTry `{:s} help` for a list of commands.".format(ssh_cmdline)) + user = os.environ.get("AUR_USER") cmd = os.environ.get("SSH_ORIGINAL_COMMAND") if not cmd: @@ -136,7 +145,7 @@ action = cmdargv[0] if enable_maintenance: remote_addr = os.environ["SSH_CLIENT"].split(" ")[0] - if not remote_addr in maintenance_exc: + if remote_addr not in maintenance_exc: die("The AUR is down due to maintenance. We will be back soon.") if action == 'git-upload-pack' or action == 'git-receive-pack': diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 6e09517f..5efc9b1d 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -1,6 +1,5 @@ #!/usr/bin/python3 -from copy import copy, deepcopy import configparser import mysql.connector import os @@ -22,6 +21,7 @@ aur_db_socket = config.get('database', 'socket') repo_path = config.get('serve', 'repo-path') repo_regex = config.get('serve', 'repo-regex') + def extract_arch_fields(pkginfo, field): values = [] @@ -36,6 +36,7 @@ def extract_arch_fields(pkginfo, field): return values + def parse_dep(depstring): dep, _, desc = depstring.partition(': ') depname = re.sub(r'(<|=|>).*', '', dep) @@ -46,6 +47,7 @@ def parse_dep(depstring): else: return (depname, depcond) + def save_srcinfo(srcinfo, db, cur, user): # Obtain package base ID and previous maintainer. pkgbase = srcinfo._pkgbase['pkgname'] @@ -72,13 +74,14 @@ def save_srcinfo(srcinfo, db, cur, user): pkginfo = srcinfo.GetMergedPackage(pkgname) if 'epoch' in pkginfo and int(pkginfo['epoch']) > 0: - ver = '{:d}:{:s}-{:s}'.format(int(pkginfo['epoch']), pkginfo['pkgver'], + ver = '{:d}:{:s}-{:s}'.format(int(pkginfo['epoch']), + pkginfo['pkgver'], pkginfo['pkgrel']) else: ver = '{:s}-{:s}'.format(pkginfo['pkgver'], pkginfo['pkgrel']) for field in ('pkgdesc', 'url'): - if not field in pkginfo: + if field not in pkginfo: pkginfo[field] = None # Create a new package. @@ -165,13 +168,16 @@ def save_srcinfo(srcinfo, db, cur, user): db.commit() + def die(msg): sys.stderr.write("error: {:s}\n".format(msg)) exit(1) + def warn(msg): sys.stderr.write("warning: {:s}\n".format(msg)) + def die_commit(msg, commit): sys.stderr.write("error: The following error " + "occurred when parsing commit\n") @@ -179,6 +185,7 @@ def die_commit(msg, commit): sys.stderr.write("error: {:s}\n".format(msg)) exit(1) + repo = pygit2.Repository(repo_path) user = os.environ.get("AUR_USER") @@ -207,7 +214,7 @@ cur = db.cursor() if sha1_old != "0000000000000000000000000000000000000000": walker = repo.walk(sha1_old, pygit2.GIT_SORT_TOPOLOGICAL) walker.hide(sha1_new) - if next(walker, None) != None: + if next(walker, None) is not None: cur.execute("SELECT AccountTypeID FROM Users WHERE UserName = %s ", [user]) if cur.fetchone()[0] == 1: @@ -221,7 +228,7 @@ if sha1_old != "0000000000000000000000000000000000000000": # Validate all new commits. for commit in walker: for fname in ('.SRCINFO', 'PKGBUILD'): - if not fname in commit.tree: + if fname not in commit.tree: die_commit("missing {:s}".format(fname), str(commit.id)) for treeobj in commit.tree: @@ -232,7 +239,8 @@ for commit in walker: str(commit.id)) if not isinstance(blob, pygit2.Blob): - die_commit("not a blob object: {:s}".format(treeobj), str(commit.id)) + die_commit("not a blob object: {:s}".format(treeobj), + str(commit.id)) if blob.size > 250000: die_commit("maximum blob size (250kB) exceeded", str(commit.id)) @@ -252,17 +260,20 @@ for commit in walker: srcinfo_pkgbase = srcinfo._pkgbase['pkgname'] if not re.match(repo_regex, srcinfo_pkgbase): - die_commit('invalid pkgbase: {:s}'.format(srcinfo_pkgbase), str(commit.id)) + die_commit('invalid pkgbase: {:s}'.format(srcinfo_pkgbase), + str(commit.id)) for pkgname in srcinfo.GetPackageNames(): pkginfo = srcinfo.GetMergedPackage(pkgname) for field in ('pkgver', 'pkgrel', 'pkgname'): - if not field in pkginfo: - die_commit('missing mandatory field: {:s}'.format(field), str(commit.id)) + if field not in pkginfo: + die_commit('missing mandatory field: {:s}'.format(field), + str(commit.id)) if 'epoch' in pkginfo and not pkginfo['epoch'].isdigit(): - die_commit('invalid epoch: {:s}'.format(pkginfo['epoch']), str(commit.id)) + die_commit('invalid epoch: {:s}'.format(pkginfo['epoch']), + str(commit.id)) if not re.match(r'[a-z0-9][a-z0-9\.+_-]*$', pkginfo['pkgname']): die_commit('invalid package name: {:s}'.format(pkginfo['pkgname']), @@ -282,8 +293,10 @@ for commit in walker: fname = field['value'] if "://" in fname or "lp:" in fname: continue - if not fname in commit.tree: - die_commit('missing source file: {:s}'.format(fname), str(commit.id)) + if fname not in commit.tree: + die_commit('missing source file: {:s}'.format(fname), + str(commit.id)) + # Display a warning if .SRCINFO is unchanged. if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): diff --git a/scripts/notify.py b/scripts/notify.py index b5bf518b..7b10efb9 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -4,7 +4,6 @@ import configparser import email.mime.text import mysql.connector import os -import smtplib import subprocess import sys import textwrap @@ -29,12 +28,15 @@ reply_to = config.get('notifications', 'reply-to') def headers_cc(cclist): return {'Cc': str.join(', ', cclist)} + def headers_msgid(thread_id): return {'Message-ID': thread_id} + def headers_reply(thread_id): return {'In-Reply-To': thread_id, 'References': thread_id} + def send_notification(to, subject, body, refs, headers={}): wrapped = '' for line in body.splitlines(): @@ -54,23 +56,28 @@ def send_notification(to, subject, body, refs, headers={}): p = subprocess.Popen([sendmail, '-t', '-oi'], stdin=subprocess.PIPE) p.communicate(msg.as_bytes()) + def username_from_id(cur, uid): cur.execute('SELECT UserName FROM Users WHERE ID = %s', [uid]) return cur.fetchone()[0] + def pkgbase_from_id(cur, pkgbase_id): cur.execute('SELECT Name FROM PackageBases WHERE ID = %s', [pkgbase_id]) return cur.fetchone()[0] + def pkgbase_from_pkgreq(cur, reqid): cur.execute('SELECT PackageBaseID FROM PackageRequests WHERE ID = %s', [reqid]) return cur.fetchone()[0] + def get_user_email(cur, uid): cur.execute('SELECT Email FROM Users WHERE ID = %s', [uid]) return cur.fetchone()[0] + def get_maintainer_email(cur, pkgbase_id): cur.execute('SELECT Users.Email FROM Users ' + 'INNER JOIN PackageBases ' + @@ -78,6 +85,7 @@ def get_maintainer_email(cur, pkgbase_id): 'PackageBases.ID = %s', [pkgbase_id]) return cur.fetchone()[0] + def get_recipients(cur, pkgbase_id, uid): cur.execute('SELECT DISTINCT Users.Email FROM Users ' + 'INNER JOIN CommentNotify ' + @@ -86,6 +94,7 @@ def get_recipients(cur, pkgbase_id, uid): 'CommentNotify.PackageBaseID = %s', [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] + def get_request_recipients(cur, pkgbase_id, uid): cur.execute('SELECT DISTINCT Users.Email FROM Users ' + 'INNER JOIN PackageBases ' + @@ -93,25 +102,30 @@ def get_request_recipients(cur, pkgbase_id, uid): 'Users.ID = %s OR PackageBases.ID = %s', [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] + def get_comment(cur, comment_id): cur.execute('SELECT Comments FROM PackageComments WHERE ID = %s', [comment_id]) return cur.fetchone()[0] + def get_flagger_comment(cur, pkgbase_id): cur.execute('SELECT FlaggerComment FROM PackageBases WHERE ID = %s', [pkgbase_id]) return cur.fetchone()[0] + def get_request_comment(cur, reqid): cur.execute('SELECT Comments FROM PackageRequests WHERE ID = %s', [reqid]) return cur.fetchone()[0] + def get_request_closure_comment(cur, reqid): cur.execute('SELECT ClosureComment FROM PackageRequests WHERE ID = %s', [reqid]) return cur.fetchone()[0] + def send_resetkey(cur, uid): cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', [uid]) @@ -126,6 +140,7 @@ def send_resetkey(cur, uid): send_notification([to], subject, body, refs) + def welcome(cur, uid): cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', [uid]) @@ -140,14 +155,13 @@ def welcome(cur, uid): send_notification([to], subject, body, refs) + def comment(cur, uid, pkgbase_id, comment_id): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) to = get_recipients(cur, pkgbase_id, uid) text = get_comment(cur, comment_id) - uri = aur_location + '/pkgbase/' + pkgbase + '/' - user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -164,6 +178,7 @@ def comment(cur, uid, pkgbase_id, comment_id): send_notification(to, subject, body, refs, headers) + def flag(cur, uid, pkgbase_id): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) @@ -182,6 +197,7 @@ def flag(cur, uid, pkgbase_id): send_notification(to, subject, body, refs) + def comaintainer_add(cur, pkgbase_id, uid): pkgbase = pkgbase_from_id(cur, pkgbase_id) to = [get_user_email(cur, uid)] @@ -194,6 +210,7 @@ def comaintainer_add(cur, pkgbase_id, uid): send_notification(to, subject, body, refs) + def comaintainer_remove(cur, pkgbase_id, uid): pkgbase = pkgbase_from_id(cur, pkgbase_id) to = [get_user_email(cur, uid)] @@ -201,12 +218,13 @@ def comaintainer_remove(cur, pkgbase_id, uid): pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase) - body = 'You were removed from the co-maintainer list of %s [1].' % \ - (pkgbase) + body = ('You were removed from the co-maintainer list of %s [1].' % + (pkgbase)) refs = '[1] ' + pkgbase_uri + '\n' send_notification(to, subject, body, refs) + def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): user = username_from_id(cur, uid) old_pkgbase = pkgbase_from_id(cur, old_pkgbase_id) @@ -215,7 +233,7 @@ def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): to = get_recipients(cur, old_pkgbase_id, uid) user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + pkgbase_uri = aur_location + '/pkgbase/' + old_pkgbase + '/' subject = 'AUR Package deleted: %s' % (old_pkgbase) if new_pkgbase_id: @@ -236,6 +254,7 @@ def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): send_notification(to, subject, body, refs) + def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) @@ -268,12 +287,13 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): send_notification(to, subject, body, refs, headers) + def request_close(cur, uid, reqid, reason): user = username_from_id(cur, uid) pkgbase_id = pkgbase_from_pkgreq(cur, reqid) to = [aur_request_ml] cc = get_request_recipients(cur, pkgbase_id, uid) - text = get_request_closure_comment(cur, reqid); + text = get_request_closure_comment(cur, reqid) user_uri = aur_location + '/account/' + user + '/' From 7a3a3876a8bea154c27f903ea9a3a7fc9fe4283e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sat, 13 Jun 2015 17:11:33 +0200 Subject: [PATCH 0156/1891] git-update: Replace aurinfo.py with python-srcinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit python-srcinfo is a more transparent and simpler library for parsing SRCINFO files. Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- INSTALL | 2 +- git-interface/aurinfo.py | 208 ------------------------------------ git-interface/git-update.py | 51 +++++---- 3 files changed, 26 insertions(+), 235 deletions(-) delete mode 100644 git-interface/aurinfo.py diff --git a/INSTALL b/INSTALL index d5664d27..be390525 100644 --- a/INSTALL +++ b/INSTALL @@ -53,7 +53,7 @@ Setup on Arch Linux 7) Install needed Python modules: - # pacman -S python-mysql-connector python-pygit2 + # pacman -S python-mysql-connector python-pygit2 python-srcinfo 8) Install the git-auth wrapper script: diff --git a/git-interface/aurinfo.py b/git-interface/aurinfo.py deleted file mode 100644 index b286316f..00000000 --- a/git-interface/aurinfo.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python - -from copy import copy, deepcopy -import pprint -import sys - -class Attr(object): - def __init__(self, name, is_multivalued=False, allow_arch_extensions=False): - self.name = name - self.is_multivalued = is_multivalued - self.allow_arch_extensions = allow_arch_extensions - -PKGBUILD_ATTRIBUTES = { - 'arch': Attr('arch', True), - 'backup': Attr('backup', True), - 'changelog': Attr('changelog', False), - 'checkdepends': Attr('checkdepends', True), - 'conflicts': Attr('conflicts', True, True), - 'depends': Attr('depends', True, True), - 'epoch': Attr('epoch', False), - 'groups': Attr('groups', True), - 'install': Attr('install', False), - 'license': Attr('license', True), - 'makedepends': Attr('makedepends', True, True), - 'md5sums': Attr('md5sums', True, True), - 'noextract': Attr('noextract', True), - 'optdepends': Attr('optdepends', True, True), - 'options': Attr('options', True), - 'pkgname': Attr('pkgname', False), - 'pkgrel': Attr('pkgrel', False), - 'pkgver': Attr('pkgver', False), - 'provides': Attr('provides', True, True), - 'replaces': Attr('replaces', True, True), - 'sha1sums': Attr('sha1sums', True, True), - 'sha224sums': Attr('sha224sums', True, True), - 'sha256sums': Attr('sha256sums', True, True), - 'sha384sums': Attr('sha384sums', True, True), - 'sha512sums': Attr('sha512sums', True, True), - 'source': Attr('source', True, True), - 'url': Attr('url', False), - 'validpgpkeys': Attr('validpgpkeys', True), -} - -def find_attr(attrname): - # exact match - attr = PKGBUILD_ATTRIBUTES.get(attrname, None) - if attr: - return attr - - # prefix match - # XXX: this could break in the future if PKGBUILD(5) ever - # introduces a key which is a subset of another. - for k in PKGBUILD_ATTRIBUTES.keys(): - if attrname.startswith(k + '_'): - return PKGBUILD_ATTRIBUTES[k] - -def IsMultiValued(attrname): - attr = find_attr(attrname) - return attr and attr.is_multivalued - -class AurInfo(object): - def __init__(self): - self._pkgbase = {} - self._packages = {} - - def GetPackageNames(self): - return self._packages.keys() - - def GetMergedPackage(self, pkgname): - package = deepcopy(self._pkgbase) - package['pkgname'] = pkgname - for k, v in self._packages.get(pkgname).items(): - package[k] = deepcopy(v) - return package - - def AddPackage(self, pkgname): - self._packages[pkgname] = {} - return self._packages[pkgname] - - def SetPkgbase(self, pkgbasename): - self._pkgbase = {'pkgname' : pkgbasename} - return self._pkgbase - - -class StderrECatcher(object): - def Catch(self, lineno, error): - print('ERROR[{:d}]: {:s}'.format(lineno, error), file=sys.stderr) - - -class CollectionECatcher(object): - def __init__(self): - self._errors = [] - - def Catch(self, lineno, error): - self._errors.append((lineno, error)) - - def HasErrors(self): - return len(self._errors) > 0 - - def Errors(self): - return copy(self._errors) - - -def ParseAurinfoFromIterable(iterable, ecatcher=None): - aurinfo = AurInfo() - - if ecatcher is None: - ecatcher = StderrECatcher() - - current_package = None - lineno = 0 - - for line in iterable: - lineno += 1 - - if line.startswith('#'): - continue - - if not line.strip(): - # end of package - current_package = None - continue - - if not (line.startswith('\t') or line.startswith(' ')): - # start of new package - try: - key, value = map(str.strip, line.split('=', 1)) - except ValueError: - ecatcher.Catch(lineno, 'unexpected header format in section={:s}'.format( - current_package['pkgname'])) - continue - - if key == 'pkgbase': - current_package = aurinfo.SetPkgbase(value) - elif key == 'pkgname': - current_package = aurinfo.AddPackage(value) - else: - ecatcher.Catch(lineno, 'unexpected new section not starting ' - 'with \'pkgname\' found') - continue - else: - # package attribute - if current_package is None: - ecatcher.Catch(lineno, 'package attribute found outside of ' - 'a package section') - continue - - try: - key, value = map(str.strip, line.split('=', 1)) - except ValueError: - ecatcher.Catch(lineno, 'unexpected attribute format in ' - 'section={:s}'.format(current_package['pkgname'])) - - if IsMultiValued(key): - if not current_package.get(key): - current_package[key] = [] - if value: - current_package[key].append(value) - else: - if not current_package.get(key): - current_package[key] = value - else: - ecatcher.Catch(lineno, 'overwriting attribute ' - '{:s}: {:s} -> {:s}'.format(key, - current_package[key], value)) - - return aurinfo - - -def ParseAurinfo(filename='.AURINFO', ecatcher=None): - with open(filename) as f: - return ParseAurinfoFromIterable(f, ecatcher) - - -def ValidateAurinfo(filename='.AURINFO'): - ecatcher = CollectionECatcher() - ParseAurinfo(filename, ecatcher) - errors = ecatcher.Errors() - for error in errors: - print('error on line {:d}: {:s}'.format(error), file=sys.stderr) - return not errors - - -if __name__ == '__main__': - pp = pprint.PrettyPrinter(indent=4) - - if len(sys.argv) == 1: - print('error: not enough arguments') - sys.exit(1) - elif len(sys.argv) == 2: - action = sys.argv[1] - filename = '.AURINFO' - else: - action, filename = sys.argv[1:3] - - if action == 'parse': - aurinfo = ParseAurinfo(filename) - for pkgname in aurinfo.GetPackageNames(): - print(">>> merged package: {:s}".format(pkgname)) - pp.pprint(aurinfo.GetMergedPackage(pkgname)) - print() - elif action == 'validate': - sys.exit(not ValidateAurinfo(filename)) - else: - print('unknown action: {:s}'.format(action)) - sys.exit(1) - -# vim: set et ts=4 sw=4: diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 5efc9b1d..a4a8d8d7 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -7,7 +7,8 @@ import pygit2 import re import sys -import aurinfo +import srcinfo.parse +import srcinfo.utils config = configparser.RawConfigParser() config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") @@ -48,9 +49,9 @@ def parse_dep(depstring): return (depname, depcond) -def save_srcinfo(srcinfo, db, cur, user): +def save_metadata(metadata, db, cur, user): # Obtain package base ID and previous maintainer. - pkgbase = srcinfo._pkgbase['pkgname'] + pkgbase = metadata['pkgbase'] cur.execute("SELECT ID, MaintainerUID FROM PackageBases " "WHERE Name = %s", [pkgbase]) (pkgbase_id, maintainer_uid) = cur.fetchone() @@ -70,8 +71,8 @@ def save_srcinfo(srcinfo, db, cur, user): cur.execute("DELETE FROM Packages WHERE PackageBaseID = %s", [pkgbase_id]) - for pkgname in srcinfo.GetPackageNames(): - pkginfo = srcinfo.GetMergedPackage(pkgname) + for pkgname in srcinfo.utils.get_package_names(metadata): + pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) if 'epoch' in pkginfo and int(pkginfo['epoch']) > 0: ver = '{:d}:{:s}-{:s}'.format(int(pkginfo['epoch']), @@ -245,26 +246,24 @@ for commit in walker: if blob.size > 250000: die_commit("maximum blob size (250kB) exceeded", str(commit.id)) - srcinfo_raw = repo[commit.tree['.SRCINFO'].id].data.decode() - srcinfo_raw = srcinfo_raw.split('\n') - ecatcher = aurinfo.CollectionECatcher() - srcinfo = aurinfo.ParseAurinfoFromIterable(srcinfo_raw, ecatcher) - errors = ecatcher.Errors() + metadata_raw = repo[commit.tree['.SRCINFO'].id].data.decode() + (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) if errors: sys.stderr.write("error: The following errors occurred " "when parsing .SRCINFO in commit\n") sys.stderr.write("error: {:s}:\n".format(str(commit.id))) for error in errors: - sys.stderr.write("error: line {:d}: {:s}\n".format(*error)) + for err in error['error']: + sys.stderr.write("error: line {:d}: {:s}\n".format(error['line'], err)) exit(1) - srcinfo_pkgbase = srcinfo._pkgbase['pkgname'] - if not re.match(repo_regex, srcinfo_pkgbase): - die_commit('invalid pkgbase: {:s}'.format(srcinfo_pkgbase), + metadata_pkgbase = metadata['pkgbase'] + if not re.match(repo_regex, metadata_pkgbase): + die_commit('invalid pkgbase: {:s}'.format(metadata_pkgbase), str(commit.id)) - for pkgname in srcinfo.GetPackageNames(): - pkginfo = srcinfo.GetMergedPackage(pkgname) + for pkgname in set(metadata['packages'].keys()): + pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) for field in ('pkgver', 'pkgrel', 'pkgname'): if field not in pkginfo: @@ -306,28 +305,28 @@ if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): warn(".SRCINFO unchanged. The package database will not be updated!") # Read .SRCINFO from the HEAD commit. -srcinfo_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode() -srcinfo_raw = srcinfo_raw.split('\n') -srcinfo = aurinfo.ParseAurinfoFromIterable(srcinfo_raw) +metadata_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode() +(metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) # Ensure that the package base name matches the repository name. -srcinfo_pkgbase = srcinfo._pkgbase['pkgname'] -if srcinfo_pkgbase != pkgbase: - die('invalid pkgbase: {:s}, expected {:s}'.format(srcinfo_pkgbase, pkgbase)) +metadata_pkgbase = metadata['pkgbase'] +if metadata_pkgbase != pkgbase: + die('invalid pkgbase: {:s}, expected {:s}'.format(metadata_pkgbase, pkgbase)) # Ensure that packages are neither blacklisted nor overwritten. +pkgbase = metadata['pkgbase'] cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) pkgbase_id = cur.fetchone()[0] if cur.rowcount == 1 else 0 cur.execute("SELECT Name FROM PackageBlacklist") blacklist = [row[0] for row in cur.fetchall()] -for pkgname in srcinfo.GetPackageNames(): - pkginfo = srcinfo.GetMergedPackage(pkgname) +for pkgname in srcinfo.utils.get_package_names(metadata): + pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) pkgname = pkginfo['pkgname'] if pkgname in blacklist and not privileged: - die('package is blacklisted: {:s}'.format(pkginfo['pkgname'])) + die('package is blacklisted: {:s}'.format(pkgname)) cur.execute("SELECT COUNT(*) FROM Packages WHERE Name = %s AND " + "PackageBaseID <> %s", [pkgname, pkgbase_id]) @@ -335,7 +334,7 @@ for pkgname in srcinfo.GetPackageNames(): die('cannot overwrite package: {:s}'.format(pkgname)) # Store package base details in the database. -save_srcinfo(srcinfo, db, cur, user) +save_metadata(metadata, db, cur, user) db.close() From daee000604243b95e439167c97b3ee8cdc4f6ca3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 7 Feb 2016 10:05:23 +0100 Subject: [PATCH 0157/1891] upgrading/4.2.0.txt: Fix numbering Signed-off-by: Lukas Fleischer --- upgrading/4.2.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index 90fee971..c43c6e7e 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -36,7 +36,7 @@ UPDATE PackageComments SET DelTS = EditedTS WHERE DelUsersID IS NOT NULL; ALTER TABLE PackageRequests ADD COLUMN ClosureComment TEXT NOT NULL DEFAULT ''; ---- -4. Change FlaggerComment from varchar to text. +6. Change FlaggerComment from VARCHAR to TEXT: ---- ALTER TABLE PackageBases MODIFY COLUMN FlaggerComment TEXT NOT NULL DEFAULT ''; From 3412de21d32708b44d1fb3011649734e3cc67d9b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 10 Nov 2015 19:26:57 +0100 Subject: [PATCH 0158/1891] Rename the CommentNotify table to PackageNotifications As a preparatory step to adding support for package notifications on events other than comments, rename the database table accordingly. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 2 +- git-interface/git-update.py | 4 ++-- schema/aur-schema.sql | 6 +++--- scripts/notify.py | 8 ++++---- upgrading/4.2.0.txt | 6 ++++++ web/lib/acctfuncs.inc.php | 2 +- web/lib/pkgbasefuncs.inc.php | 14 +++++++------- web/lib/pkgfuncs.inc.php | 6 +++--- 8 files changed, 27 insertions(+), 21 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 85815903..ff389d26 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -81,7 +81,7 @@ def create_pkgbase(pkgbase, user): "UNIX_TIMESTAMP(), %s, %s)", [pkgbase, userid, userid]) pkgbase_id = cur.lastrowid - cur.execute("INSERT INTO CommentNotify (PackageBaseID, UserID) " + + cur.execute("INSERT INTO PackageNotifications (PackageBaseID, UserID) " + "VALUES (%s, %s)", [pkgbase_id, userid]) db.commit() diff --git a/git-interface/git-update.py b/git-interface/git-update.py index a4a8d8d7..3b587b3f 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -160,11 +160,11 @@ def save_metadata(metadata, db, cur, user): # Add user to notification list on adoption. if was_orphan: - cur.execute("SELECT COUNT(*) FROM CommentNotify WHERE " + + cur.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " + "PackageBaseID = %s AND UserID = %s", [pkgbase_id, user_id]) if cur.fetchone()[0] == 0: - cur.execute("INSERT INTO CommentNotify (PackageBaseID, UserID) " + + cur.execute("INSERT INTO PackageNotifications (PackageBaseID, UserID) " + "VALUES (%s, %s)", [pkgbase_id, user_id]) db.commit() diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 9645e137..543f0256 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -284,15 +284,15 @@ CREATE TABLE PackageComaintainers ( FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE ) ENGINE = InnoDB; --- Comment addition notifications +-- Package base notifications -- -CREATE TABLE CommentNotify ( +CREATE TABLE PackageNotifications ( PackageBaseID INTEGER UNSIGNED NOT NULL, UserID INTEGER UNSIGNED NOT NULL, FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE, FOREIGN KEY (UserID) REFERENCES Users(ID) ON DELETE CASCADE ) ENGINE = InnoDB; -CREATE UNIQUE INDEX NotifyUserIDPkgID ON CommentNotify (UserID, PackageBaseID); +CREATE UNIQUE INDEX NotifyUserIDPkgID ON PackageNotifications (UserID, PackageBaseID); -- Package name blacklist -- diff --git a/scripts/notify.py b/scripts/notify.py index 7b10efb9..08cdda85 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -88,10 +88,10 @@ def get_maintainer_email(cur, pkgbase_id): def get_recipients(cur, pkgbase_id, uid): cur.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN CommentNotify ' + - 'ON CommentNotify.UserID = Users.ID WHERE ' + - 'CommentNotify.UserID != %s AND ' + - 'CommentNotify.PackageBaseID = %s', [uid, pkgbase_id]) + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'PackageNotifications.UserID != %s AND ' + + 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index c43c6e7e..7d404b3e 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -41,3 +41,9 @@ ALTER TABLE PackageRequests ADD COLUMN ClosureComment TEXT NOT NULL DEFAULT ''; ---- ALTER TABLE PackageBases MODIFY COLUMN FlaggerComment TEXT NOT NULL DEFAULT ''; ---- + +7. Rename the CommentNotify table to PackageNotifications: + +---- +ALTER TABLE CommentNotify RENAME TO PackageNotifications; +---- diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 6fb2b407..0c6388af 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -897,7 +897,7 @@ function user_delete($id) { $fields_delete = array( array("Sessions", "UsersID"), array("PackageVotes", "UsersID"), - array("CommentNotify", "UsersID") + array("PackageNotifications", "UsersID") ); $fields_set_null = array( diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 20f5bb49..c0e672ad 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -542,15 +542,15 @@ function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) { $dbh->exec($q); /* Merge notifications */ - $q = "SELECT DISTINCT UserID FROM CommentNotify cn "; + $q = "SELECT DISTINCT UserID FROM PackageNotifications cn "; $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ") "; - $q.= "AND NOT EXISTS (SELECT * FROM CommentNotify cn2 "; + $q.= "AND NOT EXISTS (SELECT * FROM PackageNotifications cn2 "; $q.= "WHERE cn2.PackageBaseID = " . intval($merge_base_id) . " "; $q.= "AND cn2.UserID = cn.UserID)"; $result = $dbh->query($q); while ($notify_uid = $result->fetch(PDO::FETCH_COLUMN, 0)) { - $q = "INSERT INTO CommentNotify (UserID, PackageBaseID) "; + $q = "INSERT INTO PackageNotifications (UserID, PackageBaseID) "; $q.= "VALUES (" . intval($notify_uid) . ", " . intval($merge_base_id) . ")"; $dbh->exec($q); } @@ -840,7 +840,7 @@ function pkgbase_user_voted($uid, $base_id) { function pkgbase_user_notify($uid, $base_id) { $dbh = DB::connect(); - $q = "SELECT * FROM CommentNotify WHERE UserID = " . $dbh->quote($uid); + $q = "SELECT * FROM PackageNotifications WHERE UserID = " . $dbh->quote($uid); $q.= " AND PackageBaseID = " . $dbh->quote($base_id); $result = $dbh->query($q); @@ -898,20 +898,20 @@ function pkgbase_notify ($base_ids, $action=true) { if ($action) { - $q = "SELECT COUNT(*) FROM CommentNotify WHERE "; + $q = "SELECT COUNT(*) FROM PackageNotifications WHERE "; $q .= "UserID = $uid AND PackageBaseID = $bid"; /* Notification already added. Don't add again. */ $result = $dbh->query($q); if ($result->fetchColumn() == 0) { - $q = "INSERT INTO CommentNotify (PackageBaseID, UserID) VALUES ($bid, $uid)"; + $q = "INSERT INTO PackageNotifications (PackageBaseID, UserID) VALUES ($bid, $uid)"; $dbh->exec($q); } $output .= $basename; } else { - $q = "DELETE FROM CommentNotify WHERE PackageBaseID = $bid "; + $q = "DELETE FROM PackageNotifications WHERE PackageBaseID = $bid "; $q .= "AND UserID = $uid"; $dbh->exec($q); diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index c2bbe387..0e152ddc 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -716,7 +716,7 @@ function pkg_search_page($SID="") { /* Build the package search query. */ $q_select = "SELECT "; if ($SID) { - $q_select .= "CommentNotify.UserID AS Notify, + $q_select .= "PackageNotifications.UserID AS Notify, PackageVotes.UsersID AS Voted, "; } $q_select .= "Users.Username AS Maintainer, @@ -731,8 +731,8 @@ function pkg_search_page($SID="") { /* This is not needed for the total row count query. */ $q_from_extra = "LEFT JOIN PackageVotes ON (PackageBases.ID = PackageVotes.PackageBaseID AND PackageVotes.UsersID = $myuid) - LEFT JOIN CommentNotify - ON (PackageBases.ID = CommentNotify.PackageBaseID AND CommentNotify.UserID = $myuid) "; + LEFT JOIN PackageNotifications + ON (PackageBases.ID = PackageNotifications.PackageBaseID AND PackageNotifications.UserID = $myuid) "; } else { $q_from_extra = ""; } From aa5e58db81b8a243e03d0f08925c2d1f34c82304 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 10 Nov 2015 19:49:13 +0100 Subject: [PATCH 0159/1891] Add global comment notification setting Add a configuration option to the account edit page that allows for globally enabling/disabling package base comment notifications. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 1 + scripts/notify.py | 12 +++++++++++- upgrading/4.2.0.txt | 7 +++++++ web/html/account.php | 18 ++++++++++++------ web/html/register.php | 4 ++-- web/lib/acctfuncs.inc.php | 7 +++++-- web/template/account_edit_form.php | 8 ++++++++ 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 543f0256..13a052e1 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -38,6 +38,7 @@ CREATE TABLE Users ( LastLoginIPAddress INTEGER UNSIGNED NOT NULL DEFAULT 0, InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0, RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CommentNotify TINYINT(1) NOT NULL DEFAULT 1, PRIMARY KEY (ID), UNIQUE (Username), UNIQUE (Email), diff --git a/scripts/notify.py b/scripts/notify.py index 08cdda85..6b106009 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -95,6 +95,16 @@ def get_recipients(cur, pkgbase_id, uid): return [row[0] for row in cur.fetchall()] +def get_comment_recipients(cur, pkgbase_id, uid): + cur.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.CommentNotify = 1 AND ' + + 'PackageNotifications.UserID != %s AND ' + + 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) + return [row[0] for row in cur.fetchall()] + + def get_request_recipients(cur, pkgbase_id, uid): cur.execute('SELECT DISTINCT Users.Email FROM Users ' + 'INNER JOIN PackageBases ' + @@ -159,7 +169,7 @@ def welcome(cur, uid): def comment(cur, uid, pkgbase_id, comment_id): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = get_recipients(cur, pkgbase_id, uid) + to = get_comment_recipients(cur, pkgbase_id, uid) text = get_comment(cur, comment_id) user_uri = aur_location + '/account/' + user + '/' diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index 7d404b3e..ce76f493 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -47,3 +47,10 @@ ALTER TABLE PackageBases MODIFY COLUMN FlaggerComment TEXT NOT NULL DEFAULT ''; ---- ALTER TABLE CommentNotify RENAME TO PackageNotifications; ---- + +8. Add new columns to store notification settings: + +---- +ALTER TABLE Users + ADD COLUMN CommentNotify TINYINT(1) NOT NULL DEFAULT 1; +---- diff --git a/web/html/account.php b/web/html/account.php index b2886fc6..2f85a8a9 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -35,7 +35,8 @@ if ($action == "UpdateAccount") { in_request("E"), in_request("H"), in_request("P"), in_request("C"), in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("PK"), - in_request("J"), in_request("ID"), $row["Username"]); + in_request("J"), in_request("CN"), in_request("ID"), + $row["Username"]); } } @@ -81,7 +82,8 @@ if (isset($_COOKIE["AURSID"])) { $row["AccountTypeID"], $row["Suspended"], $row["Email"], $row["HideEmail"], "", "", $row["RealName"], $row["LangPreference"], $row["IRCNick"], $row["PGPKey"], $PK, - $row["InactivityTS"] ? 1 : 0, $row["ID"], $row["Username"]); + $row["InactivityTS"] ? 1 : 0, $row["CommentNotify"], + $row["ID"], $row["Username"]); } else { print __("You do not have permission to edit this account."); } @@ -114,10 +116,14 @@ if (isset($_COOKIE["AURSID"])) { print $update_account_message; if (!$success) { - display_account_form("UpdateAccount", in_request("U"), in_request("T"), - in_request("S"), in_request("E"), in_request("H"), in_request("P"), - in_request("C"), in_request("R"), in_request("L"), in_request("I"), - in_request("K"), in_request("PK"), in_request("J"), in_request("ID"), + display_account_form("UpdateAccount", in_request("U"), + in_request("T"), in_request("S"), + in_request("E"), in_request("H"), + in_request("P"), in_request("C"), + in_request("R"), in_request("L"), + in_request("I"), in_request("K"), + in_request("PK"), in_request("J"), + in_request("CN"), in_request("ID"), $row["Username"]); } diff --git a/web/html/register.php b/web/html/register.php index f8400a37..f58fb258 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -23,7 +23,7 @@ if (in_request("Action") == "NewAccount") { "new", "NewAccount", in_request("U"), 1, 0, in_request("E"), in_request("H"), '', '', in_request("R"), in_request("L"), in_request("I"), in_request("K"), - in_request("PK")); + in_request("PK"), 0, in_request("CN")); print $message; @@ -31,7 +31,7 @@ if (in_request("Action") == "NewAccount") { display_account_form("NewAccount", in_request("U"), 1, 0, in_request("E"), in_request("H"), '', '', in_request("R"), in_request("L"), in_request("I"), in_request("K"), - in_request("PK")); + in_request("PK"), 0, in_request("CN")); } } else { print '

    ' . __("Use this form to create an account.") . '

    '; diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 0c6388af..796b82bd 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -56,13 +56,14 @@ function html_format_pgp_fingerprint($fingerprint) { * @param string $K The PGP key fingerprint of the displayed user * @param string $PK The list of SSH public keys * @param string $J The inactivity status of the displayed user + * @param string $CN Whether to notify of new comments * @param string $UID The user ID of the displayed user * @param string $N The username as present in the database * * @return void */ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="", - $L="",$I="",$K="",$PK="",$J="",$UID=0,$N="") { + $L="",$I="",$K="",$PK="",$J="",$CN="",$UID=0,$N="") { global $SUPPORTED_LANGS; include("account_edit_form.php"); @@ -88,13 +89,14 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $K The PGP fingerprint of the user * @param string $PK The list of public SSH keys * @param string $J The inactivity status of the user + * @param string $CN Whether to notify of new comments * @param string $UID The user ID of the modified account * @param string $N The username as present in the database * * @return array Boolean indicating success and message to be printed */ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", - $R="",$L="",$I="",$K="",$PK="",$J="",$UID=0,$N="") { + $R="",$L="",$I="",$K="",$PK="",$J="",$CN="",$UID=0,$N="") { global $SUPPORTED_LANGS; $error = ''; @@ -341,6 +343,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $q.= ", IRCNick = " . $dbh->quote($I); $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K)); $q.= ", InactivityTS = " . $inactivity_ts; + $q.= ", CommentNotify = " . ($CN ? "1" : "0"); $q.= " WHERE ID = ".intval($UID); $result = $dbh->exec($q); diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index cb0fa33b..4f92f693 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -133,6 +133,14 @@

    +
    + : +

    + + /> +

    +
    +

    From 64072461dfcc74857087b23c9ba7d9812b6afe40 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 10 Nov 2015 20:18:13 +0100 Subject: [PATCH 0160/1891] Add support for package update notifications Introduce a new notification option to receive notifications when a new commit is pushed to a package repository. Implements FS#30109. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 18 ++++++++++++++-- schema/aur-schema.sql | 1 + scripts/notify.py | 33 ++++++++++++++++++++++++++++++ upgrading/4.2.0.txt | 3 ++- web/html/account.php | 10 ++++----- web/html/register.php | 4 ++-- web/lib/acctfuncs.inc.php | 7 +++++-- web/template/account_edit_form.php | 4 ++++ 8 files changed, 68 insertions(+), 12 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 3b587b3f..e54e0e68 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -5,6 +5,7 @@ import mysql.connector import os import pygit2 import re +import subprocess import sys import srcinfo.parse @@ -19,6 +20,8 @@ aur_db_user = config.get('database', 'user') aur_db_pass = config.get('database', 'password') aur_db_socket = config.get('database', 'socket') +notify_cmd = config.get('notifications', 'notify-cmd') + repo_path = config.get('serve', 'repo-path') repo_regex = config.get('serve', 'repo-regex') @@ -169,6 +172,13 @@ def save_metadata(metadata, db, cur, user): db.commit() +def update_notify(db, cur, user, pkgbase_id): + # Obtain the user ID of the new maintainer. + cur.execute("SELECT ID FROM Users WHERE Username = %s", [user]) + user_id = int(cur.fetchone()[0]) + + # Execute the notification script. + subprocess.Popen((notify_cmd, 'update', str(user_id), str(pkgbase_id))) def die(msg): sys.stderr.write("error: {:s}\n".format(msg)) @@ -336,8 +346,6 @@ for pkgname in srcinfo.utils.get_package_names(metadata): # Store package base details in the database. save_metadata(metadata, db, cur, user) -db.close() - # Create (or update) a branch with the name of the package base for better # accessibility. repo.create_reference('refs/heads/' + pkgbase, sha1_new, True) @@ -347,3 +355,9 @@ repo.create_reference('refs/heads/' + pkgbase, sha1_new, True) # http://git.661346.n2.nabble.com/PATCH-receive-pack-Create-a-HEAD-ref-for-ref-namespace-td7632149.html # for details. repo.create_reference('refs/namespaces/' + pkgbase + '/HEAD', sha1_new, True) + +# Send package update notifications. +update_notify(db, cur, user, pkgbase_id) + +# Close the database. +db.close() diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 13a052e1..1a141c14 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -39,6 +39,7 @@ CREATE TABLE Users ( InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0, RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CommentNotify TINYINT(1) NOT NULL DEFAULT 1, + UpdateNotify TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (ID), UNIQUE (Username), UNIQUE (Email), diff --git a/scripts/notify.py b/scripts/notify.py index 6b106009..56534ae7 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -105,6 +105,16 @@ def get_comment_recipients(cur, pkgbase_id, uid): return [row[0] for row in cur.fetchall()] +def get_update_recipients(cur, pkgbase_id, uid): + cur.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.UpdateNotify = 1 AND ' + + 'PackageNotifications.UserID != %s AND ' + + 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) + return [row[0] for row in cur.fetchall()] + + def get_request_recipients(cur, pkgbase_id, uid): cur.execute('SELECT DISTINCT Users.Email FROM Users ' + 'INNER JOIN PackageBases ' + @@ -189,6 +199,28 @@ def comment(cur, uid, pkgbase_id, comment_id): send_notification(to, subject, body, refs, headers) +def update(cur, uid, pkgbase_id): + user = username_from_id(cur, uid) + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = get_update_recipients(cur, pkgbase_id, uid) + + user_uri = aur_location + '/account/' + user + '/' + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = 'AUR Package Update: %s' % (pkgbase) + body = '%s [1] pushed a new commit to %s [2].' % (user, pkgbase) + body += '\n\n' + body += 'If you no longer wish to receive notifications about this ' \ + 'package, please go to the package page [2] and select "%s".' % \ + ('Disable notifications') + refs = '[1] ' + user_uri + '\n' + refs += '[2] ' + pkgbase_uri + thread_id = '' + headers = headers_reply(thread_id) + + send_notification(to, subject, body, refs, headers) + + def flag(cur, uid, pkgbase_id): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) @@ -327,6 +359,7 @@ if __name__ == '__main__': 'send-resetkey': send_resetkey, 'welcome': welcome, 'comment': comment, + 'update': update, 'flag': flag, 'comaintainer-add': comaintainer_add, 'comaintainer-remove': comaintainer_remove, diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index ce76f493..0bf9a319 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -52,5 +52,6 @@ ALTER TABLE CommentNotify RENAME TO PackageNotifications; ---- ALTER TABLE Users - ADD COLUMN CommentNotify TINYINT(1) NOT NULL DEFAULT 1; + ADD COLUMN CommentNotify TINYINT(1) NOT NULL DEFAULT 1, + ADD COLUMN UpdateNotify TINYINT(1) NOT NULL DEFAULT 0; ---- diff --git a/web/html/account.php b/web/html/account.php index 2f85a8a9..9007ace5 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -35,8 +35,8 @@ if ($action == "UpdateAccount") { in_request("E"), in_request("H"), in_request("P"), in_request("C"), in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("PK"), - in_request("J"), in_request("CN"), in_request("ID"), - $row["Username"]); + in_request("J"), in_request("CN"), in_request("UN"), + in_request("ID"), $row["Username"]); } } @@ -83,7 +83,7 @@ if (isset($_COOKIE["AURSID"])) { $row["HideEmail"], "", "", $row["RealName"], $row["LangPreference"], $row["IRCNick"], $row["PGPKey"], $PK, $row["InactivityTS"] ? 1 : 0, $row["CommentNotify"], - $row["ID"], $row["Username"]); + $row["UpdateNotify"], $row["ID"], $row["Username"]); } else { print __("You do not have permission to edit this account."); } @@ -123,8 +123,8 @@ if (isset($_COOKIE["AURSID"])) { in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("PK"), in_request("J"), - in_request("CN"), in_request("ID"), - $row["Username"]); + in_request("CN"), in_request("UN"), + in_request("ID"), $row["Username"]); } } else { diff --git a/web/html/register.php b/web/html/register.php index f58fb258..3155449c 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -23,7 +23,7 @@ if (in_request("Action") == "NewAccount") { "new", "NewAccount", in_request("U"), 1, 0, in_request("E"), in_request("H"), '', '', in_request("R"), in_request("L"), in_request("I"), in_request("K"), - in_request("PK"), 0, in_request("CN")); + in_request("PK"), 0, in_request("CN"), in_request("UN")); print $message; @@ -31,7 +31,7 @@ if (in_request("Action") == "NewAccount") { display_account_form("NewAccount", in_request("U"), 1, 0, in_request("E"), in_request("H"), '', '', in_request("R"), in_request("L"), in_request("I"), in_request("K"), - in_request("PK"), 0, in_request("CN")); + in_request("PK"), 0, in_request("CN"), in_request("UN")); } } else { print '

    ' . __("Use this form to create an account.") . '

    '; diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 796b82bd..b39420fe 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -57,13 +57,14 @@ function html_format_pgp_fingerprint($fingerprint) { * @param string $PK The list of SSH public keys * @param string $J The inactivity status of the displayed user * @param string $CN Whether to notify of new comments + * @param string $UN Whether to notify of package updates * @param string $UID The user ID of the displayed user * @param string $N The username as present in the database * * @return void */ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="", - $L="",$I="",$K="",$PK="",$J="",$CN="",$UID=0,$N="") { + $L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$UID=0,$N="") { global $SUPPORTED_LANGS; include("account_edit_form.php"); @@ -90,13 +91,14 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $PK The list of public SSH keys * @param string $J The inactivity status of the user * @param string $CN Whether to notify of new comments + * @param string $UN Whether to notify of package updates * @param string $UID The user ID of the modified account * @param string $N The username as present in the database * * @return array Boolean indicating success and message to be printed */ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", - $R="",$L="",$I="",$K="",$PK="",$J="",$CN="",$UID=0,$N="") { + $R="",$L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$UID=0,$N="") { global $SUPPORTED_LANGS; $error = ''; @@ -344,6 +346,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K)); $q.= ", InactivityTS = " . $inactivity_ts; $q.= ", CommentNotify = " . ($CN ? "1" : "0"); + $q.= ", UpdateNotify = " . ($UN ? "1" : "0"); $q.= " WHERE ID = ".intval($UID); $result = $dbh->exec($q); diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 4f92f693..b9affd64 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -139,6 +139,10 @@ />

    +

    + + /> +

    From dc41a5afa5dbbfbca4a711b9059c4b7dc8cbeb72 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 8 Feb 2016 07:39:57 +0100 Subject: [PATCH 0161/1891] git-serve: Change syntax for setting keywords Instead of `config keywords ...`, the new syntax is `set-keywords ...`. The `config` keyword was rather general and it was not obvious that it could be used to change package base settings. Instead of replacing it with an even more verbose expression, remove that unnecessary level of indirection. Since we do not (and probably never will) support keywords anywhere else, the chance of name conflicts is small. Suggested-by: Dave Reisner Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index ff389d26..35c6b3a8 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -88,7 +88,7 @@ def create_pkgbase(pkgbase, user): db.close() -def pkgbase_config_keywords(pkgbase, keywords): +def pkgbase_set_keywords(pkgbase, keywords): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: die('{:s}: package base not found: {:s}'.format(action, pkgbase)) @@ -173,17 +173,10 @@ if action == 'git-upload-pack' or action == 'git-receive-pack': os.environ["GIT_NAMESPACE"] = pkgbase cmd = action + " '" + repo_path + "'" os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd) -elif action == 'config': +elif action == 'set-keywords': if len(cmdargv) < 2: die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) < 3: - die_with_help("{:s}: missing option name".format(action)) - pkgbase = cmdargv[1] - option = cmdargv[2] - - if option == 'keywords': - pkgbase_config_keywords(pkgbase, cmdargv[3:]) - + pkgbase_set_keywords(cmdargv[1], cmdargv[2:]) elif action == 'list-repos': if len(cmdargv) > 1: die_with_help("{:s}: too many arguments".format(action)) @@ -213,12 +206,12 @@ elif action == 'restore': os.execl(git_update_cmd, git_update_cmd, 'restore') elif action == 'help': die("Commands:\n" + - " config ... Change package base settings.\n" + - " help Show this help message and exit.\n" + - " list-repos List all your repositories.\n" + - " restore Restore a deleted package base.\n" + - " setup-repo Create an empty repository.\n" + - " git-receive-pack Internal command used with Git.\n" + - " git-upload-pack Internal command used with Git.") + " help Show this help message and exit.\n" + + " list-repos List all your repositories.\n" + + " restore Restore a deleted package base.\n" + + " set-keywords [...] Change package base keywords.\n" + + " setup-repo Create an empty repository.\n" + + " git-receive-pack Internal command used with Git.\n" + + " git-upload-pack Internal command used with Git.") else: die_with_help("invalid command: {:s}".format(action)) From 9d7d1be731eea243587a046774a650576521bcbb Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 9 Feb 2016 21:49:57 +0100 Subject: [PATCH 0162/1891] aurjson: Add package base keywords Expose package base keywords through the RPC interface (version 5). Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 51a7c64d..7f9b5f2e 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -175,10 +175,11 @@ class AurJSON { * Get extended package details (for info and multiinfo queries). * * @param $pkgid The ID of the package to retrieve details for. + * @param $base_id The ID of the package base to retrieve details for. * * @return array An array containing package details. */ - private function get_extended_fields($pkgid) { + private function get_extended_fields($pkgid, $base_id) { $query = "SELECT DependencyTypes.Name AS Type, " . "PackageDepends.DepName AS Name, " . "PackageDepends.DepCondition AS Cond " . @@ -224,6 +225,19 @@ class AurJSON { $data[$type][] = $row['Name'] . $row['Cond']; } + if ($this->version >= 5) { + $query = "SELECT Keyword FROM PackageKeywords " . + "WHERE PackageBaseID = " . intval($base_id) . " " . + "ORDER BY Keyword ASC"; + $result = $this->dbh->query($query); + + if (!$result) { + return null; + } + + $data['Keywords'] = $result->fetchAll(PDO::FETCH_COLUMN, 0); + } + return $data; } @@ -300,7 +314,7 @@ class AurJSON { } if ($this->version >= 2 && ($type == 'info' || $type == 'multiinfo')) { - $row = array_merge($row, $this->get_extended_fields($row['ID'])); + $row = array_merge($row, $this->get_extended_fields($row['ID'], $row['PackageBaseID'])); } if ($this->version < 3) { From cd1756a4ed94b34b88f4f347328432f7b3060cd8 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 9 Feb 2016 21:58:48 +0100 Subject: [PATCH 0163/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index 27622386..0ff0bb7b 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: AUR v4.1.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-01-28 23:03+0100\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1168,6 +1168,18 @@ msgstr "" msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php +msgid "Notification settings" +msgstr "" + +#: template/account_edit_form.php template/pkgbase_actions.php +msgid "Notify of new comments" +msgstr "" + +#: template/account_edit_form.php +msgid "Notify of package updates" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1300,10 +1312,6 @@ msgstr "" msgid "Disable notifications" msgstr "" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "" - #: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" From bf1b269483430f1f27b239fc6ee4c3c9b0421d9d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 11 Feb 2016 19:16:20 +0100 Subject: [PATCH 0164/1891] Add an example post-checkout hook Add a shell script to rebuild the documentation and install translations. Can be executed manually or used as a post-checkout hook in Git. Signed-off-by: Lukas Fleischer --- upgrading/post-checkout | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 upgrading/post-checkout diff --git a/upgrading/post-checkout b/upgrading/post-checkout new file mode 100755 index 00000000..7ad41cfd --- /dev/null +++ b/upgrading/post-checkout @@ -0,0 +1,4 @@ +#!/bin/sh + +( cd doc/ && make ) +( cd po/ && make && make install ) From e2632ea6c905f92ab62242abe594845c890878e0 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 15 Feb 2016 08:11:32 +0100 Subject: [PATCH 0165/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 707 ++++++++---------------------- po/ast.po | 701 ++++++++---------------------- po/ca.po | 677 +++++++---------------------- po/cs.po | 658 ++++++---------------------- po/da.po | 628 ++++++--------------------- po/de.po | 972 +++++++++++++++--------------------------- po/el.po | 689 ++++++++---------------------- po/es.po | 989 +++++++++++++++--------------------------- po/es_419.po | 982 +++++++++++++++--------------------------- po/fi.po | 799 ++++++++++------------------------ po/fr.po | 1155 +++++++++++++++++++------------------------------- po/he.po | 624 +++++---------------------- po/hr.po | 627 ++++++--------------------- po/hu.po | 913 +++++++++++++-------------------------- po/it.po | 995 +++++++++++++++---------------------------- po/ja.po | 959 ++++++++++++++--------------------------- po/nb.po | 739 +++++++++----------------------- po/nl.po | 916 +++++++++++++-------------------------- po/pl.po | 711 ++++++++----------------------- po/pt_BR.po | 958 ++++++++++++++--------------------------- po/pt_PT.po | 725 +++++++++---------------------- po/ro.po | 701 ++++++++---------------------- po/ru.po | 941 ++++++++++++++-------------------------- po/sk.po | 921 +++++++++++++--------------------------- po/sr.po | 909 +++++++++++++-------------------------- po/tr.po | 909 +++++++++++++-------------------------- po/uk.po | 942 ++++++++++++++-------------------------- po/zh_CN.po | 651 ++++++---------------------- po/zh_TW.po | 706 ++++++++---------------------- 29 files changed, 7004 insertions(+), 16800 deletions(-) diff --git a/po/ar.po b/po/ar.po index 1c7d53cd..931d2e10 100644 --- a/po/ar.po +++ b/po/ar.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # safa1996alfulaij , 2015 # صفا الفليج , 2015 @@ -9,1268 +9,1038 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 07:10+0000\n" -"Last-Translator: صفا الفليج \n" -"Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/ar/)\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" +"ar/)\n" +"Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ar\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" -#: html/404.php msgid "Page Not Found" msgstr "لم يُعثر على الصّفحة" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "آسفون، الصّفحة التي طلبتها غير موجودة." -#: html/503.php msgid "Service Unavailable" msgstr "الخدمة غير متوفّرة" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "لا تفزع! عُطّل الموقع لأعمال الصّيانة. سنعود قريبًا." -#: html/account.php msgid "Account" msgstr "حساب" -#: html/account.php template/header.php msgid "Accounts" msgstr "الحسابات" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "ليس مسموحًا لك بالنّفاذ إلى هنا." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "تعذّر جلب معلومات المستخدم المحدّد." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "لا صلاحيّات لديك لتحرير هذا الحساب." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "استخدم هذه الاستمارة للبحث عن حسابات موجودة." -#: html/account.php msgid "You must log in to view user information." msgstr "عليك الولوج لعرض معلومات المستخدمين." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "أضف رأيًا" -#: html/addvote.php msgid "Invalid token for user action." msgstr "" -#: html/addvote.php msgid "Username does not exist." msgstr "اسم المستخدم غير موجود." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "" -#: html/addvote.php msgid "Invalid type." msgstr "النّوع غير صالح." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "لا يمكن أن يكون الرّأي فارغًا." -#: html/addvote.php msgid "New proposal submitted." msgstr "قُدّم رأي جديد." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "قدّم رأيًا للتّصويت عليه." -#: html/addvote.php msgid "Applicant/TU" msgstr "" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(فارغ إن لم ينطبق)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "النّوع" -#: html/addvote.php msgid "Addition of a TU" msgstr "إضافة م‌م" -#: html/addvote.php msgid "Removal of a TU" msgstr "إزالة م‌م" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "الرّأي" -#: html/addvote.php msgid "Submit" msgstr "قدّم" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "أدر المصينين المشاركين" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "حرّر التّعليق" -#: html/home.php template/header.php msgid "Home" msgstr "الرّئيسيّة" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ الموثوقين (م‌م)%s لمعلومات أكثر." +msgstr "" +"مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ " +"الموثوقين (م‌م)%s لمعلومات أكثر." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "ملفّات PKGBUILD التي تساهم بها %sيجب%s أن تتّبع %sمعايير التّحزيم في آرتش%s وإلا فستُحذف!" +msgstr "" +"ملفّات PKGBUILD التي تساهم بها %sيجب%s أن تتّبع %sمعايير التّحزيم في آرتش%s " +"وإلا فستُحذف!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "تذكّر أن تصوّت لحزمك المفضّلة!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "قد تكون بعض الحزم متوفّرة كثنائيّات في مستودع المجتمع [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "إخلاء مسؤوليّة" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "اطّلع على المزيد..." -#: html/home.php msgid "Support" msgstr "الدّعم" -#: html/home.php msgid "Package Requests" msgstr "طلبات الحزم" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة تفاصيل الحزمة:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة " +"تفاصيل الحزمة:" -#: html/home.php msgid "Orphan Request" msgstr "طلب \"يتيمة\"" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة كقديمة لوقت طويل." +msgstr "" +"اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة " +"كقديمة لوقت طويل." -#: html/home.php msgid "Deletion Request" msgstr "طلب الحذف" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن طلب \"يتيمة\" إن تطلّب الأمر." +msgstr "" +"اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت " +"الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن " +"طلب \"يتيمة\" إن تطلّب الأمر." -#: html/home.php msgid "Merge Request" msgstr "طلب الدّمج" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "اطلب دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو استبدال بحزمة تقسيميّة." +msgstr "" +"اطلب دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو " +"استبدال بحزمة تقسيميّة." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." +msgstr "" +"إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. " +"لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." -#: html/home.php msgid "Submitting Packages" msgstr "تقديم الحزم" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." +msgstr "" +"غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع " +"قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "بصمات SSH الآتية مستخدمة في م‌م‌آ:" -#: html/home.php msgid "Discussion" msgstr "النّقاش" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِب م‌م‌آ، استخدم قائمة %saur-dev%s البريديّة." +msgstr "" +"النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين " +"تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِب م‌م‌آ، استخدم " +"قائمة %saur-dev%s البريديّة." -#: html/home.php msgid "Bug Reporting" msgstr "الإبلاغ عن العلل" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "ابحث عن حزمة" -#: html/index.php msgid "Adopt" msgstr "تبنّ" -#: html/index.php msgid "Vote" msgstr "صوّت" -#: html/index.php msgid "UnVote" msgstr "أزل التّصويت" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "الإخطار" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "أزل الإخطار" -#: html/index.php msgid "UnFlag" msgstr "أزل التّعليم" -#: html/login.php template/header.php msgid "Login" msgstr "لِج" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "والج كَـ: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "اخرج" -#: html/login.php msgid "Enter login credentials" msgstr "أدخل بيانات الولوج" -#: html/login.php msgid "User name or email address" msgstr "اسم المستخدم أو عنوان البريد الإلكترونيّ" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "كلمة المرور" -#: html/login.php msgid "Remember me" msgstr "تذكّرني" -#: html/login.php msgid "Forgot Password" msgstr "نسيت كلمة المرور" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "ولوج HTTP معطّل. فضلًا %sبدّل إلى HTTPs%s إن أردت الولوج." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "معايير البحث" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "الحزم" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "خطأ في محاولة جلب تفاصيل الحزمة." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "أحد الحقول المطلوبة ناقصة." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "حقلا كلمة المرور لا يتطابقان." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "يجب أن تكون كلمة مرورك بطول %s محارف على الأقل." -#: html/passreset.php msgid "Invalid e-mail." msgstr "بريد إلكترونيّ غير صالح." -#: html/passreset.php msgid "Password Reset" msgstr "صفّر كلمة المرور" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "افحص بريدك الإلكترونيّ لوصلة التّأكيد." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "صُفّرت كلمة مرورك بنجاح." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "أكّد عنوان بريدك الإلكترونيّ:" -#: html/passreset.php msgid "Enter your new password:" msgstr "أدخل كلمة مرورك الجديدة:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "أكّد كلمة مرورك الجديدة:" -#: html/passreset.php msgid "Continue" msgstr "تابع" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى قائمة %saur-general%s البريديّة." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى " +"قائمة %saur-general%s البريديّة." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "أدخل عنوان بريدك الإلكترونيّ:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "لم يُتنازل عن الحزم المحدّدة، افحص مربع تأشير التّأكيد." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "تعذّر العثور على الحزمة لدمج التّصويتات والتّعليقات معها." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "لا يمكن الدّمج بلا أساس الحزمة نفسه." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "لم تُحذف الحزم المحدّدة، افحص مربع تأشير التّأكيد." -#: html/pkgdel.php msgid "Package Deletion" msgstr "احذف حزمة" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "احذف الحزمة: %s" +msgid "Delete Package" +msgstr "احذف الحزمة" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "استخدم هذه الاستمارة لحذف أساس الحزمة %s%s%s والحزم الآتية من م‌م‌آ:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "حذف الحزم نهائيّ." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "حدّد مربع تأشير لتأكيد الإجراء." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "أكّد حذف الحزمة" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "احذف" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين حذف الحزم." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "تنازل عن حزمة" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "تنازل عن الحزمة: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة ونقل ملكيّتها إلى %s%s%s." +msgstr "" +"بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة ونقل ملكيّتها إلى %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "أكّد التّنازل عن الحزمة" -#: html/pkgdisown.php msgid "Disown" msgstr "تنازل" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين التّنازل عن الحزم." -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "علّم الحزمة كقديمة" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "من فضلك %sلا%s تستخدم هذه الاستمارة للتّبليع عن العلل. علّق على الحزم بدل ذلك." +msgstr "" +"من فضلك %sلا%s تستخدم هذه الاستمارة للتّبليع عن العلل. علّق على الحزم بدل ذلك." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "التّعليقات" -#: html/pkgflag.php msgid "Flag" msgstr "علّم" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "ادمج حزمة" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "ادمج الحزمة: %s" +msgid "Merge Package" +msgstr "ادمج الحزم" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "استخدم هذه الاستمارة لدمج أساس الحزمة %s%s%s مع حزمة أخرى." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "ستُحذف الحزم الآتية:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "بمجرّد دمج الحزمة لا يمكن عكس الإجراء." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "أدخل اسم الحزمة التي ترغب بدمج الحزمة معها." -#: html/pkgmerge.php msgid "Merge into:" msgstr "ادمج مع:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "أكّد دمج الحزم" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "دمج" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين دمج الحزم." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "افتح طلبًا" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "أغلق الطّلب" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "الأولى" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "السّابقة" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "التّالية" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "الأخيرة" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "الطّلبات" -#: html/register.php template/header.php msgid "Register" msgstr "سجّل" -#: html/register.php msgid "Use this form to create an account." msgstr "استخدم هذه الاستمارة لإنشاء حساب." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "مستخدم موثوق" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "تعذّر استرجاع تفاصيل الرّأي." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "أُغلق التّصويت على هذا الرّأي." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "فقط المستخدمين الموثوقين مسموح لهم بالتّصويت." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "لا يمكنك التّصويت على رأي عنك." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "لقد صوّتّ على هذا الرّأي بالفعل." -#: html/tu.php msgid "Vote ID not valid." msgstr "معرّف التّصويت غير صالح." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "التّصويتات الحاليّة" -#: html/tu.php msgid "Past Votes" msgstr "التّصويتات الماضية" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "المصوّتون" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك" +msgstr "" +"تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " +"المتكرّرة. آسفون لإزاعجك" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "معرّف المستخدم ناقص" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "اسم المستخدم غير صالح." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "يجب أن يكون بطول بين %s و %s محرفًا" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "يجب أن يبدأ وينتهي بحرف أو رقم." -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "يمكنه احتواء نقطة واحدة، أو شرطة سفليّة واحدة أو شرطة واحدة." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "عنوان البريد الإلكترونيّ غير صالح." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "بصمة مفتاح PGP غير صالحة." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "مفتاح SSH العموميّ غير صالح." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "لا يمكن زيادة صلاحيّات الحساب." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "اللغة غير مدعومة حاليًّا." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "اسم المستخدم %s%s%s مستخدم بالفعل." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "العنوان %s%s%s مستخدم بالفعل." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "مفتاح SSH العموميّ %s%s%s مستخدم بالفعل." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "فشلت محاولة إنشاء الحساب %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "أُنشئ الحساب %s%s%s بنجاح." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "مفتاح تصفير كلمة المرور أُرسل إلى عنوان بريدك الإلكترونيّ." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "انقر وصلة الولوج أعلاه لاستخدام حسابك." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "لم تتمّ أيّ تغييرات على الحساب %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "عُدّل الحساب %s%s%s بنجاح." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك." +msgstr "" +"استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " +"المتكرّرة. آسفون لإزاعجك." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "عُلّق الحساب" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من صفحة %sصفّر كلمة المرور%s." +msgstr "" +"لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد " +"الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من " +"صفحة %sصفّر كلمة المرور%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "اسم مستخدم أو كلمة مرور سيئّة." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "حدث خطأ أثناء توليد جلسة مستخدم." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "البريد الإلكترونيّ وتجميعة مفاتيح التّصفير غير صالحة." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "بلا" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "اعرض معلومات حساب %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "التّعليق غير موجود." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "أُضيف التّعليق" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "عليك الولوج قبل تحرير معلومات الحزم." + +msgid "Missing comment ID." +msgstr "معرّف التّعليق ناقص." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "خطأ في استرجاع تفاصيل الحزمة." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "تعذّر العثور على تفاصيل الحزمة." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "عليك الولوج قبل تعليم الحزم." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "لم تحدّد أيّ حزم لتعليمها." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "عُلّمت الحزم المحدّدة كقديمة." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "عليك الولوج قبل إزالة تعليم الحزم." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "لم تحدّد أيّ حزم لإزالة تعليمها." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "أزثيل تعليم الحزم المحدّدة." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "لا صلاحيّة لديك لحذف الحزم." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "لم تحدّد أيّ حزم لحذفها." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "حُذفت الحزم المحدّدة." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "عليك الولوج قبل تبنّي الحزم." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "عليك الولوج قبل التّنازل عن الحزم." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "لم تحدّد أيّ حزم لتبنّيها." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "لم تحدّد أيّ حزم للتّنازل عنها." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "تُبنّيت الحزم المحدّدة." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "تُنوزل عن الحزم المحدّدة." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "عليك الولوج قبل التّصويت للحزم." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "عليك الولوج قبل إزالة التصّويت للحزم." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "لم تحدّد أيّ حزم للتّصويت لها." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "أُزيلت تصويتاتك من الحزم المحدّدة." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "أُدليت تصويتاتك على الحزم المحدّدة." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "تعذّرت الإضافة إلى قائمة الإخطارات." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "أُضفت إلى قائمة إخطار التّعليقات لِـ %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "أُزلت من قائمة إخطار التّعليقات لِـ %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "عليك الولوج قبل تحرير معلومات الحزم." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "معرّف التّعليق ناقص." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "حُذف التّعليق." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "ليس مسموحًا لك بحذف هذا التّعليق." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "حُذف التّعليق." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "ليس مسموحًا لك بتحرير كلمات أساس الحزمة المفتاحيّة." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "حُدّثت كلمات أساس الحزمة المفتاحيّة." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "ليس مسموحًا لك بإدارة مصيني أساس الحزمة هذا المشاركين." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "اسم مستخدم غير صالح: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "حُدّث مصيني أساس الحزمة المشاركين." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "اعرض تفاصيل حزمة" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "تطلب %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "عليك الولوج لفتح طلبات حزم." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "اسم غير صالح: فقط الأحرف بالحالة الصغيرة مسموح بها." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "يجب ألّا يكون حقل التّعليق فارغًا." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "نوع الطّلب غير صالح." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "أُضيف الطّلب بنجاح." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "سبب غير صالح." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين إغلاق الطّلبات." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "ُأُغلق الطّلب بنجاح." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "يمكنك استخدام هذه الاستمارة لحذف حساب م‌م‌آ هذا %s نهائيًّا." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sتحذير%s: هذا إجراء لا عودة فيه." -#: template/account_delete.php msgid "Confirm deletion" msgstr "أكّد الحذف" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "اسم المستخدم" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "نوع الحساب" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "مستخدم" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "مطوّر" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "مستخدم موثوق ومطوّر" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "البريد الإلكترونيّ" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "الاسم الحقيقيّ" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "اسم آي‌آر‌سي المستعار" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "بصمة مفتاح PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "الحالة" -#: template/account_details.php msgid "Inactive since" msgstr "غير نشط منذ" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "نشط" -#: template/account_details.php msgid "Last Login" msgstr "آخر ولوج" -#: template/account_details.php msgid "Never" msgstr "أبدًا" -#: template/account_details.php msgid "View this user's packages" msgstr "اعرض ملفّ هذا المستخدم الشخصيّ" -#: template/account_details.php msgid "Edit this user's account" msgstr "حرّر حساب هذا المستخدم" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "انقر %sهنا%s إن أردت حذف هذا الحساب نهائيًّا." -#: template/account_edit_form.php msgid "required" msgstr "مطلوب" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "مستخدم عاديّ" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "مستخدم موثوق" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "حساب معلّق" -#: template/account_edit_form.php msgid "Inactive" msgstr "غير نشط" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "أخفِ عنوان البريد الإلكترونيّ" -#: template/account_edit_form.php msgid "Re-type password" msgstr "أعد كتابة كلمة المرور" -#: template/account_edit_form.php msgid "Language" msgstr "اللغة" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "المعلومات الآتية مطلوبة فقط إن أردت تقديم حزم إلى مستودع مستخدمي آرتش." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "مفتاح SSH العموميّ" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "أخطرني بالتّعليقات الجديدة" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "حدّث" -#: template/account_edit_form.php msgid "Create" msgstr "أنشئ" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "صفّر" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "لا نتائج طابقت معايير بحثك." -#: template/account_search_results.php msgid "Edit Account" msgstr "حرّر الحساب" -#: template/account_search_results.php msgid "Suspended" msgstr "معلّق" -#: template/account_search_results.php msgid "Edit" msgstr "حرّر" -#: template/account_search_results.php msgid "Less" msgstr "أقلّ" -#: template/account_search_results.php msgid "More" msgstr "أكثر" -#: template/account_search_results.php msgid "No more results to display." msgstr "لا نتائج أخرى لعرضها." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "أدر المصينين المشاركين: %s" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "استخدم هذه الاستمارة لإضافة مصينين مشاركين لِـ %s%s%s (اسم في كلّ سطر):" -#: template/comaintainers_form.php msgid "Users" msgstr "المستخدمون" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "احفظ" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "حزمي" -#: template/header.php msgid " My Account" msgstr "حسابي" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "إجراءات الحزمة" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "اعرض PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "اعرض التّغييرات" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "نزّل لقطة شاشة" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "ابحث في الويكي" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "معلّمة كقديمة" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "علّم الحزمة كقديمة" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "أزل تعليم الحزمة" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "أزل التّصويت" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "صوّت لهذه الحزمة" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "عطّل الإخطارات" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "أخطرني بالتّعليقات الجديدة" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "أدر المصينين المشاركين" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1281,232 +1051,180 @@ msgstr[3] "%d طلبات منتظرة" msgstr[4] "%d طلبًا منتظرًا" msgstr[5] "%d طلب منتظر" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "احذف الحزمة" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "ادمج الحزم" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "تبنّ الحزمة" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "مجهول" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "تفاصيل أساس الحزمة" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "عنوان غِت للاستنساخ" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "للقراءة فقط" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "الكلمات المفتاحيّة" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "المقدّم" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "المصين" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "آخر محزّم" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "التّصويتات" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "الشّعبيّة" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "أول تقديم" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "آخر تحديث" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "أضف تعليقًا" -#: template/pkg_comments.php msgid "View all comments" msgstr "اعرض كلّ التّعليقات" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "آخر التّعليقات" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "علّق %s على %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "تعليق مجهول على %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "احذف التّعليق" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "كلّ التّعليقات" -#: template/pkg_details.php msgid "Package Details" msgstr "تفاصيل الحزمة" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "أساس الحزمة" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "الوصف" -#: template/pkg_details.php msgid "Upstream URL" msgstr "عنوان المنبع" -#: template/pkg_details.php msgid "Visit the website for" msgstr "زُر موقع وِب" -#: template/pkg_details.php msgid "Licenses" msgstr "الرّخص" -#: template/pkg_details.php msgid "Groups" msgstr "المجموعات" -#: template/pkg_details.php msgid "Conflicts" msgstr "تتعارض مع" -#: template/pkg_details.php msgid "Provides" msgstr "توفّر" -#: template/pkg_details.php msgid "Replaces" msgstr "تستبدل" -#: template/pkg_details.php msgid "Dependencies" msgstr "الاعتماديّات" -#: template/pkg_details.php msgid "Required by" msgstr "تطلبها" -#: template/pkg_details.php msgid "Sources" msgstr "المصادر" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "أغلق الطّلب: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "استخدم هذه الاستمارة لإغلاق طلب أساس الحزمة %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "ملاحظة" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." +msgstr "" +"يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "السّبب" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "مقبول" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "مرفوض" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "افتح طلبًا: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "استخدم هذه الاستمارة لفتح طلب لأساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +msgstr "" +"استخدم هذه الاستمارة لفتح طلب لأساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" -#: template/pkgreq_form.php msgid "Request type" msgstr "نوع الطّلب" -#: template/pkgreq_form.php msgid "Deletion" msgstr "حذف" -#: template/pkgreq_form.php msgid "Orphan" msgstr "يتيمة" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "ادمج مع" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1517,29 +1235,23 @@ msgstr[3] "عُثر على %d طلبات حزم." msgstr[4] "عُثر على %d طلب حزمة." msgstr[5] "عُثر على %d طلب حزمة." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "الصّفحة %d من %d." -#: template/pkgreq_results.php msgid "Package" msgstr "الحزم" -#: template/pkgreq_results.php msgid "Filed by" msgstr "فتحه:" -#: template/pkgreq_results.php msgid "Date" msgstr "التّاريخ" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1550,116 +1262,87 @@ msgstr[3] "بقي حوالي %d ساعات" msgstr[4] "بقي حوالي %d ساعةً" msgstr[5] "بقي حوالي %d ساعة" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "بقيت أقلّ من ساعة" -#: template/pkgreq_results.php msgid "Accept" msgstr "اقبل" -#: template/pkgreq_results.php msgid "Locked" msgstr "" -#: template/pkgreq_results.php msgid "Close" msgstr "أغلق" -#: template/pkgreq_results.php msgid "Closed" msgstr "مغلق" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "الاسم، الوصف" -#: template/pkg_search_form.php msgid "Name Only" msgstr "الاسم فقط" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "الاسم بالضّبط" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "أساس الحزمة بالضّبط" -#: template/pkg_search_form.php msgid "All" msgstr "الكلّ" -#: template/pkg_search_form.php msgid "Flagged" msgstr "المعلّمة" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "غير المعلّمة" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "الاسم" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "مصوّت عليها" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "تصاعديًّا" -#: template/pkg_search_form.php msgid "Descending" msgstr "تنازليًّا" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "أدخل معايير البحث" -#: template/pkg_search_form.php msgid "Search by" msgstr "ابحث حسب" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "القديمة" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "افرز حسب" -#: template/pkg_search_form.php msgid "Sort order" msgstr "ترتيب الفرز" -#: template/pkg_search_form.php msgid "Per page" msgstr "لكلّ صفحة" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "انطلق" -#: template/pkg_search_form.php msgid "Orphans" msgstr "اليتيمة" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "خطأ في استرجاع قائمة الحزم." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "لا حزم طابقت معايير بحثك." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1670,154 +1353,116 @@ msgstr[3] "عُثر على %d حزم." msgstr[4] "عُثر على %d حزمةً." msgstr[5] "عُثر على %d حزمة." -#: template/pkg_search_results.php msgid "Version" msgstr "الإصدارة" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "نعم" -#: template/pkg_search_results.php msgid "orphan" msgstr "يتيمة" -#: template/pkg_search_results.php msgid "Actions" msgstr "الإجراءات" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "علّم كقديمة" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "أزل التّعليم كقديمة" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "تبنّ الحزم" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "تنازل عن الحزم" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "احذف الحزم" -#: template/pkg_search_results.php msgid "Confirm" msgstr "أكّد" -#: template/search_accounts_form.php msgid "Any type" msgstr "أيّ نوع" -#: template/search_accounts_form.php msgid "Search" msgstr "ابحث" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "الإحصائيّات" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "الحزم اليتيمة" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "الحزم المضافة في السّبعة أيّام الماضية" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "الحزم المحدّثة في السّبعة أيّام الماضية" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "الحزم المضافة في السّنة الماضية" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "الحزم التي لم تحدّث مطلقًا" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "المستخدمون المسجّلون" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "المستخدمون الموثوقون" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "التّحديثات الأخيرة" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "إحصائيّاتي" -#: template/tu_details.php msgid "Proposal Details" msgstr "تفاصيل الرّأي" -#: template/tu_details.php msgid "This vote is still running." msgstr "ما زال هذا التّصويت قائمًا." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "قدّمه (في %s) ‏%s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "النّهاية" -#: template/tu_details.php msgid "Result" msgstr "النّتيجة" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "لا" -#: template/tu_details.php msgid "Abstain" msgstr "الامتناع" -#: template/tu_details.php msgid "Total" msgstr "المجموع" -#: template/tu_details.php msgid "Participation" msgstr "المشاركة" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "آخر التّصويتات لِـ م‌م" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "آخر تصويت" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "لم يُعثر على أيّ نتيجة." -#: template/tu_list.php msgid "Start" msgstr "البداية" -#: template/tu_list.php msgid "Back" msgstr "السّابق" diff --git a/po/ast.po b/po/ast.po index 85ed7864..8203718f 100644 --- a/po/ast.po +++ b/po/ast.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # enolp , 2014-2015 # Ḷḷumex03 , 2014 @@ -10,1799 +10,1430 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/ast/)\n" +"Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" +"ast/)\n" +"Language: ast\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ast\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Nun s'alcontró la páxina" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Perdón, la páxina que pidisti nun esiste." -#: html/503.php msgid "Service Unavailable" msgstr "Serviciu non disponible" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "¡Asela! Esti sitiu ta cayíu debío a caltenimientu. Volverémos ceo." -#: html/account.php msgid "Account" msgstr "Cuenta" -#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentes" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nun tienes permisu p'acceder a esta area." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nun pudo recibise la información pal usuariu especificáu." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nun tienes permisu pa editar esta cuenta." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa esti formulariu pa guetar cuentes esistentes." -#: html/account.php msgid "You must log in to view user information." msgstr "Tienes d'aniciar sesión pa ver la información del usuariu." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Amestar propuesta" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Token non válidu pa la aición del usuariu" -#: html/addvote.php msgid "Username does not exist." msgstr "El nome d'usuariu nun esiste." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s yá tien la propuesta que cuerre pa ellos." -#: html/addvote.php msgid "Invalid type." msgstr "Triba non válida." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta nun pue tar balera" -#: html/addvote.php msgid "New proposal submitted." msgstr "" -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "" -#: html/addvote.php msgid "Applicant/TU" msgstr "Aplicante/Usuariu d'Enfotu." -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(baletu si nun s'aplica)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Triba" -#: html/addvote.php msgid "Addition of a TU" msgstr "Añedir un Usuariu d'Enfotu" -#: html/addvote.php msgid "Removal of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" -#: html/addvote.php msgid "Submit" -msgstr "" +msgstr "Unviar" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Aniciu" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "¡Bienllegáu al AUR! Llei la %sGuía d'usuariu del AUR%s y la %sGuía d'usuariu TU del AUR%s pa más información." +msgstr "" +"¡Bienllegáu al AUR! Llei la %sGuía d'usuariu del AUR%s y la %sGuía d'usuariu " +"TU del AUR%s pa más información." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Los PKGBUILD contribuyíos %stienen%s de ser compatibles col %sEstándar de empaquetado de Arch%s d'otra forma van ser esaniciaos." +msgstr "" +"Los PKGBUILD contribuyíos %stienen%s de ser compatibles col %sEstándar de " +"empaquetado de Arch%s d'otra forma van ser esaniciaos." -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerda votar los tos paquetes favoritos!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Dellos paquetes puen apurrise como binarios en [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Los paquetes d'AUR son conteníu producíu polos usuarios. Cualesquier usu de " +"los ficheros forníos ta sol to propiu riesgu." -#: html/home.php msgid "Learn more..." msgstr "Llei más..." -#: html/home.php msgid "Support" msgstr "Sofitu" -#: html/home.php msgid "Package Requests" msgstr "Solicitúes de paquetes" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "Solicitú güérfana" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "Solicitú de desaniciu" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "Solicitú de desanciu" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "Unviu de paquetes" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Agora úsase GIT sobro SSH pa unviar paquetes a AUR. Mira la estaya %sUnviu de paquetes%s de la páxina ArchWiki del AUR pa más detalles." +msgstr "" +"Agora úsase GIT sobro SSH pa unviar paquetes a AUR. Mira la estaya %sUnviu " +"de paquetes%s de la páxina ArchWiki del AUR pa más detalles." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Les buelgues SSH de darréu úsense pal AUR:" -#: html/home.php msgid "Discussion" msgstr "Discutiniu" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Informe de fallos" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" -msgstr "Gueta de paquete" +msgstr "Gueta de paquetes" -#: html/index.php msgid "Adopt" msgstr "" -#: html/index.php msgid "Vote" msgstr "" -#: html/index.php msgid "UnVote" msgstr "" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "" -#: html/index.php msgid "UnFlag" msgstr "" -#: html/login.php template/header.php msgid "Login" msgstr "Aniciar sesión" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "" -#: html/login.php template/header.php msgid "Logout" msgstr "Zarrar sesión" -#: html/login.php msgid "Enter login credentials" -msgstr "Introduz les tos credenciales d'aniuciu sesión" +msgstr "Introduz les tos credenciales d'aniciu sesión" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Nome d'usuariu o direición de corréu" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" -#: html/login.php msgid "Remember me" msgstr "Recordáime" -#: html/login.php msgid "Forgot Password" msgstr "Escaecí la contraseña" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteriu de gueta" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" -#: html/packages.php msgid "Error trying to retrieve package details." -msgstr "" +msgstr "Fallu intentando recibir los detalles del paquete." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campu riquíu." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Nun concasen los campos de contraseñes" -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La to contraseña tien de tener polo menos %s carauteres." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Corréu electrónicu non válidu" -#: html/passreset.php msgid "Password Reset" msgstr "Reaniciu de contraseña" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Comprueba'l to corréu pal enllaz de confirmación." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La to contraseña reanicióse con ésitu." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirma'l to corréu:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Introduz la to contraseña nueva:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirma la to contraseña nueva:" -#: html/passreset.php msgid "Continue" msgstr "Siguir" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si escaecisti la dirección de corréu electrónicu utilizasti pa rexistrar, complacer unviar un mensaxe a la llista de orréu %saur-xeneral%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Si escaecisti la dirección de corréu electrónicu utilizasti pa rexistrar, " +"complacer unviar un mensaxe a la llista de orréu %saur-xeneral%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduz la to direción de corréu:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "" -#: html/pkgdel.php msgid "Package Deletion" msgstr "Desaniciu de paquete" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Desaniciar paquete: %s" +msgid "Delete Package" +msgstr "" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Usa esti formulariu pa desaniciar el paquete base %s%s%s y los paquetes siguientes d'AUR:" +msgstr "" +"Usa esti formulariu pa desaniciar el paquete base %s%s%s y los paquetes " +"siguientes d'AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El desaniciu d'un paquete ye permanente." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" -#: html/pkgdel.php msgid "Confirm package deletion" -msgstr "" +msgstr "Confirmar desaniciu de paquete" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Desaniciar" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"%sNun%s uses esti formulariu pa informar de fallos, por favor. Usa nel so " +"llugar los comentarios del paquete." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Comentarios" -#: html/pkgflag.php msgid "Flag" msgstr "" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" +msgid "Merge Package" msgstr "" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Desaniciaránse los paquetes de darréu:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduz el nome del paquete al que deseyes amestar" -#: html/pkgmerge.php msgid "Merge into:" msgstr "" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Solicitú de ficheru" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zarar solicitú" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" -msgstr "" +msgstr "Siguiente" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Solicitúes" -#: html/register.php template/header.php msgid "Register" msgstr "Rexistrase" -#: html/register.php msgid "Use this form to create an account." msgstr "Usa esti formulariu pa crear una cuenta." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "" -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "" -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "" -#: html/tu.php msgid "You've already voted for this proposal." msgstr "" -#: html/tu.php msgid "Vote ID not valid." msgstr "Nun ye válida la ID del votu." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" -#: html/tu.php msgid "Past Votes" msgstr "Votos pasaos" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta la ID d'usuariu" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nome d'usuariu nun ye válidu" -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Tien de tar ente %s y %s carauteres de llargor" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "" -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La direición de corréu nun ye válida." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La buelga de la clave PGP nun ye válida." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave SSH pública nun ye válida." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nun puen aumentase los permisos de la cuenta." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "La llingua nun ta anguaño sofitada." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nome d'usuariu, %s%s%s, yá ta n'usu." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La direición, %s%s%s, yá ta n'usu." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La llave pública SSH, %s%s%s, ye yá n'usu." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Fallu intentando crear la cuenta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, creóse con ésitu." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "" +msgstr "Primi nel enllaz d'aniciu de sesión d'enriba pa usar la to cuenta" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." -msgstr "" +msgstr "Nun se fixeron camudancies na cuenta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, modificóse con ésitu." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." msgstr "" +"Reanicióse la to contraseña. Si tas acabantes crear una cuenta nueva, usa " +"l'enllaz del corréu de confirmación p'afitar una contraseña inicial, por " +"favor. D'otramiente, solicita una clave de reaniciu na páxina %sReaniciu de " +"contraseña%s, por favor." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nome d'usuariu o contraseña incorreutos" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Asocedió un fallu intentando xenerar una sesión d'usuariu." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Nun tienes permisu pa editar esti comentariu." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "Nun esiste'l comentariu." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "Nun pue tar baleru'l comentariu." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Amestóse'l comentariu." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php -msgid "Error retrieving package details." +msgid "You must be logged in before you can edit package information." msgstr "" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "Missing comment ID." +msgstr "Falta la ID del comentariu." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + +msgid "Error retrieving package details." +msgstr "Fallu recibiendo los detalles de paquete." + msgid "Package details could not be found." msgstr "Nun pudieron alcontrase los detalles del paquete." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "" -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nun esbillesti dengún ficheru pa desaniciar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Desaniciáronse los paquetes esbillaos." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." -msgstr "" +msgstr "Nun pudo amestase al llistáu d'avisos." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." +msgid "You are not allowed to undelete this comment." msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Falta la ID del comentariu." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "El comentariu amestóse." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nun tienes permisu pa desaniciar esti comentariu." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been edited." -msgstr "" +msgid "Comment has been deleted." +msgstr "El comentariu amestóse." + +msgid "Comment has been edited." +msgstr "Editóse'l comentariu." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nome d'usuariu non válidu: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles de paquetes pa" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campu del comentariu nun tien de tar baleru." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Triba de solicitú non válida." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Amestada con ésitu la solicitú." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón non válida." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Solicitú zarrada con ésitu." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Pues usar esti formulariu pa desaniciar la cuenta del AUR %s dafechu." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sAVISU%s: Esta aición nun pue desfacese." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar desaniciu" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nome d'usuariu" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Triba de cuenta" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuariu" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Desendolcador" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Direición de corréu" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alcuñu nel IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Buelga de clave PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Estáu" -#: template/account_details.php msgid "Inactive since" msgstr "Inactivu dende" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activu" -#: template/account_details.php msgid "Last Login" msgstr "" -#: template/account_details.php msgid "Never" msgstr "Enxamás" -#: template/account_details.php msgid "View this user's packages" msgstr "" -#: template/account_details.php msgid "Edit this user's account" msgstr "" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Primi %sequí%s si quies desaniciar esta cuenta dafechu." -#: template/account_edit_form.php msgid "required" msgstr "riquíu" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuariu normal" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuariu d'Enfotu" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivu" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Teclexa de nueves la contraseña" -#: template/account_edit_form.php msgid "Language" msgstr "Llingua" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "La información de darréu namái se rique si quies xubir paquetes al AUR." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"La información de darréu namái se rique si quies xubir paquetes al AUR." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave SSH pública" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Anovar" -#: template/account_edit_form.php msgid "Create" msgstr "Crear" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reafitar" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "" -#: template/account_search_results.php msgid "Edit Account" msgstr "Editar cuenta" -#: template/account_search_results.php msgid "Suspended" msgstr "Suspendíu" -#: template/account_search_results.php msgid "Edit" msgstr "Editar" -#: template/account_search_results.php msgid "Less" msgstr "Menos" -#: template/account_search_results.php msgid "More" msgstr "Más" -#: template/account_search_results.php msgid "No more results to display." -msgstr "" +msgstr "Nun hai más resultaos p'amosar." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Alministra comantenedores: %s" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "Usuarios" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Guardar" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Los mios paquetes" -#: template/header.php msgid " My Account" msgstr "La mio cuenta" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Aiciones de paquete" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver camudancies" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Baxar instantánea" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Guetar na wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marcar como non actualizáu" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcáu como non actualizáu" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Quitar marca de non actualizáu" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Quitar votu" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar pol paquete" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Alministra comantenedores" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "Desconocíu" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL pa clonar con Git" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Pallabres clave" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Caltenedor" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Amestar comentariu" -#: template/pkg_comments.php msgid "View all comments" msgstr "Ver tolos comentarios" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Comentarios caberos" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Desaniciar comentariu" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Tolos comentarios" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" -#: template/pkg_details.php msgid "Upstream URL" msgstr "" -#: template/pkg_details.php msgid "Visit the website for" msgstr "" -#: template/pkg_details.php msgid "Licenses" msgstr "Llicencies" -#: template/pkg_details.php msgid "Groups" msgstr "Grupos" -#: template/pkg_details.php msgid "Conflicts" msgstr "" -#: template/pkg_details.php msgid "Provides" msgstr "Apurre" -#: template/pkg_details.php msgid "Replaces" msgstr "Troca" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencies" -#: template/pkg_details.php msgid "Required by" msgstr "Riquíu por" -#: template/pkg_details.php msgid "Sources" msgstr "Fontes" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Zarrar solicitú: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa esti formulariu pa zarrar la solicitú pal paquete base %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "El campu de comentarios pue dexase baleru, Por embargu, encamiéntase amestar un comentariu al refugar una solicitú." +msgstr "" +"El campu de comentarios pue dexase baleru, Por embargu, encamiéntase amestar " +"un comentariu al refugar una solicitú." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Aceutáu" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Refugáu" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "Triba de solicitú" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Desaniciu" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Güérfanu" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Páxina %d de %d" -#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" -#: template/pkgreq_results.php msgid "Filed by" msgstr "" -#: template/pkgreq_results.php msgid "Date" msgstr "Data" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Falten ~%d díes" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Falta ~%d hora" msgstr[1] "Falten ~%d hores" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "Falta menos d'una hora" -#: template/pkgreq_results.php msgid "Accept" msgstr "Aceutar" -#: template/pkgreq_results.php msgid "Locked" msgstr "Bloquiáu" -#: template/pkgreq_results.php msgid "Close" msgstr "Zarrar" -#: template/pkgreq_results.php msgid "Closed" msgstr "Zarráu" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descripción" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Namái nome" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exautu" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exautu" -#: template/pkg_search_form.php msgid "All" msgstr "Too" -#: template/pkg_search_form.php msgid "Flagged" msgstr "" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" -#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" -#: template/pkg_search_form.php msgid "Search by" msgstr "Guetar per" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Ensin anovar" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar per" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Mou d'ordenación" -#: template/pkg_search_form.php msgid "Per page" msgstr "Per páxina" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Dir" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Güérfanos" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "" -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nun hai paquetes que concasen col criteriu de gueta." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Alcontróse %d paquete." msgstr[1] "Alcontráronse %d paquetes" -#: template/pkg_search_results.php msgid "Version" msgstr "Versión" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Sí" -#: template/pkg_search_results.php msgid "orphan" msgstr "güérfanu" -#: template/pkg_search_results.php msgid "Actions" msgstr "Aiciones" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "" -#: template/pkg_search_results.php msgid "Confirm" msgstr "" -#: template/search_accounts_form.php msgid "Any type" msgstr "" -#: template/search_accounts_form.php msgid "Search" msgstr "" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadístiques" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes güérfanos" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes amestaos nos pasaos 7 díes" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes anovaos nos pasaos 7 díes" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes anovaos nel añu caberu" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes qu'enxamás s'anovaron" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios rexistraos." -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios d'enfotu." -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Anovamientos recientes" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Les mios estadístiques" -#: template/tu_details.php msgid "Proposal Details" msgstr "" -#: template/tu_details.php msgid "This vote is still running." msgstr "" -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" -#: template/tu_details.php msgid "Result" msgstr "Resultáu" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Non" -#: template/tu_details.php msgid "Abstain" msgstr "Astención" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" -msgstr "" +msgstr "Participación" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nun s'alcontró dengún resultáu." -#: template/tu_list.php msgid "Start" msgstr "" -#: template/tu_list.php msgid "Back" msgstr "" diff --git a/po/ca.po b/po/ca.po index 5f7349c6..de3eecc6 100644 --- a/po/ca.po +++ b/po/ca.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Adolfo Jayme Barrientos, 2014 # Hector Mtz-Seara , 2011,2013 @@ -10,1799 +10,1432 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/ca/)\n" +"Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" +"ca/)\n" +"Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "No s’ha trobat la pàgina" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Ho sentim, la pàgina que ha sol·licitat no existeix." -#: html/503.php msgid "Service Unavailable" msgstr "" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" -#: html/account.php msgid "Account" msgstr "" -#: html/account.php template/header.php msgid "Accounts" msgstr "Compte" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No esteu autoritzat per a accedir a aquesta àrea." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No s'ha pogut obtenir la informació de l'usuari especificat." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "No teniu permís per a editar aquest compte." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilitzeu aquest formulari per a cercar comptes existents." -#: html/account.php msgid "You must log in to view user information." msgstr "Heu d'identificar-vos per a veure la inforació de l'usuari." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Afegeix proposta" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Element invàlid per acció de l'usuari." -#: html/addvote.php msgid "Username does not exist." msgstr "El nom d’usuari no existeix." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ja te una proposta corrent per ells." -#: html/addvote.php msgid "Invalid type." msgstr "El tipus no és vàlid." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La proposta no pot estar buit." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta presentada." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Presentar una proposta per votar." -#: html/addvote.php msgid "Applicant/TU" msgstr "Sol.licitant / TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(Buit si no s'aplica)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tipus" -#: html/addvote.php msgid "Addition of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" -#: html/addvote.php msgid "Submit" msgstr "Envia" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Inici" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Benvingut a l'AUR! Si us plau, llegiu les %sdirectrius d'usuari d'AUR%s i les %sdirectrius de TU (usuari de confiança) d'AUR%s per més informació." +msgstr "" +"Benvingut a l'AUR! Si us plau, llegiu les %sdirectrius d'usuari d'AUR%s i " +"les %sdirectrius de TU (usuari de confiança) d'AUR%s per més informació." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "És %sobligatori%s que els PKGBUILDs amb que es contribueix s'ajustin als %sEstandars d'empaquetament d'Arc%s, en cas contrari seran esborrats!" +msgstr "" +"És %sobligatori%s que els PKGBUILDs amb que es contribueix s'ajustin als " +"%sEstandars d'empaquetament d'Arc%s, en cas contrari seran esborrats!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Recordeu votar els vostres paquets preferits!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Alguns paquets poden ser oferts com binaris a [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "Avís legal" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" msgstr "" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Discussió" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Comunicar errada" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Cercar Paquets" -#: html/index.php msgid "Adopt" msgstr "" -#: html/index.php msgid "Vote" msgstr "Vota" -#: html/index.php msgid "UnVote" msgstr "Lleva el vot" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notifica" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Lleva notificació" -#: html/index.php msgid "UnFlag" msgstr "Desmarcar" -#: html/login.php template/header.php msgid "Login" msgstr "Entra" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Identificat com: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Surt" -#: html/login.php msgid "Enter login credentials" msgstr "Introduïu les credencials d'inici de sessió" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contrasenya" -#: html/login.php msgid "Remember me" msgstr "Recorda'm" -#: html/login.php msgid "Forgot Password" msgstr "Has oblidat la teva contrasenya" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "L'inici de sessió HTTP està deshabilitat. Si us plau %s canvia a HTTPs %s si voleu iniciar la sessió." +msgstr "" +"L'inici de sessió HTTP està deshabilitat. Si us plau %s canvia a HTTPs %s si " +"voleu iniciar la sessió." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteri de cerca" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquets" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "S'ha produït un error en obtenir els detalls del paquet." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Manca un camp requerit." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Els camps de contrasenya no coincideixen." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La seva contrasenya ha de tenir almenys %s caràcters." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Direcció de correu electrònic no vàlida." -#: html/passreset.php msgid "Password Reset" msgstr "Restablir contrasenya" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Revisi el seu correu electrònic per a l'enllaç de confirmació." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La seva contrasenya s'ha restablert correctament." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Tots" -#: html/passreset.php msgid "Enter your new password:" msgstr "Marcat" -#: html/passreset.php msgid "Confirm your new password:" msgstr "No marcat" -#: html/passreset.php msgid "Continue" msgstr "Continuar" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si ha oblidat l'adreça de correu electrònic utilitzada al registrar-se, si us plau envïi un missatge a la llista de correu %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Si ha oblidat l'adreça de correu electrònic utilitzada al registrar-se, si " +"us plau envïi un missatge a la llista de correu %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduiu la vostra adreça de correu." -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "No es pot trobar el paquet on combinar vots i comentaris." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Els paquets seleccionats no s'han esborrat, marqui la casella de confirmació." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Els paquets seleccionats no s'han esborrat, marqui la casella de confirmació." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Esborrament Paquet" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Esborrar Paquet: %s" +msgid "Delete Package" +msgstr "Esborrar el paquet" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "L'esborrament del paquet és permanent." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Marqueu el quadre de verificació per confirmar l'operació." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmeu l'eliminació del paquet" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Esborra" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "Només els usuaris de confiança (TUs) i desenvolupadors poden eliminar paquets." +msgstr "" +"Només els usuaris de confiança (TUs) i desenvolupadors poden eliminar " +"paquets." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Desposseir-se del paquet" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Comentaris" -#: html/pkgflag.php msgid "Flag" msgstr "Marcar" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusió de Paquets" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Fusiona el Paquet: %s" +msgid "Merge Package" +msgstr "Fusionar el paquet" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vegada que el paquet s'ha fusionat que no es pot revertir." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introdueixi el nom del paquet amb que voleu fusionar aquest paquet." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionar amb:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmi la fusió del paquet" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusió" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "Només el usuaris de confiança (TUs) i desenvolupadors poden fusionar paquets." +msgstr "" +"Només el usuaris de confiança (TUs) i desenvolupadors poden fusionar paquets." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" +msgid "Submit Request" msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primer" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Següent" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Darrer" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" -#: html/register.php template/header.php msgid "Register" msgstr "Registrar-se" -#: html/register.php msgid "Use this form to create an account." msgstr "Utilitzeu aquest formulari per a crear un compte." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuari de Confiança" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No es va poder recuperar detalls de la proposta." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "La votació es va tancar per a aquesta proposta." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No pots votar en una proposta sobre tu." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ja has votat en aquesta proposta." -#: html/tu.php msgid "Vote ID not valid." msgstr "L'identificador de vot no és vàlid." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Vots actuals" -#: html/tu.php msgid "Past Votes" msgstr "Últims vots" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votants" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "El registre de comptes ha estat inhabilitat per la seva adreça IP, probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +msgstr "" +"El registre de comptes ha estat inhabilitat per la seva adreça IP, " +"probablement a causa de continus atacs d'spam. Disculpeu les molèsties." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manca l'identificador de l'usuari" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nom d'usuari és icorrecte." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "En número de caràcters ha d'estar entre %s i %s" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comença i finalitza amb una lletra o número" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Només pot contenir un punt, guió o guió baix." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adreça del correu-e no és vàlida." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "L'empremta de la clau PGP no és vàlida." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No es possible augmentar els permisos del compte." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "L'idioma no està suportat actualment." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nom d'usuari, %s%s%s, ja s'està fent servir." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L'adressa, %s%s%s, ja s'està fent servir." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error al intentar crear el compte, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "El compte, %s%s%s, s'ha creat correctament." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "S'ha enviat una contrasenya nova al seu correu electrònic." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "Feu clic a l'enllaç superior d'Inici de sessió per utilitzar el seu compte." +msgstr "" +"Feu clic a l'enllaç superior d'Inici de sessió per utilitzar el seu compte." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No s'han fet canvis al compte, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "El compte, %s%s%s, s'ha modificat correctament." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "El formulari de registre està deshabilitat per la seva adreça IP, probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +msgstr "" +"El formulari de registre està deshabilitat per la seva adreça IP, " +"probablement a causa de continus atacs d'spam. Disculpeu les molèsties." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "La seva contrasenya s'ha restablert. Si acaba de crear un nou compte, si us plau utilitzeu l'enllaç al correu electrònic de confirmació per configurar una contrasenya inicial. En cas contrari, sol·liciti una clau de reinici a la pàgina %s de restabliment de contanenya %s." +msgstr "" +"La seva contrasenya s'ha restablert. Si acaba de crear un nou compte, si us " +"plau utilitzeu l'enllaç al correu electrònic de confirmació per configurar " +"una contrasenya inicial. En cas contrari, sol·liciti una clau de reinici a " +"la pàgina %s de restabliment de contanenya %s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "nom d'usuari o contrasenya incorrectes." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." -msgstr "Direcció de correu electrònic i combinació de tecles de restabliment no vàlida." +msgstr "" +"Direcció de correu electrònic i combinació de tecles de restabliment no " +"vàlida." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Res" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Veure l'informació del compte per %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "S'ha afegit el comentari." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Heu d'identificar-vos abans d'editar qualsevol informació de paquet." + +msgid "Missing comment ID." +msgstr "Manca l'identificador del comentari." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "No s'han pogut obtenir els detalls del paquet." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "No s'han pogut trobar els detalls del paquet." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Heu d'identificar-vos abans de marcar paquets." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No heu seleccionat cap paquet per a marcar." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Els paquets seleccionats s'han marcat com No-Actualitzats." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Heu d'identificar-vos abans de desmarcar paquets." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No heu seleccionat cap paquet per a desmarcar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Els paquets seleccionats s'han desmarcat." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No té permís per eliminar paquets." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No heu seleccionat cap paquet per a esborrar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Els paquets seleccionats s'han esborrat." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Heu d'identificar-vos abans d'apropiar-se paquets." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Heu d'identificar-vos abans de desapropiàr-se paquets." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No heu seleccionat cap paquet per apropiar-se'n." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No heu seleccionat cap paquet per desapropiar-se'n." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Els paquets seleccionats s'han apropiat." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Els paquets seleccionats han sigut desapropiats." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Heu d'identificar-vos abans de votar paquets." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Heu d'identificar-vos abans de llevar el vot als paquets." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No heu seleccionat cap paquet per votar." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Els vostres vots s'han suprimit dels paquets seleccionats." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Els vostres vots s'han enviat per als paquets seleccionats." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No s'ha pogut afegir a la llista de notificació." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Heu estat afegit a la llista de notificacions de %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Heu sigut esborrat de la llista de notificacions de comentaris de %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Heu d'identificar-vos abans d'editar qualsevol informació de paquet." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Manca l'identificador del comentari." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "S'ha esborrat el comentari." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No esteu autoritzat per esborrar aquest comentari." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "S'ha esborrat el comentari." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Veure els detalls del paquet per" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nom no vàlid: sols es permet lletres minúscules." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "El tipus de sol·licitud no és vàlid." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nom d'usuari" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipus de compte" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuari" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolupador" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Adreça de correu-e" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nom real" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nom d'usuari IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Emprempta clau PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Estat" -#: template/account_details.php msgid "Inactive since" msgstr "" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actiu" -#: template/account_details.php msgid "Last Login" msgstr "" -#: template/account_details.php msgid "Never" msgstr "Mai" -#: template/account_details.php msgid "View this user's packages" msgstr "Visualitza els paquets d'aquest usuari" -#: template/account_details.php msgid "Edit this user's account" msgstr "" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "requerit" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuari normal" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuari de Confiança" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "El compte s'ha suspès" -#: template/account_edit_form.php msgid "Inactive" msgstr "" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Escriu altre cop la contrasenya" -#: template/account_edit_form.php msgid "Language" msgstr "Idioma" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Notificar comentaris nous" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Actualitza" -#: template/account_edit_form.php msgid "Create" msgstr "Crea" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Restaura" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "No s'ha trobat cap coindidència amb els criteris de cerca." -#: template/account_search_results.php msgid "Edit Account" msgstr "Edita compte" -#: template/account_search_results.php msgid "Suspended" msgstr "Suspès" -#: template/account_search_results.php msgid "Edit" msgstr "Editar" -#: template/account_search_results.php msgid "Less" msgstr "Menys" -#: template/account_search_results.php msgid "More" msgstr "Més" -#: template/account_search_results.php msgid "No more results to display." msgstr "No hi ha més resultats per mostrar." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Els meus paquets" -#: template/header.php msgid " My Account" msgstr "El meu Compte" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Accions Paquet" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Veure PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marcat com a no-actualitzat" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar el paquet com a no-actualitzat" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar el paquet" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "eliminar vot" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Vota per aquest paquet" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Deshabilitar notificacions" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Notificar comentaris nous" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Esborrar el paquet" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Fusionar el paquet" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar Paquet" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconegut" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Paraules Clau" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Remitent" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mantenidor" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Vots" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Primer enviament" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualització" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Afegir un comentari" -#: template/pkg_comments.php msgid "View all comments" msgstr "" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Darrers Comentaris" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Esborra comentari" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Tots el comentaris" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalls del paquet" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripció" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Enllaç URL Upstream" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Visiti la pàgina web per" -#: template/pkg_details.php msgid "Licenses" msgstr "" -#: template/pkg_details.php msgid "Groups" msgstr "" -#: template/pkg_details.php msgid "Conflicts" msgstr "" -#: template/pkg_details.php msgid "Provides" msgstr "" -#: template/pkg_details.php msgid "Replaces" msgstr "" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dependències" -#: template/pkg_details.php msgid "Required by" msgstr "Requerit per" -#: template/pkg_details.php msgid "Sources" msgstr "Fonts" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motiu" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Acceptat" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Rebutjat" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "" -#: template/pkgreq_form.php msgid "Deletion" msgstr "" -#: template/pkgreq_form.php msgid "Orphan" msgstr "" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Combinar amb" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pàgina %d de %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Paquet" -#: template/pkgreq_results.php msgid "Filed by" msgstr "" -#: template/pkgreq_results.php msgid "Date" msgstr "Data" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" -#: template/pkgreq_results.php msgid "Accept" msgstr "" -#: template/pkgreq_results.php msgid "Locked" msgstr "" -#: template/pkgreq_results.php msgid "Close" msgstr "" -#: template/pkgreq_results.php msgid "Closed" msgstr "" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nom, Descripció" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Només nom" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" -#: template/pkg_search_form.php msgid "All" msgstr "Tots" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcat" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No Marcat" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nom" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votat" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendent" -#: template/pkg_search_form.php msgid "Descending" msgstr "Descendent" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introdueixi in criteri de cerca" -#: template/pkg_search_form.php msgid "Search by" msgstr "Cerca per" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "No-Actualitzat" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordena per" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordena en sentit" -#: template/pkg_search_form.php msgid "Per page" msgstr "Per pàgina" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Vés" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfes" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "S'ha produït un error en obtenir la llista de paquets." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "No s'ha trobat cap coincidència amb el teu criteri de cerca." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" -#: template/pkg_search_results.php msgid "Version" msgstr "Versió" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Sí" -#: template/pkg_search_results.php msgid "orphan" msgstr "orfe" -#: template/pkg_search_results.php msgid "Actions" msgstr "Accions" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marca com No-Actualitzat" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarca No-Actualitzat" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Apròpia paquets" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Desapròpia els paquets" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Esborra paquet" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" -#: template/search_accounts_form.php msgid "Any type" msgstr "Qualsevol tipus" -#: template/search_accounts_form.php msgid "Search" msgstr "Cerca" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadístiques" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquets orfes" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquets afegits en els darrers 7 dies" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquets actualitzats en els darrers 7 dies" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquets actualitzats en l'últim any" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquets mai actualitzats" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuaris registrats" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuaris de Confiança" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualitzacions recents" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Les meves estadístiques" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detalls de la proposta" -#: template/tu_details.php msgid "This vote is still running." msgstr "Aquesta votació encara es troba en funcionament." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Enviat: %s per %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fi" -#: template/tu_details.php msgid "Result" msgstr "" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" -#: template/tu_details.php msgid "Abstain" msgstr "Abstenir-se" -#: template/tu_details.php msgid "Total" msgstr "Nom exacte" -#: template/tu_details.php msgid "Participation" msgstr "" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No s'han trobat resultats." -#: template/tu_list.php msgid "Start" msgstr "Inici" -#: template/tu_list.php msgid "Back" msgstr "Enrere" diff --git a/po/cs.po b/po/cs.po index 6f930f2e..f9e7461f 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,9 +1,9 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: -# Jaroslav Lichtblau , 2015 +# Jaroslav Lichtblau , 2015-2016 # Jaroslav Lichtblau , 2014 # Lukas Fleischer , 2011 # Pavel Ševeček , 2014 @@ -11,770 +11,592 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-10 09:49+0000\n" +"Last-Translator: Jaroslav Lichtblau \n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" +"Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: cs\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -#: html/404.php msgid "Page Not Found" msgstr "Stránka nenalezena" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Omlouváme se, požadovaná stránka neexistuje." -#: html/503.php msgid "Service Unavailable" -msgstr "" +msgstr "Služba nedostupná" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "Nepanikařte! Na tomto webu dochází k údržbě. Brzy budeme zpět." -#: html/account.php msgid "Account" msgstr "Účet" -#: html/account.php template/header.php msgid "Accounts" msgstr "Účty" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Zde nemáte povolený přístup." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nelze obdržet informace pro vybraného uživatele." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemáte oprávnění pro úpravu tohoto účtu." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Pro vyhledání existujících účtů použíte tento formulář." -#: html/account.php msgid "You must log in to view user information." msgstr "Musíte se přihlásit, pro zobrazení informací o uživateli." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Přidat návrh" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Chybný token uživatelské akce." -#: html/addvote.php msgid "Username does not exist." msgstr "Uživatelské jméno neexistuje." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Pro %s se již hlasuje." -#: html/addvote.php msgid "Invalid type." msgstr "Chybný typ." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Návrh nemůže být prázdný." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nový návrh podán." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Předložit návrh na hlasování." -#: html/addvote.php msgid "Applicant/TU" msgstr "Uchazeč/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vynechat pokud neni vhodný)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Typ" -#: html/addvote.php msgid "Addition of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Úprava směrnic" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Návrh" -#: html/addvote.php msgid "Submit" msgstr "Odeslat" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Upravit komentář" -#: html/home.php template/header.php msgid "Home" msgstr "Domů" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nezapomeň hlasovat pro svoje oblíbené balíčky!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Některé balíčky mohou být poskytnuty v binární podobě v repozitáři [community]." +msgstr "" +"Některé balíčky mohou být poskytnuty v binární podobě v repozitáři " +"[community]." -#: html/home.php msgid "DISCLAIMER" msgstr "" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" -msgstr "" +msgstr "Podpora" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Diskuze" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Hlášení chyb" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Vyhledávání balíčků" -#: html/index.php msgid "Adopt" msgstr "Adoptovat" -#: html/index.php msgid "Vote" msgstr "Hlasovat" -#: html/index.php msgid "UnVote" msgstr "Odebrat hlas" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Oznamovat" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Neoznamovat" -#: html/index.php msgid "UnFlag" msgstr "Odznačit" -#: html/login.php template/header.php msgid "Login" msgstr "Přihlašovací jméno" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Přihlášen jako: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Odhlásit" -#: html/login.php msgid "Enter login credentials" msgstr "Vložit přihlašovací údaje" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Heslo" -#: html/login.php msgid "Remember me" msgstr "Pamatuj si mě" -#: html/login.php msgid "Forgot Password" msgstr "Zapomenuté heslo" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Vyhledávací kritéria" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Balíčky" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Došlo k chybě při získávání detailů balíčku." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Chybí povinný údaj." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Hesla se neshodují" -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Heslo musí mít nejméně %s znaků." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Neplatný e-mail." -#: html/passreset.php msgid "Password Reset" msgstr "Reset hesla" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "" -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Heslo bylo úspěšně resetováno." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrďte svou e-mailovou adresu:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Zadejte nové heslo:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrďte nové heslo:" -#: html/passreset.php msgid "Continue" msgstr "Pokračovat" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Pokud jste zapomněli emailovou adresu použitou při registraci, pošlete zprávu na %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Pokud jste zapomněli emailovou adresu použitou při registraci, pošlete " +"zprávu na %saur-general%s mailing list." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Zadejte emailovou adresu:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "" -#: html/pkgdel.php msgid "Package Deletion" msgstr "Smazání balíčku" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Smazat balíček: %s" +msgid "Delete Package" +msgstr "Smazat balíček" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Smazání balíčku je trvalé." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaškrtnout políčko pro potvrzení akce." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrdit smazání balíčku" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Smazat" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Komentáře" -#: html/pkgflag.php msgid "Flag" msgstr "Označit" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Spojení balíčku" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" +msgid "Merge Package" msgstr "" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" -#: html/pkgmerge.php msgid "Merge into:" msgstr "" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrdit spojení balíčku" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Spojit" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Zadat požadavek" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Uzavřít požadavek" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "První" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Předchozí" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Další" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Poslední" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Požadavky" -#: html/register.php template/header.php msgid "Register" msgstr "Registrovat" -#: html/register.php msgid "Use this form to create an account." msgstr "Použíte tento formulář k založení účtu." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Důvěryhodný uživatel" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nelze obdržet navrhované detaily." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Toto hlasování již skončilo." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemůžete volit sami pro sebe." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Již jste hlasoval." -#: html/tu.php msgid "Vote ID not valid." msgstr "Nesprávné ID hlasování." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Současný počet hlasů" -#: html/tu.php msgid "Past Votes" msgstr "Předešlá hlasování" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Hlasující" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Chybějící Uživateské ID" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Chybně zadané uživatelské jméno" -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Délka musí být %s až %s znaků" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Začíná a končí písmenem nebo číslicí" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Může obsahovat pouze jednu tečku, podtržítko nebo spojovník." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Vadná emailová adresa." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jazyk není momentálné podporován." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Účet pozastaven" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -782,497 +604,416 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Chybné uživatelské jméno nebo heslo." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentář byl přidán" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "" +"Musíte být přihlášeni, než budete moci upravovat informace o balíčcích." + +msgid "Missing comment ID." +msgstr "Chybějící ID komentáře." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Došlo k chybě při získávání detailů o balíčku." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Detailní informace o balíčku nejsou dostupné." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Před nastavením příznaku balíčků se musíte přihlásit." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nezvolili jste žádný balíček k označení." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Zvoleným balíčkům byl nastaven příznak zastaralé." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musíte být příhlášeni, abyste mohli odznačit balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nevybrali jste žádne balíčky k odebrání příznaku." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Zvoleným bálíčkům bylo odebráno označení." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nevybrali jste žádné balíčky ke smazání." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Zvolené balíčky byly smazány." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musíte být přihlášeni, než si budete moci osvojit balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musíte být přihlášeni, pro odebrání vlastnictví u svých balíčků." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nevybrali jste žádný balíček k osvojení." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nevybrali jste žádný balíček pro odebrání vlastnictví." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Zvolené balíčky byly osvojeny." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Vybraným balíčkům bylo odebráno vlastnictví." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Před hlasováním se musíte přihlásit." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musíte být přihlášeni, než budete moci odebrat hlasování pro balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nezvolili jste žádné balíčky k hlasování." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaše hlasování bylo odebráno vybraným balíčkům." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Vaše hlasování bylo započteno pro vybrané balíčky." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nelze přidat do seznamu upozornění." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Byly jste přidáni do seznamu oznámení ohledně %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Byli jste odebrání ze seznamu upozornění ohledně %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Musíte být přihlášeni, než budete moci upravovat informace o balíčcích." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Chybějící ID komentáře." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Komentář byl smazán." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nemáte oprávnění pro smazání tohoto komentáře." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Komentář byl smazán." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Chybný název: jsou povolena pouze malá písmena." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" -msgstr "" +msgstr "Potvrdit smazání" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Uživatelské jméno" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Typ účtu" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Uživatel" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Vyvojář" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Emailová adresa" -#: template/account_details.php msgid "hidden" -msgstr "" +msgstr "skrytý" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Skutečné jméno" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC přezdívka" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Neaktivní od" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivní" -#: template/account_details.php msgid "Last Login" msgstr "Poslední přihlášení" -#: template/account_details.php msgid "Never" msgstr "Nikdy" -#: template/account_details.php msgid "View this user's packages" msgstr "Zobrazit balíčky tohoto uživatele" -#: template/account_details.php msgid "Edit this user's account" msgstr "Upravit tento uživatelský účet" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "vyžadováno" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Obyčejný uživatel" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Důvěryhodný uživatel" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Účet pozastaven" -#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktivní" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" -msgstr "" +msgstr "Skrýt email" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Heslo znovu" -#: template/account_edit_form.php msgid "Language" msgstr "Jazyk" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Oznamovat nové komentáře" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Aktualizovat" -#: template/account_edit_form.php msgid "Create" msgstr "Vytvořit" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reset" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Pro Váš dotaz nebyl nalezen žádný odpovídající výsledek." -#: template/account_search_results.php msgid "Edit Account" msgstr "Upravit účet" -#: template/account_search_results.php msgid "Suspended" msgstr "Pozastavený" -#: template/account_search_results.php msgid "Edit" msgstr "Upravit" -#: template/account_search_results.php msgid "Less" msgstr "Méně" -#: template/account_search_results.php msgid "More" msgstr "Více" -#: template/account_search_results.php msgid "No more results to display." msgstr "Žádné další výsledky." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" -msgstr "" +msgstr "Uživatelé" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" +msgstr "Uložit" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -#: template/header.php msgid "My Packages" msgstr "Moje balíčky" -#: template/header.php msgid " My Account" msgstr "Můj účet" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Zobrazit PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Prohledat wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Označeno jako zastaralé" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Označit balíček jako zastaralý" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Zrušit označení balíčku" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Vzít zpět hlas" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Hlasovat pro tento balíček" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Vypnout oznámení" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Oznamovat nové komentáře" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1280,232 +1021,178 @@ msgstr[0] "%d čekající požadavek" msgstr[1] "%d čekající požadavky" msgstr[2] "%d čekajících požadavků" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Smazat balíček" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptovat balíček" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "neznámý" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Klíčová slova" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Správce" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Hlasy" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Naposledy aktualizováno" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Přidat komentář" -#: template/pkg_comments.php msgid "View all comments" msgstr "Zobrazit všechny komentáře" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Nejnovější komentáře" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Smazat komentář" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Všechny komentáře" -#: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčku" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Popis" -#: template/pkg_details.php msgid "Upstream URL" msgstr "" -#: template/pkg_details.php msgid "Visit the website for" msgstr "" -#: template/pkg_details.php msgid "Licenses" msgstr "Licence" -#: template/pkg_details.php msgid "Groups" msgstr "Skupiny" -#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikty" -#: template/pkg_details.php msgid "Provides" msgstr "Poskytuje" -#: template/pkg_details.php msgid "Replaces" msgstr "Nahrazuje" -#: template/pkg_details.php msgid "Dependencies" msgstr "Závislosti" -#: template/pkg_details.php msgid "Required by" msgstr "Vyžadováno" -#: template/pkg_details.php msgid "Sources" msgstr "Zdroje" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Zavřít požadavek: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Důvod" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Přijato" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Zamítnuto" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Zadat požadavek: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "Typ požadavku" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Smazání" -#: template/pkgreq_form.php msgid "Orphan" msgstr "" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1513,29 +1200,23 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" -#: template/pkgreq_results.php msgid "Package" -msgstr "" +msgstr "Balíček" -#: template/pkgreq_results.php msgid "Filed by" msgstr "" -#: template/pkgreq_results.php msgid "Date" msgstr "Datum" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1543,116 +1224,87 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" -#: template/pkgreq_results.php msgid "Accept" msgstr "Přijmout" -#: template/pkgreq_results.php msgid "Locked" msgstr "Zamčeno" -#: template/pkgreq_results.php msgid "Close" msgstr "Uzavřít" -#: template/pkgreq_results.php msgid "Closed" msgstr "Uzavřeno" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Jméno, popis" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Pouze jméno" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Přesné jméno" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" -#: template/pkg_search_form.php msgid "All" msgstr "Vše" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Označené" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Neoznačené" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Název" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Hlasováno" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Vzestupně" -#: template/pkg_search_form.php msgid "Descending" msgstr "Sestupně" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Zadat kritéria vyhledávání" -#: template/pkg_search_form.php msgid "Search by" msgstr "Vyhledat dle" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastaralé" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Seřadit dle" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Řadit" -#: template/pkg_search_form.php msgid "Per page" msgstr "Na jedné stránce" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Jdi" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Sirotci" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Chyba při získávání seznamu balíčků." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Žádný balíček neodpovídá zadaným kritériím." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1660,154 +1312,116 @@ msgstr[0] "Nalezen %d balíček." msgstr[1] "Nalezeny %d balíčky." msgstr[2] "Nalezeno %d balíčků." -#: template/pkg_search_results.php msgid "Version" msgstr "Verze" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Ano" -#: template/pkg_search_results.php msgid "orphan" msgstr "sirotek" -#: template/pkg_search_results.php msgid "Actions" msgstr "Akce" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Označit jako zastaralý" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Odebrat příznak zastaralý" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Osvojit balíček" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odebrat vlastnictví" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Smazat balíčky" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrdit" -#: template/search_accounts_form.php msgid "Any type" msgstr "Jakýkoliv" -#: template/search_accounts_form.php msgid "Search" msgstr "Hledat" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiky" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Balíčků bez správce" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Přidaných balíčků za posledních 7 dní" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Aktualizovaných balíčků za posledních 7 dní" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Aktualizovaných balíčků v posledním roce" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Balíčků, které nebyly nikdy aktualizovány" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovaných uživatelů" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Důvěryhodných uživatelů" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedávné aktualizace" -#: template/stats/user_table.php +msgid "more" +msgstr "více" + msgid "My Statistics" msgstr "Moje statistiky" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detaily návrhu" -#: template/tu_details.php msgid "This vote is still running." msgstr "Hlasování stále probíhá." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Vloženo: %s od %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Konec" -#: template/tu_details.php msgid "Result" msgstr "Výsledek" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" -#: template/tu_details.php msgid "Abstain" msgstr "Zdržet se" -#: template/tu_details.php msgid "Total" msgstr "Celkem" -#: template/tu_details.php msgid "Participation" msgstr "Účast" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Naposledy hlasováno" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Žádné výsledky." -#: template/tu_list.php msgid "Start" msgstr "Začátek" -#: template/tu_list.php msgid "Back" msgstr "Zpět" diff --git a/po/da.po b/po/da.po index ff1cf908..14253277 100644 --- a/po/da.po +++ b/po/da.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Louis Tim Larsen , 2015 # Lukas Fleischer , 2011 @@ -9,770 +9,589 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/da/)\n" +"Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" +"da/)\n" +"Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: da\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Siden blev ikke fundet" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Beklager, den forspurgte side findes ikke." -#: html/503.php msgid "Service Unavailable" msgstr "Service utilgængelig" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" -#: html/account.php msgid "Account" msgstr "Konto" -#: html/account.php template/header.php msgid "Accounts" msgstr "Konti" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Du har ikke tilladelse til dette område." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kunne ikke hente information om den specifikke bruger." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du har ikke tilladelse til at redigere denne konto." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Brug denne formular til at søge i eksisterende konti." -#: html/account.php msgid "You must log in to view user information." msgstr "Du skal være logget ind for at se brugerinformation." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "" -#: html/addvote.php msgid "Invalid token for user action." msgstr "" -#: html/addvote.php msgid "Username does not exist." msgstr "Brugernavnet findes ikke." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s har allerede et forslag kørende for dem." -#: html/addvote.php msgid "Invalid type." msgstr "" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Forslag må ikke være tomt." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nyt forslag tilføjet." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Fremsæt et forslag til afstemning." -#: html/addvote.php msgid "Applicant/TU" msgstr "" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tomt hvis ikke relevant)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Type" -#: html/addvote.php msgid "Addition of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Forslag" -#: html/addvote.php msgid "Submit" msgstr "Tilføj" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Hjem" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" -#: html/home.php msgid "DISCLAIMER" msgstr "" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" msgstr "" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Diskussion" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Pakkesøgning" -#: html/index.php msgid "Adopt" msgstr "Adopter" -#: html/index.php msgid "Vote" msgstr "Stem" -#: html/index.php msgid "UnVote" msgstr "Tilbagetræk stemme" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Påmindelse" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ingen påmindelse" -#: html/index.php msgid "UnFlag" msgstr "" -#: html/login.php template/header.php msgid "Login" msgstr "Log ind" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Logget ind som: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Log ud" -#: html/login.php msgid "Enter login credentials" msgstr "" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Adgangskode" -#: html/login.php msgid "Remember me" msgstr "Husk mig" -#: html/login.php msgid "Forgot Password" msgstr "Glemt adgangskode" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Søgekriterier" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakker" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Fejl ved modtagning af pakkedetaljer." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Du mangler at udfylde et påkrævet felt." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Adgangskoderne stemmer ikke overens." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Din adgangskode skal være mindst %s tegn." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Ugyldig mail." -#: html/passreset.php msgid "Password Reset" msgstr "Nulstil adgangskode" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Tjek din mail for bekræftelses-link." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Din adgangskode blev nulstillet." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bekræft din nye mail-adresse:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Indtast din nye adgangskode:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Bekræft din nye adgangskode:" -#: html/passreset.php msgid "Continue" msgstr "Forsæt" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." msgstr "" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Indtast din mail-adresse:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "" -#: html/pkgdel.php msgid "Package Deletion" msgstr "" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Slet pakke: %s" +msgid "Delete Package" +msgstr "Slet pakke" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Sletning af en pakke er permanent" -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bekræft sletning af pakke" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Slet" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Kun betroede brugere og udviklere kan slette pakker." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentarer" -#: html/pkgflag.php msgid "Flag" msgstr "" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" +msgid "Merge Package" msgstr "" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Følgende pakker vil blive slettet:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" -#: html/pkgmerge.php msgid "Merge into:" msgstr "" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Udfyld forspørgsel" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Luk forspørgsel" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Tidligere" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Næste" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Sidste" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Forspørgelser" -#: html/register.php template/header.php msgid "Register" msgstr "Register" -#: html/register.php msgid "Use this form to create an account." msgstr "Brug denne formular til at oprette en konto." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Betroet bruger (TU)" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Kunne ikke hente detaljer om forslaget." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Afstemningen er lukket for dette forslag." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Du kan ikke stemme i et forslag om dig selv." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du har allerede stemt ved dette forslag." -#: html/tu.php msgid "Vote ID not valid." msgstr "Stemme ID er ikke gyldigt." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Aktuelle stemmer" -#: html/tu.php msgid "Past Votes" msgstr "" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manglende bruger-ID" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Brugernavnet er ugyldigt." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Skal være mellem %s og %s tegn." -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Start og slut med et bogstav eller tal" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun indeholde ét punktum, én bundstreg eller én bindestreg." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mail adressen er ugyldig." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Sproget er ikke understøttet på nuværende tidspunkt." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto suspenderet" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -780,1028 +599,819 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Forkert brugernavn eller adgangskode" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Ingen" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentaren blev tilføjet" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Du skal være logget ind for at redigere pakkeoplysninger." + +msgid "Missing comment ID." +msgstr "Manglende kommentar ID." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Fejl ved modtagelse af pakkedetaljer." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Kunne ikke finde pakkedetaljerne.." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du skal være logget ind for at markere pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Du har ikke valgt nogle pakker at markere." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "De valgte pakker er markeret forældet." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Du skal være logget ind for at afmarkere pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Du har ikke valgt nogle at afmarkere." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De valgte pakker er afmarkeret." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du har ikke tilladelse til, at slette pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du har ikke valgt nogle pakker at slette." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De valgte pakker er blevet slettet." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du skal være logget ind for at adoptere pakker." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du skal være logget ind for at opgive ejerskabet for pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du har ikke valgt nogle pakker at adoptere." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du har ikke valgt nogle pakker at opgive ejerskabet for." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "De valgte pakker er adopteret." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De valgte pakker er blevet efterladt." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du skal være logget ind for at stemme på pakker." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du skal være logget ind for at fjerne din stemme fra pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du har ikke valgt nogle pakker at stemme på." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Dine stemmer er fjernet fra de valgte pakker." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Din stemme er afgivet for de valgte pakker." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kunne ikke tilføje til listen over påmindelser." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du vil nu modtage besked, når der kommer nye kommentarer til %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du vil ikke længere modtage besked ved nye kommentarer for %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Du skal være logget ind for at redigere pakkeoplysninger." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Manglende kommentar ID." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Kommentaren er slettet." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du har ikke rettigheder til at slette denne kommentar." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Kommentaren er slettet." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ugyldigt brugernavn: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vis pakkedeltaljer for" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ugyldigt navn: kun små bogstaver er tilladt." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ugyldig årsag" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" msgstr "Bekræft sletning" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Brugernavn" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Kontotype" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Bruger" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Udvikler" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Betroet bruger og udvikler" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail adresse" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Rigtigt navn" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC kaldenavn" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Inaktiv siden" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" -#: template/account_details.php msgid "Last Login" msgstr "Sidste login" -#: template/account_details.php msgid "Never" msgstr "Aldrig" -#: template/account_details.php msgid "View this user's packages" msgstr "Vis pakker fra denne bruger" -#: template/account_details.php msgid "Edit this user's account" msgstr "" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "påkrævet" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normal bruger" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Betroet bruger (TU)" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto suspenderet" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Bekræft adgangskode" -#: template/account_edit_form.php msgid "Language" msgstr "Sprog" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Opdater" -#: template/account_edit_form.php msgid "Create" msgstr "Opret" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Nulstil" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Ingen resultater opfyldte dine søgekriterier." -#: template/account_search_results.php msgid "Edit Account" msgstr "Rediger konto" -#: template/account_search_results.php msgid "Suspended" msgstr "Suspenderet" -#: template/account_search_results.php msgid "Edit" msgstr "" -#: template/account_search_results.php msgid "Less" msgstr "Færre" -#: template/account_search_results.php msgid "More" msgstr "Flere" -#: template/account_search_results.php msgid "No more results to display." msgstr "Ikke flere resultater at vise." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "Brugere" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Gem" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Mine pakker" -#: template/header.php msgid " My Account" msgstr "Min konto" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Vis PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "Vis ændringer" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" +#, php-format +msgid "Flagged out-of-date (%s)" msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Fjern stemme" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem på denne pakke" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Deaktiver notifikationer" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Slet pakke" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter pakke" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "ukendt" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Nøgleord" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Indsender" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ejer" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Sidste pakker" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmer" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularitet" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Først tilføjet" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Sidst opdateret" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Tilføj kommentar" -#: template/pkg_comments.php msgid "View all comments" msgstr "Vis alle kommentarer" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Seneste kommentarer" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Slet kommentar" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Alle kommentarer" -#: template/pkg_details.php msgid "Package Details" msgstr "Detaljer om pakken" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beskrivelse" -#: template/pkg_details.php msgid "Upstream URL" msgstr "" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Besøg hjemmesiden for" -#: template/pkg_details.php msgid "Licenses" msgstr "Licenser" -#: template/pkg_details.php msgid "Groups" msgstr "Grupper" -#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikter" -#: template/pkg_details.php msgid "Provides" msgstr "Tilbyder" -#: template/pkg_details.php msgid "Replaces" msgstr "Erstatter" -#: template/pkg_details.php msgid "Dependencies" msgstr "Afhængigheder" -#: template/pkg_details.php msgid "Required by" msgstr "Påkrævet af" -#: template/pkg_details.php msgid "Sources" msgstr "Kilder" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Luk forspørgsel: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Accepteret" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Afvist" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Sletning" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Forladt" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Side %d af %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pakke" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Udfyldt af" -#: template/pkgreq_results.php msgid "Date" msgstr "Dato" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dage tilbage" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d time tilbage" msgstr[1] "~%d timer tilbage" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 time tilbage" -#: template/pkgreq_results.php msgid "Accept" msgstr "Accepter" -#: template/pkgreq_results.php msgid "Locked" msgstr "Låst" -#: template/pkgreq_results.php msgid "Close" msgstr "Luk" -#: template/pkgreq_results.php msgid "Closed" msgstr "Lukket" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Navn, beskrivelse" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Kun navn" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Præcist navn" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" -#: template/pkg_search_form.php msgid "All" msgstr "Alle" -#: template/pkg_search_form.php msgid "Flagged" msgstr "" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Navn" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Stemt" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "" -#: template/pkg_search_form.php msgid "Descending" msgstr "" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" -#: template/pkg_search_form.php msgid "Search by" msgstr "Søg efter" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Forældet" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortér efter" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorter efter" -#: template/pkg_search_form.php msgid "Per page" msgstr "Per side" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Søg" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Forladt" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fejl ved modtagelse af pakkeliste." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ingen pakker opfylder dine søgekriterier." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pakke fundet." msgstr[1] "%d pakker fundet." -#: template/pkg_search_results.php msgid "Version" msgstr "Version" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Ja" -#: template/pkg_search_results.php msgid "orphan" msgstr "forladt" -#: template/pkg_search_results.php msgid "Actions" msgstr "Handlinger" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marker forældet" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Afmarker forældet" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter pakker" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Fjern ejerskab for pakker" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Slet pakker" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Forsæt" -#: template/search_accounts_form.php msgid "Any type" msgstr "Vilkårlig type" -#: template/search_accounts_form.php msgid "Search" msgstr "Søg" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistikker" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Forladte pakker" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakker tilføjet indenfor de seneste 7 dage" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakker opdateret indenfor de seneste 7 dage" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakker opdateret indenfor det seneste år" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pakker aldrig opdateret" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registerede brugere" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Betroede brugere" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Seneste opdateringer" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Mine statistikker" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detaljer om forslag" -#: template/tu_details.php msgid "This vote is still running." msgstr "Denne afstemning er stadig aktiv." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Tilføjet: %s af %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Slut" -#: template/tu_details.php msgid "Result" msgstr "Resultat" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nej" -#: template/tu_details.php msgid "Abstain" msgstr "Undlad at stemme" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" msgstr "Deltagelse" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Sidste stemme" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ingen resultater fundet." -#: template/tu_list.php msgid "Start" msgstr "Start" -#: template/tu_list.php msgid "Back" msgstr "Tilbage" diff --git a/po/de.po b/po/de.po index e6505dd4..1fc461f0 100644 --- a/po/de.po +++ b/po/de.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Alexander Griesbaum , 2013 # Alexander Griesbaum , 2013-2014 @@ -24,1799 +24,1509 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 18:35+0000\n" -"Last-Translator: Matthias Gorissen \n" -"Language-Team: German (http://www.transifex.com/lfleischer/aur/language/de/)\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" +"de/)\n" +"Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Seite nicht gefunden" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Die angeforderte Seite existiert leider nicht." -#: html/503.php msgid "Service Unavailable" msgstr "Dienst nicht verfügbr" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir werden gleich zurück sein ..." +msgstr "" +"Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir " +"werden gleich zurück sein ..." -#: html/account.php msgid "Account" msgstr "Konto" -#: html/account.php template/header.php msgid "Accounts" msgstr "Konten" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Es ist Dir nicht erlaubt, auf diesen Bereich zuzugreifen." -#: html/account.php msgid "Could not retrieve information for the specified user." -msgstr "Es konnten keine Informationen für den angegebenen Benutzer geladen werden." +msgstr "" +"Es konnten keine Informationen für den angegebenen Benutzer geladen werden." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du hast keine Berechtigung, dieses Konto zu ändern." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Benutze dieses Formular, um vorhandene Konten zu suchen." -#: html/account.php msgid "You must log in to view user information." msgstr "Du musst Dich anmelden, um Benutzerinformationen anzusehen." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Vorschlag hinzufügen" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Ungültiges Zeichen für eine Benutzer-Aktion." -#: html/addvote.php msgid "Username does not exist." msgstr "Der Nutzername existiert nicht." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Es läuft bereits ein Vorschlag für %s." -#: html/addvote.php msgid "Invalid type." msgstr "Ungültiger Typ." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Vorschlag darf nicht leer sein." -#: html/addvote.php msgid "New proposal submitted." msgstr "Neuer Vorschlag eingereicht." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Reiche einen Vorschlag zur Abstimmung ein." -#: html/addvote.php msgid "Applicant/TU" msgstr "Bewerber/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(leer, falls nicht zutreffend)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Typ" -#: html/addvote.php msgid "Addition of a TU" msgstr "TU hinzugefügt" -#: html/addvote.php msgid "Removal of a TU" msgstr "TU entfernt" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU entfernt (unerklärte Inaktivität)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Änderung der Bestimmungen" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Vorschlag" -#: html/addvote.php msgid "Submit" msgstr "Abschicken" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Verwalte Ko-Maintainer" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Kommentar bearbeiten" -#: html/home.php template/header.php msgid "Home" msgstr "Startseite" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Willkommen im AUR! Für weitere Informationen lies bitte die %sAUR User Guidelines%s und die %sAUR TU Guidelines%s." +msgstr "" +"Willkommen im AUR! Für weitere Informationen lies bitte die %sAUR User " +"Guidelines%s und die %sAUR TU Guidelines%s." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Alle hier eingereichten PKGBUILDs %smüssen%s den %sArch Packaging Standards%s entsprechen. Andernfalls werden sie entfernt!" +msgstr "" +"Alle hier eingereichten PKGBUILDs %smüssen%s den %sArch Packaging Standards" +"%s entsprechen. Andernfalls werden sie entfernt!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Denk daran, für Deine bevorzugten Pakete zu stimmen!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Manche Pakete könnten als Binär-Pakete in [community] bereitgestellt sein." +msgstr "" +"Manche Pakete könnten als Binär-Pakete in [community] bereitgestellt sein." -#: html/home.php msgid "DISCLAIMER" -msgstr "DISCLAIMER: Offiziell nicht unterstützte PKGBUILDS werden von den Benutzern erstellt - durch den Download willigt man ein, diese auf eigene Gefahr zu benutzen." +msgstr "" +"DISCLAIMER: Offiziell nicht unterstützte PKGBUILDS werden von den Benutzern " +"erstellt - durch den Download willigt man ein, diese auf eigene Gefahr zu " +"benutzen." -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "AUR Pakete sind von Benutzern erstellter Inhalt. Die Benutzung der angebotenen Dateien erfolgt auf eingenes Risiko." +msgstr "" +"AUR Pakete sind von Benutzern erstellter Inhalt. Die Benutzung der " +"angebotenen Dateien erfolgt auf eingenes Risiko." -#: html/home.php msgid "Learn more..." msgstr "Erfahre mehr ..." -#: html/home.php msgid "Support" msgstr "Untersttzung" -#: html/home.php msgid "Package Requests" msgstr "Paketanfragen" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Es gibt drei Arten von Anfragen, die in der %sPaketaktionen%s Box auf der Paketdetailseite eingereicht werden können:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Es gibt drei Arten von Anfragen, die in der %sPaketaktionen%s Box auf der " +"Paketdetailseite eingereicht werden können:" -#: html/home.php msgid "Orphan Request" msgstr "Verweisungsanfrage" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Anfrage eine Pakte abzugeben, z.B. wenn der Verwalten nicht aktiv ist und das Paket vor einer ganzen Weile als veraltet makiert wurde." +msgstr "" +"Anfrage eine Pakte abzugeben, z.B. wenn der Verwalten nicht aktiv ist und " +"das Paket vor einer ganzen Weile als veraltet makiert wurde." -#: html/home.php msgid "Deletion Request" msgstr "Lösch-Antrag" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte benutzen Sie diese nicht, wenn das Paket kaputt ist und leich repariert werden kann. Sondern kontaktieren Sie den Paketverwalter und reichen Sie eine Verwaisungsanfrage ein wenn nötig." +msgstr "" +"Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte " +"benutzen Sie diese nicht, wenn das Paket kaputt ist und leich repariert " +"werden kann. Sondern kontaktieren Sie den Paketverwalter und reichen Sie " +"eine Verwaisungsanfrage ein wenn nötig." -#: html/home.php msgid "Merge Request" msgstr "Zusammenführungsanfrage" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Anfrage ein Paket mit einem anderen zusammenzuführen. Wird benutzt, wenn ein Paket umbenannt werden muss oder durch ein geteiltes Paket ersetzt wird." +msgstr "" +"Anfrage ein Paket mit einem anderen zusammenzuführen. Wird benutzt, wenn ein " +"Paket umbenannt werden muss oder durch ein geteiltes Paket ersetzt wird." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Wenn Sie eine Anfrage diskutieren wollen, können sie die %saur-requests%s Mailingliste benutzen. Jedoch benutzen Sie diese nicht um Anfragen einzureichen." +msgstr "" +"Wenn Sie eine Anfrage diskutieren wollen, können sie die %saur-requests%s " +"Mailingliste benutzen. Jedoch benutzen Sie diese nicht um Anfragen " +"einzureichen." -#: html/home.php msgid "Submitting Packages" msgstr "Pakete einreichen" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Git über SSH wird jetzt benutzt um Pakete in das AUR einzureichen. Siehe die %sEinreichen von Paketen%s Sektion von der Arch User Repository ArchWiki Seite für mehr Details." +msgstr "" +"Git über SSH wird jetzt benutzt um Pakete in das AUR einzureichen. Siehe die " +"%sEinreichen von Paketen%s Sektion von der Arch User Repository ArchWiki " +"Seite für mehr Details." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Die folgenden SSH Fingerabdrücke werden für das AUR benutzt:" -#: html/home.php msgid "Discussion" msgstr "Diskussion" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface nutzen Sie die %saur-dev%s Mailingliste." +msgstr "" +"Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und " +"vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für " +"Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface nutzen Sie " +"die %saur-dev%s Mailingliste." -#: html/home.php msgid "Bug Reporting" msgstr "Fehler melden" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." -msgstr "Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte direkt an den zuständigen Maintainer, oder hinterlaß einen Kommentar auf der entsprechenden Seite des Paketes." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." +msgstr "" +"Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-" +"Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um " +"Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte direkt " +"an den zuständigen Maintainer, oder hinterlaß einen Kommentar auf der " +"entsprechenden Seite des Paketes." -#: html/home.php msgid "Package Search" msgstr "Paketsuche" -#: html/index.php msgid "Adopt" msgstr "Übernimm Paket" -#: html/index.php msgid "Vote" msgstr "Abstimmen" -#: html/index.php msgid "UnVote" msgstr "Stimme zurückziehen" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Benachrichtigen" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Nicht mehr benachrichtigen" -#: html/index.php msgid "UnFlag" msgstr "Markierung aufheben" -#: html/login.php template/header.php msgid "Login" msgstr "Anmelden" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Angemeldet als: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Abmelden" -#: html/login.php msgid "Enter login credentials" msgstr "Zugangsdaten eingeben" -#: html/login.php msgid "User name or email address" msgstr "Benutzername oder E-Mail-Adresse" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Passwort" -#: html/login.php msgid "Remember me" msgstr "Angemeldet bleiben" -#: html/login.php msgid "Forgot Password" msgstr "Passwort vergessen" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Die Anmeldung über HTTP wurde deaktiviert. Zum Anmelden %swechsle bitte zu HTTPS%s." +msgstr "" +"Die Anmeldung über HTTP wurde deaktiviert. Zum Anmelden %swechsle bitte zu " +"HTTPS%s." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Suchkriterien" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakete" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Während des Empfangs der Paket-Details ist ein Fehler aufgetreten." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Ein benötigtes Feld ist nicht ausgefüllt." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Passwort-Felder sind unterschiedlich." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Dein Passwort muss mindestens %s Zeichen lang sein." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Ungültige E-Mail-Adresse." -#: html/passreset.php msgid "Password Reset" msgstr "Passwort zurücksetzen" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Überprüfe Dein E-Mail-Postfach hinsichtlich des Bestätigungslinks." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Dein Passwort wurde erfolgreich zurückgesetzt." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bestätige Deine E-Mail-Adresse:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Gib Dein neues Passwort ein:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Bestätige Dein neues Passwort:" -#: html/passreset.php msgid "Continue" msgstr "Weiter" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Wenn Du die E-Mail-Adresse vergessen hast, die Du für Deine Registrierung benutzt hast, sende bitte eine Nachricht an die %saur-general%s Mailing-Liste." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Wenn Du die E-Mail-Adresse vergessen hast, die Du für Deine Registrierung " +"benutzt hast, sende bitte eine Nachricht an die %saur-general%s Mailing-" +"Liste." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Gib Deine E-Mail-Adresse ein:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "Die gewählten Pakete wurden nicht makiert, bitte einen Kommentar eingeben." - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "Die Betreuung der ausgewählten Pakete wurde nicht abgegeben, überprüfe die Bestätigungs-Checkbox." +msgstr "" +"Die Betreuung der ausgewählten Pakete wurde nicht abgegeben, überprüfe die " +"Bestätigungs-Checkbox." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Das Paket, in das die Stimmen und Kommentare übernommen werden sollen, kann nicht gefunden werden." +msgstr "" +"Das Paket, in das die Stimmen und Kommentare übernommen werden sollen, kann " +"nicht gefunden werden." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Eine Paketbasis kann nicht mit sich selbst verschmolzen werden." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Die ausgewählten Pakete wurden nicht gelöscht, bitte aktiviere die Bestätigungs-Checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Die ausgewählten Pakete wurden nicht gelöscht, bitte aktiviere die " +"Bestätigungs-Checkbox." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Pakete entfernen" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Paket löschen: %s" +msgid "Delete Package" +msgstr "Paket löschen" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Benutze dieses Formular um die Paketbasis %s%s%s und die folgenden Pakete vom AUR zu löschen:" +msgstr "" +"Benutze dieses Formular um die Paketbasis %s%s%s und die folgenden Pakete " +"vom AUR zu löschen:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Die Löschung eines Pakets ist endgültig." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Wähle ein Kästchen aus, um die Aktion zu bestätigen." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bestätige das Löschen des Pakets" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Löschen" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Nur vertrauenswürdige Benutzer und Entwickler können Pakete löschen." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Paket abgeben" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Paket-Betreuung abgeben: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Benutzen Sie dieses Formular um die Paketbasis %s%s%s, welche die folgenden Pakete enhält, abzugeben:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Benutzen Sie dieses Formular um die Paketbasis %s%s%s, welche die folgenden " +"Pakete enhält, abzugeben:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Durch das markieren des Kontrollkästchen bestätigen Sie, dass Sie das Pakte abegen und den Besitz an %s%s%s übergeben wollen." +msgstr "" +"Durch das markieren des Kontrollkästchen bestätigen Sie, dass Sie das Pakte " +"abegen und den Besitz an %s%s%s übergeben wollen." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Durch Auswahl dieser Checkbox bestätigst du, dass du die Betreuung dieses Paketes abgeben willst." +msgstr "" +"Durch Auswahl dieser Checkbox bestätigst du, dass du die Betreuung dieses " +"Paketes abgeben willst." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Bestätige die Abgabe der Paket-Betreuung" -#: html/pkgdisown.php msgid "Disown" msgstr "Gebe Paket ab" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Nur Tus und Developer können die Paket-Betreuung abgeben." -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "Paket als \"veraltet\" makieren" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "Paket als \"veraltet\" markieren: %s" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " -msgstr "Benutze dieses Formular, um die Paketbasis %s%s%s und die folgenden Pakete als \"veraltet\" zu markieren." +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " +msgstr "" +"Benutze dieses Formular, um die Paketbasis %s%s%s und die folgenden Pakete " +"als \"veraltet\" zu markieren." -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "Bitte benutze dieses Formular %snicht%s, um Fehler zu melden. Benutze stattdessen die Paketkommentare." +msgstr "" +"Bitte benutze dieses Formular %snicht%s, um Fehler zu melden. Benutze " +"stattdessen die Paketkommentare." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "Beschreibe genauer, warum das Paket \"veraltet\" ist, vorzugsweise mit Links zu der Veröffentlichungsankündigung oder dem Release-Tar-Archive." +msgstr "" +"Beschreibe genauer, warum das Paket \"veraltet\" ist, vorzugsweise mit Links " +"zu der Veröffentlichungsankündigung oder dem Release-Tar-Archive." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentare" -#: html/pkgflag.php msgid "Flag" msgstr "Markieren" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Nur registrierte Benutzer können Pakete als \"veraltet\" markieren." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakete verschmelzen" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Verschmelze Paket: %s" +msgid "Merge Package" +msgstr "Paket verschmelzen" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Benutze dieses Formular um die Paketbasis %s%s%s in ein anderes Paket zu verschmelzen." +msgstr "" +"Benutze dieses Formular um die Paketbasis %s%s%s in ein anderes Paket zu " +"verschmelzen." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Die folgenden Pakete werden gelöscht:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "Wenn das Paket einmal verschmolzen ist, kann diese Aktion nicht mehr revidiert werden." +msgstr "" +"Wenn das Paket einmal verschmolzen ist, kann diese Aktion nicht mehr " +"revidiert werden." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Trag den Namen des Pakets ein, in welches Du das vorliegende Paket verschmelzen willst." +msgstr "" +"Trag den Namen des Pakets ein, in welches Du das vorliegende Paket " +"verschmelzen willst." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Verschmelze in:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Bestätige Verschmelzung der Pakete" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Verschmelzen" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." +msgstr "" +"Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Anfrage einreichen" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Anfrage schließen" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Erste" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Zurück" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Weiter" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Letzte" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Anfragen" -#: html/register.php template/header.php msgid "Register" msgstr "Registrieren" -#: html/register.php msgid "Use this form to create an account." msgstr "Benutze dieses Formular, um ein Konto zu erstellen." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Vertrauenswürdiger Benutzer (TU)" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Es konnten keine Vorschlag-Details ermittelt werden." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Die Abstimmungsphase für diesen Vorschlag ist beendet." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Nur Trusted User dürfen wählen." -#: html/tu.php msgid "You cannot vote in an proposal about you." -msgstr "Du kannst über einen Vorschlag, der dich selbst betrifft, nicht abstimmen." +msgstr "" +"Du kannst über einen Vorschlag, der dich selbst betrifft, nicht abstimmen." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du hast über diesen Vorschlag bereits abgestimmt." -#: html/tu.php msgid "Vote ID not valid." msgstr "Ungültige Abstimmungs-ID." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Laufende Abstimmungen" -#: html/tu.php msgid "Past Votes" msgstr "Abgeschlossene Abstimmungen" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Abstimmende" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Die Registrierung ist aktuell für deine IP-Adresse deaktiviert. Ein möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die Unannehmlichkeiten." +msgstr "" +"Die Registrierung ist aktuell für deine IP-Adresse deaktiviert. Ein " +"möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die " +"Unannehmlichkeiten." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Benutzer-ID fehlt" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Der Nutzername ist ungültig." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Er muss zwischen %s und %s Zeichen lang sein." -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Muss mit einem Buchstaben oder einer Zahl beginnen und enden" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kann nur einen Punkt, Unter- oder Bindestrich enthalten." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Die E-Mail-Adresse ist ungültig." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Der PGP-Schlüssel-Fingerabdruck ist ungültig." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Der öffentliche SSH Schlüssel ist ungültig." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Die Zugriffsrechte des Kontos können nicht erweitert werden." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Diese Sprache wird momentan noch nicht unterstützt." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Der Nutzername %s%s%s ist bereits vergeben." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Die Adresse %s%s%s wird bereits verwendet." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Der öffentliche SSH Schlüssel, %s%s%s, ist bereits in Benutzung." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Beim Erstellen des Kontos %s%s%s ist ein Fehler aufgetreten." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Das Konto %s%s%s wurde erfolgreich erstellt." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ein Rücksetzungscode wurde an deine E-Mail-Adresse gesendet." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klicke zur Anmeldung bitte oben auf den Login-Link." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Es wurden keine Änderungen am Konto %s%s%s vorgenommen." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Das Konto %s%s%s wurde erfolgreich bearbeitet." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Das Loginformular ist aktuell für deine IP-Adresse deaktiviert. Ein möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die Unannehmlichkeiten." +msgstr "" +"Das Loginformular ist aktuell für deine IP-Adresse deaktiviert. Ein " +"möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die " +"Unannehmlichkeiten." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto aufgehoben" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Dein Passwort wurde zurückgesetzt. Solltest du ein neues Konto erstellt haben, verwende bitte den Bestätigungslink aus der E-Mail, um dein Passwort festzulegen. Fordere andernfalls bitte einen Rücksetzungscode über die %sPasswort zurücksetzen%s Seite an." +msgstr "" +"Dein Passwort wurde zurückgesetzt. Solltest du ein neues Konto erstellt " +"haben, verwende bitte den Bestätigungslink aus der E-Mail, um dein Passwort " +"festzulegen. Fordere andernfalls bitte einen Rücksetzungscode über die " +"%sPasswort zurücksetzen%s Seite an." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Falscher Nutzername oder falsches Passwort." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Es geschah ein Fehler beim Versuch eine Nutzersitzung zu erstellen." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ungültige Kombination aus E-Mail und Reset-Schlüssel." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Keine" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Konto-Informationen aufrufen für %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Paketbasis ID oder Paketbasis Name fehlen." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Du bist nicht berechtigt diesen Kommentar zu ändern." -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Kommentar existiert nicht" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Kommentar darf nicht leer sein." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentar wurde hinzugefügt." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Du musst angemeldet sein, um Paket-Informationen zu bearbeiten." + +msgid "Missing comment ID." +msgstr "Kommentar-ID fehlt." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Fehler beim Aufrufen der Paket-Details." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paket-Details konnten nicht gefunden werden." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du musst Dich anmelden, um Pakete markieren zu können." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Du hast kein Paket zum Markieren ausgewählt." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" +"Die gewählten Pakete wurden nicht makiert, bitte einen Kommentar eingeben." + msgid "The selected packages have been flagged out-of-date." msgstr "Die gewählten Pakete wurden als \"veraltet\" markiert." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "Du musst Dich anmelden, um die Markierung von Paketen entfernen zu können." +msgstr "" +"Du musst Dich anmelden, um die Markierung von Paketen entfernen zu können." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Du hast kein Paket für das Entfernen der Markierung ausgewählt." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Die Markierungen der gewählten Pakete wurden entfernt." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du hast keine Berechtigung zum Löschen von Paketen." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du hast keine Pakete zum Löschen ausgewählt." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Die gewählten Pakete wurden gelöscht." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du musst angemeldet sein, um Pakete übernehmen zu können." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du musst anmeldet sein, um die Betreuung eines Paketes abzugeben." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du hast keine Pakete zum Übernehmen gewählt." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du hast keine Pakete gewählt, deren Betreuung Du abgeben willst." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Die gewählten Pakete wurde übernommen." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Die Betreuung der gewählten Pakete wurde abgegeben." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du musst angemeldet sein, um für Pakete stimmen zu können." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du musst angemeldet sein, um Pakete abwählen zu können." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du hast keine Pakete zum Wählen markiert." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Deine Stimmen wurden von den markierten Paketen entfernt." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Deine Stimmen wurden für die markierten Pakete gezählt." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Es konnte nichts zur Benachrichtigungsliste hinzugefügt werden." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du wurdest zur Benachrichtigungliste für %s hinzugefügt." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du wurdest von der Benachrichtigungsliste für %s entfernt." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Du musst angemeldet sein, um Paket-Informationen zu bearbeiten." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Kommentar-ID fehlt." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Kommentar wurde gelöscht." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du darfst diesen Kommentar nicht löschen." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Kommentar wurde gelöscht." + msgid "Comment has been edited." msgstr "Kommentar wurde geändert." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Du bist nicht berechtigt die Schlagworte dieser Paketbasis zu ändern." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Die Schlagwörter der Paketbasis wurden aktualisiert." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Du darfst die Mitbetreuer für diese Paketbasis nicht verwalten." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ungültiger Nutzername: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Die Mitbetreuer der Paketbasis wurden aktualisiert." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Paket-Informationen aufrufen für" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "Benötigt %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Du musst angemeldet sein, um Paketanfragen einreichen zu können." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ungültiger Name: Es dürfen nur Kleinbuchstaben verwendet werden." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Das Kommentarfeld darf nicht leer sein." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ungültiger Anfragetyp." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Anfrage erfolgreich hinzugefügt." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ungültiger Grund." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Nur Entwicker und TUs können Anfragen schließen." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Anfrage erfolgreich geschlossen." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Du kannst dieses Formular verwenden, um den AUR Account unwiderruflich zu entfernen %s." +msgstr "" +"Du kannst dieses Formular verwenden, um den AUR Account unwiderruflich zu " +"entfernen %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWARNUNG%s: Diese Aktion kann nicht rückgängig gemacht werden." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Bestätige das Entfernen" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nutzername" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Konto-Typ" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Benutzer" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Entwickler" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Vertrauenswürdiger Benutzer & Entwickler" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "E-Mail-Adresse" -#: template/account_details.php msgid "hidden" msgstr "versteckt" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Echter Name" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC-Name" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP-Schlüssel-Fingerabdruck" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Nicht aktiv seit" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" -#: template/account_details.php msgid "Last Login" msgstr "Letzter Login" -#: template/account_details.php msgid "Never" msgstr "Niemals" -#: template/account_details.php msgid "View this user's packages" msgstr "Alle Pakete dieses Benutzers anzeigen" -#: template/account_details.php msgid "Edit this user's account" msgstr "Konto dieses Nutzers bearbeiten" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchtest." +msgstr "" +"Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchtest." -#: template/account_edit_form.php msgid "required" msgstr "Notwendig" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normaler Benutzer" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Vertrauenswürdiger Benutzer (TU)" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto gesperrt" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "Bitte stell sicher, dass du deine E-Mail korrekt eingegeben hast, sonst wirst du dich aussperren." +msgstr "" +"Bitte stell sicher, dass du deine E-Mail korrekt eingegeben hast, sonst " +"wirst du dich aussperren." -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Verstecke E-Mail-Adresse" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Bestätige das Passwort" -#: template/account_edit_form.php msgid "Language" msgstr "Sprache" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "Die folgende Information wird nur benötigt, wenn du Pakete beim Arch User Repository einreichen willst." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"Die folgende Information wird nur benötigt, wenn du Pakete beim Arch User " +"Repository einreichen willst." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Öffentlicher SSH Schlüssel" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Aktualisieren" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Erstellen" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Zurücksetzen" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Deine Suche enthält leider keine Ergebnisse." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Konto bearbeiten" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Gesperrt" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Ändern" - -#: template/account_search_results.php -msgid "Less" -msgstr "Weniger" - -#: template/account_search_results.php -msgid "More" -msgstr "Mehr" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Keine weiteren Ergebnisse." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Verwalte Ko-Maintainer: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Benutze dieses Formular um Mitbetreuer für %s%s%s hinzuzufügen (ein Benutzername pro Zeile):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Benutzer" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Speichern" - -#: template/header.php -msgid "My Packages" -msgstr "Meine Pakete" - -#: template/header.php -msgid " My Account" -msgstr "Mein Konto" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Paketaktionen" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "PKGBUILD ansehen" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Änderungen betrachten" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Schnappschuss herunterladen" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Durchsuche Wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Als \"veraltet\" markiert" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Paket als \"veraltet\" markieren" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Paketmarkierung entfernen" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Stimme entfernen" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Für dieses Paket stimmen" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Benachrichtigungen deaktivieren" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Über neue Kommentare benachrichtigen" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Aktualisieren" + +msgid "Create" +msgstr "Erstellen" + +msgid "Reset" +msgstr "Zurücksetzen" + +msgid "No results matched your search criteria." +msgstr "Deine Suche enthält leider keine Ergebnisse." + +msgid "Edit Account" +msgstr "Konto bearbeiten" + +msgid "Suspended" +msgstr "Gesperrt" + +msgid "Edit" +msgstr "Ändern" + +msgid "Less" +msgstr "Weniger" + +msgid "More" +msgstr "Mehr" + +msgid "No more results to display." +msgstr "Keine weiteren Ergebnisse." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Benutze dieses Formular um Mitbetreuer für %s%s%s hinzuzufügen (ein " +"Benutzername pro Zeile):" + +msgid "Users" +msgstr "Benutzer" + +msgid "Save" +msgstr "Speichern" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + +msgid "My Packages" +msgstr "Meine Pakete" + +msgid " My Account" +msgstr "Mein Konto" + +msgid "Package Actions" +msgstr "Paketaktionen" + +msgid "View PKGBUILD" +msgstr "PKGBUILD ansehen" + +msgid "View Changes" +msgstr "Änderungen betrachten" + +msgid "Download snapshot" +msgstr "Schnappschuss herunterladen" + +msgid "Search wiki" +msgstr "Durchsuche Wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Paket als \"veraltet\" markieren" + +msgid "Unflag package" +msgstr "Paketmarkierung entfernen" + +msgid "Remove vote" +msgstr "Stimme entfernen" + +msgid "Vote for this package" +msgstr "Für dieses Paket stimmen" + +msgid "Disable notifications" +msgstr "Benachrichtigungen deaktivieren" + msgid "Manage Co-Maintainers" msgstr "Verwalte Ko-Maintainer" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d ausstehende Anfrage" msgstr[1] "%d ausstehende Anfragen" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Paket löschen" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Paket verschmelzen" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Paket übernehmen" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "unbekannt" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Paketbasis Details" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "nur lesen" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Schlüsselwörter" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Eingereicht von" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Betreuer" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Letzter Paketierer" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stimmen" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Beliebtheit" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Zuerst eingereicht am" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Letzte Aktualisierung" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Bearbeite Kommentar für: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Kommentar hinzufügen" -#: template/pkg_comments.php msgid "View all comments" msgstr "Zeige alle Kommentare" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Neueste Kommentare" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s kommentierte %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anonym kommentierte %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "gelöscht am %s von %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "zuletzt geändert am %s von %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" +msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Kommentar löschen" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Alle Kommentare" -#: template/pkg_details.php msgid "Package Details" msgstr "Paket-Details" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paketbasis" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beschreibung" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Besuche die Web-Seite für" -#: template/pkg_details.php msgid "Licenses" msgstr "Lizenzen" -#: template/pkg_details.php msgid "Groups" msgstr "Gruppen" -#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikte" -#: template/pkg_details.php msgid "Provides" msgstr "Liefert" -#: template/pkg_details.php msgid "Replaces" msgstr "Ersetzt" -#: template/pkg_details.php msgid "Dependencies" msgstr "Abhängigkeiten" -#: template/pkg_details.php msgid "Required by" msgstr "Benötigt von" -#: template/pkg_details.php msgid "Sources" msgstr "Quellen" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Anfrage schließen: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Benutze dieses Formular, um die Anfrage für die Paketbasis %s%s%s zu schließen." +msgstr "" +"Benutze dieses Formular, um die Anfrage für die Paketbasis %s%s%s zu " +"schließen." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Anmerkung" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Das Kommentarfeld kann leer gelassen werden, es wird jedoch strengstens empfohlen, beim Ablehnen einer Anfrage einen Kommentar hinzuzufügen." +msgstr "" +"Das Kommentarfeld kann leer gelassen werden, es wird jedoch strengstens " +"empfohlen, beim Ablehnen einer Anfrage einen Kommentar hinzuzufügen." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Grund" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Akzeptiert" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Zurückgewiesen" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Anfrage einreichen: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Benutze dieses Formular um eine Anfrage für die Paketbasis %s%s%s einzureichen, welche die folgenden Pakete enthält:" +msgstr "" +"Benutze dieses Formular um eine Anfrage für die Paketbasis %s%s%s " +"einzureichen, welche die folgenden Pakete enthält:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Anfragetyp" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Löschung" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Verwaist" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Verschmelzen mit" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d Paket gefunden." msgstr[1] "%d Paketanfragen gefunden." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Seite %d von %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Paket" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Eingereicht von" -#: template/pkgreq_results.php msgid "Date" msgstr "Datum" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d Tage verbleibend" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d Stunde verbleibend" msgstr[1] "~%d Stunden verbleibend" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 Stunde verbleibend" -#: template/pkgreq_results.php msgid "Accept" msgstr "Akzeptieren" -#: template/pkgreq_results.php msgid "Locked" msgstr "Gesperrt" -#: template/pkgreq_results.php msgid "Close" msgstr "Schließen" -#: template/pkgreq_results.php msgid "Closed" msgstr "Geschlossen" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Name, Beschreibung" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Nur Name" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Exakter Name" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Exakte Paketbasis" -#: template/pkg_search_form.php msgid "All" msgstr "Alle" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Markiert" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nicht markiert" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Name" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Abgestimmt" -#: template/pkg_search_form.php msgid "Last modified" msgstr "Zuletzt geändert" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Aufsteigend" -#: template/pkg_search_form.php msgid "Descending" msgstr "Absteigend" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Suchkriterien eingeben" -#: template/pkg_search_form.php msgid "Search by" msgstr "Suche nach" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Veraltet" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortieren nach" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Neu ordnen" -#: template/pkg_search_form.php msgid "Per page" msgstr "Pro Seite" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Los" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Verwaiste Pakete" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fehler beim Aufrufen der Paket-Liste." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Keine Pakete entsprachen deinen Suchkriterien." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d Paket gefunden." msgstr[1] "%d Pakete gefunden." -#: template/pkg_search_results.php msgid "Version" msgstr "Version" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "Die Beliebtheit berechnet sich als Summe aller Stimmen, wobei jede Stimme mit einem Faktor von 0,98 pro Tag seit der Erstellung gewichtet wird." +msgstr "" +"Die Beliebtheit berechnet sich als Summe aller Stimmen, wobei jede Stimme " +"mit einem Faktor von 0,98 pro Tag seit der Erstellung gewichtet wird." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Ja" -#: template/pkg_search_results.php msgid "orphan" msgstr "Verwaist" -#: template/pkg_search_results.php msgid "Actions" msgstr "Aktionen" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Als \"veraltet\" markieren" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "\"veraltet\"-Markierung entfernen" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Pakete übernehmen" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Betreuung der Pakete abgeben" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Pakete löschen" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Bestätige" -#: template/search_accounts_form.php msgid "Any type" msgstr "Beliebiger Typ" -#: template/search_accounts_form.php msgid "Search" msgstr "Suche" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiken" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Verwaiste Pakete" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakete, die in den letzten 7 Tagen hinzugefügt wurden" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakete, die in den letzten 7 Tagen aktualisiert wurden" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakete, die im letzten Jahr aktualisiert wurden" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pakete, die nie aktualisiert wurden" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrierte Benutzer" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Vertrauenswürdige Benutzer (TU)" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Letzte Aktualisierungen" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Meine Statistiken" -#: template/tu_details.php msgid "Proposal Details" msgstr "Vorschlag-Details" -#: template/tu_details.php msgid "This vote is still running." msgstr "Diese Abstimmung läuft noch." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Eingereicht: %s von %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Ende" -#: template/tu_details.php msgid "Result" msgstr "Ergebnis" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nein" -#: template/tu_details.php msgid "Abstain" msgstr "Enthalten" -#: template/tu_details.php msgid "Total" msgstr "Insgesamt" -#: template/tu_details.php msgid "Participation" msgstr "Teilnahme" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Letzte Stimme vom TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Letzte Stimme" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Keine Ergebnisse gefunden" -#: template/tu_list.php msgid "Start" msgstr "Beginn" -#: template/tu_list.php msgid "Back" msgstr "Zurück" diff --git a/po/el.po b/po/el.po index d869ec23..6d0c9a44 100644 --- a/po/el.po +++ b/po/el.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Achilleas Pipinellis, 2014 # Achilleas Pipinellis, 2013 @@ -14,1799 +14,1440 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" +"Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: el\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Η σελίδα δε βρέθηκε" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Μας συγχωρείτε, η σελίδα που ζητήσατε δεν υπάρχει." -#: html/503.php msgid "Service Unavailable" msgstr "" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" -#: html/account.php msgid "Account" msgstr "" -#: html/account.php template/header.php msgid "Accounts" msgstr "Λογαριασμοί" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Δεν σας επιτρέπεται η πρόσβαση σε αυτήν την περιοχή." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Δεν ήταν δυνατή η λήψη πληροφοριών για αυτόν τον χρήστη." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Δεν έχετε την άδεια να επεξεργαστείτε αυτόν τον λογαριασμό." -#: html/account.php msgid "Use this form to search existing accounts." -msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να αναζητήσετε υπάρχοντες λογαριασμούς." +msgstr "" +"Χρησιμοποιήστε αυτή τη φόρμα για να αναζητήσετε υπάρχοντες λογαριασμούς." -#: html/account.php msgid "You must log in to view user information." msgstr "Πρέπει να συνδεθείτε για να δείτε πληροφορίες χρήστη." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Προσθέστε Πρόταση" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Μη έγκυρο διακριτικό για την ενέργεια του χρήστη." -#: html/addvote.php msgid "Username does not exist." msgstr "Αυτό το όνομα χρήστη δεν υπάρχει." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s έχει ήδη πρόταση σε εξέλιξη για αυτό το θέμα." -#: html/addvote.php msgid "Invalid type." msgstr "Άκυρος τύπος." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Η πρόταση δεν μπορεί να είναι κενή." -#: html/addvote.php msgid "New proposal submitted." msgstr "Υποβλήθηκε νέα πρόταση." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Υποβάλετε μία πρόταση προς ψήφιση." -#: html/addvote.php msgid "Applicant/TU" msgstr "Αιτών / TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(κενό εάν δεν είναι εφαρμόσιμο)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Είδος" -#: html/addvote.php msgid "Addition of a TU" msgstr "Προσθήκη ενός TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Αφαίρεση ενός TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Αφαίρεση ενός TU (αδήλωτη αδράνεια)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Τροποποίηση των " -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Πρόταση" -#: html/addvote.php msgid "Submit" msgstr "Υποβολή" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Αρχική" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Καλωσήρθατε στο AUR! Διαβάστε παρακαλώ τον %sOδηγό Χρηστών του AUR%s και τον %sΟδηγό των Trusted Users%s για περισσότερες πληροφορίες. " +msgstr "" +"Καλωσήρθατε στο AUR! Διαβάστε παρακαλώ τον %sOδηγό Χρηστών του AUR%s και τον " +"%sΟδηγό των Trusted Users%s για περισσότερες πληροφορίες. " -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Τα συνεισφέροντα PKGBUILDs %sπρέπει%s να ακολουθούν τα %sΠρότυπα δημιουργίας πακέτων του Arch%s αλλιώς θα διαγράφονται! " +msgstr "" +"Τα συνεισφέροντα PKGBUILDs %sπρέπει%s να ακολουθούν τα %sΠρότυπα δημιουργίας " +"πακέτων του Arch%s αλλιώς θα διαγράφονται! " -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Θυμηθείτε να ψηφίσετε τα αγαπημένα σας πακέτα!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Ορισμένα πακέτα μπορεί να μεταφερθούν ως binaries στο [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "ΑΠΟΠΟΙΗΣΗ ΕΥΘΥΝΗΣ" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" msgstr "" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Συζήτηση" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Αναφορά Σφαλμάτων" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Αναζήτηση Πακέτου" -#: html/index.php msgid "Adopt" msgstr "Υιοθέτηση" -#: html/index.php msgid "Vote" msgstr "Ψηφίστε" -#: html/index.php msgid "UnVote" msgstr "Αναίρεση ψήφου" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Ειδοποίηση" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Διακοπή Ειδοποίησης" -#: html/index.php msgid "UnFlag" msgstr "Αποχαρακτήριση" -#: html/login.php template/header.php msgid "Login" msgstr "Σύνδεση" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Έχετε συνδεθεί ως: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Αποσύνδεση" -#: html/login.php msgid "Enter login credentials" msgstr "Εισάγετε πιστοποιητικά εισόδου" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Κωδικός" -#: html/login.php msgid "Remember me" msgstr "Θυμήσου με" -#: html/login.php msgid "Forgot Password" msgstr "Ξεχάσατε τον κωδικό σας" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Το HTTP είναι απενεργοποιημένο. Παρακαλώ %sγυρίστε σε HTTPs%s αν θέλετε να εισέλθετε." +msgstr "" +"Το HTTP είναι απενεργοποιημένο. Παρακαλώ %sγυρίστε σε HTTPs%s αν θέλετε να " +"εισέλθετε." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Κριτήρια Αναζήτησης" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Πακέτα" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Σφάλμα στη διαδικασία λήψης των πληροφοριών του πακέτου." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Λείπει ένα απαραίτητο πεδίο." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." -msgstr "Οι τιμές που εισαγάγατε στα πεδία “κωδικού” και “επιβεβαίωσης κωδικού” δεν είναι ίδιες." +msgstr "" +"Οι τιμές που εισαγάγατε στα πεδία “κωδικού” και “επιβεβαίωσης κωδικού” δεν " +"είναι ίδιες." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Ο κωδικός πρέπει να αποτελείται τουλάχιστον %s χαρακτήρες." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Μη έγκυρο e-mail." -#: html/passreset.php msgid "Password Reset" msgstr "Επαναφορά Κωδικού" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Ελέγξτε το e-mail σας για το σύνδεσμο επιβεβαίωσης." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Το συνθηματικό σας έχει επαναφερθεί με επιτυχία." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Παρακαλώ επιβεβαιώστε την διεύθυνση e-mail σας:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Εισάγετε νέο κωδικό" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Επιβεβαιώστε το νέο σας συνθηματικό:" -#: html/passreset.php msgid "Continue" msgstr "Συνεχίστε" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Εάν έχετε ξεχάσει την ηλεκτρονική διεύθυνση που χρησιμοποιήσατε για να εγγραφείτε, παρακαλώ στείλτε ένα μήνυμα στη λίστα ταχυδρομείου %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Εάν έχετε ξεχάσει την ηλεκτρονική διεύθυνση που χρησιμοποιήσατε για να " +"εγγραφείτε, παρακαλώ στείλτε ένα μήνυμα στη λίστα ταχυδρομείου %saur-general" +"%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Εισάγετε την διεύθυνση e-mail σας:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Δεν μπορεί να βρεθεί το πακέτο για τη συγχώνευση ψήφων και σχόλιων" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Τα επιλεγμένα πακέτα δεν έχουν διαγραφεί, παρακαλώ ελέγξτε το κουτάκι επιβεβαίωσης." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Τα επιλεγμένα πακέτα δεν έχουν διαγραφεί, παρακαλώ ελέγξτε το κουτάκι " +"επιβεβαίωσης." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Διαγραφή Πακέτου" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Διαγράψτε Πακέτο: %s" +msgid "Delete Package" +msgstr "Διαγράψτε πακέτο" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Η διαγραφή ενός πακέτου είναι μόνιμη." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Επιλέξτε το κουτάκι για να επιβεβαιώσετε." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Επιβεβαιώστε τη διαγραφή του πακέτου" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Διαγράψτε" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Μόνο οι Trusted Users και οι Developers μπορούν να διαγράψουν πακέτα." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Aποδεσμεύστε το Πακέτο" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "Αποδέσμευση" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "" -#: html/pkgflag.php msgid "Flag" msgstr "Επισήμανση" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Συγχώνευση Πακέτου" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Συγχώνευσε Πακέτο: %s" +msgid "Merge Package" +msgstr "Συγχώνευση πακέτου" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Μόλις το πακέτο συγχωνευτεί, η διαδικασία δεν μπορεί να αντιστραφεί." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Εισάγετε το όνομα του πακέτου με το οποίο επιθυμείτε να συγχωνεύσετε το τρέχον πακέτο." +msgstr "" +"Εισάγετε το όνομα του πακέτου με το οποίο επιθυμείτε να συγχωνεύσετε το " +"τρέχον πακέτο." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Συγχωνεύστε σε:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Επιβεβαιώστε τη συγχώνευση του πακέτου" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Συγχώνευση" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "Μόνο οι Trusted Users και οι Developers μπορούν να συγχωνεύσουν πακέτα." +msgstr "" +"Μόνο οι Trusted Users και οι Developers μπορούν να συγχωνεύσουν πακέτα." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" +msgid "Submit Request" msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Πρώτο" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Προηγούμενο" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Επόμενο" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Τελευταίο" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" -#: html/register.php template/header.php msgid "Register" msgstr "Εγγραφείτε" -#: html/register.php msgid "Use this form to create an account." msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να δημιουργήσετε λογαριασμό." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Δεν ήταν δυνατή η ανάκτηση των στοιχείων της πρότασης." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Η ψηφοφορία έχει κλείσει για αυτή την πρόταση." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Μόνο οι Trusted Users έχουν δικαίωμα ψήφου." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Δεν μπορείτε να ψηφίσετε σε μία πρόταση που αφορά σε εσάς." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Έχετε ήδη ψηφίσει για αυτή τη πρόταση." -#: html/tu.php msgid "Vote ID not valid." msgstr "Το ID της ψήφου δεν είναι έγκυρο." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Τρέχουσες ψήφοι" -#: html/tu.php msgid "Past Votes" msgstr "Παρελθόντες ψήφοι" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Ψηφίσαντες" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Η εγγραφή λογαριασμών έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω επιθέσεων spam. Μας συγχωρείτε για την ενόχληση." +msgstr "" +"Η εγγραφή λογαριασμών έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω " +"επιθέσεων spam. Μας συγχωρείτε για την ενόχληση." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Λείπει το ID Χρήστη" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Το όνομα χρήστη δεν είναι έγκυρο." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Πρέπει να αποτελείται από %s έως %s χαρακτήρες" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Ξεκινήστε και τελειώστε με γράμμα ή αριθμό" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Μπορεί να περιλαμβάνει μόνο μία τελεία, κάτω παύλα ή παύλα." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Αυτή η διεύθυνση email δεν είναι έγκυρη." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Το fingerprint του PGP κλειδιού δεν είναι έγκυρο." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Δε γίνεται να αυξηθούν τα δικαιώματα του λογαριασμού" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Η γλώσσα αυτή δεν υποστηρίζεται ακόμη." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Το όνομα, %s%s%s, χρησιμοποιείται ήδη." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Η διεύθυνση, %s%s%s, χρησιμοποιείται ήδη." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Σφάλμα κατά τη δημιουργία του λογαριασμού, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Ο λογαριασμός, %s%s%s, δημιουργήθηκε επιτυχώς." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "Ένα κλειδί επαναφοράς του κωδικού έχει σταλεί στην ηλεκτρονική σας διεύθυνση." +msgstr "" +"Ένα κλειδί επαναφοράς του κωδικού έχει σταλεί στην ηλεκτρονική σας διεύθυνση." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "Πατήστε στον παραπάνω σύνδεσμο Σύνδεση για να χρησιμοποιήσετε το λογαριασμό σας." +msgstr "" +"Πατήστε στον παραπάνω σύνδεσμο Σύνδεση για να χρησιμοποιήσετε το λογαριασμό " +"σας." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Δεν έγιναν αλλαγές στο λογαριασμό, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Ο λογαριασμός, %s%s%s, τροποποποιήθηκε επιτυχώς." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Η σύνδεση στο λογαριασμό σας έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω επιθέσεων spam. Μας συγχωρείτε για την ταλαιπωρία." +msgstr "" +"Η σύνδεση στο λογαριασμό σας έχει απενεργοποιηθεί για την IP σας, πιθανόν " +"λόγω επιθέσεων spam. Μας συγχωρείτε για την ταλαιπωρία." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Ο λογαριασμός έχει ανασταλεί" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Η επαναφορά του κωδικού σας έχει πραγματοποιηθεί. Αν μόλις δημιουργήσατε ένα νέο λογαρισμό, παρακαλώ χρησιμοποιείστε τον σύνδεσμο από το email ενεργοποίησης για να ορίσετε έναν αρχικό κωδικό. Διαφορετικά, παρακαλείσθε να ζητήσετε ένα κλειδί επαναφοράς στη σελίδα %sPassword Reset%s." +msgstr "" +"Η επαναφορά του κωδικού σας έχει πραγματοποιηθεί. Αν μόλις δημιουργήσατε ένα " +"νέο λογαρισμό, παρακαλώ χρησιμοποιείστε τον σύνδεσμο από το email " +"ενεργοποίησης για να ορίσετε έναν αρχικό κωδικό. Διαφορετικά, παρακαλείσθε " +"να ζητήσετε ένα κλειδί επαναφοράς στη σελίδα %sPassword Reset%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Λάθος όνομα χρήστη ή συνθηματικό." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ένα σφάλμα προέκυψε προσπαθώντας να δημιουργήσετε μια συνεδρία χρήστη." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Μη έγκυρο e-mail και συνδυασμός κλειδιού επαναφοράς" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Κανένα" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Δείτε τις πληροφορίες λογαριασμού του %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Το σχόλιο έχει προστεθεί." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "" +"Πρέπει να έχετε συνδεθεί για να προσπαθήσετε να επεξεργαστείτε τις " +"πληροφορίες του πακέτου." + +msgid "Missing comment ID." +msgstr "Λείπει το ID του σχολίου." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Σφάλμα κατά τη διάρκεια φόρτωσης των πληροφοριών του πακέτου." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Οι πληροφορίες του πακέτου δεν μπόρεσαν να βρεθούν." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Πρέπει να έχετε συνδεθεί για να επισημάνετε τα πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Δεν επιλέξατε κάποιο πακέτο για επισήμανση." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Τα συγκεκριμένα πακέτα έχουν επισημανθεί ως παρωχημένα." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να αποχαρακτηρίσετε πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Δεν επιλέξατε κάποιο πακέτο για να αποχαρακτηρίσετε." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Τα συγκεκριμένα πακέτα έχουν αποεπισημανθεί." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Δεν έχετε τα απαραίτητα δικαιώματα για να διαγράψετε τα πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Δεν επιλέξατε κάποιο πακέτο για να διαγράψετε." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Tα επιλεγμένα πακέτα έχουν διαγραφεί." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να υιοθετήσετε πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να αποδεσμεύσετε πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Δεν επιλέξατε κανένα πακέτο για να υιοθετήσετε." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Δεν επιλέξατε κάποιο πακέτο για απόρριψη." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Τα επιλεγμένα πακέτα έχουν υιοθετηθεί." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Τα επιλεγμένα πακέτα έχουν αποδεσμευθεί." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να ψηφίσετε για πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να ακυρώσετε την ψήφο σας για πακέτα." +msgstr "" +"Πρέπει να έχετε συνδεθεί για να μπορέσετε να ακυρώσετε την ψήφο σας για " +"πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Δεν επιλέξατε κάποιο πακέτο για να το ψηφίσετε." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Οι ψήφοι σας έχουν αφαιρεθεί από τα επιλεγμένα πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Οι ψήφοι σας προστέθηκαν στα επιλεγμένα πακέτα." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Δεν ήταν δυνατή η προσθήκη του στη λίστα ειδοποίησης." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Έχετε προστεθεί στη λίστα ειδοποίησης σχολίων για το %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Έχετε αφαιρεθεί από τη λίστα ειδοποίησης σχολίων για το %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Πρέπει να έχετε συνδεθεί για να προσπαθήσετε να επεξεργαστείτε τις πληροφορίες του πακέτου." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Λείπει το ID του σχολίου." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Το σχόλιο έχει διαγραφεί." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Δεν σας επιτρέπεται να διαγράψετε αυτό το σχόλιο." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Το σχόλιο έχει διαγραφεί." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Δείτε τις λεπτομέρειες πακέτου για το" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Μη έγκυρο όνομα: μόνο πεζοί χαρακτήρες επιτρέπονται." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Όνομα χρήστη" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Είδος λογαριασμού" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Χρήστης" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Developer" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Διεύθυνση email" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Πραγματικό 'Ονομα" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Ψευδώνυμο IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP Key Fingerprint" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Κατάσταση" -#: template/account_details.php msgid "Inactive since" msgstr "Αδρανής από" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Ενεργός" -#: template/account_details.php msgid "Last Login" msgstr "Τελευταία σύνδεση" -#: template/account_details.php msgid "Never" msgstr "Ποτέ" -#: template/account_details.php msgid "View this user's packages" msgstr "Δείτε τα πακέτα αυτού του χρήστη" -#: template/account_details.php msgid "Edit this user's account" msgstr "Τροποποιήστε το λογαριασμό αυτού του χρήστη" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "απαιτούμενο" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Απλός χρήστης" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Αξιόπιστος χρήστης" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Ο Λογαριασμός έχει Ανασταλεί." -#: template/account_edit_form.php msgid "Inactive" msgstr "Αδρανής" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Πληκτρολογήστε ξανά τον κωδικό σας." -#: template/account_edit_form.php msgid "Language" msgstr "Γλώσσα" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Ειδοποίησε για νέα σχόλια" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Eνημέρωση" -#: template/account_edit_form.php msgid "Create" msgstr "Δημιουργήστε" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Επαναφορά" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Δε βρέθηκε αποτέλεσμα που να ικανοποιεί τα κριτήρια αναζήτησης." -#: template/account_search_results.php msgid "Edit Account" msgstr "Τροποποίηση Λογαριασμού" -#: template/account_search_results.php msgid "Suspended" msgstr "Έχει ανασταλεί" -#: template/account_search_results.php msgid "Edit" msgstr "Επεξεργασία" -#: template/account_search_results.php msgid "Less" msgstr "Λιγότερο" -#: template/account_search_results.php msgid "More" msgstr "Περισσότερα" -#: template/account_search_results.php msgid "No more results to display." msgstr "Δεν υπάρχουν άλλα αποτελέσματα για να δείτε." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Τα πακέτα μου" -#: template/header.php msgid " My Account" msgstr "Ο λογαριασμός μου" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ενέργειες Πακέτου" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Δείτε το PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Επισημάνθηκε ως παρωχημένο" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Επισημάνετε ως παρωχημένο" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Αποχαρακτηρίστε ως παρωχημένο" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Αφαιρέστε ψήφο" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Ψηφίστε για αυτό το πακέτο" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Απενεργοποιήστε τις ειδοποιήσεις" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Ειδοποίησε για νέα σχόλια" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Διαγράψτε πακέτο" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Συγχώνευση πακέτου" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Υιοθετήστε το Πακέτο" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "άγνωστο" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Λέξεις κλειδιά" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Υποβάλλων" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Συντηρητής" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Ψήφοι" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Πρώτη Υποβολή" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Τελευταία Ενημέρωση" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Προσθέστε σχόλιο" -#: template/pkg_comments.php msgid "View all comments" msgstr "" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Τελευταία σχόλια" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Διαγράψτε το σχόλιο" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Όλα τα σχόλια" -#: template/pkg_details.php msgid "Package Details" msgstr "Πληροφορίες Πακέτου" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Περιγραφή" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Επισκεφτείτε την ιστοσελίδα για " -#: template/pkg_details.php msgid "Licenses" msgstr "" -#: template/pkg_details.php msgid "Groups" msgstr "" -#: template/pkg_details.php msgid "Conflicts" msgstr "" -#: template/pkg_details.php msgid "Provides" msgstr "" -#: template/pkg_details.php msgid "Replaces" msgstr "" -#: template/pkg_details.php msgid "Dependencies" msgstr "Εξαρτήσεις" -#: template/pkg_details.php msgid "Required by" msgstr "Απαιτείται από" -#: template/pkg_details.php msgid "Sources" msgstr "Πηγές" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Δεκτός" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Απορριπτέος" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "" -#: template/pkgreq_form.php msgid "Deletion" msgstr "" -#: template/pkgreq_form.php msgid "Orphan" msgstr "" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Συγχώνευση σε" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" -#: template/pkgreq_results.php msgid "Package" msgstr "" -#: template/pkgreq_results.php msgid "Filed by" msgstr "" -#: template/pkgreq_results.php msgid "Date" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" -#: template/pkgreq_results.php msgid "Accept" msgstr "" -#: template/pkgreq_results.php msgid "Locked" msgstr "" -#: template/pkgreq_results.php msgid "Close" msgstr "" -#: template/pkgreq_results.php msgid "Closed" msgstr "" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Όνομα, Περιγραφή" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Όνομα μόνο" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" -#: template/pkg_search_form.php msgid "All" msgstr "Όλα" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Σημειωμένα" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Μη Σημειωμένα" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Όνομα" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Ψηφισμένο" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Αύξουσα" -#: template/pkg_search_form.php msgid "Descending" msgstr "Φθίνουσα" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Εισάγετε κριτήρια αναζήτησης" -#: template/pkg_search_form.php msgid "Search by" msgstr "Αναζήτηση κατά" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Παρωχημένα" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ταξινόμηση κατά" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Σειρά ταξινόμησης" -#: template/pkg_search_form.php msgid "Per page" msgstr "Ανά σελίδα" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Πήγαινε" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Ορφανά" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Σφάλμα κατά τη λήψη της λίστας πακέτων." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Κανένα πακέτο δεν ικανοποιεί τα κριτήρια αναζήτησης σας." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" -#: template/pkg_search_results.php msgid "Version" msgstr "Έκδοση" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Ναι" -#: template/pkg_search_results.php msgid "orphan" msgstr "ορφανό" -#: template/pkg_search_results.php msgid "Actions" msgstr "Ενέργειες" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Επισημάνετε ως Παρωχημένο" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Αποχαρακτηρίστε το πακέτο ως Παρωχημένο" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Υιοθετήστε Πακέτα" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Aποδεσμεύστε Πακέτα" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Διαγράψτε Πακέτα" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Επιβεβαιώστε" -#: template/search_accounts_form.php msgid "Any type" msgstr "Κάθε είδος" -#: template/search_accounts_form.php msgid "Search" msgstr "Αναζήτηση" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Στατιστικά" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Ορφανά Πακέτα" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Πακέτα που προστέθηκαν τις τελευταίες 7 ημέρες" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Πακέτα που ενημερώθηκαν τις τελευταίες 7 ημέρες" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Πακέτα που ενημερώθηκαν κατά το παρελθόν έτος" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Πακέτα που δεν ενημερώθηκαν ποτέ" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Εγγεγραμμένοι Χρήστες" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Πρόσφατες Ανανεώσεις" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Τα στατιστικά μου" -#: template/tu_details.php msgid "Proposal Details" msgstr "Πληροφορίες Πρότασης" -#: template/tu_details.php msgid "This vote is still running." msgstr "Η ψηφοφορία αυτή βρίσκεται ακόμη σε εξέλιξη." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Υποβλήθηκε: %s από %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Τέλος" -#: template/tu_details.php msgid "Result" msgstr "Αποτέλεσμα" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Όχι" -#: template/tu_details.php msgid "Abstain" msgstr "Απέχουν" -#: template/tu_details.php msgid "Total" msgstr "Σύνολο" -#: template/tu_details.php msgid "Participation" msgstr "Συμμετοχή" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Κανένα αποτέλεσμα δεν βρέθηκε." -#: template/tu_list.php msgid "Start" msgstr "Ξεκινήστε" -#: template/tu_list.php msgid "Back" msgstr "Πίσω" diff --git a/po/es.po b/po/es.po index 77bb9992..6e70688f 100644 --- a/po/es.po +++ b/po/es.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Adolfo Jayme Barrientos, 2015 # Angel Velasquez , 2011 @@ -15,1799 +15,1506 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/es/)\n" +"Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" +"es/)\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Página no encontrada" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "La página solicitada no existe." -#: html/503.php msgid "Service Unavailable" msgstr "Servicio no disponible" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "¡No te asustes! El sitio está desactivado por tareas de mantenimiento. Volveremos pronto." +msgstr "" +"¡No te asustes! El sitio está desactivado por tareas de mantenimiento. " +"Volveremos pronto." -#: html/account.php msgid "Account" msgstr "Cuenta" -#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentas" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No estás autorizado para acceder a esta área." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No se pudo obtener la información del usuario especificado." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "No tienes los permisos para editar esta cuenta." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa este formulario para buscar cuentas existentes." -#: html/account.php msgid "You must log in to view user information." msgstr "Debes autentificarte para ver la información del usuario." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Añadir propuesta" -#: html/addvote.php msgid "Invalid token for user action." msgstr "La ficha no es válida para la acción de usuario." -#: html/addvote.php msgid "Username does not exist." msgstr "El nombre de usuario no existe." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ya tiene una propuesta activa." -#: html/addvote.php msgid "Invalid type." msgstr "Tipo no válido." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta no puede estar vacía." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nueva propuesta enviada." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Envía una propuesta a la cual votar." -#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/Usuario de confianza (TU)" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" -#: html/addvote.php msgid "Addition of a TU" msgstr "Agregar a un nuevo usuario de confianza" -#: html/addvote.php msgid "Removal of a TU" msgstr "Remover a un usuario de confianza" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remover a un usuario de confianza (no declarado inactivo)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Enmienda a los Estatutos" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" -#: html/addvote.php msgid "Submit" msgstr "Subir" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Administrar coencargados" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Editar comentario" -#: html/home.php template/header.php msgid "Home" msgstr "Inicio" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "¡Bienvenido al repositorio de usuarios de Arch! Léase las %sDirectrices del usuario del AUR%s y las %sDirectrices del usuario de confianza del AUR%s para mayor información." +msgstr "" +"¡Bienvenido al repositorio de usuarios de Arch! Léase las %sDirectrices del " +"usuario del AUR%s y las %sDirectrices del usuario de confianza del AUR%s " +"para mayor información." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de empaquetado de Arch%s de otra forma serán eliminados." +msgstr "" +"Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de " +"empaquetado de Arch%s de otra forma serán eliminados." -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerda votar tus paquetes favoritos!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Algunos paquetes pueden estar provistos de forma binaria en [community]." +msgstr "" +"Algunos paquetes pueden estar provistos de forma binaria en [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Los paquetes del AUR son producidos por los usuarios. Cualquier uso de los " +"archivos de estos es a tu propio riesgo." -#: html/home.php msgid "Learn more..." msgstr "Más información…" -#: html/home.php msgid "Support" msgstr "Ayuda" -#: html/home.php msgid "Package Requests" msgstr "Solicitudes para los paquetes" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Hay tres tipos de solicitudes que puedes presentar en el cuadro %sAcciones del paquete%s en la página de detalles del paquete:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Hay tres tipos de solicitudes que puedes presentar en el cuadro %sAcciones " +"del paquete%s en la página de detalles del paquete:" -#: html/home.php msgid "Orphan Request" msgstr "Solicitud de orfandad" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está inactivo y el paquete se ha marcado como desactualizado por un largo tiempo." +msgstr "" +"Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está " +"inactivo y el paquete se ha marcado como desactualizado por un largo tiempo." -#: html/home.php msgid "Deletion Request" msgstr "Solicitud de eliminación" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Solicitar la eliminación de un paquete del repositorio de usuarios de Arch. No utilices esta opción si un paquete está roto pero puede ser arreglado fácilmente. En cambio, contacta al encargado del paquete y presenta una solicitud de orfandad si es necesario." +msgstr "" +"Solicitar la eliminación de un paquete del repositorio de usuarios de Arch. " +"No utilices esta opción si un paquete está roto pero puede ser arreglado " +"fácilmente. En cambio, contacta al encargado del paquete y presenta una " +"solicitud de orfandad si es necesario." -#: html/home.php msgid "Merge Request" msgstr "Solicitud de unión" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Solicitar que un paquete sea unido con otro. Puede ser utilizado cuando un paquete tiene que ser cambiado de nombre o sustituido por un paquete dividido." +msgstr "" +"Solicitar que un paquete sea unido con otro. Puede ser utilizado cuando un " +"paquete tiene que ser cambiado de nombre o sustituido por un paquete " +"dividido." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Si quieres discutir una solicitud, puedes utilizar la lista de correo %saur-requests%s. Sin embargo, por favor no utilices esa lista para presentar solicitudes." +msgstr "" +"Si quieres discutir una solicitud, puedes utilizar la lista de correo %saur-" +"requests%s. Sin embargo, por favor no utilices esa lista para presentar " +"solicitudes." -#: html/home.php msgid "Submitting Packages" msgstr "Subir paquetes" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Ahora se utiliza Git sobre SSH para subir paquetes al AUR. Véase la sección %sSubir paquetes%s de la wiki del repositorio de usuarios de Arch para más detalles." +msgstr "" +"Ahora se utiliza Git sobre SSH para subir paquetes al AUR. Véase la sección " +"%sSubir paquetes%s de la wiki del repositorio de usuarios de Arch para más " +"detalles." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Las siguientes huellas SSH están en uso para AUR." -#: html/home.php msgid "Discussion" msgstr "Debate" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "La discusión general sobre el repositorio de usuarios de Arch (AUR) y la estructura de usuarios de confianza se realiza en la lista de correos %saur-general%s. Para la discusión en relación con el desarrollo de la interfaz web del AUR, utiliza la lista de correo %saur-dev%s." +msgstr "" +"La discusión general sobre el repositorio de usuarios de Arch (AUR) y la " +"estructura de usuarios de confianza se realiza en la lista de correos %saur-" +"general%s. Para la discusión en relación con el desarrollo de la interfaz " +"web del AUR, utiliza la lista de correo %saur-dev%s." -#: html/home.php msgid "Bug Reporting" msgstr "Informe de errores" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" +"Si encuentras un error en la interfaz web del AUR, llena un informe de error " +"en nuestro %srastreador de errores o «bug tracker»%s. Usa este para reportar " +"%súnicamente%s errores de la interfaz web del AUR. Para reportar errores de " +"empaquetado debes contactar al encargado o dejar un comentario en la página " +"respectiva del paquete." -#: html/home.php msgid "Package Search" msgstr "Buscar paquetes" -#: html/index.php msgid "Adopt" msgstr "Adoptar" -#: html/index.php msgid "Vote" msgstr "Votar" -#: html/index.php msgid "UnVote" msgstr "Retirar voto" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Quitar notificación" -#: html/index.php msgid "UnFlag" msgstr "Desmarcar" -#: html/login.php template/header.php msgid "Login" msgstr "Autentificarte" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificado como: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Salir" -#: html/login.php msgid "Enter login credentials" msgstr "Proporciona tus datos de acceso" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Nombre de usuario y dirección de correo" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" -#: html/login.php msgid "Remember me" msgstr "Recordarme" -#: html/login.php msgid "Forgot Password" msgstr "¿Olvidaste tu contraseña?" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "La autentificación por HTTP está deshabilitada. %scambia a HTTPS%s si deseas autentificarte" +msgstr "" +"La autentificación por HTTP está deshabilitada. %scambia a HTTPS%s si deseas " +"autentificarte" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criterio de búsqueda" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "No se pudieron recuperar correctamente los detalles del paquete." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campo obligatorio." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Los campos de la contraseña no coinciden." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Tu contraseña debe tener como mínimo %s letras." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Dirección de correo no válida." -#: html/passreset.php msgid "Password Reset" msgstr "Restablecer la contraseña" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Comprueba tu correo para ver el enlace de confirmación." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Se ha restablecido la contraseña correctamente." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirma tu dirección de correo:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Escribe tu contraseña nueva:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirma la contraseña nueva:" -#: html/passreset.php msgid "Continue" msgstr "Continuar" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si olvidaste la dirección de correo que usaste para registrarte, envía un mensaje a la %slista de correo aur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Si olvidaste la dirección de correo que usaste para registrarte, envía un " +"mensaje a la %slista de correo aur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduce tu dirección de correo:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "Los paquetes seleccionados no se han abandonado, marca la casilla de confirmación." +msgstr "" +"Los paquetes seleccionados no se han abandonado, marca la casilla de " +"confirmación." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "No se puede encontrar el paquete para unir los votos y comentarios en él." +msgstr "" +"No se puede encontrar el paquete para unir los votos y comentarios en él." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "No se puede unir un paquete base consigo mismo." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Los paquetes seleccionados no han sido eliminados, comprueba la casilla de confirmación." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Los paquetes seleccionados no han sido eliminados, comprueba la casilla de " +"confirmación." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminación de paquetes" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Eliminar paquete: %s" +msgid "Delete Package" +msgstr "Eliminar paquete" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Usa este formulario para eliminar el paquete base %s%s%s y los siguientes paquetes en el AUR:" +msgstr "" +"Usa este formulario para eliminar el paquete base %s%s%s y los siguientes " +"paquetes en el AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El eliminado de un paquete es permanente." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Selecciona la casilla para confirmar la acción." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirma la eliminación del paquete" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Eliminar" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "Solamente usuarios de confianza y desarrolladores pueden eliminar paquetes." +msgstr "" +"Solamente usuarios de confianza y desarrolladores pueden eliminar paquetes." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar paquete" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Abandonar paquete: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Utiliza este formulario para abandonar el paquete base %s %s %s que incluye los siguientes paquetes:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Utiliza este formulario para abandonar el paquete base %s %s %s que incluye " +"los siguientes paquetes:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Al seleccionar la casilla de verificación, confirmas que deseas abandonar el paquete y transferir su propiedad a %s%s%s." +msgstr "" +"Al seleccionar la casilla de verificación, confirmas que deseas abandonar el " +"paquete y transferir su propiedad a %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Al seleccionar la casilla de verificación, confirmas que deseas abandonar el paquete." +msgstr "" +"Al seleccionar la casilla de verificación, confirmas que deseas abandonar el " +"paquete." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirma para abandonar el paquete" -#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "Solamente usuarios de confianza y desarrolladores puede forzar el abandono de paquetes." +msgstr "" +"Solamente usuarios de confianza y desarrolladores puede forzar el abandono " +"de paquetes." + +msgid "Flag Comment" +msgstr "" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Marcado como desactualizado" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" +"Usa este formulario para marcar el paquete base %s%s%s y los siguientes " +"paquetes en el AUR como desactualizados:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"%sNo%s uses el formulario para reportar fallos. Usa los comentarios del " +"paquete para ello." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Introduce el porqué del marcado del paquete como desactualizado, " +"peferiblentemente incluye un enlace al anuncio de la nueva versión o al " +"paquete comprimido." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" -msgstr "Comentario" +msgstr "Comentarios" -#: html/pkgflag.php msgid "Flag" msgstr "Marcar" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "Solamente los usuario registrados pueden marcar como desactualizado." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Unión de paquetes" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Unir paquete: %s" +msgid "Merge Package" +msgstr "Unir paquete" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Este formulario es para unir el paquete base %s%s%s en otro paquete." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Los siguientes paquetes serán eliminados:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vez unido el paquete este no puede ser separado." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduce el nombre del paquete que deseas unir." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Unir dentro:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirma la unión de paquetes" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Unión" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "Solamente usuarios de confianza y desarrolladores pueden unir paquetes." +msgstr "" +"Solamente usuarios de confianza y desarrolladores pueden unir paquetes." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Solicitud para el paquete" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Cerrar solicitud" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Solicitud" -#: html/register.php template/header.php msgid "Register" msgstr "Registro" -#: html/register.php msgid "Use this form to create an account." msgstr "Usa este formulario para crear una cuenta." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuario de confianza" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No se han podido recuperar los detalles de la propuesta." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Las votaciones para esta propuesta están cerradas." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solamente usuarios de confianza pueden votar." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No puedes votar en una propuesta sobre ti." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ya ha votado en esta propuesta." -#: html/tu.php msgid "Vote ID not valid." msgstr "El identificador del voto no es válido." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" -#: html/tu.php msgid "Past Votes" msgstr "Últimos votos" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "El registro de nuevas cuentas está desabilitado para tu dirección IP, probablemente debido a numerosos ataque de correo basura. Perdona los inconvenientes" +msgstr "" +"El registro de nuevas cuentas está desabilitado para tu dirección IP, " +"probablemente debido a numerosos ataque de correo basura. Perdona los " +"inconvenientes" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta el identificador de usuario" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nombre de usuario no es válido." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Debe tener entre %s y %s letras" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comenzar y acabar con una letra o número" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Solamente puede contener un punto, guion bajo o guion." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave pública SSH no es válida." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No se puede incrementar los permisos de la cuenta." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La dirección, %s%s%s, ya está en uso." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error tratando de crear la cuenta, %s%s%s" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "La cuenta, %s%s%s, fue creada satisfactoriamente." +msgstr "La cuenta, %s%s%s, ha sido creada satisfactoriamente." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "Se envió una clave de restablecimiento de contraseña a tu dirección de correo electrónico." +msgstr "" +"Se envió una clave de restablecimiento de contraseña a tu dirección de " +"correo electrónico." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Pulsa en el enlace de acceso anterior para utilizar la cuenta." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No se realizaron cambios a la cuenta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "La cuenta, %s%s%s, fue modificada satisfactoriamente" +msgstr "La cuenta, %s%s%s, ha sido modificada satisfactoriamente" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "El formulario de registro ha sido deshabilitado para tu dirección IP, probablemente debido a numerosos ataque de correo basura. Perdona los inconvenientes" +msgstr "" +"El formulario de registro ha sido deshabilitado para tu dirección IP, " +"probablemente debido a numerosos ataque de correo basura. Perdona los " +"inconvenientes" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Tu contraseña ha sido reinicializada, si creaste una nueva cuenta, utiliza el enlace inferior para confirmar el correo y así crear tu contraseña inicial. En caso contrario, pide un reinicialización de contraseña en la página para %sReinicializar las contraseñas%s." +msgstr "" +"Tu contraseña ha sido reinicializada, si creaste una nueva cuenta, utiliza " +"el enlace inferior para confirmar el correo y así crear tu contraseña " +"inicial. En caso contrario, pide un reinicialización de contraseña en la " +"página para %sReinicializar las contraseñas%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Contraseña o nombre de usuario erróneos." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Un error ocurrió intentando generar la sesión." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinación de dirección de correo y clave no válidos." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nada" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver información de la cuenta para %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." -msgstr "" +msgstr "Falta el identificador o el nombre del paquete base." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "No tienes permitido editar este comentario." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "El comentario no existe." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "El comentario no puede estar vacío." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Se ha añadido el comentario." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Debes autentificarte antes de editar la información del paquete." + +msgid "Missing comment ID." +msgstr "Falta el identificador del comentario." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Los detalles del paquete no se han podido encontrar." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Debes autentificarte antes de poder marcar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No seleccionaste ningún paquete a marcar." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" +"Los paquetes seleccionados no han sido marcados como desactualizados, " +"escribe un comentario." + msgid "The selected packages have been flagged out-of-date." msgstr "Los paquetes seleccionados han sido marcados como desactualizados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Debes autentificarte antes de poder desmarcar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No seleccionaste ningún paquete a desmarcar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Los paquetes seleccionados han sido desmarcados." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No posees los permisos para eliminar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No seleccionaste ningún paquete a eliminar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Los paquetes seleccionados se han eliminado." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Debes autentificarte antes de poder adoptar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Debes autentificarte antes de poder abandonar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No haz seleccionado ningún paquete para ser adoptado." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No seleccionaste ningún paquete para ser abandonado." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Los paquetes seleccionados han sido adoptados." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Los paquetes seleccionados han sido abandonados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Debes autentificarte antes de poder votar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Debes autentificarte antes de poder quitar votos a los paquetes" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No seleccionaste ningún paquete a votar." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Tus votos han sido eliminados de los paquetes seleccionados." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Tus votos han sido computados para los paquetes seleccionados." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No se pudo añadir a la lista de notificaciones." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Haz sido añadido a la lista de notificaciones de comentarios de %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Haz sido eliminado de la lista de notificaciones de comentarios de %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Debes autentificarte antes de editar la información del paquete." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Falta el identificador del comentario." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Comentario eliminado." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No estás autorizado para eliminar este comentario." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "El comentario ha sido eliminado." + msgid "Comment has been edited." -msgstr "" +msgstr "El comentario ha sido editado." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "No estás autorizado para editar las palabras clave de este paquete base." +msgstr "" +"No estás autorizado para editar las palabras clave de este paquete base." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Las palabras clave del paquete base se han actualizado." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "No se te permite administrar los coencargados de este paquete base." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nombre de usuario no válido: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Los coencargados del paquete base han sido actualizados." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles del paquete para" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" -msgstr "" +msgstr "requiere %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Debes estar identificado para realizar solicitudes para el paquete." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nombre no válido: solamente se permiten letras minúsculas." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campo de comentarios no debe estar vacío." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de solicitud no válida." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Solicitud agregada con éxito." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón no válida." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "Solamente los usuarios de confianza y desarrolladores pueden cerrar una solicitud." +msgstr "" +"Solamente los usuarios de confianza y desarrolladores pueden cerrar una " +"solicitud." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Solicitud cerrada exitosamente" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Puedes usar este formulario para eliminar la cuenta de %s en AUR permanentemente." +msgstr "" +"Puedes usar este formulario para eliminar la cuenta de %s en AUR " +"permanentemente." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVERTENCIA%s: Esta acción no puede deshacerse." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar borrado" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nombre de usuario" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de cuenta" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuario" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Desarrollador" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Usuarios de confianza y desarrolladores" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Dirección de correo" -#: template/account_details.php msgid "hidden" -msgstr "" +msgstr "oculto" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nombre real" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alias de IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Huella digital PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Estado" -#: template/account_details.php msgid "Inactive since" msgstr "Inactivo desde" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" -#: template/account_details.php msgid "Last Login" msgstr "Última autentificación" -#: template/account_details.php msgid "Never" msgstr "Nunca" -#: template/account_details.php msgid "View this user's packages" msgstr "Ver los paquetes de este usuario" -#: template/account_details.php msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Haz clic %saquí%s si deseas eliminar permanentemente esta cuenta." -#: template/account_edit_form.php msgid "required" msgstr "obligatorio" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuario normal" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuario de confianza" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivo" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Asegúrate de escribir tu dirección de correc correctamente o estarás " +"bloqueado." -#: template/account_edit_form.php msgid "Hide Email Address" -msgstr "" +msgstr "Ocultar dirreción de correo" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Reescribe la contraseña" -#: template/account_edit_form.php msgid "Language" msgstr "Idioma" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "La siguiente información únicamente es necesaria si deseas subir paquetes al repositorio de usuarios de Arch." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"La siguiente información únicamente es necesaria si deseas subir paquetes al " +"repositorio de usuarios de Arch." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave pública SSH" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Actualizar" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Crear" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Limpiar" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "No se encontraron resultados que coincidan con tu criterio de búsqueda." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Editar cuenta" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Suspendido" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Editar" - -#: template/account_search_results.php -msgid "Less" -msgstr "Menos" - -#: template/account_search_results.php -msgid "More" -msgstr "Más" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "No hay más resultados que mostrar." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Administrar coencargados: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Utiliza este formulario para agregar coencargados para %s%s%s (un nombre de usuario por línea):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Usuarios" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Guardar" - -#: template/header.php -msgid "My Packages" -msgstr "Mis paquetes" - -#: template/header.php -msgid " My Account" -msgstr "Mi cuenta" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Acciones del paquete" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Ver PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Ver cambios" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Descargar instantánea" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Buscar en la wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marcado como desactualizado" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Marcar paquete como desactualizado" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Desmarcar paquete" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Eliminar voto" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Votar por este paquete" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Deshabilitar notificaciones" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Actualizar" + +msgid "Create" +msgstr "Crear" + +msgid "Reset" +msgstr "Limpiar" + +msgid "No results matched your search criteria." +msgstr "" +"No se encontraron resultados que coincidan con tu criterio de búsqueda." + +msgid "Edit Account" +msgstr "Editar cuenta" + +msgid "Suspended" +msgstr "Suspendido" + +msgid "Edit" +msgstr "Editar" + +msgid "Less" +msgstr "Menos" + +msgid "More" +msgstr "Más" + +msgid "No more results to display." +msgstr "No hay más resultados que mostrar." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Utiliza este formulario para agregar coencargados para %s%s%s (un nombre de " +"usuario por línea):" + +msgid "Users" +msgstr "Usuarios" + +msgid "Save" +msgstr "Guardar" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + +msgid "My Packages" +msgstr "Mis paquetes" + +msgid " My Account" +msgstr "Mi cuenta" + +msgid "Package Actions" +msgstr "Acciones del paquete" + +msgid "View PKGBUILD" +msgstr "Ver PKGBUILD" + +msgid "View Changes" +msgstr "Ver cambios" + +msgid "Download snapshot" +msgstr "Descargar instantánea" + +msgid "Search wiki" +msgstr "Buscar en la wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Marcar paquete como desactualizado" + +msgid "Unflag package" +msgstr "Desmarcar paquete" + +msgid "Remove vote" +msgstr "Eliminar voto" + +msgid "Vote for this package" +msgstr "Votar por este paquete" + +msgid "Disable notifications" +msgstr "Deshabilitar notificaciones" + msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "Hay %d solicitud pendiente" msgstr[1] "Hay %d solicitudes pendientes" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Eliminar paquete" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Unir paquete" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar paquete" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconocido" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Dirección URL de clonado con Git" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "Solamente lectura" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Palabras claves" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Primer encargado" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Encargado" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último encargado" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularidad" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Fecha de creación" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualización" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Editar comentario para: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" -msgstr "Agregar comentario" +msgstr "Añadir un comentario" -#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos los comentarios" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Últimos comentarios" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s comentó en %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Comentario anónimo en %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "borrado el %s por %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Eliminar comentario" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Todos los comentarios" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Desarrollador principal" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita el sitio web de" -#: template/pkg_details.php msgid "Licenses" msgstr "Licencias" -#: template/pkg_details.php msgid "Groups" msgstr "Grupos" -#: template/pkg_details.php msgid "Conflicts" msgstr "Conflictos" -#: template/pkg_details.php msgid "Provides" msgstr "Proveen" -#: template/pkg_details.php msgid "Replaces" msgstr "Remplazan" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencias" -#: template/pkg_details.php msgid "Required by" msgstr "Requerido por" -#: template/pkg_details.php msgid "Sources" msgstr "Fuentes" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Cerrar solicitud: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Usa este formulario para cerrar la solicitud para el paquete base %s%s%s." +msgstr "" +"Usa este formulario para cerrar la solicitud para el paquete base %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda encarecidamente añadir un comentario al rechazar una solicitud." +msgstr "" +"El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda " +"encarecidamente añadir un comentario al rechazar una solicitud." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Aceptado" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Rechazado" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Solicitud para el paquete: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Usa este formulario para presentar una solicitud para el paquete base %s%s%s el cual incluye los siguientes paquetes:" +msgstr "" +"Usa este formulario para presentar una solicitud para el paquete base %s%s%s " +"el cual incluye los siguientes paquetes:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de solicitud" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Borrado" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfandad" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Unir en" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Se encontró %d solicitud para el paquete." msgstr[1] "Se encontraron %d solicitudes para el paquete." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Solicitado por" -#: template/pkgreq_results.php msgid "Date" msgstr "Fecha" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Aprox. %d días restantes" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Aprox. %d hora restante" msgstr[1] "Aprox. %d horas restantes" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 hora restante" -#: template/pkgreq_results.php msgid "Accept" msgstr "Aceptar" -#: template/pkgreq_results.php msgid "Locked" msgstr "Bloqueada" -#: template/pkgreq_results.php msgid "Close" msgstr "Cerrar" -#: template/pkgreq_results.php msgid "Closed" msgstr "Cerrada" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nombre, descripción" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Solamente nombre" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nombre exacto" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exacto" -#: template/pkg_search_form.php msgid "All" msgstr "Todos" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No marcados" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nombre" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" -#: template/pkg_search_form.php msgid "Last modified" -msgstr "" +msgstr "Última modificación" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" -#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" -#: template/pkg_search_form.php msgid "Search by" msgstr "Buscar por" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Orden" -#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Huérfanos" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Error al recuperar la lista de paquetes." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ningún paquete coincide con su criterio de búsqueda." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquete fue encontrado." msgstr[1] "%d paquetes fueron encontrados." -#: template/pkg_search_results.php msgid "Version" msgstr "Versión" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "La popularidad se calcula como la suma de todos los votos con cada voto ponderado con un factor de 0,98 por día desde la creación del paquete." +msgstr "" +"La popularidad se calcula como la suma de todos los votos con cada voto " +"ponderado con un factor de 0,98 por día desde la creación del paquete." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Sí" -#: template/pkg_search_results.php msgid "orphan" msgstr "huérfano" -#: template/pkg_search_results.php msgid "Actions" msgstr "Acciones" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marcar como desactualizado" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Marcar como actualizado" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar paquetes" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar paquetes" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Eliminar paquetes" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" -#: template/search_accounts_form.php msgid "Any type" msgstr "Cualquier tipo" -#: template/search_accounts_form.php msgid "Search" msgstr "Buscar" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadísticas" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes huérfanos" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes añadidos en los últimos 7 días" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes actualizados en los últimos 7 días" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes actualizados el último año" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes que no han sido nunca actualizados" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios registrados" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios de confianza" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizaciones recientes" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Mis estadísticas" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detalles de la propuesta" -#: template/tu_details.php msgid "This vote is still running." msgstr "Aún se puede votar." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Subido: %s por %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" -#: template/tu_details.php msgid "Result" msgstr "Resultado" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" -#: template/tu_details.php msgid "Abstain" msgstr "Abstenerse" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" msgstr "Participación" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Último voto del usuario de confianza" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No se han encontrado resultados." -#: template/tu_list.php msgid "Start" msgstr "Inicio" -#: template/tu_list.php msgid "Back" msgstr "Atrás" diff --git a/po/es_419.po b/po/es_419.po index c0d8deca..962917e7 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Angel Velasquez , 2011 # juantascon , 2011 @@ -13,1799 +13,1501 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/aur/language/es_419/)\n" +"Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" +"aur/language/es_419/)\n" +"Language: es_419\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: es_419\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Página no encontrada" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Disculpe, la página que solicitó no existe." -#: html/503.php msgid "Service Unavailable" msgstr "Servicio no disponible" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "¡No se asustes! El sitio está desactivado por mantenimiento. Pronto volveremos." +msgstr "" +"¡No se asustes! El sitio está desactivado por mantenimiento. Pronto " +"volveremos." -#: html/account.php msgid "Account" msgstr "Cuenta" -#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentas" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No está autorizado a acceder a esta área." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No se pudo obtener la información del usuario especificado." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "No tiene permisos para editar esta cuenta." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Use este formulario para buscar cuentas existentes." -#: html/account.php msgid "You must log in to view user information." msgstr "Debe autentificarse para ver la información del usuario." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Añadir propuesta" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Elemento inválido para la acción del usuario." -#: html/addvote.php msgid "Username does not exist." msgstr "El nombre de usuario no existe." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ya tiene una propuesta activa." -#: html/addvote.php msgid "Invalid type." msgstr "Tipo no válido." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta no puede estar vacía." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nueva propuesta enviada." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Envíe una propuesta a la cual votar." -#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/Usuario de confianza (TU)" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" -#: html/addvote.php msgid "Addition of a TU" msgstr "Agregar a un nuevo usuario de confianza" -#: html/addvote.php msgid "Removal of a TU" msgstr "Remover a un usuario de confianza" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remover a un usuario de confianza (no declarado inactivo)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Enmienda a las Bylaws (Reglas de los TU)" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" -#: html/addvote.php msgid "Submit" msgstr "Subir" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Administrar coencargados" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Editar comentario" -#: html/home.php template/header.php msgid "Home" msgstr "Inicio" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "¡Bienvenido al repositorio de usuarios de Arch! Lea la %sGuía del usuario del AUR%s y la %sGuía del usuario de confianza del AUR%s para mayor información." +msgstr "" +"¡Bienvenido al repositorio de usuarios de Arch! Lea la %sGuía del usuario " +"del AUR%s y la %sGuía del usuario de confianza del AUR%s para mayor " +"información." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de empaquetado de Arch%s de otra forma serán borrados." +msgstr "" +"Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de " +"empaquetado de Arch%s de otra forma serán borrados." -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerde votar sus paquetes favoritos!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Algunos paquetes pueden estar disponibles de forma binaria en [community]." +msgstr "" +"Algunos paquetes pueden estar disponibles de forma binaria en [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Los paquetes en AUR son producidos por los usuarios. Cualquier uso de ellos " +"o sus archivos es a su propio riesgo." -#: html/home.php msgid "Learn more..." msgstr "Aprenda más..." -#: html/home.php msgid "Support" msgstr "Soporte" -#: html/home.php msgid "Package Requests" msgstr "Peticiones para los paquetes" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Existen tres tipos de peticiones que pueden presentarse en el recuadro %sAcciones del paquete%s en la página de detalles del paquete:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Existen tres tipos de peticiones que pueden presentarse en el recuadro " +"%sAcciones del paquete%s en la página de detalles del paquete:" -#: html/home.php msgid "Orphan Request" msgstr "Petición de Orfandad" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Pedir la orfandad de un paquete, por ejemplo, cuando el encargado está inactivo y el paquete fue marcado como desactualizado un largo tiempo." +msgstr "" +"Pedir la orfandad de un paquete, por ejemplo, cuando el encargado está " +"inactivo y el paquete fue marcado como desactualizado por un largo tiempo." -#: html/home.php msgid "Deletion Request" msgstr "Petición de Borrado" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Pedir que un paquete sea borrado del Repositorio Usuarios de Arch. Por favor, no use esta opción si un paquete está roto y se puede arreglar fácilmente. En cambio, contacte con el encargado del paquete y presentar solicitud orfandad si es necesario." +msgstr "" +"Pedir que un paquete sea borrado del Repositorio Usuarios de Arch. Por " +"favor, no use esta opción si un paquete está roto y se puede arreglar " +"fácilmente. En cambio, contacte con el encargado del paquete y presentar " +"solicitud orfandad si es necesario." -#: html/home.php msgid "Merge Request" msgstr "Petición de Fusión" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Pedir que se fusione un paquete en otro. Puede usarla cuando un paquete tiene que ser cambiado de nombre o sustituido por un paquete dividido." +msgstr "" +"Pedir que se fusione un paquete en otro. Puede usarla cuando un paquete " +"tiene que ser cambiado de nombre o sustituido por un paquete dividido." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Si quiere discutir una petición, puede usar la lista de correo %saur-peticiones%s. Sin embargo, por favor no utilice esa lista para presentar solicitudes." +msgstr "" +"Si quiere discutir una petición, puede usar la lista de correo %saur-" +"peticiones%s. Sin embargo, por favor no utilice esa lista para presentar " +"solicitudes." -#: html/home.php msgid "Submitting Packages" msgstr "Subir paquetes" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Ahora se usa Git sobre SSH para subir paquetes al AUR. Véase la sección %sSubir paquetes%s de la wiki del Repositorio de Usuarios de Arch para más información." +msgstr "" +"Ahora se usa Git sobre SSH para subir paquetes al AUR. Véase la sección " +"%sSubir paquetes%s de la wiki del Repositorio de Usuarios de Arch para más " +"información." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Las siguientes huellas SSH están en uso para AUR." -#: html/home.php msgid "Discussion" msgstr "Debate" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "La discusión general acerca del Repositorio de Usuarios de Arch (AUR) y la estructura de Usuarios de Confianza se realiza en la lista de correos %saur-general%s. Para discusiones relacionadas con el desarrollo de la interfaz web del AUR, utilice la lista de correo %saur-dev%s." +msgstr "" +"La discusión general acerca del Repositorio de Usuarios de Arch (AUR) y la " +"estructura de Usuarios de Confianza se realiza en la lista de correos %saur-" +"general%s. Para discusiones relacionadas con el desarrollo de la interfaz " +"web del AUR, utilice la lista de correo %saur-dev%s." -#: html/home.php msgid "Bug Reporting" msgstr "Informe de errores" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" +"Si encuentra un error en la interfaz web del AUR, llene un informe de fallo " +"en nuestro %s«bug tracker»%s. Use este para reportar %súnicamente%s errores " +"de la interfaz web del AUR. Para reportar errores de empaquetado debe " +"contactar con el encargado o dejar un comentario en la página respectiva del " +"paquete." -#: html/home.php msgid "Package Search" msgstr "Buscar paquetes" -#: html/index.php msgid "Adopt" msgstr "Adoptar" -#: html/index.php msgid "Vote" msgstr "Votar" -#: html/index.php msgid "UnVote" msgstr "Retirar voto" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Quitar notificación" -#: html/index.php msgid "UnFlag" msgstr "Desmarcar" -#: html/login.php template/header.php msgid "Login" msgstr "Autentificarse" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificado como: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Salir" -#: html/login.php msgid "Enter login credentials" msgstr "Introduce las credenciales de autentificación" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Nombre de usuario y dirección de correo" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" -#: html/login.php msgid "Remember me" msgstr "Recordarme" -#: html/login.php msgid "Forgot Password" msgstr "Olvidó su cotraseña" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "La autentificación por HTTP está deshabilitada. %scambie a HTTPS%s si desea autentificarse" +msgstr "" +"La autentificación por HTTP está deshabilitada. %scambie a HTTPS%s si desea " +"autentificarse" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criterio de búsqueda" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "No se pudieron recuperar los detalles del paquete." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campo obligatorio." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Los campos de la contraseña no coinciden." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Su contraseña debe tener como mínimo %s letras." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Dirección de correo no válida." -#: html/passreset.php msgid "Password Reset" msgstr "Reiniciar la contraseña" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Compruebe su correo para ver el enlace de confirmación." -#: html/passreset.php msgid "Your password has been reset successfully." -msgstr "Su contraseña ha sido reiniciada con éxito." +msgstr "Su contraseña fue reiniciada con éxito." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme su dirección de correo:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Ingrese su nueva contraseña:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme su nueva contraseña:" -#: html/passreset.php msgid "Continue" msgstr "Continuar" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje a la %slista de correo aur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje " +"a la %slista de correo aur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduzca su dirección de correo:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "Los paquetes seleccionados no fueron abandonados, marque la casilla de confirmación." +msgstr "" +"Los paquetes seleccionados no fueron abandonados, marque la casilla de " +"confirmación." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "No se puede encontrar el paquete para fusionar sus votos y comentarios." +msgstr "" +"No se puede encontrar el paquete para fusionar sus votos y comentarios." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "No se puede fusionar un paquete base consigo mismo." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Los paquetes seleccionados no se borraron, compruebe la casilla de confirmación." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Los paquetes seleccionados no se borraron, compruebe la casilla de " +"confirmación." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminación de paquetes" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Borrar paquete: %s" +msgid "Delete Package" +msgstr "Borrar paquete" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Use este formulario para borrar el paquete base %s%s%s y los siguientes paquetes en el AUR:" +msgstr "" +"Use este formulario para borrar el paquete base %s%s%s y los siguientes " +"paquetes en el AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El borrado de un paquete es permanente." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Selecciona la casilla para confirmar la acción." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirme el borrado del paquete" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Borrar" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Solo Usuarios de Confianza y Desarrolladores pueden borrar paquetes." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar paquete" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Abandonar paquete: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Use este formulario para abandonar el paquete base %s %s %s que incluye los siguientes paquetes:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Use este formulario para abandonar el paquete base %s %s %s que incluye los " +"siguientes paquetes:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Al seleccionar la casilla de verificación, confirma que desea abandonar el paquete y transferir su propiedad a %s %s %s." +msgstr "" +"Al seleccionar la casilla de verificación, confirma que desea abandonar el " +"paquete y transferir su propiedad a %s %s %s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Al seleccionar la casilla de verificación, confirma que desea abandonar el paquete." +msgstr "" +"Al seleccionar la casilla de verificación, confirma que desea abandonar el " +"paquete." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirme para abandonar el paquete" -#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "Solo Usuarios de Confianza y Desarrolladores pueden forzar el abandono de paquetes." +msgstr "" +"Solo Usuarios de Confianza y Desarrolladores pueden forzar el abandono de " +"paquetes." + +msgid "Flag Comment" +msgstr "" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Marcado como desactualizado" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" +"Use este formulario para marcar el paquete base %s%s%s y los siguientes " +"paquetes en el AUR como desactualizados:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"%sNo%s use este formulario para reportar fallos. Use los comentarios del " +"paquete en su lugar." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Introduzca los detalles del porqué el paquete fue marcado como " +"desactualizado, peferentemente incluyendo un enlace al anuncio de la nueva " +"versión o al empaquetado." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" -msgstr "Comentario" +msgstr "Comentarios" -#: html/pkgflag.php msgid "Flag" msgstr "Marcar" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "Solo los usuario registrados pueden marcar como desactualizado." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusión de paquetes" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Fusionar paquete: %s" +msgid "Merge Package" +msgstr "Fusionar paquete" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Este formulario es para fusionar el paquete base %s%s%s en otro paquete." +msgstr "" +"Este formulario es para fusionar el paquete base %s%s%s en otro paquete." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Los siguientes paquetes serán borrados:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vez fusionado el paquete este no se puede separar." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduzca el nombre del paquete que desea fusionar." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionar dentro:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmar fusión de paquetes" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusión" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo Usuarios de Confianza y Desarrolladores pueden fusionar paquetes." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Petición para el paquete" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Cerrar Petición" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Petición" -#: html/register.php template/header.php msgid "Register" msgstr "Registro" -#: html/register.php msgid "Use this form to create an account." msgstr "Use este formulario para crear una cuenta." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuario de Confianza" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No se han podido recuperar los detalles de la propuesta." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Las votaciones para esta propuesta están cerradas." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solo Usuarios de Confianza pueden votar." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No puede votar en una propuesta sobre usted." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ya ha votado en esta propuesta." -#: html/tu.php msgid "Vote ID not valid." msgstr "El identificador del voto no es válido." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" -#: html/tu.php msgid "Past Votes" msgstr "Últimos votos" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "El registro de nuevas cuentas está desabilitado para su dirección IP, probablemente debido a numerosos ataque de correo basura. Perdone los inconvenientes" +msgstr "" +"El registro de nuevas cuentas está desabilitado para su dirección IP, " +"probablemente debido a numerosos ataque de correo basura. Perdone los " +"inconvenientes" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta el identificador de usuario" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nombre de usuario no es válido." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Debe tener entre %s y %s letras" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comenzar y acabar con una letra o número" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Solo puede contener un punto, guion bajo o guion." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave pública SSH no es válida." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No se puede incrementar los permisos de la cuenta." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La dirección, %s%s%s, ya está en uso." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error tratando de crear la cuenta, %s%s%s" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, fue creada satisfactoriamente." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "Una llave para reiniciar su contraseña a sido enviada a su correo." +msgstr "Una llave para reiniciar su contraseña fue enviada a su correo." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Haz clic en el enlace de autentificación para usar su cuenta." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No se realizaron cambios a la cuenta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, fue modificada satisfactoriamente" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "El formulario de registro ha sido deshabilitado para su dirección IP, probablemente debido a numerosos ataque de correo basura. Perdone los inconvenientes" +msgstr "" +"El formulario de registro ha sido deshabilitado para su dirección IP, " +"probablemente debido a numerosos ataque de correo basura. Perdone los " +"inconvenientes" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Su contraseña ha sido reiniciada, si creó una nueva cuenta, use el enlace inferior para confirmar el correo y así crear su contraseña inicial. En caso contrario, pida un reinicio de contraseña en la página para %sreiniciar las contraseñas%s." +msgstr "" +"Su contraseña fue reiniciada, si creó una nueva cuenta, use el enlace " +"inferior para confirmar el correo y así crear su contraseña inicial. En caso " +"contrario, pida un reinicio de contraseña en la página para %sreiniciar las " +"contraseñas%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Contraseña o nombre de usuario erróneos." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Un error ocurrió intentando generar la sesión." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinación de dirección de correo y clave no válida." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nada" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver información de la cuenta para %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." -msgstr "" +msgstr "Falta el identificador o nombre del paquete base." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "No tiene permitido editar este comentario." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "El comentario no existe." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." +msgstr "El comentario no puede estar vacío." + +msgid "Comment has been added." +msgstr "El comentario fue añadido." + +msgid "You must be logged in before you can edit package information." +msgstr "Debe autentificarse antes de editar la información del paquete." + +msgid "Missing comment ID." +msgstr "Falta el identificador del comentario." + +msgid "No more than 5 comments can be pinned." msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been added." -msgstr "Se ha añadido el comentario." +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Los detalles del paquete no se pudieron encontrar." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Debe autentificarse antes de poder marcar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No seleccionó ningún paquete para marcar." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" +"Los paquetes seleccionados no han sido marcados como desactualizados, " +"escriba un comentario." + msgid "The selected packages have been flagged out-of-date." msgstr "Los paquetes seleccionados han sido marcados como desactualizados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Debe autentificarse antes de poder desmarcar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No seleccionó ningún paquete para desmarcar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Los paquetes seleccionados han sido desmarcados." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No posee los permisos para borrar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No seleccionó ningún paquete para borrar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Los paquetes seleccionados se han borrado." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Debe autentificarse antes de poder adoptar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Debe autentificarse antes de poder abandonar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No seleccionó ningún paquete para adoptar." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No seleccionó ningún paquete para ser abandonado." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Los paquetes seleccionados han sido adoptados." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Los paquetes seleccionados han sido abandonados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Debe autentificarse antes de poder votar paquetes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Debe autentificarse antes de poder quitar votos a los paquetes" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No seleccionó ningún paquete para votarlo." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Sus votos han sido eliminados de los paquetes seleccionados." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Sus votos se añadieron a los paquetes seleccionados." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No se pudo añadir a la lista de notificaciones." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Ha sido añadido a la lista de notificaciones de comentarios de %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Ha sido eliminado de la lista de notificaciones de comentarios de %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Debe autentificarse antes de editar la información del paquete." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Falta el identificador del comentario." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Comentario borrado." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No está autorizado a borrar este comentario." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "El comentario fue borrado." + msgid "Comment has been edited." -msgstr "" +msgstr "El comentario fue editado." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "No está autorizado para editar las palabras clave de este paquete base." +msgstr "" +"No está autorizado para editar las palabras clave de este paquete base." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Las palabras clave del paquete base actualizaron ." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "No tiene permitido administrar los coencargados de este paquete base." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nombre de usuario no válido: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Los coencargados del paquete base fueron actualizados." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles del paquete para" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" -msgstr "" +msgstr "requiere %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Debe estar identificado para realizar peticiones para el paquete." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nombre no válido: solo se permiten letras minúsculas." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campo de comentarios no debe estar vacío." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de petición no válida." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Petición agregada con éxito." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón no válida." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "Solo Usuarios de Confianza y Desarrolladores pueden cerrar una petición." +msgstr "" +"Solo Usuarios de Confianza y Desarrolladores pueden cerrar una petición." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Petición cerrada exitosamente" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Puede usar este formulario para borrar la cuenta de %s en AUR permanentemente." +msgstr "" +"Puede usar este formulario para borrar la cuenta de %s en AUR " +"permanentemente." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVERTENCIA%s: Esta acción no puede deshacerse." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar borrado" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nombre de usuario" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de cuenta" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuario" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Desarrollador" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Usuarios de Confianza y desarrolladores" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Dirección de correo" -#: template/account_details.php msgid "hidden" -msgstr "" +msgstr "oculto" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nombre real" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alias de IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Huella digital PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Estado" -#: template/account_details.php msgid "Inactive since" msgstr "Inactivo desde" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" -#: template/account_details.php msgid "Last Login" msgstr "Última autentificación" -#: template/account_details.php msgid "Never" msgstr "Nunca" -#: template/account_details.php msgid "View this user's packages" msgstr "Ver los paquetes de este usuario" -#: template/account_details.php msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Haga clic %saquí%s si desea borrar permanentemente esa cuenta." -#: template/account_edit_form.php msgid "required" msgstr "obligatorio" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuario normal" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuario de Confianza" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivo" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Asegúrese de escribir su correo correctamente o de lo contrario terminará " +"bloqueado." -#: template/account_edit_form.php msgid "Hide Email Address" -msgstr "" +msgstr "Ocultar dirreción de correo" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Reescriba la contraseña" -#: template/account_edit_form.php msgid "Language" msgstr "Idioma" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "La siguiente información es necesaria únicamente si quiere subir paquetes al Repositorio de Usuarios de Arch." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"La siguiente información es necesaria únicamente si quiere subir paquetes al " +"Repositorio de Usuarios de Arch." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave pública SSH" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Actualizar" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Crear" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Limpiar" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "No se encontraron resultados que coincidan con su criterio de búsqueda." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Editar cuenta" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Suspendido" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Editar" - -#: template/account_search_results.php -msgid "Less" -msgstr "Menos" - -#: template/account_search_results.php -msgid "More" -msgstr "Más" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "No hay más resultados que mostrar." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Administrar coencargados: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Use este formulario para agregar coencargados para %s%s%s (un nombre de usuario por línea):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Usuarios" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Guardar" - -#: template/header.php -msgid "My Packages" -msgstr "Mis paquetes" - -#: template/header.php -msgid " My Account" -msgstr "Mi cuenta" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Acciones del paquete" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Ver PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Ver cambios" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Descargar instantánea" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Buscar en la wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marcado como desactualizado" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Marcar paquete como desactualizado" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Desmarcar paquete" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Eliminar voto" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Votar por este paquete" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Deshabilitar notificaciones" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Actualizar" + +msgid "Create" +msgstr "Crear" + +msgid "Reset" +msgstr "Limpiar" + +msgid "No results matched your search criteria." +msgstr "" +"No se encontraron resultados que coincidan con su criterio de búsqueda." + +msgid "Edit Account" +msgstr "Editar cuenta" + +msgid "Suspended" +msgstr "Suspendido" + +msgid "Edit" +msgstr "Editar" + +msgid "Less" +msgstr "Menos" + +msgid "More" +msgstr "Más" + +msgid "No more results to display." +msgstr "No hay más resultados que mostrar." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Use este formulario para agregar coencargados para %s%s%s (un nombre de " +"usuario por línea):" + +msgid "Users" +msgstr "Usuarios" + +msgid "Save" +msgstr "Guardar" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + +msgid "My Packages" +msgstr "Mis paquetes" + +msgid " My Account" +msgstr "Mi cuenta" + +msgid "Package Actions" +msgstr "Acciones del paquete" + +msgid "View PKGBUILD" +msgstr "Ver PKGBUILD" + +msgid "View Changes" +msgstr "Ver cambios" + +msgid "Download snapshot" +msgstr "Descargar instantánea" + +msgid "Search wiki" +msgstr "Buscar en la wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Marcar paquete como desactualizado" + +msgid "Unflag package" +msgstr "Desmarcar paquete" + +msgid "Remove vote" +msgstr "Eliminar voto" + +msgid "Vote for this package" +msgstr "Votar por este paquete" + +msgid "Disable notifications" +msgstr "Deshabilitar notificaciones" + msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "Hay %d petición pendiente" msgstr[1] "Hay %d peticiones pendientes" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Borrar paquete" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Fusionar paquete" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar paquete" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconocido" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL de clonado con Git" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "Solo lectura" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Palabras claves" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Primer encargado" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Encargado" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último encargado" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularidad" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Fecha de creación" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualización" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Editar commentario para: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" -msgstr "Agregar comentario" +msgstr "Agregar un comentario" -#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos los comentarios" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Últimos comentarios" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s comentó en %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Comentario anónimo en %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "borrado el %s por %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Borrar comentario" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Todos los comentarios" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Desarrollador principal" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita el sitio web de" -#: template/pkg_details.php msgid "Licenses" msgstr "Licencias" -#: template/pkg_details.php msgid "Groups" msgstr "Grupos" -#: template/pkg_details.php msgid "Conflicts" msgstr "Conflictos" -#: template/pkg_details.php msgid "Provides" msgstr "Proveen" -#: template/pkg_details.php msgid "Replaces" msgstr "Remplazan" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencias" -#: template/pkg_details.php msgid "Required by" msgstr "Requerido por" -#: template/pkg_details.php msgid "Sources" msgstr "Fuentes" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Cerrar petición: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Use este formulario para cerrar la petición para el paquete base %s%s%s." +msgstr "" +"Use este formulario para cerrar la petición para el paquete base %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda encarecidamente añadir un comentario al rechazar una petición." +msgstr "" +"El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda " +"encarecidamente añadir un comentario al rechazar una petición." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Aceptado" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Rechazado" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Petición para el paquete: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Use este formulario para presentar una petición para el paquete base %s%s%s el cual incluye los siguientes paquetes:" +msgstr "" +"Use este formulario para presentar una petición para el paquete base %s%s%s " +"el cual incluye los siguientes paquetes:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de petición" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Borrado" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfandad" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fusionar en" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Se encontró %d solicitud para el paquete." msgstr[1] "Se encontraron %d solicitudes para el paquete." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Solicitado por" -#: template/pkgreq_results.php msgid "Date" msgstr "Fecha" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Aprox. %d días restantes" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Aprox. %d hora restante" msgstr[1] "Aprox. %d horas restantes" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 hora restante" -#: template/pkgreq_results.php msgid "Accept" msgstr "Aceptar" -#: template/pkgreq_results.php msgid "Locked" msgstr "Bloqueada" -#: template/pkgreq_results.php msgid "Close" msgstr "Cerrar" -#: template/pkgreq_results.php msgid "Closed" msgstr "Cerrada" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nombre, descripción" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Solo nombre" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nombre exacto" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exacto" -#: template/pkg_search_form.php msgid "All" msgstr "Todos" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No marcados" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nombre" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" -#: template/pkg_search_form.php msgid "Last modified" -msgstr "" +msgstr "Última modificación" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" -#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" -#: template/pkg_search_form.php msgid "Search by" msgstr "Buscar por" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Orden" -#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Huérfanos" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Error al recuperar la lista de paquetes." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ningún paquete coincide con su criterio de búsqueda." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquete fue encontrado." msgstr[1] "%d paquetes fueron encontrados." -#: template/pkg_search_results.php msgid "Version" msgstr "Versión" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "La Popularidad es calculada como la suma de todos los votos ponderados con un factor de 0,98 por día desde la creación del paquete." +msgstr "" +"La Popularidad es calculada como la suma de todos los votos ponderados con " +"un factor de 0,98 por día desde la creación del paquete." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Sí" -#: template/pkg_search_results.php msgid "orphan" msgstr "huérfano" -#: template/pkg_search_results.php msgid "Actions" msgstr "Acciones" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marcar como desactualizado" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Marcar como actualizado" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar paquetes" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar paquetes" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Borrar paquetes" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" -#: template/search_accounts_form.php msgid "Any type" msgstr "Cualquier tipo" -#: template/search_accounts_form.php msgid "Search" msgstr "Buscar" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadísticas" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes huérfanos" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes nuevos en los últimos 7 días" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes actualizados en los últimos 7 días" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes actualizados el último año" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes que nunca se han actualizado" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios registrados" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios de Confianza" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizaciones recientes" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Mis estadísticas" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detalles de la propuesta" -#: template/tu_details.php msgid "This vote is still running." msgstr "Aún se puede votar." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Subido: %s por %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" -#: template/tu_details.php msgid "Result" msgstr "Resultado" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" -#: template/tu_details.php msgid "Abstain" msgstr "Abstenerse" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" msgstr "Participación" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Último voto del usuario de confianza" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No se han encontrado resultados." -#: template/tu_list.php msgid "Start" msgstr "Inicio" -#: template/tu_list.php msgid "Back" msgstr "Atrás" diff --git a/po/fi.po b/po/fi.po index 409546eb..e24409a0 100644 --- a/po/fi.po +++ b/po/fi.po @@ -1,777 +1,651 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: +# Elias Autio, 2016 # Jesse Jaara , 2011-2012,2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/fi/)\n" +"Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" +"fi/)\n" +"Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: fi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" -msgstr "" +msgstr "Sivua ei löydy." -#: html/404.php msgid "Sorry, the page you've requested does not exist." -msgstr "" +msgstr "Valitettavasti hakemaasi sivua ei ole olemassa." -#: html/503.php msgid "Service Unavailable" -msgstr "" +msgstr "Palvelu ei saatavilla." -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "Älä panikoi! Sivu on poissa käytöstä huollon vuoksi. Palaamme pian." -#: html/account.php msgid "Account" -msgstr "" +msgstr "Käyttäjätili" -#: html/account.php template/header.php msgid "Accounts" msgstr "Käyttäjätilit" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Sinulla ei ole oikeuksia tämän osion käyttämiseen." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Valitun käyttäjän tietoja ei voitu noutaa." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Sinulla ei ole oikeuksia tämän käyttäjätlin muokkaamiseen." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Etsi käyttäjätilejä." -#: html/account.php msgid "You must log in to view user information." msgstr "Sinun pitää kirjautua sisään tarkastellaksesi käyttäjien tietoja." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Lisää ehdotus" -#: html/addvote.php msgid "Invalid token for user action." msgstr "" -#: html/addvote.php msgid "Username does not exist." msgstr "Käyttäjänimeä ei ole olemassa." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "" -#: html/addvote.php msgid "Invalid type." msgstr "" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Ehdotus ei voi olla tyhjä." -#: html/addvote.php msgid "New proposal submitted." msgstr "Uusi ehdotus lisätty." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Lisää ehdotus äänestettäväksi." -#: html/addvote.php msgid "Applicant/TU" msgstr "Ehdokas/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tyhjä jos ei tiettyä henkilöä)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tyyppi" -#: html/addvote.php msgid "Addition of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Ehdotus" -#: html/addvote.php msgid "Submit" msgstr "Lisää" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Muokkaa kommenttia" -#: html/home.php template/header.php msgid "Home" msgstr "Etusivu" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Tervetuloa AURiin! Luethan %sAURin käyttäjä ohjeen%s sekä %sTU-käyttäjän oppaan%s, kun tarvitset lisätietoa." +msgstr "" +"Tervetuloa AURiin! Luethan %sAURin käyttäjä ohjeen%s sekä %sTU-käyttäjän " +"oppaan%s, kun tarvitset lisätietoa." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Lisättyjen PKGBUILD tiedostojen %stulee%s olla %sArchin pakettistandardien%s mukaisia, muuten ne saatetaan poistaa!" +msgstr "" +"Lisättyjen PKGBUILD tiedostojen %stulee%s olla %sArchin pakettistandardien%s " +"mukaisia, muuten ne saatetaan poistaa!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Muista äänestää suosikki pakettejasi!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Jotkin paketit saattavat olla tarjolla valmiina paketteina [community] varastossa. :)" +msgstr "" +"Jotkin paketit saattavat olla tarjolla valmiina paketteina [community] " +"varastossa. :)" -#: html/home.php msgid "DISCLAIMER" msgstr "Vastuuvapauslauseke" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"AUR-paketit ovat käyttäjien luomia eivätkä ole virallisesti tuettuja. Näiden " +"käyttäminen on omalla vastuullasi." -#: html/home.php msgid "Learn more..." -msgstr "" +msgstr "Selvitä lisää..." -#: html/home.php msgid "Support" -msgstr "" +msgstr "Tuki" -#: html/home.php msgid "Package Requests" msgstr "Pakettienhallintapyydöt" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Pakettien sivuilta löytyvän %spakettitoiminnot%s -laatikon kautta voi lähettää TU-käyttäjille kolme erilaista pakettienhallintapyyntöä." +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Pakettien sivuilta löytyvän %spakettitoiminnot%s -laatikon kautta voi " +"lähettää TU-käyttäjille kolme erilaista pakettienhallintapyyntöä." -#: html/home.php msgid "Orphan Request" msgstr "Hylkäämispyyntö" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Hallintapyyntö paketin poistamiseksi sen nykyiseltä ylläpitäjältä, esimerksi jos ylläpitäjä ei vastaa kommentteihin eikä sähköpostiin ja paketti on merkitty vanhentuneeksi jo kauan sitten." +msgstr "" +"Hallintapyyntö paketin poistamiseksi sen nykyiseltä ylläpitäjältä, esimerksi " +"jos ylläpitäjä ei vastaa kommentteihin eikä sähköpostiin ja paketti on " +"merkitty vanhentuneeksi jo kauan sitten." -#: html/home.php msgid "Deletion Request" msgstr "Poistopyyntö" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Hallintapyyntö paketin poistamiseksi AUR:ista. Jos paketti on jollain tapaa rikki tai huono, mutta helposti korjattavissa, tulisi ensisijaisesti olla yhteydessä paketin ylläpitäjään ja viimekädessä pistää paketin hylkäämispyyntö menemään." +msgstr "" +"Hallintapyyntö paketin poistamiseksi AUR:ista. Jos paketti on jollain tapaa " +"rikki tai huono, mutta helposti korjattavissa, tulisi ensisijaisesti olla " +"yhteydessä paketin ylläpitäjään ja viimekädessä pistää paketin " +"hylkäämispyyntö menemään." -#: html/home.php msgid "Merge Request" msgstr "Yhdistämispyyntö" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Hallintapyyntö kahden eri paketin yhdistämiseksi. Voidaan käyttää muun muassa silloin kun jokin paketti on nimettyuudelleen tai korvattu monipaketilla (split package)." +msgstr "" +"Hallintapyyntö kahden eri paketin yhdistämiseksi. Voidaan käyttää muun " +"muassa silloin kun jokin paketti on nimettyuudelleen tai korvattu " +"monipaketilla (split package)." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Pakettienhallintapyynnöistä voi keskustella niin yleisellä- kuin myös tiettyyn pyyntöön littyvällä tasolla %saur-requests%s -postituslistalla. Älä kuitenkaan lähetä hallintapyyntöjä postituslistalle." +msgstr "" +"Pakettienhallintapyynnöistä voi keskustella niin yleisellä- kuin myös " +"tiettyyn pyyntöön littyvällä tasolla %saur-requests%s -postituslistalla. Älä " +"kuitenkaan lähetä hallintapyyntöjä postituslistalle." -#: html/home.php msgid "Submitting Packages" msgstr "Paketien lisääminen ja päivittäminen" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Pakettien lisääminen ja päivittäminen uudessa AUR versiossa tapahtuu SSH-yhteyden yli Git-versionhallinan avulla. Tarkemman ohjeet löytyvät Arch Linuxin wiki-oppaan AUR-sivulta kohdasta %sPakettien lisääminen%s." +msgstr "" +"Pakettien lisääminen ja päivittäminen uudessa AUR versiossa tapahtuu SSH-" +"yhteyden yli Git-versionhallinan avulla. Tarkemman ohjeet löytyvät Arch " +"Linuxin wiki-oppaan AUR-sivulta kohdasta %sPakettien lisääminen%s." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR käyttää seuraavia SSH-tunnisteita:" -#: html/home.php msgid "Discussion" msgstr "Keskustelu" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Virheiden raportointi" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Pakettihaku" -#: html/index.php msgid "Adopt" -msgstr "" +msgstr "Ota haltuun" -#: html/index.php msgid "Vote" msgstr "Äänestä" -#: html/index.php msgid "UnVote" msgstr "Peru ääni" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Lähetä ilmoituksia" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "En halua ilmoituksia" -#: html/index.php msgid "UnFlag" -msgstr "" +msgstr "Poista merkintä" -#: html/login.php template/header.php msgid "Login" msgstr "Kirjaudu" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Nykyinen käyttäjä: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Kirjaudu ulos" -#: html/login.php msgid "Enter login credentials" msgstr "Kirjautumistiedot" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Käyttäjänimi tai sähköpostiosoite" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Salasana" -#: html/login.php msgid "Remember me" msgstr "Muista minut" -#: html/login.php msgid "Forgot Password" msgstr "Unohditko salasanasi?" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP:n kautta kirjoutuminen ei ole käytössä. Ole hyvä ja %svaihda HTTPS yhteyteen%s kirjautuaksesi." +msgstr "" +"HTTP:n kautta kirjoutuminen ei ole käytössä. Ole hyvä ja %svaihda HTTPS " +"yhteyteen%s kirjautuaksesi." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Haku kriteerit" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketit" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Valitun paketin tietoja ei löytynyt." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Jokin vaadituista kentistä on puutteellinen." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Salasanakentät eivät täsmää." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Salasanan pitää olla vähintään %s merkkiä pitkä." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Epäkelvollinen sähköpostiosoite." -#: html/passreset.php msgid "Password Reset" msgstr "Salasanan palautus" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Sähköpostiisi on nyt lähetetty varmistus linkki." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Salasanasi on palautettu onnistuneesti." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Vahvista sähköpostiositteesi:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Uuusi salasana:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Vahvista uusi salasana:" -#: html/passreset.php msgid "Continue" msgstr "Jatka" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." msgstr "" +"Jos olet unohtanut rekisteröityessäsi käyttämäsi sähköpostiosoitteen lähetä " +"viesti %saur-general%s postituslistalle." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Sähköpostiosoitteesi:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Pakettia, johon haluat siirtää äänet ja kommentit, ei löydy." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Valittuja paketteja ei ole poistettu. Muistitko laittaa raksin varmistus ruutuun?" - -#: html/pkgdel.php -msgid "Package Deletion" +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "" +"Valittuja paketteja ei ole poistettu. Muistitko laittaa raksin varmistus " +"ruutuun?" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Poista paketti: %s" +msgid "Package Deletion" +msgstr "Paketin poisto" + +msgid "Delete Package" +msgstr "Poista paketti" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Pakettin poistaminen on lopullista, sitä ei voi peruuttaa." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." -msgstr "" +msgstr "Vahvista toiminto valitsemalla valintaruutu." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Vahvista paketin poisto" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Poista" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "Vain Trusted- statuksen omaavat käyttäjät, sekä kehittäjät voivat poistaa paketteja." +msgstr "" +"Vain Trusted- statuksen omaavat käyttäjät, sekä kehittäjät voivat poistaa " +"paketteja." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" -msgstr "" +msgstr "Hylkää paketti" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" +"Käytä tätä lomaketta hylätäksesi pohjapaketin %s%s%s joka sisältää seuraavat " +"paketit:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"Valitsemalla valintaruudun, vahvista että haluat hylätä paketin ja siirtää " +"hallinnan käyttäjälle %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" +msgstr "Valitsemalla valintaruudun, vahvistat että haluat hylätä paketin." -#: html/pkgdisown.php msgid "Confirm to disown the package" -msgstr "" +msgstr "Vahvista paketin hylkäys" -#: html/pkgdisown.php msgid "Disown" -msgstr "" +msgstr "Hylkää" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +"Vain Trusted-statuksen omaavat käyttäjät, sekä kehittäjät voivat hylätä " +"paketteja." + +msgid "Flag Comment" +msgstr "" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Merkitse paketti vanhentuneeksi" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" +"Käytä tätä lomaketta merkitäksesi pohjapaketin %s%s%s ja seuraavat paketit " +"vanhentuneiksi:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"%sÄlä%s käytä tätä lomaketta ilmoittaaksesi bugeista. Käytä kommentteja " +"siihen." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Anna lisätietoja miksi paketti on vanhentunut, mieluiten sisältäen linkin " +"ilmoitukseen tai uuteen tiedostoon." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" -msgstr "" +msgstr "Kommentit" -#: html/pkgflag.php msgid "Flag" -msgstr "" +msgstr "Merkitse" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +"Vain rekisteröityneet käyttäjät voivat merkitä paketteja vanhentuneiksi." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakettien yhdistäminen" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Yhdistä paketit: %s" +msgid "Merge Package" +msgstr "Yhdistä toiseen pakettiin" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +"Käytä tätä lomaketta yhdistääksesi pohjapaketin %s%s%s toiseen pakettiin." -#: html/pkgmerge.php msgid "The following packages will be deleted: " -msgstr "" +msgstr "Seuraavat paketit poistetaan:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" +msgstr "Paketin yhdistämistä ei voi peruuttaa." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" +msgstr "Valitse kohdepaketti." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Yhdistä tähän pakettiin:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Vahvista pakettien yhdistäminen" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Liitä" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "Vain Trusted-statuksen omaavat käyttäjät, sekä kehittäjät voivat yhdistää paketteja." - -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" msgstr "" +"Vain Trusted-statuksen omaavat käyttäjät, sekä kehittäjät voivat yhdistää " +"paketteja." + +msgid "Submit Request" +msgstr "Lähetä pyyntö" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" -msgstr "" +msgstr "Sulje pyyntö" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Ensimmäinen" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Edellinen" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seuraava" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Viimeinen" -#: html/pkgreq.php template/header.php msgid "Requests" -msgstr "" +msgstr "Pyynnöt" -#: html/register.php template/header.php msgid "Register" msgstr "Rekisteröidy" -#: html/register.php msgid "Use this form to create an account." msgstr "Käytä tätä lomaketta uuden käyttäjätilin luomiseen." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Luotettu käyttäjä (TU)" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Ehdotuksen tietoja ei voitu noutaa." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Tämän ehdoksen äänestys on päättynyt." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." -msgstr "" +msgstr "Vain Trusted- statuksen omaavat käyttäjät voivat äänestää." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Et voi äänestää itseäsi koskevassa äänestyksessä." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Olet jo antanut äänesi tälle ehdotukselle." -#: html/tu.php msgid "Vote ID not valid." -msgstr "" +msgstr "Äänestys ID ei ole kelvollinen." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Avoimet äänestykset." -#: html/tu.php msgid "Past Votes" msgstr "Sulkeutuneet äänestykset." -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Äänestäjät" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +"Tunnuksien rekisteröinti on estetty IP-osoitteestasi, luultavasti toistuvien " +"roskapostihyökkäysten takia. Pahoittelemme aiheutunutta haittaa." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Käyttäjän tunnus puuttuu" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Käyttäjänimi ei ole kelvollinen." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Sen pitää olla %s-%s kirjaintapitkä" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Alkaa ja loppua kirjaimeen tai numeroon" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Voi sisältää vain yhden väliviivan, alaviivan tai pisteen." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Sähköpostiosoite ei ole kelvollinen." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." -msgstr "" +msgstr "PGP-avaimen sormenjälki ei ole kelvollinen." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." -msgstr "" +msgstr "Julkinen SSH-avain ei ole kelvollinen." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." -msgstr "" +msgstr "Käyttäjätunnuksen oikeuksia ei voitu korottaa." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Kieli ei ole vielä tuettuna." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." -msgstr "" +msgstr "Käyttäjänimi %s%s%s on jo käytössä." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." -msgstr "" +msgstr "Osoite %s%s%s on jo käytössä." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "Julkinen SSH-avain %s%s%s on jo käytössä." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." -msgstr "" +msgstr "Virhe luotaessa tiliä %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "" +msgstr "Käyttäjätili %s%s%s on nyt luotu." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" +msgstr "Salasanan palautuspyyntö on lähetetty sähköpostiosoitteeseesi." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "" +msgstr "Klikkaa Kirjaudu-linkkiä kirjautuaksesi." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." -msgstr "" +msgstr "Käyttäjätunnukseen %s%s%s ei tehty muutoksia." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "" +msgstr "Käyttäjätilin %s%s%s tiedot on nyt tallennettu." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +"Kirjautumislomake on estetty IP-osoitteestasi, luultavasti toistuvien " +"roskapostihyökkäysten takia. Pahoittelemme aiheutunutta haittaa." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -779,1028 +653,819 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Virheellinen käyttäjänimi tai salasana." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Epäkelvollinen sähköposti ja palautusavain yhdistelmä." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Sinulla ei ole oikeuksia tämän kommentin muokkaamiseen." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "Kommenttia ei ole olemassa." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "Kommentti ei voi olla tyhjä." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentti lisätty." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Sinun pitää kirjautua, ennen kuin voit muokata paketin tietoja." + +msgid "Missing comment ID." +msgstr "Kommentin tunnus puuttuu." + +msgid "No more than 5 comments can be pinned." +msgstr "Yli 5 kommenttia ei voi kiinnittää." + +msgid "You are not allowed to pin this comment." +msgstr "Sinulla ei ole oikeuksia tämän kommentin kiinnittämiseen." + +msgid "You are not allowed to unpin this comment." +msgstr "Sinulla ei ole oikeuksia tämän kommentin kiinnityksen poistamiseen." + +msgid "Comment has been pinned." +msgstr "Kommentti on kiinnitetty." + +msgid "Comment has been unpinned." +msgstr "Kommentin kiinnitys on poistettu." + msgid "Error retrieving package details." msgstr "Virhe haettaessa paketin tietoja." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paketin tietoja ei löydetty." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Sinun pitää kirjautua, ennen kuin voit muuttaa merkintöjä." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Et valinnut yhtään pakettia." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Valitut paketit on merkitty vanhentuneiksi." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Sinun pitää kirjautua, ennen kuin voit muuttaa merkintöjä." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Et valinnut yhtään pakettia." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Valittuilta paketeilta on poistettu merkintä." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Et valinnut yhtään pakettia poistettavaksi." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Valitut paketit on nyt poistettu." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Sinun pitää kirjautua, ennen kuin voit adoptoida paketteja." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Sinun pitää kirjautua, ennen kuin voit hylätä paketteja." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Et valinnut yhtään pakettia adoptoitavaksi." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Et valinnut yhtään pakettia hylättäväksi." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Valitut paketit on nyt adoptoitu." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Valitut paketiti on nyt hylätty." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Sinun pitää kirjautua, ennen kuin voit äänestää paketteja." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Sinun pitää kirjautua, ennen kuin voit perua äänesi." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Et valinnut yhtään pakettia äänestettäväksi." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Valittuille paketeille antamasi äänet on nyt peruttu." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Äänesi on nyt annettu valituille paketeille." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ei kyetty lisäämään ilmoituslistaan." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Saat nyt ilmoituksen paketin %s uusista kommenteista." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Et saa enää ilmoituksia paketin %s uusista kommenteista." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Sinun pitää kirjautua, ennen kuin voit muokata paketin tietoja." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Kommentin tunnus puuttuu." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Kommentti on poistettu." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Sinulla ei ole oikeuksia tämän kommentin poistamiseen." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Kommentti on poistettu." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Virheellinen nimi: vain pienet kirjaimet ovat sallittuja." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Käyttäjänimi" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "TIlin tyyppi" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Käyttäjä" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Kehittäjä" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Sähköpostiosoite" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Oikea nimi" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC nikki" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Tila" -#: template/account_details.php msgid "Inactive since" msgstr "" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiivinen" -#: template/account_details.php msgid "Last Login" msgstr "" -#: template/account_details.php msgid "Never" msgstr "Ei koskaan" -#: template/account_details.php msgid "View this user's packages" msgstr "Näytä käyttäjän paketit" -#: template/account_details.php msgid "Edit this user's account" msgstr "" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "vaaditaan" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Tavallinen käyttäjä" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Luotettu käyttäjä (TU)" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Käyttäjätili hyllytetty" -#: template/account_edit_form.php msgid "Inactive" msgstr "" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Salasana uudelleen:" -#: template/account_edit_form.php msgid "Language" msgstr "Kieli" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Julkinen SSH avain" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Lähetä ilmoitus uusista kommnteista" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Päivitä" -#: template/account_edit_form.php msgid "Create" msgstr "Luo" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Tyhjennä" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Hakuasi vastaavia paketteja ei löydy." -#: template/account_search_results.php msgid "Edit Account" msgstr "Muokkaa käyttäjätiliä" -#: template/account_search_results.php msgid "Suspended" msgstr "Hyllytä" -#: template/account_search_results.php msgid "Edit" msgstr "Muokkaa" -#: template/account_search_results.php msgid "Less" msgstr "Vähemmän" -#: template/account_search_results.php msgid "More" msgstr "Enemmän" -#: template/account_search_results.php msgid "No more results to display." msgstr "Ei enempää tuloksia" -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Omat paketit" -#: template/header.php msgid " My Account" msgstr "Omat tiedot" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakettitoiminnot" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Näytö PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "Näytä muutoshistoria" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Lataa tuorein versio" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Etsi wikistä" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Merkitty vanhentuneeksi" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Merkitse paketti vanhentuneeksi" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Poista merkintä" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Poista ääneni" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Äännestä pakettia" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "En halua enää ilmoituksia" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Lähetä ilmoitus uusista kommnteista" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Hallitse ylläpitäjäkumppaneita" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d käsittelemätön hallintapyyntö" msgstr[1] "%d käsittelemätöntä hallintapyyntöä" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Poista paketti" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Yhdistä toiseen pakettiin" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Ryhdy ylläpitäjäksi" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "tuntematon" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git kopionti osoite" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "vain luku" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Avainsanat" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Lisääjä" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ylläpitäjä" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Uusimman versionn luoja" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Äänet" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Lisättiin" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Päivitettiin" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Lisää kommentti" -#: template/pkg_comments.php msgid "View all comments" msgstr "Näytä kaikki kommentit" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Uusimmat kommentit" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Poista kommentti" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Kaikki kommentit" -#: template/pkg_details.php msgid "Package Details" msgstr "Paketin tiedot" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Ylipaketti" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Kuvaus" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Kotisivu" -#: template/pkg_details.php msgid "Visit the website for" msgstr "" -#: template/pkg_details.php msgid "Licenses" msgstr "Lisenssit" -#: template/pkg_details.php msgid "Groups" msgstr "" -#: template/pkg_details.php msgid "Conflicts" msgstr "Ristiriidat" -#: template/pkg_details.php msgid "Provides" msgstr "Tarjoaa paketit" -#: template/pkg_details.php msgid "Replaces" msgstr "Korvaa paketit" -#: template/pkg_details.php msgid "Dependencies" msgstr "Riippuvuudet" -#: template/pkg_details.php msgid "Required by" msgstr "Riippuvuutena paketeille" -#: template/pkg_details.php msgid "Sources" msgstr "Lähdetiedostot" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "" -#: template/pkgreq_form.php msgid "Deletion" msgstr "" -#: template/pkgreq_form.php msgid "Orphan" msgstr "" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Yhdistä pakettiin" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" -#: template/pkgreq_results.php msgid "Package" msgstr "" -#: template/pkgreq_results.php msgid "Filed by" msgstr "" -#: template/pkgreq_results.php msgid "Date" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" -#: template/pkgreq_results.php msgid "Accept" msgstr "" -#: template/pkgreq_results.php msgid "Locked" msgstr "" -#: template/pkgreq_results.php msgid "Close" msgstr "" -#: template/pkgreq_results.php msgid "Closed" msgstr "" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nimi, kuvaus" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Pelkkä nimi" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" -#: template/pkg_search_form.php msgid "All" msgstr "Kaikki" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Merkitty" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Ei merkitty" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nimi" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Äänestin" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Nouseva" -#: template/pkg_search_form.php msgid "Descending" msgstr "Laskeva" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" -#: template/pkg_search_form.php msgid "Search by" msgstr "Etsintäperuste" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Vanhentunut" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Järjestelyperuste" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Järjestelyperuste" -#: template/pkg_search_form.php msgid "Per page" msgstr "Sivua kohden" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Etsi" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Orvot" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Virhe pakettilistaa noudettaessa." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Hakuasi vastaavia paketteja ei löydy." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" -#: template/pkg_search_results.php msgid "Version" msgstr "Versio" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Kyllä" -#: template/pkg_search_results.php msgid "orphan" msgstr "orpo" -#: template/pkg_search_results.php msgid "Actions" msgstr "Toiminnot" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Merkitse vanhentuneeksi" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Ei vanhentunut" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptoi paketit" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Hylkää paketit" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Poista paketit" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Vahvista" -#: template/search_accounts_form.php msgid "Any type" msgstr "Mikä tahansa" -#: template/search_accounts_form.php msgid "Search" msgstr "Etsi" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Tilastoja" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Hylättyjä paketteja" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Uudet paketit 7 päivän sisällä" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paketteja päivitetty 7 päivän sisällä" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Vuoden aikana päivitettyjä paketteja" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paketteja ei ole koskaan päivitetty" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Rekisteröityjä käyttäjiä" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Luotettuja käyttäjiä" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Viimeisimmät päivitykset" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Tilastoni" -#: template/tu_details.php msgid "Proposal Details" msgstr "Ehdotuksen tiedot" -#: template/tu_details.php msgid "This vote is still running." msgstr "Tätä ehdotusta voi vielä äänestää." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Lisätty: %s Lisääjä: %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Loppu" -#: template/tu_details.php msgid "Result" msgstr "" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ei" -#: template/tu_details.php msgid "Abstain" msgstr "" -#: template/tu_details.php msgid "Total" msgstr "Yhteensä" -#: template/tu_details.php msgid "Participation" msgstr "" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ei tuloksia." -#: template/tu_list.php msgid "Start" msgstr "Alku" -#: template/tu_list.php msgid "Back" msgstr "Takaisin" diff --git a/po/fr.po b/po/fr.po index a8f31b0f..b05f0e96 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,10 +1,10 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Antoine Lubineau , 2012 -# Antoine Lubineau , 2012-2014 +# Antoine Lubineau , 2012-2016 # Cedric Girard , 2011,2014 # lordheavy , 2011 # lordheavy , 2013-2014 @@ -15,1799 +15,1520 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: French (http://www.transifex.com/lfleischer/aur/language/fr/)\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 21:38+0000\n" +"Last-Translator: Antoine Lubineau \n" +"Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" +"fr/)\n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Page non trouvée" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Désolé, la page que vous avez demandée n’existe pas." -#: html/503.php msgid "Service Unavailable" msgstr "Service indisponible" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Ne paniquez pas ! Le site est fermé pour maintenance. Nous serons bientôt de retour." +msgstr "" +"Ne paniquez pas ! Le site est fermé pour maintenance. Nous serons bientôt de " +"retour." -#: html/account.php msgid "Account" msgstr "Compte" -#: html/account.php template/header.php msgid "Accounts" msgstr "Comptes" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Vous n’avez pas la permission d’accéder à cet espace." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Impossible de trouver l’information pour l’utilisateur spécifié." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Vous n’avez pas la permission d’éditer ce compte." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilisez ce formulaire pour rechercher des comptes existants." -#: html/account.php msgid "You must log in to view user information." -msgstr "Vous devez vous authentifier pour voir les informations de l’utilisateur." +msgstr "" +"Vous devez vous authentifier pour voir les informations de l’utilisateur." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Ajoutez une proposition" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Action invalide." -#: html/addvote.php msgid "Username does not exist." msgstr "Le nom d'utilisateur n’existe pas." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s a déjà une proposition en cours à son sujet." -#: html/addvote.php msgid "Invalid type." msgstr "Type invalide." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Une proposition ne peut être vide." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nouvelle proposition enregistrée." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Soumettre une proposition à laquelle voter." -#: html/addvote.php msgid "Applicant/TU" msgstr "Requérant/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vide si non applicable)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Type" -#: html/addvote.php msgid "Addition of a TU" msgstr "Ajout d’un utilisateur de confiance." -#: html/addvote.php msgid "Removal of a TU" msgstr "Suppression d’un utilisateur de confiance" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Suppression d’un utilisateur de confiance (inactivité non prévenue)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendement du règlement" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposition" -#: html/addvote.php msgid "Submit" msgstr "Soumettre" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gérer les co-mainteneurs" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Éditer le commentaire" -#: html/home.php template/header.php msgid "Home" msgstr "Accueil" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Bienvenue sur AUR ! Veuillez lire les %sconsignes pour les utilisateurs d’AUR%s et les %sconsignes pour les utilisateurs de confiance%s pour plus d’information." +msgstr "" +"Bienvenue sur AUR ! Veuillez lire les %sconsignes pour les utilisateurs d’AUR" +"%s et les %sconsignes pour les utilisateurs de confiance%s pour plus " +"d’information." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Les PKGBUILD proposés %sdoivent%s respecter les %sstandards d’empaquetage d’Arch%s, sinon ils seront supprimés !" +msgstr "" +"Les PKGBUILD proposés %sdoivent%s respecter les %sstandards d’empaquetage " +"d’Arch%s, sinon ils seront supprimés !" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Pensez à voter pour vos paquets favoris !" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Certains paquets peuvent être disponibles sous forme binaire dans le dépôt [community]." +msgstr "" +"Certains paquets peuvent être disponibles sous forme binaire dans le dépôt " +"[community]." -#: html/home.php msgid "DISCLAIMER" msgstr "AVERTISSEMENT" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Les paquets AUR sont produits par des utilisateurs. Toute utilisation des " +"fichiers fournis se fait à vos propres risques." -#: html/home.php msgid "Learn more..." msgstr "En apprendre plus..." -#: html/home.php msgid "Support" msgstr "Soutien" -#: html/home.php msgid "Package Requests" msgstr "Requêtes de paquet" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Il existe trois types de requêtes qui peuvent être soumises dans la boîte %sActions du paquet%s sur la page des détails d'un paquet :" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Il existe trois types de requêtes qui peuvent être soumises dans la boîte " +"%sActions du paquet%s sur la page des détails d'un paquet :" -#: html/home.php msgid "Orphan Request" msgstr "Requête de destitution" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Demande qu'un paquet soit destitué, c'est-à-dire quand le mainteneur est inactif et que le paquet a été marqué comme périmé depuis un long moment." +msgstr "" +"Demande qu'un paquet soit destitué, c'est-à-dire quand le mainteneur est " +"inactif et que le paquet a été marqué comme périmé depuis un long moment." -#: html/home.php msgid "Deletion Request" msgstr "Requête de suppression" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Demande qu'un paquet soit supprimé d'AUR. Prière de ne pas l'utiliser si un paquet est cassé et que le problème peut être réglé facilement. À la place, contactez le mainteneur du paquet, et soumettez une requête de destitution si nécessaire." +msgstr "" +"Demande qu'un paquet soit supprimé d'AUR. Prière de ne pas l'utiliser si un " +"paquet est cassé et que le problème peut être réglé facilement. À la place, " +"contactez le mainteneur du paquet, et soumettez une requête de destitution " +"si nécessaire." -#: html/home.php msgid "Merge Request" msgstr "Requête de fusion" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Demande que le paquet soit fusionné dans un autre. Peut être utilisé quand un paquet a besoin d'être renommé ou bien remplacé par un paquet splitté." +msgstr "" +"Demande que le paquet soit fusionné dans un autre. Peut être utilisé quand " +"un paquet a besoin d'être renommé ou bien remplacé par un paquet splitté." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Si vous voulez débattre d'une requête, vous pouvez utiliser la mailing-list %saur-requests%s. Cependant, merci de ne pas utiliser cette liste pour soumettre des requêtes." +msgstr "" +"Si vous voulez débattre d'une requête, vous pouvez utiliser la mailing-list " +"%saur-requests%s. Cependant, merci de ne pas utiliser cette liste pour " +"soumettre des requêtes." -#: html/home.php msgid "Submitting Packages" msgstr "Soumission de paquets" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Git par-dessus SSH est maintenant utilisé pour soumettre des paquets sur AUR. Voir la section %sSoumettre des paquets%s sur la page Arch User Repository du wiki pour plus de détails." +msgstr "" +"Git par-dessus SSH est maintenant utilisé pour soumettre des paquets sur " +"AUR. Voir la section %sSoumettre des paquets%s sur la page Arch User " +"Repository du wiki pour plus de détails." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Les empreintes SSH suivantes sont utilisées pour AUR :" -#: html/home.php msgid "Discussion" msgstr "Discussion" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Les discussions générales en rapport avec AUR (Arch User Repository, dépôt des utilisateurs d’Arch Linux) et les TU (Trusted User, utilisateurs de confiance) ont lieu sur %saur-general%s. Pour les discussions en rapport avec le développement de l'interface web d'AUR, utilisez la mailing-list %saur-dev.%s" +msgstr "" +"Les discussions générales en rapport avec AUR (Arch User Repository, dépôt " +"des utilisateurs d’Arch Linux) et les TU (Trusted User, utilisateurs de " +"confiance) ont lieu sur %saur-general%s. Pour les discussions en rapport " +"avec le développement de l'interface web d'AUR, utilisez la mailing-list " +"%saur-dev.%s" -#: html/home.php msgid "Bug Reporting" msgstr "Rapports de bug" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" +"Si vous trouvez un bug dans l'interface web d'AUR, merci de remplir un " +"rapport de bug sur le %sbug tracker%s. N’utilisez le tracker %sque%s pour " +"les bugs de l'interface web d'AUR. Pour signaler un bug dans un paquet, " +"contactez directement le mainteneur du paquet, ou laissez un commentaire sur " +"la page du paquet." -#: html/home.php msgid "Package Search" msgstr "Recherche d'un paquet" -#: html/index.php msgid "Adopt" msgstr "Adopter" -#: html/index.php msgid "Vote" msgstr "Voter" -#: html/index.php msgid "UnVote" msgstr "Retirer le vote" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notifier" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne plus notifier" -#: html/index.php msgid "UnFlag" msgstr "Ne plus marquer comme périmé" -#: html/login.php template/header.php msgid "Login" msgstr "Se connecter" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Connecté en tant que : %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Déconnexion" -#: html/login.php msgid "Enter login credentials" msgstr "Entrez vos identifiants" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Nom d'utilisateur ou adresse e-mail :" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Mot de passe" -#: html/login.php msgid "Remember me" msgstr "Se souvenir de moi" -#: html/login.php msgid "Forgot Password" msgstr "Mot de passe oublié" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "La connexion HTTP est désactivée. Veuillez %sbasculer en HTTPS%s pour pouvoir vous connecter." +msgstr "" +"La connexion HTTP est désactivée. Veuillez %sbasculer en HTTPS%s pour " +"pouvoir vous connecter." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critères de recherche" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquets" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erreur en essayant de retrouver les détails du paquets." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Il manque un champ requis." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Les champs du mot de passe ne correspondent pas." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Votre mot de passe doit comprendre au moins %s caractères." -#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail invalide" -#: html/passreset.php msgid "Password Reset" msgstr "Réinitialisation de mot de passe" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Vérifiez votre e-mail pour le lien de confirmation." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Votre mot de passe a été réinitialisé avec succès." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirmez votre adresse e-mail :" -#: html/passreset.php msgid "Enter your new password:" msgstr "Entrez votre nouveau mot de passe :" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirmez votre nouveau mot de passe :" -#: html/passreset.php msgid "Continue" msgstr "Continuer" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si vous avez oublié avec quelle adresse e-mail vous vous êtes inscrit, veuillez envoyer un message sur la mailing-list %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Si vous avez oublié avec quelle adresse e-mail vous vous êtes inscrit, " +"veuillez envoyer un message sur la mailing-list %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Entrez votre adresse e-mail :" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "Les paquets sélectionnés n'ont pas été destitués, vérifiez la boîte de confirmation." +msgstr "" +"Les paquets sélectionnés n'ont pas été destitués, vérifiez la boîte de " +"confirmation." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Impossible de trouver le paquet dans lequel fusionner les votes et les commentaires." +msgstr "" +"Impossible de trouver le paquet dans lequel fusionner les votes et les " +"commentaires." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Impossible de fusionner un paquet de base avec lui-même" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Les paquets sélectionnés n'ont pas été supprimés, cochez la case de confirmation." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Les paquets sélectionnés n'ont pas été supprimés, cochez la case de " +"confirmation." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Suppression de paquet" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Supprimer le paquet : %s." +msgid "Delete Package" +msgstr "Supprimer le paquet" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Utilisez ce formulaire pour supprimer le paquet de base %s%s%s et les paquets suivants de AUR :" +msgstr "" +"Utilisez ce formulaire pour supprimer le paquet de base %s%s%s et les " +"paquets suivants de AUR :" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "La suppression d’un paquet est permanente." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Cochez la case pour confirmer l’action." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmer la suppression du paquet" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Supprimer" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent effacer des paquets." +msgstr "" +"Seuls les Utilisateur de Confiance et les Développeurs peuvent effacer des " +"paquets." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Destituer le paquet" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Destituer le paquet : %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Utilisez ce formulaire pour destituer le paquet de base %s%s%s qui inclut les paquets suivants : " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Utilisez ce formulaire pour destituer le paquet de base %s%s%s qui inclut " +"les paquets suivants : " -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "En cochant la case, vous confirmez que vous voulez destituer le paquet et transférer sa propriété à %s%s%s." +msgstr "" +"En cochant la case, vous confirmez que vous voulez destituer le paquet et " +"transférer sa propriété à %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "En cochant la case, vous confirmez que vous voulez destituer le paquet." +msgstr "" +"En cochant la case, vous confirmez que vous voulez destituer le paquet." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirmer la destitution du paquet" -#: html/pkgdisown.php msgid "Disown" msgstr "Destituer" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent destituer des paquets." +msgstr "" +"Seuls les Utilisateur de Confiance et les Développeurs peuvent destituer des " +"paquets." + +msgid "Flag Comment" +msgstr "Signaler le commentaire" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Marquer le paquet comme périmé" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" +"Utilisez ce formulaire pour marquer le paquet de base %s%s%s et les paquets " +"suivants périmés :" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"Merci de %sne pas%s utiliser ce formulaire pour rapporter des bugs. Utilisez " +"les commentaires du paquet à la place." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Entrez les détails de pourquoi le paquet est périmé, de préférence en " +"incluant un lien vers l'annonce de la version ou bien vers l'archive de la " +"nouvelle version." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Commentaires" -#: html/pkgflag.php msgid "Flag" msgstr "Marquer comme périmé" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +"Seuls les utilisateurs enregistrés peuvent marquer les paquets périmés." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusion de paquet" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Fusionner le paquet : %s" +msgid "Merge Package" +msgstr "Fusionner le paquet" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Utilisez ce formulaire pour fusionner ce paquet de base %s%s%s dans un autre paquet." +msgstr "" +"Utilisez ce formulaire pour fusionner ce paquet de base %s%s%s dans un autre " +"paquet." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Les paquets suivants vont être supprimés :" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "La fusion du paquet est une opération irréversible." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Saisissez le nom du paquet dans lequel vous souhaitez fusionner ce paquet." +msgstr "" +"Saisissez le nom du paquet dans lequel vous souhaitez fusionner ce paquet." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionner dans :" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmer la fusion du paquet" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusionner" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent fusionner des paquets." +msgstr "" +"Seuls les Utilisateur de Confiance et les Développeurs peuvent fusionner des " +"paquets." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Requête de Fichier" +msgid "Submit Request" +msgstr "Soumettre la demande" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fermer la requête" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Première" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Précédente" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Suivant" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Dernière" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Requêtes" -#: html/register.php template/header.php msgid "Register" msgstr "S’inscrire" -#: html/register.php msgid "Use this form to create an account." msgstr "Utilisez ce formulaire pour créer un compte." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Utilisateur de confiance (TU)" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Impossible d’obtenir le détail de la proposition." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Le vote est clos pour cette proposition." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Seuls les Utilisateurs de Confiance sont autorisés à voter." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Vous ne pouvez pas voter dans une proposition à votre sujet." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Vous avez déjà voté pour cette proposition." -#: html/tu.php msgid "Vote ID not valid." msgstr "ID de vote non valide." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votes en cours" -#: html/tu.php msgid "Past Votes" msgstr "Votes passés" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votants" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "La création de compte est désactivée pour votre adresse IP, probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +msgstr "" +"La création de compte est désactivée pour votre adresse IP, probablement à " +"cause d’attaques de spammeurs. Désolé pour le désagrément." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID d'utilisateur manquant" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Le nom d'utilisateur choisi n'est pas valide." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Il doit être compris entre %s et %s caractères," -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "doit débuter et se terminer par une lettre ou un chiffre." -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "ne peut contenir qu'un seul point, tiret bas ou virgule," -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adresse email n'est pas valide." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "L’empreinte de clé PGP est invalide." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clé SSH publique est invalide." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Ne peut pas augmenter les autorisations du compte." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Cette langue n'est pas supportée pour le moment." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Le nom d’utilisateur %s%s%s, est déjà utilisé." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L’adresse %s%s%s est déjà utilisée." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clé SSH publique, %s%s%s, est déjà utilisée." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erreur en essayant de créer le compte %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Le compte %s%s%s a été créé avec succès." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "Une clé de réinitialisation de mot de passe vous a été envoyée par e-mail." +msgstr "" +"Une clé de réinitialisation de mot de passe vous a été envoyée par e-mail." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Cliquez sur le lien de connexion ci-dessus pour utiliser votre compte." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Aucun changement n'ont été fait au compte, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Le compte %s%s%s a été modifié avec succès." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Le formulaire de connexion est actuellement désactivé pour votre adresse IP, probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +msgstr "" +"Le formulaire de connexion est actuellement désactivé pour votre adresse IP, " +"probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Compte suspendu." -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Votre mot de passe a été réinitialisé. Si vous venez de créer un nouveau compte, veuillez utiliser le lien présent dans l’e-mail de confirmation pour modifier le mot de passe. Sinon, demandez une clé de réinitialisation depuis la page « %sRéinitialisation de mot de passe%s »." +msgstr "" +"Votre mot de passe a été réinitialisé. Si vous venez de créer un nouveau " +"compte, veuillez utiliser le lien présent dans l’e-mail de confirmation pour " +"modifier le mot de passe. Sinon, demandez une clé de réinitialisation depuis " +"la page « %sRéinitialisation de mot de passe%s »." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Mauvais nom d'utilisateur ou mot de passe." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "Une erreur est survenue en essayant de générer une session utilisateur." +msgstr "" +"Une erreur est survenue en essayant de générer une session utilisateur." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinaison entre l'e-mail et la clef de réinitialisation invalides." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Aucun" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Voir les informations du compte pour %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." -msgstr "" +msgstr "L'ID du paquet de base ou le nom du paquet de base est manquant." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Vous n'êtes pas autorisé(e) à éditer ce commentaire." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "Le commentaire n'existe pas." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "Le commentaire ne peut pas être vide." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Le commentaire a été ajouté." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php -msgid "Error retrieving package details." -msgstr "Erreur en recherchant les détails du paquet." - -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php -msgid "Package details could not be found." -msgstr "Les détails du paquet ne peuvent pas être trouvés." - -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can flag packages." -msgstr "Vous devez être authentifié avant de pouvoir étiqueter des paquets." - -#: lib/pkgbasefuncs.inc.php -msgid "You did not select any packages to flag." -msgstr "Vous n'avez sélectionné aucun paquet à étiqueter." - -#: lib/pkgbasefuncs.inc.php -msgid "The selected packages have been flagged out-of-date." -msgstr "Les paquets sélectionnés ont été étiquetés comme périmés." - -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can unflag packages." -msgstr "Vous devez être authentifié avant de pouvoir retirer l'étiquetage des paquets." - -#: lib/pkgbasefuncs.inc.php -msgid "You did not select any packages to unflag." -msgstr "Vous n'avez sélectionné aucun paquet auquel retirer l'étiquetage." - -#: lib/pkgbasefuncs.inc.php -msgid "The selected packages have been unflagged." -msgstr "Les paquets sélectionnés ne sont plus étiquetés." - -#: lib/pkgbasefuncs.inc.php -msgid "You do not have permission to delete packages." -msgstr "Vous n’avez pas la permission de supprimer des paquets." - -#: lib/pkgbasefuncs.inc.php -msgid "You did not select any packages to delete." -msgstr "Vous n'avez sélectionné aucun paquet à supprimer." - -#: lib/pkgbasefuncs.inc.php -msgid "The selected packages have been deleted." -msgstr "Les paquets sélectionnés ont été supprimés." - -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can adopt packages." -msgstr "Vous devez être authentifié avant de pouvoir adopter des paquets." - -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can disown packages." -msgstr "Vous devez être authentifié avant de pouvoir abandonner des paquets." - -#: lib/pkgbasefuncs.inc.php -msgid "You did not select any packages to adopt." -msgstr "Vous n'avez pas sélectionné de paquet à adopter." - -#: lib/pkgbasefuncs.inc.php -msgid "You did not select any packages to disown." -msgstr "Vous n'avez sélectionné aucun paquet à abandonner." - -#: lib/pkgbasefuncs.inc.php -msgid "The selected packages have been adopted." -msgstr "Les paquets sélectionnés ont été adoptés." - -#: lib/pkgbasefuncs.inc.php -msgid "The selected packages have been disowned." -msgstr "Les paquets sélectionnés ont été abandonnés." - -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can vote for packages." -msgstr "Vous devez être authentifié avant de pouvoir voter pour des paquets." - -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can un-vote for packages." -msgstr "Vous devez être authentifié avant de pouvoir retirer votre vote sur des paquets." - -#: lib/pkgbasefuncs.inc.php -msgid "You did not select any packages to vote for." -msgstr "Vous n'avez sélectionné aucun paquet pour lequel vous souhaitez voter." - -#: lib/pkgbasefuncs.inc.php -msgid "Your votes have been removed from the selected packages." -msgstr "Vos votes ont été retirés des paquets sélectionnés." - -#: lib/pkgbasefuncs.inc.php -msgid "Your votes have been cast for the selected packages." -msgstr "Vos votes ont été distribués aux paquets sélectionnés." - -#: lib/pkgbasefuncs.inc.php -msgid "Couldn't add to notification list." -msgstr "Ajout impossible à la liste de notification." - -#: lib/pkgbasefuncs.inc.php -#, php-format -msgid "You have been added to the comment notification list for %s." -msgstr "Vous avez été ajouté à la liste des notifications de commentaire pour %s." - -#: lib/pkgbasefuncs.inc.php -#, php-format -msgid "You have been removed from the comment notification list for %s." -msgstr "Vous avez été retiré de la liste des notifications de commentaire pour %s." - -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "Vous devez vous identifier avant de pouvoir éditer les informations du paquet." +msgstr "" +"Vous devez vous identifier avant de pouvoir éditer les informations du " +"paquet." -#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "ID de commentaire manquant." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Le commentaire a été supprimé." +msgid "No more than 5 comments can be pinned." +msgstr "Au plus 5 commentaires peuvent être épinglés." + +msgid "You are not allowed to pin this comment." +msgstr "Vous n’avez pas le droit d’épingler ce commentaire." + +msgid "You are not allowed to unpin this comment." +msgstr "Vous n’avez pas le droit de désépingler ce commentaire." + +msgid "Comment has been pinned." +msgstr "Le commentaire a été épinglé." + +msgid "Comment has been unpinned." +msgstr "Le commentaire a été désépinglé." + +msgid "Error retrieving package details." +msgstr "Erreur en recherchant les détails du paquet." + +msgid "Package details could not be found." +msgstr "Les détails du paquet ne peuvent pas être trouvés." + +msgid "You must be logged in before you can flag packages." +msgstr "Vous devez être authentifié avant de pouvoir étiqueter des paquets." + +msgid "You did not select any packages to flag." +msgstr "Vous n'avez sélectionné aucun paquet à étiqueter." + +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" +"Les paquets sélectionnés n'ont pas été étiquetés, merci d'entrer un " +"commentaire." + +msgid "The selected packages have been flagged out-of-date." +msgstr "Les paquets sélectionnés ont été étiquetés comme périmés." + +msgid "You must be logged in before you can unflag packages." +msgstr "" +"Vous devez être authentifié avant de pouvoir retirer l'étiquetage des " +"paquets." + +msgid "You did not select any packages to unflag." +msgstr "Vous n'avez sélectionné aucun paquet auquel retirer l'étiquetage." + +msgid "The selected packages have been unflagged." +msgstr "Les paquets sélectionnés ne sont plus étiquetés." + +msgid "You do not have permission to delete packages." +msgstr "Vous n’avez pas la permission de supprimer des paquets." + +msgid "You did not select any packages to delete." +msgstr "Vous n'avez sélectionné aucun paquet à supprimer." + +msgid "The selected packages have been deleted." +msgstr "Les paquets sélectionnés ont été supprimés." + +msgid "You must be logged in before you can adopt packages." +msgstr "Vous devez être authentifié avant de pouvoir adopter des paquets." + +msgid "You must be logged in before you can disown packages." +msgstr "Vous devez être authentifié avant de pouvoir abandonner des paquets." + +msgid "You did not select any packages to adopt." +msgstr "Vous n'avez pas sélectionné de paquet à adopter." + +msgid "You did not select any packages to disown." +msgstr "Vous n'avez sélectionné aucun paquet à abandonner." + +msgid "The selected packages have been adopted." +msgstr "Les paquets sélectionnés ont été adoptés." + +msgid "The selected packages have been disowned." +msgstr "Les paquets sélectionnés ont été abandonnés." + +msgid "You must be logged in before you can vote for packages." +msgstr "Vous devez être authentifié avant de pouvoir voter pour des paquets." + +msgid "You must be logged in before you can un-vote for packages." +msgstr "" +"Vous devez être authentifié avant de pouvoir retirer votre vote sur des " +"paquets." + +msgid "You did not select any packages to vote for." +msgstr "Vous n'avez sélectionné aucun paquet pour lequel vous souhaitez voter." + +msgid "Your votes have been removed from the selected packages." +msgstr "Vos votes ont été retirés des paquets sélectionnés." + +msgid "Your votes have been cast for the selected packages." +msgstr "Vos votes ont été distribués aux paquets sélectionnés." + +msgid "Couldn't add to notification list." +msgstr "Ajout impossible à la liste de notification." + +#, php-format +msgid "You have been added to the comment notification list for %s." +msgstr "" +"Vous avez été ajouté à la liste des notifications de commentaire pour %s." + +#, php-format +msgid "You have been removed from the comment notification list for %s." +msgstr "" +"Vous avez été retiré de la liste des notifications de commentaire pour %s." + +msgid "You are not allowed to undelete this comment." +msgstr "Vous n’avez pas l’autorisation de restaurer ce commentaire." + +msgid "Comment has been undeleted." +msgstr "Le commentaire a été restauré." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Vous n'êtes pas autorisé(e) à supprimer ce commentaire." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been edited." -msgstr "" +msgid "Comment has been deleted." +msgstr "Le commentaire a été supprimé." + +msgid "Comment has been edited." +msgstr "Le commentaire a été édité." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Vous n'êtes pas autorisé à éditer les mots-clés de ce paquet de base." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Les mots-clés du paquet de base ont été mis à jour." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Vous n'êtes pas autorisé à gérer les co-mainteneurs de ce paquet de base." +msgstr "" +"Vous n'êtes pas autorisé à gérer les co-mainteneurs de ce paquet de base." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nom d'utilisateur invalide : %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Les co-mainteneurs du paquet de base ont été mis à jour." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Voir le paquet" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" -msgstr "" +msgstr "a besoin de %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Vous devez être identifié pour soumette des requêtes sur des paquets." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nom invalide : seules les lettres minuscules sont autorisées." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "La zone de commentaire ne doit pas être vide." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Type de requête invalide." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Requête ajouté avec succès." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Raison incorrecte." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "Seuls les utilisateurs de confiance et les développeurs peuvent fermer les requêtes." +msgstr "" +"Seuls les utilisateurs de confiance et les développeurs peuvent fermer les " +"requêtes." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Requête fermée avec succès." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Vous ne pouvez pas utiliser ce formulaire pour effacer le compte AUR %s de façon permanente." +msgstr "" +"Vous ne pouvez pas utiliser ce formulaire pour effacer le compte AUR %s de " +"façon permanente." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sATTENTION%s: cette action ne peut être annulée" -#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmer la suppression" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nom d'utilisateur" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Type de compte" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilisateur" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Développeur" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Utilisateur de confiance (TU) et Développeur" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresse e-mail" -#: template/account_details.php msgid "hidden" -msgstr "" +msgstr "caché" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nom réel" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Pseudo IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Empreinte de clé PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "État" -#: template/account_details.php msgid "Inactive since" msgstr "Inactif depuis" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actif" -#: template/account_details.php msgid "Last Login" msgstr "Dernière connexion." -#: template/account_details.php msgid "Never" msgstr "Jamais" -#: template/account_details.php msgid "View this user's packages" msgstr "Visualiser les paquets de cet utilisateur." -#: template/account_details.php msgid "Edit this user's account" msgstr "Éditer le compte de cet utilisateur." -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Cliquez %sici%s si vous voulez effacer ce compte de façon définitive." -#: template/account_edit_form.php msgid "required" msgstr "requis" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilisateur normal" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Utilisateur de confiance (TU)" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Compte suspendu" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inactif" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Assurez-vous d'avoir correctement entré votre adresse e-mail, sinon vous " +"n'arriverez plus à vous connecter." -#: template/account_edit_form.php msgid "Hide Email Address" -msgstr "" +msgstr "Cacher l'adresse e-mail" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Retapez le mot de passe" -#: template/account_edit_form.php msgid "Language" msgstr "Langue" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "L'information suivante est requise uniquement si vous voulez soumettre des paquets sur AUR" +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"L'information suivante est requise uniquement si vous voulez soumettre des " +"paquets sur AUR" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clé SSH publique" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Mise à jour" +msgid "Notification settings" +msgstr "Réglages des notifications" -#: template/account_edit_form.php -msgid "Create" -msgstr "Créer" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Réinitialiser" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Aucun résultat ne correspond à vos critères de recherche." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Éditer le compte" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Suspendu" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Éditer" - -#: template/account_search_results.php -msgid "Less" -msgstr "Moins" - -#: template/account_search_results.php -msgid "More" -msgstr "Plus" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Plus de résultats à afficher." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Gérer les co-mainteneurs : %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Utilisez ce formulaire pour ajouter des co-mainteneurs pour %s%s%s (un nom d'utilisateur par ligne) :" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Utilisateurs" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Sauvegarder" - -#: template/header.php -msgid "My Packages" -msgstr "Mes paquets" - -#: template/header.php -msgid " My Account" -msgstr "Mon compte" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Actions du paquet" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Voir le PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Voir les changements" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Télécharger un instantané" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Rechercher sur le wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marqué comme périmé" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Marquer le paquet comme périmé" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Ne plus marquer le paquet comme périmé" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Retirer le vote" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Voter pour ce paquet" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Désactiver les notifications" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Avertir des nouveaux commentaires" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "Notifications de mises à jour de paquets" + +msgid "Update" +msgstr "Mise à jour" + +msgid "Create" +msgstr "Créer" + +msgid "Reset" +msgstr "Réinitialiser" + +msgid "No results matched your search criteria." +msgstr "Aucun résultat ne correspond à vos critères de recherche." + +msgid "Edit Account" +msgstr "Éditer le compte" + +msgid "Suspended" +msgstr "Suspendu" + +msgid "Edit" +msgstr "Éditer" + +msgid "Less" +msgstr "Moins" + +msgid "More" +msgstr "Plus" + +msgid "No more results to display." +msgstr "Plus de résultats à afficher." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Utilisez ce formulaire pour ajouter des co-mainteneurs pour %s%s%s (un nom " +"d'utilisateur par ligne) :" + +msgid "Users" +msgstr "Utilisateurs" + +msgid "Save" +msgstr "Sauvegarder" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "Commentaire de paquet périmé : %s" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" +"%s%s%s a marqué %s%s%s comme périmé ls %s%s%s pour la raison suivante :" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "%s%s%s n’est pas marqué comme périmé." + +msgid "Return to Details" +msgstr "Retourner aux détails" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Copyright %s 2004-%d aurweb Development Team." + +msgid "My Packages" +msgstr "Mes paquets" + +msgid " My Account" +msgstr "Mon compte" + +msgid "Package Actions" +msgstr "Actions du paquet" + +msgid "View PKGBUILD" +msgstr "Voir le PKGBUILD" + +msgid "View Changes" +msgstr "Voir les changements" + +msgid "Download snapshot" +msgstr "Télécharger un instantané" + +msgid "Search wiki" +msgstr "Rechercher sur le wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "Marqué comme périmé (%s)" + +msgid "Flag package out-of-date" +msgstr "Marquer le paquet comme périmé" + +msgid "Unflag package" +msgstr "Ne plus marquer le paquet comme périmé" + +msgid "Remove vote" +msgstr "Retirer le vote" + +msgid "Vote for this package" +msgstr "Voter pour ce paquet" + +msgid "Disable notifications" +msgstr "Désactiver les notifications" + msgid "Manage Co-Maintainers" msgstr "Gérer les co-mainteneurs" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requête en attente" msgstr[1] "%d requêtes en attente" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Supprimer le paquet" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Fusionner le paquet" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter ce paquet" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "inconnu" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Détails du paquet de base" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL de clone (Git)" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "lecture seule" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Mots-clés" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Contributeur" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mainteneur" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Dernier packageur" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votes" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularité" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Première soumission" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Dernière mise à jour" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Commentaire édité le : %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Ajouter un commentaire" -#: template/pkg_comments.php msgid "View all comments" msgstr "Voir tous les commentaires" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "Commentaires épinglés" + msgid "Latest Comments" msgstr "Derniers commentaires" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s a commenté le %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Commentaire anonyme le %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "supprimé le %s par %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "" +msgid "deleted on %s" +msgstr "supprimé le %s" + +#, php-format +msgid "edited on %s by %s" +msgstr "édité le %s par %s" + +#, php-format +msgid "edited on %s" +msgstr "édité le %s" + +msgid "Undelete comment" +msgstr "Restaurer le commentaire" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Effacer le commentaire" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "Épingler le commentaire" + +msgid "Unpin comment" +msgstr "Désépingler le commentaire" + msgid "All comments" msgstr "Tous les commentaires" -#: template/pkg_details.php msgid "Package Details" msgstr "Détails du paquet" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquet de base" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Description" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Lien" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Accéder au site web de" -#: template/pkg_details.php msgid "Licenses" msgstr "Licences" -#: template/pkg_details.php msgid "Groups" msgstr "Groupes" -#: template/pkg_details.php msgid "Conflicts" msgstr "En conflit avec" -#: template/pkg_details.php msgid "Provides" msgstr "Fournit" -#: template/pkg_details.php msgid "Replaces" msgstr "Remplace" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dépendances" -#: template/pkg_details.php msgid "Required by" msgstr "Requis par" -#: template/pkg_details.php msgid "Sources" msgstr "Sources" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Fermer la requête : %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Utiliser ce formulaire pour fermer la requête pour le paquet de base %s%s%s." +msgstr "" +"Utiliser ce formulaire pour fermer la requête pour le paquet de base %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Note" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Le champ commentaires peut être laissé vide. Cependant, il est fortement recommandé d'ajouter un commentaire lors du rejet d'une requête." +msgstr "" +"Le champ commentaires peut être laissé vide. Cependant, il est fortement " +"recommandé d'ajouter un commentaire lors du rejet d'une requête." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Raison" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Accepté" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Rejeté" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Requête de Fichier: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Utilisez ce formulaire pour soumettre une requête concernant le paquet de base %s%s%s contenant les paquets suivant:" +msgstr "" +"Utilisez ce formulaire pour soumettre une requête concernant le paquet de " +"base %s%s%s contenant les paquets suivant:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Type de requête" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Suppression" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Rendre orphelin" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fusionner dans" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d paquet demandé trouvé." msgstr[1] "%d paquets demandés trouvés." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Page %d sur %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Paquet" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Soumise par" -#: template/pkgreq_results.php msgid "Date" msgstr "Date" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d jours restants" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d heure restante" msgstr[1] "%d heures restantes" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 heure restante" -#: template/pkgreq_results.php msgid "Accept" msgstr "Accepter" -#: template/pkgreq_results.php msgid "Locked" msgstr "Verrouillé" -#: template/pkgreq_results.php msgid "Close" msgstr "Fermer" -#: template/pkgreq_results.php msgid "Closed" msgstr "Fermé" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nom, Description" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Noms seulement" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nom exact" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquet de base exact" -#: template/pkg_search_form.php msgid "All" msgstr "Tout" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Étiqueté" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Non étiqueté" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nom" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Voté" -#: template/pkg_search_form.php msgid "Last modified" -msgstr "" +msgstr "Dernière modification" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendant" -#: template/pkg_search_form.php msgid "Descending" msgstr "Descendant" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Saisissez les critères de recherche" -#: template/pkg_search_form.php msgid "Search by" msgstr "Rechercher par" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Périmé" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Trier par" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordre de tri" -#: template/pkg_search_form.php msgid "Per page" msgstr "Par page" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Aller" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Orphelins" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erreur en récupérant la liste des paquets." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Aucun paquet ne correspond à vos critères de recherche." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquet trouvé." msgstr[1] "%d paquets trouvés." -#: template/pkg_search_results.php msgid "Version" msgstr "Version" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "La popularité est calculée à partir de la somme de tous les votes, chacun étant pondéré par un facteur de 0.98 par jour depuis sa création." +msgstr "" +"La popularité est calculée à partir de la somme de tous les votes, chacun " +"étant pondéré par un facteur de 0.98 par jour depuis sa création." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Oui" -#: template/pkg_search_results.php msgid "orphan" msgstr "orphelin" -#: template/pkg_search_results.php msgid "Actions" msgstr "Actions" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Étiqueter comme périmé" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Retirer l'étiquette « périmé »" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter des paquets" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonner les paquets" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Supprimer des paquets" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmer" -#: template/search_accounts_form.php msgid "Any type" msgstr "Tout type" -#: template/search_accounts_form.php msgid "Search" msgstr "Rechercher" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiques" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquets orphelins" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquets ajoutés au cours des 7 derniers jours" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquets mis à jour au cours des 7 derniers jours" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquets mis à jour dans l'année écoulée" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquets jamais mis à jour" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilisateurs enregistrés" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Utilisateurs de confiance (TU)" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Mises à jour récentes" -#: template/stats/user_table.php +msgid "more" +msgstr "plus" + msgid "My Statistics" msgstr "Mes statistiques" -#: template/tu_details.php msgid "Proposal Details" msgstr "Détails de la proposition" -#: template/tu_details.php msgid "This vote is still running." msgstr "Ce vote est toujours en cours." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Soumission: %s par %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" -#: template/tu_details.php msgid "Result" msgstr "Résultat" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Non" -#: template/tu_details.php msgid "Abstain" msgstr "Abstention" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" msgstr "Participation" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Derniers votes de TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Dernier vote" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Aucun résultat trouvé." -#: template/tu_list.php msgid "Start" msgstr "Début" -#: template/tu_list.php msgid "Back" msgstr "Retour" diff --git a/po/he.po b/po/he.po index fb98fe69..bfcdf8bc 100644 --- a/po/he.po +++ b/po/he.po @@ -1,777 +1,596 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/he/)\n" +"Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" +"he/)\n" +"Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: he\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "" -#: html/503.php msgid "Service Unavailable" msgstr "" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" -#: html/account.php msgid "Account" msgstr "" -#: html/account.php template/header.php msgid "Accounts" msgstr "חשבונות" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "אין לך גישה לאזור זה." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "לא ניתן לקבל נתונים עבור המשתמש שנבחר." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "אין לך הרשאה לערוך חשבון זה." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "נא להשתמש בטופס על מנת לחפש אחר חשבונות קיימים." -#: html/account.php msgid "You must log in to view user information." msgstr "עליך להתחבר על מנת לצפות בנתוני משתמש." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "הוספת הצעה" -#: html/addvote.php msgid "Invalid token for user action." msgstr "" -#: html/addvote.php msgid "Username does not exist." msgstr "שם המשתמש לא קיים." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s יש כבר הצעה קיימת." -#: html/addvote.php msgid "Invalid type." msgstr "" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "הצעה לא יכולה להיות ריקה." -#: html/addvote.php msgid "New proposal submitted." msgstr "הצעה חדשה נשלחה." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "שליחת הצבעה עבור הפעלת הצבעה." -#: html/addvote.php msgid "Applicant/TU" msgstr "" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(ריק אם אינה מתאימה)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "סוג" -#: html/addvote.php msgid "Addition of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "הצעה" -#: html/addvote.php msgid "Submit" msgstr "שליחה" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "בית" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" -#: html/home.php msgid "DISCLAIMER" msgstr "" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" msgstr "" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "דיון" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "" -#: html/index.php msgid "Adopt" msgstr "" -#: html/index.php msgid "Vote" msgstr "הצבעה" -#: html/index.php msgid "UnVote" msgstr "ביטול הצבעה" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "התרעה" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "ביטול התרעה" -#: html/index.php msgid "UnFlag" msgstr "" -#: html/login.php template/header.php msgid "Login" msgstr "כניסה" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "נכנסת בשם: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "ניתוק" -#: html/login.php msgid "Enter login credentials" msgstr "" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "ססמה" -#: html/login.php msgid "Remember me" msgstr "שמירת הפרטים" -#: html/login.php msgid "Forgot Password" msgstr "" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "קריטריונים לחיפוש" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "חבילות" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "ארעה שגיאה בזמן קבלת נתוני חבילה." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "שדה הכרחי חסר." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "שדות הססמה לא תואמים." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "הססמה חייבת להיות באורך של %s אותיות לפחות." -#: html/passreset.php msgid "Invalid e-mail." msgstr "" -#: html/passreset.php msgid "Password Reset" msgstr "איפוס ססמה" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "" -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "" -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "אישור כתובת הדוא״ל שלך" -#: html/passreset.php msgid "Enter your new password:" msgstr "הזנת ססמה חדשה:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "אישור הססמה החדשה:" -#: html/passreset.php msgid "Continue" msgstr "" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." msgstr "" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "נא להזין את כתובת הדוא״ל שלך:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "החבילות שנבחרו לא נמחקו, נא לבחור בתיבת האישור." -#: html/pkgdel.php msgid "Package Deletion" msgstr "" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" +msgid "Delete Package" msgstr "" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "" -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "" -#: html/pkgflag.php msgid "Flag" msgstr "" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" +msgid "Merge Package" msgstr "" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" -#: html/pkgmerge.php msgid "Merge into:" msgstr "" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" +msgid "Submit Request" msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "הבא" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" -#: html/register.php template/header.php msgid "Register" msgstr "" -#: html/register.php msgid "Use this form to create an account." msgstr "ניתן להשתמש בטופס זה על מנת ליצור חשבון." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "משתמש אמין" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "לא ניתן לקבל נתוני הצעה." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "ההצבעה סגורה עבור הצעה זו." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "אין באפשרותך להצביע עבור הצעה הקשורה בך." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "כבר הצבעת עבור הצעה זו." -#: html/tu.php msgid "Vote ID not valid." msgstr "מס׳ הזיהוי של ההצבעה אינו תקין." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "הצבעות נוכחיות" -#: html/tu.php msgid "Past Votes" msgstr "" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "חסר מס׳ הזיהוי של המשתמש" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "שם המשתמש אינו חוקי." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "חייב להיות בין %s ל־%s אותיות" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "יש להתחיל ולסיים עם תו או מספר" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "יכול הכיל רק נקודה אחת, קו תחתון או מקף." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "כתובת הדוא״ל שהוזנה אינה תקינה." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "שפה כרגע לא נתמכת." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -779,1028 +598,819 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "עליך להיכנס לפני שיהיה באפשרותך לערוך נתוני חבילה." + +msgid "Missing comment ID." +msgstr "חסר מס׳ זיהוי להערה." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "שגיאה בקבלת נתוני חבילה." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "נתוני חבילה לא נמצאו." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לסמן חבילות." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "לא בחרת שום חבילות לסימון." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "החבילות שנבחרו מסומנות כלא עדכניות." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "עליך להתחבר לפני שיהיה באפשרותך לבטל סימוני חבילות." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "לא בחרת שום חבילות לביטול סימון." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "החבילות שנבחרו בוטלו מהסימון." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "לא בחרת שום חבילות למחיקה." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "החבילות המסומנות נמחקו." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לאמץ חבילות." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לבטל בעלות מחבילות." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "לא בחרת שום חבילות לאימוץ." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "לא בחרת שום חבילות להסרת בעלותך מהן." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "החבילות שנבחרו אומצו." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "החבילות המסומנות ננטשו" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "עליך להיכנס לפני שתהיה באפשרותך להצביע לחבילות." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "עליך להתחבר לפני ביטול הצבעה עבור חבילות." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "לא בחרת שום חבילות להצביע עבורן." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "ההצבעות שלך הוסרו מהחבילות המסומנות." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "ההצבעות שלך נקלטו עבור החבילות המסומנות." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "לא ניתן לצרף את רשימת ההתרעות." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "צורפת אל רשימת ההתרעות עבור %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "הוסרת מרשימה ההתרעות עבור ההערות של %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "עליך להיכנס לפני שיהיה באפשרותך לערוך נתוני חבילה." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "חסר מס׳ זיהוי להערה." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "הערה נמחקה." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "אין לך הרשאה למחוק הערה זו." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "הערה נמחקה." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "שם לא חוקי: רק אותיות קטנות מותרות." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "שם משתמש" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "סוג חשבון" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "משתמש" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "מפתח" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "כתובת דוא״ל" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "שם אמתי" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "כינוי ב־IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "מצב" -#: template/account_details.php msgid "Inactive since" msgstr "" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "פעיל" -#: template/account_details.php msgid "Last Login" msgstr "" -#: template/account_details.php msgid "Never" msgstr "לעולם" -#: template/account_details.php msgid "View this user's packages" msgstr "צפייה בחבילות המשתמש" -#: template/account_details.php msgid "Edit this user's account" msgstr "" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "נדרש" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "משתמש רגיל" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "משתמשים אמינים" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "חשבון מושעה" -#: template/account_edit_form.php msgid "Inactive" msgstr "" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "הקלדת הססמה מחדש" -#: template/account_edit_form.php msgid "Language" msgstr "שפה" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "עדכון" -#: template/account_edit_form.php msgid "Create" msgstr "יצירה" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "איפוס" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "אין תוצאות עבור נתוני החיפוש שלך." -#: template/account_search_results.php msgid "Edit Account" msgstr "עריכת חשבון" -#: template/account_search_results.php msgid "Suspended" msgstr "השעייה" -#: template/account_search_results.php msgid "Edit" msgstr "" -#: template/account_search_results.php msgid "Less" msgstr "פחות" -#: template/account_search_results.php msgid "More" msgstr "עוד" -#: template/account_search_results.php msgid "No more results to display." msgstr "אין יותר תוצאות להצגה." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "החבילות שלי" -#: template/header.php msgid " My Account" msgstr "" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" +#, php-format +msgid "Flagged out-of-date (%s)" msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "מתחזק" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "הצבעות" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "" -#: template/pkg_comments.php msgid "View all comments" msgstr "" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "מחיקת הערה" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "" -#: template/pkg_details.php msgid "Package Details" msgstr "נתוני חבילה" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "תיאור" -#: template/pkg_details.php msgid "Upstream URL" msgstr "" -#: template/pkg_details.php msgid "Visit the website for" msgstr "" -#: template/pkg_details.php msgid "Licenses" msgstr "" -#: template/pkg_details.php msgid "Groups" msgstr "" -#: template/pkg_details.php msgid "Conflicts" msgstr "" -#: template/pkg_details.php msgid "Provides" msgstr "" -#: template/pkg_details.php msgid "Replaces" msgstr "" -#: template/pkg_details.php msgid "Dependencies" msgstr "תלות" -#: template/pkg_details.php msgid "Required by" msgstr "נדרש על ידי" -#: template/pkg_details.php msgid "Sources" msgstr "" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "" -#: template/pkgreq_form.php msgid "Deletion" msgstr "" -#: template/pkgreq_form.php msgid "Orphan" msgstr "" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" -#: template/pkgreq_results.php msgid "Package" msgstr "" -#: template/pkgreq_results.php msgid "Filed by" msgstr "" -#: template/pkgreq_results.php msgid "Date" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" -#: template/pkgreq_results.php msgid "Accept" msgstr "" -#: template/pkgreq_results.php msgid "Locked" msgstr "" -#: template/pkgreq_results.php msgid "Close" msgstr "" -#: template/pkgreq_results.php msgid "Closed" msgstr "" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "" -#: template/pkg_search_form.php msgid "Name Only" msgstr "" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" -#: template/pkg_search_form.php msgid "All" msgstr "" -#: template/pkg_search_form.php msgid "Flagged" msgstr "" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "שם" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "הצביעו" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "" -#: template/pkg_search_form.php msgid "Descending" msgstr "" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" -#: template/pkg_search_form.php msgid "Search by" msgstr "חיפוש לפי" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "סידור לפי" -#: template/pkg_search_form.php msgid "Sort order" msgstr "סדר המיון" -#: template/pkg_search_form.php msgid "Per page" msgstr "לפי דף" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "מעבר" -#: template/pkg_search_form.php msgid "Orphans" msgstr "יתומות" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "שגיאה בעת קבלת רשימת החבילות." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "אין חבילות התואמות לנתוני החיפוש שלך." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" -#: template/pkg_search_results.php msgid "Version" msgstr "" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "כן" -#: template/pkg_search_results.php msgid "orphan" msgstr "יתומה" -#: template/pkg_search_results.php msgid "Actions" msgstr "פעולות" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "סימון כלא עדכני" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "ביטול סימון כלא מעודכן" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "אימוץ חבילות" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "שחרור בעלות על חבילות" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "מחיקת חבילות" -#: template/pkg_search_results.php msgid "Confirm" msgstr "אישור" -#: template/search_accounts_form.php msgid "Any type" msgstr "כל סוג" -#: template/search_accounts_form.php msgid "Search" msgstr "חיפוש" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "" -#: template/tu_details.php msgid "Proposal Details" msgstr "פרטי הצעה" -#: template/tu_details.php msgid "This vote is still running." msgstr "ההצבעה עדיין קיימת." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "נשלח: %s על ידי %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "סוף" -#: template/tu_details.php msgid "Result" msgstr "" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "לא" -#: template/tu_details.php msgid "Abstain" msgstr "הימנעות" -#: template/tu_details.php msgid "Total" msgstr "סך הכול" -#: template/tu_details.php msgid "Participation" msgstr "" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "תוצאות לא נמצאו." -#: template/tu_list.php msgid "Start" msgstr "התחלה" -#: template/tu_list.php msgid "Back" msgstr "חזרה" diff --git a/po/hr.po b/po/hr.po index 9aa50369..71c151c1 100644 --- a/po/hr.po +++ b/po/hr.po @@ -1,777 +1,597 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/hr/)\n" +"Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" +"hr/)\n" +"Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: hr\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -#: html/404.php msgid "Page Not Found" msgstr "" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "" -#: html/503.php msgid "Service Unavailable" msgstr "" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" -#: html/account.php msgid "Account" msgstr "" -#: html/account.php template/header.php msgid "Accounts" msgstr "Računi" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nije vam dozvoljen pristup ovom području." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nije moguće naći informacije o zadanom korisniku." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemate ovlasti da bi mjenjali ovaj račun." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Koristite ovaj formular za pretraživanj postoječih računa." -#: html/account.php msgid "You must log in to view user information." msgstr "Morate se logirati kako bi pregledali informacije o korisniku." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "" -#: html/addvote.php msgid "Invalid token for user action." msgstr "" -#: html/addvote.php msgid "Username does not exist." msgstr "Korisničko ime ne postoji." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s već ima prijedlog." -#: html/addvote.php msgid "Invalid type." msgstr "" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Prijedlog nemože biti prazan." -#: html/addvote.php msgid "New proposal submitted." msgstr "Novi prijedlog je poslan." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Pošalji prijedlog za glasanje." -#: html/addvote.php msgid "Applicant/TU" msgstr "" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prazno ako nije prikladno)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tip" -#: html/addvote.php msgid "Addition of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU" msgstr "" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Prijedlog" -#: html/addvote.php msgid "Submit" msgstr "Pošalji" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Početna" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" -#: html/home.php msgid "DISCLAIMER" msgstr "" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" msgstr "" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Rasprava" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "" -#: html/index.php msgid "Adopt" msgstr "" -#: html/index.php msgid "Vote" msgstr "Glasaj" -#: html/index.php msgid "UnVote" msgstr "Makni glas" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Obavijesti" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne obavještavaj" -#: html/index.php msgid "UnFlag" msgstr "" -#: html/login.php template/header.php msgid "Login" msgstr "Login" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Logirani ste kao: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Logout" -#: html/login.php msgid "Enter login credentials" msgstr "" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" -#: html/login.php msgid "Remember me" msgstr "Zapamti me" -#: html/login.php msgid "Forgot Password" msgstr "" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kriteriji traženja" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketi" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Došlo je do greške prilikom dobivanja detalja o paketu." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Nedostaje Vam obvezno polje." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Lozinke nisu jednake." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Lozinka mora sadržavati najmanje %s znakova." -#: html/passreset.php msgid "Invalid e-mail." msgstr "" -#: html/passreset.php msgid "Password Reset" msgstr "" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "" -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "" -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "" -#: html/passreset.php msgid "Enter your new password:" msgstr "" -#: html/passreset.php msgid "Confirm your new password:" msgstr "" -#: html/passreset.php msgid "Continue" msgstr "" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." msgstr "" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "" -#: html/pkgdel.php msgid "Package Deletion" msgstr "" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" +msgid "Delete Package" msgstr "" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "" -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "" -#: html/pkgflag.php msgid "Flag" msgstr "" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" +msgid "Merge Package" msgstr "" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" -#: html/pkgmerge.php msgid "Merge into:" msgstr "" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" +msgid "Submit Request" msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sljedeći" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" -#: html/register.php template/header.php msgid "Register" msgstr "" -#: html/register.php msgid "Use this form to create an account." msgstr "Koristite ovaj formular za kreiranje računa." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Pouzdan korisnik" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nemogu pronaći detalje o prijedlogu." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Glasanje je zaključeno za ovaj prijedlog" -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemožete glasati o prijedlogu koji se tiće Vas." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Već ste glasali za ovaj prijedlog." -#: html/tu.php msgid "Vote ID not valid." msgstr "ID glasa je neispravan." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Trenutno glasova" -#: html/tu.php msgid "Past Votes" msgstr "" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Nedostaje ID korisnika" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Korisničko ime je neispravno." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Mora biti najmanje %s a najviše %s znakova" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Zapični i završi sa slovom ili brojkom" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržavati samo jednu točku, donju crticu ili povlaku." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Email adresa je neispravna." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -779,497 +599,415 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentar je dodan." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Morate biti logirani da biste mogli mijenjati informacije o paketu." + +msgid "Missing comment ID." +msgstr "Nedostaje ID komentara." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Došlo je do greške prilikom preuzimanja detalja o paketu." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nije moguće naći detalje o paketu." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Morate se logirati da bi obilježavali pakete." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Niste odabrali pakete koje želite obilježiti." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Odabrani paketi su obilježeni kao zastarijeli." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Morate se logirati da bi mogli obilježiti pakete kao ažurirane." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Niste odabrali pakete koje želite obilježiti kao ažurirane." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Odabrani paketu su postavljeni kao ažurirani." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Niste odabrali pakete koje želite izbrisati." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Odabrani paketi su izbrisani." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Morate se logirati da bi posvojili pakete." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Morate se logirati da bi se mogli odreknuti paketa." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Niste odabrali pakete koje želite posvojiti." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Niste odabrali pakete kojih se želite odreči." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Posvojili ste odabrane pakete." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Odrekli ste se odabranih paketa." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Morate se logirati da bi glasali za pakete." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Morate se logirati da bi mogli maknuti svoje glasove s paketa." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Niste odabrali pakete za koje želite glasati." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaši su glasovi maknuti s odabranih paketa." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Glasovi su dodijeljeni odabranim paketima." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nemogu dodati u listu za obavještavanje." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Dodani ste u listu za obavještavanje o novim komentarima za %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Niste više na listi za obavježtavanje o novim komentarima za %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Morate biti logirani da biste mogli mijenjati informacije o paketu." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Nedostaje ID komentara." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Komentar je izbrisan." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Brisanje ovog komentara Vam nije dozvoljeno." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Komentar je izbrisan." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neispravno ime: Dozvoljena su samo mala slova (kurenti)." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Korisničko ime" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip računa" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Korisnik" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Developer" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Email adresa" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Vaše stvarno ime" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nadimak na IRC-u" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Stanje" -#: template/account_details.php msgid "Inactive since" msgstr "" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivan" -#: template/account_details.php msgid "Last Login" msgstr "" -#: template/account_details.php msgid "Never" msgstr "Nikad" -#: template/account_details.php msgid "View this user's packages" msgstr "Pregledaj pakete ovog korisnika" -#: template/account_details.php msgid "Edit this user's account" msgstr "" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "obvezno" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Običan korisnik" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Pouzdan korisnik" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Račun je suspendiran" -#: template/account_edit_form.php msgid "Inactive" msgstr "" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Ponovno upišite lozinku" -#: template/account_edit_form.php msgid "Language" msgstr "Jezik" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Ažuriraj" -#: template/account_edit_form.php msgid "Create" msgstr "Kreiraj" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetiraj" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nema rezultata pretrage." -#: template/account_search_results.php msgid "Edit Account" msgstr "Podesi račun" -#: template/account_search_results.php msgid "Suspended" msgstr "Suspendiran" -#: template/account_search_results.php msgid "Edit" msgstr "" -#: template/account_search_results.php msgid "Less" msgstr "Manje" -#: template/account_search_results.php msgid "More" msgstr "Više" -#: template/account_search_results.php msgid "No more results to display." msgstr "Nema više rezultata za prikaz." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Moji paketi" -#: template/header.php msgid " My Account" msgstr "" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" +#, php-format +msgid "Flagged out-of-date (%s)" msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1277,232 +1015,178 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "nepoznato" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Održavatelj" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Glasovi" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvi put poslan" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Posljednji put ažuriran" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "" -#: template/pkg_comments.php msgid "View all comments" msgstr "" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Briši komentar" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalji o paketu" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" -#: template/pkg_details.php msgid "Upstream URL" msgstr "" -#: template/pkg_details.php msgid "Visit the website for" msgstr "" -#: template/pkg_details.php msgid "Licenses" msgstr "" -#: template/pkg_details.php msgid "Groups" msgstr "" -#: template/pkg_details.php msgid "Conflicts" msgstr "" -#: template/pkg_details.php msgid "Provides" msgstr "" -#: template/pkg_details.php msgid "Replaces" msgstr "" -#: template/pkg_details.php msgid "Dependencies" msgstr "Ovisi o" -#: template/pkg_details.php msgid "Required by" msgstr "Potreban za" -#: template/pkg_details.php msgid "Sources" msgstr "Izvor" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -#: template/pkgreq_form.php msgid "Request type" msgstr "" -#: template/pkgreq_form.php msgid "Deletion" msgstr "" -#: template/pkgreq_form.php msgid "Orphan" msgstr "" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1510,29 +1194,23 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" -#: template/pkgreq_results.php msgid "Package" msgstr "" -#: template/pkgreq_results.php msgid "Filed by" msgstr "" -#: template/pkgreq_results.php msgid "Date" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1540,116 +1218,87 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" -#: template/pkgreq_results.php msgid "Accept" msgstr "" -#: template/pkgreq_results.php msgid "Locked" msgstr "" -#: template/pkgreq_results.php msgid "Close" msgstr "" -#: template/pkgreq_results.php msgid "Closed" msgstr "" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "" -#: template/pkg_search_form.php msgid "Name Only" msgstr "" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" -#: template/pkg_search_form.php msgid "All" msgstr "" -#: template/pkg_search_form.php msgid "Flagged" msgstr "" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Ime" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Glasao" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "" -#: template/pkg_search_form.php msgid "Descending" msgstr "" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" -#: template/pkg_search_form.php msgid "Search by" msgstr "Traži po" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastario" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortiraj po" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Način sortiranja" -#: template/pkg_search_form.php msgid "Per page" msgstr "Po stranici" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Traži" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Napušteni" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Došlo je do greške prilikom stvaranja liste paketa." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nijedan paket ne odgovara kriterijima traženja." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1657,154 +1306,116 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: template/pkg_search_results.php msgid "Version" msgstr "" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Da" -#: template/pkg_search_results.php msgid "orphan" msgstr "napušten" -#: template/pkg_search_results.php msgid "Actions" msgstr "Radnje" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Obilježi kao zastario" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Obilježi kao ažuriran" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Posvoji paket" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odrekni se paketa" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Izbriši pakete" -#: template/pkg_search_results.php msgid "Confirm" msgstr "" -#: template/search_accounts_form.php msgid "Any type" msgstr "Bilo koji tip" -#: template/search_accounts_form.php msgid "Search" msgstr "Traži" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detalji prijedloga" -#: template/tu_details.php msgid "This vote is still running." msgstr "Ovaj glas još vrijedi." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Poslan: %s od %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Kraj" -#: template/tu_details.php msgid "Result" msgstr "" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" -#: template/tu_details.php msgid "Abstain" msgstr "Suzdržan" -#: template/tu_details.php msgid "Total" msgstr "Ukupno" -#: template/tu_details.php msgid "Participation" msgstr "" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nema rezultata." -#: template/tu_list.php msgid "Start" msgstr "Početak" -#: template/tu_list.php msgid "Back" msgstr "Natrag" diff --git a/po/hu.po b/po/hu.po index b0104b8a..4c3bf829 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # György Balló , 2013 # György Balló , 2011,2013-2015 @@ -10,1799 +10,1478 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/hu/)\n" +"Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" +"hu/)\n" +"Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Az oldal nem található" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Sajnálom, a megtekinteni kívánt oldal nem létezik." -#: html/503.php msgid "Service Unavailable" msgstr "Szolgáltatás nem elérhető" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Nyugalom! Ez a webhely karbantartás miatt nem üzemel. Hamarosan visszajövünk." +msgstr "" +"Nyugalom! Ez a webhely karbantartás miatt nem üzemel. Hamarosan visszajövünk." -#: html/account.php msgid "Account" msgstr "Fiók" -#: html/account.php template/header.php msgid "Accounts" msgstr "Fiókok" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nincs engedélyed hozzáférni ehhez a területhez." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nem sikerült letölteni a megadott felhasználó információit." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nincs engedélyed ennek a fióknak a szerkesztéséhez." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Már meglévő felhasználói fiókok kereséséhez használd ezt az űrlapot." -#: html/account.php msgid "You must log in to view user information." msgstr "A felhasználói információ megtekintéshez be kell jelentkezned." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Indítvány hozzáadása" -#: html/addvote.php msgid "Invalid token for user action." msgstr "A token érvénytelen a felhasználói művelethez." -#: html/addvote.php msgid "Username does not exist." msgstr "Ez a felhasználói név nem létezik." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s már megpályázta őket." -#: html/addvote.php msgid "Invalid type." msgstr "Érvénytelen típus." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Az indítvány nem lehet üres." -#: html/addvote.php msgid "New proposal submitted." msgstr "Új indítvány benyújtva." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Indítvány szavazásra bocsátása." -#: html/addvote.php msgid "Applicant/TU" msgstr "Jelölt/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(üres, ha nem alkalmazható)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Típus" -#: html/addvote.php msgid "Addition of a TU" msgstr "TU hozzáadása" -#: html/addvote.php msgid "Removal of a TU" msgstr "TU eltávolítása" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU eltávolítása (be nem jelentett inaktivitás)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Szabályzat módosítása" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Indítvány" -#: html/addvote.php msgid "Submit" msgstr "Feltöltés" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Társkarbantartók kezelése" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Honlap" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Üdvözlünk az AUR-ban! További információért olvasd el az %sAUR felhasználói irányelveket%s és az %sAUR TU irányelveket%s." +msgstr "" +"Üdvözlünk az AUR-ban! További információért olvasd el az %sAUR felhasználói " +"irányelveket%s és az %sAUR TU irányelveket%s." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "A beküldött PKGBUILD-eknek meg %skell%s felelniük az %sArch csomagolási szabályoknak%s, különben törlésre kerülnek!" +msgstr "" +"A beküldött PKGBUILD-eknek meg %skell%s felelniük az %sArch csomagolási " +"szabályoknak%s, különben törlésre kerülnek!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ne felejts el szavazni kedvenc csomagjaidra!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Néhány csomagot lehet, hogy a [community] binárisként szolgáltat." -#: html/home.php msgid "DISCLAIMER" msgstr "NYILATKOZAT" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "Tudj meg többet..." -#: html/home.php msgid "Support" msgstr "Támogatás" -#: html/home.php msgid "Package Requests" msgstr "Csomagkérelmek" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Háromfajta kérelem tölthető ki a %sCsomagműveletek%s dobozban a csomag részletei oldalon:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Háromfajta kérelem tölthető ki a %sCsomagműveletek%s dobozban a csomag " +"részletei oldalon:" -#: html/home.php msgid "Orphan Request" msgstr "Megtagadási kérelem" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Egy csomag megtagadásának kérése, pl. amikor a karbantartó inaktív, és a csomag régóta elavultnak lett jelölve." +msgstr "" +"Egy csomag megtagadásának kérése, pl. amikor a karbantartó inaktív, és a " +"csomag régóta elavultnak lett jelölve." -#: html/home.php msgid "Deletion Request" msgstr "Törlési kérelem" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Egy csomag Arch User Repositoriból való törlésének kérése. Kérünk, ne használd ezt, ha a csomag törött, és könnyen javítható. Ehelyett vedd fel a kapcsolatot a csomag karbantartójával, és tölts ki megtagadási kérelmet, ha szükséges." +msgstr "" +"Egy csomag Arch User Repositoriból való törlésének kérése. Kérünk, ne " +"használd ezt, ha a csomag törött, és könnyen javítható. Ehelyett vedd fel a " +"kapcsolatot a csomag karbantartójával, és tölts ki megtagadási kérelmet, ha " +"szükséges." -#: html/home.php msgid "Merge Request" msgstr "Beolvasztási kérelem" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Egy csomag másik csomagba történő beolvasztásának kérése. Akkor használható, amikor egy csomagot át kell nevezni, vagy lecserélésre kerül egy osztott csomagra." +msgstr "" +"Egy csomag másik csomagba történő beolvasztásának kérése. Akkor használható, " +"amikor egy csomagot át kell nevezni, vagy lecserélésre kerül egy osztott " +"csomagra." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Ha meg szeretnél tárgyalni egy kérelmet, használd az %saur-requests%s levelezőlistát. Azonban ne használd ezt a listát kérvények beadására." +msgstr "" +"Ha meg szeretnél tárgyalni egy kérelmet, használd az %saur-requests%s " +"levelezőlistát. Azonban ne használd ezt a listát kérvények beadására." -#: html/home.php msgid "Submitting Packages" msgstr "Csomagok beküldése" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Jelenleg SSH-n keresztüli Git használandó a csomagok beküldéséhez az AUR-ba. További részletekért lásd a %sCsomagok beküldése%s szakaszt az Arch User Repository ArchWiki oldalon." +msgstr "" +"Jelenleg SSH-n keresztüli Git használandó a csomagok beküldéséhez az AUR-ba. " +"További részletekért lásd a %sCsomagok beküldése%s szakaszt az Arch User " +"Repository ArchWiki oldalon." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Az alábbi SSH ujjlenyomatokat használjuk az AUR-hoz:" -#: html/home.php msgid "Discussion" msgstr "Megbeszélés" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Az Arch User Repositoryval (AUR) és a Trusted User struktúrával kapcsolatos általános tanácskozás helye az %saur-general%s. Az AUR webes felületének fejlesztésével kapcsolatos tanácskozáshoz az %saur-dev%s levelezőlista használandó." +msgstr "" +"Az Arch User Repositoryval (AUR) és a Trusted User struktúrával kapcsolatos " +"általános tanácskozás helye az %saur-general%s. Az AUR webes felületének " +"fejlesztésével kapcsolatos tanácskozáshoz az %saur-dev%s levelezőlista " +"használandó." -#: html/home.php msgid "Bug Reporting" msgstr "Hibajelentés" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Csomag keresése" -#: html/index.php msgid "Adopt" msgstr "Örökbe fogadás" -#: html/index.php msgid "Vote" msgstr "Szavazás" -#: html/index.php msgid "UnVote" msgstr "Szavazat visszavonása" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Értesítés" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Értesítés kikapcsolása" -#: html/index.php msgid "UnFlag" msgstr "Megjelölés visszavonása" -#: html/login.php template/header.php msgid "Login" msgstr "Bejelentkezés" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Bejelentkezve mint: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Kijelentkezés" -#: html/login.php msgid "Enter login credentials" msgstr "Bejelentkezési adatok megadása" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Jelszó" -#: html/login.php msgid "Remember me" msgstr "Maradjak bejelentkezve" -#: html/login.php msgid "Forgot Password" msgstr "Elfelejtett jelszó" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "A HTTP bejelentkezés letiltásra került. Ha be szeretnél jelentkezni, akkor kérünk, hogy %sválts át HTTPs-re%s." +msgstr "" +"A HTTP bejelentkezés letiltásra került. Ha be szeretnél jelentkezni, akkor " +"kérünk, hogy %sválts át HTTPs-re%s." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Keresési feltételek" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Csomagok" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Egy kötelező mező megadása hiányzik." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "A jelszó mezők nem egyeznek." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "A jelszónak legalább %s karakter hosszúságúnak kell lennie." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Érvénytelen e-mail." -#: html/passreset.php msgid "Password Reset" msgstr "Jelszó visszaállítása" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Ellenőrizd az e-mailjeidet a megerősítő hivatkozáshoz." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Jelszavad sikeresen visszaállításra került." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Erősíts meg az e-mail címedet:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Add meg az új jelszavad:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Erősítsd meg az új jelszavad:" -#: html/passreset.php msgid "Continue" msgstr "Folytatás" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Ha elfelejtetted az e-mail címet, amit a regisztrációhoz használtál, akkor küldj egy üzenetet az %saur-general%s levelezőlistára." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Ha elfelejtetted az e-mail címet, amit a regisztrációhoz használtál, akkor " +"küldj egy üzenetet az %saur-general%s levelezőlistára." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Add meg az e-mail címedet:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "A kiválasztott csomagok nem kerültek megtagadásra, ellenőrizd a megerősítő jelölőnégyzetet." +msgstr "" +"A kiválasztott csomagok nem kerültek megtagadásra, ellenőrizd a megerősítő " +"jelölőnégyzetet." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Nem található csomag, amelybe a szavazatok és megjegyzések beolvaszthatók lennének." +msgstr "" +"Nem található csomag, amelybe a szavazatok és megjegyzések beolvaszthatók " +"lennének." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Egy alapcsomag nem olvasztható önmagába." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "A kiválasztott csomagok nem kerültek törlésre, ellenőrizd a megerősítő jelölőnégyzetet." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"A kiválasztott csomagok nem kerültek törlésre, ellenőrizd a megerősítő " +"jelölőnégyzetet." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Csomag törlése" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Csomag törlése: %s" +msgid "Delete Package" +msgstr "Csomag törlése" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag és az alábbi csomagok törléséhez az AUR-ból:" +msgstr "" +"Használd ezt az űrlapot a(z) %s%s%s alapcsomag és az alábbi csomagok " +"törléséhez az AUR-ból:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Egy csomag törlése végleges. " -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "A művelet megerősítéséhez jelöld be a jelölőnégyzetet." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Csomag törlésének megerősítése" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Törlés" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Csak megbízható felhasználók és fejlesztők tudnak csomagokat törölni." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Csomag megtagadása" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Csomag megtagadása: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag megtagadásához, amely a következő csomagokat tartalmazza:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Használd ezt az űrlapot a(z) %s%s%s alapcsomag megtagadásához, amely a " +"következő csomagokat tartalmazza:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a csomagot, és átadni a tulajdonjogot neki: %s%s%s." +msgstr "" +"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " +"csomagot, és átadni a tulajdonjogot neki: %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a csomagot." +msgstr "" +"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " +"csomagot." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Csomag megtagadásának megerősítése." -#: html/pkgdisown.php msgid "Disown" msgstr "Megtagadás" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." +msgstr "" +"Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." + +msgid "Flag Comment" +msgstr "" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Megjegyzések" -#: html/pkgflag.php msgid "Flag" msgstr "Megjelölés" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Csomag beolvasztása" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Csomag beolvasztása: %s" +msgid "Merge Package" +msgstr "Csomag beolvasztása" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag másik csomagba történő beolvasztásához." +msgstr "" +"Használd ezt az űrlapot a(z) %s%s%s alapcsomag másik csomagba történő " +"beolvasztásához." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "A következő csomagok törlésre kerülnek:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "Ha egyszer egy csomag beolvasztásra került, többé nem lehet visszaállítani. " +msgstr "" +"Ha egyszer egy csomag beolvasztásra került, többé nem lehet visszaállítani. " -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Add meg a csomag nevét, amibe szeretnéd beolvasztani a csomagot." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Beolvasztás ebbe:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Csomag beolvasztásának megerősítése" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Beolvasztás" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "Csak megbízható felhasználók és fejlesztők tudnak csomagokat beolvasztani." +msgstr "" +"Csak megbízható felhasználók és fejlesztők tudnak csomagokat beolvasztani." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Kérelem beadása" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Kérelem lezárása" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Első" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Előző" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Következő" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Utolsó" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Kérelmek" -#: html/register.php template/header.php msgid "Register" msgstr "Regisztráció" -#: html/register.php msgid "Use this form to create an account." msgstr "Használd ezt a űrlapot felhasználói fiók létrehozására." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Megbízható felhasználó" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nem sikerült az indítvány részletes információinak letöltése." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A szavazás lezárult erre az indítványra." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "A szavazás csak megbízható felhasználóknak engedélyezett." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nem szavazhatsz egy rólad szóló indítványra." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Már szavaztál erre az indítványra." -#: html/tu.php msgid "Vote ID not valid." msgstr "Érvénytelen szavazatazonosító." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Jelenlegi szavazatok" -#: html/tu.php msgid "Past Votes" msgstr "Korábbi szavazatok" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Szavazók" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "A felhasználói regisztráció jelenleg letiltásra került az IP címedre, valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +msgstr "" +"A felhasználói regisztráció jelenleg letiltásra került az IP címedre, " +"valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Hiányzó felhasználóazonosító" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "A felhasználónév érvénytelen." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "%s és %s közötti karakterhosszúságúnak kell lennie" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Betűvel vagy számjeggyel kezdődjön és végződjön" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Csak egyetlen pontot, aláhúzást vagy kötőjelet tartalmazhat." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Érvénytelen e-mail cím." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A PGP kulcs ujjlenyomata érvénytelen." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "A nyilvános SSH kulcs érvénytelen." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nem lehet megnövelni a fiók jogosultságait." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "A nyelv jelenleg nem támogatott." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "A(z) %s%s%s felhasználónév már használatban van." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "A(z) %s%s%s cím már használatban van." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "A(z) %s%s%s nyilvános SSH kulcs már használatban van." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Hiba történt a(z) %s%s%s fiók létrehozása során." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A(z) %s%s%s fiók sikeresen létrejött." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Egy jelszó-visszaállító kulcs kiküldésre került az e-mail címedre." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "A fiókod használatához kattints a Bejelentkezés hivatkozásra feljebb." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "A(z) %s%s%s fiók nem módosult." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A(z) %s%s%s fiók sikeresen módosítva." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "A bejelentkező űrlap jelenleg letiltásra került az IP címedre, valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +msgstr "" +"A bejelentkező űrlap jelenleg letiltásra került az IP címedre, valószínűleg " +"rendszeres spam támadások miatt. Elnézést a kellemetlenségért." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Fiók felfüggesztve" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "A jelszavad visszaállításra került. Ha most regisztráltál, akkor a megerősítő e-mailben található hivatkozással beállíthatsz egy kezdeti jelszót. Egyéb esetben kérj egy visszaállító kulcsot a %sJelszó visszaállítása%s oldalon." +msgstr "" +"A jelszavad visszaállításra került. Ha most regisztráltál, akkor a " +"megerősítő e-mailben található hivatkozással beállíthatsz egy kezdeti " +"jelszót. Egyéb esetben kérj egy visszaállító kulcsot a %sJelszó " +"visszaállítása%s oldalon." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Hibás felhasználónév vagy jelszó." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Hiba történt a felhasználói munkamenet létrehozásának megkísérlésekor." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Érvénytelen e-mail és visszaállító kulcs kombináció." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nincs" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Fiók információinak megtekintése – %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "A megjegyzés hozzáadva." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "A csomag információinak szerkesztéséhez be kell jelentkezned." + +msgid "Missing comment ID." +msgstr "Hiányzó megjegyzésazonosító." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "A csomag részletes információi nem találhatók." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Csomagok megjelöléséhez be kell jelentkezned." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nem választottál ki egyetlen csomagot sem megjelölésre." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "A kiválasztott csomagok elavultnak lettek jelölve." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Csomagok megjelölésének visszavonásához be kell jelentkezned." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nem választottál ki egyetlen csomagot sem megjelölés visszavonására." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "A kiválasztott csomagok bejelölése visszavonva." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Csomagok törléséhez nincs jogosultságod." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nem választottál ki egyetlen törlendő csomagot sem." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "A kiválasztott csomagok törlése megtörtént." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Csomagok örökbefogadásához be kell jelentkezned." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Csomagok megtagadásához be kell jelentkezned." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nem választottál ki egyetlen örökbe fogadandó csomagot sem." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nem választottál ki egyetlen csomagot sem megtagadásra." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Sikeresen örökbe fogadtad a kiválasztott csomagokat." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "A kiválasztott csomagok megtagadva." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Csomagokra történő szavazáshoz be kell jelentkezned." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Csomagokra adott szavazatok visszavonásához be kell jelentkezned." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nem választottál ki egyetlen csomagot sem, amire szavaznál." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Szavazatod eltávolításra került a kiválasztott csomagokról." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Leadtad a szavazatod a kiválasztott csomagokra." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nem sikerült hozzáadni az értesítési listához." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "Sikeresen fel lettél véve a(z) %s csomag megjegyzésértesítési listájára." +msgstr "" +"Sikeresen fel lettél véve a(z) %s csomag megjegyzésértesítési listájára." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "El lettél távolítva a(z) %s csomag megjegyzésértesítési listájáról." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "A csomag információinak szerkesztéséhez be kell jelentkezned." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Hiányzó megjegyzésazonosító." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Megjegyzés törölve." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nem törölheted ezt a megjegyzést." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Megjegyzés törölve." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nem szerkesztheted ennek az alapcsomagnak a kulcsszavait." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Az alapcsomag kulcsszavai frissítve lettek." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nem szerkesztheted ennek az alapcsomagnak a társkarbantartóit." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Érvénytelen felhasználónév: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Az alapcsomag társkarbantartói frissítve lettek." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Csomag részleteinek megtekintése –" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Csomagkérelmek beküldéséhez be kell jelentkezned." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Érvénytelen név: csak kisbetűk használata engedélyezett." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "A megjegyzés mező nem lehet üres." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Érvénytelen kérelemtípus." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Kérelem sikeresen hozzáadva." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Érvénytelen ok." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Csak megbízható felhasználók és fejlesztők tudnak kérelmeket lezárni." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Kérelem sikeresen lezárva." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ez az űrlap %s AUR fiókjának végleges törléséhez használható." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sFIGYELMEZTETÉS%s: ez a művelet nem visszavonható." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Törlés megerősítése" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Felhasználónév" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Fióktípus" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Felhasználó" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Fejlesztő" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Megbízható felhasználó és fejlesztő" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail cím" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Valós név" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC becenév" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP kulcs ujjlenyomata" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Állapot" -#: template/account_details.php msgid "Inactive since" msgstr "Ezóta inaktív:" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktív" -#: template/account_details.php msgid "Last Login" msgstr "Legutóbbi bejelentkezés" -#: template/account_details.php msgid "Never" msgstr "Soha" -#: template/account_details.php msgid "View this user's packages" msgstr "A felhasználó csomagjainak megtekintése" -#: template/account_details.php msgid "Edit this user's account" msgstr "Ezen felhasználó fiókjának szerkesztése" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kattints %side%s, ha véglegesen törölni szeretnéd ezt a fiókot." -#: template/account_edit_form.php msgid "required" msgstr "kötelező" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normál felhasználó" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Megbízható felhasználó" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Felhasználói fiók felfüggesztve" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktív" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Megismételt jelszó" -#: template/account_edit_form.php msgid "Language" msgstr "Nyelv" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "Az alábbi információ csak akkor szükséges, ha csomagokat szeretnél beküldeni az Arch User Repositoryba." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"Az alábbi információ csak akkor szükséges, ha csomagokat szeretnél beküldeni " +"az Arch User Repositoryba." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Nyilvános SSH kulcs" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Frissítés" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Létrehozás" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Visszaállítás" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Nincs a keresési feltételeknek megfelelő találat." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Felhasználói fiók szerkesztése" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Felfüggesztve" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Szerkesztés" - -#: template/account_search_results.php -msgid "Less" -msgstr "Kevesebb" - -#: template/account_search_results.php -msgid "More" -msgstr "Több" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Nincs több kijelezhető eredmény." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Társkarbantartók kezelése: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Használd ezt az űrlapot társszerkesztők hozzáadásához a(z) %s%s%s csomaghoz (soronként egy felhasználónév):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Felhasználók" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Mentés" - -#: template/header.php -msgid "My Packages" -msgstr "Csomagjaim" - -#: template/header.php -msgid " My Account" -msgstr " Fiókom" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Csomagműveletek" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "PKGBUILD megtekintése" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Módosítások megtekintése" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Pillanatkép letöltése" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Keresés wikiben" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Elavultnak jelölve" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Csomag elavultnak jelölése" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Csomag jelölésének visszavonása" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Szavazat eltávolítása" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Szavazás erre a csomagra" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Értesítések kikapcsolása" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Értesítés új hozzászólásról" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Frissítés" + +msgid "Create" +msgstr "Létrehozás" + +msgid "Reset" +msgstr "Visszaállítás" + +msgid "No results matched your search criteria." +msgstr "Nincs a keresési feltételeknek megfelelő találat." + +msgid "Edit Account" +msgstr "Felhasználói fiók szerkesztése" + +msgid "Suspended" +msgstr "Felfüggesztve" + +msgid "Edit" +msgstr "Szerkesztés" + +msgid "Less" +msgstr "Kevesebb" + +msgid "More" +msgstr "Több" + +msgid "No more results to display." +msgstr "Nincs több kijelezhető eredmény." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Használd ezt az űrlapot társszerkesztők hozzáadásához a(z) %s%s%s csomaghoz " +"(soronként egy felhasználónév):" + +msgid "Users" +msgstr "Felhasználók" + +msgid "Save" +msgstr "Mentés" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + +msgid "My Packages" +msgstr "Csomagjaim" + +msgid " My Account" +msgstr " Fiókom" + +msgid "Package Actions" +msgstr "Csomagműveletek" + +msgid "View PKGBUILD" +msgstr "PKGBUILD megtekintése" + +msgid "View Changes" +msgstr "Módosítások megtekintése" + +msgid "Download snapshot" +msgstr "Pillanatkép letöltése" + +msgid "Search wiki" +msgstr "Keresés wikiben" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Csomag elavultnak jelölése" + +msgid "Unflag package" +msgstr "Csomag jelölésének visszavonása" + +msgid "Remove vote" +msgstr "Szavazat eltávolítása" + +msgid "Vote for this package" +msgstr "Szavazás erre a csomagra" + +msgid "Disable notifications" +msgstr "Értesítések kikapcsolása" + msgid "Manage Co-Maintainers" msgstr "Társszerkesztők kezelése" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d függő kérelem" msgstr[1] "%d függő kérelem" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Csomag törlése" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Csomag beolvasztása" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Csomag örökbe fogadása" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "ismeretlen" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Alapcsomag részletei" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git klónozási URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "csak olvasható" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Kulcsszavak" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Beküldő" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Karbantartó" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Legutóbbi csomagoló" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Szavazatok" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Népszerűség" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Először beküldve" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Legutóbb frissítve" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Hosszászólás" -#: template/pkg_comments.php msgid "View all comments" msgstr "Összes megjegyzés megjelenítése" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Legújabb hozzászólások" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Hozzászólás törlése" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Összes hozzászólás" -#: template/pkg_details.php msgid "Package Details" msgstr "Részletes csomaginformáció" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Alapcsomag" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Leírás" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "A webhely meglátogatása –" -#: template/pkg_details.php msgid "Licenses" msgstr "Licencek" -#: template/pkg_details.php msgid "Groups" msgstr "Csoportok" -#: template/pkg_details.php msgid "Conflicts" msgstr "Ütközik" -#: template/pkg_details.php msgid "Provides" msgstr "Szolgáltatja" -#: template/pkg_details.php msgid "Replaces" msgstr "Lecseréli" -#: template/pkg_details.php msgid "Dependencies" msgstr "Függőségek" -#: template/pkg_details.php msgid "Required by" msgstr "Igényli" -#: template/pkg_details.php msgid "Sources" msgstr "Források" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Kérelem lezárása: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem lezárásához." +msgstr "" +"Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem " +"lezárásához." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Megjegyzés" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "A megjegyzések mező üresen hagyható. Viszont kérelem elutasításakor erősen javasolt megjegyzés hozzáadása." +msgstr "" +"A megjegyzések mező üresen hagyható. Viszont kérelem elutasításakor erősen " +"javasolt megjegyzés hozzáadása." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Ok" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Elfogadva" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Elutasítva" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Kérelem benyújtása: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem benyújtásához, amely a következő csomagokat tartalmazza:" +msgstr "" +"Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem " +"benyújtásához, amely a következő csomagokat tartalmazza:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Kérelem típusa" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Törlés" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Megtagadás" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Beolvasztás ebbe:" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d csomagokkal kapcsolatos kérelem található." msgstr[1] "%d csomagokkal kapcsolatos kérelem található." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "%d. oldal, összesen: %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Csomag" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Kitöltő" -#: template/pkgreq_results.php msgid "Date" msgstr "Dátum" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d nap van hátra" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d óra van hátra" msgstr[1] "~%d óra van hátra" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 óra van hátra" -#: template/pkgreq_results.php msgid "Accept" msgstr "Elfogadás" -#: template/pkgreq_results.php msgid "Locked" msgstr "Zárolva" -#: template/pkgreq_results.php msgid "Close" msgstr "Lezárás" -#: template/pkgreq_results.php msgid "Closed" msgstr "Lezárva" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Név, leírás" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Csak név" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Pontos név" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pontos alapcsomag" -#: template/pkg_search_form.php msgid "All" msgstr "Összes" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Jelölt" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nem jelölt" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Név" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Szavazva" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Növekvő" -#: template/pkg_search_form.php msgid "Descending" msgstr "Csökkenő" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Keresési feltételek megadása" -#: template/pkg_search_form.php msgid "Search by" msgstr "Keresés eszerint" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Elavult" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Rendezés" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Rendezési sorrend" -#: template/pkg_search_form.php msgid "Per page" msgstr "Laponként" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Mehet" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Árvák" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Hiba történt a csomaglista letöltése közben." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nincs a keresési feltételeknek megfelelő csomag." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d csomag található." msgstr[1] "%d csomag található." -#: template/pkg_search_results.php msgid "Version" msgstr "Verzió" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat súlyozásra kerül naponta 0,98-as faktorral a létrehozása óta." +msgstr "" +"A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat " +"súlyozásra kerül naponta 0,98-as faktorral a létrehozása óta." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Igen" -#: template/pkg_search_results.php msgid "orphan" msgstr "árva" -#: template/pkg_search_results.php msgid "Actions" msgstr "Tevékenységek" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Elavultnak jelölés" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Elavultság visszavonása" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Csomagok örökbefogadása" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Csomagok megtagadása" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Csomagok törlése" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Megerősítés" -#: template/search_accounts_form.php msgid "Any type" msgstr "Bármilyen típus" -#: template/search_accounts_form.php msgid "Search" msgstr "Keresés" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statisztika" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Árva csomagok" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "A legutóbbi 7 napban hozzáadott csomagok" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "A legutóbbi 7 napban frissített csomagok" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Az utóbbi évben frissített csomagok" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Soha nem frissített csomagok" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Regisztrált felhasználók" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Megbízható felhasználók" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Legutóbbi frissítések" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Statisztikám" -#: template/tu_details.php msgid "Proposal Details" msgstr "Indítvány részletes információi" -#: template/tu_details.php msgid "This vote is still running." msgstr "A szavazás még zajlik." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Benyújtva: %s (%s által)" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Vége" -#: template/tu_details.php msgid "Result" msgstr "Eredmény" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nem" -#: template/tu_details.php msgid "Abstain" msgstr "Tartózkodik" -#: template/tu_details.php msgid "Total" msgstr "Összesen" -#: template/tu_details.php msgid "Participation" msgstr "Részvétel" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Legutóbbi szavazatok TU szerint" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Legutóbbi szavazat" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nincs találat." -#: template/tu_list.php msgid "Start" msgstr "Kezdés" -#: template/tu_list.php msgid "Back" msgstr "Vissza" diff --git a/po/it.po b/po/it.po index 3e97e59e..21f1a5e3 100644 --- a/po/it.po +++ b/po/it.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Giovanni Scafora , 2011-2015 # Lorenzo Porta , 2014 @@ -10,1799 +10,1508 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/it/)\n" +"Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" +"it/)\n" +"Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Impossibile trovare la pagina" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Spiacenti, la pagina richiesta non esiste." -#: html/503.php msgid "Service Unavailable" msgstr "Servizio non disponibile" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Niente panico! Il sito è fuori servizio per lavori di manutenzione. Torneremo presto." +msgstr "" +"Niente panico! Il sito è fuori servizio per lavori di manutenzione. " +"Torneremo presto." -#: html/account.php msgid "Account" msgstr "Account" -#: html/account.php template/header.php msgid "Accounts" msgstr "Account" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Non sei autorizzato ad accedere a quest'area." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Impossibile recuperare le informazioni dell'utente specificato." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Non hai i permessi necessari per modificare questo account." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa questo modulo per cercare gli account esistenti." -#: html/account.php msgid "You must log in to view user information." msgstr "Devi autenticarti per visualizzare le informazioni dell'utente." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Aggiungi una proposta" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Il token non è valido per l'intervento da parte dell'utente." -#: html/addvote.php msgid "Username does not exist." msgstr "Il nome utente non esiste." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ha già avviato una proposta per loro." -#: html/addvote.php msgid "Invalid type." msgstr "Tipo non valido." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La proposta non può essere vuota." -#: html/addvote.php msgid "New proposal submitted." msgstr "La nuova proposta è stata inviata." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Invia una proposta da votare." -#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vuoto se non applicabile)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" -#: html/addvote.php msgid "Addition of a TU" msgstr "Aggiunta di un TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Rimozione di un TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Rimozione di un TU (inattività non dichiarata)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Modifica dello statuto" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" -#: html/addvote.php msgid "Submit" msgstr "Invia" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gestisci i co-manutentori" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Edita il commento" -#: html/home.php template/header.php msgid "Home" msgstr "Home" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Benvenuto in AUR! Per maggiori informazioni, leggi le %sAUR User Guidelines%s e le %sAUR TU Guidelines%s." +msgstr "" +"Benvenuto in AUR! Per maggiori informazioni, leggi le %sAUR User Guidelines" +"%s e le %sAUR TU Guidelines%s." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "I PKGBUILD inviati %sdevono%s essere conformi agli %sArch Packaging Standards%s altrimenti saranno eliminati!" +msgstr "" +"I PKGBUILD inviati %sdevono%s essere conformi agli %sArch Packaging Standards" +"%s altrimenti saranno eliminati!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ricorda di votare i tuoi pacchetti preferiti!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Alcuni pacchetti potrebbero essere disponibili come precompilati in [community]." +msgstr "" +"Alcuni pacchetti potrebbero essere disponibili come precompilati in " +"[community]." -#: html/home.php msgid "DISCLAIMER" msgstr "AVVISO" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"i pacchetti presenti in AUR sono stati inviati dagli utenti. Usali a tuo " +"rischio e pericolo." -#: html/home.php msgid "Learn more..." msgstr "Ulteriori informazioni..." -#: html/home.php msgid "Support" msgstr "Supporto" -#: html/home.php msgid "Package Requests" msgstr "Richieste dei pacchetti" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Ci sono tre tipi di richieste che si possono effettuare dal riquadro %sAzioni del pacchetto%s presente nella pagina dei dettagli del pacchetto:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Ci sono tre tipi di richieste che si possono effettuare dal riquadro " +"%sAzioni del pacchetto%s presente nella pagina dei dettagli del pacchetto:" -#: html/home.php msgid "Orphan Request" msgstr "Richiesta di un pacchetto orfano" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "richiesta di un pacchetto che si vuole abbandonare, ad esempio, quando il manutentore è inattivo ed il pacchetto è stato contrassegnato come non aggiornato da molto tempo." +msgstr "" +"richiesta di un pacchetto che si vuole abbandonare, ad esempio, quando il " +"manutentore è inattivo ed il pacchetto è stato contrassegnato come non " +"aggiornato da molto tempo." -#: html/home.php msgid "Deletion Request" msgstr "Richiesta di rimozione di un pacchetto" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usare questo tipo di richiesta se un pacchetto non funziona e se può essere sistemato facilmente. Contatta il manutentore del pacchetto e, se necessario, invia una richiesta per renderlo orfano." +msgstr "" +"richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usare " +"questo tipo di richiesta se un pacchetto non funziona e se può essere " +"sistemato facilmente. Contatta il manutentore del pacchetto e, se " +"necessario, invia una richiesta per renderlo orfano." -#: html/home.php msgid "Merge Request" msgstr "Richiesta di unione di un pacchetto" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "richiesta di un pacchetto da unire con un altro. Può essere usata quando un pacchetto necessita di essere rinominato o rimpiazzato da un pacchetto suddiviso" +msgstr "" +"richiesta di un pacchetto da unire con un altro. Può essere usata quando un " +"pacchetto necessita di essere rinominato o rimpiazzato da un pacchetto " +"suddiviso" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Se vuoi discutere una richiesta, puoi usare la lista di discussione %saur-requests%s. Non usare questa lista per inoltrare richieste." +msgstr "" +"Se vuoi discutere una richiesta, puoi usare la lista di discussione %saur-" +"requests%s. Non usare questa lista per inoltrare richieste." -#: html/home.php msgid "Submitting Packages" msgstr "Invio dei pacchetti" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Per inviare i pacchetti in AUR, adesso, si utilizza Git via SSH. Per maggiori informazioni, vedi la sezione %sInviare i pacchetti%s della pagina Arch User Repository dell'ArchWiki." +msgstr "" +"Per inviare i pacchetti in AUR, adesso, si utilizza Git via SSH. Per " +"maggiori informazioni, vedi la sezione %sInviare i pacchetti%s della pagina " +"Arch User Repository dell'ArchWiki." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Per AUR si usano le seguenti fingerprint SSH:" -#: html/home.php msgid "Discussion" msgstr "Discussione" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "La discussione generale sull'Arch User Repository (AUR) e sulla struttura dei TU avviene in %saur-general%s. Per la discussione relativa allo sviluppo dell'interfaccia web di AUR, utilizza la lista di discussione %saur-dev%s." +msgstr "" +"La discussione generale sull'Arch User Repository (AUR) e sulla struttura " +"dei TU avviene in %saur-general%s. Per la discussione relativa allo sviluppo " +"dell'interfaccia web di AUR, utilizza la lista di discussione %saur-dev%s." -#: html/home.php msgid "Bug Reporting" msgstr "Segnalazione di un bug" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" +"Se trovi un bug nell'interfaccia web di AUR, invia un report al nostro %sbug " +"tracker%s. Usa il tracker %ssolo%s per inviare i bug di AUR. Per segnalare " +"bug inerenti alla pacchettizzazione, contatta il manutentore oppure lascia " +"un commento nella pagina del pacchetto." -#: html/home.php msgid "Package Search" msgstr "Ricerca dei pacchetti" -#: html/index.php msgid "Adopt" msgstr "Adotta" -#: html/index.php msgid "Vote" msgstr "Vota" -#: html/index.php msgid "UnVote" msgstr "Rimuovi il voto" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Abilita le notifiche" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Disabilita le notifiche" -#: html/index.php msgid "UnFlag" msgstr "Deseleziona" -#: html/login.php template/header.php msgid "Login" msgstr "Accedi" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Connesso con il nome utente: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Esci" -#: html/login.php msgid "Enter login credentials" msgstr "Inserisci le credenziali di accesso" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Il nome utente o l'indirizzo email" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Password" -#: html/login.php msgid "Remember me" msgstr "Ricordami" -#: html/login.php msgid "Forgot Password" msgstr "Password dimenticata" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "L'accesso tramite HTTP è stato disabilitato. Se vuoi accedere, %spassa ad HTTPs%s." +msgstr "" +"L'accesso tramite HTTP è stato disabilitato. Se vuoi accedere, %spassa ad " +"HTTPs%s." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteri di ricerca" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacchetti" -#: html/packages.php msgid "Error trying to retrieve package details." -msgstr "Si è verificato un errore durante il recupero dei dettagli del pacchetto." +msgstr "" +"Si è verificato un errore durante il recupero dei dettagli del pacchetto." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Manca un campo obbligatorio." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "I campi password non corrispondono." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La password deve contenere almeno %s caratteri." -#: html/passreset.php msgid "Invalid e-mail." msgstr "L'e-mail inserita non è valida." -#: html/passreset.php msgid "Password Reset" msgstr "Ripristina la password" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Controlla la tua e-mail per il link di conferma." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La tua password è stata ripristinata con successo." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Conferma il tuo indirizzo e-mail:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Inserisci la tua nuova password:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Conferma la tua nuova password:" -#: html/passreset.php msgid "Continue" msgstr "Continua" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un messaggio nella mailing list %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un " +"messaggio nella mailing list %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Inserisci il tuo indirizzo email:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "I pacchetti selezionati non sono stati abbandonati, conferma la tua scelta inserendo un segno di spunta nell'apposita casella di controllo." +msgstr "" +"I pacchetti selezionati non sono stati abbandonati, conferma la tua scelta " +"inserendo un segno di spunta nell'apposita casella di controllo." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Impossibile trovare il pacchetto da unire al suo interno i voti ed i commenti." +msgstr "" +"Impossibile trovare il pacchetto da unire al suo interno i voti ed i " +"commenti." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Impossibile unire un pacchetto base con se stesso." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "I pacchetti selezionati non sono stati eliminati, conferma la tua scelta inserendo un segno di spunta nell'apposita casella di controllo." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"I pacchetti selezionati non sono stati eliminati, conferma la tua scelta " +"inserendo un segno di spunta nell'apposita casella di controllo." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminazione del pacchetto" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Elimina il pacchetto: %s" +msgid "Delete Package" +msgstr "Elimina il pacchetto" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Usa questo modulo per eliminare il pacchetto base %s%s%s e i seguenti pacchetti da AUR:" +msgstr "" +"Usa questo modulo per eliminare il pacchetto base %s%s%s e i seguenti " +"pacchetti da AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "La rimozione di un pacchetto è permanente." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Seleziona la casella di controllo per confermare l'azione richiesta." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Conferma di voler rimuovere il pacchetto" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Elimina" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Solo i TU e gli sviluppatori possono eliminare i pacchetti." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abbandona il pacchetto" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Abbandona il pacchetto: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Usa questo modulo per abbandonare il pacchetto base %s%s%s che contiene i seguenti pacchetti:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Usa questo modulo per abbandonare il pacchetto base %s%s%s che contiene i " +"seguenti pacchetti:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Selezionando la casella di controllo, confermi che vuoi abbandonare il pacchetto e trasferirlo a %s%s%s." +msgstr "" +"Selezionando la casella di controllo, confermi che vuoi abbandonare il " +"pacchetto e trasferirlo a %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Selezionando la casella di controllo, confermi che vuoi abbandonare il pacchetto." +msgstr "" +"Selezionando la casella di controllo, confermi che vuoi abbandonare il " +"pacchetto." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Conferma di voler abbandonare il pacchetto" -#: html/pkgdisown.php msgid "Disown" msgstr "Abbandona" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Solo i TU e gli sviluppatori possono abbandonare i pacchetti." -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Segnala che il pacchetto non è aggiornato" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" +"Usa questo modulo per segnalare che il pacchetto base %s%s%s e i seguenti " +"pacchetti non sono aggiornati:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"%sNon%s utilizzare questo modulo per inviare bug report. Utilizza i commenti " +"nella pagina del pacchetto." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Immetti qui sotto i dettagli sul perché il pacchetto non è aggiornato, " +"preferibilmente compresi il collegamento dell'annuncio del rilascio o del " +"nuovo sorgente." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Commenti" -#: html/pkgflag.php msgid "Flag" msgstr "Seleziona" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +"Solo gli utenti registrati possono segnalare i pacchetti non aggiornati." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Unione dei pacchetti" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Unisci il pacchetto: %s" +msgid "Merge Package" +msgstr "Unisci il pacchetto" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Usa questo modulo per unire il pacchetto base %s%s%s con un altro pacchetto." +msgstr "" +"Usa questo modulo per unire il pacchetto base %s%s%s con un altro pacchetto." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "I seguenti pacchetti saranno eliminati:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "Una volta che il pacchetto è stato unito, non può essere più recuperato." +msgstr "" +"Una volta che il pacchetto è stato unito, non può essere più recuperato." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Digita il nome del pacchetto che desideri unire all'interno del pacchetto." +msgstr "" +"Digita il nome del pacchetto che desideri unire all'interno del pacchetto." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Unisci con:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Conferma di voler unire il pacchetto" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Unisci" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo i TU e gli sviluppatori possono unire i pacchetti." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Invia richiesta" +msgid "Submit Request" +msgstr "Invia la richiesta" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Chiudi la richiesta" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primo" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedente" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Successivo" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Richieste" -#: html/register.php template/header.php msgid "Register" msgstr "Registrati" -#: html/register.php msgid "Use this form to create an account." msgstr "Usa questo modulo per creare un account." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "TU" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Impossibile recuperare i dettagli della proposta." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Non puoi più votare per questa proposta." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solo i TU possono votare." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Non puoi votare per una proposta che ti riguarda in prima persona." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Hai già votato per questa proposta." -#: html/tu.php msgid "Vote ID not valid." msgstr "L'ID del voto non è valido." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Voti attuali" -#: html/tu.php msgid "Past Votes" msgstr "Vecchi voti" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votanti" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "La registrazione dell'account è stata disabilitata per il tuo indirizzo IP, probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per l'inconveniente." +msgstr "" +"La registrazione dell'account è stata disabilitata per il tuo indirizzo IP, " +"probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per " +"l'inconveniente." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manca l'ID dell'utente" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Il nome utente non è valido." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Deve contenere un minino di %s ed un massimo di %s caratteri" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Inizia e termina con una lettera o un numero" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Può contenere solo un punto, un trattino basso o un trattino." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'indirizzo email non risulta valido." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La fingerprint della chiave PGP non è valida." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La chiave pubblica SSH non è valida." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Non è possibile incrementare i permessi dell'account." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Lingua attualmente non supportata." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Il nome utente %s%s%s è già in uso." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L'indirizzo %s%s%s è già in uso." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La chiave pubblica SSH %s%s%s, è già in uso." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Si è verificato un errore durante la creazione dell'account %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "L'account %s%s%s è stato creato con successo." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "È stata inviata una chiave di ripristino della password al tuo indirizzo e-mail." +msgstr "" +"È stata inviata una chiave di ripristino della password al tuo indirizzo e-" +"mail." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Per utilizzare il tuo account, clicca sul link Accedi." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Non sono state apportate modifiche all'account %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "L'account %s%s%s è stato modificato con successo." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Il modulo d'accesso è attualmente disabilitato per il tuo indirizzo IP, probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per l'inconveniente." +msgstr "" +"Il modulo d'accesso è attualmente disabilitato per il tuo indirizzo IP, " +"probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per " +"l'inconveniente." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Account sospeso" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "La tua password è stata ripristinata. Se hai creato da poco un nuovo account, usa il link presente nell'email di conferma, per impostare una password iniziale. Altrimenti, richiedi il ripristino della password dalla pagina %sRipristina la password%s." +msgstr "" +"La tua password è stata ripristinata. Se hai creato da poco un nuovo " +"account, usa il link presente nell'email di conferma, per impostare una " +"password iniziale. Altrimenti, richiedi il ripristino della password dalla " +"pagina %sRipristina la password%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nome utente o password errati." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "Si è verificato un errore provando a generare una sessione dell'utente." +msgstr "" +"Si è verificato un errore provando a generare una sessione dell'utente." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "La combinazione e-mail e chiave di ripristino non è valida." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nessuno" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Mostra le informazioni dell'account %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." -msgstr "" +msgstr "Manca l'ID o il nome del pacchetto." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Non sei autorizzato a modificare questo commento." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "Il commento è stato rimosso." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "Il commento non può essere vuoto." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Il commento è stato inserito." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php -msgid "Error retrieving package details." -msgstr "Si è verificato un errore durante il recupero dei dettagli del pacchetto." +msgid "You must be logged in before you can edit package information." +msgstr "" +"Devi autenticarti prima di poter modificare le informazioni del pacchetto." + +msgid "Missing comment ID." +msgstr "Manca l'ID del commento." + +msgid "No more than 5 comments can be pinned." +msgstr "Non possono essere inseriti più di 5 commenti." + +msgid "You are not allowed to pin this comment." +msgstr "Non sei autorizzato ad inserire questo commento." + +msgid "You are not allowed to unpin this comment." +msgstr "Non sei autorizzato a rimuovere questo commento." + +msgid "Comment has been pinned." +msgstr "Il commento è stato rimosso." + +msgid "Comment has been unpinned." +msgstr "I commenti sono stati rimossi." + +msgid "Error retrieving package details." +msgstr "" +"Si è verificato un errore durante il recupero dei dettagli del pacchetto." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Impossibile trovare i dettagli del pacchetto." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Devi autenticarti prima di poter contrassegnare i pacchetti." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." -msgstr "Non hai selezionato nessun pacchetto da contrassegnare come non aggiornato." +msgstr "" +"Non hai selezionato nessun pacchetto da contrassegnare come non aggiornato." + +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" +"I pacchetti selezionati non sono stati contrassegnati, immetti un commento." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "I pacchetti selezionati sono stati contrassegnati come non aggiornati." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "Devi autenticarti prima di poter rimuovere il contrassegno ai pacchetti." +msgstr "" +"Devi autenticarti prima di poter rimuovere il contrassegno ai pacchetti." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." -msgstr "Non hai selezionato nessun pacchetto da contrassegnare come aggiornato." +msgstr "" +"Non hai selezionato nessun pacchetto da contrassegnare come aggiornato." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "I pacchetti selezionati non sono più contrassegnati." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Non hai il permesso per eliminare i pacchetti." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Non hai selezionato nessun pacchetto da eliminare." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "I pacchetti selezionati sono stati eliminati." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Devi autenticarti prima di poter adottare i pacchetti." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Devi autenticarti prima di poter abbandonare i pacchetti." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Non hai selezionato nessun pacchetto da adottare." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Non hai selezionato nessun pacchetto da abbandonare." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "I pacchetti selezionati sono stati adottati." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "I pacchetti selezionati sono stati abbandonati." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Devi autenticarti prima di poter votare i pacchetti." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Devi autenticarti prima di poter rimuovere il voto dai pacchetti." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Non hai selezionato nessun pacchetto a cui assegnare il voto." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "I voti sono stati rimossi dai pacchetti selezionati." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "I voti sono stati assegnati ai pacchetti selezionati." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Impossibile aggiungere alla lista delle notifiche." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Sei stato aggiunto alla lista delle notifiche dei commenti di %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Sei stato rimosso dalla lista delle notifiche dei commenti di %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Devi autenticarti prima di poter modificare le informazioni del pacchetto." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Manca l'ID del commento." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Il commento è stato rimosso." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Non sei autorizzato a rimuovere questo commento." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Il commento è stato rimosso." + msgid "Comment has been edited." -msgstr "" +msgstr "I commenti sono stati modificati." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "Non sei autorizzato a modificare le parole chiave di questo pacchetto base." +msgstr "" +"Non sei autorizzato a modificare le parole chiave di questo pacchetto base." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Le parole chiave del pacchetto base sono state aggiornate." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Non sei autorizzato a gestire i co-manutentori di questo pacchetto base." +msgstr "" +"Non sei autorizzato a gestire i co-manutentori di questo pacchetto base." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Il nome utente non è valido: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "I co-menutentori del pacchetto base sono stati aggiornati." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Mostra i dettagli dei pacchetti di" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" -msgstr "" +msgstr "richiede %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Devi autenticarti per richiedere i pacchetti." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Il nome non è valido: sono consentite solo le lettere minuscole." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Il campo dei commenti non deve essere vuoto." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Il tipo di richiesta non è valido." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "La richiesta è stata aggiunta con successo." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Il motivo non è valido." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Solo i TU e gli sviluppatori possono chiudere le richieste." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "La richiesta è stata chiusa con successo." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Puoi usare questo modulo per eliminare definitivamente da AUR l'account %s." +msgstr "" +"Puoi usare questo modulo per eliminare definitivamente da AUR l'account %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sATTENZIONE%s: questa azione non può essere incompiuta." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Conferma la rimozione" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nome utente" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo di account" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utente" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Sviluppatore" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "TU e sviluppatore" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Indirizzo email" -#: template/account_details.php msgid "hidden" -msgstr "" +msgstr "nascosto" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome reale" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Fingerprint della chiave PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Stato" -#: template/account_details.php msgid "Inactive since" msgstr "Inattivo da" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Attivo" -#: template/account_details.php msgid "Last Login" msgstr "Ultimo accesso" -#: template/account_details.php msgid "Never" msgstr "Mai" -#: template/account_details.php msgid "View this user's packages" msgstr "Mostra i pacchetti di quest'utente" -#: template/account_details.php msgid "Edit this user's account" msgstr "Modifica l'account di quest'utente" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clicca %squi%s se vuoi eliminare definitivamente questo account." -#: template/account_edit_form.php msgid "required" msgstr "obbligatorio" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utente normale" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "TU" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Account sospeso" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inattivo" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Assicurati di immettere correttamente il tuo indirizzo email, altrimenti " +"sarai bloccato." -#: template/account_edit_form.php msgid "Hide Email Address" -msgstr "" +msgstr "Nascondi l'indirizzo email" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Riscrivi la password" -#: template/account_edit_form.php msgid "Language" msgstr "Lingua" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "La seguente informazione è richiesta solo se vuoi inviare i pacchetti nell'Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"La seguente informazione è richiesta solo se vuoi inviare i pacchetti " +"nell'Arch User Repository." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Chiave pubblica SSH" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Aggiorna" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Crea" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Cancella" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Nessun risultato corrisponde ai tuoi criteri di ricerca." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Modifica l'account" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Sospeso" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Modifica" - -#: template/account_search_results.php -msgid "Less" -msgstr "Precedente" - -#: template/account_search_results.php -msgid "More" -msgstr "Successivo" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Non vi sono ulteriori risultati da mostrare." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Gestisci i co-manutentori: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Usa questo modulo per aggiungere i co-manutentori di %s%s%s (un nome utente per linea):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Utenti" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Salva" - -#: template/header.php -msgid "My Packages" -msgstr "I miei pacchetti" - -#: template/header.php -msgid " My Account" -msgstr "Il mio account" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Azioni del pacchetto" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Mostra il PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Mostra le modifiche" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Scarica lo snapshot" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Cerca nel wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Il pacchetto non è aggiornato" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Segnala che il pacchetto non è aggiornato" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Rimuovi la segnalazione del pacchetto" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Rimuovi il voto" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Vota per questo pacchetto" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Disabilita le notifiche" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notifica dei nuovi commenti" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Aggiorna" + +msgid "Create" +msgstr "Crea" + +msgid "Reset" +msgstr "Cancella" + +msgid "No results matched your search criteria." +msgstr "Nessun risultato corrisponde ai tuoi criteri di ricerca." + +msgid "Edit Account" +msgstr "Modifica l'account" + +msgid "Suspended" +msgstr "Sospeso" + +msgid "Edit" +msgstr "Modifica" + +msgid "Less" +msgstr "Precedente" + +msgid "More" +msgstr "Successivo" + +msgid "No more results to display." +msgstr "Non vi sono ulteriori risultati da mostrare." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Usa questo modulo per aggiungere i co-manutentori di %s%s%s (un nome utente " +"per linea):" + +msgid "Users" +msgstr "Utenti" + +msgid "Save" +msgstr "Salva" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Copyright %s 2004-%d aurweb Development Team." + +msgid "My Packages" +msgstr "I miei pacchetti" + +msgid " My Account" +msgstr "Il mio account" + +msgid "Package Actions" +msgstr "Azioni del pacchetto" + +msgid "View PKGBUILD" +msgstr "Mostra il PKGBUILD" + +msgid "View Changes" +msgstr "Mostra le modifiche" + +msgid "Download snapshot" +msgstr "Scarica lo snapshot" + +msgid "Search wiki" +msgstr "Cerca nel wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Segnala che il pacchetto non è aggiornato" + +msgid "Unflag package" +msgstr "Rimuovi la segnalazione del pacchetto" + +msgid "Remove vote" +msgstr "Rimuovi il voto" + +msgid "Vote for this package" +msgstr "Vota per questo pacchetto" + +msgid "Disable notifications" +msgstr "Disabilita le notifiche" + msgid "Manage Co-Maintainers" msgstr "Gestisci i co-manutentori" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d richiesta in attesa" msgstr[1] "%d richieste in attesa" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Elimina il pacchetto" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Unisci il pacchetto" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotta il pacchetto" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "sconosciuta" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Dettagli del pacchetto base" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "sola lettura" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Parole chiave" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Contributore" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Manutentore" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ultimo pacchettizzatore" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Voti" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popolarità" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Data del primo invio" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ultimo aggiornamento" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Modifica il commento di: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Aggiungi un commento" -#: template/pkg_comments.php msgid "View all comments" msgstr "Mostra tutti i commenti" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "Elimina i commenti" + msgid "Latest Comments" msgstr "Ultimi commenti" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s ha commentato su %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Commento anonimo su %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "Eliminato su %s da %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Rimuovi il commento" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "Inserisci il commento" + +msgid "Unpin comment" +msgstr "Elimina il commento" + msgid "All comments" msgstr "Tutti i commenti" -#: template/pkg_details.php msgid "Package Details" msgstr "Dettagli del pacchetto" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacchetto base" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrizione" -#: template/pkg_details.php msgid "Upstream URL" msgstr "URL dell'upstream" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita il sito web di" -#: template/pkg_details.php msgid "Licenses" msgstr "Licenze" -#: template/pkg_details.php msgid "Groups" msgstr "Gruppi" -#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitti" -#: template/pkg_details.php msgid "Provides" msgstr "Fornisce" -#: template/pkg_details.php msgid "Replaces" msgstr "Rimpiazza" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dipendenze" -#: template/pkg_details.php msgid "Required by" msgstr "Richiesto da" -#: template/pkg_details.php msgid "Sources" msgstr "Sorgenti" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Chiudi la richiesta: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa questo modulo per chiudere la richiesta del pacchetto base %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Il campo dei commenti può essere lasciato vuoto. Tuttavia, è consigliabile aggiungere un commento quando non si accetta una richiesta." +msgstr "" +"Il campo dei commenti può essere lasciato vuoto. Tuttavia, è consigliabile " +"aggiungere un commento quando non si accetta una richiesta." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motivo" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Accettato" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Rifiutato" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Invia una richiesta per: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Usa questo modulo per inviare una richiesta per il pacchetto base %s%s%s che include i seguenti pacchetti:" +msgstr "" +"Usa questo modulo per inviare una richiesta per il pacchetto base %s%s%s che " +"include i seguenti pacchetti:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo di richiesta" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Elimina" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Abbandona" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Unisci con" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d di %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pacchetto" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Inviato da" -#: template/pkgreq_results.php msgid "Date" msgstr "Data" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d giorni rimanenti" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d ora rimanente" msgstr[1] "~%d ore rimanenti" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 ora rimanente" -#: template/pkgreq_results.php msgid "Accept" msgstr "Accetta" -#: template/pkgreq_results.php msgid "Locked" msgstr "Bloccato" -#: template/pkgreq_results.php msgid "Close" msgstr "Chiudi" -#: template/pkgreq_results.php msgid "Closed" msgstr "Chiuso" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descrizione" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Solo il nome" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome esatto" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacchetto base esatto" -#: template/pkg_search_form.php msgid "All" msgstr "Tutti" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Non aggiornati" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Aggiornati" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votato" -#: template/pkg_search_form.php msgid "Last modified" -msgstr "" +msgstr "Ultima modifica" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" -#: template/pkg_search_form.php msgid "Descending" msgstr "Discendente" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Seleziona i criteri di ricerca" -#: template/pkg_search_form.php msgid "Search by" msgstr "Cerca per" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Non aggiornati" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordina per" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordina in modo" -#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagina" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Cerca" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfani" -#: template/pkg_search_results.php msgid "Error retrieving package list." -msgstr "Si è verificato un errore durante il recupero della lista dei pacchetti." +msgstr "" +"Si è verificato un errore durante il recupero della lista dei pacchetti." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nessun pacchetto corrisponde ai tuoi criteri di ricerca." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." -#: template/pkg_search_results.php msgid "Version" msgstr "Versione" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "La popolarità viene calcolata come la somma di tutti i voti con ogni voto ponderato con un fattore di 0,98 al giorno dalla sua creazione." +msgstr "" +"La popolarità viene calcolata come la somma di tutti i voti con ogni voto " +"ponderato con un fattore di 0,98 al giorno dalla sua creazione." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Sì" -#: template/pkg_search_results.php msgid "orphan" msgstr "orfano" -#: template/pkg_search_results.php msgid "Actions" msgstr "Azioni" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Il pacchetto non è aggiornato" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Il pacchetto è aggiornato" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adotta il pacchetto" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abbandona il pacchetto" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Elimina il pacchetto" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Conferma" -#: template/search_accounts_form.php msgid "Any type" msgstr "Qualsiasi tipo" -#: template/search_accounts_form.php msgid "Search" msgstr "Cerca" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiche" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacchetti orfani" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacchetti aggiunti negli ultimi 7 giorni" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacchetti aggiornati negli ultimi 7 giorni" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacchetti aggiornati nell'ultimo anno" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacchetti mai aggiornati" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utenti registrati" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "TU" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Aggiornamenti recenti" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Le mie statistiche" -#: template/tu_details.php msgid "Proposal Details" msgstr "Dettagli della proposta" -#: template/tu_details.php msgid "This vote is still running." msgstr "Questa votazione è ancora in corso." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Inviato: %s da %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fine" -#: template/tu_details.php msgid "Result" msgstr "Risultato" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" -#: template/tu_details.php msgid "Abstain" msgstr "Astenuto" -#: template/tu_details.php msgid "Total" msgstr "Totale" -#: template/tu_details.php msgid "Participation" msgstr "Partecipazione" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ultimi voti dei TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ultimo voto" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "La ricerca non ha prodotto nessun risultato." -#: template/tu_list.php msgid "Start" msgstr "Home" -#: template/tu_list.php msgid "Back" msgstr "Precedente" diff --git a/po/ja.po b/po/ja.po index 4b0417b0..add4f67b 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,1804 +1,1493 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: -# kusakata , 2013 -# kusakata , 2013 -# kusakata , 2013-2015 +# kusakata, 2013 +# kusakata, 2013 +# kusakata, 2013-2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/ja/)\n" +"Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" +"ja/)\n" +"Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ja\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: html/404.php msgid "Page Not Found" msgstr "ページが見つかりませんでした" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "あなたがリクエストしたページは存在しませんでした。" -#: html/503.php msgid "Service Unavailable" msgstr "Service Unavailable" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "落ち着いて下さい!このサイトはメンテナンスのためにダウンしています。すぐに復帰する予定です。" +msgstr "" +"落ち着いて下さい!このサイトはメンテナンスのためにダウンしています。すぐに復" +"帰する予定です。" -#: html/account.php msgid "Account" msgstr "アカウント" -#: html/account.php template/header.php msgid "Accounts" msgstr "アカウント" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "このページへのアクセスは許可されていません。" -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "指定のユーザーの情報が取得できませんでした。" -#: html/account.php msgid "You do not have permission to edit this account." msgstr "あなたはこのアカウントを編集する権利を持っていません。" -#: html/account.php msgid "Use this form to search existing accounts." msgstr "アカウントの検索はこのフォームを使って下さい。" -#: html/account.php msgid "You must log in to view user information." msgstr "ユーザー情報を見るにはログインする必要があります。" -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "提案を追加する" -#: html/addvote.php msgid "Invalid token for user action." msgstr "アクションの不正なトークン。" -#: html/addvote.php msgid "Username does not exist." msgstr "ユーザー名が存在しません。" -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s はすでにその提案を持っています。" -#: html/addvote.php msgid "Invalid type." msgstr "不正なタイプ。" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "提案が空です。" -#: html/addvote.php msgid "New proposal submitted." msgstr "新しい提案が投稿されました。" -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "採決する提案を提出してください。" -#: html/addvote.php msgid "Applicant/TU" msgstr "候補者/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(適当なものがない場合は空に)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "タイプ" -#: html/addvote.php msgid "Addition of a TU" msgstr "TU の追加" -#: html/addvote.php msgid "Removal of a TU" msgstr "TU の削除" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU の削除 (undeclared inactivity)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "規約の修正" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "提案" -#: html/addvote.php msgid "Submit" msgstr "投稿" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "共同メンテナの管理" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "コメントを編集" -#: html/home.php template/header.php msgid "Home" msgstr "ホーム" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "AUR にようこそ!AUR についての詳しい情報は %sAUR User Guidelines%s や %sAUR TU Guidelines%s を読んで下さい。" +msgstr "" +"AUR にようこそ!AUR についての詳しい情報は %sAUR User Guidelines%s や %sAUR " +"TU Guidelines%s を読んで下さい。" -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "PKGBUILD を投稿するつもりならば%s必ず%s %sArch Packaging Standards%s に従って下さい。従っていないパッケージは削除されます!" +msgstr "" +"PKGBUILD を投稿するつもりならば%s必ず%s %sArch Packaging Standards%s に従って" +"下さい。従っていないパッケージは削除されます!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "お気に入りのパッケージに投票しましょう!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "パッケージがバイナリとして [community] で提供されることになるかもしれません。" +msgstr "" +"パッケージがバイナリとして [community] で提供されることになるかもしれません。" -#: html/home.php msgid "DISCLAIMER" msgstr "免責事項" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"AUR のパッケージはユーザーによって作成されたものです。自己責任で使用して下さ" +"い。" -#: html/home.php msgid "Learn more..." msgstr "詳細..." -#: html/home.php msgid "Support" msgstr "サポート" -#: html/home.php msgid "Package Requests" msgstr "パッケージリクエスト" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "各パッケージの詳細ページにある%sパッケージアクション%sボックスから送信することができるリクエストは3種類あります:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"各パッケージの詳細ページにある%sパッケージアクション%sボックスから送信するこ" +"とができるリクエストは3種類あります:" -#: html/home.php msgid "Orphan Request" msgstr "孤児リクエスト" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "パッケージを孤児にするようにリクエストします。メンテナが活動を停止していてパッケージが長い間 out-of-date のまま放置されている場合などに使います。" +msgstr "" +"パッケージを孤児にするようにリクエストします。メンテナが活動を停止していて" +"パッケージが長い間 out-of-date のまま放置されている場合などに使います。" -#: html/home.php msgid "Deletion Request" msgstr "削除リクエスト" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Arch User Repository からパッケージを削除するようにリクエストします。パッケージが壊れていて、その不具合を簡単に修正できるような場合、このリクエストは使わないで下さい。代わりに、パッケージのメンテナに連絡したり、必要に応じて孤児リクエストを送りましょう。" +msgstr "" +"Arch User Repository からパッケージを削除するようにリクエストします。パッケー" +"ジが壊れていて、その不具合を簡単に修正できるような場合、このリクエストは使わ" +"ないで下さい。代わりに、パッケージのメンテナに連絡したり、必要に応じて孤児リ" +"クエストを送りましょう。" -#: html/home.php msgid "Merge Request" msgstr "マージリクエスト" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "あるパッケージを他のパッケージとマージするようにリクエストします。パッケージの名前を変更する必要があるときや分割パッケージによって置き換えるときに使用します。" +msgstr "" +"あるパッケージを他のパッケージとマージするようにリクエストします。パッケージ" +"の名前を変更する必要があるときや分割パッケージによって置き換えるときに使用し" +"ます。" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "リクエストについて議論したい場合、%saur-requests%s メーリングリストを使います。ただし、このメーリングリスト宛にリクエストを送るのは止めて下さい。" +msgstr "" +"リクエストについて議論したい場合、%saur-requests%s メーリングリストを使いま" +"す。ただし、このメーリングリスト宛にリクエストを送るのは止めて下さい。" -#: html/home.php msgid "Submitting Packages" msgstr "パッケージの投稿" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "現在 AUR にパッケージを送信するときは SSH を介して Git を使うことになっています。詳しくは ArchWiki の Arch User Repository のページの%sパッケージの投稿%sセクションを見て下さい。" +msgstr "" +"現在 AUR にパッケージを送信するときは SSH を介して Git を使うことになっていま" +"す。詳しくは ArchWiki の Arch User Repository のページの%sパッケージの投稿%s" +"セクションを見て下さい。" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR では以下の SSH フィンガープリントが使われます:" -#: html/home.php msgid "Discussion" msgstr "議論" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Arch User Repository (AUR) や Trusted User に関する一般的な議論は %saur-general%s で行って下さい。AUR ウェブインターフェイスの開発に関しては、%saur-dev%s メーリングリストを使用します。" +msgstr "" +"Arch User Repository (AUR) や Trusted User に関する一般的な議論は %saur-" +"general%s で行って下さい。AUR ウェブインターフェイスの開発に関しては、%saur-" +"dev%s メーリングリストを使用します。" -#: html/home.php msgid "Bug Reporting" msgstr "バグレポート" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" +"AUR のウェブインターフェイスにバグを発見した時は%sバグトラッカー%sにバグを報" +"告してください。トラッカーを使って報告できるバグは AUR ウェブインターフェイス" +"のバグ%sだけ%sです。パッケージのバグを報告するときはパッケージのメンテナに連" +"絡するか該当するパッケージのページにコメントを投稿してください。" -#: html/home.php msgid "Package Search" msgstr "パッケージ検索" -#: html/index.php msgid "Adopt" msgstr "承継" -#: html/index.php msgid "Vote" msgstr "投票" -#: html/index.php msgid "UnVote" msgstr "投票を削除" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "通知を削除" -#: html/index.php msgid "UnFlag" msgstr "フラグを降ろす" -#: html/login.php template/header.php msgid "Login" msgstr "ログイン" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "ログイン中: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "ログアウト" -#: html/login.php msgid "Enter login credentials" msgstr "ログイン情報を入力してください" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "ユーザー名またはメールアドレス" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "パスワード" -#: html/login.php msgid "Remember me" msgstr "ログインしたままにする" -#: html/login.php msgid "Forgot Password" msgstr "パスワードを忘れた" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP ログインはできません。ログインするには %sHTTPs%s に切り替えてください。" +msgstr "" +"HTTP ログインはできません。ログインするには %sHTTPs%s に切り替えてください。" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "検索条件" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "パッケージ" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "パッケージの詳細の取得エラー。" -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "必須項目が埋められていません。" -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "パスワードが一致しません。" -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "パスワードは最低でも %s 文字以上必要です。" -#: html/passreset.php msgid "Invalid e-mail." msgstr "不正なメールアドレス。" -#: html/passreset.php msgid "Password Reset" msgstr "パスワードのリセット" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "メールをチェックして確認リンクを開いて下さい。" -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "パスワードのリセットが成功しました。" -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "メールアドレスの確認:" -#: html/passreset.php msgid "Enter your new password:" msgstr "新しいパスワードを入力:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "新しいパスワードを再入力:" -#: html/passreset.php msgid "Continue" msgstr "続行" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "登録したメールアドレスを忘れてしまった場合は、%saur-general%s メーリングリストにメッセージを送って下さい。" +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"登録したメールアドレスを忘れてしまった場合は、%saur-general%s メーリングリス" +"トにメッセージを送って下さい。" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "メールアドレスを入力:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "選択されたパッケージは孤児になっていません。確認チェックボックスにチェックを入れて下さい。" +msgstr "" +"選択されたパッケージは孤児になっていません。確認チェックボックスにチェックを" +"入れて下さい。" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "投票やコメントのマージをするパッケージが見つかりません。" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "パッケージベースをそれ自体とマージすることはできません。" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "選択されたパッケージは削除されませんでした、確認チェックボックスにチェックを入れてください。" +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"選択されたパッケージは削除されませんでした、確認チェックボックスにチェックを" +"入れてください。" -#: html/pkgdel.php msgid "Package Deletion" msgstr "パッケージの削除" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "削除するパッケージ: %s" +msgid "Delete Package" +msgstr "パッケージを削除" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "AUR からパッケージベース %s%s%s と以下のパッケージを削除するにはこのフォームを使って下さい:" +msgstr "" +"AUR からパッケージベース %s%s%s と以下のパッケージを削除するにはこのフォーム" +"を使って下さい:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "パッケージの削除は戻すことができません。" -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "アクションを確認するためにチェックボックスを選択してください。" -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "パッケージ削除の確認" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "削除" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Trusted User と開発者だけがパッケージを削除できます。" -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "パッケージの放棄" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "孤児にするパッケージ: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "このフォームを使って以下のパッケージを含むパッケージベース %s%s%s を孤児にすることができます:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"このフォームを使って以下のパッケージを含むパッケージベース %s%s%s を孤児にす" +"ることができます:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "チェックボックスを選択して、パッケージを孤児にして所有権を %s%s%s に移すことを確定して下さい。" +msgstr "" +"チェックボックスを選択して、パッケージを孤児にして所有権を %s%s%s に移すこと" +"を確定して下さい。" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "チェックボックスを選択して、パッケージを孤児にすることを確定してください。" +msgstr "" +"チェックボックスを選択して、パッケージを孤児にすることを確定してください。" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "パッケージを孤児にすることの確認" -#: html/pkgdisown.php msgid "Disown" msgstr "放棄" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Trusted User と開発者だけがパッケージを孤児にできます。" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "パッケージの Out-Of-Date フラグを立てる" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" +"このフォームを使ってパッケージベース %s%s%s と以下のパッケージの out-of-date " +"フラグを立てます:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"このフォームはバグを報告するためのものでは%sありません%s。バグを報告するとき" +"はパッケージのコメント欄を使って下さい。" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"以下にパッケージが out-of-date となっている理由を記述してください。なるべくリ" +"リースアナウンスや最新の tarball へのリンクも書きましょう。" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "コメント" -#: html/pkgflag.php msgid "Flag" msgstr "フラグ" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +"パッケージの out-of-date フラグを立てることができるのは登録済みのユーザーだけ" +"です。" -#: html/pkgmerge.php msgid "Package Merging" msgstr "パッケージのマージ" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "マージするパッケージ: %s" +msgid "Merge Package" +msgstr "パッケージのマージ" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "他のパッケージにパッケージベース %s%s%s をマージするにはこのフォームを使って下さい。" +msgstr "" +"他のパッケージにパッケージベース %s%s%s をマージするにはこのフォームを使って" +"下さい。" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "次のパッケージが削除されます:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "一度パッケージがマージされると戻すことはできません。" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "このパッケージをマージしたいパッケージ名を入力してください。" -#: html/pkgmerge.php msgid "Merge into:" msgstr "マージ先:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "パッケージマージの確認" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "マージ" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Trusted User と開発者だけがパッケージをマージできます。" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "リクエストを送る" +msgid "Submit Request" +msgstr "リクエストを送信" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "リクエストをクローズ" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "最初" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "前へ" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "次へ" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "リクエスト" -#: html/register.php template/header.php msgid "Register" msgstr "登録" -#: html/register.php msgid "Use this form to create an account." msgstr "このフォームを使ってアカウントを作成してください。" -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "提案内容が取得できませんでした。" -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "この提案への投票は締め切られています。" -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Trusted User だけが投票できます。" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "あなたについての提案に投票することはできません。" -#: html/tu.php msgid "You've already voted for this proposal." msgstr "既にこの提案に投票しています。" -#: html/tu.php msgid "Vote ID not valid." msgstr "投票 ID が不正です。" -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "現在の投票" -#: html/tu.php msgid "Past Votes" msgstr "過去の投票" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票者" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "スパムのために、あなたのIPアドレスからアカウント登録はできません。ご迷惑をおかけして申し訳ございません。" +msgstr "" +"スパムのために、あなたのIPアドレスからアカウント登録はできません。ご迷惑をお" +"かけして申し訳ございません。" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ユーザー ID の消失" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "ユーザー名が不正です。" -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "文字の長さは %s から %s の間である必要があります" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "最初と最後の文字は英数字にしてください" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "ピリオド、アンダーライン、ハイフンはひとつだけ含めることができます。" -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "メールアドレスが不正です。" -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 鍵のフィンガープリントが不正です。" -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH 公開鍵が不正です。" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "アカウント権限を増やすことはできません。" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "言語は現在サポートされていません。" -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "%s%s%s というユーザー名は既に使われています。" -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "%s%s%s というメールアドレスは既に使われています。" -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開鍵、%s%s%s は既に使われています。" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "アカウントの作成エラー、%s%s%s。" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "アカウント %s%s%s の作成が完了しました。" -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "パスワードのリセットキーがあなたのメールアドレスに送られました。" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "あなたのアカウントを使うには上のログインリンクをクリックして下さい。" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "アカウントに変更は加えられませんでした、%s%s%s。" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "アカウント %s%s%s の修正が完了しました。" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "スパムのために、現在あなたのIPアドレスからはログインフォームが無効になっています。ご迷惑をおかけして申し訳ございません。" +msgstr "" +"スパムのために、現在あなたのIPアドレスからはログインフォームが無効になってい" +"ます。ご迷惑をおかけして申し訳ございません。" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "休眠アカウント" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "あなたのパスワードはリセットされました。新しいアカウントを作成したときは、確認メールにあるリンクからパスワードを設定してください。もしくは、%sPassword Reset%s ページでリセットキーを申請してください。" +msgstr "" +"あなたのパスワードはリセットされました。新しいアカウントを作成したときは、確" +"認メールにあるリンクからパスワードを設定してください。もしくは、%sPassword " +"Reset%s ページでリセットキーを申請してください。" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "不正なユーザー名またはパスワードです。" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "ユーザーセッションの生成時にエラーが発生しました。" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "メールアドレスとリセットキーの不正な組み合わせ。" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "なし" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "%s のアカウント情報を見る" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." -msgstr "" +msgstr "パッケージベース ID やパッケージベース名が見つかりません。" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "このコメントを編集する権限がありません。" -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "コメントが存在しません。" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "コメントには何か文字列を記入してください。" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "コメントが追加されました。" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "パッケージの情報を編集するにはログインする必要があります。" + +msgid "Missing comment ID." +msgstr "コメント ID が見つかりません。" + +msgid "No more than 5 comments can be pinned." +msgstr "5個までコメントをピン留めできます。" + +msgid "You are not allowed to pin this comment." +msgstr "このコメントをピン留めする権限がありません。" + +msgid "You are not allowed to unpin this comment." +msgstr "このコメントのピン留めを解除する権限がありません。" + +msgid "Comment has been pinned." +msgstr "コメントはピン留めされました。" + +msgid "Comment has been unpinned." +msgstr "コメントのピン留めは解除されました。" + msgid "Error retrieving package details." msgstr "パッケージの詳細の取得エラー。" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "パッケージの詳細が見つかりませんでした。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "パッケージのフラグを立てるにはログインする必要があります。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "フラグを立てるパッケージが選ばれていません。" -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" +"選択されたパッケージはまだフラグが立てられていません、コメントを入力してくだ" +"さい。" + msgid "The selected packages have been flagged out-of-date." msgstr "選択されたパッケージの out-of-date フラグが立てられました。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "パッケージのフラグを降ろすにはログインする必要があります。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "フラグを降ろすパッケージが選ばれていません。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "選択されたパッケージのフラグが降ろされました。" -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "あなたはパッケージを削除する許可を持っていません。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "削除するパッケージが選ばれていません。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "選択されたパッケージが削除されました。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "パッケージを承継するにはログインする必要があります。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "パッケージを放棄するにはログインする必要があります。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "承継するパッケージが選択されていません。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "放棄するパッケージが選択されていません。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "選択されたパッケージを承継しました。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "選択されたパッケージを放棄しました。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "パッケージに投票するにはログインする必要があります。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "パッケージへの投票を取り消すにはログインする必要があります。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "投票するパッケージが選ばれていません。" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "選択されたパッケージからあなたの投票が削除されました。" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "選択されたパッケージに投票しました。" -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "通知リストに追加できませんでした。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "%s がコメントの通知リストに追加されました。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "%s がコメントの通知リストから削除されました。" -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "パッケージの情報を編集するにはログインする必要があります。" +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "コメント ID が見つかりません。" +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "コメントが削除されました。" - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "このコメントを削除することはできません。" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been edited." -msgstr "" +msgid "Comment has been deleted." +msgstr "コメントが削除されました。" + +msgid "Comment has been edited." +msgstr "コメントは編集されました。" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "このパッケージベースのキーワードを編集することはできません。" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "パッケージベースのキーワードは更新されました。" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "このパッケージベースの共同メンテナを管理することはできません。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "不正なユーザー名: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "パッケージベースの共同メンテナが更新されました。" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "パッケージの詳細を見る" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" -msgstr "" +msgstr "%s が必要" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "パッケージリクエストを送るにはログインする必要があります。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "不正な名前です: 小文字だけが使用できます。" -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "コメント欄には何か記入して下さい。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "不正なリクエストの種類。" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "リクエストの追加が完了しました。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "不正な理由。" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "TU と開発者だけがリクエストをクローズできます。" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "リクエストのクローズが完了しました。" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "このフォームを使って AUR アカウント %s を恒久的に削除することができます。" +msgstr "" +"このフォームを使って AUR アカウント %s を恒久的に削除することができます。" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s: この操作は元に戻すことができません。" -#: template/account_delete.php msgid "Confirm deletion" msgstr "削除の確認" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "ユーザー名" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "アカウントタイプ" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "ユーザー" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "開発者" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & 開発者" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "メールアドレス" -#: template/account_details.php msgid "hidden" -msgstr "" +msgstr "非公開" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "本名" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC ニックネーム" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 鍵のフィンガープリント" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "状態" -#: template/account_details.php msgid "Inactive since" msgstr "休止開始" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "活動中" -#: template/account_details.php msgid "Last Login" msgstr "最後のログイン" -#: template/account_details.php msgid "Never" msgstr "Never" -#: template/account_details.php msgid "View this user's packages" msgstr "ユーザーのパッケージを見る" -#: template/account_details.php msgid "Edit this user's account" msgstr "このユーザーのアカウントを編集" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "このアカウントを恒久的に削除したい場合は%sこちら%sをクリック。" -#: template/account_edit_form.php msgid "required" msgstr "必須" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "ノーマルユーザー" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "休眠アカウント" -#: template/account_edit_form.php msgid "Inactive" msgstr "活動休止" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"入力したメールアドレスが正しいか確認してください。間違っていた場合、アカウン" +"トが使えなくなります。" -#: template/account_edit_form.php msgid "Hide Email Address" -msgstr "" +msgstr "メールアドレスを非公開にする" -#: template/account_edit_form.php msgid "Re-type password" msgstr "パスワードの再入力" -#: template/account_edit_form.php msgid "Language" msgstr "言語" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "以下の情報は Arch User Repository にパッケージを送信したい場合にのみ必要になります。" +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"以下の情報は Arch User Repository にパッケージを送信したい場合にのみ必要にな" +"ります。" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH 公開鍵" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "更新" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "作成" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "リセット" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "検索条件に一致する結果が見つかりませんでした。" - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "アカウントを編集" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "休止" - -#: template/account_search_results.php -msgid "Edit" -msgstr "編集" - -#: template/account_search_results.php -msgid "Less" -msgstr "Less" - -#: template/account_search_results.php -msgid "More" -msgstr "More" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "表示する結果はもうありません。" - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "共同メンテナの管理: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "このフォームを使って %s%s%s の共同メンテナを追加することができます (一行につき一人のユーザー名を入力):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "ユーザー" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "保存" - -#: template/header.php -msgid "My Packages" -msgstr "自分のパッケージ" - -#: template/header.php -msgid " My Account" -msgstr "アカウント" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "パッケージアクション" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "PKGBUILD を見る" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "変更履歴" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "スナップショットのダウンロード" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "wiki を検索" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "out-of-date フラグを立てる" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "パッケージの out-of-date フラグを立てる" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "パッケージのフラグを降ろす" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "投票を削除する" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "このパッケージに投票する" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "通知を止める" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "新しいコメントを通知" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "更新" + +msgid "Create" +msgstr "作成" + +msgid "Reset" +msgstr "リセット" + +msgid "No results matched your search criteria." +msgstr "検索条件に一致する結果が見つかりませんでした。" + +msgid "Edit Account" +msgstr "アカウントを編集" + +msgid "Suspended" +msgstr "休止" + +msgid "Edit" +msgstr "編集" + +msgid "Less" +msgstr "Less" + +msgid "More" +msgstr "More" + +msgid "No more results to display." +msgstr "表示する結果はもうありません。" + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"このフォームを使って %s%s%s の共同メンテナを追加することができます (一行につ" +"き一人のユーザー名を入力):" + +msgid "Users" +msgstr "ユーザー" + +msgid "Save" +msgstr "保存" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Copyright %s 2004-%d aurweb Development Team." + +msgid "My Packages" +msgstr "自分のパッケージ" + +msgid " My Account" +msgstr "アカウント" + +msgid "Package Actions" +msgstr "パッケージアクション" + +msgid "View PKGBUILD" +msgstr "PKGBUILD を見る" + +msgid "View Changes" +msgstr "変更履歴" + +msgid "Download snapshot" +msgstr "スナップショットのダウンロード" + +msgid "Search wiki" +msgstr "wiki を検索" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "パッケージの out-of-date フラグを立てる" + +msgid "Unflag package" +msgstr "パッケージのフラグを降ろす" + +msgid "Remove vote" +msgstr "投票を削除する" + +msgid "Vote for this package" +msgstr "このパッケージに投票する" + +msgid "Disable notifications" +msgstr "通知を止める" + msgid "Manage Co-Maintainers" msgstr "共同メンテナの管理" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" -msgstr[0] "%d 個の保留リクエスト。" +msgstr[0] "%d 件の保留リクエスト。" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "パッケージを削除" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "パッケージのマージ" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "パッケージを承継する" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "不明" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "パッケージベースの詳細" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git クローン URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "リードオンリー" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "キーワード" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "投稿者" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "メンテナ" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最後のパッケージ作成者" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "投票数" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "人気度" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "最初の投稿" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最終更新" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "コメントを編集: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "コメントを投稿する" -#: template/pkg_comments.php msgid "View all comments" msgstr "全てのコメントを表示" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "ピン留めされたコメント" + msgid "Latest Comments" msgstr "最新のコメント" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s が %s にコメントを投稿しました" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "匿名ユーザーが %s にコメントを投稿しました" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "%s によって %s に削除" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "コメントを削除" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "コメントをピン留めする" + +msgid "Unpin comment" +msgstr "コメントのピン留めを解除" + msgid "All comments" msgstr "全てのコメント" -#: template/pkg_details.php msgid "Package Details" msgstr "パッケージの詳細" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "パッケージベース" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "説明" -#: template/pkg_details.php msgid "Upstream URL" msgstr "上流 URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "ウェブサイトを見る" -#: template/pkg_details.php msgid "Licenses" msgstr "ライセンス" -#: template/pkg_details.php msgid "Groups" msgstr "グループ" -#: template/pkg_details.php msgid "Conflicts" msgstr "衝突" -#: template/pkg_details.php msgid "Provides" msgstr "提供" -#: template/pkg_details.php msgid "Replaces" msgstr "置換" -#: template/pkg_details.php msgid "Dependencies" msgstr "依存パッケージ" -#: template/pkg_details.php msgid "Required by" msgstr "必要としているパッケージ" -#: template/pkg_details.php msgid "Sources" msgstr "ソース" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "クローズリクエスト: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "このフォームを使ってパッケージベース %s%s%s のリクエストをクローズすることができます。" +msgstr "" +"このフォームを使ってパッケージベース %s%s%s のリクエストをクローズすることが" +"できます。" -#: template/pkgreq_close_form.php msgid "Note" msgstr "ノート" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "コメント欄は空でもかまいません。ただし、リクエストを却下されたときはコメントを追加することを強く推奨します。" +msgstr "" +"コメント欄は空でもかまいません。ただし、リクエストを却下されたときはコメント" +"を追加することを強く推奨します。" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "理由" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "承認されました" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "却下されました" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "リクエストを送る: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "このフォームを使って以下のパッケージを含むパッケージベース %s%s%s にリクエストを送ることができます:" +msgstr "" +"このフォームを使って以下のパッケージを含むパッケージベース %s%s%s にリクエス" +"トを送ることができます:" -#: template/pkgreq_form.php msgid "Request type" msgstr "リクエストの種類" -#: template/pkgreq_form.php msgid "Deletion" msgstr "削除" -#: template/pkgreq_form.php msgid "Orphan" msgstr "孤児" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "マージ" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "パッケージリクエストが %d 個見つかりました。" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "ページ %d / %d。" -#: template/pkgreq_results.php msgid "Package" msgstr "パッケージ" -#: template/pkgreq_results.php msgid "Filed by" msgstr "送信者" -#: template/pkgreq_results.php msgid "Date" msgstr "日付" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "残り ~%d 日" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "残り ~%d 時間" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "残り <1 時間" -#: template/pkgreq_results.php msgid "Accept" msgstr "承認" -#: template/pkgreq_results.php msgid "Locked" msgstr "ロックされています" -#: template/pkgreq_results.php msgid "Close" msgstr "クローズ" -#: template/pkgreq_results.php msgid "Closed" msgstr "クローズされました" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "名前、説明" -#: template/pkg_search_form.php msgid "Name Only" msgstr "名前のみ" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "名前完全一致" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "パッケージベース完全一致" -#: template/pkg_search_form.php msgid "All" msgstr "全て" -#: template/pkg_search_form.php msgid "Flagged" msgstr "フラグ付き" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "フラグなし" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名前" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "投票済" -#: template/pkg_search_form.php msgid "Last modified" -msgstr "" +msgstr "最終更新日" -#: template/pkg_search_form.php msgid "Ascending" msgstr "昇順" -#: template/pkg_search_form.php msgid "Descending" msgstr "降順" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "検索条件を入力" -#: template/pkg_search_form.php msgid "Search by" msgstr "検索対象" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Out of Date" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "ソート" -#: template/pkg_search_form.php msgid "Sort order" msgstr "ソート順" -#: template/pkg_search_form.php msgid "Per page" msgstr "表示件数" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "検索" -#: template/pkg_search_form.php msgid "Orphans" msgstr "孤児のパッケージ" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "パッケージリスト取得エラー。" -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "検索条件に一致するパッケージがありません。" -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "パッケージが %d 個見つかりました。" -#: template/pkg_search_results.php msgid "Version" msgstr "バージョン" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "人気度は各投票に作成日からの日数を0.98倍した全投票の合計で計算されます。" +msgstr "" +"人気度は各投票に作成日からの日数を0.98倍した全投票の合計で計算されます。" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "はい" -#: template/pkg_search_results.php msgid "orphan" msgstr "孤児" -#: template/pkg_search_results.php msgid "Actions" msgstr "アクション" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Out-of-date フラグを立てる" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Out-of-date フラグを降ろす" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "パッケージの承継" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "パッケージの放棄" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "パッケージの削除" -#: template/pkg_search_results.php msgid "Confirm" msgstr "確認" -#: template/search_accounts_form.php msgid "Any type" msgstr "全てのタイプ" -#: template/search_accounts_form.php msgid "Search" msgstr "検索" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "統計" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "孤児のパッケージ" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "過去7日間で追加されたパッケージ" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "過去7日間で更新されたパッケージ" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "過去1年間で更新されたパッケージ" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "更新されたことがないパッケージ" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "登録ユーザー" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted User" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最近のアップデート" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "自分の統計" -#: template/tu_details.php msgid "Proposal Details" msgstr "提案の詳細" -#: template/tu_details.php msgid "This vote is still running." msgstr "投票が実行されています。" -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "投稿: %s by %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "終了" -#: template/tu_details.php msgid "Result" msgstr "結果" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "いいえ" -#: template/tu_details.php msgid "Abstain" msgstr "Abstain" -#: template/tu_details.php msgid "Total" msgstr "合計" -#: template/tu_details.php msgid "Participation" msgstr "参加" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "TU による最後の投票" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最後の投票" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "結果が見つかりませんでした。" -#: template/tu_list.php msgid "Start" msgstr "開始" -#: template/tu_list.php msgid "Back" msgstr "前へ" diff --git a/po/nb.po b/po/nb.po index 4277ae5a..a16d6c0a 100644 --- a/po/nb.po +++ b/po/nb.po @@ -1,1808 +1,1461 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Alexander F Rødseth , 2015 # Alexander F Rødseth , 2011,2013-2014 +# Harald H. , 2015 +# AdmiringWorm , 2016 # Lukas Fleischer , 2011 +# Thor K. H. , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/language/nb/)\n" +"Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" +"language/nb/)\n" +"Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: nb\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Finner ikke siden" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Den ønskede siden finnes ikke." -#: html/503.php msgid "Service Unavailable" -msgstr "" +msgstr "Tjenesten er utilgjengelig" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "Slapp av! Siden er nede på grunn av vedlikehold. Vi er snart tilbake." -#: html/account.php msgid "Account" msgstr "Konto" -#: html/account.php template/header.php msgid "Accounts" msgstr "Kontoer" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Du har ikke adgang til dette området." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kunne ikke motta informasjon for den valgte brukeren." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du har ikke adgang til å endre denne kontoen." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Bruk dette skjemaet for å lete etter eksisterende kontoer." -#: html/account.php msgid "You must log in to view user information." msgstr "Du må logge inn for å se brukerinformasjon." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Legg til forslag" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Ugyldig billett for brukerens handling." -#: html/addvote.php msgid "Username does not exist." msgstr "Brukernavn finnes ikke." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s har allerede et forslag på gang." -#: html/addvote.php msgid "Invalid type." msgstr "Ugyldig type." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Forslag kan ikke være tomme." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nytt forslag innsendt." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Send inn et forslag for å stemme over." -#: html/addvote.php msgid "Applicant/TU" msgstr "Søker/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tomt hvis det ikke gjelder her)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Type" -#: html/addvote.php msgid "Addition of a TU" msgstr "Oppnevnelse av TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Fjerning av TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Fjerning av TU (uannonsert inaktivitet)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Endring av vedtekter" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Forslag" -#: html/addvote.php msgid "Submit" msgstr "Send inn" -#: html/comaintainers.php msgid "Manage Co-maintainers" -msgstr "" +msgstr "Administrer Med-Vedlikeholdere" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Rediger kommentar" -#: html/home.php template/header.php msgid "Home" msgstr "Hjem" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Velkommen til AUR! Vennligst les %sAUR Brukerveiledning%s og %sAUR TU Veiledning%s for mer informasjon." +msgstr "" +"Velkommen til AUR! Vennligst les %sAUR Brukerveiledning%s og %sAUR TU " +"Veiledning%s for mer informasjon." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Innsendte PKGBUILD-filer %små%s følge %sStandarden for Arch Pakker%s ellers vil de bli slettet!" +msgstr "" +"Innsendte PKGBUILD-filer %små%s følge %sStandarden for Arch Pakker%s ellers " +"vil de bli slettet!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Husk å stemme på dine favorittpakker!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Noen pakker finnes som binærfiler i [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "ANSVARSFRASKRIVELSE" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"AUR pakker er bruker produsert innhold. All bruk av de tilgjengelige filene " +"er på eget ansvar." -#: html/home.php msgid "Learn more..." -msgstr "" +msgstr "Lær mer..." -#: html/home.php msgid "Support" -msgstr "" +msgstr "Støtte" -#: html/home.php msgid "Package Requests" -msgstr "" +msgstr "Pakke Forespørsler" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" -msgstr "" +msgstr "Foreldreløs-forespørsel" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Forespør at pakken frigjøres fra eieren, dvs. at når vedlikeholderen er " +"inaktiv og pakken har vært markert som utdatert i en lengre periode." -#: html/home.php msgid "Deletion Request" -msgstr "" +msgstr "Slettingsforespørsel" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"Forespør at pakken fjernes fra Arch User Repository. Ikke bruk dette hvis " +"pakken er ødelagt og kan relativt lett rettes. Ta i stedet kontakt med " +"vedlikeholderen og send i verste fall en foreldreløs-forespørsel." -#: html/home.php msgid "Merge Request" -msgstr "" +msgstr "Flettingsforespørsel" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Forespør at pakken blir flettet inn i en annen en. Kan brukes når en pakke " +"trenger et navnebytte eller å bli erstattet av en oppsplittet pakke." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" -msgstr "" +msgstr "Innsending av pakker" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +"Git over SSH brukes nå for å sende inn pakker til AUR. Ta en titt på " +"%sSubmitting packages%s-seksjonen til Arch User Repository sin wikiside for " +"nærmere detaljer." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "De følgende SSH-fingeravtrykkene brukes for AUR-en:" -#: html/home.php msgid "Discussion" msgstr "Diskusjon" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Feilrapportering" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Pakkesøk" -#: html/index.php msgid "Adopt" msgstr "Adopter" -#: html/index.php msgid "Vote" msgstr "Stem" -#: html/index.php msgid "UnVote" msgstr "Fjern stemme" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Påminnelse" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Fjern påminnelse" -#: html/index.php msgid "UnFlag" msgstr "Fjern markering" -#: html/login.php template/header.php msgid "Login" msgstr "Logg inn" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Logget inn som: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Logg ut" -#: html/login.php msgid "Enter login credentials" msgstr "Fyll ut innloggingsinformasjon" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Brukernavn eller e-postadresse" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Passord" -#: html/login.php msgid "Remember me" msgstr "Husk meg" -#: html/login.php msgid "Forgot Password" msgstr "Glemt passord" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "HTTP-innlogging er deaktivert. %sBytt til HTTPs%s for å logge inn." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Søkekriterier" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakker" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Feil oppstod ved uthenting av pakkedetaljer." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Mangler et nødvendig felt." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Passord-feltene stemmer ikke overens." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Passordet ditt må være minst %s tegn." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Ugyldig e-post." -#: html/passreset.php msgid "Password Reset" msgstr "Tilbakestill passord" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "Sjekk e-posten din og bruk den tilsendte lenken for å bekrefte registreringen." +msgstr "" +"Sjekk e-posten din og bruk den tilsendte lenken for å bekrefte " +"registreringen." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Passordet ditt har blitt tilbakestilt." -#: html/passreset.php msgid "Confirm your e-mail address:" -msgstr "Bekreft din e-post addresse:" +msgstr "Bekreft e-postadressen din:" -#: html/passreset.php msgid "Enter your new password:" -msgstr "Skriv inn ditt nye passord:" +msgstr "Angi ditt nye passord:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Bekreft ditt nye passord:" -#: html/passreset.php msgid "Continue" msgstr "Fortsett" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Hvis du har glemt e-post adressen du brukte for å registrere deg, så kan du sende en e-post til listen %saur-general%s." - -#: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Fyll ut e-post adressen din:" - -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." msgstr "" +"Hvis du har glemt e-postadressen du brukte for å registrere deg, så kan du " +"sende en e-post til listen %saur-general%s." + +msgid "Enter your e-mail address:" +msgstr "Angi din e-postadresse:" -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Kunne ikke finne pakke for å flette stemmer og kommentarer inn i." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Kan ikke slå sammen en basispakke med seg selv." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Den valgte pakken har ikke blitt slettet, kryss av i boksen for å bekrefte." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Den valgte pakken har ikke blitt slettet, kryss av i boksen for å bekrefte." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Sletting av pakke" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Slett pakke: %s" +msgid "Delete Package" +msgstr "Slett pakke" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Bruk dette skjemaet for å slette grunnpakken %s%s%s og følgende pakker fra AUR:" +msgstr "" +"Bruk dette skjemaet for å slette grunnpakken %s%s%s og følgende pakker fra " +"AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Slettingen av en pakke er permanent. " -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Kryss av i boksen for å bekrefte." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bekreft sletting av pakke" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Slett" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Bare betrodde brukere og utviklere kan slette pakker." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Gjør foreldreløs" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "Gjør foreldreløs" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentarer" -#: html/pkgflag.php msgid "Flag" msgstr "Markering" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakkesammenslåing" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Slå sammen pakke: %s" +msgid "Merge Package" +msgstr "Slå sammen pakke" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Bruk dette skjemaet for å slå sammen grunnpakken %s%s%s med en annen pakke." +msgstr "" +"Bruk dette skjemaet for å slå sammen grunnpakken %s%s%s med en annen pakke." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Følgende pakker vil slettes:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Når pakken har blitt sammenslått, så kan det ikke angres. " -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Fyll ut navnet på pakken du ønsker å slå sammen denne pakken til." +msgstr "Angi navnet på pakken du ønsker å slå denne pakken sammen med." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Slå sammen til:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Bekreft sammenslåing" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Slå sammen" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Bare betrodde brukere og utviklere kan slå sammen pakker." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Send inn forespørsel" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Lukk forespørsel" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Forrige" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Neste" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Siste" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Forespørsler" -#: html/register.php template/header.php msgid "Register" msgstr "Registrer" -#: html/register.php msgid "Use this form to create an account." msgstr "Bruk dette feltet for å opprette en konto." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Betrodd bruker" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Kan ikke finne detaljer om forslaget." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Avstemningen er ferdig for dette forslaget." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Bare betrodde brukere har stemmerett." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Du kan ikke stemme på et forslag som gjelder deg." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du har allerede stemt på dette forslaget." -#: html/tu.php msgid "Vote ID not valid." msgstr "Stemme-ID ikke gyldig." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Foreløpige stemmer" -#: html/tu.php msgid "Past Votes" msgstr "Tidligere stemmer" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Velgere" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Funksjonen for registrering av nye kontoer har blitt slått av for din IP adresse, sannsynligvis på grunn av vedvarende spam-angrep. Vi beklager ulempen dette medfører." +msgstr "" +"Funksjonen for registrering av nye kontoer har blitt slått av for din IP " +"adresse, sannsynligvis på grunn av vedvarende spam-angrep. Vi beklager " +"ulempen dette medfører." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Mangler bruker-ID" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Brukernavnet er ugyldig." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Det må være mellom %s og %s tegn langt" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Start og slutt med en bokstav eller et siffer" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun innehold ett punktum, en understrek, eller en bindestrek." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-postadressen er ugyldig." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP fingeravtrykket er ikke gyldig." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Kan ikke gi flere tillatelser til kontoen." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Språket støttes ikke på dette tidspunktet." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Brukernavnet, %s%s%s, er allerede i bruk." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adressen, %s%s%s, er allerede i bruk." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Feil ved oppretting av konto, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Kontoen, %s%s%s, har nå blitt laget." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Nullstillingskode har blitt sendt til e-post adressen din." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klikk på Logg inn lenken over for å bruke kontoen." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Ingen endringer ble utført på kontoen, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Kontoen, %s%s%s, har nå blitt endret." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Inlogging er slått av for din IP adresse, sannsynligvis på grunn av vedvarende spam-angrep. Beklager ulempen dette medfører." +msgstr "" +"Inlogging er slått av for din IP adresse, sannsynligvis på grunn av " +"vedvarende spam-angrep. Beklager ulempen dette medfører." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Kontoen er stengt" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Passordet har blitt nullstilt. Dersom du akkurat laget en ny konto, vennligst følg lenken som ble sendt på e-post og sett så et nytt passord. Ellers kan du bruke %sNullstill Passord% siden til å få tilsendt en nullstillingskode." +msgstr "" +"Passordet har blitt nullstilt. Dersom du akkurat laget en ny konto, " +"vennligst følg lenken som ble sendt på e-post og sett så et nytt passord. " +"Ellers kan du bruke %sNullstill Passord% siden til å få tilsendt en " +"nullstillingskode." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Ugyldig brukernavn eller passord." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Feil oppstod ved generering av sesjon for bruker." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ugyldig kombinasjon av e-post og nullstillingsnøkkel." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Ingen" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Vis kontoinformasjon for %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentar har blitt lagt til." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Du må være logget inn for å kunne redigere pakkeinformasjon." + +msgid "Missing comment ID." +msgstr "Mangler kommentar-ID." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Kunne ikke finne frem pakkedetaljer." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Kunne ikke finne pakkedetaljer." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du må være logget inn for å kunne markere pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Ingen pakker ble valgt for å bli markert." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "De valgte pakkene har nå blitt markert som utdaterte." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "Du må være logget inn for å kunne fjerne \"utdatert\"-markeringen fra pakker." +msgstr "" +"Du må være logget inn for å kunne fjerne \"utdatert\"-markeringen fra pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Ingen pakker ble valgt for å fjerne markeringer fra." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De valgte pakkene har nå fått fjernet markeringen." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du har ikke rettighetene som skal til for å kunne slette pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du valgte ingen pakker for sletting." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De valgte pakkene har blitt slettet." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du må være logget inn for å kunne adoptere pakker." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du må være logget inn for å kunne gjøre pakker foreldreløse." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du valgte ingen pakker for adopsjon." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du valgte ingen pakker for å gjøre de foreldreløse." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Den valgte pakken har blitt adoptert." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De valgte pakkene er nå foreldreløse." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du må være logget inn for å kunne stemme på pakker." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du må være logget inn for å kunne trekke tilbake stemmer på pakker." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du valgte ingen pakker å stemme på." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Stemmene dine har blitt trukket tilbake fra de valgte pakkene." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Du har nå stemt på de valgte pakkene." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kunne ikke legge til i påminnelseslisten." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du har blitt lagt til påminnelselisten for kommentarer for %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du har blitt fjernet fra kommentarpåminnelselisten for %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Du må være logget inn for å kunne redigere pakkeinformasjon." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Mangler kommentar-ID." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Kommentar slettet." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du har ikke tilgang til å slette denne kommentaren." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Kommentar slettet." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vis pakkedetaljer for" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Du må være logget inn for å kunne sende inn forespørsler om pakker." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ugyldig navn: kun små bokstaver er lov." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Kommentarfeltet kan ikke være tomt." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ugyldig type forspørsel." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Forespørsel er registrert." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ugyldig grunn." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Bare betrodde brukere og utviklere kan lukke forespørsler." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Forespørselen ble lukket." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Dette skjemaet kan brukes for å permanent slette AUR kontoen %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVARSEL%s: Denne handlingen kan ikke angres." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Bekreft sletting" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Brukernavn" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Konto-type" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Bruker" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Utvikler" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Betrodd bruker & Utvikler" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "E-postadresse" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Ekte navn" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC-kallenavn" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP-nøkkel/fingeravtrykk" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Inaktiv siden" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" -#: template/account_details.php msgid "Last Login" msgstr "Sist logget inn" -#: template/account_details.php msgid "Never" msgstr "Aldri" -#: template/account_details.php msgid "View this user's packages" msgstr "Vis pakkene til denne brukereren" -#: template/account_details.php msgid "Edit this user's account" msgstr "Endre brukerkonto" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klikk %sher%s hvis du vil slette denne kontoen, for alltid." -#: template/account_edit_form.php msgid "required" msgstr "trengs" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Vanlig bruker" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Betrodd bruker" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto suspendert" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Kontroller at du har skrevet e-postadressen din korrekt, ellers vil du bli " +"låst ute." -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Skriv inn passordet på nytt" -#: template/account_edit_form.php msgid "Language" msgstr "Språk" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Gi beskjed om nye kommentarer" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Oppdater" -#: template/account_edit_form.php msgid "Create" msgstr "Opprett" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Omstart" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Ingen treff for de oppgitte søkekriteriene." -#: template/account_search_results.php msgid "Edit Account" msgstr "Endre brukerkonto" -#: template/account_search_results.php msgid "Suspended" msgstr "Suspendert" -#: template/account_search_results.php msgid "Edit" msgstr "Rediger" -#: template/account_search_results.php msgid "Less" msgstr "Færre" -#: template/account_search_results.php msgid "More" msgstr "Flere" -#: template/account_search_results.php msgid "No more results to display." msgstr "Ingen flere resultater å vise." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Mine pakker" -#: template/header.php msgid " My Account" msgstr " Min konto" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakkehandlinger" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Vis PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Søk wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Markert som utdatert" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marker pakke som utdatert" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Fjern markering" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Angre stemme" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem på denne pakken" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Slå av beskjeder" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Gi beskjed om nye kommentarer" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d ventende forespørsel" msgstr[1] "%d ventende forespørsler" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Slett pakke" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Slå sammen pakke" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter pakke" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "ukjent" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Grunnpakkedetaljer" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Nøkkelord" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Innsender" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Vedlikeholder" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Siste innpakker" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmer" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Først innsendt" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Sist oppdatert" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Legg til kommentar" -#: template/pkg_comments.php msgid "View all comments" msgstr "Vis alle kommentarer" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Siste kommentarer" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Slett kommentar" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Alle kommentarer" -#: template/pkg_details.php msgid "Package Details" msgstr "Pakkedetaljer" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Grunnpakke" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beskrivelse" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Prosjektets URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Besøk nettsiden til" -#: template/pkg_details.php msgid "Licenses" msgstr "Lisenser" -#: template/pkg_details.php msgid "Groups" msgstr "Grupper" -#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikter" -#: template/pkg_details.php msgid "Provides" msgstr "Tilbyr" -#: template/pkg_details.php msgid "Replaces" msgstr "Erstatter" -#: template/pkg_details.php msgid "Dependencies" msgstr "Avhengigheter" -#: template/pkg_details.php msgid "Required by" msgstr "Trengs av" -#: template/pkg_details.php msgid "Sources" msgstr "Kilder" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Lukk forespørsel: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Bruk dette skjemaet for å lukke forespørselen for grunnpakken %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "OBS" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Kommentarfeltet kan stå tomt, men det anbefales å legge igjen en melding når en forespørsel avvises." +msgstr "" +"Kommentarfeltet kan stå tomt, men det anbefales å legge igjen en melding når " +"en forespørsel avvises." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Begrunnelse" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Akseptert" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Avvist" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Send inn forespørsel: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Bruk dette skjemaet for å registrere en forespørsel for grunnpakken %s%s%s som inkluderer følgende pakker:" +msgstr "" +"Bruk dette skjemaet for å registrere en forespørsel for grunnpakken %s%s%s " +"som inkluderer følgende pakker:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Type forespørsel" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Sletting" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Foreldreløs" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Flett med" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Fant %d pakkeforespørsel." msgstr[1] "Fant %d pakkeforespørsler." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Side %d av %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pakke" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Registrert av" -#: template/pkgreq_results.php msgid "Date" msgstr "Dato" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dager igjen" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d time igjen" msgstr[1] "~%d timer igjen" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 time igjen" -#: template/pkgreq_results.php msgid "Accept" msgstr "Godta" -#: template/pkgreq_results.php msgid "Locked" msgstr "Låst" -#: template/pkgreq_results.php msgid "Close" msgstr "Lukk" -#: template/pkgreq_results.php msgid "Closed" msgstr "Lukket" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Navn, beskrivelse" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Bare navn" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Eksakt navn" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Eksakt grunnpakke" -#: template/pkg_search_form.php msgid "All" msgstr "Alle" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Markert" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Umarkert" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Navn" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Stemt" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Stigende" -#: template/pkg_search_form.php msgid "Descending" msgstr "Synkende" -#: template/pkg_search_form.php msgid "Enter search criteria" -msgstr "Fyll ut søkekriterier" +msgstr "Angi søkekriterier" -#: template/pkg_search_form.php msgid "Search by" msgstr "Søk etter" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Foreldet" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sorter etter" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorteringsrekkefølge" -#: template/pkg_search_form.php msgid "Per page" msgstr "Per side" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Utfør" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Foreldreløse" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Feil ved mottagelse av pakkeliste." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ingen pakker passer til dine søkekriterier." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Fant %d pakke." msgstr[1] "Fant %d pakker." -#: template/pkg_search_results.php msgid "Version" msgstr "Versjon" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Ja" -#: template/pkg_search_results.php msgid "orphan" msgstr "foreldreløs" -#: template/pkg_search_results.php msgid "Actions" msgstr "Handlinger" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marker som utdatert" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Fjern markering" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter pakker" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Gjør pakker foreldreløse" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Slett pakker" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Bekreft" -#: template/search_accounts_form.php msgid "Any type" msgstr "Hvilken som helst type" -#: template/search_accounts_form.php msgid "Search" msgstr "Søk" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistikk" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Foreldreløse pakker" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Lagt til de siste 7 dagene" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Oppdaterte pakker de siste 7 dagene" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Oppdaterte pakker det siste året" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Aldri oppdaterte pakker" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrerte brukere" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Betrodde Brukere" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nylige oppdateringer" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Min statistikk" -#: template/tu_details.php msgid "Proposal Details" msgstr "Forslagsdetaljer" -#: template/tu_details.php msgid "This vote is still running." msgstr "Avstemningen pågår fortsatt." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Innsendt: %s av %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Slutt" -#: template/tu_details.php msgid "Result" msgstr "Resultat" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nei" -#: template/tu_details.php msgid "Abstain" msgstr "Blank stemme" -#: template/tu_details.php msgid "Total" msgstr "Totalt" -#: template/tu_details.php msgid "Participation" msgstr "Deltagelse" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Siste stemmer fra TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Siste stemme" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ingen resultater." -#: template/tu_list.php msgid "Start" msgstr "Start" -#: template/tu_list.php msgid "Back" msgstr "Tilbake" diff --git a/po/nl.po b/po/nl.po index 2471e622..80bf1f0f 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Heimen Stoffels , 2015 # jelly , 2011 @@ -12,1799 +12,1479 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" +"Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "De pagina kon niet worden gevonden" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Sorry, de pagina die u heeft aangevraagd bestaat niet." -#: html/503.php msgid "Service Unavailable" msgstr "De dienst is niet beschikbaar" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Raak niet in paniek! De website is uit de lucht wegens werkzaamheden. We zullen snel weer terug in de lucht zijn." +msgstr "" +"Raak niet in paniek! De website is uit de lucht wegens werkzaamheden. We " +"zullen snel weer terug in de lucht zijn." -#: html/account.php msgid "Account" msgstr "Account" -#: html/account.php template/header.php msgid "Accounts" msgstr "Accounts" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "U heeft geen toegang tot dit gebied." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kon geen informatie ophalen voor de opgegeven gebruiker." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "U heeft geen toestemming om dit account te bewerken." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Gebruik dit formulier om bestaande accounts te zoeken." -#: html/account.php msgid "You must log in to view user information." msgstr "U moet inloggen om de gebruikersinformatie te bekijken." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Voorstel toevoegen" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Ongeldige token voor gebruikersactie." -#: html/addvote.php msgid "Username does not exist." msgstr "De gebruikersnaam bestaat niet." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s heeft al een voorstel ervoor lopen." -#: html/addvote.php msgid "Invalid type." msgstr "Ongeldig type." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Het voorstel mag niet leeg worden gelaten." -#: html/addvote.php msgid "New proposal submitted." msgstr "Het nieuwe voorstel is ingediend." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Een voorstel indienen om op te stemmen." -#: html/addvote.php msgid "Applicant/TU" msgstr "Aanvrager/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(laat leeg indien niet van toepassing)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Type" -#: html/addvote.php msgid "Addition of a TU" msgstr "Toevoeging van een TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Verwijdering van een TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Verwijdering van een TU (onverklaarbare inactiviteit)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Wijziging van de statuten" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Voorstel" -#: html/addvote.php msgid "Submit" msgstr "Versturen" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Mede-onderhouders beheren" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Startgedeelte" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Welkom bij de AUR! Lees de %sAUR-gebruikersrichtlijnen%s en de %sAUR-ontwikkelaarsrichtlijnen%s voor meer informatie." +msgstr "" +"Welkom bij de AUR! Lees de %sAUR-gebruikersrichtlijnen%s en de %sAUR-" +"ontwikkelaarsrichtlijnen%s voor meer informatie." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Bijgedragen PKGBUILDs %smoeten%s voldoen aan de %sArch-pakketstandaarden%s, anders zullen ze worden verwijderd!" +msgstr "" +"Bijgedragen PKGBUILDs %smoeten%s voldoen aan de %sArch-pakketstandaarden%s, " +"anders zullen ze worden verwijderd!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Vergeet niet te stemmen op uw favoriete pakketten!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Sommige pakketten kunnen worden geleverd als uitvoerbare bestanden in [community]." +msgstr "" +"Sommige pakketten kunnen worden geleverd als uitvoerbare bestanden in " +"[community]." -#: html/home.php msgid "DISCLAIMER" msgstr "DISCLAIMER" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "Meer leren..." -#: html/home.php msgid "Support" msgstr "Ondersteuning" -#: html/home.php msgid "Package Requests" msgstr "Pakketaanvragen" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Er zijn drie typen aanvragen die kunnen worden ingedeeld in het %sPakketacties%s-veld op de pakketdetails-pagina:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Er zijn drie typen aanvragen die kunnen worden ingedeeld in het " +"%sPakketacties%s-veld op de pakketdetails-pagina:" -#: html/home.php msgid "Orphan Request" msgstr "Weesaanvraag" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Vragen om het pakket te markeren als wees, bijv. wanneer de onderhouder inactief is en het pakket langere tijd als verouderd gemarkeerd is." +msgstr "" +"Vragen om het pakket te markeren als wees, bijv. wanneer de onderhouder " +"inactief is en het pakket langere tijd als verouderd gemarkeerd is." -#: html/home.php msgid "Deletion Request" msgstr "Verwijderaanvraag" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Verzoek om een pakket uit de Arch User Repository te laten verwijderen. Gebruik dit niet als een pakket niet naar behoren functioneert en eenvoudig gerepareerd kan worden. Neem in zo'n geval contact op met de pakketontwikkelaar en open zo nodig een weesverzoek." +msgstr "" +"Verzoek om een pakket uit de Arch User Repository te laten verwijderen. " +"Gebruik dit niet als een pakket niet naar behoren functioneert en eenvoudig " +"gerepareerd kan worden. Neem in zo'n geval contact op met de " +"pakketontwikkelaar en open zo nodig een weesverzoek." -#: html/home.php msgid "Merge Request" msgstr "Aanvraag samenvoegen" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Verzoek om een pakket samen te laten voegen met een ander pakket. Dit kan gebruikt worden als een pakket hernoemd moet worden of vervangen wordt door een opgesplitst pakket." +msgstr "" +"Verzoek om een pakket samen te laten voegen met een ander pakket. Dit kan " +"gebruikt worden als een pakket hernoemd moet worden of vervangen wordt door " +"een opgesplitst pakket." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Indien je het verzoek wilt bediscussiëren, dan kun je de %saur-requests%s maillijst gebruiken. Gebruik deze lijst niet om verzoeken in te dienen." +msgstr "" +"Indien je het verzoek wilt bediscussiëren, dan kun je de %saur-requests%s " +"maillijst gebruiken. Gebruik deze lijst niet om verzoeken in te dienen." -#: html/home.php msgid "Submitting Packages" msgstr "Het bijdragen van pakketten" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Git via SSA is nu in gebruik om pakketten bij te dragen aan de AUR. Zie de %sHet bijdragen van pakketten%s-gedeelte van de Arch User Repository ArchWiki-pagina voor meer details." +msgstr "" +"Git via SSA is nu in gebruik om pakketten bij te dragen aan de AUR. Zie de " +"%sHet bijdragen van pakketten%s-gedeelte van de Arch User Repository " +"ArchWiki-pagina voor meer details." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "De volgende SSH-vingerafdrukken worden gebruikt voor de AUR:" -#: html/home.php msgid "Discussion" msgstr "Discussie" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Algemene discussies met betrekking tot de Arch User Repository (AUR) en de opzet van Trusted Users vinden plaats op %saur-general%s. Voor discussies gerelateerd aan de ontwikkeling van de AUR web interface, gebruik de %saur-dev%s mailinglijst." +msgstr "" +"Algemene discussies met betrekking tot de Arch User Repository (AUR) en de " +"opzet van Trusted Users vinden plaats op %saur-general%s. Voor discussies " +"gerelateerd aan de ontwikkeling van de AUR web interface, gebruik de %saur-" +"dev%s mailinglijst." -#: html/home.php msgid "Bug Reporting" msgstr "Bug-rapportage" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Pakketten zoeken" -#: html/index.php msgid "Adopt" msgstr "Adopteren" -#: html/index.php msgid "Vote" msgstr "Stemmen" -#: html/index.php msgid "UnVote" msgstr "Stem verwijderen" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Informeren" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Niet informeren" -#: html/index.php msgid "UnFlag" msgstr "De-markeren" -#: html/login.php template/header.php msgid "Login" msgstr "Inloggen" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Ingelogd als: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Uitloggen" -#: html/login.php msgid "Enter login credentials" msgstr "Vul uw inloggegevens in" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Wachtwoord" -#: html/login.php msgid "Remember me" msgstr "Onthoud mij" -#: html/login.php msgid "Forgot Password" msgstr "Wachtwoord vergeten" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP-inloggen is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." +msgstr "" +"HTTP-inloggen is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Zoekcriteria" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakketten" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Fout bij het ophalen van pakket details." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Er ontbreekt een verplicht veld." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Wachtwoordvelden komen niet overeen." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Uw wachtwoord moet minimaal %s karakters lang zijn." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Ongeldig e-mailadres." -#: html/passreset.php msgid "Password Reset" msgstr "Wachtwoordherstel" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Controleer uw e-mail voor de bevestigingslink." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Uw wachtwoord is met succes teruggezet." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bevestig uw e-mailadres:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Voer uw nieuwe wachtwoord in:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Bevestig uw nieuwe wachtwoord:" -#: html/passreset.php msgid "Continue" msgstr "Doorgaan" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Als je het e-mail adres waarmee je geregistreerd hebt vergeten bent, stuur dan een bericht naar de %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Als je het e-mail adres waarmee je geregistreerd hebt vergeten bent, stuur " +"dan een bericht naar de %saur-general%s mailing list." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Vul uw e-mail adres in:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "De geselecteerde pakketten zijn niet onteigend, vink het bevestigingsvakje aan." +msgstr "" +"De geselecteerde pakketten zijn niet onteigend, vink het bevestigingsvakje " +"aan." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Kan geen pakket vinden om stemmen en comments mee samen te voegen" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Het basispakket kan niet met zichzelf worden samengevoegd." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "De geselecteerde pakketten zijn niet gewist, vink het bevestigingsvakje aan." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"De geselecteerde pakketten zijn niet gewist, vink het bevestigingsvakje aan." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Pakketverwijdering" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Pakket verwijderen: %s" +msgid "Delete Package" +msgstr "Verwijder Pakket" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Gebruik dit formulier om basispakket %s%s%s te verwijderen van AUR met inbegrip van de volgende pakketten:" +msgstr "" +"Gebruik dit formulier om basispakket %s%s%s te verwijderen van AUR met " +"inbegrip van de volgende pakketten:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Verwijdering van een pakket is permanent." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Vink het veld aan om de actie te bevestigen." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bevestig pakketverwijdering" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Verwijderen" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten verwijderen." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Pakket onteigenen" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Pakket onteigenen: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Gebruik dit formulier om basispakket %s%s%s te onteigenen met inbegrip van de volgende pakketten:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Gebruik dit formulier om basispakket %s%s%s te onteigenen met inbegrip van " +"de volgende pakketten:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen het pakket en het eigendom over te dragen aan %s%s%s." +msgstr "" +"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen het " +"pakket en het eigendom over te dragen aan %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen van het pakket." +msgstr "" +"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen van " +"het pakket." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Bevestig de onteigening van het pakket" -#: html/pkgdisown.php msgid "Disown" msgstr "Onteigenen" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "Alleen Vertouwde Gebruikers en ontwikkelaars kunnen pakketten onteigenen." +msgstr "" +"Alleen Vertouwde Gebruikers en ontwikkelaars kunnen pakketten onteigenen." + +msgid "Flag Comment" +msgstr "" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Commentaar" -#: html/pkgflag.php msgid "Flag" msgstr "Markeren" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakketsamenvoeging" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Pakket samenvoegen: %s" +msgid "Merge Package" +msgstr "Voeg Pakket Samen" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Gebruik dit formulier om basispakkete %s%s%s samen te voegen met een ander pakket." +msgstr "" +"Gebruik dit formulier om basispakkete %s%s%s samen te voegen met een ander " +"pakket." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "De volgende pakketten zullen worden verwijderd:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Als dit pakket samengevoegd is kan dit niet teruggedraaid worden." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Geef de naam van het pakket waarmee dit pakket samengevoegd moet worden." +msgstr "" +"Geef de naam van het pakket waarmee dit pakket samengevoegd moet worden." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Samenvoegen naar:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Samenvoeging bevestigen" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Samenvoegen" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten samen voegen." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Aanvraag indienen" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Aanvraag sluiten" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Eerste" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Vorige" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Volgende" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Laatste" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Aanvragen" -#: html/register.php template/header.php msgid "Register" msgstr "Registreren" -#: html/register.php msgid "Use this form to create an account." msgstr "Gebruik dit formulier om een ​​account aan te maken." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Voorsteldetails kunnen niet opgehaald worden." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Stemmen is gesloten voor dit voorstel." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Alleen Trusted Users kunnen stemmen." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "U kunt niet stemmen op een voorstel over u." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "U heeft al gestemd op dit voorstel." -#: html/tu.php msgid "Vote ID not valid." msgstr "Uw stem-ID is ongeldig." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Huidig aantal stemmen" -#: html/tu.php msgid "Past Votes" msgstr "Eerdere stemmen" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Stemmers" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Registratie is uitgeschakeld voor jouw IP adres, waarschijnlijk vanwege langdurige spam aanvallen. Excuses voor het ongemak." +msgstr "" +"Registratie is uitgeschakeld voor jouw IP adres, waarschijnlijk vanwege " +"langdurige spam aanvallen. Excuses voor het ongemak." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Gebruikers-ID ontbreekt" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "De gebruikersnaam is ongeldig." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Het moet tussen de %s en %s karakters lang zijn" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Beginnen en eindigen met een letter of nummer" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan maar één punt, komma of koppelteken bevatten." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Het e-mailadres is ongeldig." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "De vingerafdruk van de PGP sleutel is ongeldig." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "De publieke SSH-sleutel is ongeldig." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Kan de account permissies niet verhogen." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Taal wordt momenteel niet ondersteund." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "De gebruikersnaam %s%s%s is al in gebruik." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Het adres %s%s%s is al in gebruik." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "De SSH publieke sleutel, %s%s%s, is al ingebruik." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Fout bij het aanmaken van account %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Het account %s%s%s is met succes aangemaakt." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "Een sleutel voor het resetten van je wachtwoord is verstuurd naar je e-mail adres." +msgstr "" +"Een sleutel voor het resetten van je wachtwoord is verstuurd naar je e-mail " +"adres." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klik op de Login link hierboven om je account te gebruiken" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Geen veranderingen zijn gemaakt aan het account, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Het account %s%s%s is met succes aangepast." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Het log-in formulier is uitgeschakeld voor je IP adres, waarschijnlijk vanwege langdurige spam-aanvallen. Excuses voor het ongemak." +msgstr "" +"Het log-in formulier is uitgeschakeld voor je IP adres, waarschijnlijk " +"vanwege langdurige spam-aanvallen. Excuses voor het ongemak." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Account is geschorst" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Je wachtwoord is gereset. Als je net een nieuwe account hebt aangemaakt, gebruik dan de link uit de bevestigingsmail om een wachtwoord te genereren. In andere gevallen, vraag een herstelsleutel aan op de %sPassword Reset%s pagina." +msgstr "" +"Je wachtwoord is gereset. Als je net een nieuwe account hebt aangemaakt, " +"gebruik dan de link uit de bevestigingsmail om een wachtwoord te genereren. " +"In andere gevallen, vraag een herstelsleutel aan op de %sPassword Reset%s " +"pagina." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Verkeerd gebruiker of wachtwoord" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Er is een fout opgetreden bij het aanmaken van een gebruikerssessie." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ongeldige e-mail en reset-toets combinatie." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Geen" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Toon accountinformatie voor %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Opmerking is toegevoegd." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Je moet ingelogd zijn voordat je pakketinformatie kunt bewerken." + +msgid "Missing comment ID." +msgstr "Missende comment ID." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Fout bij het ophalen van pakketdetails." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Pakketdetails kunnen niet gevonden worden." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt markeren." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Je hebt geen pakketten geselecteerd om te markeren." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "De geselecteerde pakketten zijn gemarkeerd als verouderd." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "Je moet ingelogd zijn voordat je een markering voor een pakket kunt verwijderen." +msgstr "" +"Je moet ingelogd zijn voordat je een markering voor een pakket kunt " +"verwijderen." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." -msgstr "Je hebt geen pakketten geselecteerd om de markering van te verwijderen." +msgstr "" +"Je hebt geen pakketten geselecteerd om de markering van te verwijderen." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De markering voor de geselecteerde pakketten is verwijderd." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Je hebt geen toestemming om pakketten te verwijderen." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Je hebt geen pakketten geselecteerd om te verwijderen." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De geselecteerde pakketten zijn verwijderd." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt adopteren." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt onteigenen." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Je hebt geen pakketten geselecteerd om te adopteren." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Je hebt geen pakketten geselecteerd om te onteigenen." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "De geselecteerde pakketten zijn geadopteerd." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De geselecteerde pakketten zijn onteigend." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Je moet ingelogd zijn voordat je kunt stemmen op pakketten." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Je moet ingelogd zijn voordat je je stem kunt verwijderen." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Je hebt geen pakketten geselecteerd om op te stemmen." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Je stem is verwijderd voor de geselecteerde pakketten." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Je hebt gestemd voor de geselecteerde pakketten." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kon niet toevoegen aan notificatielijst." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Je bent toegevoegd aan de comment notificatielijst voor %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Je bent verwijderd van de comment notificatielijst voor %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Je moet ingelogd zijn voordat je pakketinformatie kunt bewerken." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Missende comment ID." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Comment is verwijderd." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Je hebt geen toestemming deze comment te verwijderen." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Comment is verwijderd." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "Je hebt geen toestemming de sleutelwoorden van dit basispakket aan te passen." +msgstr "" +"Je hebt geen toestemming de sleutelwoorden van dit basispakket aan te passen." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "De sleutelwoorden van het basispakket zijn bijgewerkt." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Je hebt geen toestemming om de mede-eigenaren van dit basispakket aan te passen." +msgstr "" +"Je hebt geen toestemming om de mede-eigenaren van dit basispakket aan te " +"passen." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ongeldige gebruikersnaam: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "De mede-onderhouders van het basispakket zijn bijgewerkt." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Toon pakketdetails voor" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Je moet ingelogd zijn voordat je pekketverzoeken kunt indienen." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ongeldige naam: alleen kleine letters zijn toegestaan." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Het commentaarveld mag niet leeg zijn." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ongeldig verzoektype." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Verzoek succesvol toegevoegd." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ongeldige reden." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Alleen TUs en ontwikkelaars mogen verzoeken sluiten." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Verzoek succesvol gesloten." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Gebruik dit formulier om permanent AUR account %s te verwijderen." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWAARSCHUWING%s: Deze actie kan niet ongedaan worden gemaakt." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Bevestig verwijdering" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Gebruikersnaam" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Account Type" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Gebruiker" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Ontwikkelaar" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & Ontwikkelaar" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail adres" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Echte naam" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Nick" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP sleutel vingerafdruk" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Geen activiteit sinds" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actief" -#: template/account_details.php msgid "Last Login" msgstr "Laatste Login" -#: template/account_details.php msgid "Never" msgstr "Nooit" -#: template/account_details.php msgid "View this user's packages" msgstr "Bekijk gebruiker zijn pakketten" -#: template/account_details.php msgid "Edit this user's account" msgstr "Bewerk account van deze gebruiker" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klik %shier%s als u dit account permanent wilt verwijderen." -#: template/account_edit_form.php msgid "required" msgstr "verplicht" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normale gebruiker" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Account Geschorst" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inactief" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Voer wachtwoord opnieuw in" -#: template/account_edit_form.php msgid "Language" msgstr "Taal" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "De volgende informatie is alleen verplicht als u pakketten aan de Arch User Repository wilt toevoegen." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"De volgende informatie is alleen verplicht als u pakketten aan de Arch User " +"Repository wilt toevoegen." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH Publieke Sleutel" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Update" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Aanmaken" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Reset" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Geen resultaten die voldoen aan je zoekcriteria." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Bewerk account" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Geschorst" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Bewerken" - -#: template/account_search_results.php -msgid "Less" -msgstr "Minder" - -#: template/account_search_results.php -msgid "More" -msgstr "Meer" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Geen andere resultaten gevonden " - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Beheer mede-onderhouders: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Gebruik dit formulier om mede-onderhouders voor %s%s%s toe te voegen (een gebruikersnaam per regel):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Gebruikers" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Bewaren" - -#: template/header.php -msgid "My Packages" -msgstr "Mijn pakketten" - -#: template/header.php -msgid " My Account" -msgstr "Mijn Account" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Pakket Acties" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Toon PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Bekijk Wijzigingen" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Download momentopname" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Doorzoek wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Markeer als verouderd" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Markeer pakket als verouderd" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Verwijder markering" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Verwijder stem" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Stem voor dit pakket" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Schakel notificaties uit" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificatie bij nieuwe comment" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Update" + +msgid "Create" +msgstr "Aanmaken" + +msgid "Reset" +msgstr "Reset" + +msgid "No results matched your search criteria." +msgstr "Geen resultaten die voldoen aan je zoekcriteria." + +msgid "Edit Account" +msgstr "Bewerk account" + +msgid "Suspended" +msgstr "Geschorst" + +msgid "Edit" +msgstr "Bewerken" + +msgid "Less" +msgstr "Minder" + +msgid "More" +msgstr "Meer" + +msgid "No more results to display." +msgstr "Geen andere resultaten gevonden " + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Gebruik dit formulier om mede-onderhouders voor %s%s%s toe te voegen (een " +"gebruikersnaam per regel):" + +msgid "Users" +msgstr "Gebruikers" + +msgid "Save" +msgstr "Bewaren" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + +msgid "My Packages" +msgstr "Mijn pakketten" + +msgid " My Account" +msgstr "Mijn Account" + +msgid "Package Actions" +msgstr "Pakket Acties" + +msgid "View PKGBUILD" +msgstr "Toon PKGBUILD" + +msgid "View Changes" +msgstr "Bekijk Wijzigingen" + +msgid "Download snapshot" +msgstr "Download momentopname" + +msgid "Search wiki" +msgstr "Doorzoek wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Markeer pakket als verouderd" + +msgid "Unflag package" +msgstr "Verwijder markering" + +msgid "Remove vote" +msgstr "Verwijder stem" + +msgid "Vote for this package" +msgstr "Stem voor dit pakket" + +msgid "Disable notifications" +msgstr "Schakel notificaties uit" + msgid "Manage Co-Maintainers" msgstr "Beheer mede-onderhouders" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d verzoek in wachtrij" msgstr[1] "%d verzoeken in wachtrij" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Verwijder Pakket" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Voeg Pakket Samen" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopteer Pakket" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "onbekend" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Details van Basispakket" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Sleutelwoorden" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Inzender" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Beheerder" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Laatste Packager" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmen" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Populariteit" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Toegevoegd" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Laatste Update" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Voeg Comment Toe" -#: template/pkg_comments.php msgid "View all comments" msgstr "Bekijk alle commentaar" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Nieuwste Comments" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Verwijder opmerking" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Alle comments" -#: template/pkg_details.php msgid "Package Details" msgstr "Pakketdetails" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Basispakket" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Omschrijving" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Bezoek de website voor" -#: template/pkg_details.php msgid "Licenses" msgstr "Licenties" -#: template/pkg_details.php msgid "Groups" msgstr "Groepen" -#: template/pkg_details.php msgid "Conflicts" msgstr "Conflicten" -#: template/pkg_details.php msgid "Provides" msgstr "Voorziet in" -#: template/pkg_details.php msgid "Replaces" msgstr "Vervangt" -#: template/pkg_details.php msgid "Dependencies" msgstr "Afhankelijkheden" -#: template/pkg_details.php msgid "Required by" msgstr "Vereist door" -#: template/pkg_details.php msgid "Sources" msgstr "Bronnen" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Sluit Verzoek: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." +msgstr "" +"Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Notitie" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Het commentaarveld mag leeg blijven. Echter, het wordt sterk aanbevolen om een afwijzing van commentaar te voorzien." +msgstr "" +"Het commentaarveld mag leeg blijven. Echter, het wordt sterk aanbevolen om " +"een afwijzing van commentaar te voorzien." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Reden" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Geaccepteerd" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Afgewezen" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Nieuw Verzoek: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Gebruik dit formulier om een verzoek in te dienen voor basispakket %s%s%s welke de volgende pakketten omvat:" +msgstr "" +"Gebruik dit formulier om een verzoek in te dienen voor basispakket %s%s%s " +"welke de volgende pakketten omvat:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Verzoektype" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Verwijdering" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Wees" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Voeg samen met" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d pakketverzoek gevonden" msgstr[1] "%d pakketverzoeken gevonden" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d van %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pakket" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Ingediend door" -#: template/pkgreq_results.php msgid "Date" msgstr "Datum" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dagen resterend" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d uur resterend" msgstr[1] "~%d uur resterend" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 uur resterend" -#: template/pkgreq_results.php msgid "Accept" msgstr "Accepteer" -#: template/pkgreq_results.php msgid "Locked" msgstr "Vergrendeld" -#: template/pkgreq_results.php msgid "Close" msgstr "Sluit" -#: template/pkgreq_results.php msgid "Closed" msgstr "Gesloten" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Naam, omschrijving" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Alleen de naam" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Exacte Naam" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Exact Basispakket" -#: template/pkg_search_form.php msgid "All" msgstr "Alle" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Gemarkeerd" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Ongemarkeerd" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Naam" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Gestemd" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Oplopend" -#: template/pkg_search_form.php msgid "Descending" msgstr "Aflopend" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Voer zoekcriteria in" -#: template/pkg_search_form.php msgid "Search by" msgstr "Zoek op" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Verouderd" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sorteer Op" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorteervolgorde" -#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagina" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ga" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Wezen" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fout bij het ophalen van pakkettenlijst" -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Geen pakketen gevonden die aan uw zoekcriteria voldoen" -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pakket gevonden" msgstr[1] "%d pakketten gevonden" -#: template/pkg_search_results.php msgid "Version" msgstr "Versie" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Ja" -#: template/pkg_search_results.php msgid "orphan" msgstr "wees" -#: template/pkg_search_results.php msgid "Actions" msgstr "Acties" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Markeer Verouderd" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Hef Out-of-Date markering op" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopteer Pakketten" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Onteigen Pakketten" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Verwijder pakketten" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Bevestig" -#: template/search_accounts_form.php msgid "Any type" msgstr "Elk type" -#: template/search_accounts_form.php msgid "Search" msgstr "Zoek" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistieken" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Weespakketten" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakketten toegevoegd in de laatste 7 dagen" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakketten geüpdatet in de laatste 7 dagen" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakketen geüpdatet in het laatste jaar" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nooit geüpdate pakketten" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Geregistreerde Gebruikers" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Recente updates" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Mijn statistieken" -#: template/tu_details.php msgid "Proposal Details" msgstr "Voorsteldetails" -#: template/tu_details.php msgid "This vote is still running." msgstr "Dit voorstel is nog bezig" -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Opgestuurd: %s door %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Einde" -#: template/tu_details.php msgid "Result" msgstr "Resultaat" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nee" -#: template/tu_details.php msgid "Abstain" msgstr "Onthouden" -#: template/tu_details.php msgid "Total" msgstr "Totaal" -#: template/tu_details.php msgid "Participation" msgstr "Participatie" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Laatste stemmen door TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Laatste stem" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Geen resultaten gevonden." -#: template/tu_list.php msgid "Start" msgstr "Start " -#: template/tu_list.php msgid "Back" msgstr "Terug" diff --git a/po/pl.po b/po/pl.po index 342d05c1..a444aa5a 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Bartłomiej Piotrowski , 2011 # Bartłomiej Piotrowski , 2014 @@ -10,1273 +10,1037 @@ # Kwpolska , 2011 # Lukas Fleischer , 2011 # Nuc1eoN , 2014 -# Piotr Strębski , 2013-2015 +# Piotr Strębski , 2013-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/pl/)\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-13 13:13+0000\n" +"Last-Translator: Piotr Strębski \n" +"Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" +"pl/)\n" +"Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pl\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" -#: html/404.php msgid "Page Not Found" msgstr "Nie znaleziono strony" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Przepraszamy, strona o którą prosiłeś nie istnieje." -#: html/503.php msgid "Service Unavailable" msgstr "Usługa niedostępna" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Nie panikuj! W związku z przeprowadzanymi pracami technicznymi strona jest chwilowo niedostępna. Już wkrótce wrócimy." +msgstr "" +"Nie panikuj! W związku z przeprowadzanymi pracami technicznymi strona jest " +"chwilowo niedostępna. Już wkrótce wrócimy." -#: html/account.php msgid "Account" msgstr "Konto" -#: html/account.php template/header.php msgid "Accounts" msgstr "Konta" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nie masz uprawnień do oglądania tej strony." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Uzyskanie informacji o podanym użytkowniku nie powiodło się." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nie masz uprawnień do edycji tego konta." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Przy użyciu tego formularza możesz przeszukać istniejące konta." -#: html/account.php msgid "You must log in to view user information." msgstr "Musisz być zalogowany aby móc oglądać informacje o użytkownikach." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Dodaj Propozycję" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Nieprawidłowy token dla akcji użytkownika." -#: html/addvote.php msgid "Username does not exist." msgstr "Nazwa użytkownika nie istnieje." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ma już propozycję dla nich." -#: html/addvote.php msgid "Invalid type." msgstr "Nieprawidłowy rodzaj." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Propozycja nie może być pusta." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nowa propozycja wysłana." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Wyślij propozycję do głosowania." -#: html/addvote.php msgid "Applicant/TU" msgstr "Wnioskodawca/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(puste jeśli nie dotyczy)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Rodzaj" -#: html/addvote.php msgid "Addition of a TU" msgstr "Dodanie ZU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Usunięcie ZU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Usunięcie ZU (niezadeklarowana nieaktywność)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Zmiana Regulaminu" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propozycja" -#: html/addvote.php msgid "Submit" msgstr "Wyślij" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Zarządzanie współutrzymującymi" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Edytuj komentarz" -#: html/home.php template/header.php msgid "Home" msgstr "Start" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Witamy w AUR! Aby uzyskać więcej informacji, przeczytaj %sInstrukcję Użytkownika AUR%s oraz %sInstrukcję Zaufanego Użytkownika%s." +msgstr "" +"Witamy w AUR! Aby uzyskać więcej informacji, przeczytaj %sInstrukcję " +"Użytkownika AUR%s oraz %sInstrukcję Zaufanego Użytkownika%s." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Pliki PKGBUILD %smuszą%s być zgodne ze %sStandardami Pakietów Archa%s, inaczej będą usuwane!" +msgstr "" +"Pliki PKGBUILD %smuszą%s być zgodne ze %sStandardami Pakietów Archa%s, " +"inaczej będą usuwane!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nie zapomnij zagłosować na swoje ulubione pakiety!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Część pakietów może być dostępna w formie binarnej w [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "ZRZECZENIE" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "Dowiedz się więcej..." -#: html/home.php msgid "Support" msgstr "Wsparcie" -#: html/home.php msgid "Package Requests" -msgstr "Prośby o pakiet" +msgstr "Propozycje pakietu" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" -msgstr "Prośba o usunięcie" +msgstr "Propozycja usunięcia" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" -msgstr "Prośba o połączenie" +msgstr "Propozycja połączenia" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "Przesyłanie pakietów" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Dyskusja" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Zgłaszanie błędów" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Wyszukiwanie pakietów" -#: html/index.php msgid "Adopt" msgstr "Przejmij" -#: html/index.php msgid "Vote" msgstr "Głosuj" -#: html/index.php msgid "UnVote" msgstr "Cofnij głos" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Włącz powiadamianie" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Rezygnuj z powiadamiania" -#: html/index.php msgid "UnFlag" msgstr "Odznacz" -#: html/login.php template/header.php msgid "Login" msgstr "Zaloguj się" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Zalogowany jako: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Wyloguj się" -#: html/login.php msgid "Enter login credentials" msgstr "Podaj poświadczenia logowania" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Nazwa użytkownika lub adres e-mail" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Hasło" -#: html/login.php msgid "Remember me" msgstr "Zapamiętaj mnie" -#: html/login.php msgid "Forgot Password" msgstr "Zapomniałem hasła" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Logowanie w HTTP jest wyłączone. %sPrzełącz się na HTTPs%s aby się zalogować." +msgstr "" +"Logowanie w HTTP jest wyłączone. %sPrzełącz się na HTTPs%s aby się " +"zalogować." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kryteria wyszukiwania" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakiety" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Błąd podczas pobierania informacji o pakiecie." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Brakuje wymaganego pola." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Hasła nie zgadzają się." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Twoje hasło musi mieć składać się z conajmniej %s znaków." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Nieprawidłowy e-mail." -#: html/passreset.php msgid "Password Reset" msgstr "Resetowanie hasła" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "Na Twój adres został wysłany e-mail z instrukcją dotyczącą resetowania hasła." +msgstr "" +"Na Twój adres został wysłany e-mail z instrukcją dotyczącą resetowania hasła." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Twoje hasło zostało pomyślnie zresetowane." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potwierdź swój adres e-mail:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Wpisz nowe hasło:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Wpisz ponownie hasło:" -#: html/passreset.php msgid "Continue" msgstr "Kontynuuj" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Jeśli zapomniałeś adresu e-mail, którego użyłeś do rejestracji, prosimy o wysłanie wiadomości na naszą listę dyskusyjną %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Jeśli zapomniałeś adresu e-mail, którego użyłeś do rejestracji, prosimy o " +"wysłanie wiadomości na naszą listę dyskusyjną %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Wpisz swój adres e-mail:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Nie można znaleźć pakietu do scalenia głosów i komentarzy." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nie można połączyć bazowego pakietu z nim samym." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Wybrane pakiety nie zostały usunięte, sprawdź pole wyboru potwierdzenia." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Wybrane pakiety nie zostały usunięte, sprawdź pole wyboru potwierdzenia." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Usuwanie pakietów" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Usuń pakiet: %s" +msgid "Delete Package" +msgstr "Usuń pakiet" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Użyj tego formularza, aby usunąć bazę pakietu %s%s%s i następujące pakiety z AUR:" +msgstr "" +"Użyj tego formularza, aby usunąć bazę pakietu %s%s%s i następujące pakiety z " +"AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Usunięcie pakietu jest nieodwracalne." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaznacz pole aby potwierdzić akcję." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potwierdź usunięcie pakietu" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Usuń" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą usuwać pakiety." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Porzuć pakiet" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "Porzuć" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "Oznacz komentarz" + msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Oznacz pakiet jako nieaktualny" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentarze" -#: html/pkgflag.php msgid "Flag" msgstr "Oznacz" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Scalanie pakietów" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Scal pakiet: %s" +msgid "Merge Package" +msgstr "Scal pakiet" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Użyj tego formularza, aby scalić bazę pakietu %s%s%s w inny pakiet." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Następujące pakiety zostaną usunięte:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "Gdy pakiet zostanie scalony to nie będzie możliwości odwrócenia tej czynności." +msgstr "" +"Gdy pakiet zostanie scalony to nie będzie możliwości odwrócenia tej " +"czynności." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Podaj nazwę pakietu, pod którą chcesz dokonać scalenia pakietu." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Scal z:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potwierdź scalenie pakietu" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Scal" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą scalać pakiety." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Złóż propozycję" +msgid "Submit Request" +msgstr "Prześlij propozycję" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zamknij propozycję" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Pierwsza" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Poprzednia" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Następna" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ostatnia" -#: html/pkgreq.php template/header.php msgid "Requests" -msgstr "Propozcje" +msgstr "Propozycje" -#: html/register.php template/header.php msgid "Register" msgstr "Zarejestruj się" -#: html/register.php msgid "Use this form to create an account." msgstr "Przy użyciu tego formularza możesz utworzyć konto." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Zaufany Użytkownik" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nie można odczytać szczegółów propozycji." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Głosowanie na tą propozycję jest zamknięte." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Tylko Zaufani Użytkownicy mogą głosować." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nie możesz głosować w propozycji o tobie." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Już zagłosowałeś na tą propozycję" -#: html/tu.php msgid "Vote ID not valid." msgstr "ID głosowania nieprawidłowe." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Obecne Głosy" -#: html/tu.php msgid "Past Votes" msgstr "Poprzednie Głosy" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Głosujących" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Rejestracja konta została wyłączona dla Twojego adresu IP, najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. Przepraszamy za niedogodności." +msgstr "" +"Rejestracja konta została wyłączona dla Twojego adresu IP, " +"najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. " +"Przepraszamy za niedogodności." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Brakujące ID użytkownika." -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Nazwa użytkownika jest nieprawidłowa." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Długość musi być pomiędzy %s a %s" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Zacznij i zakończ literą lub cyfrą" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Może zawierać tylko jedną kropkę, podkreślnik lub myślnik." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adres e-mail jest nieprawidłowy." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Odcisk palca klucza PGP jest nieprawidłowy." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Klucz publiczny SSH jest nieprawidłowy." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nie można zwiększyć uprawnień konta." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Język nie jest obecnie obsługiwany." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Nazwa użytkownika, %s%s%s, jest już używana." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adres, %s%s%s, jest już używany." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Wystąpił błąd podczas tworzenia konta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Konto %s%s%s zostało pomyślnie utworzone." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Klucz resetujący hasło został przesłany na Twój adres e-mail." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Kliknij na link Zaloguj się powyżej aby się zalogować." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nie zostały dokonane żadne zmiany na koncie, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Konto %s%s%s zostało pomyślnie zaktualizowane." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Formularz logowania jest obecnie wyłączony dla Twojego adresu IP, najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. Przepraszamy za niedogodności." +msgstr "" +"Formularz logowania jest obecnie wyłączony dla Twojego adresu IP, " +"najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. " +"Przepraszamy za niedogodności." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto zawieszone" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Twoje hasło zostało zresetowane. Jeśli dopiero co utworzyłeś nowe konto, prosimy o użycie odnośnika z e-maila potwierdzającego rejestrację, aby ustawić hasło początkowe. W innym przypadku, prosimy o wnioskowanie o klucz resetujący na stronie %sresetowania hasła%s." +msgstr "" +"Twoje hasło zostało zresetowane. Jeśli dopiero co utworzyłeś nowe konto, " +"prosimy o użycie odnośnika z e-maila potwierdzającego rejestrację, aby " +"ustawić hasło początkowe. W innym przypadku, prosimy o wnioskowanie o klucz " +"resetujący na stronie %sresetowania hasła%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nieprawidłowa nazwa użytkownika lub hasło." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Wystąpił błąd przy próbie utworzenia sesji użytkownika." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Nieprawidłowy e-mail i klucz do resetowania." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Żaden" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Wyświetl informacje o koncie %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentarz został dodany." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Musisz być zalogowany aby móc edytować informacje o pakiecie." + +msgid "Missing comment ID." +msgstr "Brakuje identyfikatora komentarza." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Błąd podczas pobierania informacji o pakiecie." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nie odnaleziono informacji o pakiecie." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Musisz być zalogowany aby móc oznaczyć pakiety." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nie wybrałeś żadnych pakietów do oznaczenia." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Wybrane pakiety zostały oznaczone jako nieaktualne." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musisz być zalogowany aby móc odznaczyć pakiety." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nie wybrałeś żadnych pakietów do odznaczenia." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Wybrane pakiety zostały odznaczone." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nie masz uprawnień do usuwania pakietów." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nie wybrałeś żadnych pakietów do usunięcia." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Wybrane pakiety zostały usunięte." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musisz być zalogowany aby móc przejmować pakiety." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musisz być zalogowany aby móc porzucać pakiety." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nie wybrałeś żadnych pakietów do przejęcia." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nie wybrałeś żadnych pakietów do porzucenia." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Wybrane pakiety zostały przejęte." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Wybrane pakiety zostały porzucone." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Musisz być zalogowany aby móc głosować na pakiety." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musisz być zalogowany aby móc anulować głosy na pakiety." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nie wybrałeś żadnych pakietów do zagłosowania." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Twoje głosy zostały odebrane wybranym pakietom." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Twoje głosy zostały przyznane wybranym pakietom." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Dodanie do listy powiadamiania nie powiodło się." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Zostałeś dodany do listy powiadamiania o nowych komentarzach dla %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Zostałeś usunięty z listy powiadamiania o komentarzach dla %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Musisz być zalogowany aby móc edytować informacje o pakiecie." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Brakuje identyfikatora komentarza." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Komentarz został usunięty." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nie masz uprawnień do usunięcia tego komentarza." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Komentarz został usunięty." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Niepoprawna nazwa użytkownika: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Wyświetl informacje o pakiecie" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." -msgstr "" +msgstr "Musisz być zalogowanym, aby złożyć propozycje pakietu." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nieprawidłowa nazwa: tylko małe litery są dozwolone." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Pole komentarzy nie może pozostać pustę." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Nieprawidłowy rodzaj propozycji." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Pomyślnie dodano propozycję." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Nieprawidłowy powód." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą zamykać propozycje." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Pomyślnie zamknięto propozycję." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Możesz użyć tego formularza, aby nieodwracalnie usunąć konto %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUWAGA%s: Ta czynność nie może zostać cofnięta." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Potwierdź usunięcie" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Użytkownik" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Rodzaj konta" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Użytkownik" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Deweloper" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Zaufany Użytkownik i Developer" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Adres e-mail" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Imię i nazwisko" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick na IRC-u" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Odcisk palca klucza PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Stan" -#: template/account_details.php msgid "Inactive since" msgstr "Nieaktywny od" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktywne" -#: template/account_details.php msgid "Last Login" msgstr "Ostatnie logowanie" -#: template/account_details.php msgid "Never" msgstr "Nigdy" -#: template/account_details.php msgid "View this user's packages" msgstr "Wyświetl pakiety tego użytkownika" -#: template/account_details.php msgid "Edit this user's account" msgstr "Edycja tego konta użytkownika" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknij %stutaj%s jeśli chcesz nieodwracalnie usunąć to konto." -#: template/account_edit_form.php msgid "required" msgstr "wymagane" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Zwykły użytkownik" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Zaufany Użytkownik" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto zablokowane" -#: template/account_edit_form.php msgid "Inactive" msgstr "Nieaktywny" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Hasło (ponownie)" -#: template/account_edit_form.php msgid "Language" msgstr "Język" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Klucz publiczny SSH" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Powiadom o nowych komentarzach" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Aktualizuj" -#: template/account_edit_form.php msgid "Create" msgstr "Utwórz" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Wyczyść" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Wyszukiwanie nie przyniosło rezultatu." -#: template/account_search_results.php msgid "Edit Account" msgstr "Edytuj konto" -#: template/account_search_results.php msgid "Suspended" msgstr "Zablokowane" -#: template/account_search_results.php msgid "Edit" msgstr "Edytuj" -#: template/account_search_results.php msgid "Less" msgstr "Poprzednie" -#: template/account_search_results.php msgid "More" msgstr "Następne" -#: template/account_search_results.php msgid "No more results to display." msgstr "Brak wyników do wyświetlenia." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "Użytkownicy" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Zapisz" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Moje pakiety" -#: template/header.php msgid " My Account" msgstr "Moje konto" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Działania na pakietach" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Pokaż PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "Zobacz zmiany" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Przeszukaj wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Oznaczony jako nieaktualny" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Oznacz pakiet jako nieaktualny" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Odznacz pakiet" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Usuń głos" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Zagłosuj na ten pakiet" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Wyłącz powiadomienia" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Powiadom o nowych komentarzach" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1284,232 +1048,180 @@ msgstr[0] "%d propozycja w toku" msgstr[1] "%d propozycje w toku" msgstr[2] "%d propozycji w toku" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Usuń pakiet" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Scal pakiet" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Przejmij pakiet" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "nieznana" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Szczegóły bazy pakietu" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Słowa kluczowe" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Nadesłał" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Opiekun" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ostatni pakujący" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Głosy" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularność" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Wysłany" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ostatnia aktualizacja" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Dodaj komentarz" -#: template/pkg_comments.php msgid "View all comments" msgstr "Pokaż wszystkie komentarze" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Ostatnie komentarze" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Usuń komentarz" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Wszystkie komentarze" -#: template/pkg_details.php msgid "Package Details" msgstr "Informacje o pakiecie" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Baza pakietu" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" -#: template/pkg_details.php msgid "Upstream URL" msgstr "URL upstreamu" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Odwiedź stronę pakietu" -#: template/pkg_details.php msgid "Licenses" msgstr "Licencje" -#: template/pkg_details.php msgid "Groups" msgstr "Grupy" -#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikty" -#: template/pkg_details.php msgid "Provides" msgstr "Zapewnia" -#: template/pkg_details.php msgid "Replaces" msgstr "Zastępuje" -#: template/pkg_details.php msgid "Dependencies" msgstr "Zależności" -#: template/pkg_details.php msgid "Required by" msgstr "Wymagane przez" -#: template/pkg_details.php msgid "Sources" msgstr "Źródła" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "Uwaga" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Powód" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Zaakceptowany" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Odrzucony" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Propozycja Pliku: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Użyj tego formularza, aby złożyć propozycję na bazę pakietu %s%s%s i następujące pakiety:" +msgstr "" +"Użyj tego formularza, aby złożyć propozycję na bazę pakietu %s%s%s i " +"następujące pakiety:" -#: template/pkgreq_form.php msgid "Request type" -msgstr "Rodzaj Propozycji" +msgstr "Rodzaj propozycji" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Usunięcie" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Bez opiekuna" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Scal z" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1517,29 +1229,23 @@ msgstr[0] "%d propozycje znaleziono" msgstr[1] "%d propozycje znaleziono." msgstr[2] "%d propozycji znaleziono." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Strona %d z %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pakiet" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Złożone przez" -#: template/pkgreq_results.php msgid "Date" msgstr "Data" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "pozostało ~%d dni" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1547,116 +1253,87 @@ msgstr[0] "pozostała ~%d godzina" msgstr[1] "pozostały ~%d godziny" msgstr[2] "pozostało ~%d godzin" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "pozostała <1 godzina" -#: template/pkgreq_results.php msgid "Accept" msgstr "Akceptuj" -#: template/pkgreq_results.php msgid "Locked" msgstr "Zablokowane" -#: template/pkgreq_results.php msgid "Close" msgstr "Zamknij" -#: template/pkgreq_results.php msgid "Closed" msgstr "Zamknięte" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nazwa, Opis" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Tylko nazwa" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Dokładna nazwa" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Dokładna baza pakietu" -#: template/pkg_search_form.php msgid "All" msgstr "Wszystkie" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Oznaczony" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nieoznaczony" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nazwa" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Głos" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Rosnąco" -#: template/pkg_search_form.php msgid "Descending" msgstr "Malejąco" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Podaj kryteria wyszukiwania" -#: template/pkg_search_form.php msgid "Search by" msgstr "Szukaj według" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Nieaktualny" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortuj według" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Porządek" -#: template/pkg_search_form.php msgid "Per page" msgstr "Na stronie" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Wykonaj" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Bez opiekuna" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Błąd podczas pobierania listy pakietów." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Żaden pakiet nie spełnia podanych kryteriów." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1664,154 +1341,116 @@ msgstr[0] "%d pakiet znaleziono" msgstr[1] "%d pakiety znaleziono" msgstr[2] "%d pakietów znaleziono" -#: template/pkg_search_results.php msgid "Version" msgstr "Wersja" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Tak" -#: template/pkg_search_results.php msgid "orphan" msgstr "bez opiekuna" -#: template/pkg_search_results.php msgid "Actions" msgstr "Działania" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Oznacz jako nieaktualny" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Usuń flagę nieaktualności" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Przejmij pakiety" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Porzuć pakiety" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Usuń pakiety" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Potwierdź" -#: template/search_accounts_form.php msgid "Any type" msgstr "Dowolny rodzaj" -#: template/search_accounts_form.php msgid "Search" msgstr "Szukaj" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statystyki" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Osierocone" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Dodane przez ostatnie 7 dni" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Zaktualizowane przez ostatnie 7 dni" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Zaktualizowane przez ostatni rok" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nigdy nieaktualizowane" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Zarejestrowani użytkownicy" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Zaufani Użytkownicy" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Ostatnie aktualizacje" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Moje statystyki" -#: template/tu_details.php msgid "Proposal Details" msgstr "Szczegóły propozycji" -#: template/tu_details.php msgid "This vote is still running." msgstr "Głosowanie ciągle trwa." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Wysłane: %s przez %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Koniec" -#: template/tu_details.php msgid "Result" msgstr "Wynik" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nie" -#: template/tu_details.php msgid "Abstain" msgstr "Wstrzymaj się od głosu" -#: template/tu_details.php msgid "Total" msgstr "Suma" -#: template/tu_details.php msgid "Participation" msgstr "Uczestnictwo" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ostatnie głosy ZU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ostatni głos" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Brak wyników." -#: template/tu_list.php msgid "Start" msgstr "Początek" -#: template/tu_list.php msgid "Back" msgstr "Wstecz" diff --git a/po/pt_BR.po b/po/pt_BR.po index d0c7e044..b5fec0d8 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1,1810 +1,1506 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Albino Biasutti Neto Bino , 2011 # Rafael Fontenelle , 2012-2015 -# Rafael Fontenelle , 2015 +# Rafael Fontenelle , 2011,2015 # Rafael Fontenelle , 2011 # Sandro , 2011 +# Sandro , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 10:30+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 21:44+0000\n" "Last-Translator: Rafael Fontenelle \n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/language/pt_BR/)\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" +"language/pt_BR/)\n" +"Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Página não encontrada" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Desculpe, a página que você solicitou não existe." -#: html/503.php msgid "Service Unavailable" msgstr "Serviço Indisponível" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Sem pânico! Este site está fechado para manutenção. Voltaremos às atividades em breve." +msgstr "" +"Sem pânico! Este site está fechado para manutenção. Voltaremos às atividades " +"em breve." -#: html/account.php msgid "Account" msgstr "Conta" -#: html/account.php template/header.php msgid "Accounts" msgstr "Contas" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Você não tem permissão para acessar esta área." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Não foi possível obter informações para o usuário especificado." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Você não tem permissão para editar esta conta." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." -#: html/account.php msgid "You must log in to view user information." msgstr "Você precisa fazer login para ver as informações do usuário." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adicionar proposta" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Token inválido para a ação de usuário." -#: html/addvote.php msgid "Username does not exist." msgstr "Usuário não existe." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s já tem uma proposta aberta para eles." -#: html/addvote.php msgid "Invalid type." msgstr "Tipo inválido." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Proposta não pode ser vazia." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta foi enviada." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Enviar uma proposta para ser votada." -#: html/addvote.php msgid "Applicant/TU" msgstr "Requerente/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vazio se não aplicável)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" -#: html/addvote.php msgid "Addition of a TU" msgstr "Adição de um TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Remoção de um TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remoção de um TU (inatividade não declarada)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Emenda ao Estatuto" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" -#: html/addvote.php msgid "Submit" msgstr "Enviar" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gerenciar co-mantenedores" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Editar comentário" -#: html/home.php template/header.php msgid "Home" msgstr "Início" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Bem-vindo ao AUR! Por favor, leia as %sDiretrizes de Usuário do AUR%s e %sDiretrizes de TU do AUR%s para mais informações." +msgstr "" +"Bem-vindo ao AUR! Por favor, leia as %sDiretrizes de Usuário do AUR%s e " +"%sDiretrizes de TU do AUR%s para mais informações." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "PKGBUILDs contribuídos %sdevem%s estar em conformidade com os %sPadrões de Empacotamento do Arch%s, do contrário eles serão excluídos!" +msgstr "" +"PKGBUILDs contribuídos %sdevem%s estar em conformidade com os %sPadrões de " +"Empacotamento do Arch%s, do contrário eles serão excluídos!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Lembre-se de votar nos seus pacotes favoritos!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Alguns pacotes podem ser fornecidos como binários no repositório [community]." +msgstr "" +"Alguns pacotes podem ser fornecidos como binários no repositório [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "AVISO LEGAL" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "Os pacotes do AUR são conteúdos produzidos por usuários. Qualquer uso dos arquivos fornecidos é de sua própria conta e risco." +msgstr "" +"Os pacotes do AUR são conteúdos produzidos por usuários. Qualquer uso dos " +"arquivos fornecidos é de sua própria conta e risco." -#: html/home.php msgid "Learn more..." msgstr "Aprenda mais..." -#: html/home.php msgid "Support" msgstr "Suporte" -#: html/home.php msgid "Package Requests" msgstr "Requisições de pacote" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Há três tipos de requisições que podem ser realizadas na caixa %sAções do pacote%s na página de detalhes do pacote:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Há três tipos de requisições que podem ser realizadas na caixa %sAções do " +"pacote%s na página de detalhes do pacote:" -#: html/home.php msgid "Orphan Request" msgstr "Requisição para tornar o pacote órfão" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Requisite que seja desvinculado um pacote de seu mantenedor, de forma que o pacote fique órfão, quando, por exemplo, o mantenedor está inativo e o pacote foi marcado como desatualizado há muito tempo." +msgstr "" +"Requisite que seja desvinculado um pacote de seu mantenedor, de forma que o " +"pacote fique órfão, quando, por exemplo, o mantenedor está inativo e o " +"pacote foi marcado como desatualizado há muito tempo." -#: html/home.php msgid "Deletion Request" msgstr "Requisição de exclusão" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Requisite que um pacote seja removido do Arch User Repository. Por favor, não use esta opção se um pacote está quebrado, mas que pode ser corrigido facilmente. Ao invés disso, contate o mantenedor do pacote e, se necessário, preencha uma requisição para tornar esse pacote órfão." +msgstr "" +"Requisite que um pacote seja removido do Arch User Repository. Por favor, " +"não use esta opção se um pacote está quebrado, mas que pode ser corrigido " +"facilmente. Ao invés disso, contate o mantenedor do pacote e, se necessário, " +"preencha uma requisição para tornar esse pacote órfão." -#: html/home.php msgid "Merge Request" msgstr "Requisição de mesclagem" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Requisite que um pacote seja mesclado com outro. Pode ser usado quando um pacote precisa ser renomeado ou substituído por um pacote dividido." +msgstr "" +"Requisite que um pacote seja mesclado com outro. Pode ser usado quando um " +"pacote precisa ser renomeado ou substituído por um pacote dividido." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Se você quiser discutir uma requisição, você pode user a lista de discussão %saur-request%s. Porém, por favor não use essa lista para fazer requisições." +msgstr "" +"Se você quiser discutir uma requisição, você pode user a lista de discussão " +"%saur-request%s. Porém, por favor não use essa lista para fazer requisições." -#: html/home.php msgid "Submitting Packages" msgstr "Enviando pacotes" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Git sobre SSH agora é usado para enviar pacotes para o AUR. Veja a seção %sEnviando pacotes%s da página wiki do Arch User Repository para mais detalhes." +msgstr "" +"Git sobre SSH agora é usado para enviar pacotes para o AUR. Veja a seção " +"%sEnviando pacotes%s da página wiki do Arch User Repository para mais " +"detalhes." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "As seguintes fingeprints SSH são usadas para o AUR:" -#: html/home.php msgid "Discussion" msgstr "Discussão" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) e do Trusted User acontecem no %saur-general%s. Para discussão relacionada ao desenvolvimento do AUR web, use a lista de discussão do %saur-dev%s" +msgstr "" +"Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) " +"e do Trusted User acontecem no %saur-general%s. Para discussão relacionada " +"ao desenvolvimento do AUR web, use a lista de discussão do %saur-dev%s" -#: html/home.php msgid "Bug Reporting" msgstr "Relatório de erros" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." -msgstr "Se você encontrar um erro na interface web do AUR, por favor preencha um relatório de erro no nosso %sbug tracker%s. Use o tracker para relatar erros encontrados no AUR web, %ssomente%s. Para relatar erros de empacotamento, contate o mantenedor do pacote ou deixe um comentário na página de pacote apropriada." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." +msgstr "" +"Se você encontrar um erro na interface web do AUR, por favor preencha um " +"relatório de erro no nosso %sbug tracker%s. Use o tracker para relatar erros " +"encontrados no AUR web, %ssomente%s. Para relatar erros de empacotamento, " +"contate o mantenedor do pacote ou deixe um comentário na página de pacote " +"apropriada." -#: html/home.php msgid "Package Search" msgstr "Pesquisar pacote" -#: html/index.php msgid "Adopt" msgstr "Adotar" -#: html/index.php msgid "Vote" msgstr "Votar" -#: html/index.php msgid "UnVote" msgstr "Desfazer voto" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Não notificar" -#: html/index.php msgid "UnFlag" msgstr "Desmarcar" -#: html/login.php template/header.php msgid "Login" msgstr "Login" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Conectado como: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Sair" -#: html/login.php msgid "Enter login credentials" msgstr "Digite as credenciais de login" -#: html/login.php msgid "User name or email address" msgstr "Nome de usuário ou endereço de e-mail" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Senha" -#: html/login.php msgid "Remember me" msgstr "Lembrar de mim" -#: html/login.php msgid "Forgot Password" msgstr "Esqueci minha senha" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Login via HTTP está desabilitado. Favor %sacesse via HTTPs%s caso queira fazer login." +msgstr "" +"Login via HTTP está desabilitado. Favor %sacesse via HTTPs%s caso queira " +"fazer login." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critérios de pesquisa" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacotes" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erro ao tentar obter detalhes do pacote." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Preencha todos os campos obrigatórios." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Campos de senha não correspondem." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Sua senha deve conter pelo menos %s caracteres." -#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail inválido." -#: html/passreset.php msgid "Password Reset" msgstr "Redefinição de senha" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifique no seu e-mail pelo link de confirmação." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Sua senha foi redefinida com sucesso." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme seu endereço de e-mail:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Informe com sua senha:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme sua nova senha:" -#: html/passreset.php msgid "Continue" msgstr "Continuar" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Se você esqueceu o endereço de e-mail que você usou para registrar, por favor envie uma mensagem para a lista de e-mail do %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Se você esqueceu o endereço de e-mail que você usou para registrar, por " +"favor envie uma mensagem para a lista de e-mail do %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Digite o seu endereço de e-mail:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "Os pacotes selecionados não foram marcados como desatualizados, por favor insira um comentário." - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "Os pacotes selecionados não foram abandonados, marque a caixa de confirmação." +msgstr "" +"Os pacotes selecionados não foram abandonados, marque a caixa de confirmação." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Não foi possível encontrar pacote para nele fundir votos e comentários." +msgstr "" +"Não foi possível encontrar pacote para nele fundir votos e comentários." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Não é possível mesclar um pacote base com ele mesmo" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Os pacotes selecionados não foram apagados, marque a caixa de confirmação." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Exclusão de pacotes" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Excluir pacote: %s" +msgid "Delete Package" +msgstr "Excluir pacote" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Use este formulário para excluir o pacote base %s%s%s e os seguintes pacotes do AUR: " +msgstr "" +"Use este formulário para excluir o pacote base %s%s%s e os seguintes pacotes " +"do AUR: " -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "A exclusão de pacote um pacote é permanente." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Marque a caixa de seleção para confirmar a ação." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmar exclusão de pacote" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Excluir" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Somente Trusted Users e Desenvolvedores podem excluir pacotes." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar pacote" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Abandonar pacote: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Use esse formulário para abandonar o pacote base %s%s%s que incluem os seguintes pacotes:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Use esse formulário para abandonar o pacote base %s%s%s que incluem os " +"seguintes pacotes:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote e transferir a responsabilidade para %s%s%s." +msgstr "" +"Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote e " +"transferir a responsabilidade para %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote." +msgstr "" +"Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirme para abandonar o pacote" -#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Apenas Trusted Users e Desenvolvedores podem abandonar pacotes." -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "Comentário da marcação" + msgid "Flag Package Out-Of-Date" msgstr "Marcar pacote desatualizado" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "Marcar pacote desatualizado: %s" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " -msgstr "Use este formulário para marcar o pacote base %s%s%s e os seguintes pacotes como desatualizados: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " +msgstr "" +"Use este formulário para marcar o pacote base %s%s%s e os seguintes pacotes " +"como desatualizados: " -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "Por favor, %snão%s use esse formulário para relatar erros. Para isto, use os comentários do pacote." +msgstr "" +"Por favor, %snão%s use esse formulário para relatar erros. Para isto, use os " +"comentários do pacote." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "Insira detalhes sobre o motivo do pacote estar desatualizado abaixo, preferivelmente incluindo links para o anúncio de lançamento ou um novo tarball de lançamento." +msgstr "" +"Insira detalhes sobre o motivo do pacote estar desatualizado abaixo, " +"preferivelmente incluindo links para o anúncio de lançamento ou um novo " +"tarball de lançamento." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Comentários" -#: html/pkgflag.php msgid "Flag" msgstr "Marcar" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Apenas usuários registrados podem marcar pacotes como desatualizados." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Mesclagem de pacotes" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Mesclar pacote: %s" +msgid "Merge Package" +msgstr "Mesclar pacote" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Use este formulário para mesclar o pacote base %s%s%s em outro pacote. " +msgstr "" +"Use este formulário para mesclar o pacote base %s%s%s em outro pacote. " -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Os seguintes pacotes serão excluídos: " -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "Assim que o pacote tiver sido mesclado, não é possível reverter a ação." +msgstr "" +"Assim que o pacote tiver sido mesclado, não é possível reverter a ação." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Digite o nome do pacote para o qual você deseja mesclar o pacote." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Mesclar em:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmar a mesclagem de pacotes" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Mesclar" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Somente Trusted Users e Desenvolvedores podem mesclar pacotes." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Fazer requisição" +msgid "Submit Request" +msgstr "Enviar requisição" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fechar requisição" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Próxima" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Última" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Requisições" -#: html/register.php template/header.php msgid "Register" msgstr "Registrar" -#: html/register.php msgid "Use this form to create an account." msgstr "Utilize este formulário para criar uma conta." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Não foi possível adquirir detalhes da proposta." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A votação está encerrada para esta proposta." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Apenas Trusted Users têm permissão para votar." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Você não pode votar em uma proposta sobre você." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Você já votou nessa proposta." -#: html/tu.php msgid "Vote ID not valid." msgstr "ID de voto inválido." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos atuais" -#: html/tu.php msgid "Past Votes" msgstr "Votos anteriores" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Eleitores" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "O registro de conta foi desabilitado para seu endereço IP, provavelmente por causa de ataques continuados de spam. Desculpe a inconveniência." +msgstr "" +"O registro de conta foi desabilitado para seu endereço IP, provavelmente por " +"causa de ataques continuados de spam. Desculpe a inconveniência." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Faltando ID de usuário" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "O usuário é inválido." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Deve conter entre %s e %s caracteres" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Começo e fim com uma letra ou um número" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Pode conter somente um ponto, traço inferior ou hífen." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "A chave pública de SSH é inválida." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Não foi possível aumentar as permissões da conta." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Idioma sem suporte no momento." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de usuário, %s%s%s, já está sendo usado." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "O endereço, %s%s%s, já está sendo usado." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "A chave pública de SSH, %s%s%s, já está em uso." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erro ao tentar criar uma conta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A conta, %s%s%s, foi criada com sucesso." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "Uma chave de redefinição de senha foi enviada para seu endereço de e-mail." +msgstr "" +"Uma chave de redefinição de senha foi enviada para seu endereço de e-mail." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clique no link de Login acima para usar a sua conta." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nenhuma alteração foi feita na conta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A conta, %s%s%s, foi modificada com sucesso." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "O formulário de login está desabilitado momento para seu endereço IP, provavelmente por causa de ataques continuados de spam. Desculpe a inconveniência." +msgstr "" +"O formulário de login está desabilitado momento para seu endereço IP, " +"provavelmente por causa de ataques continuados de spam. Desculpe a " +"inconveniência." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Conta suspensa" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Sua senha foi redefinida. Se você acabou de criar uma conta, por favor use o link do e-mail de confirmação para definir uma senha inicial. Do contrário, por favor requisite uma chave de senha na página de %sRedefinição de senha%s." +msgstr "" +"Sua senha foi redefinida. Se você acabou de criar uma conta, por favor use o " +"link do e-mail de confirmação para definir uma senha inicial. Do contrário, " +"por favor requisite uma chave de senha na página de %sRedefinição de senha%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Usuário ou senha inválida." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ocorreu um erro ao tentar gerar uma sessão de usuário." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinação entre email e chave de redefinição é inválida" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nenhum" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver informações da conta para %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Faltando ID ou nome do pacote base." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Você não tem permissão para editar este comentário." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "Comentário não existe." +msgstr "O comentário não existe." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "Comentário não pode estar vazio." +msgstr "O comentário não pode estar vazio." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." -msgstr "Comentário adicionado." +msgstr "O comentário foi adicionado." + +msgid "You must be logged in before you can edit package information." +msgstr "Você tem que estar conectado para poder editar informações do pacote." + +msgid "Missing comment ID." +msgstr "Faltando ID de comentário." + +msgid "No more than 5 comments can be pinned." +msgstr "Não mais que 5 comentários podem ser afixados." + +msgid "You are not allowed to pin this comment." +msgstr "Você não tem permissão para afixar este comentário." + +msgid "You are not allowed to unpin this comment." +msgstr "Você não tem permissão para desafixar este comentário." + +msgid "Comment has been pinned." +msgstr "O comentário foi afixado." + +msgid "Comment has been unpinned." +msgstr "O comentário foi desafixado." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Erro ao obter detalhes do pacote." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Não foi possível encontrar os detalhes do pacote." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Você deve estar conectado para marcar os pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Você não selecionou nenhum pacote para marcar." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" +"Os pacotes selecionados não foram marcados como desatualizados, por favor " +"insira um comentário." + msgid "The selected packages have been flagged out-of-date." msgstr "O pacote selecionado foi marcado como desatualizado." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Você deve estar conectado para desmarcar os pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Você não selecionou nenhum pacote para desmarcar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "O pacote selecionado foi desmarcado." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Você não tem permissão para excluir pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Você selecionou nenhum pacote para excluir." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Os pacotes selecionados foram excluídos." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Você deve estar conectado para adotar pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Você deve estar conectado para abandonar pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Você não selecionou pacote para adotar." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Você não selecionou pacote para abandonar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Os pacotes selecionados foram adotados." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Os pacotes selecionados foram abandonados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Você deve estar conectado para votar nos pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Você deve estar conectado para desfazer o voto dos pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Você não selecionou nenhum pacote para votar." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Seus votos foram removidos dos pacotes selecionados." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Seus votos foram enviados para os pacotes selecionados." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Não foi possível adicionar à lista de notificação." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Você foi adicionado à lista de notificação de comentários de %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Você foi removido da lista de notificação de comentários de %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Você tem que estar conectado para poder editar informações do pacote." +msgid "You are not allowed to undelete this comment." +msgstr "Você não tem permissão para desfazer a exclusão deste comentário." -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Faltando ID de comentário." +msgid "Comment has been undeleted." +msgstr "O comentário teve sua exclusão desfeita." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "O comentário foi excluído." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Você não tem permissão para excluir esse comentário." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "O comentário foi excluído." + msgid "Comment has been edited." -msgstr "Comentário foi editado." +msgstr "O comentário foi editado." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "Você não tem permissão para editar as palavras-chaves deste pacote base." +msgstr "" +"Você não tem permissão para editar as palavras-chaves deste pacote base." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "As palavras-chave do pacote base foram atualizadas." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Você não tem permissão para gerenciar comantenedores deste pacote base." +msgstr "" +"Você não tem permissão para gerenciar comantenedores deste pacote base." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nome de usuário inválido: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Os comantenedores do pacote base foram atualizados." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalhes de pacotes para" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "requer %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Você deve estar conectado para preencher requisições de pacotes." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nome inválido: apenas letras minúsculas são permitidas." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "O campo de comentário não pode estar vazio" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de requisição inválida" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Requisição adicionada com sucesso" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Motivo inválido" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Apenas TUs e desenvolvedores podem fechar requisições" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Requisição fechada com sucesso" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Você pode usar esse formulário para excluir permanentemente a conta %s do AUR." +msgstr "" +"Você pode usar esse formulário para excluir permanentemente a conta %s do " +"AUR." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sAVISO%s: Essa ação não pode ser desfeita." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar exclusão" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Usuário" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de conta" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuário" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolvedor" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & Desenvolvedor" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Endereço de e-mail" -#: template/account_details.php msgid "hidden" msgstr "oculto" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Apelido no IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Impressão digital de chave PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Inativo desde" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Ativa" -#: template/account_details.php msgid "Last Login" msgstr "Último login" -#: template/account_details.php msgid "Never" msgstr "Nunca" -#: template/account_details.php msgid "View this user's packages" msgstr "Visualizar pacotes deste usuário" -#: template/account_details.php msgid "Edit this user's account" msgstr "Edite a conta desse usuário" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clique %saqui%s se você deseja excluir permanentemente esta conta." -#: template/account_edit_form.php msgid "required" msgstr "obrigatório" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuário normal" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Conta suspensa" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inativo" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "Por favor, certifique-se de que você informou seu endereço de e-mail, do contrário você perderá acesso." +msgstr "" +"Por favor, certifique-se de que você informou seu endereço de e-mail, do " +"contrário você perderá acesso." -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Ocultar endereço de e-mail" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Re-digite a senha" -#: template/account_edit_form.php msgid "Language" msgstr "Idioma" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "A informação a seguir é necessária apenas se você deseja enviar pacotes para o Repositório de Usuário do Arch." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"A informação a seguir é necessária apenas se você deseja enviar pacotes para " +"o Repositório de Usuário do Arch." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Chave pública de SSH" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Atualizar" +msgid "Notification settings" +msgstr "Configurações de notificação" -#: template/account_edit_form.php -msgid "Create" -msgstr "Criar" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Limpar" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Nenhum resultado correspondeu aos seus critérios de pesquisa." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Editar conta" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Suspensa" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Editar" - -#: template/account_search_results.php -msgid "Less" -msgstr "Menos" - -#: template/account_search_results.php -msgid "More" -msgstr "Mais" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Não há mais resultados para serem exibidos." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Gerenciar comantenedores: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Use este formulário para adicionar comantenedores para %s%s%s (um nome de usuário por linha):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Usuários" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Salvar" - -#: template/header.php -msgid "My Packages" -msgstr "Meus pacotes" - -#: template/header.php -msgid " My Account" -msgstr " Minha conta" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Ações do pacote" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Visualizar PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Ver alterações" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Baixar snapshot" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Pesquisar no wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marcado como desatualizado" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Marcar como desatualizado" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Desmarcar desatualização" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Remover voto" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Votar neste pacote" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Desabilitar notificações" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Notificar sobre novos comentários" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "Notificar sobre atualizações de pacotes" + +msgid "Update" +msgstr "Atualizar" + +msgid "Create" +msgstr "Criar" + +msgid "Reset" +msgstr "Limpar" + +msgid "No results matched your search criteria." +msgstr "Nenhum resultado correspondeu aos seus critérios de pesquisa." + +msgid "Edit Account" +msgstr "Editar conta" + +msgid "Suspended" +msgstr "Suspensa" + +msgid "Edit" +msgstr "Editar" + +msgid "Less" +msgstr "Menos" + +msgid "More" +msgstr "Mais" + +msgid "No more results to display." +msgstr "Não há mais resultados para serem exibidos." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Use este formulário para adicionar comantenedores para %s%s%s (um nome de " +"usuário por linha):" + +msgid "Users" +msgstr "Usuários" + +msgid "Save" +msgstr "Salvar" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "Comentário sobre marcação como desatualizado: %s" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" +"%s%s%s marcou %s%s%s como desatualizado em %s%s%s pelo seguinte motivo:" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "%s%s%s não está marcado como desatualizado." + +msgid "Return to Details" +msgstr "Retornar para Detalhes" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Copyright %s 2004-%d Equipe de Desenvolvimento do aurweb." + +msgid "My Packages" +msgstr "Meus pacotes" + +msgid " My Account" +msgstr " Minha conta" + +msgid "Package Actions" +msgstr "Ações do pacote" + +msgid "View PKGBUILD" +msgstr "Visualizar PKGBUILD" + +msgid "View Changes" +msgstr "Ver alterações" + +msgid "Download snapshot" +msgstr "Baixar snapshot" + +msgid "Search wiki" +msgstr "Pesquisar no wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "Marcado como desatualizado (%s)" + +msgid "Flag package out-of-date" +msgstr "Marcar como desatualizado" + +msgid "Unflag package" +msgstr "Desmarcar desatualização" + +msgid "Remove vote" +msgstr "Remover voto" + +msgid "Vote for this package" +msgstr "Votar neste pacote" + +msgid "Disable notifications" +msgstr "Desabilitar notificações" + msgid "Manage Co-Maintainers" msgstr "Gerenciar comantenedores" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requisição pentende" msgstr[1] "%d requisições pentendes" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Excluir pacote" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Mesclar pacote" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotar pacote" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconhecido" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalhes do pacote base" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "somente leitura" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Palavras-chave" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Criado por" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mantenedor" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último empacotador" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularidade" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Criado em" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última atualização" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Editar comentário para: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adicionar comentário" -#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos os comentários" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "Comentários afixados" + msgid "Latest Comments" msgstr "Últimos comentários" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s comentou em %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Comentário anônimo em %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "excluído em %s por %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "última edição em %s por %s" +msgid "deleted on %s" +msgstr "excluído em %s" + +#, php-format +msgid "edited on %s by %s" +msgstr "editado em %s por %s" + +#, php-format +msgid "edited on %s" +msgstr "editado em %s" + +msgid "Undelete comment" +msgstr "Desfazer exclusão de comentário" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Excluir comentário" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "Afixar comentário" + +msgid "Unpin comment" +msgstr "Desafixar comentário" + msgid "All comments" msgstr "Todos os comentários" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do pacote" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacote base" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrição" -#: template/pkg_details.php msgid "Upstream URL" msgstr "URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Visitar o site para" -#: template/pkg_details.php msgid "Licenses" msgstr "Licenças" -#: template/pkg_details.php msgid "Groups" msgstr "Grupos" -#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitos" -#: template/pkg_details.php msgid "Provides" msgstr "Provê" -#: template/pkg_details.php msgid "Replaces" msgstr "Substitui" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dependências" -#: template/pkg_details.php msgid "Required by" msgstr "Necessário para" -#: template/pkg_details.php msgid "Sources" msgstr "Fontes" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Fechar requisição: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Use esse formulário para fechar a requisição para o pacote base %s%s%s." +msgstr "" +"Use esse formulário para fechar a requisição para o pacote base %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Nota" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "O campo de comentários pode ser deixado vazio. Porém, é fortemente recomendado adicionar um comentário ao rejeitar uma requisição." +msgstr "" +"O campo de comentários pode ser deixado vazio. Porém, é fortemente " +"recomendado adicionar um comentário ao rejeitar uma requisição." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motivo" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Aceito" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Rejeitado" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Fazer requisição: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Use esse formulário para fazer uma requisição sobre o pacote base %s%s%s que inclui os seguintes pacotes:" +msgstr "" +"Use esse formulário para fazer uma requisição sobre o pacote base %s%s%s que " +"inclui os seguintes pacotes:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de requisição" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Excluir" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Tornar órfão" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Mesclar em" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d requisição de pacote encontrada." msgstr[1] "%d requisições de pacotes encontradas." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pacote" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Criada por" -#: template/pkgreq_results.php msgid "Date" msgstr "Data" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dias restantes" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d hora restante" msgstr[1] "~%d horas restantes" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 hora restante" -#: template/pkgreq_results.php msgid "Accept" msgstr "Aceitar" -#: template/pkgreq_results.php msgid "Locked" msgstr "Travado" -#: template/pkgreq_results.php msgid "Close" msgstr "Fechar" -#: template/pkgreq_results.php msgid "Closed" msgstr "Fechada" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descrição" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Somente nome" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exato" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacote base exato" -#: template/pkg_search_form.php msgid "All" msgstr "Todos" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcado" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Não marcado" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" -#: template/pkg_search_form.php msgid "Last modified" msgstr "Última modificação" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Crescente" -#: template/pkg_search_form.php msgid "Descending" msgstr "Decrescente" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Digite os critérios de pesquisa" -#: template/pkg_search_form.php msgid "Search by" msgstr "Pesquisar por" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desatualizado" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordem de classificação" -#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Pesquisar" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Órfãos" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erro ao obter a lista de pacotes." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nenhum pacote correspondeu aos seus critérios de pesquisa." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." -#: template/pkg_search_results.php msgid "Version" msgstr "Versão" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "Popularidade é calculada como a soma de todos os votos, sendo cada voto pesado com um fator de 0.98 por dia desde sua criação." +msgstr "" +"Popularidade é calculada como a soma de todos os votos, sendo cada voto " +"pesado com um fator de 0.98 por dia desde sua criação." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Sim" -#: template/pkg_search_results.php msgid "orphan" msgstr "órfão" -#: template/pkg_search_results.php msgid "Actions" msgstr "Ações" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marcar como desatualizado" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar desatualizado" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adotar pacotes" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar pacotes" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Excluir pacotes" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" -#: template/search_accounts_form.php msgid "Any type" msgstr "Qualquer tipo" -#: template/search_accounts_form.php msgid "Search" msgstr "Pesquisa" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estatísticas" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacotes órfãos" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacotes adicionados nos últimos 7 dias" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacotes atualizados nos últimos 7 dias" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacotes atualizados no último ano" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacotes nunca atualizados" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuários registrados" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Atualizações recentes" -#: template/stats/user_table.php +msgid "more" +msgstr "mais" + msgid "My Statistics" msgstr "Minhas estatísticas" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detalhes da proposta" -#: template/tu_details.php msgid "This vote is still running." msgstr "Essa votação ainda está aberta." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Enviado: %s por %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fim" -#: template/tu_details.php msgid "Result" msgstr "Resultado" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Não" -#: template/tu_details.php msgid "Abstain" msgstr "Abster" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" msgstr "Participação" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Últimos votos por TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nenhum resultado encontrado." -#: template/tu_list.php msgid "Start" msgstr "Iniciar" -#: template/tu_list.php msgid "Back" msgstr "Voltar" diff --git a/po/pt_PT.po b/po/pt_PT.po index 627d88cc..fa61d356 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -1,10 +1,10 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Gaspar Santos , 2011 -# R00KIE , 2013 +# R00KIE , 2013,2016 # R00KIE , 2011 # DarkVenger , 2013-2015 # DarkVenger , 2012 @@ -12,1799 +12,1456 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/aur/language/pt_PT/)\n" +"Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" +"aur/language/pt_PT/)\n" +"Language: pt_PT\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt_PT\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Página Não Encontrada" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "As nossas desculpas, a página que pediu não existe." -#: html/503.php msgid "Service Unavailable" msgstr "Serviço não disponível" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Não entre em pânico! Esta página encontra-se em baixo devido a manutenção. Voltaremos brevemente." +msgstr "" +"Não entre em pânico! Esta página encontra-se em baixo devido a manutenção. " +"Voltaremos brevemente." -#: html/account.php msgid "Account" msgstr "Conta" -#: html/account.php template/header.php msgid "Accounts" msgstr "Contas" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Não tem autorização para aceder a esta área." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Não foi possível obter informações para o utilizador especificado." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Não tem autorização para editar esta conta." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." -#: html/account.php msgid "You must log in to view user information." msgstr "Necessita iniciar sessão para visualizar a informação do utilizador." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adicionar Proposta" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Token inválido para acção de utilizador." -#: html/addvote.php msgid "Username does not exist." msgstr "O utilizador não existe." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s já tem uma proposta a decorrer." -#: html/addvote.php msgid "Invalid type." msgstr "Tipo inválido." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "A proposta não pode estar vazia." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta submetida." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Submeta uma proposta para votação." -#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vazio se não aplicável)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" -#: html/addvote.php msgid "Addition of a TU" msgstr "Adição de um TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Remoção de um TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remoção de um TU (inatividade não declarada)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Alterações ao Estatutos" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" -#: html/addvote.php msgid "Submit" msgstr "Enviar" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Gerir responsáveis" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Editar comentário" -#: html/home.php template/header.php msgid "Home" msgstr "Início" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Bem-vindo ao AUR! Por favor leia as %sOrientações de Utilizador do AUR%s e %sOrientações de TU do AUR%s para mais informações." +msgstr "" +"Bem-vindo ao AUR! Por favor leia as %sOrientações de Utilizador do AUR%s e " +"%sOrientações de TU do AUR%s para mais informações." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "As contribuições de PKGBUILDs %sdevem%s obedecer aos %sPadrões de Empacotamento Arch%s ou serão eliminadas!" +msgstr "" +"As contribuições de PKGBUILDs %sdevem%s obedecer aos %sPadrões de " +"Empacotamento Arch%s ou serão eliminadas!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Lembre-se de votar nos seus pacotes favoritos!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Alguns dos pacotes podem ser fornecidos como binários no repositório [community]." +msgstr "" +"Alguns dos pacotes podem ser fornecidos como binários no repositório " +"[community]." -#: html/home.php msgid "DISCLAIMER" msgstr "AVISO LEGAL" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Os pacotes AUR são produzidos por utilizadores. O seu uso é por sua conta e " +"risco." -#: html/home.php msgid "Learn more..." msgstr "Saber mais..." -#: html/home.php msgid "Support" msgstr "Suporte" -#: html/home.php msgid "Package Requests" msgstr "Pedidos de Pacotes" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Existem três tipos de pedidos que podem ser preenchidos na caixa %sPackageActions%s na página de detalhes de um pacote." +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Existem três tipos de pedidos que podem ser preenchidos na caixa " +"%sPackageActions%s na página de detalhes de um pacote." -#: html/home.php msgid "Orphan Request" msgstr "Pedido para Tornar Orfão" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Pedido para que um pacote dique sem dono, por exemplo, quando o atual responsável se encontra inativo e o pacote foi marcado como desatualizado há muito tempo." +msgstr "" +"Pedido para que um pacote dique sem dono, por exemplo, quando o atual " +"responsável se encontra inativo e o pacote foi marcado como desatualizado há " +"muito tempo." -#: html/home.php msgid "Deletion Request" msgstr "Pedido para Apagar" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Pedido para que um pacote seja removido do Arch User Repository. Por favor não use este pedido se um pacote está danificado e pode ser resolvido facilmente. Contacte o responsável pelo mesmo e faça um Pedido para Tornar Orfão se necessário." - -#: html/home.php -msgid "Merge Request" msgstr "" +"Pedido para que um pacote seja removido do Arch User Repository. Por favor " +"não use este pedido se um pacote está danificado e pode ser resolvido " +"facilmente. Contacte o responsável pelo mesmo e faça um Pedido para Tornar " +"Orfão se necessário." + +msgid "Merge Request" +msgstr "Pedido de junção" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"Requerer que um pacote seja junto a outro. Pode ser utilizado quando é " +"necessário mudar o nome ao pacote ou substituir o mesmo por um pacote " +"separado." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Se quiser discutir um pedido, pode faze-lo utilizando a lista de email %saur-" +"requests%s. Por favor não use a lista para submeter pedidos." -#: html/home.php msgid "Submitting Packages" -msgstr "" +msgstr "Submeter Pacotes" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Discussão" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Reportar um Bug" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Pesquisa de Pacotes" -#: html/index.php msgid "Adopt" msgstr "Adoptar" -#: html/index.php msgid "Vote" msgstr "Votar" -#: html/index.php msgid "UnVote" msgstr "Retirar voto" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Não Notificar" -#: html/index.php msgid "UnFlag" msgstr "Desmarcar" -#: html/login.php template/header.php msgid "Login" msgstr "Iniciar sessão" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Sessão iniciada como: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Terminar sessão" -#: html/login.php msgid "Enter login credentials" msgstr "Introduza as credenciais para login" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Palavra-passe" -#: html/login.php msgid "Remember me" msgstr "Lembrar-se de mim" -#: html/login.php msgid "Forgot Password" msgstr "Esqueceu-se da palavra-passe" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Início de sessão em HTTP está desactivado. Por favor %smude para HTTPs%s se pretende iniciar sessão." +msgstr "" +"Início de sessão em HTTP está desactivado. Por favor %smude para HTTPs%s se " +"pretende iniciar sessão." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critérios de Pesquisa" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacotes" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erro ao tentar obter os detalhes do pacote." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Em falta um campo obrigatório." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Campos de palavra-passe não correspondem." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "A sua palavra-passe tem de ter pelo menos %s caracteres." -#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail inválido." -#: html/passreset.php msgid "Password Reset" msgstr "Reiniciar a Palavra-passe" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifique o seu e-mail para o link de confirmação." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "A palavra-passe foi reiniciada com êxito." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme o endereço de e-mail:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Introduza a nova palavra-passe:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme a nova palavra-passe:" -#: html/passreset.php msgid "Continue" msgstr "Continue" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Se se esqueceu do endereço de e-mail que utilizou para efectuar o registo, por favor envie uma mensagem para a lista de discussão %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Se se esqueceu do endereço de e-mail que utilizou para efectuar o registo, " +"por favor envie uma mensagem para a lista de discussão %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduza o endereço de e-mail:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Não é possível encontrar o pacote onde juntar os votos e os comentários." +msgstr "" +"Não é possível encontrar o pacote onde juntar os votos e os comentários." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Os pacotes selecionados não foram apagados, marque a caixa de confirmação." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminar Pacote" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Eliminar Pacote: %s" +msgid "Delete Package" +msgstr "Eliminar Pacote" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Use este formulário para eliminar o pacote base %s%s%s e os seguintes pacotes do AUR:" +msgstr "" +"Use este formulário para eliminar o pacote base %s%s%s e os seguintes " +"pacotes do AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "A eliminação de um pacote é permanente." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Seleccione a caixa para confirmar a acção." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmar eliminação do pacote" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Eliminar" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "Apenas Utilizadores de Confiança e Programadores podem eliminar pacotes." +msgstr "" +"Apenas Utilizadores de Confiança e Programadores podem eliminar pacotes." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Renunciar Pacote" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "Renunciar" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Comentários" -#: html/pkgflag.php msgid "Flag" msgstr "Marcar" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusão de Pacotes" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Fundir o pacote: %s" +msgid "Merge Package" +msgstr "Fundir Pacote" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Use este formulário para fundir o pacote base %s%s%s num outro pacote." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Os pacotes listados serão eliminados:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Uma vez feita a fusão do pacote não há como reverter o processo." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduza o nome do pacote com o qual deseja realizar a fusão." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Fundir com:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confimar fusão de pacote" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fundir" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Apenas Utilizadores de Confiança e Programadores podem fundir pacotes." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Pedido de Ficheiro" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fechar Pedido" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seguinte" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo." -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Pedidos" -#: html/register.php template/header.php msgid "Register" msgstr "Registar" -#: html/register.php msgid "Use this form to create an account." msgstr "Para criar uma conta utilize este formulário." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Utilizador de Confiança" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Não foi possível obter detalhes da proposta." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A votação está fechada para esta proposta." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Apenas Utilizadores de Confiança podem votar." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Não pode votar numa proposta acerca de si." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Já votou nesta proposta." -#: html/tu.php msgid "Vote ID not valid." msgstr "ID de voto não é válido." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos Actuais" -#: html/tu.php msgid "Past Votes" msgstr "Votos Passados" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "O registo de contas encontra-se inibido para pedidos do seu IP, provavelmente devido a continuados ataques de spam. Lamentamos o inconveniente." +msgstr "" +"O registo de contas encontra-se inibido para pedidos do seu IP, " +"provavelmente devido a continuados ataques de spam. Lamentamos o " +"inconveniente." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID de utilizador em falta" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "O nome de utilizador é inválido." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Tem de ter entre %s e %s caracteres de comprimento" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Começar e acabar com uma letra ou um número" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Apenas pode conter um ponto, underscore ou hífen." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Incapaz de aumentar as permissões da conta." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Língua não suportada actualmente." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de utilizador, %s%s%s, já se encontra a ser utilizado." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "O endereço, %s%s%s, já está a ser utilizado." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erro ao tentar criar a conta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A conta, %s%s%s, foi criada com sucesso." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "Uma chave de reinicialização da sua palavra-passe foi enviada para o seu endereço de e-mail." +msgstr "" +"Uma chave de reinicialização da sua palavra-passe foi enviada para o seu " +"endereço de e-mail." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clique no link Login acima para iniciar sessão." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nenhuma alterações foi realizada à conta, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A conta, %s%s%s, foi modificada com sucesso." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "O formulário de início de sessão encontra-se inibido para pedidos do seu IP, provavelmente devido a continuados ataques de spam. Lamentamos o inconveniente." +msgstr "" +"O formulário de início de sessão encontra-se inibido para pedidos do seu IP, " +"provavelmente devido a continuados ataques de spam. Lamentamos o " +"inconveniente." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Conta Suspensa" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "A sua palavra passe foi reiniciada. Se criou uma nova conta agora, por favor siga a ligação do email de confirmação para definir uma palavra passe. Caso contrário, por favor peça um reinicio à chave na pagina %sReiniciar Password%s." +msgstr "" +"A sua palavra passe foi reiniciada. Se criou uma nova conta agora, por favor " +"siga a ligação do email de confirmação para definir uma palavra passe. Caso " +"contrário, por favor peça um reinicio à chave na pagina %sReiniciar Password" +"%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Mau nome de utilizador ou palavra-passe." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ocorreu um erro ao tentar gerar uma sessão de utilizador." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinação de e-mail e chave de recuperação inválidos." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nenhum" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver informação de conta de %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "O comentário foi adicionado." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Tem de ter sessão iniciada antes de poder as informações de um pacote." + +msgid "Missing comment ID." +msgstr "ID de comentário em falta." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Erro ao obter os detalhes do pacote." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Não foi possivel encontrar detalhes acerca do pacote." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Tem de iniciar sessão antes de poder marcar pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Não seleccionou nenhum pacote a marcar." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Os pacotes seleccionados foram marcados como desactualizados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Tem de iniciar sessão antes de poder desmarcar pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Não seleccionou nenhum pacote a desmarcar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Os pacotes seleccionados foram desmarcados." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Não tem permissão para eliminar pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Não seleccionou nenhum pacote a apagar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Os pacotes seleccionados foram apagados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Tem de iniciar se sessão antes de poder adoptar pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Tem de iniciar se sessão antes de poder renunciar pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Não seleccionou nenhum pacote a adoptar." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Não seleccionou nenhum pacote a renunciar." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Os pacotes seleccionados foram adoptados." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Os pacotes seleccionados foram renunciados." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Tem de iniciar sessão antes de poder votar em pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Tem de ter sessão iniciada antes de poder retirar votos dos pacotes." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Não seleccionou nenhuns pacotes nos quais votar." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Os seus votos foram retirados dos pacotes seleccionados." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Os seus votos foram lançados para os pacotes seleccionados." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Não foi possível adicionar à lista de notificações." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Foi adicionado à lista de notificação de comentários de %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Foi removido da lista de notificação de comentários de %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Tem de ter sessão iniciada antes de poder as informações de um pacote." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "ID de comentário em falta." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "O comentário foi apagado." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Não tem permissão para apagar este comentário." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "O comentário foi apagado." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalhes do pacote de" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nome inválido: apenas são permitidas letras minúsculas." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "O campo \"comentários\" não pode ficar vazio." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de pedido inválido." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Pedido adicionado com sucesso." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razão inválida." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Apenas programadores e TUs podem fechar pedidos." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Pedido fechado com sucesso." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" -#: template/account_delete.php msgid "Confirm deletion" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nome de utilizador" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de conta" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilizador" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolvedor" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Endereço de E-mail" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Impressão digital da chave PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Estado" -#: template/account_details.php msgid "Inactive since" msgstr "Inativo desde" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" -#: template/account_details.php msgid "Last Login" msgstr "Última sessão" -#: template/account_details.php msgid "Never" msgstr "Nunca" -#: template/account_details.php msgid "View this user's packages" msgstr "Ver os pacotes deste utilizador" -#: template/account_details.php msgid "Edit this user's account" msgstr "Editar a conta deste utilizador" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" -#: template/account_edit_form.php msgid "required" msgstr "necessário" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilizador normal" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Utilizador de confiança" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Conta Suspensa" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inativo" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Reintroduza a palavra-passe" -#: template/account_edit_form.php msgid "Language" msgstr "Língua" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Notificar-me sobre novos comentários" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Actualizar" -#: template/account_edit_form.php msgid "Create" msgstr "Criar" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reiniciar" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Não existem resultados que correspondam aos seus critérios de procura." -#: template/account_search_results.php msgid "Edit Account" msgstr "Editar Conta" -#: template/account_search_results.php msgid "Suspended" msgstr "Suspenso" -#: template/account_search_results.php msgid "Edit" msgstr "Editar" -#: template/account_search_results.php msgid "Less" msgstr "Menos" -#: template/account_search_results.php msgid "More" msgstr "Mais" -#: template/account_search_results.php msgid "No more results to display." msgstr "Não existem mais resultados para mostrar." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Os meus pacotes" -#: template/header.php msgid " My Account" msgstr "A minha Conta" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ações sobre Pacotes" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Pesquisar na Wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marcado como desatualizado." +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar como desatualizado" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar pacote" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Remover voto" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar neste pacote" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Desativar notificações" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Notificar-me sobre novos comentários" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d pedido por atender" msgstr[1] "%d pedidos por atender" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Eliminar Pacote" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Fundir Pacote" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotar Pacote" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "desconhecido" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Pacote Base Detalhes" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Palavras-chave" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Submissor" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Responsável pela manutenção" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último Responsável" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Primeira Submissão" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última Actualização" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adicionar comentário" -#: template/pkg_comments.php msgid "View all comments" msgstr "" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Últimos Comentários" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Pagar comentário" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Todos os comentários" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do Pacote" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacote Base" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrição" -#: template/pkg_details.php msgid "Upstream URL" msgstr "URL a montante" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Visitar a página web de" -#: template/pkg_details.php msgid "Licenses" msgstr "Licenças" -#: template/pkg_details.php msgid "Groups" msgstr "Grupos" -#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitos" -#: template/pkg_details.php msgid "Provides" msgstr "Fornece" -#: template/pkg_details.php msgid "Replaces" msgstr "Substitui" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dependências" -#: template/pkg_details.php msgid "Required by" msgstr "Exigido por" -#: template/pkg_details.php msgid "Sources" msgstr "Fontes" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php msgid "Note" msgstr "" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Aceite" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Rejeitado" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Pedido de Ficheiro: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Use este formulário para enviar um pedido sobre o pacote base %s%s%s que inclui os seguintes pacotes:" +msgstr "" +"Use este formulário para enviar um pedido sobre o pacote base %s%s%s que " +"inclui os seguintes pacotes:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de pedido" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Apagar" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfão" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Juntar em" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d pedido de pacote encontrado." msgstr[1] "%d pedidos de pacotes encontrados." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pacote" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Enviado por" -#: template/pkgreq_results.php msgid "Date" msgstr "Data" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" -#: template/pkgreq_results.php msgid "Accept" msgstr "Aceitar" -#: template/pkgreq_results.php msgid "Locked" msgstr "" -#: template/pkgreq_results.php msgid "Close" msgstr "Fechar" -#: template/pkgreq_results.php msgid "Closed" msgstr "Fechado" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, Descrição" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Só Nome" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exacto" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacote Base Exacto" -#: template/pkg_search_form.php msgid "All" msgstr "Todos" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Não marcados" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votou" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" -#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzir critério de pesquisa" -#: template/pkg_search_form.php msgid "Search by" msgstr "Procurar por" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordem de ordenação" -#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Órfãos" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erro ao obter lista de pacotes." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nenhum pacote corresponde aos critérios de procura." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." -#: template/pkg_search_results.php msgid "Version" msgstr "Versão" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Sim" -#: template/pkg_search_results.php msgid "orphan" msgstr "Órfão" -#: template/pkg_search_results.php msgid "Actions" msgstr "Acções" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marcar como desactualizado." - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar como Desactualizado" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar Pacotes" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Renunciar Pacotes" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Apagar Pacotes" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" -#: template/search_accounts_form.php msgid "Any type" msgstr "Qualquer tipo" -#: template/search_accounts_form.php msgid "Search" msgstr "Procurar" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estatísticas" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacotes Órfãos" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacotes adicionados nos últimos 7 dias" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacotes actualizados nos últimos 7 dias" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacotes actualizados no último ano" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacotes nunca actualizados" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilizadores Registados" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Utilizadores de Confiança" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizações recentes" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Minhas Estatísticas" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detalhes da Proposta" -#: template/tu_details.php msgid "This vote is still running." msgstr "Este votação ainda está a decorrer." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Submetido: %s por %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fim" -#: template/tu_details.php msgid "Result" msgstr "Resultado" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Não" -#: template/tu_details.php msgid "Abstain" msgstr "Abster-se" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" msgstr "Participação" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Últimos votos de TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Não foram encontrados resultados." -#: template/tu_list.php msgid "Start" msgstr "Inicio" -#: template/tu_list.php msgid "Back" msgstr "Anterior" diff --git a/po/ro.po b/po/ro.po index 4ff7db4e..250c7ff0 100644 --- a/po/ro.po +++ b/po/ro.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Arthur Țițeică , 2013-2015 # Lukas Fleischer , 2011 @@ -10,1268 +10,1034 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/ro/)\n" +"Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" +"ro/)\n" +"Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ro\n" -"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?" +"2:1));\n" -#: html/404.php msgid "Page Not Found" msgstr "Pagina nu a fost găsită" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Din păcate, pagina solicitată nu există." -#: html/503.php msgid "Service Unavailable" msgstr "" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" -#: html/account.php msgid "Account" msgstr "Cont" -#: html/account.php template/header.php msgid "Accounts" msgstr "Conturi" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nu îți este permis accesul la această secțiune." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nu s-au putut prelua informații despre utilizatorul specificat." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nu ai permisiune pentru a modifica acest cont." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Folosește acest formular pentru a căuta conturi existente." -#: html/account.php msgid "You must log in to view user information." -msgstr "Trebuie să fi autentificat pentru a putea vedea informații despre utilizatori." +msgstr "" +"Trebuie să fi autentificat pentru a putea vedea informații despre " +"utilizatori." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adaugă o propunere" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Jeton nevalid pentru acțiunea utilizatorului." -#: html/addvote.php msgid "Username does not exist." msgstr "Nume de utilizator inexistent." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Pentru %s exista o propunere în desfășurare." -#: html/addvote.php msgid "Invalid type." msgstr "Tip nevalid." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Propunerea nu poate fi goală." -#: html/addvote.php msgid "New proposal submitted." msgstr "Propunerea nouă a fost trimisă." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Trimite o propunere pentru a putea fi votată." -#: html/addvote.php msgid "Applicant/TU" msgstr "Candidat/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(gol dacă nu este cazul)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tip" -#: html/addvote.php msgid "Addition of a TU" msgstr "Adăugarea unui TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Înlăturarea unui TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Înlăturarea unui TU (inactivitate nedeclarată)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendamentul Statutului" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propunere" -#: html/addvote.php msgid "Submit" msgstr "Trimite" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "Acasă" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Bine ai venit la AUR! Te rog citește %sGhidul utilizatorului AUR%s și %sGhidul AUR TU%s pentru mai multe informații." +msgstr "" +"Bine ai venit la AUR! Te rog citește %sGhidul utilizatorului AUR%s și " +"%sGhidul AUR TU%s pentru mai multe informații." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "PKGBUILDurile contribuite %strebuie%s să fie conforme cu %sStandardele de Împachetare Arch%s, altfel vor fi șterse!" +msgstr "" +"PKGBUILDurile contribuite %strebuie%s să fie conforme cu %sStandardele de " +"Împachetare Arch%s, altfel vor fi șterse!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nu uita să votezi pentru pachetele tale favorite!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Unele pachete pot fi furnizate ca binare în [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "DECLARAȚIE DE NEASUMARE A RESPONSABILITĂȚII" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" msgstr "" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "Discuție" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Semnalare buguri" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Căutare pachete" -#: html/index.php msgid "Adopt" msgstr "Adoptă" -#: html/index.php msgid "Vote" msgstr "Vot" -#: html/index.php msgid "UnVote" msgstr "EliminăVot" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificare" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "DeNotificare" -#: html/index.php msgid "UnFlag" msgstr "Elimină marcaj" -#: html/login.php template/header.php msgid "Login" msgstr "Autentificare" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificat ca: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "De-autentificare" -#: html/login.php msgid "Enter login credentials" msgstr "Introdu datele de autentificare" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Parolă" -#: html/login.php msgid "Remember me" msgstr "Ține-mă minte" -#: html/login.php msgid "Forgot Password" msgstr "Parolă uitată" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Autentificarea prin HTTP este dezactivată. %sSchimbă pe HTTPS%s dacă vrei să te autentifici." +msgstr "" +"Autentificarea prin HTTP este dezactivată. %sSchimbă pe HTTPS%s dacă vrei să " +"te autentifici." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteriul de căutare" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pachete" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Eroare la încercarea de a prelua detaliile pachetului." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Lipsește un câmp necesar." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Câmpurile parolei nu sunt potrivesc." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Parola trebuie să fie de cel puțin %s caractere." -#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail nevalid" -#: html/passreset.php msgid "Password Reset" msgstr "Resetare parolă" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifică e-mailul pentru legătura de confirmare." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Parola ta a fost restabilită cu succes." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirmă adresa de e-mail:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Introdu noua parolă:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirmă noua parolă." -#: html/passreset.php msgid "Continue" msgstr "Continuă" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Dacă ai uitat adresa de email folosită la înregistrare, trimite un mesaj la lista de discuții %saur-general%s" +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Dacă ai uitat adresa de email folosită la înregistrare, trimite un mesaj la " +"lista de discuții %saur-general%s" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introdu adresa ta de e-mail:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Nu s-a putut găsi pachet pentru fuzionare voturi și comentarii." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nu se poate fuziona un pachet cu el însuși." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "Pachetele selectate nu au fost șterse; verifică căsuța de bifare." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Ștergere pachet" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Șterge pachetul: %s" +msgid "Delete Package" +msgstr "Șterge pachet" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Folosește acest formular pentru a șterge pachetul de bază %s%s%s și următoarele pachete din AUR: " +msgstr "" +"Folosește acest formular pentru a șterge pachetul de bază %s%s%s și " +"următoarele pachete din AUR: " -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Ștergerea unui pachet este permanentă." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Bifează căsuța pentru a confirma acțiunea." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmă ștergerea pachetului" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Șterge" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Numai Dezvoltatorii și Trusted Users pot șterge pachete." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonează pachet" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "Abandonează" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Comentarii" -#: html/pkgflag.php msgid "Flag" msgstr "Marchează" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Fuzionare pachet" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Fuzionează pachetul: %s" +msgid "Merge Package" +msgstr "Fuzionează pachet" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Folosește acest formular pentru a îmbina pachetul de bază %s%s%s cu alt pachet." +msgstr "" +"Folosește acest formular pentru a îmbina pachetul de bază %s%s%s cu alt " +"pachet." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Următoarele pachete vor fi șterse:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Odată ce pachetul a fuzionat, acțiunea nu este reversibilă." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introdu numele pachetului cu care vrei să fie fuzionat acest pachet." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Fuzionează cu:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmă fuzionarea pachetului" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fuzionare" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Numai Dezvoltatorii și Trusted Users pot fuziona pachete." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Depune cerere" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Închide cererea" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prim" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedent" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Înainte" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultim" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Cereri" -#: html/register.php template/header.php msgid "Register" msgstr "Înregistrare" -#: html/register.php msgid "Use this form to create an account." msgstr "Folosește acest formular pentru a crea un cont." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nu am putut prelua detaliile propunerii." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Votarea este închisă pentru această propunere." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Doar Trusted Users au permisiunea să voteze." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nu poți vota într-o propunere despre tine." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ai votat deja pentru această propunere." -#: html/tu.php msgid "Vote ID not valid." msgstr "ID-ul votului nu este valid." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Voturi curente" -#: html/tu.php msgid "Past Votes" msgstr "Voturi precedente" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votanți" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Înregistrarea de conturi noi a fost dezactivată pentru adresa ta IP, probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +msgstr "" +"Înregistrarea de conturi noi a fost dezactivată pentru adresa ta IP, " +"probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru " +"inconveniență." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID-ul utilizatorului lipsește" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Numele de utilizator nu este valid." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Trebuie să fie între %s și %s caractere lungime" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Începe și sfârșește cu o literă sau un număr." -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Poate conține doar o virgulă, linie joasă sau cratimă." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adresa de email nu este validă." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Amprenta cheii PGP este nevalidă." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Permisiunile contului nu pot fi ridicate." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Limba nu este încă suportată." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Numele de utilizator %s%s%s este deja folosit." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s este deja folosită." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Eroare la încercarea de a crea contul, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Contul %s%s%s a fost creat cu succes." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "O cheie de resetare a parolei a fost trimisă la adresa ta de e-mail." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clic pe legătura către Autentificare pentru a-ți folosi contul." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nu a fost efectuată nicio modificare asupra contului, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Contul %s%s%s a fost modificat cu succes." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Formularul de autentificare a fost dezactivat pentru adresa ta IP, probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +msgstr "" +"Formularul de autentificare a fost dezactivat pentru adresa ta IP, probabil " +"datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cont suspendat" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Parola ta a fost resetată. Dacă tocmai ai creat un cont nou, folosește legătura din e-mailul de confirmare pentru a seta o parolă inițială. Altfel, cere o resetare a parolei din pagina %sResetare parolă%s." +msgstr "" +"Parola ta a fost resetată. Dacă tocmai ai creat un cont nou, folosește " +"legătura din e-mailul de confirmare pentru a seta o parolă inițială. Altfel, " +"cere o resetare a parolei din pagina %sResetare parolă%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nume de utilizator sau parolă greșite." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "A apărut o eroare în timp ce se genera sesiunea de utilizator." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinație e-mail și cheie pentru resetare nevalidă." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nimic" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Vezi informații despre contul lui %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Comentariul a fost adăugat." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "" +"Trebuie să fi autentificat înainte de a putea modifica informațiile " +"pachetului." + +msgid "Missing comment ID." +msgstr "ID-ul comentariului lipsește" + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Eroare la preluarea detaliilor pachetului." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Detaliile pachetului nu pot fi găsite." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Trebuie să fi autentificat înainte de a putea marca pachetele." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nu ai selectat niciun pachet pentru a fi marcat" -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Pachetele selectate au fost marcate ca fiind Neactualizate." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "Trebuie să fi autentificat înainte de a putea elimina marcajul de Neactualizat al pachetelor." +msgstr "" +"Trebuie să fi autentificat înainte de a putea elimina marcajul de " +"Neactualizat al pachetelor." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nu ai selectat niciun pachet pentru a-i fi eliminat marcajul." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "La pachetele selectate a fost eliminat marcajul de Neactualizat." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nu ai permisiune pentru a șterge pachete." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nu ai selectat niciun pachet pentru a fi șters." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Pachetele selectate au fost șterse." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Trebuie să fi autentificat înainte de a putea adopta pachete." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Trebuie să te autentifici înainte de a abandona pachete." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nu ai selectat niciun pachet pentru a-l adopta." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nu ai selectat niciun pachet pentru a-l abandona." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Pachetele selectate au fost adoptate." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Pachetele selectate au fost abandonate." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Trebuie să fi autentificat înainte de a putea vota pentru pachete." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "Trebuie să fi autentificat înainte de a putea șterge voturile pachetelor." +msgstr "" +"Trebuie să fi autentificat înainte de a putea șterge voturile pachetelor." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nu ai selectat niciun pachet pentru a vota." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Voturile tale au fost șterse de la pachetele selectate." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Voturile au fost exprimate pentru pachetele selectate." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nu am putut adăuga la lista de notificări." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Ai fost adăugat în lista de notificare a comentariilor pentru %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "Ai fost șters din lista de notificare pentru comentarii pentru pachetul %s." +msgstr "" +"Ai fost șters din lista de notificare pentru comentarii pentru pachetul %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Trebuie să fi autentificat înainte de a putea modifica informațiile pachetului." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "ID-ul comentariului lipsește" +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Comentariul a fost șters." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nu ai voie să ștergi acest comentariu." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Comentariul a fost șters." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vezi detaliile pachetelor pentru" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Trebuie să fi autentificat pentru a înregistra cereri pentru pachet." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Numele nu este valid: doar litere mici sunt permise." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Câmpul pentru comentariu nu trebuie lăsat necompletat." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tip de cerere nevalidă." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Cererea a fost adăugată cu succes." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Motiv nevalid." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Doar TU și dezvoltatorii pot închide cererile." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Cerere închisă cu succes." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Poți folosi acest formular pentru a șterge permanent contul AUR %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWARNING%s: Acestă acțiune nu poate fi anulată." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmă ștergerea" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nume utilizator" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip cont" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilizator" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Dezvoltator" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Utilizator de încredere (TU) & Dezvoltator" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresă email" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nume real" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Pseudonim IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Amprentă cheie PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Stare" -#: template/account_details.php msgid "Inactive since" msgstr "Inactiv din" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activ" -#: template/account_details.php msgid "Last Login" msgstr "Ultima autentificare" -#: template/account_details.php msgid "Never" msgstr "Niciodată" -#: template/account_details.php msgid "View this user's packages" msgstr "Vezi pachetele acestui utilizator" -#: template/account_details.php msgid "Edit this user's account" msgstr "Modifică contul acestui utilizator" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clic %saici%s dacă dorești să ștergi definitiv acest cont." -#: template/account_edit_form.php msgid "required" msgstr "cerut" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilizator obișnuit" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cont suspendat" -#: template/account_edit_form.php msgid "Inactive" msgstr "Inactiv" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Rescrie parola" -#: template/account_edit_form.php msgid "Language" msgstr "Limbă" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "Notifică pentru comentarii noi" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "Actualizare" -#: template/account_edit_form.php msgid "Create" msgstr "Creează" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetează" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nici un rezultat nu s-a încadrat în criteriile de căutare." -#: template/account_search_results.php msgid "Edit Account" msgstr "Modificare cont" -#: template/account_search_results.php msgid "Suspended" msgstr "Suspendat" -#: template/account_search_results.php msgid "Edit" msgstr "Modifică" -#: template/account_search_results.php msgid "Less" msgstr "Mai puțin" -#: template/account_search_results.php msgid "More" msgstr "Mai mult" -#: template/account_search_results.php msgid "No more results to display." msgstr "Nu mai sunt rezultate de afișat." -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "Pachetele mele" -#: template/header.php msgid " My Account" msgstr "Contul meu" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Operațiuni" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Examinează PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Caută în wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Marcat ca Neactualizat" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marchează pachetul ca Neactualizat" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Elimină marcaj pachet" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Elimină vot" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votează acest pachet" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "Dezactivează notificări" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "Notifică pentru comentarii noi" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1279,232 +1045,184 @@ msgstr[0] "%d cerere în așteptare" msgstr[1] "%d cereri în așteptare" msgstr[2] "%d de cereri în așteptare" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Șterge pachet" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Fuzionează pachet" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptă pachet" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "necunoscut" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalii pachet de bază" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Cuvinte cheie" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Autor" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Responsabil" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ultimul autor de pachet" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Voturi" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prima trimitere" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ultima actualizare" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adaugă comentariu" -#: template/pkg_comments.php msgid "View all comments" msgstr "Vizualizează toate comentariile" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Ultimele comentarii" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Șterge comentariu" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Toate comentariile" -#: template/pkg_details.php msgid "Package Details" msgstr "Detalii pachet" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pachet de bază" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descriere" -#: template/pkg_details.php msgid "Upstream URL" msgstr "URL upstream" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Vizitează pagina web pentru" -#: template/pkg_details.php msgid "Licenses" msgstr "Licențe" -#: template/pkg_details.php msgid "Groups" msgstr "Grupuri" -#: template/pkg_details.php msgid "Conflicts" msgstr "Conflicte" -#: template/pkg_details.php msgid "Provides" msgstr "Furnizează" -#: template/pkg_details.php msgid "Replaces" msgstr "Înlocuiește" -#: template/pkg_details.php msgid "Dependencies" msgstr "Dependențe" -#: template/pkg_details.php msgid "Required by" msgstr "Cerut de" -#: template/pkg_details.php msgid "Sources" msgstr "Surse" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Închide cererea: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Folosește acest formular pentru a închide cererea pentru pachetul de bază %s%s%s." +msgstr "" +"Folosește acest formular pentru a închide cererea pentru pachetul de bază %s" +"%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Notă" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Câmpul pentru comentarii poate fi lăsat necompletat. Este totuși foarte recomandat să adaugi un comentariu când respingi o cerere." +msgstr "" +"Câmpul pentru comentarii poate fi lăsat necompletat. Este totuși foarte " +"recomandat să adaugi un comentariu când respingi o cerere." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motiv" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Acceptat" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Respins" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Înregistrează cerere: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Folosește acest formular pentru a înregistra o cerere pentru pachetul de bază %s%s%s care cuprinde următoarele pachete:" +msgstr "" +"Folosește acest formular pentru a înregistra o cerere pentru pachetul de " +"bază %s%s%s care cuprinde următoarele pachete:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Tipul de cerere" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Ștergere" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfan" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fuzionează" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1512,29 +1230,23 @@ msgstr[0] "%d cerere pentru pachet găsită" msgstr[1] "%d cereri pentru pachet găsite" msgstr[2] "%d de cereri pentru pachet găsite" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d din %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Pachet" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Depusă de" -#: template/pkgreq_results.php msgid "Date" msgstr "Data" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d zile rămase" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1542,116 +1254,87 @@ msgstr[0] "~%d oră rămasă" msgstr[1] "~%d ore rămase" msgstr[2] "~%d de ore rămase" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 oră a rămas" -#: template/pkgreq_results.php msgid "Accept" msgstr "Acceptă" -#: template/pkgreq_results.php msgid "Locked" msgstr "Blocat" -#: template/pkgreq_results.php msgid "Close" msgstr "Închide" -#: template/pkgreq_results.php msgid "Closed" msgstr "Închis" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nume, Descriere" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Doar nume" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nume exact" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pachet de bază exact" -#: template/pkg_search_form.php msgid "All" msgstr "Toate" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcate" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nemarcate" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nume" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votat" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Crescător" -#: template/pkg_search_form.php msgid "Descending" msgstr "Descrescător" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introdu criteriul de căutare" -#: template/pkg_search_form.php msgid "Search by" msgstr "Caută după" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Neactualizate" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortează după" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordinea sortării" -#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagină" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Înainte" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfane" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Eroare la preluarea listei de pachete." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Niciun pachet nu s-a potrivit criteriului de căutare." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1659,154 +1342,116 @@ msgstr[0] "%d pachet găsit" msgstr[1] "%d pachete găsite" msgstr[2] "%d de pachete găsite" -#: template/pkg_search_results.php msgid "Version" msgstr "Versiune" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Da" -#: template/pkg_search_results.php msgid "orphan" msgstr "orfan" -#: template/pkg_search_results.php msgid "Actions" msgstr "Acțiuni" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Marchează ca Neactualizat" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Elimină marcajul de Neactualizat" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptă pachete" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonează pachete" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Șterge pachete" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmare" -#: template/search_accounts_form.php msgid "Any type" msgstr "Orice tip" -#: template/search_accounts_form.php msgid "Search" msgstr "Caută" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistici" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pachete orfane" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pachete adăugate în ultimele 7 zile" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pachete actualizate în ultimele 7 zile" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pachete actualizate în ultimul an" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pachete niciodată actualizate" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilizatori înregistrați" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted users" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizări recente" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Statisticile mele" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detaliile propunerii." -#: template/tu_details.php msgid "This vote is still running." msgstr "Această votare este încă în desfășurare." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Trimis: %s de %s " -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Sfârșit" -#: template/tu_details.php msgid "Result" msgstr "Rezultat" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nu" -#: template/tu_details.php msgid "Abstain" msgstr "Abținere" -#: template/tu_details.php msgid "Total" msgstr "Total" -#: template/tu_details.php msgid "Participation" msgstr "Participare" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ultimele voturi de la un TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ultimul vot" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Niciun rezultat găsit" -#: template/tu_list.php msgid "Start" msgstr "Start" -#: template/tu_list.php msgid "Back" msgstr "Înapoi" diff --git a/po/ru.po b/po/ru.po index 061f2ab8..e55f487f 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,9 +1,10 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Evgeniy Alekseev , 2014-2015 +# Evgeniy Alekseev , 2014-2015, 2016 # Kyrylo Silin , 2011 # Kyrylo Silin , 2011 # Lukas Fleischer , 2011 @@ -13,1268 +14,1070 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/ru/)\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-11 08:38+0000\n" +"Last-Translator: Evgeniy Alekseev \n" +"Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" +"ru/)\n" +"Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ru\n" -"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" -#: html/404.php msgid "Page Not Found" msgstr "Страница не найдена" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Извините, запрошенная страница не существует." -#: html/503.php msgid "Service Unavailable" msgstr "Сервис недоступен" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "Не паниковать! Сайт недоступен из-за работ. Скоро мы вернемся назад." -#: html/account.php msgid "Account" msgstr "Аккаунт" -#: html/account.php template/header.php msgid "Accounts" msgstr "Учетные записи" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "У вас нет доступа сюда." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Не удалось получить информацию об указанном пользователе." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Вы не имеете права редактировать эту учетную запись." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Используйте эту форму для поиска существующих учетных записей." -#: html/account.php msgid "You must log in to view user information." -msgstr "Вы должны представиться для того, чтобы посмотреть информацию о пользователе." +msgstr "" +"Вы должны представиться для того, чтобы посмотреть информацию о пользователе." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Добавить предложение" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Неверная метка для действия пользователя." -#: html/addvote.php msgid "Username does not exist." msgstr "Имя пользователя не существует." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "За %s уже идет голосование." -#: html/addvote.php msgid "Invalid type." msgstr "Неправильный тип" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Предложение не может быть пустым." -#: html/addvote.php msgid "New proposal submitted." msgstr "Новое предложение принято." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Отправить предложение." -#: html/addvote.php msgid "Applicant/TU" msgstr "Кандидат/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(пусто если не нужно)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Тип" -#: html/addvote.php msgid "Addition of a TU" msgstr "Добавление TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Удаление TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Удаление TU (неактивность без уведомлений)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Внесение изменений в Устав" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Предложение" -#: html/addvote.php msgid "Submit" msgstr "Прислать" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Управление ответственными" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Редактировать комментарий" -#: html/home.php template/header.php msgid "Home" msgstr "Главная" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Добро пожаловать в AUR! Пожалуйста, ознакомьтесь с %sРуководством пользователя AUR%s и с %sРуководством доверенного пользователя AUR%s, чтобы узнать больше." +msgstr "" +"Добро пожаловать в AUR! Пожалуйста, ознакомьтесь с %sРуководством " +"пользователя AUR%s и с %sРуководством доверенного пользователя AUR%s, чтобы " +"узнать больше." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Присланные пэкиджбилды (англ. PKGBUILD) %sдолжны%s соответствовать %sстандартам создания пакетов для Арча%s, иначе они будут удалены!" +msgstr "" +"Присланные пэкиджбилды (англ. PKGBUILD) %sдолжны%s соответствовать " +"%sстандартам создания пакетов для Арча%s, иначе они будут удалены!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Не забывайте голосовать за понравившиеся вам пакеты!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "В хранилище [community] некоторые пакеты могут быть представлены в бинарном виде." +msgstr "" +"В хранилище [community] некоторые пакеты могут быть представлены в бинарном " +"виде." -#: html/home.php msgid "DISCLAIMER" msgstr "Отказ от ответственности" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Пакеты в AUR содержат предоставленный пользователями контент. Любое " +"использование предоставляемых файлов выполняйте на свой риск." -#: html/home.php msgid "Learn more..." msgstr "Больше..." -#: html/home.php msgid "Support" msgstr "Поддержка" -#: html/home.php msgid "Package Requests" msgstr "Запросы по пакету" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Три типа запросов могут быть посланы с использованием %sДействия над пакетом%s на странице пакета:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Три типа запросов могут быть посланы с использованием %sДействия над пакетом" +"%s на странице пакета:" -#: html/home.php msgid "Orphan Request" msgstr "Запрос на сброс сопровождающего" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Запросить, чтобы пакет быть лишен сопровождающего, например, если текущий сопровождающий неактивен и пакет давно помечен, как устаревший." +msgstr "" +"Запросить, чтобы пакет быть лишен сопровождающего, например, если текущий " +"сопровождающий неактивен и пакет давно помечен, как устаревший." -#: html/home.php msgid "Deletion Request" msgstr "Запрос на удаление" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Запросить удаление пакета из AUR. Пожалуйста, не используйте это действие, если пакет не собирается и это может быть легко исправлено. Вместо этого, свяжитесь с сопровождающим и отправьте запрос на смену сопровождающего, если необходимо." +msgstr "" +"Запросить удаление пакета из AUR. Пожалуйста, не используйте это действие, " +"если пакет не собирается и это может быть легко исправлено. Вместо этого, " +"свяжитесь с сопровождающим и отправьте запрос на смену сопровождающего, если " +"необходимо." -#: html/home.php msgid "Merge Request" msgstr "Запрос объединения" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Запросить объединение пакета с другим. Может быть использовано, когда пакет необходимо переименовать или заменить другим." +msgstr "" +"Запросить объединение пакета с другим. Может быть использовано, когда пакет " +"необходимо переименовать или заменить другим." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Если вы хотите обсудить запрос, вы можете использовать список рассылки %saur-requests%s. Однако, пожалуйста, не используйте список рассылки для отправки запросов." +msgstr "" +"Если вы хотите обсудить запрос, вы можете использовать список рассылки %saur-" +"requests%s. Однако, пожалуйста, не используйте список рассылки для отправки " +"запросов." -#: html/home.php msgid "Submitting Packages" msgstr "Загрузка пакетов" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "На текущий момент для загрузки пакетов в AUR используется Git через SSH. Смотри %sЗагрузка пакетов%s в ArchWiki для более подробной информации." +msgstr "" +"На текущий момент для загрузки пакетов в AUR используется Git через SSH. " +"Смотри %sЗагрузка пакетов%s в ArchWiki для более подробной информации." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Следующие отпечатки ключей используются AUR:" -#: html/home.php msgid "Discussion" msgstr "Обсуждение" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Общее обсуждение Пользовательского Репозитория ArchLinux (AUR) и структуры Доверенных Пользователей ведется в %saur-general%s. Для обсуждение разработки веб-интерфейса AUR используйте %saur-dev%s." +msgstr "" +"Общее обсуждение Пользовательского Репозитория ArchLinux (AUR) и структуры " +"Доверенных Пользователей ведется в %saur-general%s. Для обсуждение " +"разработки веб-интерфейса AUR используйте %saur-dev%s." -#: html/home.php msgid "Bug Reporting" msgstr "Отчет об ошибке" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" +"Если вы нашли баг в интерфейсе AUR, пожалуйста, отправьте сообщение на %sбаг " +"трекер%s. Используйте данный баг трекер %sтолько%s для сообщениях о багах в " +"AUR. Если вы хотите сообщить о баге в пакете, свяжитесь с сопровождающим, " +"или оставьте комментарий на соответствующей странице." -#: html/home.php msgid "Package Search" msgstr "Поиск пакетов" -#: html/index.php msgid "Adopt" msgstr "Усыновить" -#: html/index.php msgid "Vote" msgstr "Голосовать" -#: html/index.php msgid "UnVote" msgstr "Убрать голос" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Извещать" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Не извещать" -#: html/index.php msgid "UnFlag" msgstr "Снять метку" -#: html/login.php template/header.php msgid "Login" msgstr "Войти" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Вы вошли как: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Выход" -#: html/login.php msgid "Enter login credentials" msgstr "Введите учётные данные" -#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Имя пользователя или email" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Пароль" -#: html/login.php msgid "Remember me" msgstr "Запомнить меня" -#: html/login.php msgid "Forgot Password" msgstr "Забыли пароль?" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Вход через HTTP отключен. Пожалуйста, %sпереключитесь на HTTPs%s, чтобы войти." +msgstr "" +"Вход через HTTP отключен. Пожалуйста, %sпереключитесь на HTTPs%s, чтобы " +"войти." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Критерии поиска" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Пакеты" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Ошибка получения информации о пакете." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Отсутствует обязательное значение." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Пароли не совпадают." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Пароль должен быть не менее %s символов." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Неверная электронная почта." -#: html/passreset.php msgid "Password Reset" msgstr "Сброс пароля" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Проверьте свою электронную почту на наличие ссылки подтверждения." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Ваш пароль был успешно переустановлен." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Подтвердите адрес своей электронной почты:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Введите ваш новый пароль:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Подтвердите ваш новый пароль:" -#: html/passreset.php msgid "Continue" msgstr "Продолжить" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Если вы забыли электронный адрес, который вы использовали для регистрации, пожалуйста, отошлите сообщение в список рассылки %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Если вы забыли электронный адрес, который вы использовали для регистрации, " +"пожалуйста, отошлите сообщение в список рассылки %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Введите свой адрес электронной почты:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Выбранные пакеты будут брошены." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Не могу найти пакет для объединения с ним голосов и комментариев." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Невозможно объединить группу пакетов с самой собой." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "Выбранные пакеты не были удалены. Поставьте галочку для подтверждения." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Удаление пакета" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Удалить пакет: %s" +msgid "Delete Package" +msgstr "Удалить пакет" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "Используйте эту форму, чтобы удалить группу пакетов %s%s%s из AUR:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Удаление пакета необратимо." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Активируйте чекбокс для подтверждения действия." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Подтвердите удаление пакета" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Удалить" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Только Доверенные Пользователи и Разработчики могут удалять пакеты." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Бросить пакет" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Бросить пакет: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Используйте данную форму, чтобы бросить группу пакетов %s%s%s, которая включает в себя следующие пакеты:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Используйте данную форму, чтобы бросить группу пакетов %s%s%s, которая " +"включает в себя следующие пакеты:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Ставя галочку, вы подтверждаете, что хотите бросить пакеты и сделать сопровождающим %s%s%s." +msgstr "" +"Ставя галочку, вы подтверждаете, что хотите бросить пакеты и сделать " +"сопровождающим %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Ставя галочку, вы подтверждаете, что хотите бросить пакет." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Подтвердите отказ от пакета" -#: html/pkgdisown.php msgid "Disown" msgstr "Бросить" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Только Доверенные Пользователи или разработчики могут бросить пакеты." -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "Отметить комментарий" + msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Отметить пакет устаревшим" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" +"Используйте данную форму, чтобы отметить устаревшими группу пакетов %s%s%s, " +"которая включает в себя следующие пакеты:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"Пожалуйста %sне%s используйте данную форму для сообщения об ошибке. " +"Используйте для этого комментарии." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Введите описание, почему данные пакет устарел; добавление ссылок на новость " +"о релизе или архив с новой версией предпочтительно." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Комментарии" -#: html/pkgflag.php msgid "Flag" msgstr "Пометить" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +"Только зарегистрированные пользователи могут отметить пакет устаревшим." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Объединение пакетов" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Объединить пакет: %s" +msgid "Merge Package" +msgstr "Объединить пакеты" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Используйте эту форму, чтобы объединить группу пакетов %s%s%s с другим пакетом." +msgstr "" +"Используйте эту форму, чтобы объединить группу пакетов %s%s%s с другим " +"пакетом." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Следующие пакеты будут удалены:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Объединение пакетов — необратимое действие." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Введите имя пакета, с которым вы хотите объединить этот пакет." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Объединить с:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Подтвердить объединение пакетов" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Объединить" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Только Доверенные Пользователи и Разработчики могут объединять пакеты." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Запрос действия" +msgid "Submit Request" +msgstr "Отправить запрос" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Закрыть запрос" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Первый" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Назад" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далее" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Последний" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Запросы" -#: html/register.php template/header.php msgid "Register" msgstr "Регистрация" -#: html/register.php msgid "Use this form to create an account." msgstr "Используйте эту форму для создания учетной записи." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Доверенный пользователь" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Не получилось показать предложение." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Голосование закрыто." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Только Доверенные Пользователи имеют право голоса." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Нельзя голосовать за себя." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Вы уже проголосовали." -#: html/tu.php msgid "Vote ID not valid." msgstr "Идентификатор голосование неверный." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Сейчас голосов" -#: html/tu.php msgid "Past Votes" msgstr "Прошлые голоса" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Голосовавшие" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Регистрация аккаунтов с вашего IP адреса запрещена, возможная причина проблемы — спам-атаки. Извините за неудобства." +msgstr "" +"Регистрация аккаунтов с вашего IP адреса запрещена, возможная причина " +"проблемы — спам-атаки. Извините за неудобства." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Отсутствует идентификатор пользователя" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Неверное имя пользователя." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Длина должна быть от %s до %s символов" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Начинаются и заканчиваются цифрой или буквой" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Может содержать только одну запятую, подчёркивание или тире." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Неправильный адрес электронной почты." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Неверный отпечаток ключа PGP." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Публичный SSH ключ неправильный." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Невозможно повысить привилегии." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Язык пока не поддерживается." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Имя пользователя, %s%s%s, уже используется." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Адрес %s%s%s уже используется." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Публичный SSH ключ %s%s%s уже используется." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Ошибка при создании аккаунта %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Учетная запись %s%s%s была успешно создана." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ключ для смены пароля был отправлен на ваш электронный адрес." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Нажмите на ссылку для входа вверху чтобы зайти." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "С аккаунтом %s%s%s не произведено никаких действий." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Учетная запись %s%s%s успешно изменена." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Доступ к форме входа с вашего IP адреса запрещен, возможная причина проблемы — спам-атаки. Извините за неудобства." +msgstr "" +"Доступ к форме входа с вашего IP адреса запрещен, возможная причина проблемы " +"— спам-атаки. Извините за неудобства." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Действие аккаунта приостановлено." -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Ваш пароль был сброшен. Если вы только что создали аккаунт, пожалуйста используйте ссылку из письма подтверждения чтобы установить начальный пароль. В противном случае, запросите ключ для сброса на странице %sСброс пароля%s." +msgstr "" +"Ваш пароль был сброшен. Если вы только что создали аккаунт, пожалуйста " +"используйте ссылку из письма подтверждения чтобы установить начальный " +"пароль. В противном случае, запросите ключ для сброса на странице %sСброс " +"пароля%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Неверно указаны имя пользователя или пароль." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Произошла ошибка при создании пользовательской сессии." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Неверная электронная почта и комбинация сброса ключа." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Нет" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Просмотр информации об аккаунте %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." -msgstr "" +msgstr "ID или имя группы пакетов отсутствует." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Вы не можете редактировать данный комментарий." -#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "Комментарий не существует." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "Комментарий не может быть пустым." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Комментарий добавлен." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Вы должны представиться прежде чем редактировать информацию о пакете." + +msgid "Missing comment ID." +msgstr "Идентификатор комментария отсутствует." + +msgid "No more than 5 comments can be pinned." +msgstr "Не более 5 комментариев могут быть прикреплены." + +msgid "You are not allowed to pin this comment." +msgstr "Вы не можете прикрепить данный комментарий." + +msgid "You are not allowed to unpin this comment." +msgstr "Вы не можете открепить данный комментарий." + +msgid "Comment has been pinned." +msgstr "Комментарий был прикреплен." + +msgid "Comment has been unpinned." +msgstr "Комментарий был откреплен." + msgid "Error retrieving package details." msgstr "Ошибка получения информации о пакете." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Не найдена информация о пакете." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Вы должны войти прежде чем расставлять флажки на пакеты." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Вы не выбрали ни одного пакета для пометки." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Выбранные пакеты не были отмечены, пожалуйста, введите комментарий." + msgid "The selected packages have been flagged out-of-date." msgstr "Выбранные пакеты помечены как устаревшие." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Вы должны войти прежде чем снимать флажки." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Вы не выбрали ни одного пакета для снятия пометки." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "С выбранных пакетов пометка снята." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "У вас нет права на удаление пакетов." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Вы не выбрали ни одного пакета для удаления." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Выбранные пакеты удалены." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Вы должны войти прежде чем усыновлять пакеты." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Вы должны войти прежде чем бросать пакеты." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Вы не выбрали ни одного пакета для усыновления." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Вы не выбрали ни одного пакета чтобы бросить." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Выбранные пакеты усыновлены." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Выбранные пакеты брошены." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Вы должны войти прежде чем голосовать." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Вы должны войти прежде чем снимать голос с пакета." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Вы не выбрали ни одного пакета для голосования." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Ваш голос убран с выбранного пакета." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Вы проголосовали за выбранные пакеты." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Невозможно добавить в список получателей извещений." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Вы добавлены в список извещений для %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Вам больше не будут приходить извещения от %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Вы должны представиться прежде чем редактировать информацию о пакете." +msgid "You are not allowed to undelete this comment." +msgstr "Вы не можете отменить удаление данного комментария." -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Идентификатор комментария отсутствует." +msgid "Comment has been undeleted." +msgstr "Комментарий был восстановлен." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Комментарий удален." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "У вас нет прав для удаления этого комментария." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been edited." -msgstr "" +msgid "Comment has been deleted." +msgstr "Комментарий удален." + +msgid "Comment has been edited." +msgstr "Комментарий был отредактирован." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Вы не можете редактировать ключевые слова данной группы пакетов." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ключевые слова были обновлены." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Вы не можете управлять сопровождающими данной группы пакетов." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Неправильное имя пользователя: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Сопровождающие пакета были обновлены." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Просмотреть информацию о пакете" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" -msgstr "" +msgstr "требует %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Вы должны войти, чтобы отправить запрос по пакету." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Неверное имя: только нижний регистр допустим." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Поле комментариев должно быть заполнено." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Неправильный тип запроса." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Запрос добавлен успешно." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Неправильная причина." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "Только Доверенные пользователи или разработчики могут закрывать запросы." +msgstr "" +"Только Доверенные пользователи или разработчики могут закрывать запросы." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Запрос закрыт успешно." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Вы можете использовать данную форму, чтобы удалить следующий аккаунт AUR: %s." +msgstr "" +"Вы можете использовать данную форму, чтобы удалить следующий аккаунт AUR: %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sПРЕДУПРЕЖДЕНИЕ%s: Данное действие не может быть отменено." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Подтвердите удаление" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Имя пользователя" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Тип учетной записи" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Пользователь" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Разработчик" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Доверенные пользователи и Разработчики" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Адрес электронной почты" -#: template/account_details.php msgid "hidden" -msgstr "" +msgstr "скрыто" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Настоящее имя" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Ник" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Отпечаток ключа PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Статус" -#: template/account_details.php msgid "Inactive since" msgstr "Неактивен с" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Активный" -#: template/account_details.php msgid "Last Login" msgstr "Последний вход" -#: template/account_details.php msgid "Never" msgstr "Никогда" -#: template/account_details.php msgid "View this user's packages" msgstr "Посмотреть пакеты этого пользователя" -#: template/account_details.php msgid "Edit this user's account" msgstr "Отредактировать этот аккаунт" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Нажмите %sздесь%s, если Вы хотите удалить данный аккаунт насовсем." -#: template/account_edit_form.php msgid "required" msgstr "необходимо" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Обычный пользователь" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Доверенный пользователь" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Действие учетной записи приостановлено" -#: template/account_edit_form.php msgid "Inactive" msgstr "Неактивен" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Пожалуйста убедитесь, что Вы корректно ввели Ваш email; в противном случае " +"вы будете заблокированы." -#: template/account_edit_form.php msgid "Hide Email Address" -msgstr "" +msgstr "Скрыть email." -#: template/account_edit_form.php msgid "Re-type password" msgstr "Введите пароль еще раз" -#: template/account_edit_form.php msgid "Language" msgstr "Язык" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "Только следующая необходима, если вы хотите загрузить пакеты в AUR." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Публичный SSH ключ" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Обновить" +msgid "Notification settings" +msgstr "Настройки уведомлений" -#: template/account_edit_form.php -msgid "Create" -msgstr "Создать" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Очистить" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "По вашему запросу ничего не найдено." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Изменить учетную запись" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Приостановлена" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Редактировать" - -#: template/account_search_results.php -msgid "Less" -msgstr "Назад" - -#: template/account_search_results.php -msgid "More" -msgstr "Далее" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Больше нет результатов." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Управление сопровождающими: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Используйте данную форму, чтобы добавить сопровождающих для %s%s%s (используйте одно имя на строку):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Пользователи" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Сохранить" - -#: template/header.php -msgid "My Packages" -msgstr "Мои пакеты" - -#: template/header.php -msgid " My Account" -msgstr "Моя учётная запись" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Действия над пакетом" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Просмотреть PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Посмотреть изменения" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Загрузить снимок" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Искать в Wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Помечен как устаревший" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Пометить пакет как устаревший" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Снять пометку" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Удалить голос" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Проголосовать за пакет" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Выключить уведомления" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Уведомлять о новых комментариях" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "Уведомлять об обновлении пакета" + +msgid "Update" +msgstr "Обновить" + +msgid "Create" +msgstr "Создать" + +msgid "Reset" +msgstr "Очистить" + +msgid "No results matched your search criteria." +msgstr "По вашему запросу ничего не найдено." + +msgid "Edit Account" +msgstr "Изменить учетную запись" + +msgid "Suspended" +msgstr "Приостановлена" + +msgid "Edit" +msgstr "Редактировать" + +msgid "Less" +msgstr "Назад" + +msgid "More" +msgstr "Далее" + +msgid "No more results to display." +msgstr "Больше нет результатов." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Используйте данную форму, чтобы добавить сопровождающих для %s%s%s " +"(используйте одно имя на строку):" + +msgid "Users" +msgstr "Пользователи" + +msgid "Save" +msgstr "Сохранить" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "Комментарий: %s" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "%s%s%s отметил %s%s%s устаревшим %s%s%s по следующей причине:" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "%s%s%s не отмечен устаревшим." + +msgid "Return to Details" +msgstr "Вернуться к деталям" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Copyright %s 2004-%d aurweb Development Team." + +msgid "My Packages" +msgstr "Мои пакеты" + +msgid " My Account" +msgstr "Моя учётная запись" + +msgid "Package Actions" +msgstr "Действия над пакетом" + +msgid "View PKGBUILD" +msgstr "Просмотреть PKGBUILD" + +msgid "View Changes" +msgstr "Посмотреть изменения" + +msgid "Download snapshot" +msgstr "Загрузить снимок" + +msgid "Search wiki" +msgstr "Искать в Wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "Отмечет устаревшим (%s)" + +msgid "Flag package out-of-date" +msgstr "Пометить пакет как устаревший" + +msgid "Unflag package" +msgstr "Снять пометку" + +msgid "Remove vote" +msgstr "Удалить голос" + +msgid "Vote for this package" +msgstr "Проголосовать за пакет" + +msgid "Disable notifications" +msgstr "Выключить уведомления" + msgid "Manage Co-Maintainers" msgstr "Управление сопровождающими" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1283,232 +1086,182 @@ msgstr[1] "%d запроса в обработке" msgstr[2] "%d запросов в обработке" msgstr[3] "%d запросов в обработке" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Удалить пакет" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Объединить пакеты" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Усыновить пакет" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "неизвестно" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Информация по группе пакетов" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL для git clone" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "только чтение" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Ключевые слова" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Автор" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ответственный" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Последний приславший" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Голосов" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Популярность" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Впервые послан" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Последнее обновление" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Редактировать комментарий для: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Добавить комментарий" -#: template/pkg_comments.php msgid "View all comments" msgstr "Посмотреть все комментарии" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "Закрепленные комментарии" + msgid "Latest Comments" msgstr "Последние комментарии" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s прокомментировал %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Анонимный комментарий для %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "удален для %s %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "" +msgid "deleted on %s" +msgstr "удален %s" + +#, php-format +msgid "edited on %s by %s" +msgstr "отредактирован %s %s" + +#, php-format +msgid "edited on %s" +msgstr "отредактирован %s" + +msgid "Undelete comment" +msgstr "Восстановить комментарий" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Удалить комментарий" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "Закрепить комментарий" + +msgid "Unpin comment" +msgstr "Открепить комментарий" + msgid "All comments" msgstr "Все комментарии" -#: template/pkg_details.php msgid "Package Details" msgstr "Информация о пакете" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Группа пакетов" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Описание" -#: template/pkg_details.php msgid "Upstream URL" msgstr "URL апстрима" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Посетить сайт" -#: template/pkg_details.php msgid "Licenses" msgstr "Лицензия" -#: template/pkg_details.php msgid "Groups" msgstr "Группы" -#: template/pkg_details.php msgid "Conflicts" msgstr "Конфликтует" -#: template/pkg_details.php msgid "Provides" msgstr "Предоставляет" -#: template/pkg_details.php msgid "Replaces" msgstr "Заменяет" -#: template/pkg_details.php msgid "Dependencies" msgstr "Зависимости" -#: template/pkg_details.php msgid "Required by" msgstr "Требуется пакетами" -#: template/pkg_details.php msgid "Sources" msgstr "Исходники" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Закрыть запрос %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Используйте эту форму, чтобы закрыть запрос о группе пакетов %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Примечание" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "При отклонении запроса рекомендуется заполнить поле комментарий (не обязательно)." +msgstr "" +"При отклонении запроса рекомендуется заполнить поле комментарий (не " +"обязательно)." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Причина" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Принято" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Отклонено" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Запрос: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Используйте данную форму, чтобы послать запрос по поводу группы пакетов %s%s%s, которая включает следующие пакеты:" +msgstr "" +"Используйте данную форму, чтобы послать запрос по поводу группы пакетов %s%s" +"%s, которая включает следующие пакеты:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Тип запроса" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Удаление" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Сделать сиротой" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Объединить с" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1517,29 +1270,23 @@ msgstr[1] "Найдены запросы для %d пакетов." msgstr[2] "Найдены запросы для %d пакетов." msgstr[3] "Найдены запросы для %d пакетов." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Страница %d из %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Пакет" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Послан" -#: template/pkgreq_results.php msgid "Date" msgstr "Дата" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "осталось ~%d дней" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1548,116 +1295,87 @@ msgstr[1] "осталось ~%d часа" msgstr[2] "осталось ~%d часов" msgstr[3] "осталось ~%d часов" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "осталось меньше часа" -#: template/pkgreq_results.php msgid "Accept" msgstr "Принять" -#: template/pkgreq_results.php msgid "Locked" msgstr "Заблокировано" -#: template/pkgreq_results.php msgid "Close" msgstr "Закрыть" -#: template/pkgreq_results.php msgid "Closed" msgstr "Закрыт" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Название, описание" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Только название" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Точное имя" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Точное имя группы" -#: template/pkg_search_form.php msgid "All" msgstr "Все" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Отмеченные" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Неотмеченные" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Имя" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Мой голос" -#: template/pkg_search_form.php msgid "Last modified" -msgstr "" +msgstr "Последнее обновление" -#: template/pkg_search_form.php msgid "Ascending" msgstr "По возрастанию" -#: template/pkg_search_form.php msgid "Descending" msgstr "По убыванию" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Введите критерии поиска" -#: template/pkg_search_form.php msgid "Search by" msgstr "Искать по" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Устарел" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Сортировать по" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Порядок сортировки" -#: template/pkg_search_form.php msgid "Per page" msgstr "Постранично" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Поехали" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Сироты" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Ошибка получения списка пакетов." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Нет пакетов по выбранному критерию поиска." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1666,154 +1384,119 @@ msgstr[1] "Найдено %d пакета." msgstr[2] "Найдено %d пакетов." msgstr[3] "Найдено %d пакетов." -#: template/pkg_search_results.php msgid "Version" msgstr "Версия" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "Популярность считается, как сумма всех голосов, где каждый голос взвешен с коэффициентом 0.98 за каждый день разницы между днем голосования и днем загрузки пакета." +msgstr "" +"Популярность считается, как сумма всех голосов, где каждый голос взвешен с " +"коэффициентом 0.98 за каждый день разницы между днем голосования и днем " +"загрузки пакета." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Да" -#: template/pkg_search_results.php msgid "orphan" msgstr "сирота" -#: template/pkg_search_results.php msgid "Actions" msgstr "Действия" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Пометить как Устаревший" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Убрать флаг Устаревший" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Усыновить пакеты" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Бросить пакеты" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Удалить пакеты" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Подтвердить" -#: template/search_accounts_form.php msgid "Any type" msgstr "Любой тип" -#: template/search_accounts_form.php msgid "Search" msgstr "Поиск" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Статистика" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Пакеты-сироты" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Пакеты, добавленные за прошедшие 7 дней" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Пакеты, обновленные за прошедшие 7 дней" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Пакеты, обновленные за прошедший год" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Пакеты, которые никогда не обновлялись" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Зарегистрированных пользователей" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Доверенных пользователей" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Последние обновления" -#: template/stats/user_table.php +msgid "more" +msgstr "больше" + msgid "My Statistics" msgstr "Моя статистика" -#: template/tu_details.php msgid "Proposal Details" msgstr "Подробнее о предложении" -#: template/tu_details.php msgid "This vote is still running." msgstr "Голосование продолжается." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Получено: %s %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Конец" -#: template/tu_details.php msgid "Result" msgstr "Результат" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Нет" -#: template/tu_details.php msgid "Abstain" msgstr "Воздерживаюсь" -#: template/tu_details.php msgid "Total" msgstr "Всего" -#: template/tu_details.php msgid "Participation" msgstr "Участие" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Последний голос TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Последний голос" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Нет результатов." -#: template/tu_list.php msgid "Start" msgstr "Начало" -#: template/tu_list.php msgid "Back" msgstr "Назад" diff --git a/po/sk.po b/po/sk.po index 2f00a1b9..d96c4ac0 100644 --- a/po/sk.po +++ b/po/sk.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # archetyp , 2013-2015 # Matej Ľach , 2011 @@ -9,1268 +9,1069 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-28 17:44+0000\n" -"Last-Translator: archetyp \n" -"Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/sk/)\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" +"sk/)\n" +"Language: sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: sk\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -#: html/404.php msgid "Page Not Found" msgstr "Stránka nebola nájdená" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Mrzí nás to, ale stránka, ktorú ste zadali, neexistuje." -#: html/503.php msgid "Service Unavailable" msgstr "Služba nie je dostupná" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Zachovajte pokoj. Na stránke momentálne prebieha údržba. Vrátime sa čoskoro." +msgstr "" +"Zachovajte pokoj. Na stránke momentálne prebieha údržba. Vrátime sa čoskoro." -#: html/account.php msgid "Account" msgstr "Účet" -#: html/account.php template/header.php msgid "Accounts" msgstr "Účty" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nemáte potrebné práva pre prístup do tejto oblasti." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nemožno získať informácie pre špecifikovaného užívateľa. " -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemáte potrebné oprávnenia, pre úpravu tohoto účtu. " -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Použite tento formulár pre vyhľadávanie v existujúcich účtoch." -#: html/account.php msgid "You must log in to view user information." msgstr "Musíte sa prihlásiť, pre zobrazenie užívateľských informácií. " -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Pridať návrh" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Neplatný znak pre užívateľskú akciu." -#: html/addvote.php msgid "Username does not exist." msgstr "Užívateľské meno neexistuje." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "O %s už návrh beží." -#: html/addvote.php msgid "Invalid type." msgstr "Neplatný typ." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Návrch nemôže byť prázdny." -#: html/addvote.php msgid "New proposal submitted." msgstr "Nový návrh bol odoslaný." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Odošli návrh na hlasovanie." -#: html/addvote.php msgid "Applicant/TU" msgstr "Adept/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prázdne ak nemožno uplatniť)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Typ" -#: html/addvote.php msgid "Addition of a TU" msgstr "Pridanie TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Odobranie TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Odobranie TU (neohlásená neaktivita)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Zmena stanov" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Návrh" -#: html/addvote.php msgid "Submit" msgstr "Odoslať" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Manažovať spolupracovníkov" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Editovať komentár" -#: html/home.php template/header.php msgid "Home" msgstr "Domov" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Vitajte v AUR! Prečítajte si prosím %sAUR smernicu pre užívateľov%s a %sAUR smernicu pre TU%s pre ďalšie informácie." +msgstr "" +"Vitajte v AUR! Prečítajte si prosím %sAUR smernicu pre užívateľov%s a %sAUR " +"smernicu pre TU%s pre ďalšie informácie." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Prispené PKGBUILDy sa %smusia%s riadiť %sArch podmienkami pre balíčky%s, inak budú vymazané!" +msgstr "" +"Prispené PKGBUILDy sa %smusia%s riadiť %sArch podmienkami pre balíčky%s, " +"inak budú vymazané!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nezabudnite hlasovať za svoje obľúbené balíčky!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Niektoré balíčky môžu byť poskytnuté ako binárky v [community]. " -#: html/home.php msgid "DISCLAIMER" msgstr "UPOZORNENIE" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "Balíčky v AUR sú výsledkom práce užívateľov. Akékoľvek použitie týchto súborov je na vlastnú zodpovednosť." +msgstr "" +"Balíčky v AUR sú výsledkom práce užívateľov. Akékoľvek použitie týchto " +"súborov je na vlastnú zodpovednosť." -#: html/home.php msgid "Learn more..." msgstr "Dozvedieť sa viac..." -#: html/home.php msgid "Support" msgstr "Podpora" -#: html/home.php msgid "Package Requests" msgstr "Žiadosti ohľadom balíčkov" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "V súčasnosti existujú tri typy žiadostí, ktoré možno vyplniť v časti %sAkcie balíčka%s na stránke s detailami balíčka, a to:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"V súčasnosti existujú tri typy žiadostí, ktoré možno vyplniť v časti %sAkcie " +"balíčka%s na stránke s detailami balíčka, a to:" -#: html/home.php msgid "Orphan Request" msgstr "Žiadosť o osirenie" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Žiadosť o odobratie vlastníctva balíčka, napr. ak správca balíčka nie je aktívny a balíček bol dlhšiu dobu označený ako neaktuálny." +msgstr "" +"Žiadosť o odobratie vlastníctva balíčka, napr. ak správca balíčka nie je " +"aktívny a balíček bol dlhšiu dobu označený ako neaktuálny." -#: html/home.php msgid "Deletion Request" msgstr "Žiadosť o vymazanie" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Žiadosť o odstránenie balíčka z AUR. Nepoužívajte prosím túto možnosť v prípade, že balíček je pokazený a možno ho ľahko opraviť. Namiesto toho radšej kontaktujte jeho správcu alebo v prípade nutnosti požiadajte o jeho osirenie." +msgstr "" +"Žiadosť o odstránenie balíčka z AUR. Nepoužívajte prosím túto možnosť v " +"prípade, že balíček je pokazený a možno ho ľahko opraviť. Namiesto toho " +"radšej kontaktujte jeho správcu alebo v prípade nutnosti požiadajte o jeho " +"osirenie." -#: html/home.php msgid "Merge Request" msgstr "Žiadosť o zlúčenie" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Žiadosť o zlúčenie balíčka do iného. Možno použiť tiež v prípade, že balíček potrebuje byť premenovaný alebo nahradený rozdeleným balíčkom." +msgstr "" +"Žiadosť o zlúčenie balíčka do iného. Možno použiť tiež v prípade, že balíček " +"potrebuje byť premenovaný alebo nahradený rozdeleným balíčkom." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Ak potrebujete prediskutovať nejakú požiadavku, kedykoľvek môžete napísať na mailing list %saur-requests%s. Nepoužívajte však tento mailing list na posielanie požiadaviek." +msgstr "" +"Ak potrebujete prediskutovať nejakú požiadavku, kedykoľvek môžete napísať na " +"mailing list %saur-requests%s. Nepoužívajte však tento mailing list na " +"posielanie požiadaviek." -#: html/home.php msgid "Submitting Packages" msgstr "Podanie balíčkov" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Git cez SSH sa teraz používa na podanie balíčkov do AUR. Pre ďalšie informácie pozri tiež sekciu %sPodanie balíčkov%s na AUR stránke v ArchWiki." +msgstr "" +"Git cez SSH sa teraz používa na podanie balíčkov do AUR. Pre ďalšie " +"informácie pozri tiež sekciu %sPodanie balíčkov%s na AUR stránke v ArchWiki." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Uvedené SSH fingerprints sa používajú pre AUR:" -#: html/home.php msgid "Discussion" msgstr "Diskusia" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Všeobecná diskusia týkajúca sa Arch Užívateľského Repozitára (AUR) a štruktúry dôverovaných užívateľov (TU) je na %saur-general%s. Na diskusiu týkajúcu sa vývoja AUR webu použite %saur-dev%s mailing list." +msgstr "" +"Všeobecná diskusia týkajúca sa Arch Užívateľského Repozitára (AUR) a " +"štruktúry dôverovaných užívateľov (TU) je na %saur-general%s. Na diskusiu " +"týkajúcu sa vývoja AUR webu použite %saur-dev%s mailing list." -#: html/home.php msgid "Bug Reporting" msgstr "Ohlasovanie chýb" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." -msgstr "Ak nájdete chybu vo webovom rozhradní AUR, pošlite prosím správu o chybe na náš %sbug tracker%s. Posielajte sem %slen%s chyby webového rozhrania AUR. Pre nahlásenie chýb balíčkov kontaktujte správcu balíčka alebo zanechate komentár na príslušnej stránke balíčka." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." +msgstr "" +"Ak nájdete chybu vo webovom rozhradní AUR, pošlite prosím správu o chybe na " +"náš %sbug tracker%s. Posielajte sem %slen%s chyby webového rozhrania AUR. " +"Pre nahlásenie chýb balíčkov kontaktujte správcu balíčka alebo zanechate " +"komentár na príslušnej stránke balíčka." -#: html/home.php msgid "Package Search" msgstr "Hľadanie balíčka" -#: html/index.php msgid "Adopt" msgstr "Adoptovať" -#: html/index.php msgid "Vote" msgstr "Hlasuj" -#: html/index.php msgid "UnVote" msgstr "Odober hlas" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Upozorni" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Zruš upozornenie" -#: html/index.php msgid "UnFlag" msgstr "Odznač" -#: html/login.php template/header.php msgid "Login" msgstr "Prihlásiť" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Prihlásený ako: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Odhlásiť" -#: html/login.php msgid "Enter login credentials" msgstr "Zadajte prihlasovacie údaje" -#: html/login.php msgid "User name or email address" msgstr "Užívateľské meno alebo emailová adresa" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Heslo" -#: html/login.php msgid "Remember me" msgstr "Zapamätaj si ma" -#: html/login.php msgid "Forgot Password" msgstr "Zabudnuté heslo" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP prihlasovanie je zablokované. Pre prihlásenie prosím %sprepnite na HTTPs%s." +msgstr "" +"HTTP prihlasovanie je zablokované. Pre prihlásenie prosím %sprepnite na HTTPs" +"%s." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Vyhľadávacie kritériá" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Balíčky" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Pri pokuse o získanie podrobností o balíčku nastala chyba." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Povinné pole nie je vyplnené." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Heslá sa nezhodujú. " -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Heslo musí mať aspoň %s znakov." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Neplatný e-mail." -#: html/passreset.php msgid "Password Reset" msgstr "Obnova hesla" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Skontrolujte si svoj e-mail pre potvrdzujúci odkaz." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Heslo bolo úspešne obnovené." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrďte svoju e-mailovú adresu:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Zadajte nové heslo:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrďte nové heslo:" -#: html/passreset.php msgid "Continue" msgstr "Pokračuj" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Ak ste zabudli e-mailovú adresu, ktorú ste použili pri registrácii, pošlite prosím správu na %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Ak ste zabudli e-mailovú adresu, ktorú ste použili pri registrácii, pošlite " +"prosím správu na %saur-general%s mailing list." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Zadajte svoju e-mailovú adresu:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "Vybrané balíčky neboli označené, zanechajte prosím komentár." - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "Vybrané balíčky neboli vyvlastnené, pozrite potvrdzovacie zaškrtávacie políčko." +msgstr "" +"Vybrané balíčky neboli vyvlastnené, pozrite potvrdzovacie zaškrtávacie " +"políčko." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Nepodarilo sa nájsť balíček, do ktorého sa mali zlúčiť hlasy a komentáre." +msgstr "" +"Nepodarilo sa nájsť balíček, do ktorého sa mali zlúčiť hlasy a komentáre." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nemožno zlúčiť základňu balíčka so sebou samou." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "Vybrané balíčky neboli odstránené, začiarknite potvrdzujúce políčko." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Vymazanie balíčka" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Vymazať balíček: %s" +msgid "Delete Package" +msgstr "Vymaž balíček" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Použite tento formulár pre vymazanie základne balíčka %s%s%s a nasledovných balíčkov z AUR: " +msgstr "" +"Použite tento formulár pre vymazanie základne balíčka %s%s%s a nasledovných " +"balíčkov z AUR: " -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Vymazanie balíčka je nevratné." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaškrtnite políčko pre potvrdenie akcie." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrďte vymazanie balíčka" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Vymazať" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Len dôverovaní užívatelia a vývojári môžu vymazať balíčky." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Vyvlastni balíček" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Vyvlastni balíček: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Použite tento formulár na vyvlastnenie základne balíčka %s%s%s, ktorá zahrňuje nasledujúce balíčky:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Použite tento formulár na vyvlastnenie základne balíčka %s%s%s, ktorá " +"zahrňuje nasledujúce balíčky:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček a presunúť vlastníctvo na %s%s%s." +msgstr "" +"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček " +"a presunúť vlastníctvo na %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček." +msgstr "" +"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Potvrďte na vyvlastnenie balíčka" -#: html/pkgdisown.php msgid "Disown" msgstr "Vyvlastniť" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Len dôverovaní užívatelia a vývojári môžu vyvlastňovať balíčky." -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "Označ balíček ako zastaranú verziu" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "Označ balíček ako zastaranú verziu: %s" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " -msgstr "Použite tento formulár na označenie základne balíčka %s%s%s a nasledujúcich balíčkov ako zastarané verzie:" +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " +msgstr "" +"Použite tento formulár na označenie základne balíčka %s%s%s a nasledujúcich " +"balíčkov ako zastarané verzie:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "Tento formulár %sneslúži%s na nahlasovanie chýb. Na to použite komentár k balíčku." +msgstr "" +"Tento formulár %sneslúži%s na nahlasovanie chýb. Na to použite komentár k " +"balíčku." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "Uveďte nižšie podrobnosti o tom prečo je balíček zastaraný, podľa možnosti pridajte tiež link na oznam k novej verzii alebo nový tarball." +msgstr "" +"Uveďte nižšie podrobnosti o tom prečo je balíček zastaraný, podľa možnosti " +"pridajte tiež link na oznam k novej verzii alebo nový tarball." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Komentáre" -#: html/pkgflag.php msgid "Flag" msgstr "Označ" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Označiť zastaranú verziu balíčka môžu iba registrovaní užívatelia." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Zlúčenie balíčkov" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Zlúčiť balíček: %s" +msgid "Merge Package" +msgstr "Zlúč balíček" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Použite tento formulár pre zlúčenie základne balíčka %s%s%s do iného balíčka. " +msgstr "" +"Použite tento formulár pre zlúčenie základne balíčka %s%s%s do iného " +"balíčka. " -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Nasledujúce balíčky budú vymazané:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Operácia zlúčenia balíčkov je nevratná." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Zadajte meno balíčka, do ktorého chcete zlúčiť uvedený balíček." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Zlúčiť do:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrďte zlúčenie balíčka" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Zlúčiť" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Len dôverovaní užívatelia a vývojári môžu zlúčiť balíčky." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Vyplniť žiadosť" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zatvorit žiadosť" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prvý" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Predchádzajúci" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Ďaľej " -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Posledný" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Žiadosti" -#: html/register.php template/header.php msgid "Register" msgstr "Registrovať" -#: html/register.php msgid "Use this form to create an account." msgstr "Použite tento formulár pre vytvorenie účtu. " -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Dôverovaný užívateľ (TU)" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nepodarilo sa načítať údaje o návrhu." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Hlasovanie o tomto návrhu bolo ukončené." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Práve hlasovať majú len dôverovaní užívatelia" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemôžete hlasovať v návrhu o Vás." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "O tomto návrhu ste už hlasovali." -#: html/tu.php msgid "Vote ID not valid." msgstr "ID hlasu nie je platné." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Súčasné hlasy" -#: html/tu.php msgid "Past Votes" msgstr "Minulé hlasy" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Hlasujúci" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Registrácia účtu bolo zablokovaná pre vašu IP adresu, pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +msgstr "" +"Registrácia účtu bolo zablokovaná pre vašu IP adresu, pravdepodobne z dôvodu " +"stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Chýba ID užívateľa" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Užívateľké meno je neplatné." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Musí mať dĺžku medzi %s a %s znakmi" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Začínať a končiť s písmenom alebo číslom" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Môže obsahovať len jednu bodku, podčiarkovník alebo pomlčku." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mailová adresa nie je platná." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP otlačok kľúča je neplatný." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Verejný SSH kľúč nie je platný." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nepodarilo sa rozšíriť práva účtu." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jazyk nie je momentálne podporovaný." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Užívateľské meno %s%s%s sa už používa." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s sa už používa." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Verejný SSH kľúč %s%s%s sa už používa." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Chyba pri vytváraní účtu, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Účer %s%s%s bol úspešne vytvorený." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Obnovovacie heslo vám bolo zaslané na vašu e-mailovú adresu." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Kliknite na Prihlásenie pre použitie svojho účtu." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Žiadne zmeny neboli vykonané na účte %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Účet %s%s%s bol úspešne zmenený." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Prihlasovací formulár je v súčasnosti zablokovaný pre vašu IP adresu, pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +msgstr "" +"Prihlasovací formulár je v súčasnosti zablokovaný pre vašu IP adresu, " +"pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa " +"ospravedlňujeme." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Účet bol pozastavený" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Vaše heslo bolo obnovené. Ak ste si práve vytvorili nový účet, použite prosím link z potvrdzovacieho emailu na nastavenie prvotného hesla. Inak prosím zašlite požiadavku na obnovenie hesla na stránku %sObnova hesla%s." +msgstr "" +"Vaše heslo bolo obnovené. Ak ste si práve vytvorili nový účet, použite " +"prosím link z potvrdzovacieho emailu na nastavenie prvotného hesla. Inak " +"prosím zašlite požiadavku na obnovenie hesla na stránku %sObnova hesla%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nesprávne užívateľské meno alebo heslo." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Pri vytváraní užívateľského sedenia sa vyskytla chyba." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Neplatný email a kombinácia obnovovacích znakov." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Žiadny" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Pozri informácie o účte pre %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Chyba ID alebo meno základne balíčka." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nemáte oprávnenie na editovanie tohoto komentára." -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Komentár neexistuje." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Komentár nemôže byť prázdny." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentár bol pridaný." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Musíte byť prihlásený ak chcete editovať informácie o balíčku." + +msgid "Missing comment ID." +msgstr "Chýba ID komentára." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Chyba pri získavaní informácií o balíčku." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Informácie o balíčku sa nepodarilo nájsť." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Musíte byť prihlásený ak chcete označovať balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nebol vybraný žiadny balíček na označenie." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Vybrané balíčky neboli označené, zanechajte prosím komentár." + msgid "The selected packages have been flagged out-of-date." msgstr "Vybrané balíčky boli označené ako zastarané." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musíte byť prihlásený ak chcete odznačiť balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nebol vybraný žiadny balíček na odznačenie." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Vybrané balíčky boli odznačené." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nemáte práve vymazať balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nebol vybraný žiadny balíček na vymazanie." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Vybrané balíčky boli vymazané." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musíte byť prihlásený ak chcete adoptovať balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musíte byť prihlásený ak chcete vyvlastniť balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nebol vybraný žiadny balíček na adopciu." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Neoznačili ste žiadne balíčky na vyvlastnenie." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Vybrané balíčky boli adoptované." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Vybrané balíčky boli vyvlastnené." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Musíte byť prihlásený ak chcete hlasovať za balíčky." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musíte byť prihlásený ak chcete odobrať hlas balíčkom." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nebol vybraný žiadny balíček pre hlasovanie." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Váš hlas bol odobratý z vyznačených balíčkov." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Váš hlas bol pridaný vyznačeným balíčkom." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Pridanie do zoznamu upozornení bolo neúspešné." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Boli ste pridaný na notifikačný zoznam komentárov pre %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Boli ste odobraný z notifikačného zoznamu komentárov pre %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Musíte byť prihlásený ak chcete editovať informácie o balíčku." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Chýba ID komentára." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Komentár bol vymazaný." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nemáte práva na vymazanie tohto komentára." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Komentár bol vymazaný." + msgid "Comment has been edited." msgstr "Komentár bol editovaný." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nemáte oprávnenie na editovanie kľúčových slov tejto základne balíčka." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Kľúčové slová základne balíčka boli aktualizované." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nie ste oprávnený manažovať spolupracovníkov tejto základne balíčka." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Neplatné užívateľské meno: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Spolupracovníci základne balíčka boli aktualizovaní." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Pozri detaily balíčky pre" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "vyžaduje %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Musíte byť prihlásený ak chcete posielať žiadosti o balíčkoch." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neplatné meno: povolené sú iba malé písmená." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Pole s komentárom nemôže byť prázdne." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Neplatný typ žiadosti." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Požiadavka bola úspešne pridaná." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Neplatný dôvod." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Len Dôverovaní Užívatelia (TU) a vývojári môžu zatvárať žiadosti." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Žiadosť bola úspešne uzavretá." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Tento formulár môžete použiť na trvalé vymazanie AUR účtu %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUPOZORNENIE%s: Túto akciu nemožno vrátiť." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Potvrdiť vymazanie" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Užívateľské meno" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Typ účtu" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Užívateľ" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Vývojár" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Dôverovaný užívateľ & Vývojár" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mailová adresa" -#: template/account_details.php msgid "hidden" msgstr "skrytý" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Skutočné meno" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC prezývka" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP otlačok kľúča" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Neaktívny od" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktívny" -#: template/account_details.php msgid "Last Login" msgstr "Posledné prihlásenie" -#: template/account_details.php msgid "Never" msgstr "Nikdy" -#: template/account_details.php msgid "View this user's packages" msgstr "Pozrieť balíčky tohto užívateľa" -#: template/account_details.php msgid "Edit this user's account" msgstr "Editovať účet tohto užívateľa" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %ssem%s ak chcete natrvalo vymazať tento účet." -#: template/account_edit_form.php msgid "required" msgstr "povinný" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normálny užívateľ" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Dôverovaný užívateľ (TU)" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Účet bol pozastavený" -#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktívny" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "Overte prosím, že ste emailovú adresu zadali správne, inak budete vymknutý." +msgstr "" +"Overte prosím, že ste emailovú adresu zadali správne, inak budete vymknutý." -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Skryť emailovú adresu" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Potvrďte heslo" -#: template/account_edit_form.php msgid "Language" msgstr "Jazyk" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "Nasledujúca informácia je dôležitá iba v prípade, že chcete podať balíčky do AUR." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"Nasledujúca informácia je dôležitá iba v prípade, že chcete podať balíčky do " +"AUR." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Verejný SSH kľúč" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Aktualizácia" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Vytvoriť" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Reset" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Pre vaše vyhľadávacie kritériá neboli nájdené žiadne výsledky." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Editovať účet" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Pozastavený" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Editovať" - -#: template/account_search_results.php -msgid "Less" -msgstr "Menej" - -#: template/account_search_results.php -msgid "More" -msgstr "Viac" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Nie sú ďalšie výsledky na zobrazenie." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Manažovať spolupracovníkov: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno užívateľké meno na riadok):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Užívatelia" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Uložiť" - -#: template/header.php -msgid "My Packages" -msgstr "Moje balíčky" - -#: template/header.php -msgid " My Account" -msgstr "Môj účet" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Akcie balíčka" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Pozrieť PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Prezrieť zmeny" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Stiahnuť snapshot" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Prehľadať wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Označený ako neaktuálny" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Označ balíček ako neaktuálny" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Odznač balíček" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Odober hlas" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Hlasuj za tento balíček" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Vypni upozornenia" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Upozorni na nové komentáre" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Aktualizácia" + +msgid "Create" +msgstr "Vytvoriť" + +msgid "Reset" +msgstr "Reset" + +msgid "No results matched your search criteria." +msgstr "Pre vaše vyhľadávacie kritériá neboli nájdené žiadne výsledky." + +msgid "Edit Account" +msgstr "Editovať účet" + +msgid "Suspended" +msgstr "Pozastavený" + +msgid "Edit" +msgstr "Editovať" + +msgid "Less" +msgstr "Menej" + +msgid "More" +msgstr "Viac" + +msgid "No more results to display." +msgstr "Nie sú ďalšie výsledky na zobrazenie." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno " +"užívateľké meno na riadok):" + +msgid "Users" +msgstr "Užívatelia" + +msgid "Save" +msgstr "Uložiť" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + +msgid "My Packages" +msgstr "Moje balíčky" + +msgid " My Account" +msgstr "Môj účet" + +msgid "Package Actions" +msgstr "Akcie balíčka" + +msgid "View PKGBUILD" +msgstr "Pozrieť PKGBUILD" + +msgid "View Changes" +msgstr "Prezrieť zmeny" + +msgid "Download snapshot" +msgstr "Stiahnuť snapshot" + +msgid "Search wiki" +msgstr "Prehľadať wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Označ balíček ako neaktuálny" + +msgid "Unflag package" +msgstr "Odznač balíček" + +msgid "Remove vote" +msgstr "Odober hlas" + +msgid "Vote for this package" +msgstr "Hlasuj za tento balíček" + +msgid "Disable notifications" +msgstr "Vypni upozornenia" + msgid "Manage Co-Maintainers" msgstr "Manažovať spolupracovníkov" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1278,232 +1079,183 @@ msgstr[0] "%d ostávajúcich žiadostí" msgstr[1] "%d ostávajúce žiadosti" msgstr[2] "%d ostávajúcich žiadostí" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Vymaž balíček" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Zlúč balíček" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptuj balíček" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "neznámy" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detaily základne balíčka" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "len na čítanie" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Kľúčové slová" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Prispievateľ" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Spravovateľ" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Naposledy zabalil" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Hlasy" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularita" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvý príspevok" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Posledná aktualizácia" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Editovať komentár k: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Pridať komentár" -#: template/pkg_comments.php msgid "View all comments" msgstr "Pozrieť všetky komentáre" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Posledné komentáre" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s dal komentár k %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anonymný komentár k %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "vymazal %s %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "naposledy editoval %s %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" +msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Vymaž komentár" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Všetky komentáre" -#: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčka" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Základňa balíčka" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Popis" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Navštív web stránku pre" -#: template/pkg_details.php msgid "Licenses" msgstr "Licencie" -#: template/pkg_details.php msgid "Groups" msgstr "Skupiny" -#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikt s" -#: template/pkg_details.php msgid "Provides" msgstr "Poskytuje" -#: template/pkg_details.php msgid "Replaces" msgstr "Nahrádza" -#: template/pkg_details.php msgid "Dependencies" msgstr "Závislosti" -#: template/pkg_details.php msgid "Required by" msgstr "Vyžadovaný" -#: template/pkg_details.php msgid "Sources" msgstr "Zdroje" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Uzavrieť požiadavku: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Použite tento formulár pre zatvorenie požiadavky na základňu balíčka %s%s%s." +msgstr "" +"Použite tento formulár pre zatvorenie požiadavky na základňu balíčka %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Poznámka" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Políčko pre komentár možno nechať prázdne. Napriek tomu sa odporúča zanechať komentár pri zamietnutí požiadavky." +msgstr "" +"Políčko pre komentár možno nechať prázdne. Napriek tomu sa odporúča zanechať " +"komentár pri zamietnutí požiadavky." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Dôvod" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Prijatý" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Zamietnutý" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Vyplniť žiadosť: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Použite tento formulár na vyplnenie požiadavky ohľadom základne balíčka %s%s%s ktorá zahrňuje nasledovné balíčky:" +msgstr "" +"Použite tento formulár na vyplnenie požiadavky ohľadom základne balíčka %s%s" +"%s ktorá zahrňuje nasledovné balíčky:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Typ žiadosti" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Vymazanie" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Vyvlastniť" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Zlúčiť do" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1511,29 +1263,23 @@ msgstr[0] "Bola nájdená %d požiadavka ohľadom balíčkov." msgstr[1] "Boli nájdené %d požiadavky ohľadom balíčkov." msgstr[2] "Bolo nájdených %d požiadaviek ohľadom balíčkov." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Strana %d z %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Balíček" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Vyplnil" -#: template/pkgreq_results.php msgid "Date" msgstr "Dátum" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d dní ostáva" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1541,116 +1287,87 @@ msgstr[0] "ostáva ~%d hodina" msgstr[1] "ostávajú ~%d hodiny" msgstr[2] "ostáva ~%d hodín" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "ostáva < 1 hodina" -#: template/pkgreq_results.php msgid "Accept" msgstr "Prijať" -#: template/pkgreq_results.php msgid "Locked" msgstr "Uzamknuté" -#: template/pkgreq_results.php msgid "Close" msgstr "Zatvoriť" -#: template/pkgreq_results.php msgid "Closed" msgstr "Zatvorené" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "meno, popis" -#: template/pkg_search_form.php msgid "Name Only" msgstr "iba meno" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Presné meno" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Presná základňa balíčka" -#: template/pkg_search_form.php msgid "All" msgstr "Všetky" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Označené" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Neoznačené" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Meno" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Hlasoval" -#: template/pkg_search_form.php msgid "Last modified" msgstr "Naposledy zmenený" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Vzostupne" -#: template/pkg_search_form.php msgid "Descending" msgstr "Zostupne" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Zadaj kritériá pre vyhľadávanie" -#: template/pkg_search_form.php msgid "Search by" msgstr "Vyhľadávať podľa" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Neaktuálny" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Zotriediť podľa" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Zotriediť" -#: template/pkg_search_form.php msgid "Per page" msgstr "Na stránku" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Choď" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Osirené" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Chyba pri získavaní zoznamu balíčkov." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Žiadne balíčky nezodpovedajú vaším vyhľadávacím kritériám." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1658,154 +1375,118 @@ msgstr[0] "%d nájdených balíčkov." msgstr[1] "%d nájdené balíčky." msgstr[2] "%d nájdených balíčkov." -#: template/pkg_search_results.php msgid "Version" msgstr "Verzia" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "Popularita sa počíta ako suma všetkých hlasov, pričom každý hlas je násobený váhovým faktorom 0.98 za deň od dátumu vzniku." +msgstr "" +"Popularita sa počíta ako suma všetkých hlasov, pričom každý hlas je násobený " +"váhovým faktorom 0.98 za deň od dátumu vzniku." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Áno" -#: template/pkg_search_results.php msgid "orphan" msgstr "osirelý" -#: template/pkg_search_results.php msgid "Actions" msgstr "Akcie" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Označ ako neaktuálny." - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Odznač ako neaktuálny" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptuj balíčky" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Vyvlastni balíčky" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Vymaž balíčky" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrď" -#: template/search_accounts_form.php msgid "Any type" msgstr "Ľub. typ" -#: template/search_accounts_form.php msgid "Search" msgstr "Hľadaj" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Štatistika" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Osirelé balíčky" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Balíčky pridané za posledných 7 dní" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Balíčky aktualiz. za uplynulých 7 dní" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Balíčky aktualiz. za posledný rok" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nikdy neaktualizované balíčky" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovaní užívatelia" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Dôverovaní užívatelia (TU)" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedávne aktualizácie" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "Moja štatistika" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detaily o návrhu" -#: template/tu_details.php msgid "This vote is still running." msgstr "Hlasovanie stále prebieha." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Prispené: %s od %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Koniec" -#: template/tu_details.php msgid "Result" msgstr "Výsledok" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nie" -#: template/tu_details.php msgid "Abstain" msgstr "Zdržalo sa" -#: template/tu_details.php msgid "Total" msgstr "Celkom" -#: template/tu_details.php msgid "Participation" msgstr "Účasť" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Posledné hlasy od TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Posledný hlas" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Žiadne výsledky neboli nájdené." -#: template/tu_list.php msgid "Start" msgstr "Začiatok" -#: template/tu_list.php msgid "Back" msgstr "Späť" diff --git a/po/sr.po b/po/sr.po index 4aa146bc..e0c352b9 100644 --- a/po/sr.po +++ b/po/sr.po @@ -1,1277 +1,1071 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Lukas Fleischer , 2011 -# Slobodan Terzić , 2011-2012,2015 +# Slobodan Terzić , 2011-2012,2015-2016 # Slobodan Terzić , 2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 12:23+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-11 01:46+0000\n" "Last-Translator: Slobodan Terzić \n" -"Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/sr/)\n" +"Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" +"sr/)\n" +"Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: sr\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: html/404.php msgid "Page Not Found" msgstr "Stranica nije nađena" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Stranica koju ste zahtevali ne postoji." -#: html/503.php msgid "Service Unavailable" msgstr "Servis nije dostupan" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Ne paničite! Sajt je van mreže usled održavanja. Povratak se očekuje uskoro." +msgstr "" +"Ne paničite! Sajt je van mreže usled održavanja. Povratak se očekuje uskoro." -#: html/account.php msgid "Account" msgstr "Nalog" -#: html/account.php template/header.php msgid "Accounts" msgstr "Nalozi" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nije vam dozvoljen pristup ovoj oblasti." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Ne mogu da dobavim podatke o izabranom korisniku." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemate dozvole za uređivanje ovog naloga." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Ovim obrascem pretražujete postojeće naloge." -#: html/account.php msgid "You must log in to view user information." msgstr "Morate se prijaviti da bi videli podatke o korisniku." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Dodavanje predloga" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Neispravan token korisničke radnje." -#: html/addvote.php msgid "Username does not exist." msgstr "Korisničko ime ne postoji." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Predlog za %s već postoji." -#: html/addvote.php msgid "Invalid type." msgstr "Nedozvoljen tip." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Predlog ne može biti prazan." -#: html/addvote.php msgid "New proposal submitted." msgstr "Novi predlog je poslat." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Pošaljite predlog za glasanje." -#: html/addvote.php msgid "Applicant/TU" msgstr "Podnosioc/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prazno ako je nevažeće)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Vrsta" -#: html/addvote.php msgid "Addition of a TU" msgstr "Dodavanje TU" -#: html/addvote.php msgid "Removal of a TU" msgstr "Uklanjanje TU" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Uklanjanje TU (nedeklarisana neaktivnost)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Dopuna o podzakonskim aktima" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Predlog" -#: html/addvote.php msgid "Submit" msgstr "Slanje" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Upravljanje koodržavaocima" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Uređivanje komentara" -#: html/home.php template/header.php msgid "Home" msgstr "Početna" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Dobrodošli u AUR! Molimo pročitajte %sSmernice za korisnike AUR-a%s i %sSmernice za poverljive korinike%s za više informacija." +msgstr "" +"Dobrodošli u AUR! Molimo pročitajte %sSmernice za korisnike AUR-a%s i " +"%sSmernice za poverljive korinike%s za više informacija." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Priloženi PKGBUILD-ovi %smoraju%s biti u skladu sa %sArčovim standardima pakiranja%s ili će biti obrisani!" +msgstr "" +"Priloženi PKGBUILD-ovi %smoraju%s biti u skladu sa %sArčovim standardima " +"pakiranja%s ili će biti obrisani!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ne zaboravite da glasate za omiljene pakete!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Neki paketi se dostavljaju u binarnom obliku u riznici [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "UPOZORENJE" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "Paketi u AUR-u su sadržaj koji stvaraju korisnici. Upotrebljavate ih na sopstvenu odgovornost." +msgstr "" +"Paketi u AUR-u su sadržaj koji stvaraju korisnici. Upotrebljavate ih na " +"sopstvenu odgovornost." -#: html/home.php msgid "Learn more..." msgstr "Saznajte više..." -#: html/home.php msgid "Support" msgstr "Podrška" -#: html/home.php msgid "Package Requests" msgstr "Zahtevi za pakete" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Postoje tri vrste zahteva koji mogu biti podneti kroz kućicu %sRadnje nad paketima%s na stranici sa detaljima o paketu:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Postoje tri vrste zahteva koji mogu biti podneti kroz kućicu %sRadnje nad " +"paketima%s na stranici sa detaljima o paketu:" -#: html/home.php msgid "Orphan Request" msgstr "Zahtevi za odricanje" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "zahtev za odricanje od paketa, npr. kada je održavalac neaktivan a paket je predugo označen kao zastareo." +msgstr "" +"zahtev za odricanje od paketa, npr. kada je održavalac neaktivan a paket je " +"predugo označen kao zastareo." -#: html/home.php msgid "Deletion Request" msgstr "Zahtevi za brisanje" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "zahtev za brisanje paketa iz Arčove Korisničke Riznice. Ne koristite ovo ako je paket polomljen i može se lako ispraviti. Umesto toga, kontaktirajte održavaoca paketa i podnesite zahtev za odricanje ukoliko je potreban." +msgstr "" +"zahtev za brisanje paketa iz Arčove Korisničke Riznice. Ne koristite ovo ako " +"je paket polomljen i može se lako ispraviti. Umesto toga, kontaktirajte " +"održavaoca paketa i podnesite zahtev za odricanje ukoliko je potreban." -#: html/home.php msgid "Merge Request" msgstr "Zahtevi za spajanje" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "tahtev za spajanje paketa sa drugim paketom. Koristi se kada je paketu potrebno novo ime ili ga je potrebno razdeliti ma manje pakete." +msgstr "" +"zahtev za spajanje paketa sa drugim paketom. Koristi se kada je paketu " +"potrebno novo ime ili ga je potrebno razdeliti ma manje pakete." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Ukoliko želite da diskutujete o zahtevu, možete koristiti dopisnu listu %saur-requests%s. Međutim, molimo da ne koristite tu listu za podnošenje zahteva." +msgstr "" +"Ukoliko želite da diskutujete o zahtevu, možete koristiti dopisnu listu " +"%saur-requests%s. Međutim, molimo da ne koristite tu listu za podnošenje " +"zahteva." -#: html/home.php msgid "Submitting Packages" msgstr "Prilaganje paketa" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Za prilaganje paketa u AUR sada se koristi Git preko SSH. Pogledajte sekciju %sPrilaganje paketa%s na stranici o AUR-u na Arčovom wikiju." +msgstr "" +"Za prilaganje paketa u AUR sada se koristi Git preko SSH. Pogledajte sekciju " +"%sPrilaganje paketa%s na stranici o AUR-u na Arčovom wikiju." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Sledeći SSH otisci se koriste za AUR:" -#: html/home.php msgid "Discussion" msgstr "Diskusija" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Opšta diskusija vezana za Arčovu Korisničku Riznicu (AUR) i strukturu Poverljivih korisnika se vodi na dopisnoj listi %saur-general%s.Za diskusiju o razvoju samog web sučelja AUR-a, pogedajte dopisnu listu %saur-dev%s." +msgstr "" +"Opšta diskusija vezana za Arčovu Korisničku Riznicu (AUR) i strukturu " +"Poverljivih korisnika se vodi na dopisnoj listi %saur-general%s.Za diskusiju " +"o razvoju samog web sučelja AUR-a, pogedajte dopisnu listu %saur-dev%s." -#: html/home.php msgid "Bug Reporting" msgstr "Prijavljivanje grešaka" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." -msgstr "Ukoliko nađete grešku u web sučelju AUR-a. molimo da je prijavite na našem %sbubolovcu%s. Bubolovac koristite %sisključivo%s za prjavljivanje grešaka u samom AUR-u. Za prijavu grešaka u samim paketima kontaktirajte održavaoce paketa ili ostavite komentar na odgovarajućoj stranici paketa." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." +msgstr "" +"Ukoliko nađete grešku u web sučelju AUR-a. molimo da je prijavite na našem " +"%sbubolovcu%s. Bubolovac koristite %sisključivo%s za prjavljivanje grešaka u " +"samom AUR-u. Za prijavu grešaka u samim paketima kontaktirajte održavaoce " +"paketa ili ostavite komentar na odgovarajućoj stranici paketa." -#: html/home.php msgid "Package Search" msgstr "Pretraga paketa" -#: html/index.php msgid "Adopt" msgstr "Usvoji" -#: html/index.php msgid "Vote" msgstr "Daj glas" -#: html/index.php msgid "UnVote" msgstr "Ukloni glas" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" -msgstr "Obaveštavaj" +msgstr "Obaveštenja" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne obaveštavaj" -#: html/index.php msgid "UnFlag" msgstr "Odznači" -#: html/login.php template/header.php msgid "Login" msgstr "Prijava" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Prijavljeni ste kao: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Odjava" -#: html/login.php msgid "Enter login credentials" msgstr "Unesite podatke za prijavu" -#: html/login.php msgid "User name or email address" msgstr "Korisničko ime ili adresa e-pošte" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" -#: html/login.php msgid "Remember me" msgstr "Pamti me" -#: html/login.php msgid "Forgot Password" msgstr "Zaboravljena lozinka" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Prijavljivanje preko HTTP je isključeno. Koristite %sHTTPs%s da bi se prijavili." +msgstr "" +"Prijavljivanje preko HTTP je isključeno. Koristite %sHTTPs%s da bi se " +"prijavili." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kriterijum pretrage" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketi" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Greška pri dobavljanju detalja paketa." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Nedostaje neophodno polje." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Polja lozinke se ne poklapaju." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Lozinka mora imati najmanje %s znaka." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Neispravna e-pošta." -#: html/passreset.php msgid "Password Reset" msgstr "Resetovanje lozinke" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Proverite e-poštu za vezu za potvrđivanje." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Vaša lozinka je uspešno resetovana." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrdite adresu e-pošte:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Unesite novu lozinku:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrdite novu lozinku:" -#: html/passreset.php msgid "Continue" msgstr "Nastavi" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Ukoliko ste zaboravili registracionu adresu e-pošte, molimo pošaljite poruku na dopisnu listu %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Ukoliko ste zaboravili registracionu adresu e-pošte, molimo pošaljite poruku " +"na dopisnu listu %saur-general%s." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Unesite adresu e-pošte:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "Izabrani paketi nisu označeni, molimo unesite komentar." - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Izabrani paketi nisu odreknuti, pogledajte kućicu za potvrdu." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Ne mogu da nađem paket kako bih stopio glasove i komentare." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Ne mogu da spojim osnovu paketa sa samom sobom." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "Izabrani paketi nisu obrisani; pogledajte kućicu za potvrđivanje." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Brisanje paketa" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Obriši paket: %s" +msgid "Delete Package" +msgstr "Obriši paket" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Ovim formularom brišete osnovu paketa %s%s%s i sledeće pakete iz AUR-a:" +msgstr "" +"Ovim formularom brišete osnovu paketa %s%s%s i sledeće pakete iz AUR-a:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Brisanje paketa je trajno." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Označite kućicu za potvrdu." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrdite brisanje paketa" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Obriši" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Samo Poverljivi korisnici i Programeri mogu brisati pakete." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Odrekni se paketa" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Odricanje paketa: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Ovim formularom se odričete osnove paketa %s%s%s i sledećih pripadajučih pakete:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Ovim formularom se odričete osnove paketa %s%s%s i sledećih pripadajučih " +"pakete:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Označavanjem kućice potvrđujete odricanje prenos vlasništva paketa na %s%s%s." +msgstr "" +"Označavanjem kućice potvrđujete odricanje prenos vlasništva paketa na %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Označavanjem kućice potvrđujete da želite da se odreknete od paketa." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Potvrdite odricanje od paketa" -#: html/pkgdisown.php msgid "Disown" msgstr "Odrekni se" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Samo Poverljivi korisnici i Programeri mogu vršiti odricanje paketa." -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "Označi komentar" + msgid "Flag Package Out-Of-Date" msgstr "Označi paket kao zastareo" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "Označavanje paketa zastarelim: %s" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " -msgstr "Ovim formularom označavate osnovu paketa %s%s%s i sledeće pakete kao zastarele:" +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " +msgstr "" +"Ovim formularom označavate osnovu paketa %s%s%s i sledeće pakete kao " +"zastarele:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "Molimo da ovim formularom %sNE%s prijavljujete greške. Umesto toga koristite komentare o paketu." +msgstr "" +"Molimo da ovim formularom %sNE%s prijavljujete greške. Umesto toga koristite " +"komentare o paketu." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "Ispod unesite razloge zbog kojih je paket zastareo, poželjno i veze ka objavi novog izdanja ili izvornom kodu nove verzije." +msgstr "" +"Ispod unesite razloge zbog kojih je paket zastareo, poželjno i veze ka " +"objavi novog izdanja ili izvornom kodu nove verzije." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Komentari" -#: html/pkgflag.php msgid "Flag" msgstr "Označi" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Samo registrovani korisnici mogu označavati pakete zastarelim." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Spajanje paketa" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Spajanje paketa: %s" +msgid "Merge Package" +msgstr "Spoji paket" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Ovim formularom spajate osnovu paketa %s%s%s sa drugim paketom." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Sledeći paketi će biti obrisani:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Kada se jednom spoje, paketi ne mogu više biti razdvojeni." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Unesite ime paketa sa kojim želite da spojite ovaj paket." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Spoji sa:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrdite spajanje" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Spoji" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Samo Poverljivi korisnici i Programeri mogu da spajaju pakete." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" +msgid "Submit Request" msgstr "Podnesi zahtev" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zatvori zahtev" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prva" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Prethodna" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sledeća" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Zadnja" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Zahtevi" -#: html/register.php template/header.php msgid "Register" msgstr "Registracija" -#: html/register.php msgid "Use this form to create an account." msgstr "Ovim formularom pravite nalog." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Poverljivi korisnik" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Ne mogu da dobavim detalje o predlogu." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Glasanje o ovom predlogu je završeno." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Samo poverljivi korisnici mogu da glasaju." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Ne možete glasati za predlog koji se odnosi na vas." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Već ste glasali za ovaj predlog." -#: html/tu.php msgid "Vote ID not valid." msgstr "Neispravan ID glasa." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Trenutno glasova" -#: html/tu.php msgid "Past Votes" msgstr "Prethodni glasovi" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Glasači" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Registrovanje naloga sa vaše IP adrese je onemogućeno, najverovatnije usled napada spama. Oprostite na neprijatnosti." +msgstr "" +"Registrovanje naloga sa vaše IP adrese je onemogućeno, najverovatnije usled " +"napada spama. Oprostite na neprijatnosti." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Nedostaje ID korisnika" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Neispravno korisničko ime." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Mora imati između %s i %s znakova." -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Počnje i završava slovom ili brojem" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržati samo jedan razmak, podvlaku ili crticu." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Neispravna adresa e-pošte." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Otisak PGP ključa nije ispravan." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Neispravan javni SSH ključ." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Ne mogu da uvećam dozvole naloga." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Korisničko ime %s%s%s je već u upotrebi." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s je već u upotrebi." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Javni SSH ključ %s%s%s je već u upotrebi." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Greška pri pravljenju naloga %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Nalog %s%s%s je uspešno napravljen." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ključ za resetovanje lozinke je poslat na vašu adresu e-pošte." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Kliknite iznad na vezu Prijava da bi koristili svoj nalog." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nisu izvršene nikakve izmene naloga %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Nalog %s%s%s je uspešno izmenjen." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Formular za prijavljivanje je trenutno onemogućen za vašu IP adresu, najverovatnije usled napada spama. Oprostite na neprijatnosti." +msgstr "" +"Formular za prijavljivanje je trenutno onemogućen za vašu IP adresu, " +"najverovatnije usled napada spama. Oprostite na neprijatnosti." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Nalog je suspendovan" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Vaša lozinka je resetovana. Ukoliko ste tek napravili nov nalog, molimo upotrebite vezu iz e-pisma za potvrdu kako bi postavili početnu lozinku. U suprotnom, zatražite resetovajne ključa putem stranice %sResetovanje lozinke%s." +msgstr "" +"Vaša lozinka je resetovana. Ukoliko ste tek napravili nov nalog, molimo " +"upotrebite vezu iz e-pisma za potvrdu kako bi postavili početnu lozinku. U " +"suprotnom, zatražite resetovajne ključa putem stranice %sResetovanje lozinke" +"%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Loše korisničko ime ili lozinka." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Došlo je do greške pri pravljenju korisničke sesije." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Neispravna kombinacija e-pošte i ključa za resetovanje." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nema" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Prikaži podatke o nalogu za %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Nedostaje ID ili ime baze paketa." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nemate dozvolu za uređivanje ovog komentara." -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Komentar ne postoji." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Komentar ne sme biti prazan." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentar je dodat." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Morate se prijaviti da bi ste uređivali podatke o paketu." + +msgid "Missing comment ID." +msgstr "Nedostaje ID komentara." + +msgid "No more than 5 comments can be pinned." +msgstr "Ne može se izdvojiti više od 5 komentara." + +msgid "You are not allowed to pin this comment." +msgstr "Nemate dozvole za izdvajanje ovog komentara." + +msgid "You are not allowed to unpin this comment." +msgstr "Nemate dozvole da odvajanje ovog komentara." + +msgid "Comment has been pinned." +msgstr "Komentar je izdvojen." + +msgid "Comment has been unpinned." +msgstr "Komentar je odvojen." + msgid "Error retrieving package details." msgstr "Greška pri dobavaljanju podataka o paketu." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Ne mogu naći podatke o paketu." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Morate se prijaviti pre označavanja paketa." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Niste izabrali pakete za označavanje." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Izabrani paketi nisu označeni, molimo unesite komentar." + msgid "The selected packages have been flagged out-of-date." msgstr "Izabrani paketi su označeni kao zastareli." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Morate se prijaviti da bi uklonili oznake." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Niste izabrali paket za uklanjanje oznake." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Označenim paketima je uklonjena oznaka." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nemate dozvole za brisanje paketa." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Niste izabrali pakete za brisanje." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Izbrani paketi su obrisani." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Morate se prijaviti da bi usvojili pakete." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Morate se prijaviti da bi ste se odrekli paketa." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Niste izabrali paketa za usvajanje." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Niste izabrali pakete kojih bi da se odreknete." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Izabrani paketi su usvojeni." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Odrekli ste se izabranog paketa." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Morate se prijaviti da bi glasali za pakete." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Morate se prijaviti da bi uklonili glasove za pakete." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Niste izabrali pakete za koje glasate." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaši glasovi su uklonjeni za izabrane paketa." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Dali ste glas izabranim paketima." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ne mogu da dodam na spisak za obaveštenja." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Dodati ste na spisak za obaveštenja o %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Uklonjeni ste sa spiska obaveštavanja o komentarima za %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Morate se prijaviti da bi ste uređivali podatke o paketu." +msgid "You are not allowed to undelete this comment." +msgstr "Nemate dozvole za povraćaj ovog komentara." -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Nedostaje ID komentara." +msgid "Comment has been undeleted." +msgstr "Komentar je povraćen." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Komentar je obrisan." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nije vam dozvoljeno brisanje ovog komentara." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Komentar je obrisan." + msgid "Comment has been edited." msgstr "Komentar je uređen." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nije vam dozvoljeno da uređujete ključne reči za ovu osnovu paketa." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ključne reči baze paketa su ažurirane." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nije vam dozvvoljeno da upravljate koodržavaocima ove osnove paketa." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Neispravno korisničko ime: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Koodržavaoci osnove baze paketa su ažurirani." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Prikaži detalje paketa za" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "zahteva %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Morate se prijaviti da bi slali zahteve za pakete." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neispravno ime: dozvoljena su samo mala slova." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Polje komentara ne sme biti prazno." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Neispravan tip zahteva" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Zahtev je uspešno dodat." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Neispravan razlog." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Samo Poverljivi korisnici i programeri mogu zatvarati zahteve." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Zahtev je uspešno zatvoren." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ovim možete trajno obrisati nalog %s iz AUR-a." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUPOZORENJE%s: ova radnja se ne može opozvati" -#: template/account_delete.php msgid "Confirm deletion" msgstr "Potvrda brisanja" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Korisničko ime" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip naloga" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Korisnik" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Programer" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Poverljivi korisnik i programer" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresa e-pošte" -#: template/account_details.php msgid "hidden" msgstr "skrivena" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Pravo ime" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC nadimak" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Otisak PGP ključa" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Status" -#: template/account_details.php msgid "Inactive since" msgstr "Neaktivan od" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivan" -#: template/account_details.php msgid "Last Login" msgstr "Poslednje prijavljivanje" -#: template/account_details.php msgid "Never" msgstr "Nikad" -#: template/account_details.php msgid "View this user's packages" msgstr "Pregledaj korisnikove pakete" -#: template/account_details.php msgid "Edit this user's account" msgstr "Uređivanje naloga ovog korisnika" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %sovde%s ako želite trajno brisanje ovog naloga." -#: template/account_edit_form.php msgid "required" msgstr "neophodno" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Običan korisnik" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Poverljivi korisnik" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Nalog je suspendovan" -#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktivan" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "Proverite da li ste ispravno uneli adresu e-pošte, inače će vam pristup biti odbijen." +msgstr "" +"Proverite da li ste ispravno uneli adresu e-pošte, inače će vam pristup biti " +"odbijen." -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Skrij adresu e-pošte" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Ponovo unesite lozinku" -#: template/account_edit_form.php msgid "Language" msgstr "Jezik" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "Sledeće informacije su neophodne ako želite da prilažete pakete u Arčovu korisničku riznicu." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"Sledeće informacije su neophodne ako želite da prilažete pakete u Arčovu " +"korisničku riznicu." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Javni SSH ključ" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Ažuriraj" +msgid "Notification settings" +msgstr "Postavke obaveštenja" -#: template/account_edit_form.php -msgid "Create" -msgstr "Napravi" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Resetuj" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Nema rezultata koji se poklapaju sa kriterijumom pretrage." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Uredi nalog" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Suspendovan" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Uredi" - -#: template/account_search_results.php -msgid "Less" -msgstr "Manje" - -#: template/account_search_results.php -msgid "More" -msgstr "Više" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Nema daljih rezultata." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Upravljanje koodržavaocima: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Ovim formularom dodajete koodržavaoce za %s%s%s (jedno korisničko ime po liniji):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Korisnici" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Sačuvaj" - -#: template/header.php -msgid "My Packages" -msgstr "Moji paketi" - -#: template/header.php -msgid " My Account" -msgstr "Moj nalog" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Radnje nad paketom" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Prikaži PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Prikaz izmena" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Preuzimanje snimka" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Pretraži wiki" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Označen kao zastareo" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Označi kao zastareo" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Odznači paket" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Ukloni glas" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Glasajte za paket" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Ugasi obaveštenja" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Obavesti o novim komentarima" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "Obavesti o nadogradnjama paketa" + +msgid "Update" +msgstr "Ažuriraj" + +msgid "Create" +msgstr "Napravi" + +msgid "Reset" +msgstr "Resetuj" + +msgid "No results matched your search criteria." +msgstr "Nema rezultata koji se poklapaju sa kriterijumom pretrage." + +msgid "Edit Account" +msgstr "Uredi nalog" + +msgid "Suspended" +msgstr "Suspendovan" + +msgid "Edit" +msgstr "Uredi" + +msgid "Less" +msgstr "Manje" + +msgid "More" +msgstr "Više" + +msgid "No more results to display." +msgstr "Nema daljih rezultata." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Ovim formularom dodajete koodržavaoce za %s%s%s (jedno korisničko ime po " +"liniji):" + +msgid "Users" +msgstr "Korisnici" + +msgid "Save" +msgstr "Sačuvaj" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "Komentar o oznaci zastarelosti: %s" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "%s%s%s označi %s%s%s kao zastareo %s%s%s iz sledećeg razloga:" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "%s%s%s nije označen kao zastareo." + +msgid "Return to Details" +msgstr "Nazad na detalje" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Copyright %s 2004-%d aurweb Development Team." + +msgid "My Packages" +msgstr "Moji paketi" + +msgid " My Account" +msgstr "Moj nalog" + +msgid "Package Actions" +msgstr "Radnje nad paketom" + +msgid "View PKGBUILD" +msgstr "Prikaži PKGBUILD" + +msgid "View Changes" +msgstr "Prikaz izmena" + +msgid "Download snapshot" +msgstr "Preuzimanje snimka" + +msgid "Search wiki" +msgstr "Pretraži wiki" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "Označen kao zastareo (%s)" + +msgid "Flag package out-of-date" +msgstr "Označi kao zastareo" + +msgid "Unflag package" +msgstr "Odznači paket" + +msgid "Remove vote" +msgstr "Ukloni glas" + +msgid "Vote for this package" +msgstr "Glasajte za paket" + +msgid "Disable notifications" +msgstr "Ugasi obaveštenja" + msgid "Manage Co-Maintainers" msgstr "Upravljanje koodržavaocima" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1279,232 +1073,182 @@ msgstr[0] "%d zahtev na čekanju" msgstr[1] "%d zahteva na čekanju" msgstr[2] "%d zahteva na čekanju" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Obriši paket" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Spoji paket" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Usvoji paket" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "nepoznata" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Podaci o bazi paketa" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL za git kloniranje" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "samo za čitanje" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Ključne reči" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Pošiljalac" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Održavalac" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Poslednji paketar" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" -msgstr "Glasova" +msgstr "Glasovi" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularnost" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvi put priloženo" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Poslednje ažuriranje" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Uređivanje komentara za: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Dodaj komentar" -#: template/pkg_comments.php msgid "View all comments" msgstr "Prikaži sve komentare" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "Izdvojeni komentari" + msgid "Latest Comments" msgstr "Poslednji komentari" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s postavi komentar za %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anoniman komentar za %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "%s obrisa %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "poslednja izmena %s od %s" +msgid "deleted on %s" +msgstr "obrisan %s" + +#, php-format +msgid "edited on %s by %s" +msgstr "%s izmeni %s " + +#, php-format +msgid "edited on %s" +msgstr "izmenjen %s" + +msgid "Undelete comment" +msgstr "Povraćeni komentar" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Obriši komentar" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "Izdvoji komentar" + +msgid "Unpin comment" +msgstr "Odvoji komentar" + msgid "All comments" msgstr "Svi komentari" -#: template/pkg_details.php msgid "Package Details" msgstr "Podaci o paketu" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Osnova paketa" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Uzvodni URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Poseti sajt za" -#: template/pkg_details.php msgid "Licenses" msgstr "Licence" -#: template/pkg_details.php msgid "Groups" msgstr "Grupe" -#: template/pkg_details.php msgid "Conflicts" msgstr "Sukobi" -#: template/pkg_details.php msgid "Provides" msgstr "Dostavlja" -#: template/pkg_details.php msgid "Replaces" msgstr "Smenjuje" -#: template/pkg_details.php msgid "Dependencies" msgstr "Zavisnosti" -#: template/pkg_details.php msgid "Required by" msgstr "Zahteva ga" -#: template/pkg_details.php msgid "Sources" msgstr "Izvori" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Zatvaranje zahteva: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Ovim formularom zatvarate zahteve za osnovu paketa %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Beleška" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Polje komentara može ostati prazno. Međutim, preporučujemo da uvek dodate komentar pri odbijanju zahteva." +msgstr "" +"Polje komentara može ostati prazno. Međutim, preporučujemo da uvek dodate " +"komentar pri odbijanju zahteva." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razlog" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Prihvaćeno" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Odbijeno" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Slanje zahteva: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Ovim formularom pošaljite zahtev vezan za osnovu paketa %s%s%s koja sadrži sledeće pakete:" +msgstr "" +"Ovim formularom pošaljite zahtev vezan za osnovu paketa %s%s%s koja sadrži " +"sledeće pakete:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Tip zahteva" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Brisanje" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Siročić" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Stopi sa" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1512,29 +1256,23 @@ msgstr[0] "%d zahtev za paket." msgstr[1] "%d zahteva za paket." msgstr[2] "%d zahteva za paket." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Stranica %d od %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Paket" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Posla" -#: template/pkgreq_results.php msgid "Date" msgstr "Datum" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "Preostalo dana: ~%d" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1542,116 +1280,87 @@ msgstr[0] "Preostao ~%d čas" msgstr[1] "Preostala ~%d časa" msgstr[2] "Preostalo ~%d časova" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 sata preostalo" -#: template/pkgreq_results.php msgid "Accept" msgstr "Prihvati" -#: template/pkgreq_results.php msgid "Locked" msgstr "Zaključano" -#: template/pkgreq_results.php msgid "Close" msgstr "Zatvori" -#: template/pkgreq_results.php msgid "Closed" msgstr "Zatvoreno" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Ime, opis" -#: template/pkg_search_form.php msgid "Name Only" -msgstr "samo ime" +msgstr "Samo ime" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Tačno ime" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Tačna osnova paketa" -#: template/pkg_search_form.php msgid "All" msgstr "svi" -#: template/pkg_search_form.php msgid "Flagged" msgstr "označeni" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "neoznačeni" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Ime" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Dat glas" -#: template/pkg_search_form.php msgid "Last modified" msgstr "Poslednja izmena" -#: template/pkg_search_form.php msgid "Ascending" msgstr "rastući" -#: template/pkg_search_form.php msgid "Descending" msgstr "opadajući" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Unesite kriterijum pretrage" -#: template/pkg_search_form.php msgid "Search by" msgstr "Traži se" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastareli paketi" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Složi prema" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Način ređanja" -#: template/pkg_search_form.php msgid "Per page" msgstr "Po stranici" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Idi" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Siročići" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Greška pri pruzimanju spiska paketa." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nijedan paket ne odgovara kriterijumu pretrage." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1659,154 +1368,118 @@ msgstr[0] "Nađen %d paket." msgstr[1] "Nađena %d paketa." msgstr[2] "Nađeno %d paketa." -#: template/pkg_search_results.php msgid "Version" msgstr "Verzija" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "Popularnost se izračunava kao suma svih glasova, gde glas ima faktor težine 0,98 za svaki dan od njegovog nastanka." +msgstr "" +"Popularnost se izračunava kao suma svih glasova, gde glas ima faktor težine " +"0,98 za svaki dan od njegovog nastanka." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Da" -#: template/pkg_search_results.php msgid "orphan" msgstr "sirčoić" -#: template/pkg_search_results.php msgid "Actions" msgstr "Radnje" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Označi kao zastareo" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Ukloni oznaku zastarelosti" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Usvoji paket" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odrekni se paketa" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Obriši pakete" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrdi" -#: template/search_accounts_form.php msgid "Any type" msgstr "Bilo koji tip" -#: template/search_accounts_form.php msgid "Search" msgstr "Pretraži" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistika" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paketa siročića" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paketa dodato u zadnjih 7 dana" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paketa ažurirano u zadnjih 7 dana" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paketa ažurirano prethodne godine" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paketa koji nikad nisu ažurirani" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovanih korisnika" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Poverljivih korisnika" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedavno ažurirano" -#: template/stats/user_table.php +msgid "more" +msgstr "više" + msgid "My Statistics" msgstr "Moja statistika" -#: template/tu_details.php msgid "Proposal Details" msgstr "Detalji predloga" -#: template/tu_details.php msgid "This vote is still running." msgstr "Glasanje u toku." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Priloženo: %s od %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Ističe" -#: template/tu_details.php msgid "Result" msgstr "Rezultat" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" -#: template/tu_details.php msgid "Abstain" msgstr "Uzdržan" -#: template/tu_details.php msgid "Total" msgstr "Ukupno" -#: template/tu_details.php msgid "Participation" msgstr "Učešće" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Poslednji glasovi od TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Poslednji glas" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nema rezultata." -#: template/tu_list.php msgid "Start" msgstr "Pokrenut" -#: template/tu_list.php msgid "Back" msgstr "Nazad" diff --git a/po/tr.po b/po/tr.po index cf04d40d..2e6fdf81 100644 --- a/po/tr.po +++ b/po/tr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Atilla Öntaş , 2011,2013-2015 # Atilla Öntaş , 2012,2014 @@ -14,1799 +14,1474 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/tr/)\n" +"Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" +"tr/)\n" +"Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: tr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: html/404.php msgid "Page Not Found" msgstr "Sayfa Bulunamadı" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Üzgünüz, talep ettiğiniz sayfa bulunamadı." -#: html/503.php msgid "Service Unavailable" msgstr "Hizmete Erişilemiyor" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Paniklemeyin! Bu site bakım çalışmaları nedeniyle erişime kapatıldı. Kısa süre sonra yeniden çalışmaya başlayacak" +msgstr "" +"Paniklemeyin! Bu site bakım çalışmaları nedeniyle erişime kapatıldı. Kısa " +"süre sonra yeniden çalışmaya başlayacak" -#: html/account.php msgid "Account" msgstr "Hesap" -#: html/account.php template/header.php msgid "Accounts" msgstr "Hesaplar" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Bu alana erişim izniniz yok." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Belirtilen kullanıcı verileri alınamadı." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "Bu hesap üzerinde değişiklik yapma izniniz yok." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Mevcut hesaplar içinde arama yapmak için bu formu kullanın." -#: html/account.php msgid "You must log in to view user information." msgstr "Kullanıcı bilgilerini görmek için giriş yapmalısınız." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Öneri ekle" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Kullanıcı işlemi için geçersiz anahtar." -#: html/addvote.php msgid "Username does not exist." msgstr "Kullanıcı adı bulunamadı." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s için yürürlükte olan bir öneri var." -#: html/addvote.php msgid "Invalid type." msgstr "Geçersiz tür." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Öneri boş olamaz." -#: html/addvote.php msgid "New proposal submitted." msgstr "Yeni öneri gönderildi." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Oylanması için öneri gönder." -#: html/addvote.php msgid "Applicant/TU" msgstr "İstekli/TU" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(uygulanabilir değilse boş)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Tür" -#: html/addvote.php msgid "Addition of a TU" msgstr "Bir GK ekleme" -#: html/addvote.php msgid "Removal of a TU" msgstr "Bir GK çıkartma" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Bir GK çıkartma (bildirilmemiş hareketsizlik)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendment of Bylaws" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Öneri" -#: html/addvote.php msgid "Submit" msgstr "Gönder" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Yardımcı bakımcıları Yönet" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Yorumu düzenle" -#: html/home.php template/header.php msgid "Home" msgstr "Anasayfa" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "AUR'a hoş geldiniz! Bilgi almak için lütfen %sAUR Kullanıcı Rehberi%s ve %sGK Rehberini%s okuyun." +msgstr "" +"AUR'a hoş geldiniz! Bilgi almak için lütfen %sAUR Kullanıcı Rehberi%s ve " +"%sGK Rehberini%s okuyun." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Eklenen PKGBUILD dosyaları %smutlaka%s %sArch Paket Standartlarına%s uymalıdır aksi takdirde silinecektir. " +msgstr "" +"Eklenen PKGBUILD dosyaları %smutlaka%s %sArch Paket Standartlarına%s " +"uymalıdır aksi takdirde silinecektir. " -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Beğendiğiniz paketleri oylamayı unutmayın!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Burada listelenen paketlerin bazıları [community] deposunda yer almaktadır." +msgstr "" +"Burada listelenen paketlerin bazıları [community] deposunda yer almaktadır." -#: html/home.php msgid "DISCLAIMER" msgstr "FERAGATNAME" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"AUR paketleri kullanıcılar tarafından üretilirler. Bu paketlerin herhangi " +"bir risk taşıyabileceğini unutmayın." -#: html/home.php msgid "Learn more..." msgstr "Daha fazlasını öğrenin..." -#: html/home.php msgid "Support" msgstr "Destek" -#: html/home.php msgid "Package Requests" msgstr "Paket Talepleri" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Paket ayrıntıları sayfasındaki %sPaket Eylemleri%s kutusunda doldurulabilecek üç tür talep vardır:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Paket ayrıntıları sayfasındaki %sPaket Eylemleri%s kutusunda " +"doldurulabilecek üç tür talep vardır:" -#: html/home.php msgid "Orphan Request" msgstr "Sahipsiz Bırakma Talebi" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Bir paketin sahipliğinin bırakılması talebi, mesela bakımcısının etkin olmaması ve paketin uzun zamandır güncel değil olarak işaretlenmiş olması." +msgstr "" +"Bir paketin sahipliğinin bırakılması talebi, mesela bakımcısının etkin " +"olmaması ve paketin uzun zamandır güncel değil olarak işaretlenmiş olması." -#: html/home.php msgid "Deletion Request" msgstr "Silme Talebi" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Bir paketin Arch Kullanıcı Deposundan kaldırılması talebidir. Lütfen bunu, bir paket çalışmıyor fakat kolayca düzeltilebiliyorsa kullanmayın. Bunun yerine, paket bakımcısı ile iletişim kurun ve mecbur kalınırsa paketin sahipsiz bırakılması talebinde bulunun." +msgstr "" +"Bir paketin Arch Kullanıcı Deposundan kaldırılması talebidir. Lütfen bunu, " +"bir paket çalışmıyor fakat kolayca düzeltilebiliyorsa kullanmayın. Bunun " +"yerine, paket bakımcısı ile iletişim kurun ve mecbur kalınırsa paketin " +"sahipsiz bırakılması talebinde bulunun." -#: html/home.php msgid "Merge Request" msgstr "Birleştirme Talebi" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Bir paketin bir başkası ile birleştirilmesi talebidir. Bir paketin yeniden adlandırılması veya bir ayrılmış paketle değiştirilmesi gerekiyorsa kullanılabilir." +msgstr "" +"Bir paketin bir başkası ile birleştirilmesi talebidir. Bir paketin yeniden " +"adlandırılması veya bir ayrılmış paketle değiştirilmesi gerekiyorsa " +"kullanılabilir." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Bir talep hakkında tartışmak istiyorsanız, %saur-requests%s e-posta listesini kullanabilirsiniz. Bununla birlikte o e-posta listesini dosya talepleri için kullanmamalısınız." +msgstr "" +"Bir talep hakkında tartışmak istiyorsanız, %saur-requests%s e-posta " +"listesini kullanabilirsiniz. Bununla birlikte o e-posta listesini dosya " +"talepleri için kullanmamalısınız." -#: html/home.php msgid "Submitting Packages" msgstr "Paketleri göndermek" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Artık AUR' a paket göndermek için SSH üzerinden Git kullanılmaktadır. Daha fazla bilgi için Arch Kullanıcı Deposu ArchWiki sayfasındaki %sPaketleri Göndermek%s bölümüne bakın." +msgstr "" +"Artık AUR' a paket göndermek için SSH üzerinden Git kullanılmaktadır. Daha " +"fazla bilgi için Arch Kullanıcı Deposu ArchWiki sayfasındaki %sPaketleri " +"Göndermek%s bölümüne bakın." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR için şu SSH parmak izleri kullanılmaktadır:" -#: html/home.php msgid "Discussion" msgstr "Tartışma" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Arch Kullanıcı Deposu (AUR) ve Güvenilir Kullanıcı yapısı ile ilgili genel tartışmalar %saur-general%s üzerinde yapılır. AUR web arayüzü geliştirme süreci ilgili tartışmalar %saur-dev%s listesinde yapılmaktadır." +msgstr "" +"Arch Kullanıcı Deposu (AUR) ve Güvenilir Kullanıcı yapısı ile ilgili genel " +"tartışmalar %saur-general%s üzerinde yapılır. AUR web arayüzü geliştirme " +"süreci ilgili tartışmalar %saur-dev%s listesinde yapılmaktadır." -#: html/home.php msgid "Bug Reporting" msgstr "Hata Bildirimi" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "Paket Ara" -#: html/index.php msgid "Adopt" msgstr "Sorumluluğunu Al" -#: html/index.php msgid "Vote" msgstr "Oy ver" -#: html/index.php msgid "UnVote" msgstr "Oyu kaldır" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Bilgilendirme" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Bildirimi iptal et" -#: html/index.php msgid "UnFlag" msgstr "İşareti Kaldır" -#: html/login.php template/header.php msgid "Login" msgstr "Giriş" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "%s olarak giriş yapıldı" -#: html/login.php template/header.php msgid "Logout" msgstr "Çıkış" -#: html/login.php msgid "Enter login credentials" msgstr "Giriş bilgilerinizi doldurun" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Parola" -#: html/login.php msgid "Remember me" msgstr "Beni hatırla" -#: html/login.php msgid "Forgot Password" msgstr "Parolamı Unuttum" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP oturum açma devredışı. Lütfen oturum açmak için %sHTTPS kullanın%s." +msgstr "" +"HTTP oturum açma devredışı. Lütfen oturum açmak için %sHTTPS kullanın%s." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Arama Ölçütü" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketler" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Paket ayrıntılarını almaya çalışırken hata oluştu." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Gerekli bir alan doldurulmamış." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Parolalar eşleşmiyor." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Şifreniz en az %s karakterden oluşmalıdır." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Geçersiz e-posta adresi" -#: html/passreset.php msgid "Password Reset" msgstr "Parola sıfırlama" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Onaylama bağlantısı için e-posta hesabınızı denetleyin." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Parolanız başarıyla sıfırlandı." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "E-posta adresinizi onaylayın:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Yeni parolanızı girin:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Yeni parolanızı onaylayın:" -#: html/passreset.php msgid "Continue" msgstr "Devam" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Kayıt olurken kullandığınız e-posta adresini hatırlamıyorsanız lütfen %saur-general%s posta listesine mesaj gönderin." +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Kayıt olurken kullandığınız e-posta adresini hatırlamıyorsanız lütfen %saur-" +"general%s posta listesine mesaj gönderin." -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "E-posta adresinizi girin:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "Seçilen paketler için sahiplik bırakılamadı. Onaylama kutucuğunu işaretleyin." +msgstr "" +"Seçilen paketler için sahiplik bırakılamadı. Onaylama kutucuğunu işaretleyin." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "Oyların ve yorumların ilişkilendirilebileceği herhangi bir paket bulunamadı." +msgstr "" +"Oyların ve yorumların ilişkilendirilebileceği herhangi bir paket bulunamadı." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Paket temeli kendisi ile birleştirilemiyor." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "Seçilen paketler silinmedi. Onaylama kutucuğunu işaretleyin." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Paket Silimi" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Paketi sil: %s" +msgid "Delete Package" +msgstr "Paketi Sil" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Bu formu paket temeli %s%s%s ve şu paketleri AUR üzerinden silmek için kullanın: " +msgstr "" +"Bu formu paket temeli %s%s%s ve şu paketleri AUR üzerinden silmek için " +"kullanın: " -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Paket silme işlemi kalıcıdır." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "İşlemi onaylamak için kutucuğu işaretleyin." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Paket silmeyi onaylayın" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Sil" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paket silebilir." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Paket Sahipliğini Bırak" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Paketi sahiplenmeyi bırak: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Şu paketleri içeren %s%s%s paket temelinin sahipliğini bırakmak için bu formu kullanın:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Şu paketleri içeren %s%s%s paket temelinin sahipliğini bırakmak için bu " +"formu kullanın:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "İşaretleme kutucuğunu seçerek paketin sahipliğini bırakmayı ve sahipliği %s%s%s üzerine geçirmeyi kabul ediyorsunuz." +msgstr "" +"İşaretleme kutucuğunu seçerek paketin sahipliğini bırakmayı ve sahipliği %s%s" +"%s üzerine geçirmeyi kabul ediyorsunuz." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "Kutucuğu işaretleyerek paketin sahipliğini bırakmayı kabul ediyorsunuz." +msgstr "" +"Kutucuğu işaretleyerek paketin sahipliğini bırakmayı kabul ediyorsunuz." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Paket sahipliğini bırakmayı onayla" -#: html/pkgdisown.php msgid "Disown" msgstr "Sorumluluğunu bırak" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paketleri sahipsiz bırakabilir." +msgstr "" +"Sadece geliştiriciler ve güvenilir kullanıcılar paketleri sahipsiz " +"bırakabilir." + +msgid "Flag Comment" +msgstr "" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Yorumlar" -#: html/pkgflag.php msgid "Flag" msgstr "İşaretle" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "Paket birleştirme" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Paket Birleştir: %s" +msgid "Merge Package" +msgstr "Paketi Birleştir" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Bu formu paket temeli %s%s%s ile bir başka paketi birleştirmek için kullanın. " +msgstr "" +"Bu formu paket temeli %s%s%s ile bir başka paketi birleştirmek için " +"kullanın. " -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Şu paketler silinecek: " -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Paket birleştirme işlemi geri alınamaz." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Birleştirmek istediğiniz paketin ismini girin." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Şununla birleştir:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Paket birleştirme onayı" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Birleştir" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paket birleştirebilir." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Bir talep doldur" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Kapama Talebi" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "İlk" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Önceki" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "İleri" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Son" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Talepler" -#: html/register.php template/header.php msgid "Register" msgstr "Kayıt ol" -#: html/register.php msgid "Use this form to create an account." msgstr "Yeni bir hesap oluşturmak için bu formu kullanın." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Güvenilen Kullanıcı" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Öneri detayları alınamadı." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Bu öneri için oylama kapanmıştır." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Sadece Güvenilir Kullanıcılar oy kullanabilir." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Sizin hakkınızdaki bir öneride oy kullanamazsınız." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Bu öneri için zaten oy vermişsiniz." -#: html/tu.php msgid "Vote ID not valid." msgstr "Oy kimliği geçersiz." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Mevcut Oylar" -#: html/tu.php msgid "Past Votes" msgstr "Geçmiş Oylar" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Oy verenler" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden hesap oluşturma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +msgstr "" +"Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden hesap " +"oluşturma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Kullanıcı kimliği eksik" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Bu kullanıcı adı geçersizdir." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Uzunluğu %s ve %s karakter arasında olabilir." -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Bir rakam veya harf ile başlatıp bitirmelisiniz" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Sadece bir nokta, alt çizgi veya tire barındırabilir." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-posta adresi geçerli değil." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP anahtarı parmak izi hatalı." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH kamu anahtarı geçersiz." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Hesap izinleri yükseltilemiyor." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Dil henüz desteklenmiyor." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Kullanıcı adı, %s%s%s, zaten kullanılıyor." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adres, %s%s%s, zaten kullanılıyor." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH kamu anahtarı, %s%s%s, zaten kullanımda." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Hesap oluşturulurken hata oluştu, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Hesap, %s%s%s, başarıyla oluşturuldu." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Bir parola sıfırlama anahtarı e-posta adresinize gönderildi." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Hesabınızı kullanmak için Giriş bağlantısını kullanın." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Hesapta değişiklik yapılmadı, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Hesap, %s%s%s, başarıyla düzenlendi." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden giriş yapma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +msgstr "" +"Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden giriş " +"yapma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Hesap donduruldu" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Parolanız sıfırlandı. Kısa süre önce yeni hesap oluşturduysanız lütfen, ilk parolanızı ayarlamak için onaylama e-postasındaki bağlantıyı kullanın. Aksi takdirde, %sParola Sıfırlama%s sayfasında bir sıfırlama anahtarı talep edin." +msgstr "" +"Parolanız sıfırlandı. Kısa süre önce yeni hesap oluşturduysanız lütfen, ilk " +"parolanızı ayarlamak için onaylama e-postasındaki bağlantıyı kullanın. Aksi " +"takdirde, %sParola Sıfırlama%s sayfasında bir sıfırlama anahtarı talep edin." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Yanlış kullanıcı adı veya şifresi." -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Bir kullanıcı oturumu üretilmeye çalışılırken sorun oluştu." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Geçersiz e-posta adresi ve sıfırlama anahtarı bileşimi" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Yok" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "%s için hesap bilgilerini görüntüle" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Yorum eklendi." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "Paket bilgilerini güncellemek için giriş yapmalısınız." + +msgid "Missing comment ID." +msgstr "Yorum kimliği bulunamadı." + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "Paket bilgileri alınırken hata oluştu." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paket ayrıntıları bulunamadı." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Paketleri işaretleyebilmek için giriş yapmalısınız." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "İşaretlenecek paketleri seçmediniz." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "Seçilen paketler güncelliğini yitirmiş olarak işaretlendi." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Paketlerin işaretini kaldırabilmek için giriş yapmalısınız." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "İşareti kaldırılacak paketleri seçmediniz." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Seçilen paketlerin işareti kaldırıldı." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Paket silmek için gerekli izne sahip değilsiniz." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Silinecek paketleri seçmediniz." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Seçilen paketler silindi." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Paketleri sahiplenmek için giriş yapmalısınız." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Paketlerin sahipliğini bırakmak için giriş yapmalısınız." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Sahiplenilecek paketleri seçmediniz." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Sahipliği bırakılacak paketleri seçmediniz." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Seçilen paketler sahiplenildi." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Seçilen paketlerin sahipliği bırakıldı." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Paketlere oy vermeden önce giriş yapmalısınız." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Oy iptali için giriş yapmalısınız." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Oy verilecek paketleri seçmediniz." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Seçtiğiniz paketlerden oyunuz geri alındı." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Seçtiğiniz paketlere oyunuz eklendi." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Bildirim listesine ekleme işlemi başarısız oldu." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "%s bildirim listesine başarıyla eklendiniz." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "%s bildirim listesinden başarıyla çıktınız." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Paket bilgilerini güncellemek için giriş yapmalısınız." +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Yorum kimliği bulunamadı." +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Yorum silindi." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Bu yorumu silme yetkiniz yok." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Yorum silindi." + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "Bu paket temelinin anahtar kelimelerini düzenleme yetkisine sahip değilsiniz." +msgstr "" +"Bu paket temelinin anahtar kelimelerini düzenleme yetkisine sahip değilsiniz." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Paket temeli anahtar kelimeleri güncellendi." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Bu paket temelinin yardımcı bakımcılarını yönetme yetkisine sahip değilsiniz." +msgstr "" +"Bu paket temelinin yardımcı bakımcılarını yönetme yetkisine sahip değilsiniz." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Geçersiz kullanıcı adı: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Paket temeli yardımcı bakımcıları güncellendi." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Paket detaylarını görüntüle" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Paket gereksinimlerinin kaydını tutmalısın." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Geçersiz isim: yalnızca küçük harf kullanılabilir." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Yorum alanı boş olmamalı." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Geçersiz talep türü." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Talep başarıyla eklendi." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Geçersiz sebep." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Sadece GK'lar ve geliştiriciler talepleri kapatabilirler." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Talep başarıyla kapatıldı." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Bu formu kullanarak %s AUR hesabını temelli silebilirsiniz." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUYARI%s: Bu eylem geri döndürülemez." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Silmeyi onayla" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Kullanıcı Adı" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Hesap Türü" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Kullanıcı" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Geliştirici" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Güvenilir Kullanıcı & Geliştirici" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "E-posta adresi" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Gerçek İsim" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Rumuzu" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP Anahtar Parmak İzi" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Durum" -#: template/account_details.php msgid "Inactive since" msgstr "Şu tarihten beri etkin değil:" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Etkin" -#: template/account_details.php msgid "Last Login" msgstr "Son giriş" -#: template/account_details.php msgid "Never" msgstr "Hiç" -#: template/account_details.php msgid "View this user's packages" msgstr "Bu kullanıcı tarafından hazırlanan paketleri göster" -#: template/account_details.php msgid "Edit this user's account" msgstr "Bu kullanıcının hesabını düzenleyin" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Bu hesabı temelli olarak silmek istiyorsanız %sburaya%s tıklayın." -#: template/account_edit_form.php msgid "required" msgstr "gerekli" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normal kullanıcı" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Güvenilen kullanıcı" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Hesap Donduruldu" -#: template/account_edit_form.php msgid "Inactive" msgstr "Etkin değil" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Parolayı tekrar girin" -#: template/account_edit_form.php msgid "Language" msgstr "Dil" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "Aşağıdaki bilgi sadece Arch Kullanıcı Deposu' na paket göndermek istiyorsanız gereklidir." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"Aşağıdaki bilgi sadece Arch Kullanıcı Deposu' na paket göndermek " +"istiyorsanız gereklidir." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH Kamu Anahtarı" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Güncelle" +msgid "Notification settings" +msgstr "" -#: template/account_edit_form.php -msgid "Create" -msgstr "Oluştur" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Sıfırla" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "Arama ölçütünzle eşleşen bir sonuç bulunamadı." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Hesap Bilgilerini Düzenle" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Donduruldu" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Düzenle" - -#: template/account_search_results.php -msgid "Less" -msgstr "Az" - -#: template/account_search_results.php -msgid "More" -msgstr "Fazla" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Gösterilecek daha fazla sonuç yok." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Yardımcı bakımcıları yönet: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "%s%s%s için yardımcı bakımcı eklemek istiyorsanız bu formu kullannı (her satırda bir kullanıcı adı):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Kullanıcılar" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Kaydet" - -#: template/header.php -msgid "My Packages" -msgstr "Paketlerim" - -#: template/header.php -msgid " My Account" -msgstr "Hesabım" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Paket Eylemleri" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "PKGBUILD görüntüle" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Değişiklikleri Görüntüle" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Anlık görüntüsünü indir" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Wikide ara" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Güncelliğini yitirmiş olarak işaretlendi" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Güncelliğini yitirmiş olarak işaretle" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "İşareti kaldır" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Oyu kaldır" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Pakete oy ver" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Bildirimleri kapat" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Yeni yorumları bildir" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "" + +msgid "Update" +msgstr "Güncelle" + +msgid "Create" +msgstr "Oluştur" + +msgid "Reset" +msgstr "Sıfırla" + +msgid "No results matched your search criteria." +msgstr "Arama ölçütünzle eşleşen bir sonuç bulunamadı." + +msgid "Edit Account" +msgstr "Hesap Bilgilerini Düzenle" + +msgid "Suspended" +msgstr "Donduruldu" + +msgid "Edit" +msgstr "Düzenle" + +msgid "Less" +msgstr "Az" + +msgid "More" +msgstr "Fazla" + +msgid "No more results to display." +msgstr "Gösterilecek daha fazla sonuç yok." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"%s%s%s için yardımcı bakımcı eklemek istiyorsanız bu formu kullannı (her " +"satırda bir kullanıcı adı):" + +msgid "Users" +msgstr "Kullanıcılar" + +msgid "Save" +msgstr "Kaydet" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + +msgid "My Packages" +msgstr "Paketlerim" + +msgid " My Account" +msgstr "Hesabım" + +msgid "Package Actions" +msgstr "Paket Eylemleri" + +msgid "View PKGBUILD" +msgstr "PKGBUILD görüntüle" + +msgid "View Changes" +msgstr "Değişiklikleri Görüntüle" + +msgid "Download snapshot" +msgstr "Anlık görüntüsünü indir" + +msgid "Search wiki" +msgstr "Wikide ara" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" + +msgid "Flag package out-of-date" +msgstr "Güncelliğini yitirmiş olarak işaretle" + +msgid "Unflag package" +msgstr "İşareti kaldır" + +msgid "Remove vote" +msgstr "Oyu kaldır" + +msgid "Vote for this package" +msgstr "Pakete oy ver" + +msgid "Disable notifications" +msgstr "Bildirimleri kapat" + msgid "Manage Co-Maintainers" msgstr "Yardımcı Bakımcıları Yönet" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d adet bekleyen talep" msgstr[1] "%d adet bekleyen talep" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Paketi Sil" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Paketi Birleştir" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Paketi Sahiplen" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "bilinmiyor" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Paket Temeli Ayrıntıları" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "salt okunur" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Anahtar kelimeler" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Yükleyen" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Sorumlu" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Son Paketleyici" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Oy" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Beğenilme" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "İlk Yükleme" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Son Güncelleme" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Yorum Ekle" -#: template/pkg_comments.php msgid "View all comments" msgstr "Tüm yorumları görünüle" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "Son Yorumlar" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Yorumu sil" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "Tüm yorumlar" -#: template/pkg_details.php msgid "Package Details" msgstr "Paket Ayrıntıları" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paket Temeli" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Açıklama" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Geliştiricinin Bağlantısı" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Web sayfasını görüntüle" -#: template/pkg_details.php msgid "Licenses" msgstr "Lisanslar" -#: template/pkg_details.php msgid "Groups" msgstr "Gruplar" -#: template/pkg_details.php msgid "Conflicts" msgstr "Çakışır" -#: template/pkg_details.php msgid "Provides" msgstr "Sunar" -#: template/pkg_details.php msgid "Replaces" msgstr "Yerini alır" -#: template/pkg_details.php msgid "Dependencies" msgstr "Bağımlılıklar" -#: template/pkg_details.php msgid "Required by" msgstr "İhtiyaç duyanlar" -#: template/pkg_details.php msgid "Sources" msgstr "Kaynak kodlar" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Kapatma Talebi: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Bu formu %s%s%s paket temeli için yapılan talebi kapatmak için kullanın." +msgstr "" +"Bu formu %s%s%s paket temeli için yapılan talebi kapatmak için kullanın." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Not" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Yorum alanı boş bırakılabilir. Ancak, bir talebi reddederken bir yorum eklemeniz şiddetle önerilir." +msgstr "" +"Yorum alanı boş bırakılabilir. Ancak, bir talebi reddederken bir yorum " +"eklemeniz şiddetle önerilir." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Sebep" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Kabul edildi" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Reddedildi" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Dosya Talebi: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Bu formu kullanarak aşağıdaki paketleri içeren paket temeli %s%s%s için talep doldurun:" +msgstr "" +"Bu formu kullanarak aşağıdaki paketleri içeren paket temeli %s%s%s için " +"talep doldurun:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Talep türü" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Silme" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Öksüz" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Şununla ilişkilendir:" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d adet paket talebi bulundu." msgstr[1] "%d adet paket talebi bulundu." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Sayfa %d / %d" -#: template/pkgreq_results.php msgid "Package" msgstr "Paket" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Dolduran" -#: template/pkgreq_results.php msgid "Date" msgstr "Tarih" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d gün kaldı" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d saat kaldı" msgstr[1] "~%d saat kaldı" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 saat kaldı" -#: template/pkgreq_results.php msgid "Accept" msgstr "Kabul" -#: template/pkgreq_results.php msgid "Locked" msgstr "Kilitli" -#: template/pkgreq_results.php msgid "Close" msgstr "Kapat" -#: template/pkgreq_results.php msgid "Closed" msgstr "Kapandı" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "İsim, Açıklama" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Sadece İsim" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Tam Ad" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Tam Paket Temeli" -#: template/pkg_search_form.php msgid "All" msgstr "Tümü" -#: template/pkg_search_form.php msgid "Flagged" msgstr "İşaretlenmiş" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "İşaretlenmemiş" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "İsim" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Oylanmış" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Eskiden yeniye" -#: template/pkg_search_form.php msgid "Descending" msgstr "Yeniden eskiye" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Arama kriteri girin" -#: template/pkg_search_form.php msgid "Search by" msgstr "Buna göre ara" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Güncelliğini Yitirmiş" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sırala" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Sıralama düzeni" -#: template/pkg_search_form.php msgid "Per page" msgstr "Her sayfa" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Git" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Sahipsiz" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Paket listesi alınırken hata oluştu." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Arama ölçütünüz ile eşleşen paket bulunamadı." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d adet paket bulundu." msgstr[1] "%d adet paket bulundu." -#: template/pkg_search_results.php msgid "Version" msgstr "Sürüm" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "Beğenilirlik, oluşturulmasından itibaren günlük 0.98 oranı ile çarpılarak bulunan her oyun toplamı ile ölçülür." +msgstr "" +"Beğenilirlik, oluşturulmasından itibaren günlük 0.98 oranı ile çarpılarak " +"bulunan her oyun toplamı ile ölçülür." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Evet" -#: template/pkg_search_results.php msgid "orphan" msgstr "sahipsiz" -#: template/pkg_search_results.php msgid "Actions" msgstr "Eylemler" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Güncelliğini yitirmiş olarak işaretle" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "\"Güncelliğini Yitirmiş\" İşaretini Kaldır" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Paketleri Sahiplen" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Paketleri sahiplenmeyi bırak" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Paketleri Sil" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Onayla" -#: template/search_accounts_form.php msgid "Any type" msgstr "Herhangi bir tür" -#: template/search_accounts_form.php msgid "Search" msgstr "Ara" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "İstatistikler" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Sahipsiz Paketler" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Son 7 günde eklenen paketler" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Son 7 günde güncellenen paketler" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Geçtiğimiz yıl güncellenen paketler" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Hiç güncellenmemiş paketler" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Kayıtlı Kullanıcılar" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Güvenilen Kullanıcılar" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Son Güncellemeler" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "İstatistiklerim" -#: template/tu_details.php msgid "Proposal Details" msgstr "Öneri Detayları" -#: template/tu_details.php msgid "This vote is still running." msgstr "Bu oylama hala yürürlükte." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Yüklendi: %s %s tarafından" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Son" -#: template/tu_details.php msgid "Result" msgstr "Sonuç" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Hayır" -#: template/tu_details.php msgid "Abstain" msgstr "Çekimser" -#: template/tu_details.php msgid "Total" msgstr "Toplam" -#: template/tu_details.php msgid "Participation" msgstr "Katkı" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "GK tarafından verilen son oylar" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Son Oy" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Sonuç bulunamadı." -#: template/tu_list.php msgid "Start" msgstr "Başlangıç" -#: template/tu_list.php msgid "Back" msgstr "Geri" diff --git a/po/uk.po b/po/uk.po index ce607299..b2ac3dcc 100644 --- a/po/uk.po +++ b/po/uk.po @@ -1,1279 +1,1086 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Lukas Fleischer , 2011 # Rax Garfield , 2012 # Rax Garfield , 2012 -# Yarema aka Knedlyk , 2011-2015 +# Yarema aka Knedlyk , 2011-2016 # Данило Коростіль , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 06:13+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 23:36+0000\n" "Last-Translator: Yarema aka Knedlyk \n" -"Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/uk/)\n" +"Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" +"uk/)\n" +"Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: uk\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -#: html/404.php msgid "Page Not Found" msgstr "Сторінку не знайдено" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "На жаль, запитаної сторінки не існує." -#: html/503.php msgid "Service Unavailable" msgstr "Сервіс недоступний" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Не панікуйте! Сторінка закрита на технічне обслуговування. Ми швидко повернемося." +msgstr "" +"Не панікуйте! Сторінка закрита на технічне обслуговування. Ми швидко " +"повернемося." -#: html/account.php msgid "Account" msgstr "Обліковий запис" -#: html/account.php template/header.php msgid "Accounts" msgstr "Облікові записи" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "У вас недостатньо прав доступу." -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Не вдалося отримати інформацію про вказаного користувача." -#: html/account.php msgid "You do not have permission to edit this account." msgstr "У вас недостатньо прав для редагування цього облікового запису." -#: html/account.php msgid "Use this form to search existing accounts." msgstr "Шукайте облікові записи за допомогою цієї форми." -#: html/account.php msgid "You must log in to view user information." msgstr "Ви повинні увійти в систему для перегляду даних користувача." -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Додати пропозицію" -#: html/addvote.php msgid "Invalid token for user action." msgstr "Невірний маркер для дій користувача." -#: html/addvote.php msgid "Username does not exist." msgstr "Користувача не існує." -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s вже мають зареєстровану на себе пропозицію." -#: html/addvote.php msgid "Invalid type." msgstr "Неправильний тип." -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Пропозиція не може бути порожньою." -#: html/addvote.php msgid "New proposal submitted." msgstr "Нову пропозицію надіслано." -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Надіслати пропозицію для голосування." -#: html/addvote.php msgid "Applicant/TU" msgstr "Претендент/Довірений користувач" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(Порожньо, якщо не застосовується)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "Тип" -#: html/addvote.php msgid "Addition of a TU" msgstr "Додавання довіреного користувача" -#: html/addvote.php msgid "Removal of a TU" msgstr "Вилучення довіреного користувача" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Вилучення довіреного користувача (неоголошена бездіяльність)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Поправки до Статуту" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Пропозиція" -#: html/addvote.php msgid "Submit" msgstr "Надіслати пакунок" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "Керування супровідниками" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Редагувати коментар" -#: html/home.php template/header.php msgid "Home" msgstr "Початкова сторінка" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "Раді вітати вас в «AUR» — у сховищі користувацьких пакунків. Розширена довідка надана в %sінструкції користувача AUR%s та %sінструкції довіреного користувача (TU) AUR%s." +msgstr "" +"Раді вітати вас в «AUR» — у сховищі користувацьких пакунків. Розширена " +"довідка надана в %sінструкції користувача AUR%s та %sінструкції довіреного " +"користувача (TU) AUR%s." -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Надіслані PKGBUILD %sповинні%s задовольняти %sстандарти пакування%s, інакше вони вилучаються." +msgstr "" +"Надіслані PKGBUILD %sповинні%s задовольняти %sстандарти пакування%s, інакше " +"вони вилучаються." -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Не забудьте проголосувати за улюблені пакунки!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Деякі пакунки можуть бути в бінарному вигляді у сховищі [community]." -#: html/home.php msgid "DISCLAIMER" msgstr "ВІДМОВА ВІД ВІДПОВІДАЛЬНОСТІ" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "Пакунки у сховищі AUR - це пакунки, створені користувачами. Ви можете використовувати їх тільки на Ваш власний страх і ризик." +msgstr "" +"Пакунки у сховищі AUR - це пакунки, створені користувачами. Ви можете " +"використовувати їх тільки на Ваш власний страх і ризик." -#: html/home.php msgid "Learn more..." msgstr "Дізнатись більше..." -#: html/home.php msgid "Support" msgstr "Підтримка" -#: html/home.php msgid "Package Requests" -msgstr "Запит пакунку" +msgstr "Запит щодо пакунку" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" -msgstr "Існують три типи запитів, які можна заповнити в полі %sДія над пакунком%s на сторінці подробиць пакунку:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" +msgstr "" +"Існують три типи запитів, які можна створити в полі %sДія над пакунком%s на " +"сторінці подробиць пакунку:" -#: html/home.php msgid "Orphan Request" -msgstr "Запит на покинення пакунку" +msgstr "Запит щодо покинення пакунку" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "Запит на позбавлення пакунка власника, наприклад, коли супровідник пакунку неактивний і пакунок позначений як застарілий вже довгий період часу." +msgstr "" +"Запит щодо позбавлення пакунка власника, наприклад, коли супровідник пакунку " +"неактивний і пакунок позначений як застарілий вже довгий період часу." -#: html/home.php msgid "Deletion Request" -msgstr "Запит на вилучення" +msgstr "Запит щодо вилучення" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Запит на вилучення пакунку зі Сховища Користувацьких Пакунків AUR. Будь ласка, не використовуйте це, якщо пакунок є зламаний і його можна легко направити. Для цього зв’яжіться з супровідником пакунку і заповніть форму на покинення пакунку в разі необхідності." +msgstr "" +"Запит щодо вилучення пакунку зі Сховища Користувацьких Пакунків AUR. Будь " +"ласка, не використовуйте його, якщо пакунок містить ваду, яку можна легко " +"виправити. Для цього зв’яжіться з супровідником пакунку і заповніть форму на " +"покинення пакунку в разі необхідності." -#: html/home.php msgid "Merge Request" -msgstr "Запит на злиття" +msgstr "Запит щодо злиття" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "Запит на злиття пакунку з іншим пакунком. Цей запит можна використати, коли потрібно перейменувати пакунок або замінити на розділений пакунок." +msgstr "" +"Запит щодо злиття пакунку з іншим пакунком. Цей запит можна використати, " +"коли потрібно перейменувати пакунок або замінити на розділений пакунок." -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "Якщо Ви бажаєте обговорити запит, використайте список розсилки %saur-requests%s. Будь ласка, не використовуйте цю розсилку для подання запитів." +msgstr "" +"Якщо Ви бажаєте обговорити запит, використайте список розсилки %saur-requests" +"%s. Будь ласка, не використовуйте цю розсилку для подання запитів." -#: html/home.php msgid "Submitting Packages" msgstr "Надсилання пакунків" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Git через SSH тепер використовується для надсилання пакунків до AUR. Для деталей дивіться розділ %sНадсилання пакунків%s на сторінці ArchWiki про Сховище Користувацьких Пакунків AUR." +msgstr "" +"Git через SSH тепер використовується для надсилання пакунків до AUR. Для " +"деталей дивіться розділ %sНадсилання пакунків%s на сторінці ArchWiki про " +"Сховище Користувацьких Пакунків AUR." -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Наступні відбитки ключів SSH використовуються в AUR:" -#: html/home.php msgid "Discussion" msgstr "Обговорення" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "Загальне обговорення сховища користувацьких пакунків (AUR) та структури довірених користувачів відбувається в %saur-general%s. Для дискусій про розробку AUR використовуйте список розсилання %saur-dev%s." +msgstr "" +"Загальне обговорення сховища користувацьких пакунків (AUR) та структури " +"довірених користувачів відбувається в %saur-general%s. Для дискусій про " +"розробку AUR використовуйте список розсилання %saur-dev%s." -#: html/home.php msgid "Bug Reporting" msgstr "Повідомлення про вади" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." -msgstr "Якщо Ви знайдете ваду у веб-інтерфейсі AUR, повідомте про це нас на нашому %sтрекері вад%s. Таким чином слід сповіщати %sлише%s про проблеми у веб-інтерфейсі AUR. Про вади пакунка зв’яжіться з його супровідником або залиште коментар на відповідній сторінці цього пакунка." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." +msgstr "" +"Якщо Ви знайдете ваду у веб-інтерфейсі AUR, повідомте про це нас на нашому " +"%sтрекері вад%s. Таким чином слід сповіщати %sлише%s про проблеми у веб-" +"інтерфейсі AUR. Про вади пакунка зв’яжіться з його супровідником або залиште " +"коментар на відповідній сторінці цього пакунка." -#: html/home.php msgid "Package Search" msgstr "Пошук пакунків" -#: html/index.php msgid "Adopt" msgstr "Прийняти" -#: html/index.php msgid "Vote" msgstr "Проголосувати" -#: html/index.php msgid "UnVote" msgstr "Забрати голос" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Сповіщати" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Не сповіщати" -#: html/index.php msgid "UnFlag" msgstr "Зняти позначку" -#: html/login.php template/header.php msgid "Login" msgstr "Увійти" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "Ввійшов як: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "Вийти" -#: html/login.php msgid "Enter login credentials" msgstr "Увійдіть, ввівши облікові дані." -#: html/login.php msgid "User name or email address" msgstr "Назва користувача або адреса електронної пошти" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Пароль" -#: html/login.php msgid "Remember me" msgstr "Запам'ятати мене" -#: html/login.php msgid "Forgot Password" msgstr "Забули пароль?" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "Реєстрування через HTTP вимкнено. Будь-ласка, %sперейдіть на HTTPs%s для входу." +msgstr "" +"Реєстрування через HTTP вимкнено. Будь-ласка, %sперейдіть на HTTPs%s для " +"входу." -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Критерії пошуку" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Пакунки" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Стався збій під час пошуку інформації про пакунок." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Бракує обов’язкового рядка." -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Паролі не збігаються." -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Ваш пароль має містити щонайменше %s символів." -#: html/passreset.php msgid "Invalid e-mail." msgstr "Неправильна електронна адреса." -#: html/passreset.php msgid "Password Reset" msgstr "Скидання паролю" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Перевірте свою електронну пошту для підтвердження." -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Ваш пароль успішно скинуто." -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Підтвердьте адресу електронної пошти:" -#: html/passreset.php msgid "Enter your new password:" msgstr "Введіть новий пароль:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "Підтвердження нового паролю:" -#: html/passreset.php msgid "Continue" msgstr "Продовжити" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Якщо Ви забули електронну адресу, використану при реєстрації, зверніться до списку розсилання %saur-general%s" +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"Якщо Ви забули електронну адресу, використану при реєстрації, зверніться до " +"списку розсилання %saur-general%s" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Введіть адресу електронної пошти:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "Вибрані пакунки не мають міток, подайте коментар, будь ласка." - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Вибрані пакунки все ще мають власника, підтвердіть дію." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Не вдалося знайти пакунок для об’єднання голосів та коментарів." -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Неможливо злити пакунок з самим собою." -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." -msgstr "Обрані пакунки не вилучено, перевірте, чи поставлено галочку в полі підтвердження." +"The selected packages have not been deleted, check the confirmation checkbox." +msgstr "" +"Обрані пакунки не вилучено, перевірте, чи поставлено галочку в полі " +"підтвердження." -#: html/pkgdel.php msgid "Package Deletion" msgstr "Вилучення пакунку" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "Вилучити пакунок: %s" +msgid "Delete Package" +msgstr "Вилучити пакунок" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "Використовуйте цю форму для вилучення пакунку %s%s%s з AUR. " -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Вилучення пакунку є безповоротне." -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Встановіть галочку, щоб підтвердити дію." -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Підтвердити вилучення пакунку" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Вилучити" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Тільки Довірені Користувачі та Розробники можуть вилучати пакунки." -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Зректися пакунку" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "Позбавлення пакунка власника: %s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " -msgstr "Використайте ці форму для позбавлення базового пакунка %s%s%s власника, який містить наступні пакунки:" +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " +msgstr "" +"Використайте ці форму для позбавлення базового пакунка %s%s%s власника, який " +"містить наступні пакунки:" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника і перенести права власності до %s%s%s." +msgstr "" +"Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника і " +"перенести права власності до %s%s%s." -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника." -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Підтвердіть позбавлення пакунка власника" -#: html/pkgdisown.php msgid "Disown" msgstr "Відректися" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "Тільки Довірені Користувачі та Розробники можуть забирати права власності на пакунок." +msgstr "" +"Тільки Довірені Користувачі та Розробники можуть забирати права власності на " +"пакунок." + +msgid "Flag Comment" +msgstr "Позначити коментар" -#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Позначити пакунок як застарілий" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "Позначити пакунок як застарілий: %s" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " -msgstr "Використовуйте цю форму для позначення базового пакунку %s%s%s і наступні пакунки як застарілі:" +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " +msgstr "" +"Використовуйте цю форму для позначення базового пакунку %s%s%s і наступні " +"пакунки як застарілі:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "Будь ласка, %sне%s використовуйте цю форму для повідомлення про вади. Використовуйте для цього коментарі до пакунку." +msgstr "" +"Будь ласка, %sне%s використовуйте цю форму для повідомлення про вади. " +"Використовуйте для цього коментарі до пакунку." -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "Введіть нижче деталі, чому пакунок є застарілим, по можливості подайте посилання до оголошення про новий випуск або архів оновленого випуску." +msgstr "" +"Введіть нижче деталі, чому пакунок є застарілим, по можливості подайте " +"посилання до оголошення про новий випуск або архів оновленого випуску." -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "Коментарі" -#: html/pkgflag.php msgid "Flag" msgstr "Позначити" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "Тільки зареєстровані користувачі можуть позначати пакунки як застарілі." +msgstr "" +"Тільки зареєстровані користувачі можуть позначати пакунки як застарілі." -#: html/pkgmerge.php msgid "Package Merging" msgstr "Об’єднання пакунків" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "Об’єднати пакунки: %s" +msgid "Merge Package" +msgstr "Об’єднати пакунок" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Використовуйте цю форму для злиття пакунку %s%s%s з іншим пакунком." -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Наступні пакунки будуть вилучені:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Як тільки пакунок буде об’єднаний, його вже неможливо повернути." -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Введіть назву пакунка, до якого потрібно приєднати цей." -#: html/pkgmerge.php msgid "Merge into:" msgstr "Об’єднати з:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Підтвердити об’єднання пакунків" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Об’єднати" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Тільки Довірені Користувачі та Розробники можуть об’єднувати пакунки." -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "Запит файлу" +msgid "Submit Request" +msgstr "Надіслати запит" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" -msgstr "Замкнути запит" +msgstr "Закриття запиту" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Перший" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Попередній" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далі" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Останній" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Запити" -#: html/register.php template/header.php msgid "Register" msgstr "Зареєструватись" -#: html/register.php msgid "Use this form to create an account." msgstr "Створіть обліковий запис за допомогою цієї форми." -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Довірений користувач" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Не вдалось отримати подробиць пропозиції." -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Голосування на цю пропозицію закрито." -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Тільки Довірені Користувачі мають право голосу." -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Ви не можете голосувати за свою пропозицію." -#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ви вже проголосували за цю пропозицію." -#: html/tu.php msgid "Vote ID not valid." msgstr "Ідентифікатор голосу неправильний." -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Поточні голосування" -#: html/tu.php msgid "Past Votes" msgstr "Минулі голосування" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Проголосували" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Реєстрація рахунку закрита для Вашої адреси IP, можливо із-за інтенсивної спам-атаки. Вибачте за незручності." +msgstr "" +"Реєстрація рахунку закрита для Вашої адреси IP, можливо із-за інтенсивної " +"спам-атаки. Вибачте за незручності." -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Бракує ідентифікатора користувача" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Користувач неправильний." -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Кількість символів повинна бути від %s до %s" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Початок та кінець з літери або цифри" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Може містити тільки один період, підкреслення або дефіс." -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Адреса електронної пошти неправильна." -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Відбиток ключа PGP недійсний." -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Неправильний публічний ключ SSH." -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Неможливо збільшити дозволи рахунку." -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Наразі ця мова не підтримується." -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Назва користувача %s%s%s вже використовується." -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Адрес %s%s%s вже використовується." -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Публічний ключ SSH, %s%s%s, вже використовується." -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Помилка при спробі створити рахунок %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Рахунок %s%s%s успішно створено." -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ключ скидання пароля висланий на Вашу адресу електронної пошти." -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "Використовуйте обліковий запис, увійшовши за допомогою посилання «Увійти» (згори)." +msgstr "" +"Використовуйте обліковий запис, увійшовши за допомогою посилання " +"«Увійти» (згори)." -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Ніяких змін не внесено до рахунку, %s%s%s." -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Рахунок %s%s%s успішно змінено." -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Форма логування зараз заборонена для Вашої адреси IP, можливо із-за інтенсивної спам-атаки. Вибачте за незручності." +msgstr "" +"Форма логування зараз заборонена для Вашої адреси IP, можливо із-за " +"інтенсивної спам-атаки. Вибачте за незручності." -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Рахунок вилучено" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Ваш пароль скинуто. Якщо Ви щойно створили новий рахунок, тоді використайте посилання електронного листа-підтвердження для встановлення початкового пароля. В протилежному випадку використайте запит на скидання паролю на сторінці %sPassword Reset%s." +msgstr "" +"Ваш пароль скинуто. Якщо Ви щойно створили новий рахунок, тоді використайте " +"посилання електронного листа-підтвердження для встановлення початкового " +"пароля. В протилежному випадку використайте запит щодо скидання паролю на " +"сторінці %sPassword Reset%s." -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Неправильний користувач або пароль. " -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Сталася помилка під час створення сесії користувача." -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Неприпустима адреса електронної пошти й комбінація клавіш скидання." -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Немає" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Показати інформацію про рахунок для %s" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "ID базового пакунку або ж назва базового пакунку пропущена." -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "У вас немає прав, щоб редагувати цей коментар." -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Коментаря не існує." -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Коментар не може бути порожнім." -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Коментар додано." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "" +"Ви повинні увійти у систему, щоб мати можливість редагувати інформацію про " +"пакунок." + +msgid "Missing comment ID." +msgstr "Немає ідентифікатора коментаря." + +msgid "No more than 5 comments can be pinned." +msgstr "Можна прикріпити не більше 5 коментарів." + +msgid "You are not allowed to pin this comment." +msgstr "Вам заборонено прикріпляти цей коментар." + +msgid "You are not allowed to unpin this comment." +msgstr "Вам заборонено відкріпляти цей коментар." + +msgid "Comment has been pinned." +msgstr "Коментар прикріплено." + +msgid "Comment has been unpinned." +msgstr "Коментар відкріплено." + msgid "Error retrieving package details." msgstr "Помилка пошуку інформації про пакунок." -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Інформації про пакунок не знайдено." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Для встановлення мітки слід увійти." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Ви не вибрали жодного пакунку для мітки." -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "Вибрані пакунки не мають міток, подайте коментар, будь ласка." + msgid "The selected packages have been flagged out-of-date." msgstr "Для вибраних пакунків призначено мітку «застарілий»." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Для зняття мітки слід увійти." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Не вибрано жодного пакунку, щоб зняти мітку." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "З вибраних пакунків було знято мітку." -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "У Вас немає прав для вилучення пакунків." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Не вибрано жодного пакунку для вилучення." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Вибрані пакунки вилучено." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Для перейняття пакунків слід увійти." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Для зречення пакунків слід увійти." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Ви не вибрали жодного пакунку для переймання." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Не вибрано жодного пакунку, щоб зректись." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Вибрані пакунки перейнято." -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Ви зреклись вибраних пакунків." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Для голосування слід увійти." -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Для скасування голосу слід увійти." -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Ви не вибрали жодного пакунка для голосування." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Ваші голоси вилучено з вибраних пакунків." -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Ви проголосували за вибрані пакунки." -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Неможливо долучити до списку соповіщень." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Вас долучено до списку сповіщень про коментарі для %s." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Вас вилучено із списку сповіщень про коментарі для %s." -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "Ви повинні увійти у систему, щоб мати можливість редагувати інформацію про пакунок." +msgid "You are not allowed to undelete this comment." +msgstr "Вам заборонено відновлювати цей коментар." -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "Немає ідентифікатора коментаря." +msgid "Comment has been undeleted." +msgstr "Коментар відновлено." -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "Коментар вилучено." - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "У вас немає прав, щоб вилучити цей коментар." -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "Коментар вилучено." + msgid "Comment has been edited." msgstr "Коментар редаговано." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "Ви не маєте прав для редагування ключових слів для цього базового пакунку." +msgstr "" +"Ви не маєте прав для редагування ключових слів для цього базового пакунку." -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ключові слова базового пакунку оновлено." -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Ви не має прав для керування супровідниками цього базового пакунку." -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Неправильна назва користувача: %s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Оновлено супровідників базового пакунку." -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Показати деталі пакунку для " -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "вимагається %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." -msgstr "Ви повинні увійти, щоб робити запит пакунків." +msgstr "Ви повинні увійти, щоб створювати запити щодо пакунків." -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Неправильна назва: дозволено тільки малі літери." -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Поле коментаря не повинно пустувати." -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Неправильний тип запиту." -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Запит успішно додано." -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Неправильна причина." -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Тільки TU (довірені користувачі) і розробники можуть закривати запити." -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Запит успішно закритий." -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ви можете використати цю форму для вилучення рахунку в AUR %s." -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sУВАГА%s: Цю дію неможливо відмінити." -#: template/account_delete.php msgid "Confirm deletion" msgstr "Підтвердити вилучення" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Користувач" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "Тип облікового запису" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Користувач" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "Розробник" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Довірений користувач & Розробник" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Адреса електронної пошти" -#: template/account_details.php msgid "hidden" msgstr "приховано" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Справжнє ім'я" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Псевдонім IRC" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Відбиток ключа PGP" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "Статус" -#: template/account_details.php msgid "Inactive since" msgstr "Неактивний з" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Активний" -#: template/account_details.php msgid "Last Login" msgstr "Останній вхід" -#: template/account_details.php msgid "Never" msgstr "Ніколи" -#: template/account_details.php msgid "View this user's packages" msgstr "Переглянути пакунки цього користувача" -#: template/account_details.php msgid "Edit this user's account" msgstr "Редагування рахунку цього користувача" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Натисніть %sтут%s, якщо Ви бажаєте безповоротно вилучити цей рахунок." -#: template/account_edit_form.php msgid "required" msgstr "обов'язково" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Звичайний користувач" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Довіренний користувач" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Обліковий запис призупинено" -#: template/account_edit_form.php msgid "Inactive" msgstr "Неактивний" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "Будь ласка переконайтесь, що Ви правильно ввели Вашу адресу електронної пошти, інакше Ви будете заблоковані." +msgstr "" +"Будь ласка переконайтесь, що Ви правильно ввели Вашу адресу електронної " +"пошти, інакше Ви будете заблоковані." -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Приховати адресу електронної пошти" -#: template/account_edit_form.php msgid "Re-type password" msgstr "Введіть пароль ще раз" -#: template/account_edit_form.php msgid "Language" msgstr "Мова" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." -msgstr "Наступну інформацію потрібно, якщо Ви бажаєте надіслати пакунки до Сховища Користувацьких Пакунків AUR." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." +msgstr "" +"Наступну інформацію потрібно, якщо Ви бажаєте надіслати пакунки до Сховища " +"Користувацьких Пакунків AUR." -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Публічний ключ SSH" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php -msgid "Update" -msgstr "Оновити" +msgid "Notification settings" +msgstr "Налаштування повідомлень" -#: template/account_edit_form.php -msgid "Create" -msgstr "Створити" - -#: template/account_edit_form.php template/search_accounts_form.php -msgid "Reset" -msgstr "Очистити" - -#: template/account_search_results.php -msgid "No results matched your search criteria." -msgstr "За вашим запитом нічого не знайдено." - -#: template/account_search_results.php -msgid "Edit Account" -msgstr "Редагувати обліковий запис" - -#: template/account_search_results.php -msgid "Suspended" -msgstr "Призупинено" - -#: template/account_search_results.php -msgid "Edit" -msgstr "Редагувати" - -#: template/account_search_results.php -msgid "Less" -msgstr "Менше" - -#: template/account_search_results.php -msgid "More" -msgstr "Більше" - -#: template/account_search_results.php -msgid "No more results to display." -msgstr "Більше немає результатів." - -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "Керування супровідниками: %s" - -#: template/comaintainers_form.php -#, php-format -msgid "" -"Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Використайте цю форму для додавання супровідника для %s%s%s (одна назва користувача в одній стрічці):" - -#: template/comaintainers_form.php -msgid "Users" -msgstr "Користувачі" - -#: template/comaintainers_form.php template/pkg_comment_form.php -msgid "Save" -msgstr "Зберегти" - -#: template/header.php -msgid "My Packages" -msgstr "Мої пакунки" - -#: template/header.php -msgid " My Account" -msgstr "Мій рахунок" - -#: template/pkgbase_actions.php -msgid "Package Actions" -msgstr "Дії над пакунком" - -#: template/pkgbase_actions.php -msgid "View PKGBUILD" -msgstr "Переглянути PKGBUILD" - -#: template/pkgbase_actions.php -msgid "View Changes" -msgstr "Переглянути зміни" - -#: template/pkgbase_actions.php -msgid "Download snapshot" -msgstr "Звантажити поточну версію" - -#: template/pkgbase_actions.php -msgid "Search wiki" -msgstr "Шукати у Вікі" - -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "Позначено як застарілий" - -#: template/pkgbase_actions.php -msgid "Flag package out-of-date" -msgstr "Позначити пакунок як застарілий" - -#: template/pkgbase_actions.php -msgid "Unflag package" -msgstr "Відмінити позначення" - -#: template/pkgbase_actions.php -msgid "Remove vote" -msgstr "Вилучити голос" - -#: template/pkgbase_actions.php -msgid "Vote for this package" -msgstr "Голосувати за цей пакунок" - -#: template/pkgbase_actions.php -msgid "Disable notifications" -msgstr "Відключити сповіщення" - -#: template/pkgbase_actions.php msgid "Notify of new comments" msgstr "Сповіщати про нові коментарі" -#: template/pkgbase_actions.php +msgid "Notify of package updates" +msgstr "Повідомлення про оновлення пакунків" + +msgid "Update" +msgstr "Оновити" + +msgid "Create" +msgstr "Створити" + +msgid "Reset" +msgstr "Очистити" + +msgid "No results matched your search criteria." +msgstr "За вашим запитом нічого не знайдено." + +msgid "Edit Account" +msgstr "Редагувати обліковий запис" + +msgid "Suspended" +msgstr "Призупинено" + +msgid "Edit" +msgstr "Редагувати" + +msgid "Less" +msgstr "Менше" + +msgid "More" +msgstr "Більше" + +msgid "No more results to display." +msgstr "Більше немає результатів." + +#, php-format +msgid "" +"Use this form to add co-maintainers for %s%s%s (one user name per line):" +msgstr "" +"Використайте цю форму для додавання супровідника для %s%s%s (одна назва " +"користувача в одній стрічці):" + +msgid "Users" +msgstr "Користувачі" + +msgid "Save" +msgstr "Зберегти" + +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "%s%s%s позначено %s%s%s як застарілий на %s%s%s з наступної причини:" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "%s%s%s не позначений як застарілий." + +msgid "Return to Details" +msgstr "Повернення до подробиць." + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Всі права застережено %s 2004-%d Команда Розробників aurweb." + +msgid "My Packages" +msgstr "Мої пакунки" + +msgid " My Account" +msgstr "Мій рахунок" + +msgid "Package Actions" +msgstr "Дії над пакунком" + +msgid "View PKGBUILD" +msgstr "Переглянути PKGBUILD" + +msgid "View Changes" +msgstr "Переглянути зміни" + +msgid "Download snapshot" +msgstr "Звантажити поточну версію" + +msgid "Search wiki" +msgstr "Шукати у Вікі" + +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "Позначено як застарілий (%s)" + +msgid "Flag package out-of-date" +msgstr "Позначити пакунок як застарілий" + +msgid "Unflag package" +msgstr "Відмінити позначення" + +msgid "Remove vote" +msgstr "Вилучити голос" + +msgid "Vote for this package" +msgstr "Голосувати за цей пакунок" + +msgid "Disable notifications" +msgstr "Відключити сповіщення" + msgid "Manage Co-Maintainers" msgstr "Керування Супровідниками" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1281,262 +1088,206 @@ msgstr[0] "%d запит в обробці" msgstr[1] "%d запитів в обробці" msgstr[2] "%d запитів в обробці" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "Вилучити пакунок" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "Об’єднати пакунок" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Прийняти пакунок" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "невідомо" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Деталі бази пакунків" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Адреса URL для клонування Git" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "тільки для читання" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "Ключові слова" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "Подавач" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Супровідник" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Останній збирач пакунку" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Голоси" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Популярність" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Вперше надіслано" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Останній раз оновлено" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Редагувати коментар для: %s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Додати коментар" -#: template/pkg_comments.php msgid "View all comments" msgstr "Переглянути всі коментарі" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "Прикріплені коментарі" + msgid "Latest Comments" msgstr "Останні коментарі" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s коментував про %s" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Анонімний коментар про %s" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "вилучено на %s через %s" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "востаннє редагувалося на %s через %s" +msgid "deleted on %s" +msgstr "вилучено %s" + +#, php-format +msgid "edited on %s by %s" +msgstr "редаговано %s через %s" + +#, php-format +msgid "edited on %s" +msgstr "редаговано %s" + +msgid "Undelete comment" +msgstr "Відновити коментар" -#: template/pkg_comments.php msgid "Delete comment" msgstr "Вилучити коментар" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "Прикріпити коментар" + +msgid "Unpin comment" +msgstr "Відкріпити коментар" + msgid "All comments" msgstr "Всі коментарі" -#: template/pkg_details.php msgid "Package Details" msgstr "Подробиці пакунку" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "База пакунків" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Опис" -#: template/pkg_details.php msgid "Upstream URL" msgstr "Посилання" -#: template/pkg_details.php msgid "Visit the website for" msgstr "Відвідати веб-сторінку для" -#: template/pkg_details.php msgid "Licenses" msgstr "Ліцензії" -#: template/pkg_details.php msgid "Groups" msgstr "Групи" -#: template/pkg_details.php msgid "Conflicts" msgstr "Конфлікти" -#: template/pkg_details.php msgid "Provides" msgstr "Забезпечує" -#: template/pkg_details.php msgid "Replaces" msgstr "Замінює" -#: template/pkg_details.php msgid "Dependencies" msgstr "Залежності" -#: template/pkg_details.php msgid "Required by" msgstr "Потрібен для" -#: template/pkg_details.php msgid "Sources" msgstr "Сирці" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "Закрити запит: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Використайте цю форму для закриття запиту бази пакетів %s%s%s." +msgstr "Використайте цю форму для закриття запиту щодо бази пакетів %s%s%s." -#: template/pkgreq_close_form.php msgid "Note" msgstr "Примітка" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "Поле коментарів може залишатися пустим. Тим не менше, рекомендовано залишити коментар при відкиданні запиту." +msgstr "" +"Поле коментарів може залишатися пустим. Тим не менше, рекомендовано залишити " +"коментар при відкиданні запиту." -#: template/pkgreq_close_form.php msgid "Reason" msgstr "Причина" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "Прийнято" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "Відхилено" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "Запит файлу: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "Використайте цю форму для запиту файлу з бази пакунків %s%s%s, який містить наступні пакунки:" +msgstr "" +"Використайте цю форму для створення запиту щодо бази пакунків %s%s%s, яка " +"містить наступні пакунки:" -#: template/pkgreq_form.php msgid "Request type" msgstr "Тип запиту" -#: template/pkgreq_form.php msgid "Deletion" msgstr "Вилучення" -#: template/pkgreq_form.php msgid "Orphan" msgstr "Позначити застарілим" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Об'єднати в" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Знайдено %d запит пакунку." msgstr[1] "Знайдено %d запитів пакунку." -msgstr[2] "Знайдено %d запитів пакунку." +msgstr[2] "Знайдено %d запитів щодо пакунків." -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Сторінка %d з %d." -#: template/pkgreq_results.php msgid "Package" msgstr "Пакунок" -#: template/pkgreq_results.php msgid "Filed by" msgstr "Запаковано через" -#: template/pkgreq_results.php msgid "Date" msgstr "Дата" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "~%d днів залишилося" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1544,116 +1295,87 @@ msgstr[0] "~%d година залишилася" msgstr[1] "~%d годин залишилося" msgstr[2] "~%d годин залишилося" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 години залишилося" -#: template/pkgreq_results.php msgid "Accept" msgstr "Прийняти" -#: template/pkgreq_results.php msgid "Locked" msgstr "Замкнено" -#: template/pkgreq_results.php msgid "Close" msgstr "Закрити" -#: template/pkgreq_results.php msgid "Closed" msgstr "Замкнено" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "Назва, опис" -#: template/pkg_search_form.php msgid "Name Only" msgstr "Назва" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "Точна назва" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Точна база пакунків" -#: template/pkg_search_form.php msgid "All" msgstr "Всі" -#: template/pkg_search_form.php msgid "Flagged" msgstr "Позначені" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Не позначені" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Назва" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Проголосовано" -#: template/pkg_search_form.php msgid "Last modified" msgstr "Востаннє змінювалося" -#: template/pkg_search_form.php msgid "Ascending" msgstr "Висхідний" -#: template/pkg_search_form.php msgid "Descending" msgstr "Спадний" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Введіть критерії пошуку" -#: template/pkg_search_form.php msgid "Search by" msgstr "Де шукати" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Застарілих" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Упорядкувати за" -#: template/pkg_search_form.php msgid "Sort order" msgstr "Порядок упорядкування" -#: template/pkg_search_form.php msgid "Per page" msgstr "Результатів на сторінку" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Перейти" -#: template/pkg_search_form.php msgid "Orphans" msgstr "Покинуті" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Помилка отримання списку пакунків." -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "За вашим запитом не знайдено пакунків." -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1661,154 +1383,118 @@ msgstr[0] "Знайдено %d пакунок." msgstr[1] "Знайдено %d пакунків." msgstr[2] "Знайдено %d пакунків." -#: template/pkg_search_results.php msgid "Version" msgstr "Версія" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." -msgstr "Популярність розраховується як сума всіх голосувань, де кожен голос береться з ваговим коефіцієнтом 0.98 за кожен день з часу створення." +msgstr "" +"Популярність розраховується як сума всіх голосувань, де кожен голос береться " +"з ваговим коефіцієнтом 0.98 за кожен день з часу створення." -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "Так" -#: template/pkg_search_results.php msgid "orphan" msgstr "покинутий" -#: template/pkg_search_results.php msgid "Actions" msgstr "Дії" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "Призначити мітку «застарілий»" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Зняти мітку «застарілий»" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Прийняти пакунки" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Зректися пакунків" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Вилучити пакунки" -#: template/pkg_search_results.php msgid "Confirm" msgstr "Підтвердити" -#: template/search_accounts_form.php msgid "Any type" msgstr "Будь-який тип" -#: template/search_accounts_form.php msgid "Search" msgstr "Пошук" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Статистика" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Покинуті пакунки" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Пакунки, додані за останні 7 днів" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Пакунки, оновлені за останні 7 днів" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Пакунки, оновлені за останній рік" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Пакунки, що ніколи не оновлювалися" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Зареєстровані користувачі" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Довірені користувачі" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Останні зміни" -#: template/stats/user_table.php +msgid "more" +msgstr "більше" + msgid "My Statistics" msgstr "Моя статистика" -#: template/tu_details.php msgid "Proposal Details" msgstr "Подробиці пропозиції" -#: template/tu_details.php msgid "This vote is still running." msgstr "Це голосування все ще доречне." -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Подано: %s з %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Кінець" -#: template/tu_details.php msgid "Result" msgstr "Результат" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ні" -#: template/tu_details.php msgid "Abstain" msgstr "Утриматися" -#: template/tu_details.php msgid "Total" msgstr "Всього" -#: template/tu_details.php msgid "Participation" msgstr "Участь" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Останні голосування через TU" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Останнє голосування" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Результатів не знайдено." -#: template/tu_list.php msgid "Start" msgstr "Початок" -#: template/tu_list.php msgid "Back" msgstr "Назад" diff --git a/po/zh_CN.po b/po/zh_CN.po index cce8e13d..928d9fac 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # leonfeng , 2015 # dongfengweixiao , 2015 @@ -13,1795 +13,1414 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-26 05:50+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-09 20:59+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/language/zh_CN/)\n" +"Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" +"language/zh_CN/)\n" +"Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: html/404.php msgid "Page Not Found" msgstr "页面未找到" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "请求的页面不存在。" -#: html/503.php msgid "Service Unavailable" msgstr "" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" -#: html/account.php msgid "Account" msgstr "帐户" -#: html/account.php template/header.php msgid "Accounts" msgstr "帐户" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "您无权访问此区域。" -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "无法获取指定用户的信息。" -#: html/account.php msgid "You do not have permission to edit this account." msgstr "您没有权限编辑此帐户。" -#: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表单查找存在的帐户。" -#: html/account.php msgid "You must log in to view user information." msgstr "您需要登录后才能察看用户信息。" -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "添加提议" -#: html/addvote.php msgid "Invalid token for user action." msgstr "用户操作使用了无效的令牌。" -#: html/addvote.php msgid "Username does not exist." msgstr "此用户不存在。" -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s 已经有了关于他们的提议。" -#: html/addvote.php msgid "Invalid type." msgstr "无效的类别。" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "提议不能为空。" -#: html/addvote.php msgid "New proposal submitted." msgstr "新提议已被提交。" -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "提交一个提议用于投票。" -#: html/addvote.php msgid "Applicant/TU" msgstr "申请人/信任用户(TU)" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(如果不符合可以留空)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "类别" -#: html/addvote.php msgid "Addition of a TU" msgstr "添加受信用户" -#: html/addvote.php msgid "Removal of a TU" msgstr "移除受信用户" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "移除受信用户(无故不活跃)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "修订章程" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "提议" -#: html/addvote.php msgid "Submit" msgstr "提交" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" -#: html/home.php template/header.php msgid "Home" msgstr "首页" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "欢迎来到 AUR!想了解更多信息,请阅读 %sAUR 用户指南%s和 %sAUR 受信用户指南%s。" +msgstr "" +"欢迎来到 AUR!想了解更多信息,请阅读 %sAUR 用户指南%s和 %sAUR 受信用户指" +"南%s。" -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "提交的 PKGBUILD %s必须%s遵守 %sArch 软件包规范%s,否则它们将被删除!" -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "记得为您喜欢的软件包投票!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "部分软件包将在 [community] 仓库以二进制包的形式提供。" -#: html/home.php msgid "DISCLAIMER" msgstr "免责声明" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -#: html/home.php msgid "Learn more..." msgstr "" -#: html/home.php msgid "Support" msgstr "" -#: html/home.php msgid "Package Requests" msgstr "" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "" -#: html/home.php msgid "Orphan Request" msgstr "" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -#: html/home.php msgid "Deletion Request" msgstr "" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -#: html/home.php msgid "Merge Request" msgstr "" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -#: html/home.php msgid "Submitting Packages" msgstr "" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" -#: html/home.php msgid "Discussion" msgstr "邮件列表" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" -#: html/home.php msgid "Bug Reporting" msgstr "Bug 报告" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." msgstr "" -#: html/home.php msgid "Package Search" msgstr "软件包搜索" -#: html/index.php msgid "Adopt" msgstr "接管" -#: html/index.php msgid "Vote" msgstr "投票" -#: html/index.php msgid "UnVote" msgstr "取消投票" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "取消通知" -#: html/index.php msgid "UnFlag" msgstr "取消标记" -#: html/login.php template/header.php msgid "Login" msgstr "登录" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "登录为: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "退出" -#: html/login.php msgid "Enter login credentials" msgstr "输入账户信息" -#: html/login.php msgid "User name or email address" msgstr "" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "密码" -#: html/login.php msgid "Remember me" msgstr "记住我" -#: html/login.php msgid "Forgot Password" msgstr "找回密码" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "HTTP 登陆已被禁用,请使用%s切换到HTTPS%s。" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "搜索标准" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "软件包" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "尝试重新获取软件包详情时发生错误。" -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "缺少必填项。" -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "密码字段不匹配。" -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "密码至少要 %s 个字符。" -#: html/passreset.php msgid "Invalid e-mail." msgstr "电子邮箱不正确。" -#: html/passreset.php msgid "Password Reset" msgstr "密码重置" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "请进入您的邮箱查看确认邮件。" -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "密码已经成功重置。" -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "确认邮箱地址:" -#: html/passreset.php msgid "Enter your new password:" msgstr "输入新密码:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "确认新密码:" -#: html/passreset.php msgid "Continue" msgstr "继续" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "如果您忘记了注册账号时使用的邮件地址,请向 %saur-general%s 邮件列表寻求帮助。" +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"如果您忘记了注册账号时使用的邮件地址,请向 %saur-general%s 邮件列表寻求帮助。" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "输入您的邮箱地址:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "找不到合并投票与评论的目标包。" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "无法将一个包基础合并到它自己。" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "选中的软件包未被删除,请检查确认复选框。" -#: html/pkgdel.php msgid "Package Deletion" msgstr "软件包删除" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "删除包:%s" +msgid "Delete Package" +msgstr "删除软件包" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "使用这个表单将包基础 %s%s%s 和以下包从 AUR 中移除:" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "删除软件包是一个永久性的操作" -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "选中复选框以确认操作。" -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "确认删除包" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "删除" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "只有受信用户和开发人员能删除软件包。" -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "弃置软件包" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" -#: html/pkgdisown.php msgid "Disown" msgstr "弃置" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "" + msgid "Flag Package Out-Of-Date" msgstr "" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "评论" -#: html/pkgflag.php msgid "Flag" msgstr "标记" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" -#: html/pkgmerge.php msgid "Package Merging" msgstr "软件包合并" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "合并软件包: %s" +msgid "Merge Package" +msgstr "合并软件包" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "使用这个表单将包基础 %s%s%s 合并到另一个包。" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "下面这些软件包将被删除:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "一旦包被合并,这个操作将是不可逆的。" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "请输入合并的目标包名。" -#: html/pkgmerge.php msgid "Merge into:" msgstr "合并到:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "确认合并包" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "合并" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "只有受信用户和开发人员才能删除软件包。" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "提交请求" +msgid "Submit Request" +msgstr "" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "关闭请求" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一页" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一页" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一页" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "末页" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "请求" -#: html/register.php template/header.php msgid "Register" msgstr "注册" -#: html/register.php msgid "Use this form to create an account." msgstr "使用此表单创建帐号。" -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "受信用户" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "无法获取提议详情。" -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "该提议的投票已被关闭。" -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "只有受信用户可以投票。" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "您不能在关于您的提议里投票。" -#: html/tu.php msgid "You've already voted for this proposal." msgstr "您已经在这个提议上投票了。" -#: html/tu.php msgid "Vote ID not valid." msgstr "非法的投票标识" -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "当前的投票" -#: html/tu.php msgid "Past Votes" msgstr "历史投票" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "账户注册目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引起的不便表示抱歉。" +msgstr "" +"账户注册目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引" +"起的不便表示抱歉。" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "缺少用户标识" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "用户名需要符合以下条件:" -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "在 %s 到 %s 个字符之间" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "开头和结尾是数字/英文字母" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一个“.”,“_”,或“-”" -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "错误的 Email 地址。" -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 密钥指纹无效。" -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "不能提高账户权限。" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "目前不支持此语言。" -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "用户名 %s%s%s 已被使用。" -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "该地址 %s%s%s 已被使用。" -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "尝试创建帐户 %s%s%s 失败。" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "帐户 %s%s%s 创建成功。" -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "一个密码重置密钥已经发送到你的电子邮箱。" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "点击上方的登陆链接以使用你的帐号。" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "账户 %s%s%s 没有被修改。" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "帐号 %s%s%s 已被成功修改。" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "登陆表单目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引起的不便表示抱歉。" +msgstr "" +"登陆表单目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引" +"起的不便表示抱歉。" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "帐号被停用" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "你的密码已经成功被重置。如果你刚刚创建了一个新账户,请使用确认邮件中的链接来设置一个初始密码。否则,请在 %s重置密码%s 页面申请一个重置密码密钥。" +msgstr "" +"你的密码已经成功被重置。如果你刚刚创建了一个新账户,请使用确认邮件中的链接来" +"设置一个初始密码。否则,请在 %s重置密码%s 页面申请一个重置密码密钥。" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "用户名或密码错误。" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "在创建用户会话的过程中出现了一个错误。" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "邮箱和重置 key 不匹配。" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "无" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "查看 %s 的账户信息" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "已经添加评论。" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "您需要登录后才能编辑软件包信息。" + +msgid "Missing comment ID." +msgstr "评论标识丢失。" + +msgid "No more than 5 comments can be pinned." +msgstr "" + +msgid "You are not allowed to pin this comment." +msgstr "" + +msgid "You are not allowed to unpin this comment." +msgstr "" + +msgid "Comment has been pinned." +msgstr "" + +msgid "Comment has been unpinned." +msgstr "" + msgid "Error retrieving package details." msgstr "获取软件包详情时发生错误。" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "无法找到软件包的详细信息。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "您需要登录后才能标记软件包。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "您没有选择要标记的软件包。" -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "" + msgid "The selected packages have been flagged out-of-date." msgstr "选择的软件包已被标记为过期。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "您需要登录后才能移除软件包标记。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "您没有选择要取消标记的软件包。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "选中的软件包的标记已被移除。" -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "您没有删除软件包的权限。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "您没有选择要删除的软件包。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "选中的软件包已经被删除。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "登陆后才能接管软件包" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "您需要登录后才能弃置软件包。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "您没有选择要接管的软件包。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "您没有选择要弃置的软件包。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "选择的软件包已经被接管。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "选中的软件包已经被弃置。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "您需要登录后才能为软件包投票。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "您需要登录后才能为软件包取消投票。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "您没有选择要投票的软件包。" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "您对所选软件包的投票已被取消。" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "您对所选软件包的投票已被记录。" -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "无法将您添加到通知列表。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "您已被成功添加到 %s 的评论通知列表。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "您将不再收到 %s 的评论通知。" -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "您需要登录后才能编辑软件包信息。" +msgid "You are not allowed to undelete this comment." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "评论标识丢失。" +msgid "Comment has been undeleted." +msgstr "" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "评论已被删除。" - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "您没有权限删除此评论。" -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "评论已被删除。" + msgid "Comment has been edited." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "查看软件包详细信息" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "登录之后才能提交软件包需求。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "无效的名称: 只允许小写字母。" -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "评论内容不能为空。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "无效的请求类型。" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "请求提交成功。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "无效的理由。" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "只有受信用户和开发者可以关闭请求。" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "请求关闭成功。" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "你可以使用这个表单来彻底删除 AUR 帐号 %s。" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s:这个操作无法被撤销" -#: template/account_delete.php msgid "Confirm deletion" msgstr "确认删除" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "用户名" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "帐户类别" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "用户" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "开发人员" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "受信用户 & 开发者" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "Email" -#: template/account_details.php msgid "hidden" msgstr "" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "真实名字" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC昵称" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 密钥指纹" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "状态" -#: template/account_details.php msgid "Inactive since" msgstr "不活跃自" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "激活" -#: template/account_details.php msgid "Last Login" msgstr "最后登陆" -#: template/account_details.php msgid "Never" msgstr "从不" -#: template/account_details.php msgid "View this user's packages" msgstr "查看这个用户提交的软件包" -#: template/account_details.php msgid "Edit this user's account" msgstr "编辑此用户的帐号" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果你想要彻底删除这个帐号,请点击%s这里%s。" -#: template/account_edit_form.php msgid "required" msgstr "必填" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "普通用户" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "受信用户" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "帐户被暂停" -#: template/account_edit_form.php msgid "Inactive" msgstr "不活跃" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" -#: template/account_edit_form.php msgid "Re-type password" msgstr "确认密码" -#: template/account_edit_form.php msgid "Language" msgstr "语言" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "" + +msgid "Notify of new comments" +msgstr "当有新评论的时候提醒我" + +msgid "Notify of package updates" +msgstr "" + msgid "Update" msgstr "更新" -#: template/account_edit_form.php msgid "Create" msgstr "创建" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "重填" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "没有结果符合您的搜索条件。" -#: template/account_search_results.php msgid "Edit Account" msgstr "编辑帐户" -#: template/account_search_results.php msgid "Suspended" msgstr "暂停" -#: template/account_search_results.php msgid "Edit" msgstr "编辑" -#: template/account_search_results.php msgid "Less" msgstr "更少" -#: template/account_search_results.php msgid "More" msgstr "更多" -#: template/account_search_results.php msgid "No more results to display." msgstr "没有更多的结果供显示。" -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -#: template/comaintainers_form.php msgid "Users" msgstr "" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +msgid "Return to Details" +msgstr "" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "" + msgid "My Packages" msgstr "我的软件包" -#: template/header.php msgid " My Account" msgstr "我的帐户" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "软件包操作" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "查看 PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "搜索 Wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "已标记为过期" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "将软件包标记为过期" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "取消标记软件包" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "移除投票" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "为这个软件包投票" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "禁用通知" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "当有新评论的时候提醒我" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 个未处理的请求" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "删除软件包" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "合并软件包" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "接管软件包" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "未知" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "包基础详情" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "关键字" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "提交人" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "维护者" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最近一次打包者" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "得票" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "首次提交" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最后更新" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "添加评论" -#: template/pkg_comments.php msgid "View all comments" msgstr "查看所有评论" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "" + msgid "Latest Comments" msgstr "最新的评论" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#, php-format +msgid "edited on %s" +msgstr "" + +msgid "Undelete comment" msgstr "" -#: template/pkg_comments.php msgid "Delete comment" msgstr "删除评论" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "" + +msgid "Unpin comment" +msgstr "" + msgid "All comments" msgstr "全部评论" -#: template/pkg_details.php msgid "Package Details" msgstr "软件包详情" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "包基础" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "描述" -#: template/pkg_details.php msgid "Upstream URL" msgstr "上游 URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "访问网站" -#: template/pkg_details.php msgid "Licenses" msgstr "许可协议" -#: template/pkg_details.php msgid "Groups" msgstr "组" -#: template/pkg_details.php msgid "Conflicts" msgstr "冲突" -#: template/pkg_details.php msgid "Provides" msgstr "提供" -#: template/pkg_details.php msgid "Replaces" msgstr "取代" -#: template/pkg_details.php msgid "Dependencies" msgstr "依赖于:" -#: template/pkg_details.php msgid "Required by" msgstr "被需要:" -#: template/pkg_details.php msgid "Sources" msgstr "源代码:" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "关闭请求:%s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "使用这个表单来关闭对包基础 %s%s%s 的请求。" -#: template/pkgreq_close_form.php msgid "Note" msgstr "提示" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "评论可以留空。不过,当拒绝一个请求的时候,强烈推荐提供一条评论。" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "原因" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "已接受" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "已拒绝" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "提交请求:%s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "使用这个表格,提交一个针对包基础 %s%s%s 的请求,其中包括下列软件包:" -#: template/pkgreq_form.php msgid "Request type" msgstr "请求类型" -#: template/pkgreq_form.php msgid "Deletion" msgstr "删除" -#: template/pkgreq_form.php msgid "Orphan" msgstr "弃置" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "合并到" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "找到了 %d 个软件包请求。" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "第 %d 页,共 %d 页。" -#: template/pkgreq_results.php msgid "Package" msgstr "软件包" -#: template/pkgreq_results.php msgid "Filed by" msgstr "提交者是" -#: template/pkgreq_results.php msgid "Date" msgstr "日期" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "剩余~%d天" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "剩余~%d小时" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "剩余<1小时" -#: template/pkgreq_results.php msgid "Accept" msgstr "接受" -#: template/pkgreq_results.php msgid "Locked" msgstr "已锁定" -#: template/pkgreq_results.php msgid "Close" msgstr "关闭" -#: template/pkgreq_results.php msgid "Closed" msgstr "已关闭" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "名称和描述" -#: template/pkg_search_form.php msgid "Name Only" msgstr "名称" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "确切的名字" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "准确包基础" -#: template/pkg_search_form.php msgid "All" msgstr "全部" -#: template/pkg_search_form.php msgid "Flagged" msgstr "已标记" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "未标记" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名称" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "已投票" -#: template/pkg_search_form.php msgid "Last modified" msgstr "" -#: template/pkg_search_form.php msgid "Ascending" msgstr "从小到大" -#: template/pkg_search_form.php msgid "Descending" msgstr "从大到小" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "输入搜索条件" -#: template/pkg_search_form.php msgid "Search by" msgstr "搜索" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "过期状态" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "排列依据" -#: template/pkg_search_form.php msgid "Sort order" msgstr "排列方式" -#: template/pkg_search_form.php msgid "Per page" msgstr "每页显示" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Go" -#: template/pkg_search_form.php msgid "Orphans" msgstr "孤儿包" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "无法获取包列表。" -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "没有相关的软件包符合您的搜索条件。" -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "找到了 %d 个软件包。" -#: template/pkg_search_results.php msgid "Version" msgstr "版本" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "是" -#: template/pkg_search_results.php msgid "orphan" msgstr "孤儿包" -#: template/pkg_search_results.php msgid "Actions" msgstr "操作" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "标记为过期" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "移除过期标记" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "接管软件包" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "弃置软件包" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "删除软件包" -#: template/pkg_search_results.php msgid "Confirm" msgstr "确认" -#: template/search_accounts_form.php msgid "Any type" msgstr "所有类别" -#: template/search_accounts_form.php msgid "Search" msgstr "搜索" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "统计" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "无人维护的软件包" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "7天内新增的软件包" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "7天内更新的软件包" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "一年内更新的软件包" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "从未更新的软件包" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "注册用户" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "受信用户" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最新更新" -#: template/stats/user_table.php +msgid "more" +msgstr "" + msgid "My Statistics" msgstr "我的统计" -#: template/tu_details.php msgid "Proposal Details" msgstr "提议详情" -#: template/tu_details.php msgid "This vote is still running." msgstr "投票仍在继续。" -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "已提交 %s 由 %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "结束" -#: template/tu_details.php msgid "Result" msgstr "结果" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "否" -#: template/tu_details.php msgid "Abstain" msgstr "弃权" -#: template/tu_details.php msgid "Total" msgstr "总数" -#: template/tu_details.php msgid "Participation" msgstr "参与" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "受信用户的最后投票" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最后投票" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "没有找到结果。" -#: template/tu_list.php msgid "Start" msgstr "开始" -#: template/tu_list.php msgid "Back" msgstr "返回" diff --git a/po/zh_TW.po b/po/zh_TW.po index 7ff5aec7..bb26fd59 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1,1802 +1,1442 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: -# Jeff Huang , 2014-2015 +# Jeff Huang , 2014-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-09-26 07:44+0200\n" -"PO-Revision-Date: 2015-09-27 03:45+0000\n" +"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"PO-Revision-Date: 2016-02-11 13:26+0000\n" "Last-Translator: Jeff Huang \n" -"Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/language/zh_TW/)\n" +"Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" +"language/zh_TW/)\n" +"Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: html/404.php msgid "Page Not Found" msgstr "頁面找不到" -#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "抱歉,您所請求的頁面不存在。" -#: html/503.php msgid "Service Unavailable" msgstr "服務不可用" -#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "別緊張!這個頁面因維護而暫時下線。我們很快就會回來。" -#: html/account.php msgid "Account" msgstr "帳號" -#: html/account.php template/header.php msgid "Accounts" msgstr "帳號" -#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "您不被允許存取此區域。" -#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "無法擷取指定使用者的資訊。" -#: html/account.php msgid "You do not have permission to edit this account." msgstr "您沒有權限編輯此帳號。" -#: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表單來搜尋已有的帳號。" -#: html/account.php msgid "You must log in to view user information." -msgstr "您必須登入以檢視使用者資訊。" +msgstr "您必須登入才能檢視使用者資訊。" -#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "添加建議" -#: html/addvote.php msgid "Invalid token for user action." msgstr "無效的使用者動作標誌。" -#: html/addvote.php msgid "Username does not exist." msgstr "使用者名稱不存在。" -#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s 已經有了關於他們的建議。" -#: html/addvote.php msgid "Invalid type." msgstr "無效的類型。" -#: html/addvote.php msgid "Proposal cannot be empty." msgstr "建議不能為空。" -#: html/addvote.php msgid "New proposal submitted." msgstr "已提交新的建議。" -#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "提交一個建議用於投票。" -#: html/addvote.php msgid "Applicant/TU" msgstr "申請人/受信使用者" -#: html/addvote.php msgid "(empty if not applicable)" msgstr "(如果不符合可以留空)" -#: html/addvote.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Type" msgstr "類型" -#: html/addvote.php msgid "Addition of a TU" msgstr "添加受信使用者" -#: html/addvote.php msgid "Removal of a TU" msgstr "移除受信使用者" -#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "移除受信使用者(無故不活躍)" -#: html/addvote.php msgid "Amendment of Bylaws" msgstr "修定規則" -#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "建議" -#: html/addvote.php msgid "Submit" msgstr "提交" -#: html/comaintainers.php msgid "Manage Co-maintainers" msgstr "管理共同維護者" -#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "編輯評論" -#: html/home.php template/header.php msgid "Home" msgstr "首頁" -#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "歡迎來到 AUR!請閱讀 %sAUR 使用者指導方針%s 和 %sAUR 受信使用者指導方針%s 以獲取更多的詳細資訊。" +msgstr "" +"歡迎來到 AUR!請閱讀 %sAUR 使用者指導方針%s 和 %sAUR 受信使用者指導方針%s 以" +"獲取更多的詳細資訊。" -#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "所貢獻的 PKGBUILDs 和 PKGINFOs %s必須%s 符合 %sArch 打包標準%s 否則將被被刪除! " +msgstr "" +"所貢獻的 PKGBUILDs 和 PKGINFOs %s必須%s 符合 %sArch 打包標準%s 否則將被被刪" +"除! " -#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "記得投一票給您喜愛的套件!" -#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "某些套件可能會在 [community] 提供二進位檔案。" -#: html/home.php msgid "DISCLAIMER" msgstr "免責聲明" -#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "AUR 上的檔案是使用者產生的內容。任何使用檔案的風險由您自行承擔。" +msgstr "AUR 上的檔案是使用者產生的內容。任何使用檔案造成的風險由您自行承擔。" -#: html/home.php msgid "Learn more..." msgstr "了解更多..." -#: html/home.php msgid "Support" msgstr "支援" -#: html/home.php msgid "Package Requests" msgstr "套件請求" -#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage " -"Actions%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage Actions" +"%s box on the package details page:" msgstr "有三種您可以在套件細節頁面中的 %s套件動作%s 中使用的請求:" -#: html/home.php msgid "Orphan Request" msgstr "棄置請求" -#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "請求一個套件被解除擁有權,例如:當維護者不活躍且套件已經被標記為過期很長一段時間。" +msgstr "" +"請求一個套件被解除擁有權,例如:當維護者不活躍且套件已經被標記為過期很長一段" +"時間。" -#: html/home.php msgid "Deletion Request" msgstr "刪除請求" -#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not" -" use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not " +"use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "請求套件從 Arch 使用者套件庫中移除。如果套件損毀但可以很容易的被修復,請不要使用這個請求。您應該聯絡套件維護者,並在必要時提出棄置請求。" +msgstr "" +"請求套件從 Arch 使用者套件庫中移除。如果套件損毀但可以很容易的被修復,請不要" +"使用這個請求。您應該聯絡套件維護者,並在必要時提出棄置請求。" -#: html/home.php msgid "Merge Request" msgstr "合併請求" -#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "請求將一個套件合併到另一個。可以使用在需要重新命名或是由分裂的套件所取代的套件。" +msgstr "" +"請求將一個套件合併到另一個。可以使用在需要重新命名或是由分裂的套件所取代的套" +"件。" -#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "如果您想要討論某一個請求,您可以使用 %saur-requests%s 郵件列表。但請不要使用這個列表來提出請求。" +msgstr "" +"如果您想要討論某一個請求,您可以使用 %saur-requests%s 郵件列表。但請不要使用" +"這個列表來提出請求。" -#: html/home.php msgid "Submitting Packages" msgstr "遞交套件" -#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" -" packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " +"packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "現在透過 SSH 的 Git 開始用於遞交套件到 AUR 上。參見 ArchWiki 上的 Arch User Repository 頁面之 %s遞交套件%s 章節以取得更多資訊。" +msgstr "" +"現在遞交套件到 AUR 上的方法是透過 SSH 的 Git。參見 ArchWiki 上的 Arch User " +"Repository 頁面之 %s遞交套件%s 章節以取得更多資訊。" -#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" -msgstr "下列 SSH 指紋被用於 AUR:" +msgstr "AUR 使用下列 SSH 指紋:" -#: html/home.php msgid "Discussion" msgstr "討論" -#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User" -" structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User " +"structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "與 Arch 使用者套件庫(AUR)及受信使用者結構相關的一般性討論請見 %saur-general%s 。討論關於 AUR 網頁介面的開發,請使用 %saur-dev%s 郵件列表。" +msgstr "" +"與 Arch 使用者套件庫(AUR)及受信使用者結構相關的一般性討論請見 %saur-general" +"%s 。討論關於 AUR 網頁介面的開發,請使用 %saur-dev%s 郵件列表。" -#: html/home.php msgid "Bug Reporting" msgstr "臭蟲回報" -#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" -" %sonly%s. To report packaging bugs contact the package maintainer or leave " -"a comment on the appropriate package page." -msgstr "如果您在 AUR 網頁介面中發現了臭蟲,請在我們的 %s臭蟲追蹤系統%s 中回報。請%s只%s回報 AUR 網頁介面本身的臭蟲。要回報打包臭蟲,請連絡套件的維護者或是在對應的套件頁面中留下評論。" +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " +"%sonly%s. To report packaging bugs contact the package maintainer or leave a " +"comment on the appropriate package page." +msgstr "" +"如果您在 AUR 網頁介面中發現了臭蟲,請在我們的 %s臭蟲追蹤系統%s 中回報。請%s" +"只%s回報 AUR 網頁介面本身的臭蟲。要回報打包臭蟲,請連絡套件的維護者或是在對應" +"的套件頁面中留下評論。" -#: html/home.php msgid "Package Search" msgstr "搜尋套件" -#: html/index.php msgid "Adopt" msgstr "接管" -#: html/index.php msgid "Vote" msgstr "投票" -#: html/index.php msgid "UnVote" msgstr "取消投票" -#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" -#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "取消通知" -#: html/index.php msgid "UnFlag" msgstr "取消標記" -#: html/login.php template/header.php msgid "Login" msgstr "登入" -#: html/login.php #, php-format msgid "Logged-in as: %s" msgstr "已登入為: %s" -#: html/login.php template/header.php msgid "Logout" msgstr "登出" -#: html/login.php msgid "Enter login credentials" msgstr "輸入登入資訊" -#: html/login.php msgid "User name or email address" msgstr "使用者名稱或電子郵件地址" -#: html/login.php template/account_edit_form.php msgid "Password" msgstr "密碼" -#: html/login.php msgid "Remember me" msgstr "記住我" -#: html/login.php msgid "Forgot Password" msgstr "忘記密碼" -#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "HTTP 登入已被停用。如果您想要登入的話,請 %s切換至HTTPs%s 。" -#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "搜尋條件" -#: html/packages.php template/header.php template/pkgbase_details.php -#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "套件" -#: html/packages.php msgid "Error trying to retrieve package details." msgstr "嘗試擷取套件細節時發生錯誤。" -#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "缺少必填項目。" -#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "密碼不符合。" -#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "您的密碼必須至少 %s 個字節。" -#: html/passreset.php msgid "Invalid e-mail." msgstr "無效的電子郵件。" -#: html/passreset.php msgid "Password Reset" msgstr "密碼重置" -#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "請檢查您的電子郵件信箱裡是否有確認連結。" -#: html/passreset.php msgid "Your password has been reset successfully." msgstr "您的密碼已成功重置。" -#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "確認您的電子郵件位置:" -#: html/passreset.php msgid "Enter your new password:" msgstr "輸入您的新密碼:" -#: html/passreset.php msgid "Confirm your new password:" msgstr "確認您的新密碼:" -#: html/passreset.php msgid "Continue" msgstr "繼續" -#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "如果您忘了您用來註冊的電子郵件地址,請寄一封訊息到 %saur-general%s 郵件列表中。" +"If you have forgotten the e-mail address you used to register, please send a " +"message to the %saur-general%s mailing list." +msgstr "" +"如果您忘了您用來註冊的電子郵件地址,請寄一封訊息到 %saur-general%s 郵件列表" +"中。" -#: html/passreset.php msgid "Enter your e-mail address:" msgstr "輸入您的電子郵件地址:" -#: html/pkgbase.php -msgid "The selected packages have not been flagged, please enter a comment." -msgstr "選定的套件尚未被標記,請輸入評論。" - -#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "選取的套件未被棄置,請檢查確認的核取方塊。" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "找不到合併投票與評論的目標套件。" -#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "無法將一個套件基礎與它自己合併。" -#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation " -"checkbox." +"The selected packages have not been deleted, check the confirmation checkbox." msgstr "選取的套件未被刪除,請檢查確認的核取方塊。" -#: html/pkgdel.php msgid "Package Deletion" msgstr "套件刪除" -#: html/pkgdel.php -#, php-format -msgid "Delete Package: %s" -msgstr "刪除套件: %s" +msgid "Delete Package" +msgstr "刪除套件" -#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "使用這個表單以從 AUR 刪除套件基礎 %s%s%s 以及以下的套件。" -#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "套件刪除是永久性的操作。" -#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "選取核取方塊以確認動作。" -#: html/pkgdel.php msgid "Confirm package deletion" msgstr "確認套件刪除" -#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "刪除" -#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "只有受信使用者和開發者可以刪除套件。" -#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "棄置套件" -#: html/pkgdisown.php -#, php-format -msgid "Disown Package: %s" -msgstr "棄置套件:%s" - -#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following" -" packages: " +"Use this form to disown the package base %s%s%s which includes the following " +"packages: " msgstr "使用這個表單以棄置一個包含以下套件的套件基礎 %s%s%s :" -#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "透過選取核取方塊,您就會確認您想要棄置此套件並轉移所有權給 %s%s%s。" -#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "透過選取核取方塊,您就會確認您想要棄置此套件。" -#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "確認棄置此套件" -#: html/pkgdisown.php msgid "Disown" msgstr "棄置" -#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "只有受信使用者和開發者可以棄置套件。" -#: html/pkgflag.php +msgid "Flag Comment" +msgstr "標記評論" + msgid "Flag Package Out-Of-Date" msgstr "將套件標記為過期" -#: html/pkgflag.php -#, php-format -msgid "Flag Package Out-Of-Date: %s" -msgstr "將套件標記為過期:%s" - -#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages " -"out-of-date: " +"Use this form to flag the package base %s%s%s and the following packages out-" +"of-date: " msgstr "使用這個表單來標記套件基礎 %s%s%s 以及以下的套件已過期:" -#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "請 %s不要%s 使用此表單來回報臭蟲。使用套件的評論來代替。" +msgstr "" +"請 %s不要%s 使用此表單來回報臭蟲。打包臭蟲應使用套件頁面的評論功能回報。" -#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "在下面輸入關於套件要被標記為過期的細節,最好包括釋出公告或是新版 tarball 的連結。" +msgstr "" +"在下面輸入要將套件標記為過期的詳細原因,最好包括釋出公告或是新版 tarball 的連" +"結。" -#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php -#: template/pkgreq_results.php msgid "Comments" msgstr "評論" -#: html/pkgflag.php msgid "Flag" msgstr "標記" -#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "只有已註冊的使用者可以標記套件為過期。" -#: html/pkgmerge.php msgid "Package Merging" msgstr "套件合併" -#: html/pkgmerge.php -#, php-format -msgid "Merge Package: %s" -msgstr "合併套件:: %s" +msgid "Merge Package" +msgstr "合併套件" -#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "使用這個表單以合併套件基礎 %s%s%s 以及其他套件。" -#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "以下套件將會被刪除:" -#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "套件一經合併即無法回復。" -#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "請輸入您想要合併到該套件的套件名稱。" -#: html/pkgmerge.php msgid "Merge into:" msgstr "合併到:" -#: html/pkgmerge.php msgid "Confirm package merge" msgstr "確認套件合併" -#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "合併" -#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "只有受信使用者和開發者可以合併套件。" -#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php -msgid "File Request" -msgstr "提交請求" +msgid "Submit Request" +msgstr "遞交請求" -#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "關閉請求" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一頁" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一頁" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一頁" -#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後一頁" -#: html/pkgreq.php template/header.php msgid "Requests" msgstr "請求" -#: html/register.php template/header.php msgid "Register" msgstr "註冊" -#: html/register.php msgid "Use this form to create an account." msgstr "使用此表單來新建一個帳號。" -#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "受信使用者" -#: html/tu.php msgid "Could not retrieve proposal details." msgstr "無法取得建議的細節。" -#: html/tu.php msgid "Voting is closed for this proposal." msgstr "這個建議的投票已被關閉。" -#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "只有受信使用者可以投票。" -#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "您不能在關於您的建議中投票。" -#: html/tu.php msgid "You've already voted for this proposal." msgstr "您已經在此建議上投過票了。" -#: html/tu.php msgid "Vote ID not valid." msgstr "投票的 ID 無效。" -#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "目前的投票" -#: html/tu.php msgid "Past Votes" msgstr "過去投票" -#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票者" -#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "帳號註冊在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們為您的不便致歉。" +msgstr "" +"帳號註冊在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們" +"為您的不便致歉。" -#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "遺失使用者 ID" -#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "使用者名稱無效。" -#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "使用者名稱的長度必須在 %s 到 %s 個字節間。" -#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "以字母或數字當做開頭或結尾" -#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一個「.」、「_」或「-」。" -#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "電子郵件地址無效。" -#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 密鑰指紋無效。" -#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH 公開金鑰無效。" -#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "無法提升帳號權限。" -#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "目前不支援此語言。" -#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "使用者名稱 %s%s%s 已被使用。" -#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "該位址 %s%s%s 已被使用。" -#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開金鑰,%s%s%s,已在使用中。" -#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "嘗試建立帳號 %s%s%s 時發生錯誤。" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "帳號 %s%s%s 已成功建立。" -#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "一個密碼重置密鑰已寄到您的電子郵件信箱中。" -#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "點擊上面的登入連結以使用您的帳號。" -#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "帳號 %s%s%s 沒有被修改。" -#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "帳號 %s%s%s 已成功修改。" -#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "登入表單在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們為您的不便致歉。" +msgstr "" +"登入表單在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們" +"為您的不便致歉。" -#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "帳號被暫停" -#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "您的密碼已成功重置。如果您剛建立了一個新帳號,請使用確認郵件中的連結來設定一個初始密碼。否則,請在 %s密碼重置%s 頁面上請求一個重置密鑰。" +msgstr "" +"您的密碼已成功重置。如果您剛建立了一個新帳號,請使用確認郵件中的連結來設定一" +"個初始密碼。否則,請在 %s密碼重置%s 頁面上請求一個重置密鑰。" -#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "使用者名稱或密碼錯誤。" -#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "嘗試生成使用者工作階段時發生錯誤。" -#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "無效的電子郵件與密鑰組合。" -#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "無" -#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "檢視 %s 的帳號資訊" -#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "套件基礎的 ID 或套件基礎的名稱遺失。" -#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "您不被允許編輯此評論。" -#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "評論不存在。" -#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "評論不能為空。" -#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "評論已新增。" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php +msgid "You must be logged in before you can edit package information." +msgstr "您必須先登入才能編輯套件資訊。" + +msgid "Missing comment ID." +msgstr "遺失評論 ID。" + +msgid "No more than 5 comments can be pinned." +msgstr "只能釘選不超過 5 個評論。" + +msgid "You are not allowed to pin this comment." +msgstr "您不被允許釘選這個評論。" + +msgid "You are not allowed to unpin this comment." +msgstr "您不被允許解除釘選這個評論。" + +msgid "Comment has been pinned." +msgstr "評論已釘選。" + +msgid "Comment has been unpinned." +msgstr "評論已解除釘選。" + msgid "Error retrieving package details." msgstr "擷取套件細節時發生錯誤。" -#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "找不到套件的詳細資訊。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "您必須先登入才能標記套件。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "您沒有選擇任何要標記的套件。" -#: lib/pkgbasefuncs.inc.php +msgid "The selected packages have not been flagged, please enter a comment." +msgstr "選定的套件尚未被標記,請輸入評論。" + msgid "The selected packages have been flagged out-of-date." msgstr "選定的套件已被標記為過期。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "您必須先登入才能取消標記套件。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "您沒有選擇任何要取消標記的套件。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "選定的套件已被取消標記。" -#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "您沒有權限刪除套件。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." -msgstr "您無法選取任何套件刪除。" +msgstr "您沒有選取任何要刪除的套件。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "選取的套件已刪除。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "您必須先登入才能接管套件。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "您必須先登入才能棄置套件。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "您沒有選擇任何要接管的套件。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "您沒有選擇任何要棄置的套件。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "選定的套件已接管。" -#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "選定的套件已棄置。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "您必須先登入才能對套件投票。" -#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "您必須先登入才能對套件取消投票。" -#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "您沒有選擇任何要投票的套件。" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "您的投票已從選定的套件中被移除。" -#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "您的投票已加入選定的套件中。" -#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "無法加入到通知清單中。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "您已經成功加入到 %s 的評論通知列表。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "您已經成功從 %s 的評論通知列表移除。" -#: lib/pkgbasefuncs.inc.php -msgid "You must be logged in before you can edit package information." -msgstr "您必須先登入才能編輯套件資訊。" +msgid "You are not allowed to undelete this comment." +msgstr "您不被允許反刪除此則評論。" -#: lib/pkgbasefuncs.inc.php -msgid "Missing comment ID." -msgstr "遺失評論 ID。" +msgid "Comment has been undeleted." +msgstr "評論已被反刪除。" -#: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." -msgstr "評論已被刪除。" - -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "您不被允許刪除此則評論。" -#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "評論已被刪除。" + msgid "Comment has been edited." msgstr "評論已被編輯。" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "您不被允許編輯此套件基礎的關鍵字。" -#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "套件基礎關鍵字已更新。" -#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "您不被允許管理此套件基礎的共同維護者。" -#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "無效的使用者名稱:%s" -#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "套件基礎共同維護者已更新。" -#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "檢視套件的詳細資訊" -#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "需要 %s" -#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "您必須先登入才能匯報套件請求。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "無效的名稱:只允許小寫字母。" -#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "評論區域不能為空。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "無效的請求類型。" -#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "成功加入請求。" -#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "無效的理由。" -#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "只有受信使用者和開發者可以關閉請求。" -#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "請求關閉成功。" -#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "您可以使用這個表單來永久刪除 AUR 帳號 %s 。" -#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s :此動作無法回復。" -#: template/account_delete.php msgid "Confirm deletion" msgstr "確認刪除" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "使用者名稱" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Account Type" msgstr "帳號類型" -#: template/account_details.php template/tu_details.php -#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "使用者" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Developer" msgstr "開發者" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "受信使用者 & 開發者" -#: template/account_details.php template/account_edit_form.php -#: template/search_accounts_form.php msgid "Email Address" msgstr "電子郵件地址" -#: template/account_details.php msgid "hidden" msgstr "已隱藏" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "真實名稱" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC 暱稱" -#: template/account_details.php template/account_edit_form.php -#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 密鑰指紋" -#: template/account_details.php template/account_search_results.php -#: template/pkgreq_results.php msgid "Status" msgstr "狀態" -#: template/account_details.php msgid "Inactive since" msgstr "不活躍自" -#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "活躍" -#: template/account_details.php msgid "Last Login" msgstr "最後登入" -#: template/account_details.php msgid "Never" msgstr "從未" -#: template/account_details.php msgid "View this user's packages" msgstr "檢視此使用者的套件" -#: template/account_details.php msgid "Edit this user's account" msgstr "編輯此使用者的帳號" -#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果您想要永久刪除此帳號,請點擊 %s這裡%s 。" -#: template/account_edit_form.php msgid "required" msgstr "必填" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "一般使用者" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "受信使用者" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "帳號被暫停" -#: template/account_edit_form.php msgid "Inactive" msgstr "不活躍" -#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "請確保您正確的輸入了您的電子郵件地址,否則您將會被鎖定。" -#: template/account_edit_form.php msgid "Hide Email Address" msgstr "隱藏電子郵件地址" -#: template/account_edit_form.php msgid "Re-type password" msgstr "重新輸入密碼" -#: template/account_edit_form.php msgid "Language" msgstr "語言" -#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to" -" the Arch User Repository." +"The following information is only required if you want to submit packages to " +"the Arch User Repository." msgstr "以下的資訊僅在您想要遞交套件到 Arch 使用者套件庫時是必須的。" -#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH 公開金鑰" -#: template/account_edit_form.php template/pkgbase_details.php -#: template/pkg_details.php +msgid "Notification settings" +msgstr "通知設定" + +msgid "Notify of new comments" +msgstr "接收新評論通知" + +msgid "Notify of package updates" +msgstr "通知套件更新" + msgid "Update" msgstr "更新" -#: template/account_edit_form.php msgid "Create" msgstr "建立" -#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "重置" -#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "沒有符合您搜尋條件的搜尋結果。" -#: template/account_search_results.php msgid "Edit Account" msgstr "編輯帳號" -#: template/account_search_results.php msgid "Suspended" msgstr "暫停" -#: template/account_search_results.php msgid "Edit" msgstr "編輯" -#: template/account_search_results.php msgid "Less" msgstr "更少" -#: template/account_search_results.php msgid "More" msgstr "更多" -#: template/account_search_results.php msgid "No more results to display." msgstr "無更多結果可顯示。" -#: template/comaintainers_form.php -#, php-format -msgid "Manage Co-maintainers: %s" -msgstr "管理共同維護者:%s" - -#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "使用此表單來加入 %s%s%s 的共同維護者(每個使用者名稱一行):" -#: template/comaintainers_form.php msgid "Users" msgstr "使用者" -#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "儲存" -#: template/header.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "標記過期評論:%s" + +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "%s%s%s 標記了 %s%s%s 過期在 %s%s%s 上並提供了下列理由:" + +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "%s%s%s 並未被標記為過期。" + +msgid "Return to Details" +msgstr "回到詳情" + +#, php-format +msgid "Copyright %s 2004-%d aurweb Development Team." +msgstr "Copyright %s 2004-%d aurweb 開發團隊。" + msgid "My Packages" msgstr "我的套件" -#: template/header.php msgid " My Account" msgstr "我的帳號" -#: template/pkgbase_actions.php msgid "Package Actions" msgstr "套件動作" -#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "檢視 PKGBUILD" -#: template/pkgbase_actions.php msgid "View Changes" msgstr "檢視變更" -#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "下載快照" -#: template/pkgbase_actions.php msgid "Search wiki" msgstr "搜尋 wiki" -#: template/pkgbase_actions.php -msgid "Flagged out-of-date" -msgstr "已標記為過期" +#, php-format +msgid "Flagged out-of-date (%s)" +msgstr "標記為過期 (%s)" -#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "將套件標記為過期" -#: template/pkgbase_actions.php msgid "Unflag package" msgstr "取消標記套件" -#: template/pkgbase_actions.php msgid "Remove vote" msgstr "移除投票" -#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "為此套件投票" -#: template/pkgbase_actions.php msgid "Disable notifications" msgstr "停用通知" -#: template/pkgbase_actions.php -msgid "Notify of new comments" -msgstr "新評論通知" - -#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "管理共同維護者" -#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 個擱置的請求" -#: template/pkgbase_actions.php -msgid "Delete Package" -msgstr "刪除套件" - -#: template/pkgbase_actions.php -msgid "Merge Package" -msgstr "合併套件" - -#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "接管套件" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php msgid "unknown" msgstr "未知" -#: template/pkgbase_details.php msgid "Package Base Details" msgstr "套件基礎詳細資訊" -#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" -#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "唯讀" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Keywords" msgstr "關鍵字" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php msgid "Submitter" msgstr "提交人" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "維護者" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最近一次打包者" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "得票" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "人氣" -#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "首次提交" -#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最後更新" -#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "編輯評論:%s" -#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "新增評論" -#: template/pkg_comments.php msgid "View all comments" msgstr "檢視所有評論" -#: template/pkg_comments.php +msgid "Pinned Comments" +msgstr "已釘選評論" + msgid "Latest Comments" msgstr "最新的評論" -#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s 在 %s 上評論" -#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "在 %s 上的匿名評論" -#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "在 %s 由 %s 刪除" -#: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" -msgstr "在 %s 最後由 %s 編輯" +msgid "deleted on %s" +msgstr "已在 %s 上刪除" + +#, php-format +msgid "edited on %s by %s" +msgstr "在 %s 上由 %s 編輯" + +#, php-format +msgid "edited on %s" +msgstr "在 %s 上編輯" + +msgid "Undelete comment" +msgstr "反刪除評論" -#: template/pkg_comments.php msgid "Delete comment" msgstr "刪除評論" -#: template/pkg_comments.php +msgid "Pin comment" +msgstr "釘選評論" + +msgid "Unpin comment" +msgstr "解除釘選評論" + msgid "All comments" msgstr "所有評論" -#: template/pkg_details.php msgid "Package Details" msgstr "套件詳細資訊" -#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "套件基礎" -#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "描述" -#: template/pkg_details.php msgid "Upstream URL" msgstr "上游 URL" -#: template/pkg_details.php msgid "Visit the website for" msgstr "參觀網頁" -#: template/pkg_details.php msgid "Licenses" msgstr "授權條款" -#: template/pkg_details.php msgid "Groups" msgstr "軟體群組" -#: template/pkg_details.php msgid "Conflicts" msgstr "衝突" -#: template/pkg_details.php msgid "Provides" msgstr "它提供" -#: template/pkg_details.php msgid "Replaces" msgstr "它會取代" -#: template/pkg_details.php msgid "Dependencies" msgstr "它依賴" -#: template/pkg_details.php msgid "Required by" msgstr "需要它" -#: template/pkg_details.php msgid "Sources" msgstr "來源" -#: template/pkgreq_close_form.php -#, php-format -msgid "Close Request: %s" -msgstr "關閉請求: %s" - -#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "使用這個表單以關閉請求套件基礎 %s%s%s 。" -#: template/pkgreq_close_form.php msgid "Note" msgstr "注意" -#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "評論區域可以留空。但強烈建議在拒絕一個請求時加入一些評論。" -#: template/pkgreq_close_form.php msgid "Reason" msgstr "理由" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Accepted" msgstr "已接受" -#: template/pkgreq_close_form.php template/pkgreq_results.php -#: template/tu_details.php msgid "Rejected" msgstr "已拒絕" -#: template/pkgreq_form.php -#, php-format -msgid "File Request: %s" -msgstr "檔案請求: %s" - -#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "使用這個表單以提交一個針對包含以下套件的套件基礎 %s%s%s :" +msgstr "使用這個表單以提交針對套件基礎 %s%s%s 的請求。它包含以下套件:" -#: template/pkgreq_form.php msgid "Request type" msgstr "請求類型" -#: template/pkgreq_form.php msgid "Deletion" msgstr "刪除" -#: template/pkgreq_form.php msgid "Orphan" msgstr "棄置" -#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "合併到" -#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "找到了 %d 個套件請求。" -#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "第 %d 頁,共 %d 頁。" -#: template/pkgreq_results.php msgid "Package" msgstr "套件" -#: template/pkgreq_results.php msgid "Filed by" msgstr "提交人為" -#: template/pkgreq_results.php msgid "Date" msgstr "日期" -#: template/pkgreq_results.php #, php-format msgid "~%d days left" msgstr "剩餘 ~%d 天" -#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "剩餘 ~%d 小時" -#: template/pkgreq_results.php msgid "<1 hour left" msgstr "剩餘 <1 小時" -#: template/pkgreq_results.php msgid "Accept" msgstr "接受" -#: template/pkgreq_results.php msgid "Locked" msgstr "已鎖定" -#: template/pkgreq_results.php msgid "Close" msgstr "關閉" -#: template/pkgreq_results.php msgid "Closed" msgstr "已關閉" -#: template/pkg_search_form.php msgid "Name, Description" msgstr "名稱,描述" -#: template/pkg_search_form.php msgid "Name Only" msgstr "只有名稱" -#: template/pkg_search_form.php msgid "Exact Name" msgstr "確切的名稱" -#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "確切的套件基礎" -#: template/pkg_search_form.php msgid "All" msgstr "全部" -#: template/pkg_search_form.php msgid "Flagged" msgstr "已標記" -#: template/pkg_search_form.php msgid "Not Flagged" msgstr "未標記" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名稱" -#: template/pkg_search_form.php template/pkg_search_results.php -#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "已投票" -#: template/pkg_search_form.php msgid "Last modified" msgstr "最後修改" -#: template/pkg_search_form.php msgid "Ascending" msgstr "遞增" -#: template/pkg_search_form.php msgid "Descending" msgstr "遞減" -#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "輸入搜尋條件" -#: template/pkg_search_form.php msgid "Search by" msgstr "以何種方式搜尋" -#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "過期狀態" -#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "排列依據" -#: template/pkg_search_form.php msgid "Sort order" msgstr "排列方式" -#: template/pkg_search_form.php msgid "Per page" msgstr "每頁顯示" -#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "到" -#: template/pkg_search_form.php msgid "Orphans" msgstr "被棄置的套件" -#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "擷取套件列表時發生錯誤。" -#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "沒有套件符合您的搜尋條件。" -#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "找到 %d 個套件。" -#: template/pkg_search_results.php msgid "Version" msgstr "版本" -#: template/pkg_search_results.php msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of 0.98 per day since its creation." msgstr "人氣的計算方式為,將所有票數加總,且每一票自建立以來每天乘上 0.98。" -#: template/pkg_search_results.php template/tu_details.php -#: template/tu_list.php msgid "Yes" msgstr "是" -#: template/pkg_search_results.php msgid "orphan" msgstr "被棄置的套件" -#: template/pkg_search_results.php msgid "Actions" msgstr "動作" -#: template/pkg_search_results.php -msgid "Flag Out-of-date" -msgstr "標記為過期" - -#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "取消過期標誌" -#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "接管套件" -#: template/pkg_search_results.php msgid "Disown Packages" msgstr "棄置套件" -#: template/pkg_search_results.php msgid "Delete Packages" msgstr "刪除套件" -#: template/pkg_search_results.php msgid "Confirm" msgstr "確認" -#: template/search_accounts_form.php msgid "Any type" msgstr "任何類型" -#: template/search_accounts_form.php msgid "Search" msgstr "搜尋" -#: template/stats/general_stats_table.php msgid "Statistics" msgstr "統計" -#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "棄置套件" -#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "過去 7 天內加入的套件" -#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "過去 7 天內更新的套件" -#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "過去一年內更新的套件" -#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "從未更新過的套件" -#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "已註冊的使用者" -#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "受信使用者" -#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最近更新" -#: template/stats/user_table.php +msgid "more" +msgstr "更多" + msgid "My Statistics" msgstr "我的統計" -#: template/tu_details.php msgid "Proposal Details" msgstr "建議詳情" -#: template/tu_details.php msgid "This vote is still running." msgstr "此投票仍在繼續。" -#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "已提交 %s 由 %s" -#: template/tu_details.php template/tu_list.php msgid "End" msgstr "結束" -#: template/tu_details.php msgid "Result" msgstr "結果" -#: template/tu_details.php template/tu_list.php msgid "No" msgstr "否" -#: template/tu_details.php msgid "Abstain" msgstr "棄權" -#: template/tu_details.php msgid "Total" msgstr "總數" -#: template/tu_details.php msgid "Participation" msgstr "參與" -#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "受信使用者的最後投票" -#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最後投票" -#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "沒有找到結果。" -#: template/tu_list.php msgid "Start" msgstr "開始" -#: template/tu_list.php msgid "Back" msgstr "返回" From d38a562b4d60c480fe27e5a4010e378a4485035b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 15 Feb 2016 08:18:55 +0100 Subject: [PATCH 0166/1891] Release 4.2.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 7241c3ef..37f30f06 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Thu, 18 Feb 2016 08:26:18 +0100 Subject: [PATCH 0167/1891] notify: Reintroduce Message-ID again In commit 7b57e0e (Set Message-ID when sending package request emails, 2014-07-01), we changed the code responsible for sending notifications such that the value of the Message-ID header is set deterministically in the first email referring to a request. Unfortunately, this was forgotten when porting the notification routines to Python in 9746a65 (Port notification routines to Python, 2015-06-27) and later fixed by 092e00f (notify: Fix references in request notifications, 2015-10-10). However, when fixing another bug, the old behavior of not setting a Message-ID was restored by d87b138 (notify: Fix merging of header dicts, 2015-10-26). Revert that particular change once more and add a comment such that the line gets extra attention, should it be changed in the future. Fixes FS#48239. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/notify.py b/scripts/notify.py index 56534ae7..2dd8805c 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -324,7 +324,8 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): refs = '[1] ' + user_uri + '\n' refs += '[2] ' + pkgbase_uri + '\n' thread_id = '' - headers = headers_reply(thread_id) + # Use a deterministic Message-ID for the first email referencing a request. + headers = headers_msgid(thread_id) headers.update(headers_cc(cc)) send_notification(to, subject, body, refs, headers) From 1626d4d2f7a854ae39df31ccde9105b59197d16d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 18 Feb 2016 08:43:50 +0100 Subject: [PATCH 0168/1891] notify: Fix notification of request initiator Reimplement get_request_recipients() such that it always returns the email addresses of the package base maintainer and the request initiator, instead of the email address of the user triggering the request status change. Fixes FS#48238. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 2dd8805c..25102a26 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -115,11 +115,14 @@ def get_update_recipients(cur, pkgbase_id, uid): return [row[0] for row in cur.fetchall()] -def get_request_recipients(cur, pkgbase_id, uid): - cur.execute('SELECT DISTINCT Users.Email FROM Users ' + +def get_request_recipients(cur, reqid): + cur.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + 'INNER JOIN PackageBases ' + - 'ON PackageBases.MaintainerUID = Users.ID WHERE ' + - 'Users.ID = %s OR PackageBases.ID = %s', [uid, pkgbase_id]) + 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + + 'INNER JOIN Users ' + + 'ON Users.ID = PackageRequests.UsersID ' + + 'OR Users.ID = PackageBases.MaintainerUID ' + + 'WHERE PackageRequests.ID = %s', [reqid]) return [row[0] for row in cur.fetchall()] @@ -301,7 +304,7 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): user = username_from_id(cur, uid) pkgbase = pkgbase_from_id(cur, pkgbase_id) to = [aur_request_ml] - cc = get_request_recipients(cur, pkgbase_id, uid) + cc = get_request_recipients(cur, reqid) text = get_request_comment(cur, reqid) user_uri = aur_location + '/account/' + user + '/' @@ -333,9 +336,8 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): def request_close(cur, uid, reqid, reason): user = username_from_id(cur, uid) - pkgbase_id = pkgbase_from_pkgreq(cur, reqid) to = [aur_request_ml] - cc = get_request_recipients(cur, pkgbase_id, uid) + cc = get_request_recipients(cur, reqid) text = get_request_closure_comment(cur, reqid) user_uri = aur_location + '/account/' + user + '/' From fb56ec9d1e4c814f76e6c84174151376092b96dc Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 18 Feb 2016 08:33:12 +0100 Subject: [PATCH 0169/1891] Hide orphan request option for disowned package bases If a package base is unmaintained, there is no need to file an orphan request. Hide the option from the front-end in this case. Signed-off-by: Lukas Fleischer --- web/template/pkgreq_form.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php index 5bd2bfe9..4fd7851d 100644 --- a/web/template/pkgreq_form.php +++ b/web/template/pkgreq_form.php @@ -19,7 +19,9 @@

    From c23914fc1df309a6b1d85ec5387cfbef2161e655 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Tue, 16 Feb 2016 08:21:55 -0500 Subject: [PATCH 0170/1891] Unset $pinned unconditionally when displaying comments In pkg_comments.php, the $pinned variable is used to determine whether the template is supposed to print all comments or pinned comments only. If the $pinned variable is unset, the top 10 comments are printed, followed by an "All comments" link. If the $pinned variable is set, the pinned comments are printed and the "All comments" link below the comment listing is skipped. Thus, we need to make sure that this variable is always unset at the time we include the template to display all comments, even if it was empty before. Fixes FS#48194. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 2 +- web/lib/pkgfuncs.inc.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index c0e672ad..1691bff7 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -252,8 +252,8 @@ function pkgbase_display_details($base_id, $row, $SID="") { $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); if (!empty($pinned)) { include('pkg_comments.php'); - unset($pinned); } + unset($pinned); $limit = isset($_GET['comments']) ? 0 : 10; $comments = pkgbase_comments($base_id, $limit, $include_deleted); diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 0e152ddc..eaea3188 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -629,8 +629,8 @@ function pkg_display_details($id=0, $row, $SID="") { $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); if (!empty($pinned)) { include('pkg_comments.php'); - unset($pinned); } + unset($pinned); $limit = isset($_GET['comments']) ? 0 : 10; $comments = pkgbase_comments($base_id, $limit, $include_deleted); From 6ec4a3589e327ded693ab0c741828fc5ec66b840 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 21 Feb 2016 19:44:38 +0100 Subject: [PATCH 0171/1891] Send notifications when changing ownership Add a new option that makes it possible to subscribe to package ownership changes (adoption/disownment). Fixes FS#15412. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 44 ++++++++++++++++++++++++++++++ upgrading/4.3.0.txt | 5 ++++ web/lib/acctfuncs.inc.php | 7 +++-- web/lib/pkgbasefuncs.inc.php | 8 +++++- web/template/account_edit_form.php | 4 +++ 5 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 upgrading/4.3.0.txt diff --git a/scripts/notify.py b/scripts/notify.py index 25102a26..5e5f3772 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -115,6 +115,16 @@ def get_update_recipients(cur, pkgbase_id, uid): return [row[0] for row in cur.fetchall()] +def get_ownership_recipients(cur, pkgbase_id, uid): + cur.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.OwnershipNotify = 1 AND ' + + 'PackageNotifications.UserID != %s AND ' + + 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) + return [row[0] for row in cur.fetchall()] + + def get_request_recipients(cur, reqid): cur.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + 'INNER JOIN PackageBases ' + @@ -243,6 +253,38 @@ def flag(cur, uid, pkgbase_id): send_notification(to, subject, body, refs) +def adopt(cur, pkgbase_id, uid): + user = username_from_id(cur, uid) + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = get_ownership_recipients(cur, pkgbase_id, uid) + + user_uri = aur_location + '/account/' + user + '/' + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = 'AUR Ownership Notification for %s' % (pkgbase) + body = 'The package %s [1] was adopted by %s [2].' % (pkgbase, user) + refs = '[1] ' + pkgbase_uri + '\n' + refs += '[2] ' + user_uri + + send_notification(to, subject, body, refs) + + +def disown(cur, pkgbase_id, uid): + user = username_from_id(cur, uid) + pkgbase = pkgbase_from_id(cur, pkgbase_id) + to = get_ownership_recipients(cur, pkgbase_id, uid) + + user_uri = aur_location + '/account/' + user + '/' + pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' + + subject = 'AUR Ownership Notification for %s' % (pkgbase) + body = 'The package %s [1] was disowned by %s [2].' % (pkgbase, user) + refs = '[1] ' + pkgbase_uri + '\n' + refs += '[2] ' + user_uri + + send_notification(to, subject, body, refs) + + def comaintainer_add(cur, pkgbase_id, uid): pkgbase = pkgbase_from_id(cur, pkgbase_id) to = [get_user_email(cur, uid)] @@ -364,6 +406,8 @@ if __name__ == '__main__': 'comment': comment, 'update': update, 'flag': flag, + 'adopt': adopt, + 'disown': disown, 'comaintainer-add': comaintainer_add, 'comaintainer-remove': comaintainer_remove, 'delete': delete, diff --git a/upgrading/4.3.0.txt b/upgrading/4.3.0.txt new file mode 100644 index 00000000..0d3a9b7b --- /dev/null +++ b/upgrading/4.3.0.txt @@ -0,0 +1,5 @@ +1. Add a column to store ownership notification settings: + +---- +ALTER TABLE Users ADD COLUMN OwnershipNotify TINYINT(1) NOT NULL DEFAULT 1; +---- diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index b39420fe..be0981f2 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -58,13 +58,14 @@ function html_format_pgp_fingerprint($fingerprint) { * @param string $J The inactivity status of the displayed user * @param string $CN Whether to notify of new comments * @param string $UN Whether to notify of package updates + * @param string $ON Whether to notify of ownership changes * @param string $UID The user ID of the displayed user * @param string $N The username as present in the database * * @return void */ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="", - $L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$UID=0,$N="") { + $L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="") { global $SUPPORTED_LANGS; include("account_edit_form.php"); @@ -92,13 +93,14 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $J The inactivity status of the user * @param string $CN Whether to notify of new comments * @param string $UN Whether to notify of package updates + * @param string $ON Whether to notify of ownership changes * @param string $UID The user ID of the modified account * @param string $N The username as present in the database * * @return array Boolean indicating success and message to be printed */ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", - $R="",$L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$UID=0,$N="") { + $R="",$L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="") { global $SUPPORTED_LANGS; $error = ''; @@ -347,6 +349,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $q.= ", InactivityTS = " . $inactivity_ts; $q.= ", CommentNotify = " . ($CN ? "1" : "0"); $q.= ", UpdateNotify = " . ($UN ? "1" : "0"); + $q.= ", OwnershipNotify = " . ($ON ? "1" : "0"); $q.= " WHERE ID = ".intval($UID); $result = $dbh->exec($q); diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 1691bff7..5d10cce5 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -661,6 +661,9 @@ function pkgbase_adopt ($base_ids, $action=true, $via) { $q.= "SET MaintainerUID = $uid "; $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; $dbh->exec($q); + + /* Add the new maintainer to the notification list. */ + pkgbase_notify($base_ids); } else { /* Update the co-maintainer list when disowning a package. */ if (has_credential(CRED_PKGBASE_DISOWN)) { @@ -692,8 +695,11 @@ function pkgbase_adopt ($base_ids, $action=true, $via) { } } + foreach ($base_ids as $base_id) { + notify(array($action ? 'adopt' : 'disown', $base_id, $uid)); + } + if ($action) { - pkgbase_notify($base_ids); return array(true, __("The selected packages have been adopted.")); } else { return array(true, __("The selected packages have been disowned.")); diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index b9affd64..b4f01926 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -143,6 +143,10 @@ />

    +

    + + /> +

    From 4c15f02ecb01e5d31ee575ead72c5b33db731032 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 1 Mar 2016 08:45:46 +0100 Subject: [PATCH 0172/1891] popupdate: Avoid NULL entries in the popularity field The popularity field is declared as "NOT NULL" in the database schema. Fix the popularity update query such that it uses a popularity of 0.0 instead of NULL for packages with no votes. Signed-off-by: Lukas Fleischer --- scripts/popupdate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/popupdate.py b/scripts/popupdate.py index 2aa8a546..f3ba5131 100755 --- a/scripts/popupdate.py +++ b/scripts/popupdate.py @@ -22,7 +22,7 @@ cur.execute("UPDATE PackageBases SET NumVotes = (SELECT COUNT(*) FROM " + "PackageVotes WHERE PackageVotes.PackageBaseID = PackageBases.ID)") cur.execute("UPDATE PackageBases SET Popularity = (" + - "SELECT SUM(POWER(0.98, (UNIX_TIMESTAMP() - VoteTS) / 86400)) " + + "SELECT COALESCE(SUM(POWER(0.98, (UNIX_TIMESTAMP() - VoteTS) / 86400)), 0.0) " + "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + "PackageBases.ID AND NOT VoteTS IS NULL)") From 42f5c405c0280b6216028d0513e29c306e388426 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 1 Mar 2016 18:30:48 +0100 Subject: [PATCH 0173/1891] aurjson: Remove stray GROUP BY clause The IDs of packages are unique, so there is no need to group search results by package ID. Note that the GROUP BY statement in question was introduced in commit 3447dfc (Support versioned RPC queries, 2014-04-28) for no apparent reason and could even lead to errors in various DBMS. Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 7f9b5f2e..3bd9179c 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -266,7 +266,6 @@ class AurJSON { "ON Licenses.ID = PackageLicenses.LicenseID " . "WHERE ${where_condition} " . "AND PackageBases.PackagerUID IS NOT NULL " . - "GROUP BY Packages.ID " . "LIMIT $max_results"; } elseif ($this->version >= 2) { if ($this->version == 2 || $this->version == 3) { From 7b13203b817084717a46e2f671e3cb533fdb1092 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Sat, 12 Mar 2016 14:50:03 +0000 Subject: [PATCH 0174/1891] Limit comment height to 15 lines Signed-off-by: Eric Engestrom Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index f5e10371..f777ab83 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -148,3 +148,8 @@ label.confirmation, color: red; font-weight: bold; } + +#news div p { + max-height: 15em; + overflow: auto; +} From 2dfa72131bfbc96584b78b597f86471874108a89 Mon Sep 17 00:00:00 2001 From: "Ian D. Scott" Date: Sat, 12 Mar 2016 13:49:46 -0800 Subject: [PATCH 0175/1891] Remove code referencing non-existent and unused file Signed-off-by: Lukas Fleischer --- web/html/index.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/web/html/index.php b/web/html/index.php index 3787d4e4..78ab6ad7 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -167,10 +167,6 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { header("Content-Type: image/gif"); readfile("./$path"); break; - case "/css/archnavbar/archlogo.gif": - header("Content-Type: image/png"); - readfile("./$path"); - break; case "/css/archnavbar/archlogo.png": case "/css/archnavbar/aurlogo.png": case "/images/favicon.ico": From 761952d424ded8848335116beef962c39c551bc4 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 11 Mar 2016 20:31:50 +0100 Subject: [PATCH 0176/1891] Fix l10n of "more" Use __() instead of _() to make the string translatable. Fixes FS#48529. Signed-off-by: Lukas Fleischer --- web/template/stats/updates_table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index 4e2d39d5..580583b5 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -1,4 +1,4 @@ -

    ()

    +

    ()

    RSS Feed From 32c8d0c3f837950518f886ed9baef00e98740049 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Mar 2016 11:37:48 +0100 Subject: [PATCH 0177/1891] Store last login address as plain text Directly store the information contained in $_SERVER['REMOTE_ADDR'] instead of using ip2long() which does not support IPv6 addresses. Note that the LastLoginIPAddress field is designed to be used by the administrator on rare occasions only (e.g. to fight spam) and is not displayed anywhere. Fixes FS#48557. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.2.1.txt | 5 +++++ web/lib/acctfuncs.inc.php | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 upgrading/4.2.1.txt diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 1a141c14..aa5ed9da 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -35,7 +35,7 @@ CREATE TABLE Users ( IRCNick VARCHAR(32) NOT NULL DEFAULT '', PGPKey VARCHAR(40) NULL DEFAULT NULL, LastLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, - LastLoginIPAddress INTEGER UNSIGNED NOT NULL DEFAULT 0, + LastLoginIPAddress VARCHAR(40) NULL DEFAULT NULL, InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0, RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CommentNotify TINYINT(1) NOT NULL DEFAULT 1, diff --git a/upgrading/4.2.1.txt b/upgrading/4.2.1.txt new file mode 100644 index 00000000..83c8d46a --- /dev/null +++ b/upgrading/4.2.1.txt @@ -0,0 +1,5 @@ +1. Convert the LastLoginIPAddress column to VARCHAR(40): + +---- +ALTER TABLE Users MODIFY LastLoginIPAddress VARCHAR(40) NULL DEFAULT NULL; +---- diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index b39420fe..2d70f65f 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -554,8 +554,8 @@ function try_login() { } $q = "UPDATE Users SET LastLogin = UNIX_TIMESTAMP(), "; - $q.= "LastLoginIPAddress = " . $dbh->quote(ip2long($_SERVER['REMOTE_ADDR'])) . " "; - $q.= "WHERE ID = '$userID'"; + $q.= "LastLoginIPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']) . " "; + $q.= "WHERE ID = $userID"; $dbh->exec($q); /* Set the SID cookie. */ From 27ad06e3538e0ffb112b49a9edba6bd42d0e2e2d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Mar 2016 13:52:57 +0100 Subject: [PATCH 0178/1891] Release 4.2.1 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 37f30f06..9c0a5e60 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Tue, 15 Mar 2016 17:56:43 +0100 Subject: [PATCH 0179/1891] Fix instructions for omitting "have" lines In 002d348 (Describe how to omit "have" lines, 2015-11-14), we added instructions on how to omit "have" lines originating from other package repositories. Fix those instructions such that the HEAD ref of the repository is transferred properly. Signed-off-by: Lukas Fleischer --- INSTALL | 3 ++- doc/git-interface.txt | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/INSTALL b/INSTALL index be390525..8b0cd290 100644 --- a/INSTALL +++ b/INSTALL @@ -47,7 +47,8 @@ Setup on Arch Linux # cd /srv/http/aurweb/aur.git/ # git init --bare # git config --local transfer.hideRefs '^refs/' - # git config --local transfer.hideRefs '!refs/' + # git config --local --add transfer.hideRefs '!refs/' + # git config --local --add transfer.hideRefs '!HEAD' # ln -s ../../git-interface/git-update.py hooks/update # chown -R aur . diff --git a/doc/git-interface.txt b/doc/git-interface.txt index 4a24eeff..69c558b1 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -89,7 +89,7 @@ so-called "have" lines. This is normally used to reduce traffic but it has the opposite effect in the case of aurweb: Many essentially useless lines are transferred to the Git client during `git push` operations. -In order to omit these advertisements, add the strings "^refs/" and "!refs/" to -the transfer.hideRefs configuration setting. Note that the order of these -patterns is important ("^refs/" must come first) and that Git 2.7 or newer is -required for them to work. +In order to omit these advertisements, add the strings "^refs/", "!refs/" and +"!HEAD" to the transfer.hideRefs configuration setting. Note that the order of +these patterns is important ("^refs/" must come first) and that Git 2.7 or +newer is required for them to work. From 0108c64541d2cd9684ce0b75acfc541bf479ae71 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 15 Mar 2016 18:01:15 +0100 Subject: [PATCH 0180/1891] Resize the LastLoginIPAddress column Make sure that all valid IPv6 addresses fit into the LastLoginIPAddress field. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.3.0.txt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index aa5ed9da..0804ac35 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -35,7 +35,7 @@ CREATE TABLE Users ( IRCNick VARCHAR(32) NOT NULL DEFAULT '', PGPKey VARCHAR(40) NULL DEFAULT NULL, LastLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, - LastLoginIPAddress VARCHAR(40) NULL DEFAULT NULL, + LastLoginIPAddress VARCHAR(45) NULL DEFAULT NULL, InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0, RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CommentNotify TINYINT(1) NOT NULL DEFAULT 1, diff --git a/upgrading/4.3.0.txt b/upgrading/4.3.0.txt index 0d3a9b7b..34b19a2c 100644 --- a/upgrading/4.3.0.txt +++ b/upgrading/4.3.0.txt @@ -3,3 +3,9 @@ ---- ALTER TABLE Users ADD COLUMN OwnershipNotify TINYINT(1) NOT NULL DEFAULT 1; ---- + +2. Resize the LastLoginIPAddress column: + +---- +ALTER TABLE Users MODIFY LastLoginIPAddress VARCHAR(45) NULL DEFAULT NULL; +---- From 2ef5f8a5ff23ee0b45a67f1d2ca3f646f09c2ff5 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Thu, 17 Mar 2016 15:58:14 -0400 Subject: [PATCH 0181/1891] Change text of enable notifications link Since notifications are sent for more than just comments, change the notify link to more generic text. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/template/pkgbase_actions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php index 237e712f..d3f05921 100644 --- a/web/template/pkgbase_actions.php +++ b/web/template/pkgbase_actions.php @@ -24,7 +24,7 @@
  • -
  • +
  • From b091fb77580d56dbdca6424f9065581945b8e815 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 28 Apr 2016 08:19:25 +0200 Subject: [PATCH 0182/1891] Add hard limit on the length of dependency lists Introduce a configuration option max_depends which can be used to specify a maximum number of (reverse) dependencies to display on the package details pages. Fixes FS#49059. Signed-off-by: Lukas Fleischer --- conf/config.proto | 1 + web/lib/pkgfuncs.inc.php | 10 ++++++---- web/template/pkg_details.php | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index 560c705e..64af774d 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -21,6 +21,7 @@ aur_location = https://aur.archlinux.org git_clone_uri_anon = https://aur.archlinux.org/%s.git git_clone_uri_priv = ssh://aur@aur.archlinux.org/%s.git max_rpc_results = 5000 +max_depends = 1000 aur_request_ml = aur-requests@archlinux.org request_idle_time = 1209600 auto_orphan_age = 15552000 diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index eaea3188..f34dbba6 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -230,10 +230,11 @@ function pkg_providers($name) { * Get package dependencies for a specific package * * @param int $pkgid The package to get dependencies for + * @param int $limit An upper bound on the number of packages to retrieve * * @return array All package dependencies for the package */ -function pkg_dependencies($pkgid) { +function pkg_dependencies($pkgid, $limit) { $deps = array(); $pkgid = intval($pkgid); if ($pkgid > 0) { @@ -243,7 +244,7 @@ function pkg_dependencies($pkgid) { $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) = p.Name "; $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; $q.= "WHERE pd.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pd.DepName"; + $q.= "ORDER BY pd.DepName LIMIT " . intval($limit); $result = $dbh->query($q); if (!$result) { return array(); @@ -505,10 +506,11 @@ function pkg_source_link($url, $arch) { * * @param string $name The package name for the dependency search * @param array $provides A list of virtual provisions of the package + * @param int $limit An upper bound on the number of packages to retrieve * * @return array All packages that depend on the specified package name */ -function pkg_required($name="", $provides) { +function pkg_required($name="", $provides, $limit) { $deps = array(); if ($name != "") { $dbh = DB::connect(); @@ -523,7 +525,7 @@ function pkg_required($name="", $provides) { $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; $q.= "WHERE pd.DepName IN (" . $name_list . ") "; $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) IN (" . $name_list . ") "; - $q.= "ORDER BY p.Name"; + $q.= "ORDER BY p.Name LIMIT " . intval($limit); $result = $dbh->query($q); if (!$result) {return array();} while ($row = $result->fetch(PDO::FETCH_NUM)) { diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 8b038b9b..b9c66d47 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -5,6 +5,7 @@ $log_uri = sprintf(config_get('options', 'log_uri'), urlencode($row['BaseName']) $snapshot_uri = sprintf(config_get('options', 'snapshot_uri'), urlencode($row['BaseName'])); $git_clone_uri_anon = sprintf(config_get('options', 'git_clone_uri_anon'), htmlspecialchars($row['BaseName'])); $git_clone_uri_priv = sprintf(config_get('options', 'git_clone_uri_priv'), htmlspecialchars($row['BaseName'])); +$max_depends = config_get_int('options', 'max_depends'); $uid = uid_from_sid($SID); @@ -40,7 +41,7 @@ $out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : gmdate("Y-m-d", intval($ $lics = pkg_licenses($row["ID"]); $grps = pkg_groups($row["ID"]); -$deps = pkg_dependencies($row["ID"]); +$deps = pkg_dependencies($row["ID"], $max_depends); usort($deps, function($x, $y) { if ($x[1] != $y[1]) { @@ -82,7 +83,7 @@ foreach ($rels as $rel) { } } -$requiredby = pkg_required($row["Name"], $rels_p); +$requiredby = pkg_required($row["Name"], $rels_p, $max_depends); # $sources[0] = 'src'; $sources = pkg_sources($row["ID"]); From b2e97cdd1ee804468b2dd601eafda9574c05a3a7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 17 May 2016 19:03:39 +0200 Subject: [PATCH 0183/1891] Add repository information to official providers When updating the list of packages provided by the official repositories, also save the repository names. --- schema/aur-schema.sql | 1 + scripts/aurblup.py | 8 ++++++-- upgrading/4.3.0.txt | 6 ++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 0804ac35..ea19d465 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -310,6 +310,7 @@ CREATE TABLE PackageBlacklist ( CREATE TABLE OfficialProviders ( ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, Name VARCHAR(64) NOT NULL, + Repo VARCHAR(64) NOT NULL, Provides VARCHAR(64) NOT NULL, PRIMARY KEY (ID) ) ENGINE = InnoDB; diff --git a/scripts/aurblup.py b/scripts/aurblup.py index 325ef3dd..9e11e430 100755 --- a/scripts/aurblup.py +++ b/scripts/aurblup.py @@ -20,6 +20,7 @@ servers = config.get('aurblup', 'servers').split(' ') blacklist = set() providers = set() +repomap = dict() h = pyalpm.Handle("/", db_path) for sync_db in sync_dbs: @@ -33,9 +34,11 @@ for sync_db in sync_dbs: blacklist.add(pkg.name) [blacklist.add(x) for x in pkg.replaces] providers.add((pkg.name, pkg.name)) + repomap[(pkg.name, pkg.name)] = repo.name for provision in pkg.provides: provisionname = re.sub(r'(<|=|>).*', '', provision) providers.add((pkg.name, provisionname)) + repomap[(pkg.name, provisionname)] = repo.name db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, @@ -54,8 +57,9 @@ cur.execute("SELECT Name, Provides FROM OfficialProviders") oldproviders = set(cur.fetchall()) for pkg, provides in providers.difference(oldproviders): - cur.execute("INSERT INTO OfficialProviders (Name, Provides) " - "VALUES (%s, %s)", [pkg, provides]) + repo = repomap[(pkg, provides)] + cur.execute("INSERT INTO OfficialProviders (Name, Repo, Provides) " + "VALUES (%s, %s, %s)", [pkg, repo, provides]) for pkg, provides in oldproviders.difference(providers): cur.execute("DELETE FROM OfficialProviders " "WHERE Name = %s AND Provides = %s", [pkg, provides]) diff --git a/upgrading/4.3.0.txt b/upgrading/4.3.0.txt index 34b19a2c..f7f3e08c 100644 --- a/upgrading/4.3.0.txt +++ b/upgrading/4.3.0.txt @@ -9,3 +9,9 @@ ALTER TABLE Users ADD COLUMN OwnershipNotify TINYINT(1) NOT NULL DEFAULT 1; ---- ALTER TABLE Users MODIFY LastLoginIPAddress VARCHAR(45) NULL DEFAULT NULL; ---- + +3. Add a new column to store repository information of official providers: + +---- +ALTER TABLE OfficialProviders ADD COLUMN Repo VARCHAR(64) NOT NULL; +---- From d273ee5eb20ecb6e97d5d6cd8a1f493e3652b584 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 17 May 2016 19:07:41 +0200 Subject: [PATCH 0184/1891] Use the official provider list to detect duplicates Instead of automatically adding packages from the official binary repositories to the package blacklist, use the official provider list to prevent users from uploading duplicates. This does not only result in reduced disk usage but also has a nice visible side effect. The error messages printed by the update hook now look like error: package already provided by [community]: powerline-fonts instead of error: package is blacklisted: powerline-fonts which was confusing to most end users. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 6 ++++++ scripts/aurblup.py | 8 -------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index e54e0e68..2c24e720 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -331,12 +331,18 @@ pkgbase_id = cur.fetchone()[0] if cur.rowcount == 1 else 0 cur.execute("SELECT Name FROM PackageBlacklist") blacklist = [row[0] for row in cur.fetchall()] +cur.execute("SELECT Name, Repo FROM OfficialProviders") +providers = dict(cur.fetchall()) + for pkgname in srcinfo.utils.get_package_names(metadata): pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) pkgname = pkginfo['pkgname'] if pkgname in blacklist and not privileged: die('package is blacklisted: {:s}'.format(pkgname)) + if pkgname in providers and not privileged: + repo = providers[pkgname] + die('package already provided by [{:s}]: {:s}'.format(repo, pkgname)) cur.execute("SELECT COUNT(*) FROM Packages WHERE Name = %s AND " + "PackageBaseID <> %s", [pkgname, pkgbase_id]) diff --git a/scripts/aurblup.py b/scripts/aurblup.py index 9e11e430..6733b45d 100755 --- a/scripts/aurblup.py +++ b/scripts/aurblup.py @@ -45,14 +45,6 @@ db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, unix_socket=aur_db_socket, buffered=True) cur = db.cursor() -cur.execute("SELECT Name FROM PackageBlacklist") -oldblacklist = set([row[0] for row in cur.fetchall()]) - -for pkg in blacklist.difference(oldblacklist): - cur.execute("INSERT INTO PackageBlacklist (Name) VALUES (%s)", [pkg]) -for pkg in oldblacklist.difference(blacklist): - cur.execute("DELETE FROM PackageBlacklist WHERE Name = %s", [pkg]) - cur.execute("SELECT Name, Provides FROM OfficialProviders") oldproviders = set(cur.fetchall()) From e17e88a2e20531914cda220543c55d991b99721c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 23 May 2016 22:53:12 +0200 Subject: [PATCH 0185/1891] Add request type hints Add a text that explains when the currently selected request type should be used. Signed-off-by: Lukas Fleischer --- web/template/pkgreq_form.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php index 4fd7851d..639326eb 100644 --- a/web/template/pkgreq_form.php +++ b/web/template/pkgreq_form.php @@ -16,7 +16,7 @@

    - @@ -35,8 +35,16 @@ } } + function showHideRequestHints() { + $('#deletion_hint').hide(); + $('#merge_hint').hide(); + $('#orphan_hint').hide(); + $('#' + $('#id_type').val() + '_hint').show(); + } + $(document).ready(function() { showHideMergeSection(); + showHideRequestHints(); $('#id_merge_into').typeahead({ source: function(query, callback) { @@ -59,6 +67,15 @@

    +

    + +

    +

    + +

    +

    + +

    " />

    From b757246e33a8cfcb5b8973d659a0b513d3b767d7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 2 Jun 2016 08:37:43 +0200 Subject: [PATCH 0186/1891] pkgbasefuncs.inc.php: Remove debug statement Remove a leftover var_dump() invocation that was introduced in commit 5fb7a74 (Replace categories with keywords, 2015-06-13). Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 5d10cce5..b0827844 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -1062,7 +1062,6 @@ function pkgbase_set_keywords($base_id, $keywords) { $i = 0; foreach ($keywords as $keyword) { $q = sprintf("INSERT INTO PackageKeywords (PackageBaseID, Keyword) VALUES (%d, %s)", $base_id, $dbh->quote($keyword)); - var_dump($q); $dbh->exec($q); $i++; From 333596ab4aca12bd9444196066f1511f07650f3f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 8 Jun 2016 22:02:03 +0200 Subject: [PATCH 0187/1891] Update Arch Linux projects subdomain The projects.archlinux.org subdomain was moved to git.archlinux.org. Signed-off-by: Lukas Fleischer --- INSTALL | 2 +- README | 2 +- doc/i18n.txt | 2 +- web/template/footer.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/INSTALL b/INSTALL index 8b0cd290..dab48cc1 100644 --- a/INSTALL +++ b/INSTALL @@ -4,7 +4,7 @@ Setup on Arch Linux 1) Clone the AUR project: $ cd /srv/http/ - $ git clone git://projects.archlinux.org/aurweb.git + $ git clone git://git.archlinux.org/aurweb.git 2) Setup a web server with PHP and MySQL. Configure the web server to redirect all URLs to /index.php/foo/bar/. The following block can be used with nginx: diff --git a/README b/README index 71e84818..19881864 100644 --- a/README +++ b/README @@ -42,7 +42,7 @@ web:: Links ----- -* The repository is hosted at git://projects.archlinux.org/aurweb.git -- see +* The repository is hosted at git://git.archlinux.org/aurweb.git -- see doc/CodingGuidelines for information on submitting patches. * Discovered bugs can be submitted to the aurweb bug tracker: diff --git a/doc/i18n.txt b/doc/i18n.txt index d5b67644..a1c21fe6 100644 --- a/doc/i18n.txt +++ b/doc/i18n.txt @@ -21,7 +21,7 @@ strings for the translation to be usable, and it may have to be disabled. 1. Check out the aurweb source using git: -$ git clone git://projects.archlinux.org/aurweb.git aurweb-git +$ git clone git://git.archlinux.org/aurweb.git aurweb-git 2. Go into the "po/" directory in the aurweb source and run msginit(1) to create a initial translation file from our translation catalog: diff --git a/web/template/footer.php b/web/template/footer.php index f5dc2d06..572dbb26 100644 --- a/web/template/footer.php +++ b/web/template/footer.php @@ -3,7 +3,7 @@
    + + + + diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index b4f01926..6c2b8fb8 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -98,6 +98,11 @@

    +

    + + +

    +

    From a2a888625eb3c3dc353e2ef55e6fcbe054ab582f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Wed, 22 Jun 2016 23:24:24 +0200 Subject: [PATCH 0190/1891] Add missing database and account fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commits 6ec4a35 (Send notifications when changing ownership, 2016-02-21) and e3670ef (Add a homepage field to accounts, 2016-06-02) forgot to change some usages of display_account_form() and process_account_form() to account for the new parameter. The former also forgot to add the new column to the database schema. Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 1 + web/html/account.php | 9 ++++++--- web/html/register.php | 45 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 7edf94c6..1affc25e 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -41,6 +41,7 @@ CREATE TABLE Users ( RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CommentNotify TINYINT(1) NOT NULL DEFAULT 1, UpdateNotify TINYINT(1) NOT NULL DEFAULT 0, + OwnershipNotify TINYINT(1) NOT NULL DEFAULT 1, PRIMARY KEY (ID), UNIQUE (Username), UNIQUE (Email), diff --git a/web/html/account.php b/web/html/account.php index 8d92b2c3..2892f046 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -34,9 +34,10 @@ if ($action == "UpdateAccount") { in_request("U"), in_request("T"), in_request("S"), in_request("E"), in_request("H"), in_request("P"), in_request("C"), in_request("R"), in_request("L"), - in_request("I"), in_request("K"), in_request("PK"), - in_request("J"), in_request("CN"), in_request("UN"), - in_request("ID"), $row["Username"]); + in_request("HP"), in_request("I"), in_request("K"), + in_request("PK"), in_request("J"), in_request("CN"), + in_request("UN"), in_request("ON"), in_request("ID"), + $row["Username"]); } } @@ -95,6 +96,7 @@ if (isset($_COOKIE["AURSID"])) { $row["InactivityTS"] ? 1 : 0, $row["CommentNotify"], $row["UpdateNotify"], + $row["OwnershipNotify"], $row["ID"], $row["Username"]); } else { @@ -146,6 +148,7 @@ if (isset($_COOKIE["AURSID"])) { in_request("J"), in_request("CN"), in_request("UN"), + in_request("ON"), in_request("ID"), $row["Username"]); } diff --git a/web/html/register.php b/web/html/register.php index 3155449c..6c6d52e6 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -20,18 +20,47 @@ echo '

    ' . __('Register') . '

    '; if (in_request("Action") == "NewAccount") { list($success, $message) = process_account_form( - "new", "NewAccount", in_request("U"), 1, 0, - in_request("E"), in_request("H"), '', '', in_request("R"), - in_request("L"), in_request("I"), in_request("K"), - in_request("PK"), 0, in_request("CN"), in_request("UN")); + "new", + "NewAccount", + in_request("U"), + 1, + 0, + in_request("E"), + in_request("H"), + '', + '', + in_request("R"), + in_request("L"), + in_request("HP"), + in_request("I"), + in_request("K"), + in_request("PK"), + 0, + in_request("CN"), + in_request("UN"), + in_request("ON")); print $message; if (!$success) { - display_account_form("NewAccount", in_request("U"), 1, 0, - in_request("E"), in_request("H"), '', '', in_request("R"), - in_request("L"), in_request("I"), in_request("K"), - in_request("PK"), 0, in_request("CN"), in_request("UN")); + display_account_form("NewAccount", + in_request("U"), + 1, + 0, + in_request("E"), + in_request("H"), + '', + '', + in_request("R"), + in_request("L"), + in_request("HP"), + in_request("I"), + in_request("K"), + in_request("PK"), + 0, + in_request("CN"), + in_request("UN"), + in_request("ON")); } } else { print '

    ' . __("Use this form to create an account.") . '

    '; From 16674e4c9d226446a8e6f2189858ab4d3b77ece0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Wed, 22 Jun 2016 23:28:43 +0200 Subject: [PATCH 0191/1891] Linkify user homepage URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/template/account_details.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/account_details.php b/web/template/account_details.php index 0ac85a5a..8b763824 100644 --- a/web/template/account_details.php +++ b/web/template/account_details.php @@ -43,7 +43,7 @@ - + From 7d42d3fc1c60e9354efb44a8a5a494ede8ddeadd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 25 Jun 2016 16:09:16 +0200 Subject: [PATCH 0192/1891] Make request type hints translatable Signed-off-by: Lukas Fleischer --- web/template/pkgreq_form.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php index 639326eb..35dbef57 100644 --- a/web/template/pkgreq_form.php +++ b/web/template/pkgreq_form.php @@ -68,13 +68,13 @@

    - +

    - +

    - +

    " /> From 0350de4b422b06e99ce769ba03d451577ecb0ee8 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 25 Jun 2016 16:09:55 +0200 Subject: [PATCH 0193/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index 0ff0bb7b..945ce5d8 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.1.1\n" +"Project-Id-Version: AUR v4.2.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" +"POT-Creation-Date: 2016-06-25 16:09+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1076,6 +1076,10 @@ msgstr "" msgid "Real Name" msgstr "" +#: template/account_details.php template/account_edit_form.php +msgid "Homepage" +msgstr "" + #: template/account_details.php template/account_edit_form.php #: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" @@ -1172,7 +1176,7 @@ msgstr "" msgid "Notification settings" msgstr "" -#: template/account_edit_form.php template/pkgbase_actions.php +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "" @@ -1180,6 +1184,10 @@ msgstr "" msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php +msgid "Notify of ownership changes" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1312,6 +1320,10 @@ msgstr "" msgid "Disable notifications" msgstr "" +#: template/pkgbase_actions.php +msgid "Enable notifications" +msgstr "" + #: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" @@ -1556,6 +1568,29 @@ msgstr "" msgid "Merge into" msgstr "" +#: template/pkgreq_form.php +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +#: template/pkgreq_form.php +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +#: template/pkgreq_form.php +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #: template/pkgreq_results.php #, php-format msgid "%d package request found." From fbf3e5405781f0f7ded67e99ab83bebc0737499d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 28 Apr 2016 19:28:23 +0200 Subject: [PATCH 0194/1891] Add hard limit for the length of dependency lists Introduce a configuration option max_depends which can be used to specify a maximum number of (reverse) dependencies to display on the package details pages. Fixes FS#49059. Signed-off-by: Lukas Fleischer --- conf/config.proto | 1 + web/lib/pkgfuncs.inc.php | 10 ++++++---- web/template/pkg_details.php | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index 560c705e..64af774d 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -21,6 +21,7 @@ aur_location = https://aur.archlinux.org git_clone_uri_anon = https://aur.archlinux.org/%s.git git_clone_uri_priv = ssh://aur@aur.archlinux.org/%s.git max_rpc_results = 5000 +max_depends = 1000 aur_request_ml = aur-requests@archlinux.org request_idle_time = 1209600 auto_orphan_age = 15552000 diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index eaea3188..4b0fdbac 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -230,10 +230,11 @@ function pkg_providers($name) { * Get package dependencies for a specific package * * @param int $pkgid The package to get dependencies for + * @param int $limit An upper bound for the number of packages to retrieve * * @return array All package dependencies for the package */ -function pkg_dependencies($pkgid) { +function pkg_dependencies($pkgid, $limit) { $deps = array(); $pkgid = intval($pkgid); if ($pkgid > 0) { @@ -243,7 +244,7 @@ function pkg_dependencies($pkgid) { $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) = p.Name "; $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; $q.= "WHERE pd.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pd.DepName"; + $q.= "ORDER BY pd.DepName LIMIT " . intval($limit); $result = $dbh->query($q); if (!$result) { return array(); @@ -505,10 +506,11 @@ function pkg_source_link($url, $arch) { * * @param string $name The package name for the dependency search * @param array $provides A list of virtual provisions of the package + * @param int $limit An upper bound for the number of packages to retrieve * * @return array All packages that depend on the specified package name */ -function pkg_required($name="", $provides) { +function pkg_required($name="", $provides, $limit) { $deps = array(); if ($name != "") { $dbh = DB::connect(); @@ -523,7 +525,7 @@ function pkg_required($name="", $provides) { $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; $q.= "WHERE pd.DepName IN (" . $name_list . ") "; $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) IN (" . $name_list . ") "; - $q.= "ORDER BY p.Name"; + $q.= "ORDER BY p.Name LIMIT " . intval($limit); $result = $dbh->query($q); if (!$result) {return array();} while ($row = $result->fetch(PDO::FETCH_NUM)) { diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 8b038b9b..b9c66d47 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -5,6 +5,7 @@ $log_uri = sprintf(config_get('options', 'log_uri'), urlencode($row['BaseName']) $snapshot_uri = sprintf(config_get('options', 'snapshot_uri'), urlencode($row['BaseName'])); $git_clone_uri_anon = sprintf(config_get('options', 'git_clone_uri_anon'), htmlspecialchars($row['BaseName'])); $git_clone_uri_priv = sprintf(config_get('options', 'git_clone_uri_priv'), htmlspecialchars($row['BaseName'])); +$max_depends = config_get_int('options', 'max_depends'); $uid = uid_from_sid($SID); @@ -40,7 +41,7 @@ $out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : gmdate("Y-m-d", intval($ $lics = pkg_licenses($row["ID"]); $grps = pkg_groups($row["ID"]); -$deps = pkg_dependencies($row["ID"]); +$deps = pkg_dependencies($row["ID"], $max_depends); usort($deps, function($x, $y) { if ($x[1] != $y[1]) { @@ -82,7 +83,7 @@ foreach ($rels as $rel) { } } -$requiredby = pkg_required($row["Name"], $rels_p); +$requiredby = pkg_required($row["Name"], $rels_p, $max_depends); # $sources[0] = 'src'; $sources = pkg_sources($row["ID"]); From 60cdad28eebf45ac2822155cea27277e1f7de455 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jun 2016 15:57:53 +0200 Subject: [PATCH 0195/1891] Distinguish auto-accepted requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before commit 9746a65 (Port notification routines to Python, 2015-06-27), notification emails for automatically closed requests explicitly stated that the action was taken "automatically by the Arch User Repository package request system". When porting the notification routines to Python, this feature was overlooked and emails sent by the new script always reported that the requester triggered the acceptance or rejection of a request. This patch reimplements the old behavior such that notifications no longer look as if the requester had accepted the request himself. Reported-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- scripts/notify.py | 19 +++++++++++++------ web/lib/pkgreqfuncs.inc.php | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/scripts/notify.py b/scripts/notify.py index 5e5f3772..6ea25d12 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -41,7 +41,10 @@ def send_notification(to, subject, body, refs, headers={}): wrapped = '' for line in body.splitlines(): wrapped += textwrap.fill(line, break_long_words=False) + '\n' - body = wrapped + '\n' + refs + if refs: + body = wrapped + '\n' + refs + else: + body = wrapped for recipient in to: msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') @@ -377,20 +380,24 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): def request_close(cur, uid, reqid, reason): - user = username_from_id(cur, uid) to = [aur_request_ml] cc = get_request_recipients(cur, reqid) text = get_request_closure_comment(cur, reqid) - user_uri = aur_location + '/account/' + user + '/' - subject = '[PRQ#%d] Request %s' % (int(reqid), reason.title()) - body = 'Request #%d has been %s by %s [1]' % (int(reqid), reason, user) + if int(uid): + user = username_from_id(cur, uid) + user_uri = aur_location + '/account/' + user + '/' + body = 'Request #%d has been %s by %s [1]' % (int(reqid), reason, user) + refs = '[1] ' + user_uri + else: + body = 'Request #%d has been %s automatically by the Arch User ' \ + 'Repository package request system' % (int(reqid), reason) + refs = None if text.strip() == '': body += '.' else: body += ':\n\n' + text - refs = '[1] ' + user_uri thread_id = '' headers = headers_reply(thread_id) headers.update(headers_cc(cc)) diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index cf56663b..8ceac8df 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -221,7 +221,7 @@ function pkgreq_close($id, $reason, $comments, $auto_close=false) { $dbh = DB::connect(); $id = intval($id); - $uid = uid_from_sid($_COOKIE["AURSID"]); + $uid = $auto_close ? 0 : uid_from_sid($_COOKIE["AURSID"]); if (!$auto_close && !has_credential(CRED_PKGREQ_CLOSE)) { return array(false, __("Only TUs and developers can close requests.")); From 9cab008e15aeb9327f319afee98479248b888a1d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 11 Jul 2016 17:44:19 +0200 Subject: [PATCH 0196/1891] Update the Git/SSH interface documentation Add information on the new set-keywords command and slightly reword some paragraphs. Signed-off-by: Lukas Fleischer --- doc/git-interface.txt | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/doc/git-interface.txt b/doc/git-interface.txt index 69c558b1..14ff0c5d 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -22,15 +22,15 @@ Authentication: git-auth Pushing to package repositories is possible via SSH. In order to access the SSH interface, users first need to add an SSH public key to their account using the web interface. Authentication is performed by the git-auth -AuthorizedKeysCommand script (see sshd_config(5) for details) that looks up the -public key in the AUR user table. Using this concept of "virtual users", there -is no need to create separate UNIX accounts for each registered AUR user. +AuthorizedKeysCommand script (see sshd_config(5) for details) which looks up +the public key in the AUR user table. Using this concept of "virtual users", +there is no need to create separate UNIX accounts for each registered AUR user. If the public key is found, the corresponding authorized_keys line is printed to stdout. If the public key does not exist, the login is denied. The authorized_keys line also contains a forced command such that authenticated users cannot access anything on the server except for the aurweb SSH interface. -The forced command can be configured in the aurweb configuration file and +The forced command can be configured in the aurweb configuration file and it usually points to the git-serve program. The INSTALL file in the top-level directory contains detailed instructions on @@ -43,17 +43,18 @@ The git-serve command, the "aurweb shell", provides different subcommands: * The help command shows a list of available commands. * The list-repos command lists all repositories of the authenticated user. +* The set-keywords command modifies the keywords assigned to a package base. * The setup-repo command can be used to create a new repository. * The restore command can be used to restore a deleted package base. * The git-{receive,upload}-pack commands are redirected to git-shell(1). -The requested command is extracted from the SSH_ORIGINAL_COMMAND environment -variable which is usually set by the SSH daemon. If no command is specified, -git-serve displays a message that aurweb does not provide an interactive shell. +The command is extracted from the SSH_ORIGINAL_COMMAND environment variable +which is usually set by the SSH daemon. If no command is specified, git-serve +displays a message stating that aurweb does not provide an interactive shell. When invoking git-shell(1), the git-serve command also redirects all paths to the shared Git repository and sets up the GIT_NAMESPACE environment variable -such that Git updates the right namespaced branch. +such that Git updates the correct namespaced branch. The Update Hook: git-update --------------------------- @@ -62,7 +63,7 @@ The Git update hook, called git-update, performs several subtasks: * Prevent from creating branches or tags other than master. * Deny non-fast-forwards, except for Trusted Users and Developers. -* Check each new commit (validate meta data, impose file size limits, ...) +* Verify each new commit (validate meta data, impose file size limits, ...) * Update package base information and package information in the database. * Update the named branch and the namespaced HEAD ref of the package. @@ -74,9 +75,8 @@ Accessing Git repositories via HTTP Git repositories can also be accessed via HTTP by configuring the web server to forward specific requests to git-http-backend(1). Note that, since Git -namespaces are used internally, the web server also needs to rewrite URIs and -setup the GIT_NAMESPACE environment variable accordingly before forwarding a -request. +namespaces are used internally, the web server needs to rewrite URIs and setup +the GIT_NAMESPACE environment variable accordingly before forwarding a request. An example configuration for nginx and fcgiwrap can be found in the INSTALL instructions in the top-level directory. @@ -86,10 +86,11 @@ Further Configuration When using Git namespaces, Git advertises refs outside the current namespace as so-called "have" lines. This is normally used to reduce traffic but it has the -opposite effect in the case of aurweb: Many essentially useless lines are -transferred to the Git client during `git push` operations. +opposite effect in the case of aurweb: Most of the refs transferred to the +client during `git push` operations belong to branches of other package bases +and are essentially useless. -In order to omit these advertisements, add the strings "^refs/", "!refs/" and -"!HEAD" to the transfer.hideRefs configuration setting. Note that the order of -these patterns is important ("^refs/" must come first) and that Git 2.7 or -newer is required for them to work. +In order to omit these advertisements, one can add the strings "^refs/", +"!refs/" and "!HEAD" to the transfer.hideRefs configuration setting. Note that +the order of these patterns is important ("^refs/" must come first) and that +Git 2.7 or newer is required for them to work. From 2160678f9bfb4ff5403086e202cc24e8e0d4cf69 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 15 Jul 2016 16:21:35 +0200 Subject: [PATCH 0197/1891] Remove wearout factor from translatable string Even though that number is hardcoded in the source code, it is better to make it not appear in the message catalog such that it can be made configurable easily later. Signed-off-by: Lukas Fleischer --- web/template/pkg_search_results.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index 3046c253..37a90328 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -35,7 +35,7 @@ if (!$result): ?>

    - + From e55b529813feb806fd139ccbf47be87970d95b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Wed, 20 Jul 2016 20:16:25 +0200 Subject: [PATCH 0198/1891] Make LangPreference DB field wide enough to fit es_419 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The language code for Latin American Spanish is es_419, which is longer than the 5 characters previously allowed. Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.3.0.txt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 1affc25e..99911298 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -31,7 +31,7 @@ CREATE TABLE Users ( Salt CHAR(32) NOT NULL DEFAULT '', ResetKey CHAR(32) NOT NULL DEFAULT '', RealName VARCHAR(64) NOT NULL DEFAULT '', - LangPreference VARCHAR(5) NOT NULL DEFAULT 'en', + LangPreference VARCHAR(6) NOT NULL DEFAULT 'en', Homepage TEXT NULL DEFAULT NULL, IRCNick VARCHAR(32) NOT NULL DEFAULT '', PGPKey VARCHAR(40) NULL DEFAULT NULL, diff --git a/upgrading/4.3.0.txt b/upgrading/4.3.0.txt index 6c1753de..78f94551 100644 --- a/upgrading/4.3.0.txt +++ b/upgrading/4.3.0.txt @@ -21,3 +21,9 @@ ALTER TABLE OfficialProviders ADD COLUMN Repo VARCHAR(64) NOT NULL; ---- ALTER TABLE Users ADD COLUMN Homepage TEXT NULL DEFAULT NULL; ---- + +5. Resize LangPreference to fit Latin American Spanish language code: + +-- +ALTER TABLE Users MODIFY LangPreference VARCHAR(6); +-- From b089747774b495126bf4e2b4ec0b63bd0c2af5c4 Mon Sep 17 00:00:00 2001 From: Safa AlFulaij Date: Thu, 14 Jul 2016 09:52:26 +0300 Subject: [PATCH 0199/1891] Fix plural string Even though the singular form never occurs, we need to use _n() here to obtain the correct behavior for languages with multiple plural forms. Signed-off-by: Safa AlFulaij Signed-off-by: Lukas Fleischer --- web/template/pkgreq_results.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index 24ee877a..b27963be 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -39,7 +39,7 @@ if (!$due) { $time_left = $idle_time - (time() - intval($row['RequestTS'])); if ($time_left > 48 * 3600) { - $time_left_fmt = __("~%d days left", round($time_left / (24 * 3600))); + $time_left_fmt = _n("~%d day left", "~%d days left", round($time_left / (24 * 3600))); } elseif ($time_left > 3600) { $time_left_fmt = _n("~%d hour left", "~%d hours left", round($time_left / 3600)); } else { From 573715afd9f7e56e34be07f983055f938351d990 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 1 Aug 2016 19:48:02 +0200 Subject: [PATCH 0200/1891] git-serve: Refactor environment variable access Read all environment variables at the beginning of the script and immediately pre-process their values. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 35c6b3a8..aa5f1c93 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -108,15 +108,12 @@ def pkgbase_set_keywords(pkgbase, keywords): db.close() -def check_permissions(pkgbase, user): +def pkgbase_has_write_access(pkgbase, user): db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, unix_socket=aur_db_socket, buffered=True) cur = db.cursor() - if os.environ.get('AUR_PRIVILEGED', '0') == '1': - return True - cur.execute("SELECT COUNT(*) FROM PackageBases " + "LEFT JOIN PackageComaintainers " + "ON PackageComaintainers.PackageBaseID = PackageBases.ID " + @@ -136,15 +133,18 @@ def die_with_help(msg): die(msg + "\nTry `{:s} help` for a list of commands.".format(ssh_cmdline)) -user = os.environ.get("AUR_USER") -cmd = os.environ.get("SSH_ORIGINAL_COMMAND") -if not cmd: +user = os.environ.get('AUR_USER') +privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1') +ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND') +ssh_client = os.environ.get('SSH_CLIENT') + +if not ssh_cmd: die_with_help("Interactive shell is disabled.") -cmdargv = shlex.split(cmd) +cmdargv = shlex.split(ssh_cmd) action = cmdargv[0] +remote_addr = ssh_client.split(' ')[0] if ssh_client else None if enable_maintenance: - remote_addr = os.environ["SSH_CLIENT"].split(" ")[0] if remote_addr not in maintenance_exc: die("The AUR is down due to maintenance. We will be back soon.") @@ -165,7 +165,7 @@ if action == 'git-upload-pack' or action == 'git-receive-pack': create_pkgbase(pkgbase, user) if action == 'git-receive-pack': - if not check_permissions(pkgbase, user): + if not privileged and not pkgbase_has_write_access(pkgbase, user): die('{:s}: permission denied: {:s}'.format(action, user)) os.environ["AUR_USER"] = user From 415a2c836df9094ddac555d5ed967ac11e48907e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 1 Aug 2016 20:14:25 +0200 Subject: [PATCH 0201/1891] git-update: Notify privileged users of forced uploads Show a warning when a Trusted User or a developer creates a package that is blacklisted or already provided by an official package. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 2c24e720..41b38a6c 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -202,6 +202,7 @@ repo = pygit2.Repository(repo_path) user = os.environ.get("AUR_USER") pkgbase = os.environ.get("AUR_PKGBASE") privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1') +warn_or_die = warn if privileged else die if len(sys.argv) == 2 and sys.argv[1] == "restore": if 'refs/heads/' + pkgbase not in repo.listall_references(): @@ -338,11 +339,11 @@ for pkgname in srcinfo.utils.get_package_names(metadata): pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) pkgname = pkginfo['pkgname'] - if pkgname in blacklist and not privileged: - die('package is blacklisted: {:s}'.format(pkgname)) - if pkgname in providers and not privileged: + if pkgname in blacklist: + warn_or_die('package is blacklisted: {:s}'.format(pkgname)) + if pkgname in providers: repo = providers[pkgname] - die('package already provided by [{:s}]: {:s}'.format(repo, pkgname)) + warn_or_die('package already provided by [{:s}]: {:s}'.format(repo, pkgname)) cur.execute("SELECT COUNT(*) FROM Packages WHERE Name = %s AND " + "PackageBaseID <> %s", [pkgname, pkgbase_id]) From 0c1187caa46ba2b5d159a88c9301356b56ef0637 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 24 Jul 2016 19:22:18 +0200 Subject: [PATCH 0202/1891] git-serve: Deprecate setup-repo Since 02dd9c5 (git-serve.py: Automatically create repositories, 2015-01-06), one can create new package bases by running `git push`. It is no longer necessary to run setup-repo manually. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index aa5f1c93..e0ebd0ec 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -133,6 +133,10 @@ def die_with_help(msg): die(msg + "\nTry `{:s} help` for a list of commands.".format(ssh_cmdline)) +def warn(msg): + sys.stderr.write("warning: {:s}\n".format(msg)) + + user = os.environ.get('AUR_USER') privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1') ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND') @@ -186,6 +190,7 @@ elif action == 'setup-repo': die_with_help("{:s}: missing repository name".format(action)) if len(cmdargv) > 2: die_with_help("{:s}: too many arguments".format(action)) + warn('{:s} is deprecated. Use `git push` to create new repositories.'.format(action)) create_pkgbase(cmdargv[1], user) elif action == 'restore': if len(cmdargv) < 2: From 12ab89b78c51fcd7b2b73049ac78922c9b238cc5 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 2 Aug 2016 20:07:36 +0200 Subject: [PATCH 0203/1891] Change default SSH options to "restrict" From the sshd(8) man page: Enable all restrictions, i.e. disable port, agent and X11 forwarding, as well as disabling PTY allocation and execution of ~/.ssh/rc. If any future restriction capabilities are added to authorized_keys files they will be included in this set. Signed-off-by: Lukas Fleischer --- conf/config.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.proto b/conf/config.proto index 64af774d..d5778a03 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -47,7 +47,7 @@ RSA = SHA256:Ju+yWiMb/2O+gKQ9RJCDqvRg7l+Q95KFAeqM5sr6l2s valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ git-serve-cmd = /srv/http/aurweb/git-interface/git-serve.py -ssh-options = no-port-forwarding,no-X11-forwarding,no-pty +ssh-options = restrict [serve] repo-path = /srv/http/aurweb/aur.git/ From 7a53ded5fea71cc89d0530d5c087e452e89c9d3f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 2 Aug 2016 00:47:17 +0200 Subject: [PATCH 0204/1891] git-update: Fix some issues reported by pyflakes Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 41b38a6c..5fc5562c 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -167,11 +167,13 @@ def save_metadata(metadata, db, cur, user): "PackageBaseID = %s AND UserID = %s", [pkgbase_id, user_id]) if cur.fetchone()[0] == 0: - cur.execute("INSERT INTO PackageNotifications (PackageBaseID, UserID) " + - "VALUES (%s, %s)", [pkgbase_id, user_id]) + cur.execute("INSERT INTO PackageNotifications " + + "(PackageBaseID, UserID) VALUES (%s, %s)", + [pkgbase_id, user_id]) db.commit() + def update_notify(db, cur, user, pkgbase_id): # Obtain the user ID of the new maintainer. cur.execute("SELECT ID FROM Users WHERE Username = %s", [user]) @@ -180,6 +182,7 @@ def update_notify(db, cur, user, pkgbase_id): # Execute the notification script. subprocess.Popen((notify_cmd, 'update', str(user_id), str(pkgbase_id))) + def die(msg): sys.stderr.write("error: {:s}\n".format(msg)) exit(1) From 87f5f1b407fee29412c761e6f1484f51fae86eda Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 2 Aug 2016 23:21:06 +0200 Subject: [PATCH 0205/1891] git-update: Use AUR_PRIVILEGED for forced pushes Instead of looking up the account type of the current user again, use the AUR_PRIVILEGED environment variable to check whether the user is allowed to perform non-fast-forward ref updates. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 5fc5562c..68f73873 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -226,14 +226,11 @@ db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, cur = db.cursor() # Detect and deny non-fast-forwards. -if sha1_old != "0000000000000000000000000000000000000000": +if sha1_old != "0000000000000000000000000000000000000000" and not privileged: walker = repo.walk(sha1_old, pygit2.GIT_SORT_TOPOLOGICAL) walker.hide(sha1_new) if next(walker, None) is not None: - cur.execute("SELECT AccountTypeID FROM Users WHERE UserName = %s ", - [user]) - if cur.fetchone()[0] == 1: - die("denying non-fast-forward (you should pull first)") + die("denying non-fast-forward (you should pull first)") # Prepare the walker that validates new commits. walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) From 2cd69bf66d244c7d438992aff1a03ea52cdba819 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 3 Aug 2016 01:59:37 +0200 Subject: [PATCH 0206/1891] git-update: Make maximum blob size configurable Support setting the maximum blob size in the configuration file. Signed-off-by: Lukas Fleischer --- conf/config.proto | 3 +++ git-interface/git-update.py | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index d5778a03..543c3ca1 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -56,6 +56,9 @@ git-shell-cmd = /usr/bin/git-shell git-update-cmd = /srv/http/aurweb/git-interface/git-update.py ssh-cmdline = ssh aur@aur.archlinux.org +[update] +max-blob-size = 256000 + [aurblup] db-path = /srv/http/aurweb/aurblup/ sync-dbs = core extra community multilib testing community-testing diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 68f73873..7aace9be 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -25,6 +25,19 @@ notify_cmd = config.get('notifications', 'notify-cmd') repo_path = config.get('serve', 'repo-path') repo_regex = config.get('serve', 'repo-regex') +max_blob_size = config.getint('update', 'max-blob-size') + + +def size_humanize(num): + for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB']: + if abs(num) < 2048.0: + if isinstance(num, int): + return "{}{}".format(num, unit) + else: + return "{:.2f}{}".format(num, unit) + num /= 1024.0 + return "{:.2f}{}".format(num, 'YiB') + def extract_arch_fields(pkginfo, field): values = [] @@ -254,8 +267,8 @@ for commit in walker: die_commit("not a blob object: {:s}".format(treeobj), str(commit.id)) - if blob.size > 250000: - die_commit("maximum blob size (250kB) exceeded", str(commit.id)) + if blob.size > max_blob_size: + die_commit("maximum blob size ({:s}) exceeded".format(size_humanize(max_blob_size)), str(commit.id)) metadata_raw = repo[commit.tree['.SRCINFO'].id].data.decode() (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) From 2915abb9d35308150ec107c5f4664e116daaf1de Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 3 Aug 2016 02:20:40 +0200 Subject: [PATCH 0207/1891] git-interface: Add database abstraction layer Add a new class that connects to the database specified in the configuration file and provides an interface to execute SQL queries. Prepared statements with qmark ("?") placeholders are supported. Replace all direct database accesses with calls to the new abstraction layer. Signed-off-by: Lukas Fleischer --- git-interface/db.py | 38 ++++++++++ git-interface/git-auth.py | 22 ++---- git-interface/git-serve.py | 90 +++++++++------------- git-interface/git-update.py | 144 +++++++++++++++++------------------- 4 files changed, 149 insertions(+), 145 deletions(-) create mode 100644 git-interface/db.py diff --git a/git-interface/db.py b/git-interface/db.py new file mode 100644 index 00000000..d3e1e697 --- /dev/null +++ b/git-interface/db.py @@ -0,0 +1,38 @@ +import configparser +import mysql.connector +import os + + +class Connection: + _conn = None + + def __init__(self): + config = configparser.RawConfigParser() + config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") + + aur_db_host = config.get('database', 'host') + aur_db_name = config.get('database', 'name') + aur_db_user = config.get('database', 'user') + aur_db_pass = config.get('database', 'password') + aur_db_socket = config.get('database', 'socket') + + self._conn = mysql.connector.connect(host=aur_db_host, + user=aur_db_user, + passwd=aur_db_pass, + db=aur_db_name, + unix_socket=aur_db_socket, + buffered=True) + + def execute(self, query, params=()): + query = query.replace('%', '%%').replace('?', '%s') + + cur = self._conn.cursor() + cur.execute(query, params) + + return cur + + def commit(self): + self._conn.commit() + + def close(self): + self._conn.close() diff --git a/git-interface/git-auth.py b/git-interface/git-auth.py index 83bd20c0..7cd033c2 100755 --- a/git-interface/git-auth.py +++ b/git-interface/git-auth.py @@ -1,12 +1,13 @@ #!/usr/bin/python3 import configparser -import mysql.connector import shlex import os import re import sys +import db + def format_command(env_vars, command, ssh_opts, ssh_key): environment = '' @@ -26,12 +27,6 @@ def format_command(env_vars, command, ssh_opts, ssh_key): config = configparser.RawConfigParser() config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') - valid_keytypes = config.get('auth', 'valid-keytypes').split() username_regex = config.get('auth', 'username-regex') git_serve_cmd = config.get('auth', 'git-serve-cmd') @@ -42,15 +37,12 @@ keytext = sys.argv[2] if keytype not in valid_keytypes: exit(1) -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) +conn = db.Connection() -cur = db.cursor() -cur.execute("SELECT Users.Username, Users.AccountTypeID FROM Users " + - "INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID " - "WHERE SSHPubKeys.PubKey = %s AND Users.Suspended = 0", - (keytype + " " + keytext,)) +cur = conn.execute("SELECT Users.Username, Users.AccountTypeID FROM Users " + + "INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID " + "WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0", + (keytype + " " + keytext,)) if cur.rowcount != 1: exit(1) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index e0ebd0ec..ab612f08 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -1,21 +1,16 @@ #!/usr/bin/python3 import configparser -import mysql.connector import os import re import shlex import sys +import db + config = configparser.RawConfigParser() config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') - repo_path = config.get('serve', 'repo-path') repo_regex = config.get('serve', 'repo-regex') git_shell_cmd = config.get('serve', 'git-shell-cmd') @@ -27,12 +22,8 @@ maintenance_exc = config.get('options', 'maintenance-exceptions').split() def pkgbase_from_name(pkgbase): - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket) - cur = db.cursor() - cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) - db.close() + conn = db.Connection() + cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase]) row = cur.fetchone() return row[0] if row else None @@ -43,21 +34,18 @@ def pkgbase_exists(pkgbase): def list_repos(user): - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket) - cur = db.cursor() + conn = db.Connection() - cur.execute("SELECT ID FROM Users WHERE Username = %s ", [user]) + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: die('{:s}: unknown user: {:s}'.format(action, user)) - cur.execute("SELECT Name, PackagerUID FROM PackageBases " + - "WHERE MaintainerUID = %s ", [userid]) + cur = conn.execute("SELECT Name, PackagerUID FROM PackageBases " + + "WHERE MaintainerUID = ?", [userid]) for row in cur: print((' ' if row[1] else '*') + row[0]) - db.close() + conn.close() def create_pkgbase(pkgbase, user): @@ -66,26 +54,25 @@ def create_pkgbase(pkgbase, user): if pkgbase_exists(pkgbase): die('{:s}: package base already exists: {:s}'.format(action, pkgbase)) - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket) - cur = db.cursor() + conn = db.Connection() - cur.execute("SELECT ID FROM Users WHERE Username = %s ", [user]) + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: die('{:s}: unknown user: {:s}'.format(action, user)) - cur.execute("INSERT INTO PackageBases (Name, SubmittedTS, ModifiedTS, " + - "SubmitterUID, MaintainerUID) VALUES (%s, UNIX_TIMESTAMP(), " + - "UNIX_TIMESTAMP(), %s, %s)", [pkgbase, userid, userid]) + cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " + + "ModifiedTS, SubmitterUID, MaintainerUID) VALUES " + + "(?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), ?, ?)", + [pkgbase, userid, userid]) pkgbase_id = cur.lastrowid - cur.execute("INSERT INTO PackageNotifications (PackageBaseID, UserID) " + - "VALUES (%s, %s)", [pkgbase_id, userid]) + cur = conn.execute("INSERT INTO PackageNotifications " + + "(PackageBaseID, UserID) VALUES (?, ?)", + [pkgbase_id, userid]) - db.commit() - db.close() + conn.commit() + conn.close() def pkgbase_set_keywords(pkgbase, keywords): @@ -93,34 +80,29 @@ def pkgbase_set_keywords(pkgbase, keywords): if not pkgbase_id: die('{:s}: package base not found: {:s}'.format(action, pkgbase)) - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket) - cur = db.cursor() + conn = db.Connection() - cur.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = %s", - [pkgbase_id]) + conn.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = ?", + [pkgbase_id]) for keyword in keywords: - cur.execute("INSERT INTO PackageKeywords (PackageBaseID, Keyword) " - "VALUES (%s, %s)", [pkgbase_id, keyword]) + conn.execute("INSERT INTO PackageKeywords (PackageBaseID, Keyword) " + + "VALUES (?, ?)", [pkgbase_id, keyword]) - db.commit() - db.close() + conn.commit() + conn.close() def pkgbase_has_write_access(pkgbase, user): - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) - cur = db.cursor() + conn = db.Connection() - cur.execute("SELECT COUNT(*) FROM PackageBases " + - "LEFT JOIN PackageComaintainers " + - "ON PackageComaintainers.PackageBaseID = PackageBases.ID " + - "INNER JOIN Users ON Users.ID = PackageBases.MaintainerUID " + - "OR PackageBases.MaintainerUID IS NULL " + - "OR Users.ID = PackageComaintainers.UsersID " + - "WHERE Name = %s AND Username = %s", [pkgbase, user]) + cur = conn.execute("SELECT COUNT(*) FROM PackageBases " + + "LEFT JOIN PackageComaintainers " + + "ON PackageComaintainers.PackageBaseID = PackageBases.ID " + + "INNER JOIN Users " + + "ON Users.ID = PackageBases.MaintainerUID " + + "OR PackageBases.MaintainerUID IS NULL " + + "OR Users.ID = PackageComaintainers.UsersID " + + "WHERE Name = ? AND Username = ?", [pkgbase, user]) return cur.fetchone()[0] > 0 diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 7aace9be..b7199e61 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -1,7 +1,6 @@ #!/usr/bin/python3 import configparser -import mysql.connector import os import pygit2 import re @@ -11,15 +10,11 @@ import sys import srcinfo.parse import srcinfo.utils +import db + config = configparser.RawConfigParser() config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') - notify_cmd = config.get('notifications', 'notify-cmd') repo_path = config.get('serve', 'repo-path') @@ -65,27 +60,27 @@ def parse_dep(depstring): return (depname, depcond) -def save_metadata(metadata, db, cur, user): +def save_metadata(metadata, conn, user): # Obtain package base ID and previous maintainer. pkgbase = metadata['pkgbase'] - cur.execute("SELECT ID, MaintainerUID FROM PackageBases " - "WHERE Name = %s", [pkgbase]) + cur = conn.execute("SELECT ID, MaintainerUID FROM PackageBases " + "WHERE Name = ?", [pkgbase]) (pkgbase_id, maintainer_uid) = cur.fetchone() was_orphan = not maintainer_uid # Obtain the user ID of the new maintainer. - cur.execute("SELECT ID FROM Users WHERE Username = %s", [user]) + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) user_id = int(cur.fetchone()[0]) # Update package base details and delete current packages. - cur.execute("UPDATE PackageBases SET ModifiedTS = UNIX_TIMESTAMP(), " + - "PackagerUID = %s, OutOfDateTS = NULL WHERE ID = %s", - [user_id, pkgbase_id]) - cur.execute("UPDATE PackageBases SET MaintainerUID = %s " + - "WHERE ID = %s AND MaintainerUID IS NULL", - [user_id, pkgbase_id]) - cur.execute("DELETE FROM Packages WHERE PackageBaseID = %s", - [pkgbase_id]) + conn.execute("UPDATE PackageBases SET ModifiedTS = UNIX_TIMESTAMP(), " + + "PackagerUID = ?, OutOfDateTS = NULL WHERE ID = ?", + [user_id, pkgbase_id]) + conn.execute("UPDATE PackageBases SET MaintainerUID = ? " + + "WHERE ID = ? AND MaintainerUID IS NULL", + [user_id, pkgbase_id]) + conn.execute("DELETE FROM Packages WHERE PackageBaseID = ?", + [pkgbase_id]) for pkgname in srcinfo.utils.get_package_names(metadata): pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) @@ -102,94 +97,94 @@ def save_metadata(metadata, db, cur, user): pkginfo[field] = None # Create a new package. - cur.execute("INSERT INTO Packages (PackageBaseID, Name, " + - "Version, Description, URL) " + - "VALUES (%s, %s, %s, %s, %s)", - [pkgbase_id, pkginfo['pkgname'], ver, - pkginfo['pkgdesc'], pkginfo['url']]) - db.commit() + cur = conn.execute("INSERT INTO Packages (PackageBaseID, Name, " + + "Version, Description, URL) " + + "VALUES (?, ?, ?, ?, ?)", + [pkgbase_id, pkginfo['pkgname'], ver, + pkginfo['pkgdesc'], pkginfo['url']]) + conn.commit() pkgid = cur.lastrowid # Add package sources. for source_info in extract_arch_fields(pkginfo, 'source'): - cur.execute("INSERT INTO PackageSources (PackageID, Source, " + - "SourceArch) VALUES (%s, %s, %s)", - [pkgid, source_info['value'], source_info['arch']]) + conn.execute("INSERT INTO PackageSources (PackageID, Source, " + + "SourceArch) VALUES (?, ?, ?)", + [pkgid, source_info['value'], source_info['arch']]) # Add package dependencies. for deptype in ('depends', 'makedepends', 'checkdepends', 'optdepends'): - cur.execute("SELECT ID FROM DependencyTypes WHERE Name = %s", - [deptype]) + cur = conn.execute("SELECT ID FROM DependencyTypes WHERE Name = ?", + [deptype]) deptypeid = cur.fetchone()[0] for dep_info in extract_arch_fields(pkginfo, deptype): depname, depcond = parse_dep(dep_info['value']) deparch = dep_info['arch'] - cur.execute("INSERT INTO PackageDepends (PackageID, " + - "DepTypeID, DepName, DepCondition, DepArch) " + - "VALUES (%s, %s, %s, %s, %s)", - [pkgid, deptypeid, depname, depcond, deparch]) + conn.execute("INSERT INTO PackageDepends (PackageID, " + + "DepTypeID, DepName, DepCondition, DepArch) " + + "VALUES (?, ?, ?, ?, ?)", + [pkgid, deptypeid, depname, depcond, deparch]) # Add package relations (conflicts, provides, replaces). for reltype in ('conflicts', 'provides', 'replaces'): - cur.execute("SELECT ID FROM RelationTypes WHERE Name = %s", - [reltype]) + cur = conn.execute("SELECT ID FROM RelationTypes WHERE Name = ?", + [reltype]) reltypeid = cur.fetchone()[0] for rel_info in extract_arch_fields(pkginfo, reltype): relname, relcond = parse_dep(rel_info['value']) relarch = rel_info['arch'] - cur.execute("INSERT INTO PackageRelations (PackageID, " + - "RelTypeID, RelName, RelCondition, RelArch) " + - "VALUES (%s, %s, %s, %s, %s)", - [pkgid, reltypeid, relname, relcond, relarch]) + conn.execute("INSERT INTO PackageRelations (PackageID, " + + "RelTypeID, RelName, RelCondition, RelArch) " + + "VALUES (?, ?, ?, ?, ?)", + [pkgid, reltypeid, relname, relcond, relarch]) # Add package licenses. if 'license' in pkginfo: for license in pkginfo['license']: - cur.execute("SELECT ID FROM Licenses WHERE Name = %s", - [license]) + cur = conn.execute("SELECT ID FROM Licenses WHERE Name = ?", + [license]) if cur.rowcount == 1: licenseid = cur.fetchone()[0] else: - cur.execute("INSERT INTO Licenses (Name) VALUES (%s)", - [license]) - db.commit() + cur = conn.execute("INSERT INTO Licenses (Name) " + + "VALUES (?)", [license]) + conn.commit() licenseid = cur.lastrowid - cur.execute("INSERT INTO PackageLicenses (PackageID, " + - "LicenseID) VALUES (%s, %s)", - [pkgid, licenseid]) + conn.execute("INSERT INTO PackageLicenses (PackageID, " + + "LicenseID) VALUES (?, ?)", + [pkgid, licenseid]) # Add package groups. if 'groups' in pkginfo: for group in pkginfo['groups']: - cur.execute("SELECT ID FROM Groups WHERE Name = %s", - [group]) + cur = conn.execute("SELECT ID FROM Groups WHERE Name = ?", + [group]) if cur.rowcount == 1: groupid = cur.fetchone()[0] else: - cur.execute("INSERT INTO Groups (Name) VALUES (%s)", - [group]) - db.commit() + cur = conn.execute("INSERT INTO Groups (Name) VALUES (?)", + [group]) + conn.commit() groupid = cur.lastrowid - cur.execute("INSERT INTO PackageGroups (PackageID, " - "GroupID) VALUES (%s, %s)", [pkgid, groupid]) + conn.execute("INSERT INTO PackageGroups (PackageID, " + "GroupID) VALUES (?, ?)", [pkgid, groupid]) # Add user to notification list on adoption. if was_orphan: - cur.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " + - "PackageBaseID = %s AND UserID = %s", - [pkgbase_id, user_id]) + cur = conn.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " + + "PackageBaseID = ? AND UserID = ?", + [pkgbase_id, user_id]) if cur.fetchone()[0] == 0: - cur.execute("INSERT INTO PackageNotifications " + - "(PackageBaseID, UserID) VALUES (%s, %s)", - [pkgbase_id, user_id]) + conn.execute("INSERT INTO PackageNotifications " + + "(PackageBaseID, UserID) VALUES (?, ?)", + [pkgbase_id, user_id]) - db.commit() + conn.commit() -def update_notify(db, cur, user, pkgbase_id): +def update_notify(conn, user, pkgbase_id): # Obtain the user ID of the new maintainer. - cur.execute("SELECT ID FROM Users WHERE Username = %s", [user]) + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) user_id = int(cur.fetchone()[0]) # Execute the notification script. @@ -233,10 +228,7 @@ else: if refname != "refs/heads/master": die("pushing to a branch other than master is restricted") -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) -cur = db.cursor() +conn = db.Connection() # Detect and deny non-fast-forwards. if sha1_old != "0000000000000000000000000000000000000000" and not privileged: @@ -339,13 +331,13 @@ if metadata_pkgbase != pkgbase: # Ensure that packages are neither blacklisted nor overwritten. pkgbase = metadata['pkgbase'] -cur.execute("SELECT ID FROM PackageBases WHERE Name = %s", [pkgbase]) +cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase]) pkgbase_id = cur.fetchone()[0] if cur.rowcount == 1 else 0 -cur.execute("SELECT Name FROM PackageBlacklist") +cur = conn.execute("SELECT Name FROM PackageBlacklist") blacklist = [row[0] for row in cur.fetchall()] -cur.execute("SELECT Name, Repo FROM OfficialProviders") +cur = conn.execute("SELECT Name, Repo FROM OfficialProviders") providers = dict(cur.fetchall()) for pkgname in srcinfo.utils.get_package_names(metadata): @@ -358,13 +350,13 @@ for pkgname in srcinfo.utils.get_package_names(metadata): repo = providers[pkgname] warn_or_die('package already provided by [{:s}]: {:s}'.format(repo, pkgname)) - cur.execute("SELECT COUNT(*) FROM Packages WHERE Name = %s AND " + - "PackageBaseID <> %s", [pkgname, pkgbase_id]) + cur = conn.execute("SELECT COUNT(*) FROM Packages WHERE Name = ? AND " + + "PackageBaseID <> ?", [pkgname, pkgbase_id]) if cur.fetchone()[0] > 0: die('cannot overwrite package: {:s}'.format(pkgname)) # Store package base details in the database. -save_metadata(metadata, db, cur, user) +save_metadata(metadata, conn, user) # Create (or update) a branch with the name of the package base for better # accessibility. @@ -377,7 +369,7 @@ repo.create_reference('refs/heads/' + pkgbase, sha1_new, True) repo.create_reference('refs/namespaces/' + pkgbase + '/HEAD', sha1_new, True) # Send package update notifications. -update_notify(db, cur, user, pkgbase_id) +update_notify(conn, user, pkgbase_id) # Close the database. -db.close() +conn.close() From 2f5f5583bec2a0a04424d6bedd763855f308bce6 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 3 Aug 2016 20:21:40 +0200 Subject: [PATCH 0208/1891] git-interface: Factor out configuration file parsing Add a new module that automatically locates the configuration file and provides methods to obtain the values of configuration options. Use the new module instead of ConfigParser everywhere. Signed-off-by: Lukas Fleischer --- git-interface/config.py | 27 +++++++++++++++++++++++++++ git-interface/db.py | 7 ++----- git-interface/git-auth.py | 6 +----- git-interface/git-serve.py | 5 +---- git-interface/git-update.py | 5 +---- 5 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 git-interface/config.py diff --git a/git-interface/config.py b/git-interface/config.py new file mode 100644 index 00000000..cd6495b3 --- /dev/null +++ b/git-interface/config.py @@ -0,0 +1,27 @@ +import configparser +import os + +_parser = None + + +def _get_parser(): + global _parser + + if not _parser: + _parser = configparser.RawConfigParser() + path = os.path.dirname(os.path.realpath(__file__)) + "/../conf/config" + _parser.read(path) + + return _parser + + +def get(section, option): + return _get_parser().get(section, option) + + +def getboolean(section, option): + return _get_parser().getboolean(section, option) + + +def getint(section, option): + return _get_parser().getint(section, option) diff --git a/git-interface/db.py b/git-interface/db.py index d3e1e697..c4c7d31c 100644 --- a/git-interface/db.py +++ b/git-interface/db.py @@ -1,15 +1,12 @@ -import configparser import mysql.connector -import os + +import config class Connection: _conn = None def __init__(self): - config = configparser.RawConfigParser() - config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") - aur_db_host = config.get('database', 'host') aur_db_name = config.get('database', 'name') aur_db_user = config.get('database', 'user') diff --git a/git-interface/git-auth.py b/git-interface/git-auth.py index 7cd033c2..ebdc75cc 100755 --- a/git-interface/git-auth.py +++ b/git-interface/git-auth.py @@ -1,11 +1,10 @@ #!/usr/bin/python3 -import configparser import shlex -import os import re import sys +import config import db @@ -24,9 +23,6 @@ def format_command(env_vars, command, ssh_opts, ssh_key): return msg -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") - valid_keytypes = config.get('auth', 'valid-keytypes').split() username_regex = config.get('auth', 'username-regex') git_serve_cmd = config.get('auth', 'git-serve-cmd') diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index ab612f08..6377ffce 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -1,16 +1,13 @@ #!/usr/bin/python3 -import configparser import os import re import shlex import sys +import config import db -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") - repo_path = config.get('serve', 'repo-path') repo_regex = config.get('serve', 'repo-regex') git_shell_cmd = config.get('serve', 'git-shell-cmd') diff --git a/git-interface/git-update.py b/git-interface/git-update.py index b7199e61..9a127a94 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -1,6 +1,5 @@ #!/usr/bin/python3 -import configparser import os import pygit2 import re @@ -10,11 +9,9 @@ import sys import srcinfo.parse import srcinfo.utils +import config import db -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") - notify_cmd = config.get('notifications', 'notify-cmd') repo_path = config.get('serve', 'repo-path') From ecbf32f0cc4673c56380a97a0097187924d47624 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 3 Aug 2016 20:25:29 +0200 Subject: [PATCH 0209/1891] git-interface: Add AUR_CONFIG environment variable Introduce a new environment variable that can be used to specify the path to an aurweb configuration file. If the environment variable is unset, the default search path is used. Signed-off-by: Lukas Fleischer --- git-interface/config.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/git-interface/config.py b/git-interface/config.py index cd6495b3..aac188b1 100644 --- a/git-interface/config.py +++ b/git-interface/config.py @@ -9,7 +9,11 @@ def _get_parser(): if not _parser: _parser = configparser.RawConfigParser() - path = os.path.dirname(os.path.realpath(__file__)) + "/../conf/config" + if 'AUR_CONFIG' in os.environ: + path = os.environ.get('AUR_CONFIG') + else: + relpath = "/../conf/config" + path = os.path.dirname(os.path.realpath(__file__)) + relpath _parser.read(path) return _parser From 27631f1157226bd9ca4d0dbfb6a59c7656e7e361 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 4 Aug 2016 21:00:50 +0200 Subject: [PATCH 0210/1891] git-interface: Do not use rowcount Avoid using Cursor.rowcount to obtain the number of rows returned by a SELECT statement as this is not guaranteed to be supported by every database engine. Signed-off-by: Lukas Fleischer --- git-interface/git-auth.py | 5 +++-- git-interface/git-update.py | 13 ++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/git-interface/git-auth.py b/git-interface/git-auth.py index ebdc75cc..45fd5772 100755 --- a/git-interface/git-auth.py +++ b/git-interface/git-auth.py @@ -40,10 +40,11 @@ cur = conn.execute("SELECT Users.Username, Users.AccountTypeID FROM Users " + "WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0", (keytype + " " + keytext,)) -if cur.rowcount != 1: +row = cur.fetchone() +if not row or cur.fetchone(): exit(1) -user, account_type = cur.fetchone() +user, account_type = row if not re.match(username_regex, user): exit(1) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 9a127a94..d6c9f101 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -140,8 +140,9 @@ def save_metadata(metadata, conn, user): for license in pkginfo['license']: cur = conn.execute("SELECT ID FROM Licenses WHERE Name = ?", [license]) - if cur.rowcount == 1: - licenseid = cur.fetchone()[0] + row = cur.fetchone() + if row: + licenseid = row[0] else: cur = conn.execute("INSERT INTO Licenses (Name) " + "VALUES (?)", [license]) @@ -156,8 +157,9 @@ def save_metadata(metadata, conn, user): for group in pkginfo['groups']: cur = conn.execute("SELECT ID FROM Groups WHERE Name = ?", [group]) - if cur.rowcount == 1: - groupid = cur.fetchone()[0] + row = cur.fetchone() + if row: + groupid = row[0] else: cur = conn.execute("INSERT INTO Groups (Name) VALUES (?)", [group]) @@ -329,7 +331,8 @@ if metadata_pkgbase != pkgbase: # Ensure that packages are neither blacklisted nor overwritten. pkgbase = metadata['pkgbase'] cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase]) -pkgbase_id = cur.fetchone()[0] if cur.rowcount == 1 else 0 +row = cur.fetchone() +pkgbase_id = row[0] if row else 0 cur = conn.execute("SELECT Name FROM PackageBlacklist") blacklist = [row[0] for row in cur.fetchall()] From f2a6bd207d5c3400e304c53f0b6eafb4bc5b7ece Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 5 Aug 2016 11:36:19 +0200 Subject: [PATCH 0211/1891] git-interface: Do not use UNIX_TIMESTAMP Avoid using UNIX_TIMESTAMP which is not part of the SQL standard. Retrieve the current UNIX time in Python and substitute it into the SQL queries instead. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 5 +++-- git-interface/git-update.py | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 6377ffce..d3a32c39 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -4,6 +4,7 @@ import os import re import shlex import sys +import time import config import db @@ -58,10 +59,10 @@ def create_pkgbase(pkgbase, user): if userid == 0: die('{:s}: unknown user: {:s}'.format(action, user)) + now = int(time.time()) cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " + "ModifiedTS, SubmitterUID, MaintainerUID) VALUES " + - "(?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), ?, ?)", - [pkgbase, userid, userid]) + "(?, ?, ?, ?, ?)", [pkgbase, now, now, userid, userid]) pkgbase_id = cur.lastrowid cur = conn.execute("INSERT INTO PackageNotifications " + diff --git a/git-interface/git-update.py b/git-interface/git-update.py index d6c9f101..28207203 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -5,6 +5,7 @@ import pygit2 import re import subprocess import sys +import time import srcinfo.parse import srcinfo.utils @@ -70,9 +71,10 @@ def save_metadata(metadata, conn, user): user_id = int(cur.fetchone()[0]) # Update package base details and delete current packages. - conn.execute("UPDATE PackageBases SET ModifiedTS = UNIX_TIMESTAMP(), " + + now = int(time.time()) + conn.execute("UPDATE PackageBases SET ModifiedTS = ?, " + "PackagerUID = ?, OutOfDateTS = NULL WHERE ID = ?", - [user_id, pkgbase_id]) + [now, user_id, pkgbase_id]) conn.execute("UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ? AND MaintainerUID IS NULL", [user_id, pkgbase_id]) From baf8a220ab923371cf19c742d2a7805e2276a037 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 3 Aug 2016 20:28:22 +0200 Subject: [PATCH 0212/1891] git-interface: Support SQLite as database backend In addition to MySQL, add support for SQLite to the database abstraction layer. Also, add a new configuration option to select the DBMS. Signed-off-by: Lukas Fleischer --- conf/config.proto | 2 +- git-interface/db.py | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index 543c3ca1..c56141c2 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -1,5 +1,5 @@ [database] -dsn_prefix = mysql +backend = mysql host = localhost socket = /var/run/mysqld/mysqld.sock name = AUR diff --git a/git-interface/db.py b/git-interface/db.py index c4c7d31c..060689b1 100644 --- a/git-interface/db.py +++ b/git-interface/db.py @@ -1,27 +1,43 @@ import mysql.connector +import sqlite3 import config class Connection: _conn = None + _paramstyle = None def __init__(self): - aur_db_host = config.get('database', 'host') - aur_db_name = config.get('database', 'name') - aur_db_user = config.get('database', 'user') - aur_db_pass = config.get('database', 'password') - aur_db_socket = config.get('database', 'socket') + aur_db_backend = config.get('database', 'backend') - self._conn = mysql.connector.connect(host=aur_db_host, - user=aur_db_user, - passwd=aur_db_pass, - db=aur_db_name, - unix_socket=aur_db_socket, - buffered=True) + if aur_db_backend == 'mysql': + aur_db_host = config.get('database', 'host') + aur_db_name = config.get('database', 'name') + aur_db_user = config.get('database', 'user') + aur_db_pass = config.get('database', 'password') + aur_db_socket = config.get('database', 'socket') + self._conn = mysql.connector.connect(host=aur_db_host, + user=aur_db_user, + passwd=aur_db_pass, + db=aur_db_name, + unix_socket=aur_db_socket, + buffered=True) + self._paramstyle = mysql.connector.paramstyle + elif aur_db_backend == 'sqlite': + aur_db_name = config.get('database', 'name') + self._conn = sqlite3.connect(aur_db_name) + self._paramstyle = sqlite3.paramstyle + else: + raise ValueError('unsupported database backend') def execute(self, query, params=()): - query = query.replace('%', '%%').replace('?', '%s') + if self._paramstyle == 'format': + query = query.replace('%', '%%').replace('?', '%s') + elif self._paramstyle == 'qmark': + pass + else: + raise ValueError('unsupported paramstyle') cur = self._conn.cursor() cur.execute(query, params) From 5014b74868138172090e7528f1b069642e15f295 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 3 Aug 2016 13:03:32 +0200 Subject: [PATCH 0213/1891] Cleanup database schema * Remove test accounts. * Create indices using CREATE INDEX. * Always use INTEGER UNSIGNED for IDs. * Always use BIGINT UNSIGNED for timestamps. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 67 +++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 99911298..030370b7 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -45,16 +45,9 @@ CREATE TABLE Users ( PRIMARY KEY (ID), UNIQUE (Username), UNIQUE (Email), - INDEX (AccountTypeID), FOREIGN KEY (AccountTypeID) REFERENCES AccountTypes(ID) ON DELETE NO ACTION ) ENGINE = InnoDB; --- A default developer account for testing purposes -INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd) VALUES ( - 1, 3, 'dev', 'dev@localhost', MD5('dev')); -INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd) VALUES ( - 2, 2, 'tu', 'tu@localhost', MD5('tu')); -INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd) VALUES ( - 3, 1, 'user', 'user@localhost', MD5('user')); +CREATE INDEX UsersAccountTypeID ON Users (AccountTypeID); -- SSH public keys used for the aurweb SSH/Git interface. @@ -96,16 +89,16 @@ CREATE TABLE PackageBases ( PackagerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- Last packager PRIMARY KEY (ID), UNIQUE (Name), - INDEX (NumVotes), - INDEX (SubmitterUID), - INDEX (MaintainerUID), - INDEX (PackagerUID), FOREIGN KEY (FlaggerUID) REFERENCES Users(ID) ON DELETE SET NULL, -- deleting a user will cause packages to be orphaned, not deleted FOREIGN KEY (SubmitterUID) REFERENCES Users(ID) ON DELETE SET NULL, FOREIGN KEY (MaintainerUID) REFERENCES Users(ID) ON DELETE SET NULL, FOREIGN KEY (PackagerUID) REFERENCES Users(ID) ON DELETE SET NULL ) ENGINE = InnoDB; +CREATE INDEX BasesNumVotes ON PackageBases (NumVotes); +CREATE INDEX BasesSubmitterUID ON PackageBases (SubmitterUID); +CREATE INDEX BasesMaintainerUID ON PackageBases (MaintainerUID); +CREATE INDEX BasesPackagerUID ON PackageBases (PackagerUID); -- Keywords of package bases @@ -196,11 +189,11 @@ CREATE TABLE PackageDepends ( DepName VARCHAR(255) NOT NULL, DepCondition VARCHAR(255), DepArch VARCHAR(255) NULL DEFAULT NULL, - INDEX (PackageID), - INDEX (DepName), FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE, FOREIGN KEY (DepTypeID) REFERENCES DependencyTypes(ID) ON DELETE NO ACTION ) ENGINE = InnoDB; +CREATE INDEX DependsPackageID ON PackageDepends (PackageID); +CREATE INDEX DependsDepName ON PackageDepends (DepName); -- Define the package relation types @@ -223,11 +216,11 @@ CREATE TABLE PackageRelations ( RelName VARCHAR(255) NOT NULL, RelCondition VARCHAR(255), RelArch VARCHAR(255) NULL DEFAULT NULL, - INDEX (PackageID), - INDEX (RelName), FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE, FOREIGN KEY (RelTypeID) REFERENCES RelationTypes(ID) ON DELETE NO ACTION ) ENGINE = InnoDB; +CREATE INDEX RelationsPackageID ON PackageRelations (PackageID); +CREATE INDEX RelationsRelName ON PackageRelations (RelName); -- Track which sources a package has @@ -236,9 +229,9 @@ CREATE TABLE PackageSources ( PackageID INTEGER UNSIGNED NOT NULL, Source VARCHAR(255) NOT NULL DEFAULT "/dev/null", SourceArch VARCHAR(255) NULL DEFAULT NULL, - INDEX (PackageID), FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE ) ENGINE = InnoDB; +CREATE INDEX SourcesPackageID ON PackageSources (PackageID); -- Track votes for packages @@ -247,12 +240,12 @@ CREATE TABLE PackageVotes ( UsersID INTEGER UNSIGNED NOT NULL, PackageBaseID INTEGER UNSIGNED NOT NULL, VoteTS BIGINT UNSIGNED NULL DEFAULT NULL, - INDEX (UsersID), - INDEX (PackageBaseID), FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE ) ENGINE = InnoDB; CREATE UNIQUE INDEX VoteUsersIDPackageID ON PackageVotes (UsersID, PackageBaseID); +CREATE INDEX VotesUsersID ON PackageVotes (UsersID); +CREATE INDEX VotesPackageBaseID ON PackageVotes (PackageBaseID); -- Record comments for packages -- @@ -268,13 +261,13 @@ CREATE TABLE PackageComments ( DelUsersID INTEGER UNSIGNED NULL DEFAULT NULL, PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (ID), - INDEX (UsersID), - INDEX (PackageBaseID), FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE SET NULL, FOREIGN KEY (EditedUsersID) REFERENCES Users(ID) ON DELETE SET NULL, FOREIGN KEY (DelUsersID) REFERENCES Users(ID) ON DELETE CASCADE, FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE ) ENGINE = InnoDB; +CREATE INDEX CommentsUsersID ON PackageComments (UsersID); +CREATE INDEX CommentsPackageBaseID ON PackageComments (PackageBaseID); -- Package base co-maintainers -- @@ -282,11 +275,11 @@ CREATE TABLE PackageComaintainers ( UsersID INTEGER UNSIGNED NOT NULL, PackageBaseID INTEGER UNSIGNED NOT NULL, Priority INTEGER UNSIGNED NOT NULL, - INDEX (UsersID), - INDEX (PackageBaseID), FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE ) ENGINE = InnoDB; +CREATE INDEX ComaintainersUsersID ON PackageComaintainers (UsersID); +CREATE INDEX ComaintainersPackageBaseID ON PackageComaintainers (PackageBaseID); -- Package base notifications -- @@ -343,27 +336,27 @@ CREATE TABLE PackageRequests ( RequestTS BIGINT UNSIGNED NOT NULL DEFAULT 0, Status TINYINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (ID), - INDEX (UsersID), - INDEX (PackageBaseID), FOREIGN KEY (ReqTypeID) REFERENCES RequestTypes(ID) ON DELETE NO ACTION, FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE SET NULL, FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE SET NULL ) ENGINE = InnoDB; +CREATE INDEX RequestsUsersID ON PackageRequests (UsersID); +CREATE INDEX RequestsPackageBaseID ON PackageRequests (PackageBaseID); -- Vote information -- CREATE TABLE IF NOT EXISTS TU_VoteInfo ( - ID int(10) unsigned NOT NULL auto_increment, - Agenda text NOT NULL, + ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + Agenda TEXT NOT NULL, User VARCHAR(32) NOT NULL, - Submitted bigint(20) unsigned NOT NULL, - End bigint(20) unsigned NOT NULL, - Quorum decimal(2, 2) unsigned NOT NULL, - SubmitterID int(10) unsigned NOT NULL, - Yes tinyint(3) unsigned NOT NULL default '0', - No tinyint(3) unsigned NOT NULL default '0', - Abstain tinyint(3) unsigned NOT NULL default '0', - ActiveTUs tinyint(3) unsigned NOT NULL default '0', + Submitted BIGINT UNSIGNED NOT NULL, + End BIGINT UNSIGNED NOT NULL, + Quorum DECIMAL(2, 2) UNSIGNED NOT NULL, + SubmitterID INTEGER UNSIGNED NOT NULL, + Yes TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + No TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + Abstain TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + ActiveTUs TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (ID), FOREIGN KEY (SubmitterID) REFERENCES Users(ID) ON DELETE CASCADE ) ENGINE = InnoDB; @@ -371,8 +364,8 @@ CREATE TABLE IF NOT EXISTS TU_VoteInfo ( -- Individual vote records -- CREATE TABLE IF NOT EXISTS TU_Votes ( - VoteID int(10) unsigned NOT NULL, - UserID int(10) unsigned NOT NULL, + VoteID INTEGER UNSIGNED NOT NULL, + UserID INTEGER UNSIGNED NOT NULL, FOREIGN KEY (VoteID) REFERENCES TU_VoteInfo(ID) ON DELETE CASCADE, FOREIGN KEY (UserID) REFERENCES Users(ID) ON DELETE CASCADE ) ENGINE = InnoDB; From 6e38309c194d860cccd26f901ee5687502331779 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 4 Aug 2016 20:36:31 +0200 Subject: [PATCH 0214/1891] git-interface: Add test suite and basic tests Add basic tests for the Git interface. The test suite is based on sharness. Signed-off-by: Lukas Fleischer --- git-interface/test/Makefile | 11 + git-interface/test/setup.sh | 121 ++++ git-interface/test/sharness.sh | 851 +++++++++++++++++++++++++++++ git-interface/test/t0001-auth.sh | 19 + git-interface/test/t0002-serve.sh | 26 + git-interface/test/t0003-update.sh | 20 + 6 files changed, 1048 insertions(+) create mode 100644 git-interface/test/Makefile create mode 100644 git-interface/test/setup.sh create mode 100644 git-interface/test/sharness.sh create mode 100755 git-interface/test/t0001-auth.sh create mode 100755 git-interface/test/t0002-serve.sh create mode 100755 git-interface/test/t0003-update.sh diff --git a/git-interface/test/Makefile b/git-interface/test/Makefile new file mode 100644 index 00000000..d6f0f740 --- /dev/null +++ b/git-interface/test/Makefile @@ -0,0 +1,11 @@ +T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) + +check: $(T) + +clean: + $(RM) -r test-results/ + +$(T): + @echo "*** $@ ***"; $(SHELL) $@ + +.PHONY: check clean $(T) diff --git a/git-interface/test/setup.sh b/git-interface/test/setup.sh new file mode 100644 index 00000000..eecb4d57 --- /dev/null +++ b/git-interface/test/setup.sh @@ -0,0 +1,121 @@ +TEST_DIRECTORY="$(pwd)" + +. ./sharness.sh + +# Configure paths to the Git interface scripts. +GIT_AUTH="$TEST_DIRECTORY/../git-auth.py" +GIT_SERVE="$TEST_DIRECTORY/../git-serve.py" +GIT_UPDATE="$TEST_DIRECTORY/../git-update.py" + +# Create the configuration file and a dummy notification script. +cat >config <<-EOF +[database] +backend = sqlite +name = aur.db + +[options] +enable-maintenance = 0 +maintenance-exceptions = 127.0.0.1 + +[notifications] +notify-cmd = ./notify.sh + +[auth] +valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 +username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ +git-serve-cmd = /srv/http/aurweb/git-interface/git-serve.py +ssh-options = restrict + +[serve] +repo-path = ./aur.git/ +repo-regex = [a-z0-9][a-z0-9.+_-]*$ +git-shell-cmd = /usr/bin/git-shell +git-update-cmd = /srv/http/aurweb/git-interface/git-update.py +ssh-cmdline = ssh aur@aur.archlinux.org + +[update] +max-blob-size = 256000 +EOF + +cat >notify.sh <<-EOF +#!/bin/sh +EOF +chmod +x notify.sh + +AUR_CONFIG=config +export AUR_CONFIG + +# Create SSH public keys which will be used by the test users later. +AUTH_KEYTYPE_USER=ssh-rsa +AUTH_KEYTEXT_USER=AAAAB3NzaC1yc2EAAAADAQABAAABAQCeUafDK4jqUiRHNQfwHcYjBKLZ4Rc1sNUofHApBP6j91nIvDHZe2VUqeBmFUhBz7kXK4VbXD9nlHMun2HeshL8hXnMzymZ8Wk7+IKefj61pajJkIdttw9Tnayfg7uhg5RbFy9zpEjmGjnIVjSzOXKCwppNT+CNujpKM5FD8gso/Z+l3fD+IwrPwS1SzF1Z99nqI9n2FM/JWZqluvTqnW9WdAvBDfutXxp0R5ZiLI5TAKL2Ssp5rpL70pkLXhv+9sK545zKKlXUFmw6Pi2iVBdqdRsk9ocl49dLiNIh8CYDCO3CRQn+8EnpBhTor2TKQxGJI3mzoBwWJJxoKhD/XlYJ +AUTH_FINGERPRINT_USER=SHA256:F/OFtYAy0JCytAGUi4RUZnOsThhQtFMK7fH1YvFBCpo + +AUTH_KEYTYPE_TU=ssh-rsa +AUTH_KEYTEXT_TU=AAAAB3NzaC1yc2EAAAADAQABAAABAQC4Q2Beg6jf2r1LZ4vwT5y10dK8+/c5RaNyTwv77wF2OSLXh32xW0ovhE2lW2gqoakdGsxgM2fTtqMTl29WOsAxlGF7x9XbWhFXFUT88Daq1fAeuihkiRjfBbInSW/WcrFZ+biLBch67addtfkkd4PmAafDeeCtszAXqza+ltBG1oxAGiTXgI3LOhA1/GtLLxsi5sPUO3ZlhvwDn4Sy0aXYx8l9hop/PU4Cjn82hyRa9r+SRxQ3KtjKxcVMnZ8IyXOrBwXTukgSBR/6nSdEmO0JPkYUFuNwh3UGFKuNkrPguL5T+4YDym6czYmZJzQ7NNl2pLKYmYgBwBe5rORlWfN5 +AUTH_FINGERPRINT_TU=SHA256:xQGC6j/U1Q3NDXLl04pm+Shr1mjYUXbGMUzlm9vby4k + +# Initialize the test database. +rm -f aur.db +sed \ + -e '/^DROP DATABASE /d' \ + -e '/^CREATE DATABASE /d' \ + -e '/^USE /d' \ + -e 's/ ENGINE = InnoDB//' \ + -e 's/ [A-Z]* UNSIGNED NOT NULL AUTO_INCREMENT/ INTEGER NOT NULL/' \ + -e 's/([0-9, ]*) UNSIGNED / UNSIGNED /' \ + "$TEST_DIRECTORY/../../schema/aur-schema.sql" | sqlite3 aur.db + +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 2);" | sqlite3 aur.db + +echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (1, '$AUTH_FINGERPRINT_USER', '$AUTH_KEYTYPE_USER $AUTH_KEYTEXT_USER');" | sqlite3 aur.db +echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FINGERPRINT_TU', '$AUTH_KEYTYPE_TU $AUTH_KEYTEXT_TU');" | sqlite3 aur.db + +# Initialize a Git repository to store test packages in. +( + GIT_AUTHOR_EMAIL=author@example.com + GIT_AUTHOR_NAME='A U Thor' + GIT_COMMITTER_EMAIL=committer@example.com + GIT_COMMITTER_NAME='C O Mitter' + export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME + export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME + + mkdir aur.git + cd aur.git + + git init -q + git checkout -q -b refs/namespaces/foobar/refs/heads/master + + cat >PKGBUILD <<-EOF + pkgname=foobar + pkgver=1 + pkgrel=1 + pkgdesc='aurweb test package.' + url='https://aur.archlinux.org/' + license=('GPL') + arch=('any') + depends=('python-pygit2') + source=() + md5sums=() + + package() { + echo 'Hello world!' + } + EOF + + cat >.SRCINFO <<-EOF + pkgbase = foobar + pkgdesc = aurweb test package. + pkgver = 1 + pkgrel = 1 + url = https://aur.archlinux.org/ + arch = any + license = GPL + depends = python-pygit2 + + pkgname = foobar + EOF + + git add PKGBUILD .SRCINFO + git commit -q -am 'Initial import' +) diff --git a/git-interface/test/sharness.sh b/git-interface/test/sharness.sh new file mode 100644 index 00000000..1d57ce9a --- /dev/null +++ b/git-interface/test/sharness.sh @@ -0,0 +1,851 @@ +#!/bin/sh +# +# Copyright (c) 2011-2012 Mathias Lafeldt +# Copyright (c) 2005-2012 Git project +# Copyright (c) 2005-2012 Junio C Hamano +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/ . + +# Public: Current version of Sharness. +SHARNESS_VERSION="1.0.0" +export SHARNESS_VERSION + +# Public: The file extension for tests. By default, it is set to "t". +: ${SHARNESS_TEST_EXTENSION:=t} +export SHARNESS_TEST_EXTENSION + +# Reset TERM to original terminal if found, otherwise save orignal TERM +[ "x" = "x$SHARNESS_ORIG_TERM" ] && + SHARNESS_ORIG_TERM="$TERM" || + TERM="$SHARNESS_ORIG_TERM" +# Public: The unsanitized TERM under which sharness is originally run +export SHARNESS_ORIG_TERM + +# Export SHELL_PATH +: ${SHELL_PATH:=$SHELL} +export SHELL_PATH + +# For repeatability, reset the environment to a known state. +# TERM is sanitized below, after saving color control sequences. +LANG=C +LC_ALL=C +PAGER=cat +TZ=UTC +EDITOR=: +export LANG LC_ALL PAGER TZ EDITOR +unset VISUAL CDPATH GREP_OPTIONS + +# Line feed +LF=' +' + +[ "x$TERM" != "xdumb" ] && ( + [ -t 1 ] && + tput bold >/dev/null 2>&1 && + tput setaf 1 >/dev/null 2>&1 && + tput sgr0 >/dev/null 2>&1 + ) && + color=t + +while test "$#" -ne 0; do + case "$1" in + -d|--d|--de|--deb|--debu|--debug) + debug=t; shift ;; + -i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate) + immediate=t; shift ;; + -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests) + TEST_LONG=t; export TEST_LONG; shift ;; + --in|--int|--inte|--inter|--intera|--interac|--interact|--interacti|--interactiv|--interactive|--interactive-|--interactive-t|--interactive-te|--interactive-tes|--interactive-test|--interactive-tests): + TEST_INTERACTIVE=t; export TEST_INTERACTIVE; verbose=t; shift ;; + -h|--h|--he|--hel|--help) + help=t; shift ;; + -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) + verbose=t; shift ;; + -q|--q|--qu|--qui|--quie|--quiet) + # Ignore --quiet under a TAP::Harness. Saying how many tests + # passed without the ok/not ok details is always an error. + test -z "$HARNESS_ACTIVE" && quiet=t; shift ;; + --chain-lint) + chain_lint=t; shift ;; + --no-chain-lint) + chain_lint=; shift ;; + --no-color) + color=; shift ;; + --root=*) + root=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; + *) + echo "error: unknown test option '$1'" >&2; exit 1 ;; + esac +done + +if test -n "$color"; then + # Save the color control sequences now rather than run tput + # each time say_color() is called. This is done for two + # reasons: + # * TERM will be changed to dumb + # * HOME will be changed to a temporary directory and tput + # might need to read ~/.terminfo from the original HOME + # directory to get the control sequences + # Note: This approach assumes the control sequences don't end + # in a newline for any terminal of interest (command + # substitutions strip trailing newlines). Given that most + # (all?) terminals in common use are related to ECMA-48, this + # shouldn't be a problem. + say_color_error=$(tput bold; tput setaf 1) # bold red + say_color_skip=$(tput setaf 4) # blue + say_color_warn=$(tput setaf 3) # brown/yellow + say_color_pass=$(tput setaf 2) # green + say_color_info=$(tput setaf 6) # cyan + say_color_reset=$(tput sgr0) + say_color_="" # no formatting for normal text + say_color() { + test -z "$1" && test -n "$quiet" && return + eval "say_color_color=\$say_color_$1" + shift + printf "%s\\n" "$say_color_color$*$say_color_reset" + } +else + say_color() { + test -z "$1" && test -n "$quiet" && return + shift + printf "%s\n" "$*" + } +fi + +TERM=dumb +export TERM + +error() { + say_color error "error: $*" + EXIT_OK=t + exit 1 +} + +say() { + say_color info "$*" +} + +test -n "$test_description" || error "Test script did not set test_description." + +if test "$help" = "t"; then + echo "$test_description" + exit 0 +fi + +exec 5>&1 +exec 6<&0 +if test "$verbose" = "t"; then + exec 4>&2 3>&1 +else + exec 4>/dev/null 3>/dev/null +fi + +test_failure=0 +test_count=0 +test_fixed=0 +test_broken=0 +test_success=0 + +die() { + code=$? + if test -n "$EXIT_OK"; then + exit $code + else + echo >&5 "FATAL: Unexpected exit with code $code" + exit 1 + fi +} + +EXIT_OK= +trap 'die' EXIT + +# Public: Define that a test prerequisite is available. +# +# The prerequisite can later be checked explicitly using test_have_prereq or +# implicitly by specifying the prerequisite name in calls to test_expect_success +# or test_expect_failure. +# +# $1 - Name of prerequiste (a simple word, in all capital letters by convention) +# +# Examples +# +# # Set PYTHON prerequisite if interpreter is available. +# command -v python >/dev/null && test_set_prereq PYTHON +# +# # Set prerequisite depending on some variable. +# test -z "$NO_GETTEXT" && test_set_prereq GETTEXT +# +# Returns nothing. +test_set_prereq() { + satisfied_prereq="$satisfied_prereq$1 " +} +satisfied_prereq=" " + +# Public: Check if one or more test prerequisites are defined. +# +# The prerequisites must have previously been set with test_set_prereq. +# The most common use of this is to skip all the tests if some essential +# prerequisite is missing. +# +# $1 - Comma-separated list of test prerequisites. +# +# Examples +# +# # Skip all remaining tests if prerequisite is not set. +# if ! test_have_prereq PERL; then +# skip_all='skipping perl interface tests, perl not available' +# test_done +# fi +# +# Returns 0 if all prerequisites are defined or 1 otherwise. +test_have_prereq() { + # prerequisites can be concatenated with ',' + save_IFS=$IFS + IFS=, + set -- $* + IFS=$save_IFS + + total_prereq=0 + ok_prereq=0 + missing_prereq= + + for prerequisite; do + case "$prerequisite" in + !*) + negative_prereq=t + prerequisite=${prerequisite#!} + ;; + *) + negative_prereq= + esac + + total_prereq=$(($total_prereq + 1)) + case "$satisfied_prereq" in + *" $prerequisite "*) + satisfied_this_prereq=t + ;; + *) + satisfied_this_prereq= + esac + + case "$satisfied_this_prereq,$negative_prereq" in + t,|,t) + ok_prereq=$(($ok_prereq + 1)) + ;; + *) + # Keep a list of missing prerequisites; restore + # the negative marker if necessary. + prerequisite=${negative_prereq:+!}$prerequisite + if test -z "$missing_prereq"; then + missing_prereq=$prerequisite + else + missing_prereq="$prerequisite,$missing_prereq" + fi + esac + done + + test $total_prereq = $ok_prereq +} + +# You are not expected to call test_ok_ and test_failure_ directly, use +# the text_expect_* functions instead. + +test_ok_() { + test_success=$(($test_success + 1)) + say_color "" "ok $test_count - $@" +} + +test_failure_() { + test_failure=$(($test_failure + 1)) + say_color error "not ok $test_count - $1" + shift + echo "$@" | sed -e 's/^/# /' + test "$immediate" = "" || { EXIT_OK=t; exit 1; } +} + +test_known_broken_ok_() { + test_fixed=$(($test_fixed + 1)) + say_color error "ok $test_count - $@ # TODO known breakage vanished" +} + +test_known_broken_failure_() { + test_broken=$(($test_broken + 1)) + say_color warn "not ok $test_count - $@ # TODO known breakage" +} + +# Public: Execute commands in debug mode. +# +# Takes a single argument and evaluates it only when the test script is started +# with --debug. This is primarily meant for use during the development of test +# scripts. +# +# $1 - Commands to be executed. +# +# Examples +# +# test_debug "cat some_log_file" +# +# Returns the exit code of the last command executed in debug mode or 0 +# otherwise. +test_debug() { + test "$debug" = "" || eval "$1" +} + +# Public: Stop execution and start a shell. +# +# This is useful for debugging tests and only makes sense together with "-v". +# Be sure to remove all invocations of this command before submitting. +test_pause() { + if test "$verbose" = t; then + "$SHELL_PATH" <&6 >&3 2>&4 + else + error >&5 "test_pause requires --verbose" + fi +} + +test_eval_() { + # This is a separate function because some tests use + # "return" to end a test_expect_success block early. + case ",$test_prereq," in + *,INTERACTIVE,*) + eval "$*" + ;; + *) + eval &3 2>&4 "$*" + ;; + esac +} + +test_run_() { + test_cleanup=: + expecting_failure=$2 + test_eval_ "$1" + eval_ret=$? + + if test "$chain_lint" = "t"; then + test_eval_ "(exit 117) && $1" + if test "$?" != 117; then + error "bug in the test script: broken &&-chain: $1" + fi + fi + + if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then + test_eval_ "$test_cleanup" + fi + if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then + echo "" + fi + return "$eval_ret" +} + +test_skip_() { + test_count=$(($test_count + 1)) + to_skip= + for skp in $SKIP_TESTS; do + case $this_test.$test_count in + $skp) + to_skip=t + break + esac + done + if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq"; then + to_skip=t + fi + case "$to_skip" in + t) + of_prereq= + if test "$missing_prereq" != "$test_prereq"; then + of_prereq=" of $test_prereq" + fi + + say_color skip >&3 "skipping test: $@" + say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" + : true + ;; + *) + false + ;; + esac +} + +# Public: Run test commands and expect them to succeed. +# +# When the test passed, an "ok" message is printed and the number of successful +# tests is incremented. When it failed, a "not ok" message is printed and the +# number of failed tests is incremented. +# +# With --immediate, exit test immediately upon the first failed test. +# +# Usually takes two arguments: +# $1 - Test description +# $2 - Commands to be executed. +# +# With three arguments, the first will be taken to be a prerequisite: +# $1 - Comma-separated list of test prerequisites. The test will be skipped if +# not all of the given prerequisites are set. To negate a prerequisite, +# put a "!" in front of it. +# $2 - Test description +# $3 - Commands to be executed. +# +# Examples +# +# test_expect_success \ +# 'git-write-tree should be able to write an empty tree.' \ +# 'tree=$(git-write-tree)' +# +# # Test depending on one prerequisite. +# test_expect_success TTY 'git --paginate rev-list uses a pager' \ +# ' ... ' +# +# # Multiple prerequisites are separated by a comma. +# test_expect_success PERL,PYTHON 'yo dawg' \ +# ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" ' +# +# Returns nothing. +test_expect_success() { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_success" + export test_prereq + if ! test_skip_ "$@"; then + say >&3 "expecting success: $2" + if test_run_ "$2"; then + test_ok_ "$1" + else + test_failure_ "$@" + fi + fi + echo >&3 "" +} + +# Public: Run test commands and expect them to fail. Used to demonstrate a known +# breakage. +# +# This is NOT the opposite of test_expect_success, but rather used to mark a +# test that demonstrates a known breakage. +# +# When the test passed, an "ok" message is printed and the number of fixed tests +# is incremented. When it failed, a "not ok" message is printed and the number +# of tests still broken is incremented. +# +# Failures from these tests won't cause --immediate to stop. +# +# Usually takes two arguments: +# $1 - Test description +# $2 - Commands to be executed. +# +# With three arguments, the first will be taken to be a prerequisite: +# $1 - Comma-separated list of test prerequisites. The test will be skipped if +# not all of the given prerequisites are set. To negate a prerequisite, +# put a "!" in front of it. +# $2 - Test description +# $3 - Commands to be executed. +# +# Returns nothing. +test_expect_failure() { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_failure" + export test_prereq + if ! test_skip_ "$@"; then + say >&3 "checking known breakage: $2" + if test_run_ "$2" expecting_failure; then + test_known_broken_ok_ "$1" + else + test_known_broken_failure_ "$1" + fi + fi + echo >&3 "" +} + +# Public: Run command and ensure that it fails in a controlled way. +# +# Use it instead of "! ". For example, when dies due to a +# segfault, test_must_fail diagnoses it as an error, while "! " would +# mistakenly be treated as just another expected failure. +# +# This is one of the prefix functions to be used inside test_expect_success or +# test_expect_failure. +# +# $1.. - Command to be executed. +# +# Examples +# +# test_expect_success 'complain and die' ' +# do something && +# do something else && +# test_must_fail git checkout ../outerspace +# ' +# +# Returns 1 if the command succeeded (exit code 0). +# Returns 1 if the command died by signal (exit codes 130-192) +# Returns 1 if the command could not be found (exit code 127). +# Returns 0 otherwise. +test_must_fail() { + "$@" + exit_code=$? + if test $exit_code = 0; then + echo >&2 "test_must_fail: command succeeded: $*" + return 1 + elif test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_must_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_must_fail: command not found: $*" + return 1 + fi + return 0 +} + +# Public: Run command and ensure that it succeeds or fails in a controlled way. +# +# Similar to test_must_fail, but tolerates success too. Use it instead of +# " || :" to catch failures caused by a segfault, for instance. +# +# This is one of the prefix functions to be used inside test_expect_success or +# test_expect_failure. +# +# $1.. - Command to be executed. +# +# Examples +# +# test_expect_success 'some command works without configuration' ' +# test_might_fail git config --unset all.configuration && +# do something +# ' +# +# Returns 1 if the command died by signal (exit codes 130-192) +# Returns 1 if the command could not be found (exit code 127). +# Returns 0 otherwise. +test_might_fail() { + "$@" + exit_code=$? + if test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_might_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_might_fail: command not found: $*" + return 1 + fi + return 0 +} + +# Public: Run command and ensure it exits with a given exit code. +# +# This is one of the prefix functions to be used inside test_expect_success or +# test_expect_failure. +# +# $1 - Expected exit code. +# $2.. - Command to be executed. +# +# Examples +# +# test_expect_success 'Merge with d/f conflicts' ' +# test_expect_code 1 git merge "merge msg" B master +# ' +# +# Returns 0 if the expected exit code is returned or 1 otherwise. +test_expect_code() { + want_code=$1 + shift + "$@" + exit_code=$? + if test $exit_code = $want_code; then + return 0 + fi + + echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" + return 1 +} + +# Public: Compare two files to see if expected output matches actual output. +# +# The TEST_CMP variable defines the command used for the comparision; it +# defaults to "diff -u". Only when the test script was started with --verbose, +# will the command's output, the diff, be printed to the standard output. +# +# This is one of the prefix functions to be used inside test_expect_success or +# test_expect_failure. +# +# $1 - Path to file with expected output. +# $2 - Path to file with actual output. +# +# Examples +# +# test_expect_success 'foo works' ' +# echo expected >expected && +# foo >actual && +# test_cmp expected actual +# ' +# +# Returns the exit code of the command set by TEST_CMP. +test_cmp() { + ${TEST_CMP:-diff -u} "$@" +} + +# Public: portably print a sequence of numbers. +# +# seq is not in POSIX and GNU seq might not be available everywhere, +# so it is nice to have a seq implementation, even a very simple one. +# +# $1 - Starting number. +# $2 - Ending number. +# +# Examples +# +# test_expect_success 'foo works 10 times' ' +# for i in $(test_seq 1 10) +# do +# foo || return +# done +# ' +# +# Returns 0 if all the specified numbers can be displayed. +test_seq() { + i="$1" + j="$2" + while test "$i" -le "$j" + do + echo "$i" || return + i=$(expr "$i" + 1) + done +} + +# Public: Check if the file expected to be empty is indeed empty, and barfs +# otherwise. +# +# $1 - File to check for emptyness. +# +# Returns 0 if file is empty, 1 otherwise. +test_must_be_empty() { + if test -s "$1" + then + echo "'$1' is not empty, it contains:" + cat "$1" + return 1 + fi +} + +# Public: Schedule cleanup commands to be run unconditionally at the end of a +# test. +# +# If some cleanup command fails, the test will not pass. With --immediate, no +# cleanup is done to help diagnose what went wrong. +# +# This is one of the prefix functions to be used inside test_expect_success or +# test_expect_failure. +# +# $1.. - Commands to prepend to the list of cleanup commands. +# +# Examples +# +# test_expect_success 'test core.capslock' ' +# git config core.capslock true && +# test_when_finished "git config --unset core.capslock" && +# do_something +# ' +# +# Returns the exit code of the last cleanup command executed. +test_when_finished() { + test_cleanup="{ $* + } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" +} + +# Public: Schedule cleanup commands to be run unconditionally when all tests +# have run. +# +# This can be used to clean up things like test databases. It is not needed to +# clean up temporary files, as test_done already does that. +# +# Examples: +# +# cleanup mysql -e "DROP DATABASE mytest" +# +# Returns the exit code of the last cleanup command executed. +final_cleanup= +cleanup() { + final_cleanup="{ $* + } && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup" +} + +# Public: Summarize test results and exit with an appropriate error code. +# +# Must be called at the end of each test script. +# +# Can also be used to stop tests early and skip all remaining tests. For this, +# set skip_all to a string explaining why the tests were skipped before calling +# test_done. +# +# Examples +# +# # Each test script must call test_done at the end. +# test_done +# +# # Skip all remaining tests if prerequisite is not set. +# if ! test_have_prereq PERL; then +# skip_all='skipping perl interface tests, perl not available' +# test_done +# fi +# +# Returns 0 if all tests passed or 1 if there was a failure. +test_done() { + EXIT_OK=t + + if test -z "$HARNESS_ACTIVE"; then + test_results_dir="$SHARNESS_TEST_DIRECTORY/test-results" + mkdir -p "$test_results_dir" + test_results_path="$test_results_dir/$this_test.$$.counts" + + cat >>"$test_results_path" <<-EOF + total $test_count + success $test_success + fixed $test_fixed + broken $test_broken + failed $test_failure + + EOF + fi + + if test "$test_fixed" != 0; then + say_color error "# $test_fixed known breakage(s) vanished; please update test(s)" + fi + if test "$test_broken" != 0; then + say_color warn "# still have $test_broken known breakage(s)" + fi + if test "$test_broken" != 0 || test "$test_fixed" != 0; then + test_remaining=$(( $test_count - $test_broken - $test_fixed )) + msg="remaining $test_remaining test(s)" + else + test_remaining=$test_count + msg="$test_count test(s)" + fi + + case "$test_failure" in + 0) + # Maybe print SKIP message + if test -n "$skip_all" && test $test_count -gt 0; then + error "Can't use skip_all after running some tests" + fi + [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all" + + if test $test_remaining -gt 0; then + say_color pass "# passed all $msg" + fi + say "1..$test_count$skip_all" + + test_eval_ "$final_cleanup" + + test -d "$remove_trash" && + cd "$(dirname "$remove_trash")" && + rm -rf "$(basename "$remove_trash")" + + exit 0 ;; + + *) + say_color error "# failed $test_failure among $msg" + say "1..$test_count" + + exit 1 ;; + + esac +} + +# Public: Root directory containing tests. Tests can override this variable, +# e.g. for testing Sharness itself. +: ${SHARNESS_TEST_DIRECTORY:=$(pwd)} +export SHARNESS_TEST_DIRECTORY + +# Public: Source directory of test code and sharness library. +# This directory may be different from the directory in which tests are +# being run. +: ${SHARNESS_TEST_SRCDIR:=$(cd $(dirname $0) && pwd)} +export SHARNESS_TEST_SRCDIR + +# Public: Build directory that will be added to PATH. By default, it is set to +# the parent directory of SHARNESS_TEST_DIRECTORY. +: ${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."} +PATH="$SHARNESS_BUILD_DIRECTORY:$PATH" +export PATH SHARNESS_BUILD_DIRECTORY + +# Public: Path to test script currently executed. +SHARNESS_TEST_FILE="$0" +export SHARNESS_TEST_FILE + +# Prepare test area. +SHARNESS_TRASH_DIRECTORY="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")" +test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY" +case "$SHARNESS_TRASH_DIRECTORY" in +/*) ;; # absolute path is good + *) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$SHARNESS_TRASH_DIRECTORY" ;; +esac +test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY" +rm -rf "$SHARNESS_TRASH_DIRECTORY" || { + EXIT_OK=t + echo >&5 "FATAL: Cannot prepare test area" + exit 1 +} + + +# +# Load any extensions in $srcdir/sharness.d/*.sh +# +if test -d "${SHARNESS_TEST_SRCDIR}/sharness.d" +then + for file in "${SHARNESS_TEST_SRCDIR}"/sharness.d/*.sh + do + # Ensure glob was not an empty match: + test -e "${file}" || break + + if test -n "$debug" + then + echo >&5 "sharness: loading extensions from ${file}" + fi + . "${file}" + if test $? != 0 + then + echo >&5 "sharness: Error loading ${file}. Aborting." + exit 1 + fi + done +fi + +# Public: Empty trash directory, the test area, provided for each test. The HOME +# variable is set to that directory too. +export SHARNESS_TRASH_DIRECTORY + +HOME="$SHARNESS_TRASH_DIRECTORY" +export HOME + +mkdir -p "$SHARNESS_TRASH_DIRECTORY" || exit 1 +# Use -P to resolve symlinks in our working directory so that the cwd +# in subprocesses like git equals our $PWD (for pathname comparisons). +cd -P "$SHARNESS_TRASH_DIRECTORY" || exit 1 + +this_test=${SHARNESS_TEST_FILE##*/} +this_test=${this_test%.$SHARNESS_TEST_EXTENSION} +for skp in $SKIP_TESTS; do + case "$this_test" in + $skp) + say_color info >&3 "skipping test $this_test altogether" + skip_all="skip all tests in $this_test" + test_done + esac +done + +test -n "$TEST_LONG" && test_set_prereq EXPENSIVE +test -n "$TEST_INTERACTIVE" && test_set_prereq INTERACTIVE + +# Make sure this script ends with code 0 +: + +# vi: set ts=4 sw=4 noet : diff --git a/git-interface/test/t0001-auth.sh b/git-interface/test/t0001-auth.sh new file mode 100755 index 00000000..50ef510f --- /dev/null +++ b/git-interface/test/t0001-auth.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='git-auth tests' + +. ./setup.sh + +test_expect_success 'Test basic authentication.' ' + "$GIT_AUTH" "$AUTH_KEYTYPE_USER" "$AUTH_KEYTEXT_USER" >out && + grep -q AUR_USER=user out && + grep -q AUR_PRIVILEGED=0 out +' + +test_expect_success 'Test Trusted User authentication.' ' + "$GIT_AUTH" "$AUTH_KEYTYPE_TU" "$AUTH_KEYTEXT_TU" >out && + grep -q AUR_USER=tu out && + grep -q AUR_PRIVILEGED=1 out +' + +test_done diff --git a/git-interface/test/t0002-serve.sh b/git-interface/test/t0002-serve.sh new file mode 100755 index 00000000..7e17bcbc --- /dev/null +++ b/git-interface/test/t0002-serve.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_description='git-serve tests' + +. ./setup.sh + +test_expect_success 'Test interactive shell.' ' + "$GIT_SERVE" 2>&1 | grep -q "Interactive shell is disabled." +' + +test_expect_success 'Test help.' ' + SSH_ORIGINAL_COMMAND=help "$GIT_SERVE" 2>&1 | grep -q "^Commands:$" +' + +test_expect_success 'Test setup-repo and list-repos.' ' + SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + *foobar + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_done diff --git a/git-interface/test/t0003-update.sh b/git-interface/test/t0003-update.sh new file mode 100755 index 00000000..0e8962c1 --- /dev/null +++ b/git-interface/test/t0003-update.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +test_description='git-update tests' + +. ./setup.sh + +test_expect_success 'Test update hook.' ' + old=0000000000000000000000000000000000000000 && + new=$(git -C aur.git rev-parse HEAD) && + SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user "$GIT_SERVE" && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && + cat >expected <<-EOF && + 1|1|foobar|1-1|aurweb test package.|https://aur.archlinux.org/ + EOF + echo "SELECT * FROM Packages;" | sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_done From 3a41f8d56495e469396455b7d95e94e21e26f9b0 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 5 Aug 2016 14:01:06 +0200 Subject: [PATCH 0215/1891] git-update: Remove package details before updating Explicitly remove all package sources, dependencies, relations, licenses and groups before inserting new ones. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 28207203..e6f6410a 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -78,8 +78,13 @@ def save_metadata(metadata, conn, user): conn.execute("UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ? AND MaintainerUID IS NULL", [user_id, pkgbase_id]) - conn.execute("DELETE FROM Packages WHERE PackageBaseID = ?", - [pkgbase_id]) + for table in ('Sources', 'Depends', 'Relations', 'Licenses', 'Groups'): + conn.execute("DELETE FROM Package" + table + " WHERE EXISTS (" + + "SELECT * FROM Packages " + + "WHERE Packages.PackageBaseID = ? AND " + + "Package" + table + ".PackageID = Packages.ID)", + [pkgbase_id]) + conn.execute("DELETE FROM Packages WHERE PackageBaseID = ?", [pkgbase_id]) for pkgname in srcinfo.utils.get_package_names(metadata): pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) From 008eace8dbeb0343ae3908cb8373d669efcb8e63 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 5 Aug 2016 21:00:02 +0200 Subject: [PATCH 0216/1891] t0001: Add more git-auth tests Test the authentication script with an invalid key type and with a key that does not exist in the database. Signed-off-by: Lukas Fleischer --- git-interface/test/setup.sh | 4 ++++ git-interface/test/t0001-auth.sh | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/git-interface/test/setup.sh b/git-interface/test/setup.sh index eecb4d57..45129782 100644 --- a/git-interface/test/setup.sh +++ b/git-interface/test/setup.sh @@ -54,6 +54,10 @@ AUTH_KEYTYPE_TU=ssh-rsa AUTH_KEYTEXT_TU=AAAAB3NzaC1yc2EAAAADAQABAAABAQC4Q2Beg6jf2r1LZ4vwT5y10dK8+/c5RaNyTwv77wF2OSLXh32xW0ovhE2lW2gqoakdGsxgM2fTtqMTl29WOsAxlGF7x9XbWhFXFUT88Daq1fAeuihkiRjfBbInSW/WcrFZ+biLBch67addtfkkd4PmAafDeeCtszAXqza+ltBG1oxAGiTXgI3LOhA1/GtLLxsi5sPUO3ZlhvwDn4Sy0aXYx8l9hop/PU4Cjn82hyRa9r+SRxQ3KtjKxcVMnZ8IyXOrBwXTukgSBR/6nSdEmO0JPkYUFuNwh3UGFKuNkrPguL5T+4YDym6czYmZJzQ7NNl2pLKYmYgBwBe5rORlWfN5 AUTH_FINGERPRINT_TU=SHA256:xQGC6j/U1Q3NDXLl04pm+Shr1mjYUXbGMUzlm9vby4k +AUTH_KEYTYPE_MISSING=sha-rsa +AUTH_KEYTEXT_MISSING=AAAAB3NzaC1yc2EAAAADAQABAAABAQC9UTpssBunuTBCT3KFtv+yb+cN0VmI2C9O9U7wHlkEZWxNBK8is6tnDHXBxRuvRk0LHILkTidLLFX22ZF0+TFgSz7uuEvGZVNpa2Fn2+vKJJYMvZEvb/f8VHF5/Jddt21VOyu23royTN/duiT7WIZdCtEmq5C9Y43NPfsB8FbUc+FVSYT2Lq7g1/bzvFF+CZxwCrGjC3qC7p3pshICfFR8bbWgRN33ClxIQ7MvkcDtfNu38dLotJqdfEa7NdQgba5/S586f1A4OWKc/mQJFyTaGhRBxw/cBSjqonvO0442VYLHFxlrTHoUunKyOJ8+BJfKgjWmfENC9ESY3mL/IEn5 +AUTH_FINGERPRINT_MISSING=SHA256:uB0B+30r2WA1TDMUmFcaEBjosjnFGzn33XFhiyvTL9w + # Initialize the test database. rm -f aur.db sed \ diff --git a/git-interface/test/t0001-auth.sh b/git-interface/test/t0001-auth.sh index 50ef510f..71d526f2 100755 --- a/git-interface/test/t0001-auth.sh +++ b/git-interface/test/t0001-auth.sh @@ -16,4 +16,13 @@ test_expect_success 'Test Trusted User authentication.' ' grep -q AUR_PRIVILEGED=1 out ' +test_expect_success 'Test authentication with an unsupported key type.' ' + test_must_fail "$GIT_AUTH" ssh-xxx "$AUTH_KEYTEXT_USER" +' + +test_expect_success 'Test authentication with a wrong key.' ' + "$GIT_AUTH" "$AUTH_KEYTYPE_MISSING" "$AUTH_KEYTEXT_MISSING" >out + test_must_be_empty out +' + test_done From 9a03c7fbdd9a1eff197d9c14301ab23aabc88109 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 5 Aug 2016 21:22:36 +0200 Subject: [PATCH 0217/1891] t0002: Add more git-serve tests Add tests for common scenarios that should be detected/handled by the git-serve script. Signed-off-by: Lukas Fleischer --- git-interface/test/setup.sh | 19 +++++++++- git-interface/test/t0002-serve.sh | 62 +++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/git-interface/test/setup.sh b/git-interface/test/setup.sh index 45129782..cb1e2506 100644 --- a/git-interface/test/setup.sh +++ b/git-interface/test/setup.sh @@ -29,8 +29,8 @@ ssh-options = restrict [serve] repo-path = ./aur.git/ repo-regex = [a-z0-9][a-z0-9.+_-]*$ -git-shell-cmd = /usr/bin/git-shell -git-update-cmd = /srv/http/aurweb/git-interface/git-update.py +git-shell-cmd = ./git-shell.sh +git-update-cmd = ./update.sh ssh-cmdline = ssh aur@aur.archlinux.org [update] @@ -42,6 +42,21 @@ cat >notify.sh <<-EOF EOF chmod +x notify.sh +cat >git-shell.sh <<-\EOF +#!/bin/sh +echo $AUR_USER +echo $AUR_PKGBASE +echo $GIT_NAMESPACE +EOF +chmod +x git-shell.sh + +cat >update.sh <<-\EOF +#!/bin/sh +echo $AUR_USER +echo $AUR_PKGBASE +EOF +chmod +x update.sh + AUR_CONFIG=config export AUR_CONFIG diff --git a/git-interface/test/t0002-serve.sh b/git-interface/test/t0002-serve.sh index 7e17bcbc..f36f1d88 100755 --- a/git-interface/test/t0002-serve.sh +++ b/git-interface/test/t0002-serve.sh @@ -15,6 +15,8 @@ test_expect_success 'Test help.' ' test_expect_success 'Test setup-repo and list-repos.' ' SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user \ "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="setup-repo foobar2" AUR_USER=tu \ + "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && *foobar EOF @@ -23,4 +25,64 @@ test_expect_success 'Test setup-repo and list-repos.' ' test_cmp expected actual ' +test_expect_success 'Test git-receive-pack.' ' + cat >expected <<-EOF && + user + foobar + foobar + EOF + SSH_ORIGINAL_COMMAND="git-receive-pack /foobar.git/" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success 'Test git-receive-pack with an invalid repository name.' ' + SSH_ORIGINAL_COMMAND="git-receive-pack /!.git/" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 >actual +' + +test_expect_success "Test git-upload-pack." ' + cat >expected <<-EOF && + user + foobar + foobar + EOF + SSH_ORIGINAL_COMMAND="git-upload-pack /foobar.git/" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success "Try to pull from someone else's repository." ' + cat >expected <<-EOF && + user + foobar2 + foobar2 + EOF + SSH_ORIGINAL_COMMAND="git-upload-pack /foobar2.git/" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success "Try to push to someone else's repository." ' + SSH_ORIGINAL_COMMAND="git-receive-pack /foobar2.git/" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 +' + +test_expect_success "Try to push to someone else's repository as Trusted User." ' + cat >expected <<-EOF && + tu + foobar + foobar + EOF + SSH_ORIGINAL_COMMAND="git-receive-pack /foobar.git/" \ + AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + test_done From dd9c6f3ddca37479ce14425c0a82a4b46d7a727a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 5 Aug 2016 14:01:22 +0200 Subject: [PATCH 0218/1891] t0003: Add more git-update tests Add tests for common scenarios that should be detected/handled by the update hook. Signed-off-by: Lukas Fleischer --- git-interface/test/setup.sh | 68 +++++- git-interface/test/t0003-update.sh | 350 ++++++++++++++++++++++++++++- 2 files changed, 404 insertions(+), 14 deletions(-) diff --git a/git-interface/test/setup.sh b/git-interface/test/setup.sh index cb1e2506..7f3d45a1 100644 --- a/git-interface/test/setup.sh +++ b/git-interface/test/setup.sh @@ -90,20 +90,23 @@ echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (1, '$AUTH_FINGERPRINT_USER', '$AUTH_KEYTYPE_USER $AUTH_KEYTEXT_USER');" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FINGERPRINT_TU', '$AUTH_KEYTYPE_TU $AUTH_KEYTEXT_TU');" | sqlite3 aur.db -# Initialize a Git repository to store test packages in. -( - GIT_AUTHOR_EMAIL=author@example.com - GIT_AUTHOR_NAME='A U Thor' - GIT_COMMITTER_EMAIL=committer@example.com - GIT_COMMITTER_NAME='C O Mitter' - export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME - export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME +echo "INSERT INTO PackageBlacklist (Name) VALUES ('forbidden');" | sqlite3 aur.db +echo "INSERT INTO OfficialProviders (Name, Repo, Provides) VALUES ('official', 'core', 'official');" | sqlite3 aur.db +# Initialize a Git repository and test packages. +GIT_AUTHOR_EMAIL=author@example.com +GIT_AUTHOR_NAME='A U Thor' +GIT_COMMITTER_EMAIL=committer@example.com +GIT_COMMITTER_NAME='C O Mitter' +export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME +export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME + +( mkdir aur.git cd aur.git - git init -q - git checkout -q -b refs/namespaces/foobar/refs/heads/master + + git checkout -q --orphan refs/namespaces/foobar/refs/heads/master cat >PKGBUILD <<-EOF pkgname=foobar @@ -136,5 +139,48 @@ echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FIN EOF git add PKGBUILD .SRCINFO - git commit -q -am 'Initial import' + git commit -q -m 'Initial import' + + sed 's/\(pkgrel.*\)1/\12/' PKGBUILD >PKGBUILD.new + sed 's/\(pkgrel.*\)1/\12/' .SRCINFO >.SRCINFO.new + mv PKGBUILD.new PKGBUILD + mv .SRCINFO.new .SRCINFO + git commit -q -am 'Bump pkgrel' + + git checkout -q --orphan refs/namespaces/foobar2/refs/heads/master + + cat >PKGBUILD <<-EOF + pkgname=foobar2 + pkgver=1 + pkgrel=1 + pkgdesc='aurweb test package.' + url='https://aur.archlinux.org/' + license=('MIT') + arch=('any') + depends=('python-pygit2') + source=() + md5sums=() + + package() { + echo 'Hello world!' + } + EOF + + cat >.SRCINFO <<-EOF + pkgbase = foobar2 + pkgdesc = aurweb test package. + pkgver = 1 + pkgrel = 1 + url = https://aur.archlinux.org/ + arch = any + license = MIT + depends = python-pygit2 + + pkgname = foobar2 + EOF + + git add PKGBUILD .SRCINFO + git commit -q -m 'Initial import' + + git checkout -q refs/namespaces/foobar/refs/heads/master ) diff --git a/git-interface/test/t0003-update.sh b/git-interface/test/t0003-update.sh index 0e8962c1..810b860c 100755 --- a/git-interface/test/t0003-update.sh +++ b/git-interface/test/t0003-update.sh @@ -4,17 +4,361 @@ test_description='git-update tests' . ./setup.sh -test_expect_success 'Test update hook.' ' +test_expect_success 'Setup repositories and create package bases.' ' + SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user "$GIT_SERVE" + SSH_ORIGINAL_COMMAND="setup-repo foobar2" AUR_USER=user "$GIT_SERVE" +' + +test_expect_success 'Test update hook on a fresh repository.' ' old=0000000000000000000000000000000000000000 && - new=$(git -C aur.git rev-parse HEAD) && - SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user "$GIT_SERVE" && + new=$(git -C aur.git rev-parse HEAD^) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && cat >expected <<-EOF && 1|1|foobar|1-1|aurweb test package.|https://aur.archlinux.org/ + 1|GPL + 1|1 + 1|1|python-pygit2|| + 1|1 + 2|1 + EOF + >actual && + for t in Packages Licenses PackageLicenses Groups PackageGroups \ + PackageDepends PackageRelations PackageSources \ + PackageNotifications; do + echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual + done && + test_cmp expected actual +' + +test_expect_success 'Test update hook on another fresh repository.' ' + old=0000000000000000000000000000000000000000 && + test_when_finished "git -C aur.git checkout refs/namespaces/foobar/refs/heads/master" && + git -C aur.git checkout -q refs/namespaces/foobar2/refs/heads/master && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar2 AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && + cat >expected <<-EOF && + 1|1|foobar|1-1|aurweb test package.|https://aur.archlinux.org/ + 2|2|foobar2|1-1|aurweb test package.|https://aur.archlinux.org/ + 1|GPL + 2|MIT + 1|1 + 2|2 + 1|1|python-pygit2|| + 2|1|python-pygit2|| + 1|1 + 2|1 + EOF + >actual && + for t in Packages Licenses PackageLicenses Groups PackageGroups \ + PackageDepends PackageRelations PackageSources \ + PackageNotifications; do + echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual + done && + test_cmp expected actual +' + +test_expect_success 'Test update hook on an updated repository.' ' + old=$(git -C aur.git rev-parse HEAD^) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && + cat >expected <<-EOF && + 2|2|foobar2|1-1|aurweb test package.|https://aur.archlinux.org/ + 3|1|foobar|1-2|aurweb test package.|https://aur.archlinux.org/ + 1|GPL + 2|MIT + 2|2 + 3|1 + 2|1|python-pygit2|| + 3|1|python-pygit2|| + 1|1 + 2|1 + EOF + >actual && + for t in Packages Licenses PackageLicenses Groups PackageGroups \ + PackageDepends PackageRelations PackageSources \ + PackageNotifications; do + echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual + done && + test_cmp expected actual +' + +test_expect_success 'Pushing to a branch other than master.' ' + old=0000000000000000000000000000000000000000 && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/pu "$old" "$new" 2>&1 +' + +test_expect_success 'Performing a non-fast-forward ref update.' ' + old=$(git -C aur.git rev-parse HEAD) && + new=$(git -C aur.git rev-parse HEAD^) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Performing a non-fast-forward ref update as Trusted User.' ' + old=$(git -C aur.git rev-parse HEAD) && + new=$(git -C aur.git rev-parse HEAD^) && + AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Removing .SRCINFO.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + git -C aur.git rm -q .SRCINFO && + git -C aur.git commit -q -m "Remove .SRCINFO" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Removing .SRCINFO with a follow-up fix.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + git -C aur.git rm -q .SRCINFO && + git -C aur.git commit -q -m "Remove .SRCINFO" && + git -C aur.git revert --no-edit HEAD && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Removing PKGBUILD.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + git -C aur.git rm -q PKGBUILD && + git -C aur.git commit -q -m "Remove PKGBUILD" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing a tree with a subdirectory.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir aur.git/subdir && + touch aur.git/subdir/file && + git -C aur.git add subdir/file && + git -C aur.git commit -q -m "Add subdirectory" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing a tree with a large blob.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + printf "%256001s" x >aur.git/file && + git -C aur.git add file && + git -C aur.git commit -q -m "Add large blob" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing .SRCINFO with a non-matching package base.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/\(pkgbase.*\)foobar/\1foobar2/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Change package base" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing .SRCINFO with invalid syntax.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/=//" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Break .SRCINFO" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing .SRCINFO without pkgver.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "/pkgver/d" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Remove pkgver" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing .SRCINFO without pkgrel.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "/pkgrel/d" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Remove pkgrel" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing .SRCINFO with epoch.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/.*pkgrel.*/\\0\\nepoch = 1/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Add epoch" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && + cat >expected <<-EOF && + 2|2|foobar2|1-1|aurweb test package.|https://aur.archlinux.org/ + 3|1|foobar|1:1-2|aurweb test package.|https://aur.archlinux.org/ EOF echo "SELECT * FROM Packages;" | sqlite3 aur.db >actual && test_cmp expected actual ' +test_expect_success 'Pushing .SRCINFO with invalid pkgname.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/\(pkgname.*\)foobar/\1!/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Change pkgname" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing .SRCINFO with invalid epoch.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/.*pkgrel.*/\\0\\nepoch = !/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Change epoch" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Missing install file.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/.*depends.*/\\0\\ninstall = install/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Add install field" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Missing changelog file.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/.*depends.*/\\0\\nchangelog = changelog/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Add changelog field" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Missing source file.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s/.*depends.*/\\0\\nsource = file/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Add file to the source array" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing a blacklisted package.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + echo "pkgname = forbidden" >>aur.git/.SRCINFO && + git -C aur.git commit -q -am "Add blacklisted package" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing a blacklisted package as Trusted User.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + echo "pkgname = forbidden" >>aur.git/.SRCINFO && + git -C aur.git commit -q -am "Add blacklisted package" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 | grep ^warning: +' + +test_expect_success 'Pushing a package already in the official repositories.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + echo "pkgname = official" >>aur.git/.SRCINFO && + git -C aur.git commit -q -am "Add official package" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + +test_expect_success 'Pushing a package already in the official repositories as Trusted User.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + echo "pkgname = official" >>aur.git/.SRCINFO && + git -C aur.git commit -q -am "Add official package" && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 | grep ^warning: +' + +test_expect_success 'Trying to hijack a package.' ' + old=0000000000000000000000000000000000000000 && + test_when_finished "git -C aur.git checkout refs/namespaces/foobar/refs/heads/master" && + ( + cd aur.git && + git checkout -q refs/namespaces/foobar2/refs/heads/master && + sed "s/\\(.*pkgname.*\\)2/\\1/" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Change package name" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar2 AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + test_done From 83df9808b4d533473da51c819c88214a406c5cb9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 6 Aug 2016 01:45:15 +0200 Subject: [PATCH 0219/1891] Add tests for the restore command Test the restore mode of git-serve and git-update. Signed-off-by: Lukas Fleischer --- git-interface/test/t0002-serve.sh | 17 +++++++++++++++++ git-interface/test/t0003-update.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/git-interface/test/t0002-serve.sh b/git-interface/test/t0002-serve.sh index f36f1d88..52fdcd1e 100755 --- a/git-interface/test/t0002-serve.sh +++ b/git-interface/test/t0002-serve.sh @@ -85,4 +85,21 @@ test_expect_success "Try to push to someone else's repository as Trusted User." test_cmp expected actual ' +test_expect_success "Test restore." ' + echo "DELETE FROM PackageBases WHERE Name = \"foobar\";" | \ + sqlite3 aur.db && + cat >expected <<-EOF && + user + foobar + EOF + SSH_ORIGINAL_COMMAND="restore foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual + test_cmp expected actual +' + +test_expect_success "Try to restore an existing package base." ' + SSH_ORIGINAL_COMMAND="restore foobar2" AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 +' + test_done diff --git a/git-interface/test/t0003-update.sh b/git-interface/test/t0003-update.sh index 810b860c..81c5687d 100755 --- a/git-interface/test/t0003-update.sh +++ b/git-interface/test/t0003-update.sh @@ -85,6 +85,35 @@ test_expect_success 'Test update hook on an updated repository.' ' test_cmp expected actual ' +test_expect_success 'Test restore mode.' ' + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" restore 2>&1 && + cat >expected <<-EOF && + 2|2|foobar2|1-1|aurweb test package.|https://aur.archlinux.org/ + 3|1|foobar|1-2|aurweb test package.|https://aur.archlinux.org/ + 1|GPL + 2|MIT + 2|2 + 3|1 + 2|1|python-pygit2|| + 3|1|python-pygit2|| + 1|1 + 2|1 + EOF + >actual && + for t in Packages Licenses PackageLicenses Groups PackageGroups \ + PackageDepends PackageRelations PackageSources \ + PackageNotifications; do + echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual + done && + test_cmp expected actual +' + +test_expect_success 'Test restore mode on a non-existent repository.' ' + AUR_USER=user AUR_PKGBASE=foobar3 AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" restore 2>&1 +' + test_expect_success 'Pushing to a branch other than master.' ' old=0000000000000000000000000000000000000000 && new=$(git -C aur.git rev-parse HEAD) && From ac6b09172483fae46bc643fa80da71961682965f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 6 Aug 2016 11:44:40 +0200 Subject: [PATCH 0220/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index 945ce5d8..e773913a 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: AUR v4.2.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-06-25 16:09+0200\n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1617,8 +1617,10 @@ msgstr "" #: template/pkgreq_results.php #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #: template/pkgreq_results.php #, php-format @@ -1748,9 +1750,10 @@ msgid "Version" msgstr "" #: template/pkg_search_results.php +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" #: template/pkg_search_results.php template/tu_details.php template/tu_list.php From 936ee66f1e3e387d24f9bb4f5d00071c15c9f3bd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 9 Aug 2016 14:46:08 +0200 Subject: [PATCH 0221/1891] Lazy-add new package bases Create new package bases just before saving package metadata. This protects from stray package bases left behind when new packages are rejected, e.g. when the user tries to push a package that is available from the official repositories already. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 5 +---- git-interface/git-update.py | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index d3a32c39..19c3ab2e 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -145,10 +145,7 @@ if action == 'git-upload-pack' or action == 'git-receive-pack': if not re.match(repo_regex, pkgbase): die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) - if not pkgbase_exists(pkgbase): - create_pkgbase(pkgbase, user) - - if action == 'git-receive-pack': + if action == 'git-receive-pack' and pkgbase_exists(pkgbase): if not privileged and not pkgbase_has_write_access(pkgbase, user): die('{:s}: permission denied: {:s}'.format(action, user)) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index e6f6410a..40d834d8 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -58,6 +58,25 @@ def parse_dep(depstring): return (depname, depcond) +def create_pkgbase(conn, pkgbase, user): + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + + now = int(time.time()) + cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " + + "ModifiedTS, SubmitterUID, MaintainerUID) VALUES " + + "(?, ?, ?, ?, ?)", [pkgbase, now, now, userid, userid]) + pkgbase_id = cur.lastrowid + + cur = conn.execute("INSERT INTO PackageNotifications " + + "(PackageBaseID, UserID) VALUES (?, ?)", + [pkgbase_id, userid]) + + conn.commit() + + return pkgbase_id + + def save_metadata(metadata, conn, user): # Obtain package base ID and previous maintainer. pkgbase = metadata['pkgbase'] @@ -362,6 +381,10 @@ for pkgname in srcinfo.utils.get_package_names(metadata): if cur.fetchone()[0] > 0: die('cannot overwrite package: {:s}'.format(pkgname)) +# Create a new package base if it does not exist yet. +if pkgbase_id == 0: + pkgbase_id = create_pkgbase(conn, pkgbase, user) + # Store package base details in the database. save_metadata(metadata, conn, user) From 435b5fc9024bff261d18456cd6628966eab8452f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 9 Aug 2016 20:04:05 +0200 Subject: [PATCH 0222/1891] t0003: Do not initialize package bases explicitly Package bases are created by git-update automatically when the repository receives a ref update for the first time. Signed-off-by: Lukas Fleischer --- git-interface/test/t0003-update.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/git-interface/test/t0003-update.sh b/git-interface/test/t0003-update.sh index 81c5687d..aeb223e8 100755 --- a/git-interface/test/t0003-update.sh +++ b/git-interface/test/t0003-update.sh @@ -4,11 +4,6 @@ test_description='git-update tests' . ./setup.sh -test_expect_success 'Setup repositories and create package bases.' ' - SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user "$GIT_SERVE" - SSH_ORIGINAL_COMMAND="setup-repo foobar2" AUR_USER=user "$GIT_SERVE" -' - test_expect_success 'Test update hook on a fresh repository.' ' old=0000000000000000000000000000000000000000 && new=$(git -C aur.git rev-parse HEAD^) && @@ -20,7 +15,6 @@ test_expect_success 'Test update hook on a fresh repository.' ' 1|1 1|1|python-pygit2|| 1|1 - 2|1 EOF >actual && for t in Packages Licenses PackageLicenses Groups PackageGroups \ From d43f8478b4ad26f5cd6b69d6036b38613425a23f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 14 Aug 2016 07:59:12 +0200 Subject: [PATCH 0223/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 116 +++++++---- po/ast.po | 46 ++++- po/ca.po | 46 ++++- po/cs.po | 45 +++- po/da.po | 44 +++- po/de.po | 66 ++++-- po/el.po | 44 +++- po/es.po | 116 ++++++++--- po/es_419.po | 111 +++++++--- po/fi.po | 44 +++- po/fr.po | 64 +++++- po/he.po | 567 ++++++++++++++++++++++++++++----------------------- po/hr.po | 45 +++- po/hu.po | 183 +++++++++++------ po/it.po | 46 ++++- po/ja.po | 89 ++++++-- po/nb.po | 46 ++++- po/nl.po | 44 +++- po/pl.po | 226 ++++++++++++-------- po/pt_BR.po | 101 ++++++--- po/pt_PT.po | 44 +++- po/ro.po | 45 +++- po/ru.po | 103 +++++++--- po/sk.po | 47 ++++- po/sr.po | 60 +++++- po/tr.po | 46 ++++- po/uk.po | 57 +++++- po/zh_CN.po | 227 +++++++++++++-------- po/zh_TW.po | 50 ++++- 29 files changed, 1952 insertions(+), 816 deletions(-) diff --git a/po/ar.po b/po/ar.po index 931d2e10..836bfc36 100644 --- a/po/ar.po +++ b/po/ar.po @@ -4,14 +4,14 @@ # # Translators: # safa1996alfulaij , 2015 -# صفا الفليج , 2015 +# صفا الفليج , 2015-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" "ar/)\n" "Language: ar\n" @@ -145,6 +145,7 @@ msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"حزم م‌م‌آ هي حزم قدّمها المستخدمين. أيّ استخدام للملفّات يكون على مسؤوليّتك الخاصّة." msgid "Learn more..." msgstr "اطّلع على المزيد..." @@ -228,7 +229,7 @@ msgid "" "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" "النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين " -"تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِب م‌م‌آ، استخدم " +"تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِبّ م‌م‌آ، استخدم " "قائمة %saur-dev%s البريديّة." msgid "Bug Reporting" @@ -241,6 +242,9 @@ msgid "" "%sonly%s. To report packaging bugs contact the package maintainer or leave a " "comment on the appropriate package page." msgstr "" +"إن وجدت علّة في واجهة وِبّ م‌م‌آ، فضلًا املأ تقريرًا بها في %sمتعقّب العلل%s. استخدم " +"المتعقّب للإبلاغ عن العلل في واجهة وِبّ م‌م‌آ %sفقط%s. للإبلاغ عن علل الحزم راسل " +"مديرها أو اترك تعليقًا في صفحة الحزمة المناسبة." msgid "Package Search" msgstr "ابحث عن حزمة" @@ -429,7 +433,7 @@ msgstr "علّم الحزمة كقديمة" msgid "" "Use this form to flag the package base %s%s%s and the following packages out-" "of-date: " -msgstr "" +msgstr "استخدم هذه الاستمارة لتعليم أساس الحزمة %s%s%s والحزم الآتية كقديمة:" #, php-format msgid "" @@ -450,7 +454,7 @@ msgid "Flag" msgstr "علّم" msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "يمكن فقط للمستخدمين المسجّلين تعليم الحزم كقديمة." msgid "Package Merging" msgstr "ادمج حزمة" @@ -606,7 +610,7 @@ msgstr "انقر وصلة الولوج أعلاه لاستخدام حسابك." #, php-format msgid "No changes were made to the account, %s%s%s." -msgstr "لم تتمّ أيّ تغييرات على الحساب %s%s%s." +msgstr "لم تجري أيّ تغييرات على الحساب %s%s%s." #, php-format msgid "The account, %s%s%s, has been successfully modified." @@ -649,16 +653,16 @@ msgid "View account information for %s" msgstr "اعرض معلومات حساب %s" msgid "Package base ID or package base name missing." -msgstr "" +msgstr "معرّف أساس الحزمة أو اسمه ناقص." msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "ليس مسموحًا لك بتحرير هذا التّعليق." msgid "Comment does not exist." msgstr "التّعليق غير موجود." msgid "Comment cannot be empty." -msgstr "" +msgstr "لا يمكن أن يكون التّعليق فارغًا." msgid "Comment has been added." msgstr "أُضيف التّعليق" @@ -670,19 +674,19 @@ msgid "Missing comment ID." msgstr "معرّف التّعليق ناقص." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "لا يمكن تثبيت أكثر من 5 تعليقات." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "ليس مسموحًا لك بتثبيت هذا التّعليق." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "ليس مسموحًا لك بفكّ تثبيت هذا التّعليق." msgid "Comment has been pinned." -msgstr "" +msgstr "ثّبّت التّعليق." msgid "Comment has been unpinned." -msgstr "" +msgstr "فُكّ تثبيت التعليق." msgid "Error retrieving package details." msgstr "خطأ في استرجاع تفاصيل الحزمة." @@ -697,7 +701,7 @@ msgid "You did not select any packages to flag." msgstr "لم تحدّد أيّ حزم لتعليمها." msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" +msgstr "لم تعلّم الحزم المحدّدة، فضلًا أدخل تعليقًا." msgid "The selected packages have been flagged out-of-date." msgstr "عُلّمت الحزم المحدّدة كقديمة." @@ -777,7 +781,7 @@ msgid "Comment has been deleted." msgstr "حُذف التّعليق." msgid "Comment has been edited." -msgstr "" +msgstr "حُرّر التّعليق." msgid "You are not allowed to edit the keywords of this package base." msgstr "ليس مسموحًا لك بتحرير كلمات أساس الحزمة المفتاحيّة." @@ -856,11 +860,14 @@ msgid "Email Address" msgstr "البريد الإلكترونيّ" msgid "hidden" -msgstr "" +msgstr "مخفيّ" msgid "Real Name" msgstr "الاسم الحقيقيّ" +msgid "Homepage" +msgstr "الرّئيسيّة" + msgid "IRC Nick" msgstr "اسم آي‌آر‌سي المستعار" @@ -910,7 +917,7 @@ msgstr "غير نشط" msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" +msgstr "فضلًا تأكّد من إدخال البريد الإلكترونيّ الصّحيح، وإلّا فسيُقفل الحساب." msgid "Hide Email Address" msgstr "أخفِ عنوان البريد الإلكترونيّ" @@ -930,13 +937,16 @@ msgid "SSH Public Key" msgstr "مفتاح SSH العموميّ" msgid "Notification settings" -msgstr "" +msgstr "إعدادات الإخطارات" msgid "Notify of new comments" msgstr "أخطرني بالتّعليقات الجديدة" msgid "Notify of package updates" -msgstr "" +msgstr "أخطرني بتحديثات الحزم" + +msgid "Notify of ownership changes" +msgstr "أخطرني بتغيير المُلّاك" msgid "Update" msgstr "حدّث" @@ -981,22 +991,22 @@ msgstr "احفظ" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "تعليق التّعليم كقديمة: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" +msgstr "علّم %s%s%s الحزمة %s%s%s بقديمة في %s%s%s وذلك للأسباب الآتية:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "لم تُعلّم الحزمة %s%s%s كقديمة." msgid "Return to Details" -msgstr "" +msgstr "عُد إلى التّفاصيل" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "الحقوق محفوظة %s 2004-%d فريق تطوير aurweb." msgid "My Packages" msgstr "حزمي" @@ -1021,7 +1031,7 @@ msgstr "ابحث في الويكي" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "معلّمة كقديمة (%s)" msgid "Flag package out-of-date" msgstr "علّم الحزمة كقديمة" @@ -1038,6 +1048,9 @@ msgstr "صوّت لهذه الحزمة" msgid "Disable notifications" msgstr "عطّل الإخطارات" +msgid "Enable notifications" +msgstr "فعّل الإخطارات" + msgid "Manage Co-Maintainers" msgstr "أدر المصينين المشاركين" @@ -1092,7 +1105,7 @@ msgstr "آخر تحديث" #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "حرّر تعليق: %s" msgid "Add Comment" msgstr "أضف تعليقًا" @@ -1101,7 +1114,7 @@ msgid "View all comments" msgstr "اعرض كلّ التّعليقات" msgid "Pinned Comments" -msgstr "" +msgstr "التّعليقات المثبّتة" msgid "Latest Comments" msgstr "آخر التّعليقات" @@ -1137,10 +1150,10 @@ msgid "Delete comment" msgstr "احذف التّعليق" msgid "Pin comment" -msgstr "" +msgstr "ثبّت التّعليق" msgid "Unpin comment" -msgstr "" +msgstr "فكّ تثبيت التّعليق" msgid "All comments" msgstr "كلّ التّعليقات" @@ -1158,7 +1171,7 @@ msgid "Upstream URL" msgstr "عنوان المنبع" msgid "Visit the website for" -msgstr "زُر موقع وِب" +msgstr "زُر موقع وِبّ" msgid "Licenses" msgstr "الرّخص" @@ -1225,6 +1238,26 @@ msgstr "يتيمة" msgid "Merge into" msgstr "ادمج مع" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1249,8 +1282,14 @@ msgid "Date" msgstr "التّاريخ" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" +msgstr[4] "" +msgstr[5] "" #, php-format msgid "~%d hour left" @@ -1305,7 +1344,7 @@ msgid "Voted" msgstr "مصوّت عليها" msgid "Last modified" -msgstr "" +msgstr "آخر تعديل" msgid "Ascending" msgstr "تصاعديًّا" @@ -1356,9 +1395,10 @@ msgstr[5] "عُثر على %d حزمة." msgid "Version" msgstr "الإصدارة" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" @@ -1419,7 +1459,7 @@ msgid "Recent Updates" msgstr "التّحديثات الأخيرة" msgid "more" -msgstr "" +msgstr "أخرى" msgid "My Statistics" msgstr "إحصائيّاتي" diff --git a/po/ast.po b/po/ast.po index 8203718f..7444474c 100644 --- a/po/ast.po +++ b/po/ast.po @@ -5,14 +5,14 @@ # Translators: # enolp , 2014-2015 # Ḷḷumex03 , 2014 -# Pablo Roberto Francisco Lezaeta Reyes , 2014-2015 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2014-2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" "ast/)\n" "Language: ast\n" @@ -847,6 +847,9 @@ msgstr "" msgid "Real Name" msgstr "Nome real" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Alcuñu nel IRC" @@ -925,6 +928,9 @@ msgstr "" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Anovar" @@ -1025,6 +1031,9 @@ msgstr "Votar pol paquete" msgid "Disable notifications" msgstr "" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "Alministra comantenedores" @@ -1208,6 +1217,26 @@ msgstr "Güérfanu" msgid "Merge into" msgstr "" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1228,8 +1257,10 @@ msgid "Date" msgstr "Data" #, php-format -msgid "~%d days left" -msgstr "Falten ~%d díes" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1327,9 +1358,10 @@ msgstr[1] "Alcontráronse %d paquetes" msgid "Version" msgstr "Versión" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/ca.po b/po/ca.po index de3eecc6..fc7659c7 100644 --- a/po/ca.po +++ b/po/ca.po @@ -3,16 +3,16 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# Adolfo Jayme Barrientos, 2014 +# Adolfo Jayme-Barrientos, 2014 # Hector Mtz-Seara , 2011,2013 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" "ca/)\n" "Language: ca\n" @@ -852,6 +852,9 @@ msgstr "" msgid "Real Name" msgstr "Nom real" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Nom d'usuari IRC" @@ -929,6 +932,9 @@ msgstr "Notificar comentaris nous" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Actualitza" @@ -1029,6 +1035,9 @@ msgstr "Vota per aquest paquet" msgid "Disable notifications" msgstr "Deshabilitar notificacions" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1210,6 +1219,26 @@ msgstr "" msgid "Merge into" msgstr "Combinar amb" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1230,8 +1259,10 @@ msgid "Date" msgstr "Data" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1329,9 +1360,10 @@ msgstr[1] "" msgid "Version" msgstr "Versió" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/cs.po b/po/cs.po index f9e7461f..0301019e 100644 --- a/po/cs.po +++ b/po/cs.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-10 09:49+0000\n" -"Last-Translator: Jaroslav Lichtblau \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" "Language: cs\n" "MIME-Version: 1.0\n" @@ -834,6 +834,9 @@ msgstr "skrytý" msgid "Real Name" msgstr "Skutečné jméno" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC přezdívka" @@ -911,6 +914,9 @@ msgstr "Oznamovat nové komentáře" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Aktualizovat" @@ -1011,6 +1017,9 @@ msgstr "Hlasovat pro tento balíček" msgid "Disable notifications" msgstr "Vypnout oznámení" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1193,6 +1202,26 @@ msgstr "" msgid "Merge into" msgstr "" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1214,8 +1243,11 @@ msgid "Date" msgstr "Datum" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" #, php-format msgid "~%d hour left" @@ -1315,9 +1347,10 @@ msgstr[2] "Nalezeno %d balíčků." msgid "Version" msgstr "Verze" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/da.po b/po/da.po index 14253277..66327dfd 100644 --- a/po/da.po +++ b/po/da.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" "da/)\n" "Language: da\n" @@ -828,6 +828,9 @@ msgstr "" msgid "Real Name" msgstr "Rigtigt navn" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC kaldenavn" @@ -905,6 +908,9 @@ msgstr "" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Opdater" @@ -1005,6 +1011,9 @@ msgstr "Stem på denne pakke" msgid "Disable notifications" msgstr "Deaktiver notifikationer" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1186,6 +1195,26 @@ msgstr "Forladt" msgid "Merge into" msgstr "" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1206,8 +1235,10 @@ msgid "Date" msgstr "Dato" #, php-format -msgid "~%d days left" -msgstr "~%d dage tilbage" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1305,9 +1336,10 @@ msgstr[1] "%d pakker fundet." msgid "Version" msgstr "Version" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/de.po b/po/de.po index 1fc461f0..d49870d6 100644 --- a/po/de.po +++ b/po/de.po @@ -9,7 +9,7 @@ # FabianS_ , 2012 # go2sh , 2015 # FabianS_ , 2012 -# Giuliano Schneider , 2015 +# Giuliano Schneider , 2015-2016 # go2sh , 2015 # Lukas Fleischer , 2011 # Mark Gerlach, 2015 @@ -24,9 +24,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" "de/)\n" "Language: de\n" @@ -830,10 +830,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "Du wurdest von der Benachrichtigungsliste für %s entfernt." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Du bist nicht berechtigt diesen Kommentar wiederherzustellen." msgid "Comment has been undeleted." -msgstr "" +msgstr "Kommentar wurde wiederhergestellt." msgid "You are not allowed to delete this comment." msgstr "Du darfst diesen Kommentar nicht löschen." @@ -928,6 +928,9 @@ msgstr "versteckt" msgid "Real Name" msgstr "Echter Name" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC-Name" @@ -1010,6 +1013,9 @@ msgstr "Über neue Kommentare benachrichtigen" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Aktualisieren" @@ -1070,7 +1076,7 @@ msgstr "" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "Copyright %s 2004-%d aurweb Development Team." msgid "My Packages" msgstr "Meine Pakete" @@ -1095,7 +1101,7 @@ msgstr "Durchsuche Wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Als \"veraltet\" markiert (%s)" msgid "Flag package out-of-date" msgstr "Paket als \"veraltet\" markieren" @@ -1112,6 +1118,9 @@ msgstr "Für dieses Paket stimmen" msgid "Disable notifications" msgstr "Benachrichtigungen deaktivieren" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "Verwalte Ko-Maintainer" @@ -1190,18 +1199,18 @@ msgstr "gelöscht am %s von %s" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "gelöscht am %s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "geändert am %s von %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "geändert am %s" msgid "Undelete comment" -msgstr "" +msgstr "Kommentar wiederherstellen" msgid "Delete comment" msgstr "Kommentar löschen" @@ -1299,6 +1308,26 @@ msgstr "Verwaist" msgid "Merge into" msgstr "Verschmelzen mit" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1319,8 +1348,10 @@ msgid "Date" msgstr "Datum" #, php-format -msgid "~%d days left" -msgstr "~%d Tage verbleibend" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1418,12 +1449,11 @@ msgstr[1] "%d Pakete gefunden." msgid "Version" msgstr "Version" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"Die Beliebtheit berechnet sich als Summe aller Stimmen, wobei jede Stimme " -"mit einem Faktor von 0,98 pro Tag seit der Erstellung gewichtet wird." msgid "Yes" msgstr "Ja" @@ -1483,7 +1513,7 @@ msgid "Recent Updates" msgstr "Letzte Aktualisierungen" msgid "more" -msgstr "" +msgstr "mehr" msgid "My Statistics" msgstr "Meine Statistiken" diff --git a/po/el.po b/po/el.po index 6d0c9a44..c241f35c 100644 --- a/po/el.po +++ b/po/el.po @@ -14,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" "Language: el\n" "MIME-Version: 1.0\n" @@ -864,6 +864,9 @@ msgstr "" msgid "Real Name" msgstr "Πραγματικό 'Ονομα" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Ψευδώνυμο IRC" @@ -941,6 +944,9 @@ msgstr "Ειδοποίησε για νέα σχόλια" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Eνημέρωση" @@ -1041,6 +1047,9 @@ msgstr "Ψηφίστε για αυτό το πακέτο" msgid "Disable notifications" msgstr "Απενεργοποιήστε τις ειδοποιήσεις" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1222,6 +1231,26 @@ msgstr "" msgid "Merge into" msgstr "Συγχώνευση σε" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1242,8 +1271,10 @@ msgid "Date" msgstr "" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1341,9 +1372,10 @@ msgstr[1] "" msgid "Version" msgstr "Έκδοση" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/es.po b/po/es.po index 6e70688f..4dd702e8 100644 --- a/po/es.po +++ b/po/es.po @@ -3,21 +3,22 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# Adolfo Jayme Barrientos, 2015 +# Adolfo Jayme-Barrientos, 2015 # Angel Velasquez , 2011 # juantascon , 2011 # Lukas Fleischer , 2011 # neiko , 2011 # Nicolás de la Torre , 2012 -# Pablo Roberto Francisco Lezaeta Reyes , 2012 -# Pablo Roberto Francisco Lezaeta Reyes , 2013-2015 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2012 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2013-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" "es/)\n" "Language: es\n" @@ -457,7 +458,7 @@ msgstr "" "de paquetes." msgid "Flag Comment" -msgstr "" +msgstr "Marcar comentario" msgid "Flag Package Out-Of-Date" msgstr "Marcado como desactualizado" @@ -528,7 +529,7 @@ msgstr "" "Solamente usuarios de confianza y desarrolladores pueden unir paquetes." msgid "Submit Request" -msgstr "" +msgstr "Enviar solicitud" msgid "Close Request" msgstr "Cerrar solicitud" @@ -719,19 +720,19 @@ msgid "Missing comment ID." msgstr "Falta el identificador del comentario." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "No pueden fijarse más de 5 comentarios." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "No tienes permitido fijar este comentario." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "No tienes permitido desfijar este comentario." msgid "Comment has been pinned." -msgstr "" +msgstr "El comentario ha sido fijado." msgid "Comment has been unpinned." -msgstr "" +msgstr "El comentario ha sido desfijado." msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." @@ -816,10 +817,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "Haz sido eliminado de la lista de notificaciones de comentarios de %s." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "No estás autorizado a restablecer este comentario." msgid "Comment has been undeleted." -msgstr "" +msgstr "El comentario se ha restablecido." msgid "You are not allowed to delete this comment." msgstr "No estás autorizado para eliminar este comentario." @@ -917,6 +918,9 @@ msgstr "oculto" msgid "Real Name" msgstr "Nombre real" +msgid "Homepage" +msgstr "Página principal" + msgid "IRC Nick" msgstr "Alias de IRC" @@ -990,13 +994,16 @@ msgid "SSH Public Key" msgstr "Clave pública SSH" msgid "Notification settings" -msgstr "" +msgstr "Gestión de notificaciones" msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" msgid "Notify of package updates" -msgstr "" +msgstr "Notificar de actualizaciones de un paquete" + +msgid "Notify of ownership changes" +msgstr "Notificar de cambios de propietario" msgid "Update" msgstr "Actualizar" @@ -1044,22 +1051,25 @@ msgstr "Guardar" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Marcar comentario como desactualizado: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +"%s%s%s se ha marcado %s%s%s como desactualizado %s%s%s por la siguiente " +"razón:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s no está marcado como desactualizado." msgid "Return to Details" -msgstr "" +msgstr "Regresar a detalles" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +"Derechos de autor %s 2004 - %d, equipo desarrollador de la web del AUR." msgid "My Packages" msgstr "Mis paquetes" @@ -1084,7 +1094,7 @@ msgstr "Buscar en la wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Marcado como desactualizado (%s)" msgid "Flag package out-of-date" msgstr "Marcar paquete como desactualizado" @@ -1101,6 +1111,9 @@ msgstr "Votar por este paquete" msgid "Disable notifications" msgstr "Deshabilitar notificaciones" +msgid "Enable notifications" +msgstr "Habilitar notificaciones" + msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" @@ -1160,7 +1173,7 @@ msgid "View all comments" msgstr "Ver todos los comentarios" msgid "Pinned Comments" -msgstr "" +msgstr "Comentarios fijados" msgid "Latest Comments" msgstr "Últimos comentarios" @@ -1179,27 +1192,27 @@ msgstr "borrado el %s por %s" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "borrado el %s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "editado el %s por %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "editado el %s" msgid "Undelete comment" -msgstr "" +msgstr "Comentario restablecido" msgid "Delete comment" msgstr "Eliminar comentario" msgid "Pin comment" -msgstr "" +msgstr "Comentario fijado" msgid "Unpin comment" -msgstr "" +msgstr "Comentario desfijado" msgid "All comments" msgstr "Todos los comentarios" @@ -1287,6 +1300,40 @@ msgstr "Orfandad" msgid "Merge into" msgstr "Unir en" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"Al enviar una solicitud de eliminación, le preguntas a un usuario de " +"confianza que elimine el paquete base. Este tipo de solicitud debe ser " +"utilizado para los duplicados, programas abandonados por el desarrollador " +"principal o encargado, así como programas ilegales e irreparablemente rotos." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"Al enviar una solicitud de unión, le preguntas a un usuario de confianza que " +"elimine el paquete base y transfiera sus votos y comentarios a otro paquete " +"base. La unión de un paquete no afecta a los correspondientes repositorios " +"Git. Por tanto asegúrate de actualizar el historia Git del paquete de " +"destino tú mismo." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"Al enviar una solicitud de orfandad, le preguntas a un usuario de confianza " +"que remueva la propiedad sobre el paquete base al encargado principal de " +"este. Por favor, haz esto solamente si el paquete necesita una acción de " +"mantenención, el encargado no presenta signos de actividad y ya intentaste " +"ponerte en contacto con él anteriormente." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1307,8 +1354,10 @@ msgid "Date" msgstr "Fecha" #, php-format -msgid "~%d days left" -msgstr "Aprox. %d días restantes" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1406,12 +1455,11 @@ msgstr[1] "%d paquetes fueron encontrados." msgid "Version" msgstr "Versión" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"La popularidad se calcula como la suma de todos los votos con cada voto " -"ponderado con un factor de 0,98 por día desde la creación del paquete." msgid "Yes" msgstr "Sí" @@ -1471,7 +1519,7 @@ msgid "Recent Updates" msgstr "Actualizaciones recientes" msgid "more" -msgstr "" +msgstr "más" msgid "My Statistics" msgstr "Mis estadísticas" diff --git a/po/es_419.po b/po/es_419.po index 962917e7..de9196af 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -8,14 +8,15 @@ # Lukas Fleischer , 2011 # neiko , 2011 # Nicolás de la Torre , 2012 -# Pablo Roberto Francisco Lezaeta Reyes , 2012,2015 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2012,2015-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" "aur/language/es_419/)\n" "Language: es_419\n" @@ -453,7 +454,7 @@ msgstr "" "paquetes." msgid "Flag Comment" -msgstr "" +msgstr "Marcar comentario" msgid "Flag Package Out-Of-Date" msgstr "Marcado como desactualizado" @@ -524,7 +525,7 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo Usuarios de Confianza y Desarrolladores pueden fusionar paquetes." msgid "Submit Request" -msgstr "" +msgstr "Enviar petición" msgid "Close Request" msgstr "Cerrar Petición" @@ -713,19 +714,19 @@ msgid "Missing comment ID." msgstr "Falta el identificador del comentario." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "No pueden ser anclar más de 5 comentarios." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "No tiene permitido anclar este comentario." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "No tiene permitido desanclar este comentario." msgid "Comment has been pinned." -msgstr "" +msgstr "El comentario fue anclado." msgid "Comment has been unpinned." -msgstr "" +msgstr "El comentario fue desanclado." msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." @@ -810,10 +811,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "Ha sido eliminado de la lista de notificaciones de comentarios de %s." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "No está autorizado a restablecer este comentario." msgid "Comment has been undeleted." -msgstr "" +msgstr "El comentario fue restablecido." msgid "You are not allowed to delete this comment." msgstr "No está autorizado a borrar este comentario." @@ -910,6 +911,9 @@ msgstr "oculto" msgid "Real Name" msgstr "Nombre real" +msgid "Homepage" +msgstr "Página principal" + msgid "IRC Nick" msgstr "Alias de IRC" @@ -983,13 +987,16 @@ msgid "SSH Public Key" msgstr "Clave pública SSH" msgid "Notification settings" -msgstr "" +msgstr "Configuración de notificaciones" msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" msgid "Notify of package updates" -msgstr "" +msgstr "Notificar sobre actualizaciones de un paquete" + +msgid "Notify of ownership changes" +msgstr "Notificarme de cambios de propietario" msgid "Update" msgstr "Actualizar" @@ -1037,22 +1044,24 @@ msgstr "Guardar" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Marcar comentario como desactualizado: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +"%s%s%s fue marcado %s%s%s como desactualizado %s%s%s por la siguiente razón:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s no está marcado como desactualizado." msgid "Return to Details" -msgstr "" +msgstr "Regresar a detalles" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +"Derechos de autor %s 2004 - %d, equipo desarrollador de la web del AUR." msgid "My Packages" msgstr "Mis paquetes" @@ -1077,7 +1086,7 @@ msgstr "Buscar en la wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Marcado como desactualizado (%s)" msgid "Flag package out-of-date" msgstr "Marcar paquete como desactualizado" @@ -1094,6 +1103,9 @@ msgstr "Votar por este paquete" msgid "Disable notifications" msgstr "Deshabilitar notificaciones" +msgid "Enable notifications" +msgstr "Habilitar notificaciones" + msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" @@ -1153,7 +1165,7 @@ msgid "View all comments" msgstr "Ver todos los comentarios" msgid "Pinned Comments" -msgstr "" +msgstr "Comentarios anclados" msgid "Latest Comments" msgstr "Últimos comentarios" @@ -1172,27 +1184,27 @@ msgstr "borrado el %s por %s" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "borrado el %s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "editado el %s por %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "editado el %s" msgid "Undelete comment" -msgstr "" +msgstr "Comentario restablecido" msgid "Delete comment" msgstr "Borrar comentario" msgid "Pin comment" -msgstr "" +msgstr "Comentario anclado" msgid "Unpin comment" -msgstr "" +msgstr "Comentario desanclado" msgid "All comments" msgstr "Todos los comentarios" @@ -1280,6 +1292,40 @@ msgstr "Orfandad" msgid "Merge into" msgstr "Fusionar en" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"Al enviar una Petición de Borrado, le preguntará a un Usuario de Confianza " +"que elimine dicho paquete base. Este tipo de peticiones debe ser utilizada " +"para duplicados, programas abandonados por el desarrollador principal o " +"encargado, así como programas ilegales e irreparablemente rotos." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"Al enviar una Petición de Fusión, le preguntará a un Usuario de Confianza " +"que borre el paquete base y transfiera sus votos y comentarios a otro " +"paquete base. La fusión de un paquete no afecta a los correspondientes " +"repositorios Git. Por lo tanto asegúrese de actualizar el historia Git del " +"paquete de destino uste mismo." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"Al enviar una Petición de Orfandad, le preguntarás a un Usuario de Confianza " +"que le quite la propiedad sobre el paquete base al encargado principal de " +"este. Por favor, haga esto solo si el paquete necesita acciones de " +"mantenención para funcionar, el encargado no presenta da de actividad y ya " +"intentó ponerse en contacto con él anteriormente." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1300,8 +1346,10 @@ msgid "Date" msgstr "Fecha" #, php-format -msgid "~%d days left" -msgstr "Aprox. %d días restantes" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1399,12 +1447,11 @@ msgstr[1] "%d paquetes fueron encontrados." msgid "Version" msgstr "Versión" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"La Popularidad es calculada como la suma de todos los votos ponderados con " -"un factor de 0,98 por día desde la creación del paquete." msgid "Yes" msgstr "Sí" @@ -1464,7 +1511,7 @@ msgid "Recent Updates" msgstr "Actualizaciones recientes" msgid "more" -msgstr "" +msgstr "más" msgid "My Statistics" msgstr "Mis estadísticas" diff --git a/po/fi.po b/po/fi.po index e24409a0..68499671 100644 --- a/po/fi.po +++ b/po/fi.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" "fi/)\n" "Language: fi\n" @@ -882,6 +882,9 @@ msgstr "" msgid "Real Name" msgstr "Oikea nimi" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC nikki" @@ -959,6 +962,9 @@ msgstr "Lähetä ilmoitus uusista kommnteista" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Päivitä" @@ -1059,6 +1065,9 @@ msgstr "Äännestä pakettia" msgid "Disable notifications" msgstr "En halua enää ilmoituksia" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "Hallitse ylläpitäjäkumppaneita" @@ -1240,6 +1249,26 @@ msgstr "" msgid "Merge into" msgstr "Yhdistä pakettiin" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1260,8 +1289,10 @@ msgid "Date" msgstr "" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1359,9 +1390,10 @@ msgstr[1] "" msgid "Version" msgstr "Versio" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/fr.po b/po/fr.po index b05f0e96..ec4cbf34 100644 --- a/po/fr.po +++ b/po/fr.po @@ -5,7 +5,7 @@ # Translators: # Antoine Lubineau , 2012 # Antoine Lubineau , 2012-2016 -# Cedric Girard , 2011,2014 +# Cedric Girard , 2011,2014,2016 # lordheavy , 2011 # lordheavy , 2013-2014 # lordheavy , 2011-2012 @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 21:38+0000\n" -"Last-Translator: Antoine Lubineau \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-08 09:34+0000\n" +"Last-Translator: Cedric Girard \n" "Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" "fr/)\n" "Language: fr\n" @@ -536,7 +536,7 @@ msgstr "" "paquets." msgid "Submit Request" -msgstr "Soumettre la demande" +msgstr "Soumettre une demande" msgid "Close Request" msgstr "Fermer la requête" @@ -931,6 +931,9 @@ msgstr "caché" msgid "Real Name" msgstr "Nom réel" +msgid "Homepage" +msgstr "Accueil" + msgid "IRC Nick" msgstr "Pseudo IRC" @@ -1012,6 +1015,9 @@ msgstr "Avertir des nouveaux commentaires" msgid "Notify of package updates" msgstr "Notifications de mises à jour de paquets" +msgid "Notify of ownership changes" +msgstr "Notifier des changements de propriétaire" + msgid "Update" msgstr "Mise à jour" @@ -1115,6 +1121,9 @@ msgstr "Voter pour ce paquet" msgid "Disable notifications" msgstr "Désactiver les notifications" +msgid "Enable notifications" +msgstr "Activer les notifications" + msgid "Manage Co-Maintainers" msgstr "Gérer les co-mainteneurs" @@ -1301,6 +1310,40 @@ msgstr "Rendre orphelin" msgid "Merge into" msgstr "Fusionner dans" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"En soumettant une requète de suppression, vous demandez à un utilisateur de " +"confiance de supprimer le paquet de base. Ce type de requète doit être " +"utilisé pour les doublons, les logiciels abandonnés par l'upstream ainsi que " +"pour les paquets illégaux ou irréparables." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"En soumettant une requète de fusion, vous demandez à un utilisateur de " +"confiance de supprimer le paquet de base et de transférer les votes et les " +"commentaires vers un autre paquet de base. Fusionner un paquet n'impacte pas " +"le dépot Git correspondant. Assurez-vous de mettre à jour l'historique Git " +"du paquet cible vous-même." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"En soumettant une requète pour rendre orphelin, vous demandez à un " +"utilisateur de confiance de retirer le mainteneur du paquet de base. Merci " +"de ne faire ceci que si le paquet nécessite l'action d'un mainteneur, que le " +"mainteneur ne répond pas et que vous avez préalablement essayé de contacter " +"le mainteneur." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1321,8 +1364,10 @@ msgid "Date" msgstr "Date" #, php-format -msgid "~%d days left" -msgstr "~%d jours restants" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "~%d jour restant" +msgstr[1] "~%d jours restants" #, php-format msgid "~%d hour left" @@ -1420,12 +1465,13 @@ msgstr[1] "%d paquets trouvés." msgid "Version" msgstr "Version" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" "La popularité est calculée à partir de la somme de tous les votes, chacun " -"étant pondéré par un facteur de 0.98 par jour depuis sa création." +"étant pondéré par un facteur de %.2f par jour depuis sa création." msgid "Yes" msgstr "Oui" diff --git a/po/he.po b/po/he.po index bfcdf8bc..c660b103 100644 --- a/po/he.po +++ b/po/he.po @@ -3,14 +3,16 @@ # This file is distributed under the same license as the AUR package. # # Translators: +# GenghisKhan , 2016 # Lukas Fleischer , 2011 +# Yaron Shahrabani , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-11 14:16+0000\n" +"Last-Translator: Yaron Shahrabani \n" "Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" "he/)\n" "Language: he\n" @@ -20,20 +22,20 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Page Not Found" -msgstr "" +msgstr "העמוד לא נמצא" msgid "Sorry, the page you've requested does not exist." -msgstr "" +msgstr "העמוד שביקשת אינו קיים, עמך הסליחה." msgid "Service Unavailable" -msgstr "" +msgstr "השירות אינו זמין" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "אל בהלה! אתר זה הושבת לטובת עבודות תחזוקה. נשוב במהרה." msgid "Account" -msgstr "" +msgstr "חשבון" msgid "Accounts" msgstr "חשבונות" @@ -51,23 +53,23 @@ msgid "Use this form to search existing accounts." msgstr "נא להשתמש בטופס על מנת לחפש אחר חשבונות קיימים." msgid "You must log in to view user information." -msgstr "עליך להתחבר על מנת לצפות בנתוני משתמש." +msgstr "עליך להיכנס על מנת לצפות בנתוני משתמש." msgid "Add Proposal" msgstr "הוספת הצעה" msgid "Invalid token for user action." -msgstr "" +msgstr "אסימון שגוי לפעולת משתמש." msgid "Username does not exist." msgstr "שם המשתמש לא קיים." #, php-format msgid "%s already has proposal running for them." -msgstr "%s יש כבר הצעה קיימת." +msgstr "ל־%s יש כבר הצעה קיימת." msgid "Invalid type." -msgstr "" +msgstr "סוג שגוי." msgid "Proposal cannot be empty." msgstr "הצעה לא יכולה להיות ריקה." @@ -79,7 +81,7 @@ msgid "Submit a proposal to vote on." msgstr "שליחת הצבעה עבור הפעלת הצבעה." msgid "Applicant/TU" -msgstr "" +msgstr "מועמד/משתמש מהימן" msgid "(empty if not applicable)" msgstr "(ריק אם אינה מתאימה)" @@ -88,13 +90,13 @@ msgid "Type" msgstr "סוג" msgid "Addition of a TU" -msgstr "" +msgstr "הוספת משתמש מהימן" msgid "Removal of a TU" -msgstr "" +msgstr "הסרת משתמש מהימן" msgid "Removal of a TU (undeclared inactivity)" -msgstr "" +msgstr "הסרת משתמש מהימן (חוסר פעילות בלתי מוצהרת)" msgid "Amendment of Bylaws" msgstr "" @@ -106,10 +108,10 @@ msgid "Submit" msgstr "שליחה" msgid "Manage Co-maintainers" -msgstr "" +msgstr "ניהול שותפים לתחזוקה" msgid "Edit comment" -msgstr "" +msgstr "עריכת תגובה" msgid "Home" msgstr "בית" @@ -119,52 +121,62 @@ msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +"ברוך בואך ל־AUR, מאגר תרומות המשתמשים של ארץ׳! נא לקרוא את %sהכללים למשתמש ב־" +"AUR%s ואת %sהכללים למשתמשים מהימנים ב־AUR%s." #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +"הגדרות PKGBUILD שנתרמו %sחייבות%s לעמוד ב%sתקני האריזה של ארץ׳%s אחרת הן " +"תמחקנה!" msgid "Remember to vote for your favourite packages!" -msgstr "" +msgstr "לא לשכוח להצביע לחבילות המועדפות עליך!" msgid "Some packages may be provided as binaries in [community]." -msgstr "" +msgstr "יתכן שחלק מהחבילות מסופקות בתור קבצים בינריים תחת [community] (קהילה)." msgid "DISCLAIMER" -msgstr "" +msgstr "הבהרה" msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"חבילות AUR הן תוכן שנוצר על ידי המשתמשים. כל שימוש בקבצים שסופקו הוא על " +"אחריותך בלבד." msgid "Learn more..." -msgstr "" +msgstr "מידע נוסף..." msgid "Support" -msgstr "" +msgstr "תמיכה" msgid "Package Requests" -msgstr "" +msgstr "בקשות חבילה" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"ישנם שלושה סוגים של בקשות שניתן להגיש בתיבה %sפעולות על חבילה%s בעמוד פרטי " +"החבילה:" msgid "Orphan Request" -msgstr "" +msgstr "בקשה יתומה" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"הגשת בקשה לניתוק בעלות על חבילה, למשל כאשר המתחזק אינו פעיל והחבילה סומנה " +"כלא עדכנית במשך זמן מה." msgid "Deletion Request" -msgstr "" +msgstr "בקשת מחיקה" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " @@ -173,7 +185,7 @@ msgid "" msgstr "" msgid "Merge Request" -msgstr "" +msgstr "בקשת מיזוג" msgid "" "Request a package to be merged into another one. Can be used when a package " @@ -187,7 +199,7 @@ msgid "" msgstr "" msgid "Submitting Packages" -msgstr "" +msgstr "שליחת חבילות" #, php-format msgid "" @@ -195,9 +207,11 @@ msgid "" "packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +"Git על גבי SSH היא התשתית העדכנית להגשת חבילות ל־AUR. ניתן לעיין בסעיף " +"%sהגשת חבילות%s בעמוד Arch User Repository ב־ArchWiki לקבלת פרטים נוספים." msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "טביעות האצבע מסוג SSH הבאות נמצאות בשימוש עבור AUR:" msgid "Discussion" msgstr "דיון" @@ -210,7 +224,7 @@ msgid "" msgstr "" msgid "Bug Reporting" -msgstr "" +msgstr "דיווח על באגים" #, php-format msgid "" @@ -221,10 +235,10 @@ msgid "" msgstr "" msgid "Package Search" -msgstr "" +msgstr "חיפוש חבילות" msgid "Adopt" -msgstr "" +msgstr "אימוץ" msgid "Vote" msgstr "הצבעה" @@ -239,7 +253,7 @@ msgid "UnNotify" msgstr "ביטול התרעה" msgid "UnFlag" -msgstr "" +msgstr "ביטול סימון" msgid "Login" msgstr "כניסה" @@ -252,10 +266,10 @@ msgid "Logout" msgstr "ניתוק" msgid "Enter login credentials" -msgstr "" +msgstr "נא להזין פרטי גישה" msgid "User name or email address" -msgstr "" +msgstr "שם משתמש או כתובת דוא״ל" msgid "Password" msgstr "ססמה" @@ -264,12 +278,12 @@ msgid "Remember me" msgstr "שמירת הפרטים" msgid "Forgot Password" -msgstr "" +msgstr "שכחתי את הססמה" #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" +msgstr "כניסה באמצעות HTTP מנוטרלת. נא %sלעבור ל־HTTPs%s אם ברצונך להיכנס." msgid "Search Criteria" msgstr "קריטריונים לחיפוש" @@ -291,16 +305,16 @@ msgid "Your password must be at least %s characters." msgstr "הססמה חייבת להיות באורך של %s אותיות לפחות." msgid "Invalid e-mail." -msgstr "" +msgstr "כתובת דוא״ל שגויה." msgid "Password Reset" msgstr "איפוס ססמה" msgid "Check your e-mail for the confirmation link." -msgstr "" +msgstr "נא לבדוק בתיבת הדוא״ל שלך אם התקבל קישור לאישור." msgid "Your password has been reset successfully." -msgstr "" +msgstr "הססמה שלך התאפסה בהצלחה." msgid "Confirm your e-mail address:" msgstr "אישור כתובת הדוא״ל שלך" @@ -312,13 +326,15 @@ msgid "Confirm your new password:" msgstr "אישור הססמה החדשה:" msgid "Continue" -msgstr "" +msgstr "המשך" #, php-format msgid "" "If you have forgotten the e-mail address you used to register, please send a " "message to the %saur-general%s mailing list." msgstr "" +"אם שכחת את כתובת הדוא״ל בה השתמש כדי להירשם, נא לשלוח הודעה לקבוצת הדיוור " +"%saur-general%s." msgid "Enter your e-mail address:" msgstr "נא להזין את כתובת הדוא״ל שלך:" @@ -326,23 +342,23 @@ msgstr "נא להזין את כתובת הדוא״ל שלך:" msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" +msgstr "החבילות הבאות לא נותקו מבעליהן, נא לסמן את התיבה לאישור." msgid "Cannot find package to merge votes and comments into." -msgstr "" +msgstr "לא ניתן למצוא חבילה למיזוג הצבעות ותגובות אליה." msgid "Cannot merge a package base with itself." -msgstr "" +msgstr "אי אפשר למזג בסיס חבילה עם עצמו." msgid "" "The selected packages have not been deleted, check the confirmation checkbox." msgstr "החבילות שנבחרו לא נמחקו, נא לבחור בתיבת האישור." msgid "Package Deletion" -msgstr "" +msgstr "מחיקת חבילות" msgid "Delete Package" -msgstr "" +msgstr "מחיקת חבילה" #, php-format msgid "" @@ -351,22 +367,22 @@ msgid "" msgstr "" msgid "Deletion of a package is permanent. " -msgstr "" +msgstr "מחיקת חבילה היא לצמיתות." msgid "Select the checkbox to confirm action." -msgstr "" +msgstr "נא לבחור את תיבת הסימון כדי לאשר את הפעולה." msgid "Confirm package deletion" -msgstr "" +msgstr "אישור מחיקת חבילה" msgid "Delete" -msgstr "" +msgstr "מחיקה" msgid "Only Trusted Users and Developers can delete packages." -msgstr "" +msgstr "רק משתמשים מהימנים ומפתחים יכולים למחוק חבילות." msgid "Disown Package" -msgstr "" +msgstr "ניתוק בעלות על חבילה" #, php-format msgid "" @@ -379,25 +395,27 @@ msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"על ידי סימון תיבת הבחירה, ניתן אישורך לניתוק הבעלות על חבילה והעברת הבעלות " +"אל %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" +msgstr "על ידי סימון תיבת הבחירה, נתת את אישורך לניתוק הבעלות על חבילה." msgid "Confirm to disown the package" -msgstr "" +msgstr "אישור ניתוק בעלות החבילה" msgid "Disown" -msgstr "" +msgstr "ניתוק בעלות" msgid "Only Trusted Users and Developers can disown packages." -msgstr "" +msgstr "רק משתמשים מהימנים ומפתחים יכולים לנתק בעלות של חבילות." msgid "Flag Comment" -msgstr "" +msgstr "סימון התגובה" msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "סימון תגובה כבלתי עדכנית" #, php-format msgid "" @@ -415,70 +433,72 @@ msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"נא להזין את הפרטים על מדוע החבילה אינה בתוקף, מומלץ להוסיף קישורים להכרזות " +"המתאימות או לקובצי הגרסה העדכנית." msgid "Comments" -msgstr "" +msgstr "תגובות" msgid "Flag" -msgstr "" +msgstr "סימון" msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "רק משתמשים רשומים יכולים לסמן חבילות כפגות תוקף." msgid "Package Merging" -msgstr "" +msgstr "מיזוג חבילות" msgid "Merge Package" -msgstr "" +msgstr "מיזוג חבילה" #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" msgid "The following packages will be deleted: " -msgstr "" +msgstr "החבילות הבאות תימחקנה:" msgid "Once the package has been merged it cannot be reversed. " -msgstr "" +msgstr "לאחר מיזוג החבילות לא ניתן לחזור אחורה בתהליך." msgid "Enter the package name you wish to merge the package into. " -msgstr "" +msgstr "נא להזין את שם החבילה שאליה ברצונך למזג את החבילה." msgid "Merge into:" -msgstr "" +msgstr "מיזוג לתוך:" msgid "Confirm package merge" -msgstr "" +msgstr "אימות מיזוג חבילה" msgid "Merge" -msgstr "" +msgstr "מיזוג" msgid "Only Trusted Users and Developers can merge packages." -msgstr "" +msgstr "רק משתמשים מהימנים ומפתחים יכולים למזג חבילות." msgid "Submit Request" -msgstr "" +msgstr "שליחת בקשה" msgid "Close Request" -msgstr "" +msgstr "סגירת בקשה" msgid "First" -msgstr "" +msgstr "ראשון" msgid "Previous" -msgstr "" +msgstr "הקודם" msgid "Next" msgstr "הבא" msgid "Last" -msgstr "" +msgstr "אחרון" msgid "Requests" -msgstr "" +msgstr "בקשות" msgid "Register" -msgstr "" +msgstr "הרשמה" msgid "Use this form to create an account." msgstr "ניתן להשתמש בטופס זה על מנת ליצור חשבון." @@ -493,7 +513,7 @@ msgid "Voting is closed for this proposal." msgstr "ההצבעה סגורה עבור הצעה זו." msgid "Only Trusted Users are allowed to vote." -msgstr "" +msgstr "רק משתמשים מהימנים מורשים להצביע." msgid "You cannot vote in an proposal about you." msgstr "אין באפשרותך להצביע עבור הצעה הקשורה בך." @@ -505,13 +525,13 @@ msgid "Vote ID not valid." msgstr "מס׳ הזיהוי של ההצבעה אינו תקין." msgid "Current Votes" -msgstr "הצבעות נוכחיות" +msgstr "קולות נוכחיים" msgid "Past Votes" -msgstr "" +msgstr "קולות עבר" msgid "Voters" -msgstr "" +msgstr "מצביעים" msgid "" "Account registration has been disabled for your IP address, probably due to " @@ -519,7 +539,7 @@ msgid "" msgstr "" msgid "Missing User ID" -msgstr "חסר מס׳ הזיהוי של המשתמש" +msgstr "מס׳ הזיהוי של המשתמש חסר" msgid "The username is invalid." msgstr "שם המשתמש אינו חוקי." @@ -538,58 +558,60 @@ msgid "The email address is invalid." msgstr "כתובת הדוא״ל שהוזנה אינה תקינה." msgid "The PGP key fingerprint is invalid." -msgstr "" +msgstr "טביעת האצבע מסוג PGP שגויה." msgid "The SSH public key is invalid." -msgstr "" +msgstr "מפתח ה־SSH הציבורי שגוי." msgid "Cannot increase account permissions." -msgstr "" +msgstr "לא ניתן להגדיל את הרשאות החשבון." msgid "Language is not currently supported." msgstr "שפה כרגע לא נתמכת." #, php-format msgid "The username, %s%s%s, is already in use." -msgstr "" +msgstr "שם המשתמש, %s%s%s, כבר נמצא בשימוש." #, php-format msgid "The address, %s%s%s, is already in use." -msgstr "" +msgstr "הכתובת, %s%s%s, כבר נמצאת בשימוש." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "מפתח ה־SSH הציבורי, %s%s%s, כבר נמצא בשימוש." #, php-format msgid "Error trying to create account, %s%s%s." -msgstr "" +msgstr "אירעה שגיאה בניסיון ליצירת חשבון, %s%s%s." #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "" +msgstr "החשבון, %s%s%s, נוצר בהצלחה." msgid "A password reset key has been sent to your e-mail address." -msgstr "" +msgstr "מפתח איפוס ססמה נשלח לכתובת הדוא״ל שלך." msgid "Click on the Login link above to use your account." -msgstr "" +msgstr "נא ללחוץ על קישור הכניסה להלן כדי להשתמש בחשבון שלך." #, php-format msgid "No changes were made to the account, %s%s%s." -msgstr "" +msgstr "לא בוצעו שינויים בחשבון, %s%s%s." #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "" +msgstr "החשבון, %s%s%s, השתנה בהצלחה." msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +"כתובת הכניסה מנוטרלת לכתובת ה־ IP שלך, כנראה עקב מתקפות ספאם מתמשכות. אנו " +"מתנצלים על אי הנוחות." msgid "Account suspended" -msgstr "" +msgstr "חשבון מושעה" #, php-format msgid "" @@ -599,35 +621,35 @@ msgid "" msgstr "" msgid "Bad username or password." -msgstr "" +msgstr "שם המשתמש או הססמה שגויים." msgid "An error occurred trying to generate a user session." -msgstr "" +msgstr "אירעה שגיאה בעת הניסיון ליצירת הפעלת משתמש." msgid "Invalid e-mail and reset key combination." -msgstr "" +msgstr "השילוב בין כתובת דוא״ל למפתח איפוס שגוי." msgid "None" -msgstr "" +msgstr "ללא" #, php-format msgid "View account information for %s" -msgstr "" +msgstr "הצגת פרטי החשבון %s" msgid "Package base ID or package base name missing." msgstr "" msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "אין לך הרשאה לערוך את התגובה הזו." msgid "Comment does not exist." -msgstr "" +msgstr "התגובה אינה קיימת." msgid "Comment cannot be empty." -msgstr "" +msgstr "התגובה לא יכולה להישאר ריקה." msgid "Comment has been added." -msgstr "" +msgstr "נוספה תגובה." msgid "You must be logged in before you can edit package information." msgstr "עליך להיכנס לפני שיהיה באפשרותך לערוך נתוני חבילה." @@ -636,19 +658,19 @@ msgid "Missing comment ID." msgstr "חסר מס׳ זיהוי להערה." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "אי אפשר להצמיד למעלה מ־5 תגובות." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "אין לך הרשאה להצמיד תגובה זו." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "אין לך הרשה לבטל את ההצמדה של תגובה זו." msgid "Comment has been pinned." -msgstr "" +msgstr "התגובה הוצמדה." msgid "Comment has been unpinned." -msgstr "" +msgstr "הצמדת התגובה בוטלה." msgid "Error retrieving package details." msgstr "שגיאה בקבלת נתוני חבילה." @@ -663,7 +685,7 @@ msgid "You did not select any packages to flag." msgstr "לא בחרת שום חבילות לסימון." msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" +msgstr "החבילות הנבחרות לא סומנו, נא לכתוב תגובה." msgid "The selected packages have been flagged out-of-date." msgstr "החבילות שנבחרו מסומנות כלא עדכניות." @@ -678,7 +700,7 @@ msgid "The selected packages have been unflagged." msgstr "החבילות שנבחרו בוטלו מהסימון." msgid "You do not have permission to delete packages." -msgstr "" +msgstr "אין לך הרשאה למחוק חבילות." msgid "You did not select any packages to delete." msgstr "לא בחרת שום חבילות למחיקה." @@ -690,19 +712,19 @@ msgid "You must be logged in before you can adopt packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לאמץ חבילות." msgid "You must be logged in before you can disown packages." -msgstr "עליך להיכנס לפני שיהיה באפשרותך לבטל בעלות מחבילות." +msgstr "עליך להיכנס לפני שיהיה באפשרותך לנתק בעלות על חבילות." msgid "You did not select any packages to adopt." msgstr "לא בחרת שום חבילות לאימוץ." msgid "You did not select any packages to disown." -msgstr "לא בחרת שום חבילות להסרת בעלותך מהן." +msgstr "לא בחרת שום חבילות לניתוק בעלותך מהן." msgid "The selected packages have been adopted." msgstr "החבילות שנבחרו אומצו." msgid "The selected packages have been disowned." -msgstr "החבילות המסומנות ננטשו" +msgstr "החבילות המסומנות ננטשו על ידי בעליהן." msgid "You must be logged in before you can vote for packages." msgstr "עליך להיכנס לפני שתהיה באפשרותך להצביע לחבילות." @@ -731,10 +753,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "הוסרת מרשימה ההתרעות עבור ההערות של %s." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "אין לך הרשאה לשחזר את התגובה הזו." msgid "Comment has been undeleted." -msgstr "" +msgstr "התגובה שוחזרה." msgid "You are not allowed to delete this comment." msgstr "אין לך הרשאה למחוק הערה זו." @@ -743,7 +765,7 @@ msgid "Comment has been deleted." msgstr "הערה נמחקה." msgid "Comment has been edited." -msgstr "" +msgstr "התגובה נערכה." msgid "You are not allowed to edit the keywords of this package base." msgstr "" @@ -752,56 +774,56 @@ msgid "The package base keywords have been updated." msgstr "" msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "אין לך הרשאה לנהל את מתחזקי המשנה לבסיס חבילה זה." #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "שם משתמש שגוי: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "מתחזקי המשנה של בסיס החבילה עודכנו." msgid "View packages details for" -msgstr "" +msgstr "הצגת פרטי החבילה עבור" #, php-format msgid "requires %s" msgstr "" msgid "You must be logged in to file package requests." -msgstr "" +msgstr "עליך להיכנס כדי להגיש בקשות חבילה." msgid "Invalid name: only lowercase letters are allowed." msgstr "שם לא חוקי: רק אותיות קטנות מותרות." msgid "The comment field must not be empty." -msgstr "" +msgstr "שדה התגובה לא יכול להישאר ריק." msgid "Invalid request type." -msgstr "" +msgstr "סוג הבקשה שגוי." msgid "Added request successfully." -msgstr "" +msgstr "התגובה נוספה בהצלחה." msgid "Invalid reason." -msgstr "" +msgstr "הסיבה שגויה." msgid "Only TUs and developers can close requests." -msgstr "" +msgstr "רק משתמשים מהימנים ומפתחים יכולים לסגור בקשות." msgid "Request closed successfully." -msgstr "" +msgstr "הבקשה נסגרה בהצלחה." #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" +msgstr "ניתן להשתמש בטופס זה כדי למחוק את חשבון ה־AUR בשם %s לצמיתות." #, php-format msgid "%sWARNING%s: This action cannot be undone." -msgstr "" +msgstr "%sאזהרה%s: לא ניתן לחזור בך מפעולה זו." msgid "Confirm deletion" -msgstr "" +msgstr "אימות מחיקה" msgid "Username" msgstr "שם משתמש" @@ -816,7 +838,7 @@ msgid "Developer" msgstr "מפתח" msgid "Trusted User & Developer" -msgstr "" +msgstr "משתמש מהימן ומפתח" msgid "Email Address" msgstr "כתובת דוא״ל" @@ -827,23 +849,26 @@ msgstr "" msgid "Real Name" msgstr "שם אמתי" +msgid "Homepage" +msgstr "עמוד הבית" + msgid "IRC Nick" -msgstr "כינוי ב־IRC" +msgstr "כינוי IRC" msgid "PGP Key Fingerprint" -msgstr "" +msgstr "טביעת אצבע מסוג PGP" msgid "Status" msgstr "מצב" msgid "Inactive since" -msgstr "" +msgstr "אין פעילות מאז" msgid "Active" msgstr "פעיל" msgid "Last Login" -msgstr "" +msgstr "כניסה אחרונה" msgid "Never" msgstr "לעולם" @@ -852,11 +877,11 @@ msgid "View this user's packages" msgstr "צפייה בחבילות המשתמש" msgid "Edit this user's account" -msgstr "" +msgstr "עריכת החשבון של משתמש זה" #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "" +msgstr "נא ללחוץ %sכאן%s אם רצונך הוא למחוק את החשבון הזה לצמיתות." msgid "required" msgstr "נדרש" @@ -871,15 +896,15 @@ msgid "Account Suspended" msgstr "חשבון מושעה" msgid "Inactive" -msgstr "" +msgstr "בלתי פעיל" msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" +msgstr "נא לוודא שהזנת את כתובת הדוא״ל שלך כראוי, אחרת חשבונך יינעל." msgid "Hide Email Address" -msgstr "" +msgstr "הסתרת כתובת דוא״ל" msgid "Re-type password" msgstr "הקלדת הססמה מחדש" @@ -890,19 +915,22 @@ msgstr "שפה" msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." -msgstr "" +msgstr "המידע הבא נחוץ רק אם ברצונך להגיש חבילות למאגר החבילות של ארץ׳." msgid "SSH Public Key" -msgstr "" +msgstr "מפתח SSH ציבורי" msgid "Notification settings" -msgstr "" +msgstr "הגדרות התרעה" msgid "Notify of new comments" -msgstr "" +msgstr "להודיע לי על תגובות חדשות" msgid "Notify of package updates" -msgstr "" +msgstr "להודיע לי ל עדכונים בחבילה" + +msgid "Notify of ownership changes" +msgstr "להודיע לי על שינויים בבעלות" msgid "Update" msgstr "עדכון" @@ -923,7 +951,7 @@ msgid "Suspended" msgstr "השעייה" msgid "Edit" -msgstr "" +msgstr "עריכה" msgid "Less" msgstr "פחות" @@ -938,12 +966,13 @@ msgstr "אין יותר תוצאות להצגה." msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"ניתן להשתמש בטופס זה כדי להוסיף מתחזקי משנה %s%s%s (שם משתמש אחד בשורה):" msgid "Users" -msgstr "" +msgstr "משתמשים" msgid "Save" -msgstr "" +msgstr "שמירה" #, php-format msgid "Flagged Out-of-Date Comment: %s" @@ -955,35 +984,35 @@ msgstr "" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s אינה מסומנת כפגת תוקף." msgid "Return to Details" -msgstr "" +msgstr "חזרה לפרטים" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "כל הזכויות שמורות %s 2004-%d לצוות הפיתוח של aurweb." msgid "My Packages" msgstr "החבילות שלי" msgid " My Account" -msgstr "" +msgstr "החשבון שלי" msgid "Package Actions" -msgstr "" +msgstr "פעולות חבילה" msgid "View PKGBUILD" -msgstr "" +msgstr "הצגת ה־PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "הצגת השינויים" msgid "Download snapshot" -msgstr "" +msgstr "הורדת לכידה עדכנית" msgid "Search wiki" -msgstr "" +msgstr "חיפוש בוויקי" #, php-format msgid "Flagged out-of-date (%s)" @@ -993,43 +1022,46 @@ msgid "Flag package out-of-date" msgstr "" msgid "Unflag package" -msgstr "" +msgstr "ביטול סימון חבילה" msgid "Remove vote" -msgstr "" +msgstr "הסרת הצבעה" msgid "Vote for this package" -msgstr "" +msgstr "להצביע לחבילה זו" msgid "Disable notifications" -msgstr "" +msgstr "נטרול התרעות" + +msgid "Enable notifications" +msgstr "הפעלת התרעות" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "ניהול מתחזקי משנה" #, php-format msgid "%d pending request" msgid_plural "%d pending requests" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "בקשה %d ממתינה" +msgstr[1] "%d בקשות ממתינות" msgid "Adopt Package" -msgstr "" +msgstr "אימוץ חבילה" msgid "unknown" -msgstr "" +msgstr "לא מוכר" msgid "Package Base Details" -msgstr "" +msgstr "פרטי בסיס החבילה" msgid "Git Clone URL" -msgstr "" +msgstr "כתובת השכפול מ־Git" msgid "read-only" -msgstr "" +msgstr "לקריאה בלבד" msgid "Keywords" -msgstr "" +msgstr "מילות מפתח" msgid "Submitter" msgstr "" @@ -1038,120 +1070,120 @@ msgid "Maintainer" msgstr "מתחזק" msgid "Last Packager" -msgstr "" +msgstr "נארז לאחרונה ע״י" msgid "Votes" msgstr "הצבעות" msgid "Popularity" -msgstr "" +msgstr "פופולריות" msgid "First Submitted" -msgstr "" +msgstr "נשלחה לראשונה" msgid "Last Updated" -msgstr "" +msgstr "עודכנה באחרונה" #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "עריכת תגובה עבור: %s" msgid "Add Comment" -msgstr "" +msgstr "הוספת תגובה" msgid "View all comments" -msgstr "" +msgstr "הצגת כל התגובות" msgid "Pinned Comments" -msgstr "" +msgstr "תגובות נעוצות" msgid "Latest Comments" -msgstr "" +msgstr "התגובות האחרונות" #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "נכתבה תגובה ע״י %s על %s" #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "תגובה אלמונית על %s" #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "נמחקה ב־%s ע״י %s" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "נמחקה ב־%s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "נערכה בתאריך %s ע״י %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "נערכה ב־%s" msgid "Undelete comment" -msgstr "" +msgstr "ביטול מחיקת התגובה" msgid "Delete comment" msgstr "מחיקת הערה" msgid "Pin comment" -msgstr "" +msgstr "הצמדת התגובה" msgid "Unpin comment" -msgstr "" +msgstr "ביטול הצמדת התגובה" msgid "All comments" -msgstr "" +msgstr "כל התגובות" msgid "Package Details" msgstr "נתוני חבילה" msgid "Package Base" -msgstr "" +msgstr "בסיס החבילה" msgid "Description" msgstr "תיאור" msgid "Upstream URL" -msgstr "" +msgstr "כתובת מאגר המקור" msgid "Visit the website for" -msgstr "" +msgstr "ביקור באתר של" msgid "Licenses" -msgstr "" +msgstr "רישיונות" msgid "Groups" -msgstr "" +msgstr "קבוצות" msgid "Conflicts" -msgstr "" +msgstr "התנגשויות" msgid "Provides" -msgstr "" +msgstr "מספקת" msgid "Replaces" -msgstr "" +msgstr "מחליפה" msgid "Dependencies" -msgstr "תלות" +msgstr "תלויות" msgid "Required by" -msgstr "נדרש על ידי" +msgstr "נדרשת על ידי" msgid "Sources" -msgstr "" +msgstr "מקורות" #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" +msgstr "ניתן להשתמש בטופס זה כדי לסגור את הבקשה לבסיס החבילה %s%s%s." msgid "Note" -msgstr "" +msgstr "הערה" msgid "" "The comments field can be left empty. However, it is highly recommended to " @@ -1159,13 +1191,13 @@ msgid "" msgstr "" msgid "Reason" -msgstr "" +msgstr "סיבה" msgid "Accepted" -msgstr "" +msgstr "התקבל" msgid "Rejected" -msgstr "" +msgstr "נדחה" #, php-format msgid "" @@ -1174,81 +1206,103 @@ msgid "" msgstr "" msgid "Request type" -msgstr "" +msgstr "סוג הבקשה" msgid "Deletion" -msgstr "" +msgstr "מחיקה" msgid "Orphan" -msgstr "" +msgstr "יתומה" msgid "Merge into" +msgstr "מיזוג לתוך" + +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." msgstr "" #, php-format msgid "%d package request found." msgid_plural "%d package requests found." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "נמצאה בקשה אחת (%d) לחבילה." +msgstr[1] "נמצאו %d בקשות לחבילות." #, php-format msgid "Page %d of %d." -msgstr "" +msgstr "עמוד %d מתוך %d." msgid "Package" -msgstr "" +msgstr "חבילה" msgid "Filed by" -msgstr "" +msgstr "הוגש ע״י" msgid "Date" -msgstr "" +msgstr "תאריך" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "נותר ~%d אחד" +msgstr[1] "נותרו ~%d ימים" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "נותרה שעה ~%d" +msgstr[1] "~%d שעות נותרו" msgid "<1 hour left" -msgstr "" +msgstr "נותרה פחות משעה" msgid "Accept" -msgstr "" +msgstr "קבלה" msgid "Locked" -msgstr "" +msgstr "ננעל" msgid "Close" -msgstr "" +msgstr "סגירה" msgid "Closed" -msgstr "" +msgstr "סגור" msgid "Name, Description" -msgstr "" +msgstr "שם, תיאור" msgid "Name Only" -msgstr "" +msgstr "שם בלבד" msgid "Exact Name" -msgstr "" +msgstr "שם מדויק" msgid "Exact Package Base" -msgstr "" +msgstr "בסיס החבילה המדויק" msgid "All" -msgstr "" +msgstr "הכול" msgid "Flagged" -msgstr "" +msgstr "מסומנת" msgid "Not Flagged" -msgstr "" +msgstr "לא מסומנת" msgid "Name" msgstr "שם" @@ -1257,22 +1311,22 @@ msgid "Voted" msgstr "הצביעו" msgid "Last modified" -msgstr "" +msgstr "מועד שינוי אחרון" msgid "Ascending" -msgstr "" +msgstr "עולה" msgid "Descending" -msgstr "" +msgstr "יורד" msgid "Enter search criteria" -msgstr "" +msgstr "נא להזין תנאי חיפוש" msgid "Search by" msgstr "חיפוש לפי" msgid "Out of Date" -msgstr "" +msgstr "לא עדכני" msgid "Sort by" msgstr "סידור לפי" @@ -1298,15 +1352,16 @@ msgstr "אין חבילות התואמות לנתוני החיפוש שלך." #, php-format msgid "%d package found." msgid_plural "%d packages found." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "נמצאה חבילה %d." +msgstr[1] "נמצאו %d חבילות." msgid "Version" -msgstr "" +msgstr "גרסה" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" @@ -1325,7 +1380,7 @@ msgid "Adopt Packages" msgstr "אימוץ חבילות" msgid "Disown Packages" -msgstr "שחרור בעלות על חבילות" +msgstr "ניתוק בעלות על חבילות" msgid "Delete Packages" msgstr "מחיקת חבילות" @@ -1340,37 +1395,37 @@ msgid "Search" msgstr "חיפוש" msgid "Statistics" -msgstr "" +msgstr "סטטיסטיקות" msgid "Orphan Packages" -msgstr "" +msgstr "חבילות יתומות" msgid "Packages added in the past 7 days" -msgstr "" +msgstr "חבילות שנוספו בשבוע החולף" msgid "Packages updated in the past 7 days" -msgstr "" +msgstr "חבילות שעודכנו בשבוע החולף" msgid "Packages updated in the past year" -msgstr "" +msgstr "חבילות שעודכנו בשנה החולפת" msgid "Packages never updated" -msgstr "" +msgstr "חבילות שלא עודכנו מעולם" msgid "Registered Users" -msgstr "" +msgstr "משתמשים רשומים" msgid "Trusted Users" -msgstr "" +msgstr "משתמשים מהימנים" msgid "Recent Updates" -msgstr "" +msgstr "עדכונים אחרונים" msgid "more" -msgstr "" +msgstr "עוד" msgid "My Statistics" -msgstr "" +msgstr "הסטטיסטיקות שלי" msgid "Proposal Details" msgstr "פרטי הצעה" @@ -1386,7 +1441,7 @@ msgid "End" msgstr "סוף" msgid "Result" -msgstr "" +msgstr "תוצאה" msgid "No" msgstr "לא" @@ -1398,13 +1453,13 @@ msgid "Total" msgstr "סך הכול" msgid "Participation" -msgstr "" +msgstr "השתתפות" msgid "Last Votes by TU" -msgstr "" +msgstr "הצבעות אחרונות של משתמשים מהימנים" msgid "Last vote" -msgstr "" +msgstr "הצבעה אחרונה" msgid "No results found." msgstr "תוצאות לא נמצאו." diff --git a/po/hr.po b/po/hr.po index 71c151c1..461dc288 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" "hr/)\n" "Language: hr\n" @@ -828,6 +828,9 @@ msgstr "" msgid "Real Name" msgstr "Vaše stvarno ime" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Nadimak na IRC-u" @@ -905,6 +908,9 @@ msgstr "" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Ažuriraj" @@ -1005,6 +1011,9 @@ msgstr "" msgid "Disable notifications" msgstr "" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1187,6 +1196,26 @@ msgstr "" msgid "Merge into" msgstr "" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1208,8 +1237,11 @@ msgid "Date" msgstr "" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" #, php-format msgid "~%d hour left" @@ -1309,9 +1341,10 @@ msgstr[2] "" msgid "Version" msgstr "" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/hu.po b/po/hu.po index 4c3bf829..8287d14d 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3,16 +3,17 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# György Balló , 2013 -# György Balló , 2011,2013-2015 +# György Balló , 2013 +# György Balló , 2011,2013-2016 +# György Balló , 2016 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-08 08:56+0000\n" +"Last-Translator: György Balló \n" "Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" "hu/)\n" "Language: hu\n" @@ -112,7 +113,7 @@ msgid "Manage Co-maintainers" msgstr "Társkarbantartók kezelése" msgid "Edit comment" -msgstr "" +msgstr "Hozzászólás szerkesztése" msgid "Home" msgstr "Honlap" @@ -146,6 +147,8 @@ msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Az AUR csomagok felhasználók által készített tartalmak. A szolgáltatott " +"fájlok használata csak saját felelősségre." msgid "Learn more..." msgstr "Tudj meg többet..." @@ -246,6 +249,11 @@ msgid "" "%sonly%s. To report packaging bugs contact the package maintainer or leave a " "comment on the appropriate package page." msgstr "" +"Ha találsz egy hibát az AUR webes felületén, kérünk, tölts ki egy " +"hibajelentést a %shibakövetőnkben%s. A hibakövetőt %scsak%s az AUR webes " +"felületén található hibák jelentésére használd. Csomagolási hibák " +"jelentéséhez lépj kapcsolatba a csomag fenntartójával, vagy hagyj egy " +"hozzászólást a megfelelő csomag oldalán." msgid "Package Search" msgstr "Csomag keresése" @@ -282,7 +290,7 @@ msgid "Enter login credentials" msgstr "Bejelentkezési adatok megadása" msgid "User name or email address" -msgstr "" +msgstr "Felhasználónév vagy e-mail cím" msgid "Password" msgstr "Jelszó" @@ -363,7 +371,7 @@ msgstr "" msgid "Cannot find package to merge votes and comments into." msgstr "" -"Nem található csomag, amelybe a szavazatok és megjegyzések beolvaszthatók " +"Nem található csomag, amelybe a szavazatok és hozzászólások beolvaszthatók " "lennének." msgid "Cannot merge a package base with itself." @@ -440,36 +448,42 @@ msgstr "" "Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." msgid "Flag Comment" -msgstr "" +msgstr "Hozzászólás jelölése" msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Csomag elvaultnak jelölése" #, php-format msgid "" "Use this form to flag the package base %s%s%s and the following packages out-" "of-date: " msgstr "" +"Használd ezt az űrlapot annak jelzésére, hogy a(z) %s%s%s alapcsomag és a " +"következő csomagok elavultak:" #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"Kérünk, %sne%s használd ezt az űrlapot hibák jelentéséhez. Használd a " +"csomaghozzászólásokat helyette." msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Add meg alább a részleteit, hogy miért avult el a csomag, lehetőleg " +"hivatkozásokkal a kiadási közleményre vagy az új kiadás tarballjára." msgid "Comments" -msgstr "Megjegyzések" +msgstr "Hozzászólások" msgid "Flag" msgstr "Megjelölés" msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "Csak regisztrált felhasználók jelölhetnek csomagokat elavultnak." msgid "Package Merging" msgstr "Csomag beolvasztása" @@ -507,7 +521,7 @@ msgstr "" "Csak megbízható felhasználók és fejlesztők tudnak csomagokat beolvasztani." msgid "Submit Request" -msgstr "" +msgstr "Kérelem beküldése" msgid "Close Request" msgstr "Kérelem lezárása" @@ -673,40 +687,40 @@ msgid "View account information for %s" msgstr "Fiók információinak megtekintése – %s" msgid "Package base ID or package base name missing." -msgstr "" +msgstr "Alapcsomag-azonosító vagy alapcsomagnév hiányzik." msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Nem szerkesztheted ezt a hozzászólást." msgid "Comment does not exist." -msgstr "" +msgstr "A hozzászólás nem létezik." msgid "Comment cannot be empty." -msgstr "" +msgstr "A hozzászólás nem lehet üres." msgid "Comment has been added." -msgstr "A megjegyzés hozzáadva." +msgstr "A hozzászólás hozzáadva." msgid "You must be logged in before you can edit package information." msgstr "A csomag információinak szerkesztéséhez be kell jelentkezned." msgid "Missing comment ID." -msgstr "Hiányzó megjegyzésazonosító." +msgstr "Hiányzó hozzászólásazonosító." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "5-nél több hozzászólás nem rögzíthető." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Nem rögzítheted ezt a hozzászólást." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "Nem oldhatod fel ezt a hozzászólást." msgid "Comment has been pinned." -msgstr "" +msgstr "A hozzászólás rögzítésre került." msgid "Comment has been unpinned." -msgstr "" +msgstr "A hozzászólás feloldásra került." msgid "Error retrieving package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." @@ -721,7 +735,7 @@ msgid "You did not select any packages to flag." msgstr "Nem választottál ki egyetlen csomagot sem megjelölésre." msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" +msgstr "A kiválasztott csomagok nem lettek jelölve, adj meg egy megjegyzést." msgid "The selected packages have been flagged out-of-date." msgstr "A kiválasztott csomagok elavultnak lettek jelölve." @@ -783,26 +797,26 @@ msgstr "Nem sikerült hozzáadni az értesítési listához." #, php-format msgid "You have been added to the comment notification list for %s." msgstr "" -"Sikeresen fel lettél véve a(z) %s csomag megjegyzésértesítési listájára." +"Sikeresen fel lettél véve a(z) %s csomag hozzászólásértesítési listájára." #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "El lettél távolítva a(z) %s csomag megjegyzésértesítési listájáról." +msgstr "El lettél távolítva a(z) %s csomag hozzászólásértesítési listájáról." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Ennek a hozzászólásnak nem vonhatod vissza a törlését." msgid "Comment has been undeleted." -msgstr "" +msgstr "A hozzászólás törlése visszavonásra került." msgid "You are not allowed to delete this comment." -msgstr "Nem törölheted ezt a megjegyzést." +msgstr "Nem törölheted ezt a hozzászólást." msgid "Comment has been deleted." -msgstr "Megjegyzés törölve." +msgstr "Hozzászólás törölve." msgid "Comment has been edited." -msgstr "" +msgstr "A hozzászólás szerkesztve lett." msgid "You are not allowed to edit the keywords of this package base." msgstr "Nem szerkesztheted ennek az alapcsomagnak a kulcsszavait." @@ -825,7 +839,7 @@ msgstr "Csomag részleteinek megtekintése –" #, php-format msgid "requires %s" -msgstr "" +msgstr "igényli ezt: %s" msgid "You must be logged in to file package requests." msgstr "Csomagkérelmek beküldéséhez be kell jelentkezned." @@ -834,7 +848,7 @@ msgid "Invalid name: only lowercase letters are allowed." msgstr "Érvénytelen név: csak kisbetűk használata engedélyezett." msgid "The comment field must not be empty." -msgstr "A megjegyzés mező nem lehet üres." +msgstr "A hozászólás mező nem lehet üres." msgid "Invalid request type." msgstr "Érvénytelen kérelemtípus." @@ -881,11 +895,14 @@ msgid "Email Address" msgstr "E-mail cím" msgid "hidden" -msgstr "" +msgstr "rejtett" msgid "Real Name" msgstr "Valós név" +msgid "Homepage" +msgstr "Honlap" + msgid "IRC Nick" msgstr "IRC becenév" @@ -936,9 +953,11 @@ msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Kérünk, győződj meg arról, hogy helyesen adtad meg az e-mail címedet, " +"különben ki leszel zárva." msgid "Hide Email Address" -msgstr "" +msgstr "E-mail cím elrejtése" msgid "Re-type password" msgstr "Megismételt jelszó" @@ -957,13 +976,16 @@ msgid "SSH Public Key" msgstr "Nyilvános SSH kulcs" msgid "Notification settings" -msgstr "" +msgstr "Értesítési beállítások" msgid "Notify of new comments" msgstr "Értesítés új hozzászólásról" msgid "Notify of package updates" -msgstr "" +msgstr "Értesítés csomagfrissítésekről." + +msgid "Notify of ownership changes" +msgstr "Értesítés tulajdonváltozásokról" msgid "Update" msgstr "Frissítés" @@ -1010,22 +1032,24 @@ msgstr "Mentés" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Elavultnak jelölő hozzászólás: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +"%s%s%s elavultnak jelölte a(z) %s%s%s csomagot ekkor: %s%s%s a következő " +"okból:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s nincs elavultnak jelölve." msgid "Return to Details" -msgstr "" +msgstr "Vissza a részletekhez" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "Copyright %s 2004-%d aurweb fejlesztői csapat." msgid "My Packages" msgstr "Csomagjaim" @@ -1050,7 +1074,7 @@ msgstr "Keresés wikiben" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Elavultnak jelölve (%s)" msgid "Flag package out-of-date" msgstr "Csomag elavultnak jelölése" @@ -1067,6 +1091,9 @@ msgstr "Szavazás erre a csomagra" msgid "Disable notifications" msgstr "Értesítések kikapcsolása" +msgid "Enable notifications" +msgstr "Értesítések engedélyezése" + msgid "Manage Co-Maintainers" msgstr "Társszerkesztők kezelése" @@ -1117,7 +1144,7 @@ msgstr "Legutóbb frissítve" #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Hozzászólás szerkesztése ehhez: %s" msgid "Add Comment" msgstr "Hosszászólás" @@ -1126,46 +1153,46 @@ msgid "View all comments" msgstr "Összes megjegyzés megjelenítése" msgid "Pinned Comments" -msgstr "" +msgstr "Rögzített hozzászólások" msgid "Latest Comments" msgstr "Legújabb hozzászólások" #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s hozzászólt ekkor: %s" #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Névtelen hozzászólás ekkor: %s" #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "törölve ekkor: %s %s által" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "törölve ekkor: %s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "szerkesztve ekkor: %s %s által" #, php-format msgid "edited on %s" -msgstr "" +msgstr "szerkesztve ekkor: %s" msgid "Undelete comment" -msgstr "" +msgstr "Hozzászólás törlésének visszavonása" msgid "Delete comment" msgstr "Hozzászólás törlése" msgid "Pin comment" -msgstr "" +msgstr "Hozzászólás rögzítése" msgid "Unpin comment" -msgstr "" +msgstr "Hozzászólás feloldása" msgid "All comments" msgstr "Összes hozzászólás" @@ -1254,6 +1281,39 @@ msgstr "Megtagadás" msgid "Merge into" msgstr "Beolvasztás ebbe:" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"Törlési kérelem beküldésével megkérsz egy megbízható felhasználót, hogy " +"törölje az alapcsomagot. Ez a típusú kérelem duplikátumok, főági fejlesztők " +"által felhagyott szoftverek, valamint illegális és helyrehozhatatlanul " +"elromlott csomagokhoz használható." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"Beolvasztási kérelem beküldésével megkérsz egy megbízható felhasználót, hogy " +"törölje az alapcsomagot, és vigye át a szavazatait és hozzászólásait egy " +"másik alapcsomaghoz. Egy csomag egyesítése nem érinti a kapcsolódó Git " +"tárolókat. Győződj meg róla, hogy frissítetted magadnak a célcsomag Git " +"történetét." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"Megtagadási kérelem beküldésével megkérsz egy megbízható felhasználót, hogy " +"tegye árvává az alapcsomagot. Kérünk, hogy ezt csak akkor tedd, ha a csomag " +"igényel fenntartói műveletet, a fenntartó eltűnt, és előzőleg már " +"megpróbáltad felvenni a kapcsolatot a fenntartóval." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1274,8 +1334,10 @@ msgid "Date" msgstr "Dátum" #, php-format -msgid "~%d days left" -msgstr "~%d nap van hátra" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "~%d nap van hátra" +msgstr[1] "~%d nap van hátra" #, php-format msgid "~%d hour left" @@ -1326,7 +1388,7 @@ msgid "Voted" msgstr "Szavazva" msgid "Last modified" -msgstr "" +msgstr "Legutóbb módosítva" msgid "Ascending" msgstr "Növekvő" @@ -1373,12 +1435,13 @@ msgstr[1] "%d csomag található." msgid "Version" msgstr "Verzió" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" "A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat " -"súlyozásra kerül naponta 0,98-as faktorral a létrehozása óta." +"súlyozásra kerül naponta %.2f-as faktorral a létrehozása óta." msgid "Yes" msgstr "Igen" @@ -1438,7 +1501,7 @@ msgid "Recent Updates" msgstr "Legutóbbi frissítések" msgid "more" -msgstr "" +msgstr "több" msgid "My Statistics" msgstr "Statisztikám" diff --git a/po/it.po b/po/it.po index 21f1a5e3..042aaf36 100644 --- a/po/it.po +++ b/po/it.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" "it/)\n" "Language: it\n" @@ -915,6 +915,9 @@ msgstr "nascosto" msgid "Real Name" msgstr "Nome reale" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Nick IRC" @@ -996,6 +999,9 @@ msgstr "Notifica dei nuovi commenti" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Aggiorna" @@ -1098,6 +1104,9 @@ msgstr "Vota per questo pacchetto" msgid "Disable notifications" msgstr "Disabilita le notifiche" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "Gestisci i co-manutentori" @@ -1283,6 +1292,26 @@ msgstr "Abbandona" msgid "Merge into" msgstr "Unisci con" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1303,8 +1332,10 @@ msgid "Date" msgstr "Data" #, php-format -msgid "~%d days left" -msgstr "~%d giorni rimanenti" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1403,12 +1434,11 @@ msgstr[1] "Sono stati trovati %d pacchetti." msgid "Version" msgstr "Versione" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"La popolarità viene calcolata come la somma di tutti i voti con ogni voto " -"ponderato con un fattore di 0,98 al giorno dalla sua creazione." msgid "Yes" msgstr "Sì" diff --git a/po/ja.po b/po/ja.po index add4f67b..d3547425 100644 --- a/po/ja.po +++ b/po/ja.po @@ -5,14 +5,14 @@ # Translators: # kusakata, 2013 # kusakata, 2013 -# kusakata, 2013-2015 +# kusakata, 2013-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-13 16:24+0000\n" +"Last-Translator: kusakata\n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" "ja/)\n" "Language: ja\n" @@ -442,7 +442,7 @@ msgid "Only Trusted Users and Developers can disown packages." msgstr "Trusted User と開発者だけがパッケージを孤児にできます。" msgid "Flag Comment" -msgstr "" +msgstr "コメントのフラグを立てる" msgid "Flag Package Out-Of-Date" msgstr "パッケージの Out-Of-Date フラグを立てる" @@ -798,10 +798,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "%s がコメントの通知リストから削除されました。" msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "このコメントを復元する権限がありません。" msgid "Comment has been undeleted." -msgstr "" +msgstr "コメントは復元されました。" msgid "You are not allowed to delete this comment." msgstr "このコメントを削除することはできません。" @@ -895,6 +895,9 @@ msgstr "非公開" msgid "Real Name" msgstr "本名" +msgid "Homepage" +msgstr "ホームページ" + msgid "IRC Nick" msgstr "IRC ニックネーム" @@ -968,13 +971,16 @@ msgid "SSH Public Key" msgstr "SSH 公開鍵" msgid "Notification settings" -msgstr "" +msgstr "通知設定" msgid "Notify of new comments" msgstr "新しいコメントを通知" msgid "Notify of package updates" -msgstr "" +msgstr "パッケージアップデートの通知" + +msgid "Notify of ownership changes" +msgstr "所有者の変更の通知" msgid "Update" msgstr "更新" @@ -1021,18 +1027,19 @@ msgstr "保存" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Out-of-Date フラグが立てられたコメント: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +"%s%s%s は %s%s%s を %s%s%s に以下の理由で out-of-date フラグを立てました:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s は out-of-date フラグが立てられていません。" msgid "Return to Details" -msgstr "" +msgstr "詳細に戻る" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." @@ -1061,7 +1068,7 @@ msgstr "wiki を検索" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "out-of-date フラグが立てられています (%s)" msgid "Flag package out-of-date" msgstr "パッケージの out-of-date フラグを立てる" @@ -1078,6 +1085,9 @@ msgstr "このパッケージに投票する" msgid "Disable notifications" msgstr "通知を止める" +msgid "Enable notifications" +msgstr "通知を有効にする" + msgid "Manage Co-Maintainers" msgstr "共同メンテナの管理" @@ -1155,18 +1165,18 @@ msgstr "%s によって %s に削除" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "%s に削除" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "%s に %s によって編集" #, php-format msgid "edited on %s" -msgstr "" +msgstr "%s に編集" msgid "Undelete comment" -msgstr "" +msgstr "コメントを復元" msgid "Delete comment" msgstr "コメントを削除" @@ -1264,6 +1274,38 @@ msgstr "孤児" msgid "Merge into" msgstr "マージ" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"削除リクエストを送信することで、Trusted User にパッケージベースの削除を要求で" +"きます。削除リクエストを使用するケース: パッケージの重複や、上流によってソフ" +"トウェアの開発が放棄された場合、違法なパッケージ、あるいはパッケージがどうし" +"ようもなく壊れてしまっている場合など。" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"マージリクエストを送信することで、パッケージベースを削除して\n" +"投票数とコメントを他のパッケージベースに移動することを Trusted User に要求で" +"きます。パッケージのマージは Git リポジトリに影響を与えません。マージ先のパッ" +"ケージの Git 履歴は自分で更新してください。" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"孤児リクエストを送信することで、パッケージベースの所有権が放棄されるように " +"Trusted User に要求できます。パッケージにメンテナが何らかの手を加える必要があ" +"り、現在のメンテナが行方不明で、メンテナに連絡を取ろうとしても返答がない場合" +"にのみ、リクエストを送信してください。" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1283,8 +1325,9 @@ msgid "Date" msgstr "日付" #, php-format -msgid "~%d days left" -msgstr "残り ~%d 日" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "残り ~%d 日" #, php-format msgid "~%d hour left" @@ -1380,11 +1423,13 @@ msgstr[0] "パッケージが %d 個見つかりました。" msgid "Version" msgstr "バージョン" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"人気度は各投票に作成日からの日数を0.98倍した全投票の合計で計算されます。" +"人気度は各投票にパッケージ作成日からの日数を %.2f 倍した全投票の合計で計算さ" +"れます。" msgid "Yes" msgstr "はい" @@ -1444,7 +1489,7 @@ msgid "Recent Updates" msgstr "最近のアップデート" msgid "more" -msgstr "" +msgstr "詳細" msgid "My Statistics" msgstr "自分の統計" diff --git a/po/nb.po b/po/nb.po index a16d6c0a..db09acfe 100644 --- a/po/nb.po +++ b/po/nb.po @@ -6,16 +6,16 @@ # Alexander F Rødseth , 2015 # Alexander F Rødseth , 2011,2013-2014 # Harald H. , 2015 -# AdmiringWorm , 2016 +# Kim Nordmo , 2016 # Lukas Fleischer , 2011 # Thor K. H. , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" "language/nb/)\n" "Language: nb\n" @@ -866,6 +866,9 @@ msgstr "" msgid "Real Name" msgstr "Ekte navn" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC-kallenavn" @@ -945,6 +948,9 @@ msgstr "Gi beskjed om nye kommentarer" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Oppdater" @@ -1045,6 +1051,9 @@ msgstr "Stem på denne pakken" msgid "Disable notifications" msgstr "Slå av beskjeder" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1230,6 +1239,26 @@ msgstr "Foreldreløs" msgid "Merge into" msgstr "Flett med" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1250,8 +1279,10 @@ msgid "Date" msgstr "Dato" #, php-format -msgid "~%d days left" -msgstr "~%d dager igjen" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1349,9 +1380,10 @@ msgstr[1] "Fant %d pakker." msgid "Version" msgstr "Versjon" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/nl.po b/po/nl.po index 80bf1f0f..2a85dab4 100644 --- a/po/nl.po +++ b/po/nl.po @@ -12,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" "Language: nl\n" "MIME-Version: 1.0\n" @@ -892,6 +892,9 @@ msgstr "" msgid "Real Name" msgstr "Echte naam" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC Nick" @@ -971,6 +974,9 @@ msgstr "Notificatie bij nieuwe comment" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Update" @@ -1073,6 +1079,9 @@ msgstr "Stem voor dit pakket" msgid "Disable notifications" msgstr "Schakel notificaties uit" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "Beheer mede-onderhouders" @@ -1259,6 +1268,26 @@ msgstr "Wees" msgid "Merge into" msgstr "Voeg samen met" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1279,8 +1308,10 @@ msgid "Date" msgstr "Datum" #, php-format -msgid "~%d days left" -msgstr "~%d dagen resterend" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1378,9 +1409,10 @@ msgstr[1] "%d pakketten gevonden" msgid "Version" msgstr "Versie" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/pl.po b/po/pl.po index a444aa5a..bc423b5d 100644 --- a/po/pl.po +++ b/po/pl.po @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-13 13:13+0000\n" -"Last-Translator: Piotr Strębski \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" "pl/)\n" "Language: pl\n" @@ -61,13 +61,13 @@ msgid "Use this form to search existing accounts." msgstr "Przy użyciu tego formularza możesz przeszukać istniejące konta." msgid "You must log in to view user information." -msgstr "Musisz być zalogowany aby móc oglądać informacje o użytkownikach." +msgstr "Musisz być zalogowany, aby móc przeglądać informacje o użytkownikach." msgid "Add Proposal" -msgstr "Dodaj Propozycję" +msgstr "Dodaj propozycję" msgid "Invalid token for user action." -msgstr "Nieprawidłowy token dla akcji użytkownika." +msgstr "Nieprawidłowy token dla czynności użytkownika." msgid "Username does not exist." msgstr "Nazwa użytkownika nie istnieje." @@ -89,10 +89,10 @@ msgid "Submit a proposal to vote on." msgstr "Wyślij propozycję do głosowania." msgid "Applicant/TU" -msgstr "Wnioskodawca/TU" +msgstr "Wnioskodawca/ZU" msgid "(empty if not applicable)" -msgstr "(puste jeśli nie dotyczy)" +msgstr "(puste, jeśli nie dotyczy)" msgid "Type" msgstr "Rodzaj" @@ -153,6 +153,7 @@ msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Pakiety w AUR są tworzone przez użytkowników. Używasz ich na własne ryzyko." msgid "Learn more..." msgstr "Dowiedz się więcej..." @@ -161,7 +162,7 @@ msgid "Support" msgstr "Wsparcie" msgid "Package Requests" -msgstr "Propozycje pakietu" +msgstr "Prośby o pakiet" #, php-format msgid "" @@ -178,7 +179,7 @@ msgid "" msgstr "" msgid "Deletion Request" -msgstr "Propozycja usunięcia" +msgstr "Prośba o usunięcie" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " @@ -187,7 +188,7 @@ msgid "" msgstr "" msgid "Merge Request" -msgstr "Propozycja połączenia" +msgstr "Prośba o połączenie" msgid "" "Request a package to be merged into another one. Can be used when a package " @@ -351,7 +352,7 @@ msgid "Cannot find package to merge votes and comments into." msgstr "Nie można znaleźć pakietu do scalenia głosów i komentarzy." msgid "Cannot merge a package base with itself." -msgstr "Nie można połączyć bazowego pakietu z nim samym." +msgstr "Nie można połączyć bazy pakietu z nią samą." msgid "" "The selected packages have not been deleted, check the confirmation checkbox." @@ -404,16 +405,16 @@ msgstr "" msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" +msgstr "Zaznaczając pole wyboru potwierdzasz, że chcesz porzucić pakiet." msgid "Confirm to disown the package" -msgstr "" +msgstr "Potwierdź porzucenie pakietu" msgid "Disown" msgstr "Porzuć" msgid "Only Trusted Users and Developers can disown packages." -msgstr "" +msgstr "Tylko Zaufani Użytkownicy i Programiści mogą porzucać pakiety." msgid "Flag Comment" msgstr "Oznacz komentarz" @@ -426,17 +427,24 @@ msgid "" "Use this form to flag the package base %s%s%s and the following packages out-" "of-date: " msgstr "" +"Użyj tego formularza, aby oznaczyć bazę pakietu %s%s%s i następujące pakiety " +"jako nieaktualne:" #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"Prosimy %snie%s używać tego formularza do zgłaszania błędów. Użyj do tego " +"systemu komentowania pakietu." msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Wprowadź poniżej szczegóły, dlaczego pakiet został oznaczony jako " +"nieaktualny, najlepiej łącznie z odnośnikiem do ogłoszenia o nowym wydaniu " +"lub do archiwum tarball nowego wydania." msgid "Comments" msgstr "Kommentarze" @@ -446,6 +454,7 @@ msgstr "Oznacz" msgid "Only registered users can flag packages out-of-date." msgstr "" +"Tylko zarejestrowani użytkownicy mogą oznaczać pakiety jako nieaktualne." msgid "Package Merging" msgstr "Scalanie pakietów" @@ -481,10 +490,10 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą scalać pakiety." msgid "Submit Request" -msgstr "Prześlij propozycję" +msgstr "Prześlij prośbę" msgid "Close Request" -msgstr "Zamknij propozycję" +msgstr "Zamknij prośbę" msgid "First" msgstr "Pierwsza" @@ -499,7 +508,7 @@ msgid "Last" msgstr "Ostatnia" msgid "Requests" -msgstr "Propozycje" +msgstr "Prośby" msgid "Register" msgstr "Zarejestruj się" @@ -526,13 +535,13 @@ msgid "You've already voted for this proposal." msgstr "Już zagłosowałeś na tą propozycję" msgid "Vote ID not valid." -msgstr "ID głosowania nieprawidłowe." +msgstr "Nieprawidłowy identyfikator głosowania." msgid "Current Votes" -msgstr "Obecne Głosy" +msgstr "Obecne głosy" msgid "Past Votes" -msgstr "Poprzednie Głosy" +msgstr "Poprzednie głosy" msgid "Voters" msgstr "Głosujących" @@ -586,7 +595,7 @@ msgstr "Adres, %s%s%s, jest już używany." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "Publiczny klucz SSH, %s%s%s, jest już używany." #, php-format msgid "Error trying to create account, %s%s%s." @@ -649,16 +658,16 @@ msgid "View account information for %s" msgstr "Wyświetl informacje o koncie %s" msgid "Package base ID or package base name missing." -msgstr "" +msgstr "Brakuje identyfikatora lub nazwy bazy pakietów." msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Nie masz uprawnień do edycji tego komentarza." msgid "Comment does not exist." -msgstr "" +msgstr "Komentarz nie istnieje." msgid "Comment cannot be empty." -msgstr "" +msgstr "Komentarz nie może być pusty." msgid "Comment has been added." msgstr "Komentarz został dodany." @@ -670,19 +679,19 @@ msgid "Missing comment ID." msgstr "Brakuje identyfikatora komentarza." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "Można przypiąć nie więcej niż 5 komentarzy." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Nie masz uprawnień do przypięcia tego komentarza." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "Nie masz uprawnień do odpięcia tego komentarza." msgid "Comment has been pinned." -msgstr "" +msgstr "Komentarz został przypięty." msgid "Comment has been unpinned." -msgstr "" +msgstr "Komentarz został odpięty." msgid "Error retrieving package details." msgstr "Błąd podczas pobierania informacji o pakiecie." @@ -698,6 +707,7 @@ msgstr "Nie wybrałeś żadnych pakietów do oznaczenia." msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +"Zaznaczone pakiety nie zostały oznaczone, prosimy o wpisanie komentarza." msgid "The selected packages have been flagged out-of-date." msgstr "Wybrane pakiety zostały oznaczone jako nieaktualne." @@ -724,7 +734,7 @@ msgid "You must be logged in before you can adopt packages." msgstr "Musisz być zalogowany aby móc przejmować pakiety." msgid "You must be logged in before you can disown packages." -msgstr "Musisz być zalogowany aby móc porzucać pakiety." +msgstr "Musisz być zalogowany, aby móc porzucać pakiety." msgid "You did not select any packages to adopt." msgstr "Nie wybrałeś żadnych pakietów do przejęcia." @@ -765,10 +775,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "Zostałeś usunięty z listy powiadamiania o komentarzach dla %s." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Nie masz uprawnień do cofnięcia usunięcia tego komentarza." msgid "Comment has been undeleted." -msgstr "" +msgstr "Zostało cofnięte usunięcie komentarza." msgid "You are not allowed to delete this comment." msgstr "Nie masz uprawnień do usunięcia tego komentarza." @@ -777,33 +787,33 @@ msgid "Comment has been deleted." msgstr "Komentarz został usunięty." msgid "Comment has been edited." -msgstr "" +msgstr "Komentarz został zmodyfikowany." msgid "You are not allowed to edit the keywords of this package base." -msgstr "" +msgstr "Nie masz uprawnień, by modyfikować słowa kluczowe tej bazy pakietów." msgid "The package base keywords have been updated." -msgstr "" +msgstr "Słowa kluczowe bazy pakietu zostały zaktualizowane." msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "Nie masz uprawnień, by zarządzać współutrzymującymi tej bazy pakietu." #, php-format msgid "Invalid user name: %s" msgstr "Niepoprawna nazwa użytkownika: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "Współutrzymujący bazy pakietu zostali zaktualizowani." msgid "View packages details for" msgstr "Wyświetl informacje o pakiecie" #, php-format msgid "requires %s" -msgstr "" +msgstr "wymaga %s" msgid "You must be logged in to file package requests." -msgstr "Musisz być zalogowanym, aby złożyć propozycje pakietu." +msgstr "Musisz być zalogowanym, aby złożyć prośbę o pakiet." msgid "Invalid name: only lowercase letters are allowed." msgstr "Nieprawidłowa nazwa: tylko małe litery są dozwolone." @@ -812,19 +822,19 @@ msgid "The comment field must not be empty." msgstr "Pole komentarzy nie może pozostać pustę." msgid "Invalid request type." -msgstr "Nieprawidłowy rodzaj propozycji." +msgstr "Nieprawidłowy rodzaj prośby." msgid "Added request successfully." -msgstr "Pomyślnie dodano propozycję." +msgstr "Pomyślnie dodano prośbę." msgid "Invalid reason." msgstr "Nieprawidłowy powód." msgid "Only TUs and developers can close requests." -msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą zamykać propozycje." +msgstr "Tylko Zaufani Użytkownicy i programiści mogą zamykać prośby." msgid "Request closed successfully." -msgstr "Pomyślnie zamknięto propozycję." +msgstr "Pomyślnie zamknięto prośbę." #, php-format msgid "You can use this form to permanently delete the AUR account %s." @@ -856,11 +866,14 @@ msgid "Email Address" msgstr "Adres e-mail" msgid "hidden" -msgstr "" +msgstr "ukryte" msgid "Real Name" msgstr "Imię i nazwisko" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Nick na IRC-u" @@ -890,7 +903,7 @@ msgstr "Edycja tego konta użytkownika" #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "Kliknij %stutaj%s jeśli chcesz nieodwracalnie usunąć to konto." +msgstr "Kliknij %stutaj%s, jeśli chcesz nieodwracalnie usunąć to konto." msgid "required" msgstr "wymagane" @@ -911,9 +924,11 @@ msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Upewnij się, czy poprawnie wpisano adres e-mail, w przeciwnym razie " +"zostaniesz zablokowany." msgid "Hide Email Address" -msgstr "" +msgstr "Ukryj adres e-mail" msgid "Re-type password" msgstr "Hasło (ponownie)" @@ -925,17 +940,22 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"Następująca informacja jest wymagana jedynie w sytuacji, gdy chcesz przesłać " +"pakiety do Repozytorium Użytkowników Arch." msgid "SSH Public Key" msgstr "Klucz publiczny SSH" msgid "Notification settings" -msgstr "" +msgstr "Ustawienia powiadomień" msgid "Notify of new comments" msgstr "Powiadom o nowych komentarzach" msgid "Notify of package updates" +msgstr "Powiadom o aktualizacjach pakietu" + +msgid "Notify of ownership changes" msgstr "" msgid "Update" @@ -972,6 +992,8 @@ msgstr "Brak wyników do wyświetlenia." msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"Użyj tego formularza, aby dodać współutrzymujących %s%s%s (jedna nazwa " +"użytkownika na wiersz):" msgid "Users" msgstr "Użytkownicy" @@ -981,22 +1003,23 @@ msgstr "Zapisz" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Komentarz do oznaczenia jako nieaktualny: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +"%s%s%s oznaczył %s%s%s jako nieaktualny dnia %s%s%s z następującego powodu:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s nie jest oznaczone jako nieaktualne." msgid "Return to Details" -msgstr "" +msgstr "Powrót do szczegółów" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "Prawa autorskie %s 2004-%d Zespół Programistów aurweb." msgid "My Packages" msgstr "Moje pakiety" @@ -1014,14 +1037,14 @@ msgid "View Changes" msgstr "Zobacz zmiany" msgid "Download snapshot" -msgstr "" +msgstr "Pobierz migawkę" msgid "Search wiki" msgstr "Przeszukaj wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Oznaczono jako nieaktualny (%s)" msgid "Flag package out-of-date" msgstr "Oznacz pakiet jako nieaktualny" @@ -1038,15 +1061,18 @@ msgstr "Zagłosuj na ten pakiet" msgid "Disable notifications" msgstr "Wyłącz powiadomienia" -msgid "Manage Co-Maintainers" +msgid "Enable notifications" msgstr "" +msgid "Manage Co-Maintainers" +msgstr "Zarządzanie współutrzymującymi" + #, php-format msgid "%d pending request" msgid_plural "%d pending requests" -msgstr[0] "%d propozycja w toku" -msgstr[1] "%d propozycje w toku" -msgstr[2] "%d propozycji w toku" +msgstr[0] "%d prośba w toku" +msgstr[1] "%d prośby w toku" +msgstr[2] "%d próśb w toku" msgid "Adopt Package" msgstr "Przejmij pakiet" @@ -1058,10 +1084,10 @@ msgid "Package Base Details" msgstr "Szczegóły bazy pakietu" msgid "Git Clone URL" -msgstr "" +msgstr "URL klonu Git" msgid "read-only" -msgstr "" +msgstr "tylko do odczytu" msgid "Keywords" msgstr "Słowa kluczowe" @@ -1082,14 +1108,14 @@ msgid "Popularity" msgstr "Popularność" msgid "First Submitted" -msgstr "Wysłany" +msgstr "Umieszczony" msgid "Last Updated" msgstr "Ostatnia aktualizacja" #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Edycja komentarza do: %s" msgid "Add Comment" msgstr "Dodaj komentarz" @@ -1098,46 +1124,46 @@ msgid "View all comments" msgstr "Pokaż wszystkie komentarze" msgid "Pinned Comments" -msgstr "" +msgstr "Przypięte komentarze" msgid "Latest Comments" msgstr "Ostatnie komentarze" #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s skomentował dnia %s" #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Anonimowy komentarz do %s" #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "usunięte %s przez %s" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "usunięte %s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "edytowane %s przez %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "edytowane %s" msgid "Undelete comment" -msgstr "" +msgstr "Cofnij usunięcie komentarza" msgid "Delete comment" msgstr "Usuń komentarz" msgid "Pin comment" -msgstr "" +msgstr "Przypnij komentarz" msgid "Unpin comment" -msgstr "" +msgstr "Odepnij komentarz" msgid "All comments" msgstr "Wszystkie komentarze" @@ -1152,7 +1178,7 @@ msgid "Description" msgstr "Opis" msgid "Upstream URL" -msgstr "URL upstreamu" +msgstr "URL źródła" msgid "Visit the website for" msgstr "Odwiedź stronę pakietu" @@ -1183,7 +1209,7 @@ msgstr "Źródła" #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" +msgstr "Użyj tego formularza, aby zamknąć prośbę o bazę pakietów %s%s%s." msgid "Note" msgstr "Uwaga" @@ -1192,6 +1218,8 @@ msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +"Pole komentarza może zostać pozostawione pustym. Jednakże w przypadku " +"odrzucenia prośby dodanie komentarza jest wysoce polecane." msgid "Reason" msgstr "Powód" @@ -1207,11 +1235,11 @@ msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -"Użyj tego formularza, aby złożyć propozycję na bazę pakietu %s%s%s i " -"następujące pakiety:" +"Użyj tego formularza, aby złożyć prośbę przeciwko bazie pakietu %s%s%s, " +"która zawiera następujące pakiety:" msgid "Request type" -msgstr "Rodzaj propozycji" +msgstr "Rodzaj prośby" msgid "Deletion" msgstr "Usunięcie" @@ -1222,12 +1250,32 @@ msgstr "Bez opiekuna" msgid "Merge into" msgstr "Scal z" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." -msgstr[0] "%d propozycje znaleziono" -msgstr[1] "%d propozycje znaleziono." -msgstr[2] "%d propozycji znaleziono." +msgstr[0] "%d prośba odnaleziona." +msgstr[1] "%d prośby odnalezione." +msgstr[2] "%d próśb odnaleziono." #, php-format msgid "Page %d of %d." @@ -1243,8 +1291,11 @@ msgid "Date" msgstr "Data" #, php-format -msgid "~%d days left" -msgstr "pozostało ~%d dni" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" #, php-format msgid "~%d hour left" @@ -1293,10 +1344,10 @@ msgid "Name" msgstr "Nazwa" msgid "Voted" -msgstr "Głos" +msgstr "Zagłosowany" msgid "Last modified" -msgstr "" +msgstr "Ostatnio zmienione" msgid "Ascending" msgstr "Rosnąco" @@ -1344,9 +1395,10 @@ msgstr[2] "%d pakietów znaleziono" msgid "Version" msgstr "Wersja" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" @@ -1407,7 +1459,7 @@ msgid "Recent Updates" msgstr "Ostatnie aktualizacje" msgid "more" -msgstr "" +msgstr "więcej" msgid "My Statistics" msgstr "Moje statystyki" diff --git a/po/pt_BR.po b/po/pt_BR.po index b5fec0d8..27259703 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -4,8 +4,9 @@ # # Translators: # Albino Biasutti Neto Bino , 2011 +# Fábio Nogueira , 2016 # Rafael Fontenelle , 2012-2015 -# Rafael Fontenelle , 2011,2015 +# Rafael Fontenelle , 2011,2015-2016 # Rafael Fontenelle , 2011 # Sandro , 2011 # Sandro , 2011 @@ -13,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 21:44+0000\n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 12:23+0000\n" "Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" "language/pt_BR/)\n" @@ -31,7 +32,7 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Desculpe, a página que você solicitou não existe." msgid "Service Unavailable" -msgstr "Serviço Indisponível" +msgstr "Serviço indisponível" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." @@ -86,7 +87,7 @@ msgid "Submit a proposal to vote on." msgstr "Enviar uma proposta para ser votada." msgid "Applicant/TU" -msgstr "Requerente/TU" +msgstr "Requerente/UC" msgid "(empty if not applicable)" msgstr "(vazio se não aplicável)" @@ -95,13 +96,13 @@ msgid "Type" msgstr "Tipo" msgid "Addition of a TU" -msgstr "Adição de um TU" +msgstr "Adição de um UC" msgid "Removal of a TU" -msgstr "Remoção de um TU" +msgstr "Remoção de um UC" msgid "Removal of a TU (undeclared inactivity)" -msgstr "Remoção de um TU (inatividade não declarada)" +msgstr "Remoção de um UC (inatividade não declarada)" msgid "Amendment of Bylaws" msgstr "Emenda ao Estatuto" @@ -127,7 +128,7 @@ msgid "" "Guidelines%s for more information." msgstr "" "Bem-vindo ao AUR! Por favor, leia as %sDiretrizes de Usuário do AUR%s e " -"%sDiretrizes de TU do AUR%s para mais informações." +"%sDiretrizes de UC do AUR%s para mais informações." #, php-format msgid "" @@ -227,7 +228,7 @@ msgstr "" "detalhes." msgid "The following SSH fingerprints are used for the AUR:" -msgstr "As seguintes fingeprints SSH são usadas para o AUR:" +msgstr "As seguintes impressões digitais SSH são usadas para o AUR:" msgid "Discussion" msgstr "Discussão" @@ -239,8 +240,9 @@ msgid "" "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" "Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) " -"e do Trusted User acontecem no %saur-general%s. Para discussão relacionada " -"ao desenvolvimento do AUR web, use a lista de discussão do %saur-dev%s" +"e do Usuário Confiável acontecem no %saur-general%s. Para discussão " +"relacionada ao desenvolvimento do AUR web, use a lista de discussão do %saur-" +"dev%s" msgid "Bug Reporting" msgstr "Relatório de erros" @@ -410,7 +412,7 @@ msgid "Delete" msgstr "Excluir" msgid "Only Trusted Users and Developers can delete packages." -msgstr "Somente Trusted Users e Desenvolvedores podem excluir pacotes." +msgstr "Somente Usuários Confiáveis e Desenvolvedores podem excluir pacotes." msgid "Disown Package" msgstr "Abandonar pacote" @@ -443,7 +445,7 @@ msgid "Disown" msgstr "Abandonar" msgid "Only Trusted Users and Developers can disown packages." -msgstr "Apenas Trusted Users e Desenvolvedores podem abandonar pacotes." +msgstr "Apenas Usuários Confiáveis e Desenvolvedores podem abandonar pacotes." msgid "Flag Comment" msgstr "Comentário da marcação" @@ -515,7 +517,7 @@ msgid "Merge" msgstr "Mesclar" msgid "Only Trusted Users and Developers can merge packages." -msgstr "Somente Trusted Users e Desenvolvedores podem mesclar pacotes." +msgstr "Somente Usuários Confiáveis e Desenvolvedores podem mesclar pacotes." msgid "Submit Request" msgstr "Enviar requisição" @@ -545,7 +547,7 @@ msgid "Use this form to create an account." msgstr "Utilize este formulário para criar uma conta." msgid "Trusted User" -msgstr "Trusted User" +msgstr "Usuário confiável" msgid "Could not retrieve proposal details." msgstr "Não foi possível adquirir detalhes da proposta." @@ -554,7 +556,7 @@ msgid "Voting is closed for this proposal." msgstr "A votação está encerrada para esta proposta." msgid "Only Trusted Users are allowed to vote." -msgstr "Apenas Trusted Users têm permissão para votar." +msgstr "Apenas Usuários Confiáveis têm permissão para votar." msgid "You cannot vote in an proposal about you." msgstr "Você não pode votar em uma proposta sobre você." @@ -630,7 +632,7 @@ msgstr "Erro ao tentar criar uma conta, %s%s%s." #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "A conta, %s%s%s, foi criada com sucesso." +msgstr "A conta %s%s%s foi criada com sucesso." msgid "A password reset key has been sent to your e-mail address." msgstr "" @@ -645,7 +647,7 @@ msgstr "Nenhuma alteração foi feita na conta, %s%s%s." #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "A conta, %s%s%s, foi modificada com sucesso." +msgstr "A conta %s%s%s foi modificada com sucesso." msgid "" "The login form is currently disabled for your IP address, probably due to " @@ -861,7 +863,7 @@ msgid "Invalid reason." msgstr "Motivo inválido" msgid "Only TUs and developers can close requests." -msgstr "Apenas TUs e desenvolvedores podem fechar requisições" +msgstr "Apenas UCs e desenvolvedores podem fechar requisições." msgid "Request closed successfully." msgstr "Requisição fechada com sucesso" @@ -892,7 +894,7 @@ msgid "Developer" msgstr "Desenvolvedor" msgid "Trusted User & Developer" -msgstr "Trusted User & Desenvolvedor" +msgstr "Usuário Confiável & Desenvolvedor" msgid "Email Address" msgstr "Endereço de e-mail" @@ -903,6 +905,9 @@ msgstr "oculto" msgid "Real Name" msgstr "Nome real" +msgid "Homepage" +msgstr "Página inicial" + msgid "IRC Nick" msgstr "Apelido no IRC" @@ -984,6 +989,9 @@ msgstr "Notificar sobre novos comentários" msgid "Notify of package updates" msgstr "Notificar sobre atualizações de pacotes" +msgid "Notify of ownership changes" +msgstr "Notificar sobre mudanças de mantenedor" + msgid "Update" msgstr "Atualizar" @@ -1087,6 +1095,9 @@ msgstr "Votar neste pacote" msgid "Disable notifications" msgstr "Desabilitar notificações" +msgid "Enable notifications" +msgstr "Habilitar notificações" + msgid "Manage Co-Maintainers" msgstr "Gerenciar comantenedores" @@ -1273,6 +1284,39 @@ msgstr "Tornar órfão" msgid "Merge into" msgstr "Mesclar em" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"Ao enviar uma requisição de exclusão, você solicita que um Trusted User " +"exclua o pacote base. Esse tipo de requisição deveria ser usada em caso de " +"duplicidade, softwares abandonados pelo upstream, assim como pacotes ilegais " +"ou irreparavelmente quebrados." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"Ao enviar uma requisição de mesclagem, você solicita que um Trusted User " +"exclua o pacote base e transfira seus votos e comentários para um outro " +"pacote base. Mesclar um pacote não afeta os repositórios Git " +"correspondentes. Certifique-se de você mesmo atualizar o histórico Git do " +"pacote alvo." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"Ao enviar uma requisição de tornar órfão, você pede que um Trusted User " +"abandona o pacote base. Por favor, apenas faça isto se o pacote precise de " +"ação do mantenedor, estando este ausente por muito tempo, e você já tentou - " +"e não conseguiu - contatá-lo anteriormente." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1293,8 +1337,10 @@ msgid "Date" msgstr "Data" #, php-format -msgid "~%d days left" -msgstr "~%d dias restantes" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "~%d dia restante" +msgstr[1] "~%d dias restantes" #, php-format msgid "~%d hour left" @@ -1392,12 +1438,13 @@ msgstr[1] "%d pacotes encontrados." msgid "Version" msgstr "Versão" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" "Popularidade é calculada como a soma de todos os votos, sendo cada voto " -"pesado com um fator de 0.98 por dia desde sua criação." +"pesado com um fator de %.2f por dia desde sua criação." msgid "Yes" msgstr "Sim" @@ -1451,7 +1498,7 @@ msgid "Registered Users" msgstr "Usuários registrados" msgid "Trusted Users" -msgstr "Trusted Users" +msgstr "Usuários Confiáveis" msgid "Recent Updates" msgstr "Atualizações recentes" @@ -1491,7 +1538,7 @@ msgid "Participation" msgstr "Participação" msgid "Last Votes by TU" -msgstr "Últimos votos por TU" +msgstr "Últimos votos por UC" msgid "Last vote" msgstr "Último voto" diff --git a/po/pt_PT.po b/po/pt_PT.po index fa61d356..395b3242 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -12,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" "aur/language/pt_PT/)\n" "Language: pt_PT\n" @@ -876,6 +876,9 @@ msgstr "" msgid "Real Name" msgstr "Nome real" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Nick IRC" @@ -953,6 +956,9 @@ msgstr "Notificar-me sobre novos comentários" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Actualizar" @@ -1053,6 +1059,9 @@ msgstr "Votar neste pacote" msgid "Disable notifications" msgstr "Desativar notificações" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1236,6 +1245,26 @@ msgstr "Orfão" msgid "Merge into" msgstr "Juntar em" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1256,8 +1285,10 @@ msgid "Date" msgstr "Data" #, php-format -msgid "~%d days left" -msgstr "" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1355,9 +1386,10 @@ msgstr[1] "%d pacotes encontrados." msgid "Version" msgstr "Versão" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/ro.po b/po/ro.po index 250c7ff0..b93d53d2 100644 --- a/po/ro.po +++ b/po/ro.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" "ro/)\n" "Language: ro\n" @@ -858,6 +858,9 @@ msgstr "" msgid "Real Name" msgstr "Nume real" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "Pseudonim IRC" @@ -935,6 +938,9 @@ msgstr "Notifică pentru comentarii noi" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Actualizare" @@ -1035,6 +1041,9 @@ msgstr "Votează acest pachet" msgid "Disable notifications" msgstr "Dezactivează notificări" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "" @@ -1223,6 +1232,26 @@ msgstr "Orfan" msgid "Merge into" msgstr "Fuzionează" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1244,8 +1273,11 @@ msgid "Date" msgstr "Data" #, php-format -msgid "~%d days left" -msgstr "~%d zile rămase" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" #, php-format msgid "~%d hour left" @@ -1345,9 +1377,10 @@ msgstr[2] "%d de pachete găsite" msgid "Version" msgstr "Versiune" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" diff --git a/po/ru.po b/po/ru.po index e55f487f..e75a688c 100644 --- a/po/ru.po +++ b/po/ru.po @@ -9,14 +9,15 @@ # Kyrylo Silin , 2011 # Lukas Fleischer , 2011 # Rustam Tsurik , 2013 -# Sergey Shepelev , 2014 +# Sergey Shepelev , 2014,2016 +# Аскольд , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-11 08:38+0000\n" -"Last-Translator: Evgeniy Alekseev \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" "ru/)\n" "Language: ru\n" @@ -342,7 +343,7 @@ msgid "Check your e-mail for the confirmation link." msgstr "Проверьте свою электронную почту на наличие ссылки подтверждения." msgid "Your password has been reset successfully." -msgstr "Ваш пароль был успешно переустановлен." +msgstr "Ваш пароль успешно сброшен." msgid "Confirm your e-mail address:" msgstr "Подтвердите адрес своей электронной почты:" @@ -373,7 +374,7 @@ msgid "" msgstr "Выбранные пакеты будут брошены." msgid "Cannot find package to merge votes and comments into." -msgstr "Не могу найти пакет для объединения с ним голосов и комментариев." +msgstr "Не могу найти пакет для объединения голосов и комментариев." msgid "Cannot merge a package base with itself." msgstr "Невозможно объединить группу пакетов с самой собой." @@ -591,7 +592,7 @@ msgid "Start and end with a letter or number" msgstr "Начинаются и заканчиваются цифрой или буквой" msgid "Can contain only one period, underscore or hyphen." -msgstr "Может содержать только одну запятую, подчёркивание или тире." +msgstr "Может содержать только одну точку, подчёркивание или тире." msgid "The email address is invalid." msgstr "Неправильный адрес электронной почты." @@ -610,7 +611,7 @@ msgstr "Язык пока не поддерживается." #, php-format msgid "The username, %s%s%s, is already in use." -msgstr "Имя пользователя, %s%s%s, уже используется." +msgstr "Имя %s%s%s уже занято." #, php-format msgid "The address, %s%s%s, is already in use." @@ -632,7 +633,7 @@ msgid "A password reset key has been sent to your e-mail address." msgstr "Ключ для смены пароля был отправлен на ваш электронный адрес." msgid "Click on the Login link above to use your account." -msgstr "Нажмите на ссылку для входа вверху чтобы зайти." +msgstr "Нажмите на ссылку Войти выше." #, php-format msgid "No changes were made to the account, %s%s%s." @@ -722,7 +723,7 @@ msgid "Package details could not be found." msgstr "Не найдена информация о пакете." msgid "You must be logged in before you can flag packages." -msgstr "Вы должны войти прежде чем расставлять флажки на пакеты." +msgstr "Вы должны войти чтобы ставить флажки на пакеты." msgid "You did not select any packages to flag." msgstr "Вы не выбрали ни одного пакета для пометки." @@ -734,7 +735,7 @@ msgid "The selected packages have been flagged out-of-date." msgstr "Выбранные пакеты помечены как устаревшие." msgid "You must be logged in before you can unflag packages." -msgstr "Вы должны войти прежде чем снимать флажки." +msgstr "Вы должны войти чтобы снимать флажки." msgid "You did not select any packages to unflag." msgstr "Вы не выбрали ни одного пакета для снятия пометки." @@ -752,10 +753,10 @@ msgid "The selected packages have been deleted." msgstr "Выбранные пакеты удалены." msgid "You must be logged in before you can adopt packages." -msgstr "Вы должны войти прежде чем усыновлять пакеты." +msgstr "Вы должны войти чтобы усыновлять пакеты." msgid "You must be logged in before you can disown packages." -msgstr "Вы должны войти прежде чем бросать пакеты." +msgstr "Вы должны войти чтобы бросать пакеты." msgid "You did not select any packages to adopt." msgstr "Вы не выбрали ни одного пакета для усыновления." @@ -770,10 +771,10 @@ msgid "The selected packages have been disowned." msgstr "Выбранные пакеты брошены." msgid "You must be logged in before you can vote for packages." -msgstr "Вы должны войти прежде чем голосовать." +msgstr "Вы должны войти чтобы голосовать." msgid "You must be logged in before you can un-vote for packages." -msgstr "Вы должны войти прежде чем снимать голос с пакета." +msgstr "Вы должны войти чтобы снимать голос с пакета." msgid "You did not select any packages to vote for." msgstr "Вы не выбрали ни одного пакета для голосования." @@ -837,7 +838,7 @@ msgid "You must be logged in to file package requests." msgstr "Вы должны войти, чтобы отправить запрос по пакету." msgid "Invalid name: only lowercase letters are allowed." -msgstr "Неверное имя: только нижний регистр допустим." +msgstr "Неверное имя: допустим только нижний регистр." msgid "The comment field must not be empty." msgstr "Поле комментариев должно быть заполнено." @@ -894,6 +895,9 @@ msgstr "скрыто" msgid "Real Name" msgstr "Настоящее имя" +msgid "Homepage" +msgstr "Домашняя страница" + msgid "IRC Nick" msgstr "IRC Ник" @@ -959,7 +963,9 @@ msgstr "Язык" msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." -msgstr "Только следующая необходима, если вы хотите загрузить пакеты в AUR." +msgstr "" +"Следующая информация необходима, только если вы хотите загружать пакеты в " +"AUR." msgid "SSH Public Key" msgstr "Публичный SSH ключ" @@ -973,6 +979,9 @@ msgstr "Уведомлять о новых комментариях" msgid "Notify of package updates" msgstr "Уведомлять об обновлении пакета" +msgid "Notify of ownership changes" +msgstr "Уведомлять об измененях собственности" + msgid "Update" msgstr "Обновить" @@ -1007,8 +1016,8 @@ msgstr "Больше нет результатов." msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -"Используйте данную форму, чтобы добавить сопровождающих для %s%s%s " -"(используйте одно имя на строку):" +"Используйте данную форму, чтобы добавить сопровождающих для %s%s%s (одно имя " +"на строку):" msgid "Users" msgstr "Пользователи" @@ -1058,7 +1067,7 @@ msgstr "Искать в Wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "Отмечет устаревшим (%s)" +msgstr "Отмечен устаревшим (%s)" msgid "Flag package out-of-date" msgstr "Пометить пакет как устаревший" @@ -1075,6 +1084,9 @@ msgstr "Проголосовать за пакет" msgid "Disable notifications" msgstr "Выключить уведомления" +msgid "Enable notifications" +msgstr "Включить уведомления" + msgid "Manage Co-Maintainers" msgstr "Управление сопровождающими" @@ -1262,6 +1274,37 @@ msgstr "Сделать сиротой" msgid "Merge into" msgstr "Объединить с" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"Отправляя запрос удаления, Вы просите Доверенного Пользователя удалить " +"основной пакет. Этот тип запроса должен использоваться для дубликатов, " +"заброшенных, а также незаконных и безнадёжно сломанных пакетов." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"Отправляя запрос на слияние, Вы просите Доверенного Пользователя удалить " +"основной пакет, переместить голоса и комментарии к другому основному пакету. " +"Слияние пакета не влияет на соответствующие Git репозитории. Обновите Git " +"историю целевого пакета самостоятельно." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"Отправляя сиротский запрос, Вы просите Доверенного Пользователя бросить " +"основной пакет. Пожалуйста, делайте это, только если пакет нуждается в " +"действиях обслуживающего, который недоступен и вы уже пытались связаться с " +"ним ранее." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1284,8 +1327,12 @@ msgid "Date" msgstr "Дата" #, php-format -msgid "~%d days left" -msgstr "осталось ~%d дней" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" +msgstr[3] "" #, php-format msgid "~%d hour left" @@ -1387,19 +1434,17 @@ msgstr[3] "Найдено %d пакетов." msgid "Version" msgstr "Версия" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"Популярность считается, как сумма всех голосов, где каждый голос взвешен с " -"коэффициентом 0.98 за каждый день разницы между днем голосования и днем " -"загрузки пакета." msgid "Yes" msgstr "Да" msgid "orphan" -msgstr "сирота" +msgstr "брошеный" msgid "Actions" msgstr "Действия" @@ -1429,7 +1474,7 @@ msgid "Statistics" msgstr "Статистика" msgid "Orphan Packages" -msgstr "Пакеты-сироты" +msgstr "Брошеные пакеты" msgid "Packages added in the past 7 days" msgstr "Пакеты, добавленные за прошедшие 7 дней" @@ -1459,7 +1504,7 @@ msgid "My Statistics" msgstr "Моя статистика" msgid "Proposal Details" -msgstr "Подробнее о предложении" +msgstr "Подробности предложения" msgid "This vote is still running." msgstr "Голосование продолжается." diff --git a/po/sk.po b/po/sk.po index d96c4ac0..9a8c80a9 100644 --- a/po/sk.po +++ b/po/sk.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" "sk/)\n" "Language: sk\n" @@ -887,6 +887,9 @@ msgstr "skrytý" msgid "Real Name" msgstr "Skutočné meno" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC prezývka" @@ -967,6 +970,9 @@ msgstr "Upozorni na nové komentáre" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Aktualizácia" @@ -1069,6 +1075,9 @@ msgstr "Hlasuj za tento balíček" msgid "Disable notifications" msgstr "Vypni upozornenia" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "Manažovať spolupracovníkov" @@ -1256,6 +1265,26 @@ msgstr "Vyvlastniť" msgid "Merge into" msgstr "Zlúčiť do" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1277,8 +1306,11 @@ msgid "Date" msgstr "Dátum" #, php-format -msgid "~%d days left" -msgstr "~%d dní ostáva" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" #, php-format msgid "~%d hour left" @@ -1378,12 +1410,11 @@ msgstr[2] "%d nájdených balíčkov." msgid "Version" msgstr "Verzia" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"Popularita sa počíta ako suma všetkých hlasov, pričom každý hlas je násobený " -"váhovým faktorom 0.98 za deň od dátumu vzniku." msgid "Yes" msgstr "Áno" diff --git a/po/sr.po b/po/sr.po index e0c352b9..b9b2f406 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-11 01:46+0000\n" -"Last-Translator: Slobodan Terzić \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" "sr/)\n" "Language: sr\n" @@ -880,6 +880,9 @@ msgstr "skrivena" msgid "Real Name" msgstr "Pravo ime" +msgid "Homepage" +msgstr "Domaća stranica" + msgid "IRC Nick" msgstr "IRC nadimak" @@ -961,6 +964,9 @@ msgstr "Obavesti o novim komentarima" msgid "Notify of package updates" msgstr "Obavesti o nadogradnjama paketa" +msgid "Notify of ownership changes" +msgstr "Obavesti o promenama vlasništva" + msgid "Update" msgstr "Ažuriraj" @@ -1063,6 +1069,9 @@ msgstr "Glasajte za paket" msgid "Disable notifications" msgstr "Ugasi obaveštenja" +msgid "Enable notifications" +msgstr "Uključi obaveštenja" + msgid "Manage Co-Maintainers" msgstr "Upravljanje koodržavaocima" @@ -1130,7 +1139,7 @@ msgstr "Poslednji komentari" #, php-format msgid "%s commented on %s" -msgstr "%s postavi komentar za %s" +msgstr "%s postavi komentar %s u" #, php-format msgid "Anonymous comment on %s" @@ -1249,6 +1258,37 @@ msgstr "Siročić" msgid "Merge into" msgstr "Stopi sa" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"Podnošenjem zahteva za brisanje tražili ste of poverljivog korisnika da " +"obriše bazu paketa. Ovaj tip zahteva treba koristiti za duplikate, uzvodno " +"napišten softver, kao i nelegalne ili nepopravljivo pokvarene pakete." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"Podnošenjem zahteva za spajanje tražili ste of poverljivog korisnika da " +"obriše bazu paketa i spoji njene glasove sa drugom bazom paketa. Spajanje " +"paketa ne utiče na pripadajuće Git riznice. Postarajte se sami da ažurirate " +"Git istorijat ciljanog paketa." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"Podnošenjem zahteva za odricanje tražili ste od poverljivog korisnika da " +"izvrži odricanje od baze paketa. Molimo da ovo tražite samo ukoliko paket " +"zahteva održavanje, a održavalac je nedosupan i već ste pokušali da ga " +"kontaktirate." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1270,8 +1310,11 @@ msgid "Date" msgstr "Datum" #, php-format -msgid "~%d days left" -msgstr "Preostalo dana: ~%d" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" #, php-format msgid "~%d hour left" @@ -1371,12 +1414,11 @@ msgstr[2] "Nađeno %d paketa." msgid "Version" msgstr "Verzija" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"Popularnost se izračunava kao suma svih glasova, gde glas ima faktor težine " -"0,98 za svaki dan od njegovog nastanka." msgid "Yes" msgstr "Da" diff --git a/po/tr.po b/po/tr.po index 2e6fdf81..9f843c22 100644 --- a/po/tr.po +++ b/po/tr.po @@ -14,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" "tr/)\n" "Language: tr\n" @@ -887,6 +887,9 @@ msgstr "" msgid "Real Name" msgstr "Gerçek İsim" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC Rumuzu" @@ -966,6 +969,9 @@ msgstr "Yeni yorumları bildir" msgid "Notify of package updates" msgstr "" +msgid "Notify of ownership changes" +msgstr "" + msgid "Update" msgstr "Güncelle" @@ -1068,6 +1074,9 @@ msgstr "Pakete oy ver" msgid "Disable notifications" msgstr "Bildirimleri kapat" +msgid "Enable notifications" +msgstr "" + msgid "Manage Co-Maintainers" msgstr "Yardımcı Bakımcıları Yönet" @@ -1254,6 +1263,26 @@ msgstr "Öksüz" msgid "Merge into" msgstr "Şununla ilişkilendir:" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1274,8 +1303,10 @@ msgid "Date" msgstr "Tarih" #, php-format -msgid "~%d days left" -msgstr "~%d gün kaldı" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" +msgstr[1] "" #, php-format msgid "~%d hour left" @@ -1373,12 +1404,11 @@ msgstr[1] "%d adet paket bulundu." msgid "Version" msgstr "Sürüm" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" -"Beğenilirlik, oluşturulmasından itibaren günlük 0.98 oranı ile çarpılarak " -"bulunan her oyun toplamı ile ölçülür." msgid "Yes" msgstr "Evet" diff --git a/po/uk.po b/po/uk.po index b2ac3dcc..5f475c3a 100644 --- a/po/uk.po +++ b/po/uk.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 23:36+0000\n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 11:02+0000\n" "Last-Translator: Yarema aka Knedlyk \n" "Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" "uk/)\n" @@ -895,6 +895,9 @@ msgstr "приховано" msgid "Real Name" msgstr "Справжнє ім'я" +msgid "Homepage" +msgstr "Домашня сторінка" + msgid "IRC Nick" msgstr "Псевдонім IRC" @@ -976,6 +979,9 @@ msgstr "Сповіщати про нові коментарі" msgid "Notify of package updates" msgstr "Повідомлення про оновлення пакунків" +msgid "Notify of ownership changes" +msgstr "Сповіщення про зміну власника" + msgid "Update" msgstr "Оновити" @@ -1021,7 +1027,7 @@ msgstr "Зберегти" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Позначено як застарілий коментар: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" @@ -1078,6 +1084,9 @@ msgstr "Голосувати за цей пакунок" msgid "Disable notifications" msgstr "Відключити сповіщення" +msgid "Enable notifications" +msgstr "Включити сповіщення" + msgid "Manage Co-Maintainers" msgstr "Керування Супровідниками" @@ -1264,6 +1273,36 @@ msgstr "Позначити застарілим" msgid "Merge into" msgstr "Об'єднати в" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"Надсилаючи запит на вилучення, Ви просите Довіреного Користувача вилучити " +"пакунок з бази. Цей тип запиту повинен використовуватися для дублікатів, " +"неоновлюваних програм, а також нелегальних і невиправно пошкоджених пакунків." + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"Надсилаючи запит на об'єднання, Ви просите Довіреного Користувача вилучити " +"пакунок і перенести всі його голосування і коментарі до іншого пакунку. " +"Об'єднання пакунку не впливає на відповідні сховища Git. Впевніться, що Ви " +"оновили самі історію Git доцільового пакунку." + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"Надсилаючи запит на зречення, Ви просите Довіреного Користувача позбавити " +"пакунок власника. Робіть це, якщо пакунок потребує якоїсь дії, супровідник " +"не робить жодних дій і Ви вже попередньо намагалися зв'язатися з ним." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1285,8 +1324,11 @@ msgid "Date" msgstr "Дата" #, php-format -msgid "~%d days left" -msgstr "~%d днів залишилося" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "~%d день залишився" +msgstr[1] "~%d днів залишилося" +msgstr[2] "~%d днів залишилося" #, php-format msgid "~%d hour left" @@ -1386,12 +1428,13 @@ msgstr[2] "Знайдено %d пакунків." msgid "Version" msgstr "Версія" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" "Популярність розраховується як сума всіх голосувань, де кожен голос береться " -"з ваговим коефіцієнтом 0.98 за кожен день з часу створення." +"з ваговим коефіцієнтом %.2f за кожен день з часу створення." msgid "Yes" msgstr "Так" diff --git a/po/zh_CN.po b/po/zh_CN.po index 928d9fac..9c55ab98 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3,19 +3,20 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# leonfeng , 2015 +# leonfeng , 2015-2016 # dongfengweixiao , 2015 # Felix Yan , 2014 # Lukas Fleischer , 2011 # leonfeng , 2012 # Weiwen Zhao , 2013 +# Xiaodong Qi , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-09 20:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-06 09:48+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" "language/zh_CN/)\n" "Language: zh_CN\n" @@ -31,11 +32,11 @@ msgid "Sorry, the page you've requested does not exist." msgstr "请求的页面不存在。" msgid "Service Unavailable" -msgstr "" +msgstr "服务不可用" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "别怕!本站正在维护中,我们会回来的。" msgid "Account" msgstr "帐户" @@ -111,10 +112,10 @@ msgid "Submit" msgstr "提交" msgid "Manage Co-maintainers" -msgstr "" +msgstr "管理共同维护者" msgid "Edit comment" -msgstr "" +msgstr "编辑评论" msgid "Home" msgstr "首页" @@ -145,56 +146,64 @@ msgstr "免责声明" msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" +msgstr "AUR 包为用户产生的内容。使用它们造成的后果自负。" msgid "Learn more..." -msgstr "" +msgstr "了解更多..." msgid "Support" -msgstr "" +msgstr "支持" msgid "Package Requests" -msgstr "" +msgstr "软件包请求" #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" -msgstr "" +msgstr "在软件包详情页面上有三种可以在 %s软件包操作%s 框中提交的请求:" msgid "Orphan Request" -msgstr "" +msgstr "弃置请求" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"请求标记这个软件包为无主的,比如维护者不活跃而且这个软件包已经被标记为过时很" +"久了。" msgid "Deletion Request" -msgstr "" +msgstr "删除请求" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"请求软件包从 AUR 中移除。如果这个包虽然损坏了但是可以被轻易地修好,请不要进行" +"此操作,您应该联系包的维护者或者有必要的情况下发送 orphan request。" msgid "Merge Request" -msgstr "" +msgstr "合并请求" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"请求一个软件包被合并到另一个中。在一个包需要被重命名或者被分离成多个包的情况" +"下使用。" #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"如果你想讨论一个请求,你可以在 %saur-requests%s 邮件列表上发送消息。然而,不" +"要在那里发送请求。" msgid "Submitting Packages" -msgstr "" +msgstr "提交软件包" #, php-format msgid "" @@ -202,9 +211,11 @@ msgid "" "packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +"现在请使用 Git over SSH 来向 AUR 提交软件包。如果想知道更多,请查看 Arch " +"Wiki 上的 Arch User Repository (简体中文) 页面中 %s提交软件包%s 章节。" msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "AUR 使用以下 SSH 指纹:" msgid "Discussion" msgstr "邮件列表" @@ -215,6 +226,8 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"与 Arch 用户仓库(AUR)或者受信用户结构相关的一般讨论在 %saur-general%s 邮件" +"列表。若是与 AUR web 页面开发相关的讨论,请使用 %saur-dev%s 邮件列表。" msgid "Bug Reporting" msgstr "Bug 报告" @@ -226,6 +239,9 @@ msgid "" "%sonly%s. To report packaging bugs contact the package maintainer or leave a " "comment on the appropriate package page." msgstr "" +"如果你在 AUR web 页面中发现了一个 Bug,请提交到我们的 %sBug 追踪系统%s。请%s" +"仅仅%s使用追踪系统报告 AUR 自身的 Bug。如果想要报告打包方面的 Bug,请联系相应" +"的包维护者,或者在相应的软件包页面中留下一条评论。" msgid "Package Search" msgstr "软件包搜索" @@ -262,7 +278,7 @@ msgid "Enter login credentials" msgstr "输入账户信息" msgid "User name or email address" -msgstr "" +msgstr "用户名或 E-mail" msgid "Password" msgstr "密码" @@ -334,7 +350,7 @@ msgstr "输入您的邮箱地址:" msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" +msgstr "选中的软件包未被弃置,请检查确认复选框。" msgid "Cannot find package to merge votes and comments into." msgstr "找不到合并投票与评论的目标包。" @@ -380,49 +396,51 @@ msgstr "弃置软件包" msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " -msgstr "" +msgstr "使用这个表格来弃置包基础 %s%s%s,其中包括下列软件包:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" +msgstr "通过选中复选框,您将确认您将弃置这个包并将其所有权转移给 %s%s%s。" msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" +msgstr "通过选中复选框,您将确认您将弃置这个包。" msgid "Confirm to disown the package" -msgstr "" +msgstr "继续以弃置包" msgid "Disown" msgstr "弃置" msgid "Only Trusted Users and Developers can disown packages." -msgstr "" +msgstr "只有受信用户和开发人员能弃置软件包。" msgid "Flag Comment" -msgstr "" +msgstr "标记评论" msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "将软件包标记为过期" #, php-format msgid "" "Use this form to flag the package base %s%s%s and the following packages out-" "of-date: " -msgstr "" +msgstr "使用这个表单将包基础 %s%s%s 和以下包标记为已过期 :" #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" +msgstr "请 %s不%s 要用这个表单提交问题。请您使用包评论功能。" msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"在下面输入为什么这个软件包过期了,最好写一下更新日志的链接或者新版软件压缩包" +"的地址。" msgid "Comments" msgstr "评论" @@ -431,7 +449,7 @@ msgid "Flag" msgstr "标记" msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "只有已注册的用户才能把软件标记为已过期。" msgid "Package Merging" msgstr "软件包合并" @@ -465,7 +483,7 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "只有受信用户和开发人员才能删除软件包。" msgid "Submit Request" -msgstr "" +msgstr "提交请求" msgid "Close Request" msgstr "关闭请求" @@ -551,7 +569,7 @@ msgid "The PGP key fingerprint is invalid." msgstr "PGP 密钥指纹无效。" msgid "The SSH public key is invalid." -msgstr "" +msgstr "此 SSH 公钥无效。" msgid "Cannot increase account permissions." msgstr "不能提高账户权限。" @@ -569,7 +587,7 @@ msgstr "该地址 %s%s%s 已被使用。" #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "SSH 公钥 %s%s%s 已被使用。" #, php-format msgid "Error trying to create account, %s%s%s." @@ -629,16 +647,16 @@ msgid "View account information for %s" msgstr "查看 %s 的账户信息" msgid "Package base ID or package base name missing." -msgstr "" +msgstr "缺少软件包基础 ID 或软件包名。" msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "你没有权限编辑评论。" msgid "Comment does not exist." -msgstr "" +msgstr "评论不存在。" msgid "Comment cannot be empty." -msgstr "" +msgstr "评论不能为空。" msgid "Comment has been added." msgstr "已经添加评论。" @@ -650,19 +668,19 @@ msgid "Missing comment ID." msgstr "评论标识丢失。" msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "不能同时锁定 5 条以上的评论。" msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "你没有权限锁定这条评论。" msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "你没有权限解锁这条评论。" msgid "Comment has been pinned." -msgstr "" +msgstr "评论已锁定。" msgid "Comment has been unpinned." -msgstr "" +msgstr "评论已解锁。" msgid "Error retrieving package details." msgstr "获取软件包详情时发生错误。" @@ -677,7 +695,7 @@ msgid "You did not select any packages to flag." msgstr "您没有选择要标记的软件包。" msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" +msgstr "选中的软件包已被标记,请输入评论。" msgid "The selected packages have been flagged out-of-date." msgstr "选择的软件包已被标记为过期。" @@ -745,10 +763,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "您将不再收到 %s 的评论通知。" msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "你没有权限恢复这条评论。" msgid "Comment has been undeleted." -msgstr "" +msgstr "评论已恢复。" msgid "You are not allowed to delete this comment." msgstr "您没有权限删除此评论。" @@ -757,30 +775,30 @@ msgid "Comment has been deleted." msgstr "评论已被删除。" msgid "Comment has been edited." -msgstr "" +msgstr "评论已编辑。" msgid "You are not allowed to edit the keywords of this package base." -msgstr "" +msgstr "你没有权限编辑这个软件包基础的关键词。" msgid "The package base keywords have been updated." -msgstr "" +msgstr "软件包基础的关键词已被更新。" msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" +msgstr "你没有权限管理这个软件包基础的共同管理者。" #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "非法用户名:%s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "软件包基础的共同维护者已更新。" msgid "View packages details for" msgstr "查看软件包详细信息" #, php-format msgid "requires %s" -msgstr "" +msgstr "需要 %s" msgid "You must be logged in to file package requests." msgstr "登录之后才能提交软件包需求。" @@ -836,11 +854,14 @@ msgid "Email Address" msgstr "Email" msgid "hidden" -msgstr "" +msgstr "已隐藏" msgid "Real Name" msgstr "真实名字" +msgid "Homepage" +msgstr "" + msgid "IRC Nick" msgstr "IRC昵称" @@ -890,10 +911,10 @@ msgstr "不活跃" msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" +msgstr "请确认你正确地输入了你的 E-mail,或者你将会被锁定。" msgid "Hide Email Address" -msgstr "" +msgstr "隐藏 E-mail" msgid "Re-type password" msgstr "确认密码" @@ -904,18 +925,21 @@ msgstr "语言" msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." -msgstr "" +msgstr "仅仅当你想要向 AUR 提交软件包时才需要填写以下信息。" msgid "SSH Public Key" -msgstr "" +msgstr "SSH 公钥" msgid "Notification settings" -msgstr "" +msgstr "提醒设置" msgid "Notify of new comments" msgstr "当有新评论的时候提醒我" msgid "Notify of package updates" +msgstr "软件包更新提醒" + +msgid "Notify of ownership changes" msgstr "" msgid "Update" @@ -951,32 +975,32 @@ msgstr "没有更多的结果供显示。" #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" +msgstr "使用这个表单来添加 %s%s%s 的共同维护者(一个用户名一行):" msgid "Users" -msgstr "" +msgstr "用户" msgid "Save" -msgstr "" +msgstr "保存" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "已标记为过期的评论:%s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" +msgstr "%s%s%s 标记了 %s%s%s 为过期,在 %s%s%s,因为以下原因:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s 未被标记为过期。" msgid "Return to Details" -msgstr "" +msgstr "返回详情" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "版权所有 %s 2004-%d aurweb 开发组" msgid "My Packages" msgstr "我的软件包" @@ -991,17 +1015,17 @@ msgid "View PKGBUILD" msgstr "查看 PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "查看更改" msgid "Download snapshot" -msgstr "" +msgstr "下载快照" msgid "Search wiki" msgstr "搜索 Wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "已标记为过期 (%s)" msgid "Flag package out-of-date" msgstr "将软件包标记为过期" @@ -1018,9 +1042,12 @@ msgstr "为这个软件包投票" msgid "Disable notifications" msgstr "禁用通知" -msgid "Manage Co-Maintainers" +msgid "Enable notifications" msgstr "" +msgid "Manage Co-Maintainers" +msgstr "管理共同维护者" + #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1036,10 +1063,10 @@ msgid "Package Base Details" msgstr "包基础详情" msgid "Git Clone URL" -msgstr "" +msgstr "Git 克隆地址" msgid "read-only" -msgstr "" +msgstr "只读" msgid "Keywords" msgstr "关键字" @@ -1057,7 +1084,7 @@ msgid "Votes" msgstr "得票" msgid "Popularity" -msgstr "" +msgstr "受欢迎度" msgid "First Submitted" msgstr "首次提交" @@ -1067,7 +1094,7 @@ msgstr "最后更新" #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "编辑 %s 的评论" msgid "Add Comment" msgstr "添加评论" @@ -1076,46 +1103,46 @@ msgid "View all comments" msgstr "查看所有评论" msgid "Pinned Comments" -msgstr "" +msgstr "已锁定评论" msgid "Latest Comments" msgstr "最新的评论" #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s 在 %s 发表了评论" #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "在 %s 发表的匿名评论" #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "在 %s 被 %s 删除" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "在 %s 被删除" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "在 %s 被 %s 编辑" #, php-format msgid "edited on %s" -msgstr "" +msgstr "在 %s 被编辑" msgid "Undelete comment" -msgstr "" +msgstr "恢复评论" msgid "Delete comment" msgstr "删除评论" msgid "Pin comment" -msgstr "" +msgstr "锁定评论" msgid "Unpin comment" -msgstr "" +msgstr "解锁评论" msgid "All comments" msgstr "全部评论" @@ -1198,6 +1225,26 @@ msgstr "弃置" msgid "Merge into" msgstr "合并到" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1217,8 +1264,9 @@ msgid "Date" msgstr "日期" #, php-format -msgid "~%d days left" -msgstr "剩余~%d天" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "" #, php-format msgid "~%d hour left" @@ -1268,7 +1316,7 @@ msgid "Voted" msgstr "已投票" msgid "Last modified" -msgstr "" +msgstr "上次修改" msgid "Ascending" msgstr "从小到大" @@ -1314,9 +1362,10 @@ msgstr[0] "找到了 %d 个软件包。" msgid "Version" msgstr "版本" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." +"weighted with a factor of %.2f per day since its creation." msgstr "" msgid "Yes" @@ -1377,7 +1426,7 @@ msgid "Recent Updates" msgstr "最新更新" msgid "more" -msgstr "" +msgstr "更多" msgid "My Statistics" msgstr "我的统计" diff --git a/po/zh_TW.po b/po/zh_TW.po index bb26fd59..a888401c 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-02-09 21:58+0100\n" -"PO-Revision-Date: 2016-02-11 13:26+0000\n" +"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"PO-Revision-Date: 2016-08-08 07:33+0000\n" "Last-Translator: Jeff Huang \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" "language/zh_TW/)\n" @@ -857,6 +857,9 @@ msgstr "已隱藏" msgid "Real Name" msgstr "真實名稱" +msgid "Homepage" +msgstr "首頁" + msgid "IRC Nick" msgstr "IRC 暱稱" @@ -934,6 +937,9 @@ msgstr "接收新評論通知" msgid "Notify of package updates" msgstr "通知套件更新" +msgid "Notify of ownership changes" +msgstr "擁有者變更通知" + msgid "Update" msgstr "更新" @@ -1034,6 +1040,9 @@ msgstr "為此套件投票" msgid "Disable notifications" msgstr "停用通知" +msgid "Enable notifications" +msgstr "啟用通知" + msgid "Manage Co-Maintainers" msgstr "管理共同維護者" @@ -1214,6 +1223,33 @@ msgstr "棄置" msgid "Merge into" msgstr "合併到" +msgid "" +"By submitting a deletion request, you ask a Trusted User to delete the " +"package base. This type of request should be used for duplicates, software " +"abandoned by upstream, as well as illegal and irreparably broken packages." +msgstr "" +"透過遞交刪除請求,您會請求受信使用者刪除套件基礎。這個類型的請求應該用於重" +"複、被上游放棄的軟體,以及違法與無法修復的損壞套件。" + +msgid "" +"By submitting a merge request, you ask a Trusted User to delete the package " +"base and transfer its votes and comments to another package base. Merging a " +"package does not affect the corresponding Git repositories. Make sure you " +"update the Git history of the target package yourself." +msgstr "" +"透過遞交合併請求,您會請求受信使用者刪除套件基礎並轉移其投票數到其他的套件基" +"礎。合併一個套件不會影響相對應的 Git 倉庫。確保您可以自己更新目標套件的 Git " +"歷史。" + +msgid "" +"By submitting an orphan request, you ask a Trusted User to disown the " +"package base. Please only do this if the package needs maintainer action, " +"the maintainer is MIA and you already tried to contact the maintainer " +"previously." +msgstr "" +"透過遞交棄置請求,您會請求受信使用者棄置套件基礎。請僅在該套件需要有維護者動" +"作、維護者突然消失且您先前已經連絡過維護者時做此動作。" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1233,8 +1269,9 @@ msgid "Date" msgstr "日期" #, php-format -msgid "~%d days left" -msgstr "剩餘 ~%d 天" +msgid "~%d day left" +msgid_plural "~%d days left" +msgstr[0] "剩餘 ~%d 天" #, php-format msgid "~%d hour left" @@ -1330,10 +1367,11 @@ msgstr[0] "找到 %d 個套件。" msgid "Version" msgstr "版本" +#, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " -"weighted with a factor of 0.98 per day since its creation." -msgstr "人氣的計算方式為,將所有票數加總,且每一票自建立以來每天乘上 0.98。" +"weighted with a factor of %.2f per day since its creation." +msgstr "人氣的計算方式為,將所有票數加總,且每一票自建立以來每天乘上 %.2f。" msgid "Yes" msgstr "是" From f3b65e59f7365ca4e8e9b8752d69ba08e94c4234 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 14 Aug 2016 08:00:06 +0200 Subject: [PATCH 0224/1891] Release 4.3.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 9c0a5e60..7918a7f0 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Thu, 11 Aug 2016 20:52:53 +0200 Subject: [PATCH 0225/1891] Display registration date on account details page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/template/account_details.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/template/account_details.php b/web/template/account_details.php index 8b763824..b79685be 100644 --- a/web/template/account_details.php +++ b/web/template/account_details.php @@ -59,6 +59,10 @@ + + + + From 4a355c71cb21d21db2d7d6dec5746a432e47aaea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Thu, 11 Aug 2016 20:52:54 +0200 Subject: [PATCH 0226/1891] Add details link from account edit form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/template/account_edit_form.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 6c2b8fb8..19821a0b 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -1,6 +1,7 @@

    ', '') ?> + ', '') ?>

    From 2c36c17a18b0d7b54072cb85898b2795567fbf99 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 14 Aug 2016 21:56:41 +0200 Subject: [PATCH 0227/1891] db.py: Support pyformat paramstyle This is used by the MySQL database backend. Signed-off-by: Lukas Fleischer --- git-interface/db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/db.py b/git-interface/db.py index 060689b1..75d2283d 100644 --- a/git-interface/db.py +++ b/git-interface/db.py @@ -32,7 +32,7 @@ class Connection: raise ValueError('unsupported database backend') def execute(self, query, params=()): - if self._paramstyle == 'format': + if self._paramstyle in ('format', 'pyformat'): query = query.replace('%', '%%').replace('?', '%s') elif self._paramstyle == 'qmark': pass From c7616311810ae4817fc4b0585b5ef335e6273dbb Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 22 Aug 2016 07:54:52 +0200 Subject: [PATCH 0228/1891] t0003: Make tests more strict Instead of testing the exit code only, also check the error output. This reveals two bugs. The corresponding tests are marked as known breakages. Signed-off-by: Lukas Fleischer --- git-interface/test/t0003-update.sh | 91 ++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/git-interface/test/t0003-update.sh b/git-interface/test/t0003-update.sh index aeb223e8..ec830ba5 100755 --- a/git-interface/test/t0003-update.sh +++ b/git-interface/test/t0003-update.sh @@ -104,22 +104,34 @@ test_expect_success 'Test restore mode.' ' ' test_expect_success 'Test restore mode on a non-existent repository.' ' + cat >expected <<-EOD && + error: restore: repository not found: foobar3 + EOD AUR_USER=user AUR_PKGBASE=foobar3 AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" restore 2>&1 + test_must_fail "$GIT_UPDATE" restore >actual 2>&1 && + test_cmp expected actual ' test_expect_success 'Pushing to a branch other than master.' ' old=0000000000000000000000000000000000000000 && new=$(git -C aur.git rev-parse HEAD) && + cat >expected <<-EOD && + error: pushing to a branch other than master is restricted + EOD AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/pu "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/pu "$old" "$new" >actual 2>&1 && + test_cmp expected actual ' test_expect_success 'Performing a non-fast-forward ref update.' ' old=$(git -C aur.git rev-parse HEAD) && new=$(git -C aur.git rev-parse HEAD^) && + cat >expected <<-EOD && + error: denying non-fast-forward (you should pull first) + EOD AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_cmp expected actual ' test_expect_success 'Performing a non-fast-forward ref update as Trusted User.' ' @@ -136,7 +148,8 @@ test_expect_success 'Removing .SRCINFO.' ' git -C aur.git commit -q -m "Remove .SRCINFO" && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing .SRCINFO$" actual ' test_expect_success 'Removing .SRCINFO with a follow-up fix.' ' @@ -147,7 +160,8 @@ test_expect_success 'Removing .SRCINFO with a follow-up fix.' ' git -C aur.git revert --no-edit HEAD && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing .SRCINFO$" actual ' test_expect_success 'Removing PKGBUILD.' ' @@ -157,7 +171,8 @@ test_expect_success 'Removing PKGBUILD.' ' git -C aur.git commit -q -m "Remove PKGBUILD" && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing PKGBUILD$" actual ' test_expect_success 'Pushing a tree with a subdirectory.' ' @@ -169,7 +184,8 @@ test_expect_success 'Pushing a tree with a subdirectory.' ' git -C aur.git commit -q -m "Add subdirectory" && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the repository must not contain subdirectories$" actual ' test_expect_success 'Pushing a tree with a large blob.' ' @@ -180,7 +196,8 @@ test_expect_success 'Pushing a tree with a large blob.' ' git -C aur.git commit -q -m "Add large blob" && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual ' test_expect_success 'Pushing .SRCINFO with a non-matching package base.' ' @@ -194,7 +211,8 @@ test_expect_success 'Pushing .SRCINFO with a non-matching package base.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: invalid pkgbase: foobar2, expected foobar$" actual ' test_expect_success 'Pushing .SRCINFO with invalid syntax.' ' @@ -222,7 +240,8 @@ test_expect_success 'Pushing .SRCINFO without pkgver.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing mandatory field: pkgver$" actual ' test_expect_success 'Pushing .SRCINFO without pkgrel.' ' @@ -236,7 +255,8 @@ test_expect_success 'Pushing .SRCINFO without pkgrel.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing mandatory field: pkgrel$" actual ' test_expect_success 'Pushing .SRCINFO with epoch.' ' @@ -270,7 +290,8 @@ test_expect_success 'Pushing .SRCINFO with invalid pkgname.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: invalid package name: !$" actual ' test_expect_success 'Pushing .SRCINFO with invalid epoch.' ' @@ -284,7 +305,8 @@ test_expect_success 'Pushing .SRCINFO with invalid epoch.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: invalid epoch: !$" actual ' test_expect_success 'Missing install file.' ' @@ -298,7 +320,8 @@ test_expect_success 'Missing install file.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing install file: install$" actual ' test_expect_success 'Missing changelog file.' ' @@ -312,7 +335,8 @@ test_expect_success 'Missing changelog file.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing changelog file: changelog$" actual ' test_expect_success 'Missing source file.' ' @@ -326,7 +350,8 @@ test_expect_success 'Missing source file.' ' ) && new=$(git -C aur.git rev-parse HEAD) && AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: missing source file: file$" actual ' test_expect_success 'Pushing a blacklisted package.' ' @@ -335,18 +360,26 @@ test_expect_success 'Pushing a blacklisted package.' ' echo "pkgname = forbidden" >>aur.git/.SRCINFO && git -C aur.git commit -q -am "Add blacklisted package" && new=$(git -C aur.git rev-parse HEAD) && + cat >expected <<-EOD && + error: package is blacklisted: forbidden + EOD AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_cmp expected actual ' -test_expect_success 'Pushing a blacklisted package as Trusted User.' ' +test_expect_failure 'Pushing a blacklisted package as Trusted User.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && echo "pkgname = forbidden" >>aur.git/.SRCINFO && git -C aur.git commit -q -am "Add blacklisted package" && new=$(git -C aur.git rev-parse HEAD) && + cat >expected <<-EOD && + warning: package is blacklisted: forbidden + EOD AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ - "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 | grep ^warning: + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_cmp expected actual ' test_expect_success 'Pushing a package already in the official repositories.' ' @@ -355,18 +388,26 @@ test_expect_success 'Pushing a package already in the official repositories.' ' echo "pkgname = official" >>aur.git/.SRCINFO && git -C aur.git commit -q -am "Add official package" && new=$(git -C aur.git rev-parse HEAD) && + cat >expected <<-EOD && + error: package already provided by [core]: official + EOD AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_cmp expected actual ' -test_expect_success 'Pushing a package already in the official repositories as Trusted User.' ' +test_expect_failure 'Pushing a package already in the official repositories as Trusted User.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && echo "pkgname = official" >>aur.git/.SRCINFO && git -C aur.git commit -q -am "Add official package" && new=$(git -C aur.git rev-parse HEAD) && + cat >expected <<-EOD && + warning: package already provided by [core]: official + EOD AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ - "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 | grep ^warning: + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_cmp expected actual ' test_expect_success 'Trying to hijack a package.' ' @@ -380,8 +421,12 @@ test_expect_success 'Trying to hijack a package.' ' git commit -q -am "Change package name" ) && new=$(git -C aur.git rev-parse HEAD) && + cat >expected <<-EOD && + error: cannot overwrite package: foobar + EOD AUR_USER=user AUR_PKGBASE=foobar2 AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_cmp expected actual ' test_done From 29625e074472b6546e7433e9b72a3b907abd06ff Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 22 Aug 2016 08:12:07 +0200 Subject: [PATCH 0229/1891] git-update: Close cursor before closing database When using SQLite as backend, we need to close the cursor before closing the database to avoid the following error: sqlite3.OperationalError: unable to close due to unfinalized statements or unfinished backups Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 1 + git-interface/test/t0003-update.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 40d834d8..50938c3c 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -402,4 +402,5 @@ repo.create_reference('refs/namespaces/' + pkgbase + '/HEAD', sha1_new, True) update_notify(conn, user, pkgbase_id) # Close the database. +cur.close() conn.close() diff --git a/git-interface/test/t0003-update.sh b/git-interface/test/t0003-update.sh index ec830ba5..4a457793 100755 --- a/git-interface/test/t0003-update.sh +++ b/git-interface/test/t0003-update.sh @@ -368,7 +368,7 @@ test_expect_success 'Pushing a blacklisted package.' ' test_cmp expected actual ' -test_expect_failure 'Pushing a blacklisted package as Trusted User.' ' +test_expect_success 'Pushing a blacklisted package as Trusted User.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && echo "pkgname = forbidden" >>aur.git/.SRCINFO && From e3bcf83feb2dd68352c6c47aa16d64c025e1fb5b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 22 Aug 2016 08:16:47 +0200 Subject: [PATCH 0230/1891] git-update: Do not overwrite the repo variable The repo variable is already used to store the pygit2.Repository. Fixes a regression introduced in d273ee5 (Use the official provider list to detect duplicates, 2016-05-17). Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 3 +-- git-interface/test/t0003-update.sh | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 50938c3c..be4c9be9 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -373,8 +373,7 @@ for pkgname in srcinfo.utils.get_package_names(metadata): if pkgname in blacklist: warn_or_die('package is blacklisted: {:s}'.format(pkgname)) if pkgname in providers: - repo = providers[pkgname] - warn_or_die('package already provided by [{:s}]: {:s}'.format(repo, pkgname)) + warn_or_die('package already provided by [{:s}]: {:s}'.format(providers[pkgname], pkgname)) cur = conn.execute("SELECT COUNT(*) FROM Packages WHERE Name = ? AND " + "PackageBaseID <> ?", [pkgname, pkgbase_id]) diff --git a/git-interface/test/t0003-update.sh b/git-interface/test/t0003-update.sh index 4a457793..b642089c 100755 --- a/git-interface/test/t0003-update.sh +++ b/git-interface/test/t0003-update.sh @@ -396,7 +396,7 @@ test_expect_success 'Pushing a package already in the official repositories.' ' test_cmp expected actual ' -test_expect_failure 'Pushing a package already in the official repositories as Trusted User.' ' +test_expect_success 'Pushing a package already in the official repositories as Trusted User.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && echo "pkgname = official" >>aur.git/.SRCINFO && From ab228fd3c3124d4fc4d927c91245072d8a0ec32d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 12 Sep 2016 08:44:54 +0200 Subject: [PATCH 0231/1891] git-serve: Mark setup-repo as deprecated Since 0c1187c (git-serve: Deprecate setup-repo, 2016-07-24), it is no longer recommended to use setup-repo. Mark the command as deprecated in the usage/help text. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 19c3ab2e..38048c92 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -192,7 +192,7 @@ elif action == 'help': " list-repos List all your repositories.\n" + " restore Restore a deleted package base.\n" + " set-keywords [...] Change package base keywords.\n" + - " setup-repo Create an empty repository.\n" + + " setup-repo Create a repository (deprecated).\n" + " git-receive-pack Internal command used with Git.\n" + " git-upload-pack Internal command used with Git.") else: From e0450694216e5e88df6f48aaa9f7adc91e3f23f3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 17 Sep 2016 16:02:42 +0200 Subject: [PATCH 0232/1891] git-serve: Format usage text automatically Remove the formatting of the usage text and add code to columnize it automatically instead. Also, add more strict tests for the usage output. These new tests ensure that the usage header is printed, commands are indented properly and no overly long lines are produced. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 26 ++++++++++++++++++-------- git-interface/test/t0002-serve.sh | 10 +++++++++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 38048c92..0187de9a 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -117,6 +117,14 @@ def warn(msg): sys.stderr.write("warning: {:s}\n".format(msg)) +def usage(cmds): + sys.stderr.write("Commands:\n") + colwidth = max([len(cmd) for cmd in cmds.keys()]) + 4 + for key in sorted(cmds): + sys.stderr.write(" " + key.ljust(colwidth) + cmds[key] + "\n") + exit(0) + + user = os.environ.get('AUR_USER') privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1') ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND') @@ -187,13 +195,15 @@ elif action == 'restore': os.environ["AUR_PKGBASE"] = pkgbase os.execl(git_update_cmd, git_update_cmd, 'restore') elif action == 'help': - die("Commands:\n" + - " help Show this help message and exit.\n" + - " list-repos List all your repositories.\n" + - " restore Restore a deleted package base.\n" + - " set-keywords [...] Change package base keywords.\n" + - " setup-repo Create a repository (deprecated).\n" + - " git-receive-pack Internal command used with Git.\n" + - " git-upload-pack Internal command used with Git.") + cmds = { + "help": "Show this help message and exit.", + "list-repos": "List all your repositories.", + "restore ": "Restore a deleted package base.", + "set-keywords [...]": "Change package base keywords.", + "setup-repo ": "Create a repository (deprecated).", + "git-receive-pack": "Internal command used with Git.", + "git-upload-pack": "Internal command used with Git.", + } + usage(cmds) else: die_with_help("invalid command: {:s}".format(action)) diff --git a/git-interface/test/t0002-serve.sh b/git-interface/test/t0002-serve.sh index 52fdcd1e..ce8340e6 100755 --- a/git-interface/test/t0002-serve.sh +++ b/git-interface/test/t0002-serve.sh @@ -9,7 +9,15 @@ test_expect_success 'Test interactive shell.' ' ' test_expect_success 'Test help.' ' - SSH_ORIGINAL_COMMAND=help "$GIT_SERVE" 2>&1 | grep -q "^Commands:$" + SSH_ORIGINAL_COMMAND=help "$GIT_SERVE" 2>actual && + save_IFS=$IFS + IFS= + while read -r line; do + echo $line | grep -q "^Commands:$" && continue + echo $line | grep -q "^ [a-z]" || return 1 + [ ${#line} -le 80 ] || return 1 + done Date: Mon, 12 Sep 2016 19:56:12 +0200 Subject: [PATCH 0233/1891] git-serve: Add support for adopting package bases Add support for adopting packages from the SSH interface. The syntax is `adopt `. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 0187de9a..353771c9 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -3,12 +3,15 @@ import os import re import shlex +import subprocess import sys import time import config import db +notify_cmd = config.get('notifications', 'notify-cmd') + repo_path = config.get('serve', 'repo-path') repo_regex = config.get('serve', 'repo-regex') git_shell_cmd = config.get('serve', 'git-shell-cmd') @@ -73,6 +76,40 @@ def create_pkgbase(pkgbase, user): conn.close() +def pkgbase_adopt(pkgbase): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + + conn = db.Connection() + + cur = conn.execute("SELECT ID FROM PackageBases WHERE ID = ? AND " + + "MaintainerUID IS NULL", [pkgbase_id]) + if not privileged and not cur.fetchone(): + die('{:s}: permission denied: {:s}'.format(action, user)) + + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + if userid == 0: + die('{:s}: unknown user: {:s}'.format(action, user)) + + cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " + + "WHERE ID = ?", [userid, pkgbase_id]) + + cur = conn.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " + + "PackageBaseID = ? AND UserID = ?", + [pkgbase_id, userid]) + if cur.fetchone()[0] == 0: + cur = conn.execute("INSERT INTO PackageNotifications " + + "(PackageBaseID, UserID) VALUES (?, ?)", + [pkgbase_id, userid]) + conn.commit() + + subprocess.Popen((notify_cmd, 'adopt', str(pkgbase_id), str(userid))) + + conn.close() + + def pkgbase_set_keywords(pkgbase, keywords): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: @@ -194,8 +231,17 @@ elif action == 'restore': os.environ["AUR_USER"] = user os.environ["AUR_PKGBASE"] = pkgbase os.execl(git_update_cmd, git_update_cmd, 'restore') +elif action == 'adopt': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) + + pkgbase = cmdargv[1] + pkgbase_adopt(pkgbase) elif action == 'help': cmds = { + "adopt ": "Adopt a package base.", "help": "Show this help message and exit.", "list-repos": "List all your repositories.", "restore ": "Restore a deleted package base.", From 9b983ac03e127160693441d6754f129a44f80870 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 13 Sep 2016 08:57:00 +0200 Subject: [PATCH 0234/1891] git-serve: Add support for disowning package bases Add support for disowning packages from the SSH interface. The syntax is `disown `. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 136 +++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 353771c9..9959934d 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -110,6 +110,123 @@ def pkgbase_adopt(pkgbase): conn.close() +def pkgbase_get_comaintainers(pkgbase): + conn = db.Connection() + + cur = conn.execute("SELECT UserName FROM PackageComaintainers " + + "INNER JOIN Users " + + "ON Users.ID = PackageComaintainers.UsersID " + + "INNER JOIN PackageBases " + + "ON PackageBases.ID = PackageComaintainers.PackageBaseID " + + "WHERE PackageBases.Name = ? " + + "ORDER BY Priority ASC", [pkgbase]) + + return [row[0] for row in cur.fetchall()] + + +def pkgbase_set_comaintainers(pkgbase, userlist): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + + if not privileged and not pkgbase_has_full_access(pkgbase, user): + die('{:s}: permission denied: {:s}'.format(action, user)) + + conn = db.Connection() + + userlist_old = set(pkgbase_get_comaintainers(pkgbase)) + + uids_old = set() + for olduser in userlist_old: + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", + [olduser]) + userid = cur.fetchone()[0] + if userid == 0: + die('{:s}: unknown user: {:s}'.format(action, user)) + uids_old.add(userid) + + uids_new = set() + for newuser in userlist: + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", + [newuser]) + userid = cur.fetchone()[0] + if userid == 0: + die('{:s}: unknown user: {:s}'.format(action, user)) + uids_new.add(userid) + + uids_add = uids_new - uids_old + uids_rem = uids_old - uids_new + + i = 1 + for userid in uids_new: + if userid in uids_add: + cur = conn.execute("INSERT INTO PackageComaintainers " + + "(PackageBaseID, UsersID, Priority) " + + "VALUES (?, ?, ?)", [pkgbase_id, userid, i]) + subprocess.Popen((notify_cmd, 'comaintainer-add', str(pkgbase_id), + str(userid))) + else: + cur = conn.execute("UPDATE PackageComaintainers " + + "SET Priority = ? " + + "WHERE PackageBaseID = ? AND UsersID = ?", + [i, pkgbase_id, userid]) + i += 1 + + for userid in uids_rem: + cur = conn.execute("DELETE FROM PackageComaintainers " + + "WHERE PackageBaseID = ? AND UsersID = ?", + [pkgbase_id, userid]) + subprocess.Popen((notify_cmd, 'comaintainer-remove', + str(pkgbase_id), str(userid))) + + conn.commit() + conn.close() + + +def pkgbase_disown(pkgbase): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + + initialized_by_owner = pkgbase_has_full_access(pkgbase, user) + if not privileged and not initialized_by_owner: + die('{:s}: permission denied: {:s}'.format(action, user)) + + # TODO: Support disowning package bases via package request. + # TODO: Scan through pending orphan requests and close them. + + comaintainers = [] + new_maintainer_userid = None + + conn = db.Connection() + + # Make the first co-maintainer the new maintainer, unless the action was + # enforced by a Trusted User. + if initialized_by_owner: + comaintainers = pkgbase_get_comaintainers(pkgbase) + if len(comaintainers) > 0: + new_maintainer = comaintainers[0] + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", + [new_maintainer]) + new_maintainer_userid = cur.fetchone()[0] + comaintainers.remove(new_maintainer) + + pkgbase_set_comaintainers(pkgbase, comaintainers) + cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " + + "WHERE ID = ?", [new_maintainer_userid, pkgbase_id]) + + conn.commit() + + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + if userid == 0: + die('{:s}: unknown user: {:s}'.format(action, user)) + + subprocess.Popen((notify_cmd, 'disown', str(pkgbase_id), str(userid))) + + conn.close() + + def pkgbase_set_keywords(pkgbase, keywords): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: @@ -141,6 +258,16 @@ def pkgbase_has_write_access(pkgbase, user): return cur.fetchone()[0] > 0 +def pkgbase_has_full_access(pkgbase, user): + conn = db.Connection() + + cur = conn.execute("SELECT COUNT(*) FROM PackageBases " + + "INNER JOIN Users " + + "ON Users.ID = PackageBases.MaintainerUID " + + "WHERE Name = ? AND Username = ?", [pkgbase, user]) + return cur.fetchone()[0] > 0 + + def die(msg): sys.stderr.write("{:s}\n".format(msg)) exit(1) @@ -239,9 +366,18 @@ elif action == 'adopt': pkgbase = cmdargv[1] pkgbase_adopt(pkgbase) +elif action == 'disown': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) + + pkgbase = cmdargv[1] + pkgbase_disown(pkgbase) elif action == 'help': cmds = { "adopt ": "Adopt a package base.", + "disown ": "Disown a package base.", "help": "Show this help message and exit.", "list-repos": "List all your repositories.", "restore ": "Restore a deleted package base.", From 94ac084d9dc130d9bbee2b9abfe4ea154a6a8439 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 17 Sep 2016 20:14:35 +0200 Subject: [PATCH 0235/1891] git-serve: Add support for setting co-maintainers Add support for changing co-maintainers from the SSH interface. The syntax is `set-comaintainers ...`. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 9959934d..47e7df9a 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -374,6 +374,13 @@ elif action == 'disown': pkgbase = cmdargv[1] pkgbase_disown(pkgbase) +elif action == 'set-comaintainers': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + + pkgbase = cmdargv[1] + userlist = cmdargv[2:] + pkgbase_set_comaintainers(pkgbase, userlist) elif action == 'help': cmds = { "adopt ": "Adopt a package base.", @@ -381,6 +388,7 @@ elif action == 'help': "help": "Show this help message and exit.", "list-repos": "List all your repositories.", "restore ": "Restore a deleted package base.", + "set-comaintainers [...]": "Set package base co-maintainers.", "set-keywords [...]": "Change package base keywords.", "setup-repo ": "Create a repository (deprecated).", "git-receive-pack": "Internal command used with Git.", From 5f43e2aaa9bcd233a310d4f6bf65640976457d85 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 18 Sep 2016 13:20:39 +0200 Subject: [PATCH 0236/1891] t0002: Add tests for adopt/disown/set-comaintainers Signed-off-by: Lukas Fleischer --- git-interface/test/setup.sh | 4 + git-interface/test/t0002-serve.sh | 207 ++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) diff --git a/git-interface/test/setup.sh b/git-interface/test/setup.sh index 7f3d45a1..f9c16166 100644 --- a/git-interface/test/setup.sh +++ b/git-interface/test/setup.sh @@ -86,6 +86,10 @@ sed \ echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (3, 'dev', '!', 'dev@localhost', 3);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (4, 'user2', '!', 'user2@localhost', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (5, 'user3', '!', 'user3@localhost', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (6, 'user4', '!', 'user4@localhost', 1);" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (1, '$AUTH_FINGERPRINT_USER', '$AUTH_KEYTYPE_USER $AUTH_KEYTEXT_USER');" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FINGERPRINT_TU', '$AUTH_KEYTYPE_TU $AUTH_KEYTEXT_TU');" | sqlite3 aur.db diff --git a/git-interface/test/t0002-serve.sh b/git-interface/test/t0002-serve.sh index ce8340e6..2f1926e2 100755 --- a/git-interface/test/t0002-serve.sh +++ b/git-interface/test/t0002-serve.sh @@ -110,4 +110,211 @@ test_expect_success "Try to restore an existing package base." ' test_must_fail "$GIT_SERVE" 2>&1 ' +test_expect_success "Disown all package bases." ' + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="disown foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success "Adopt a package base as a regular user." ' + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + *foobar + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success "Adopt an already adopted package base." ' + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 +' + +test_expect_success "Adopt a package base as a Trusted User." ' + SSH_ORIGINAL_COMMAND="adopt foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + *foobar2 + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success "Disown one's own package base as a regular user." ' + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success "Disown one's own package base as a Trusted User." ' + SSH_ORIGINAL_COMMAND="disown foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual +' + +test_expect_success "Try to steal another user's package as a regular user." ' + SSH_ORIGINAL_COMMAND="adopt foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="adopt foobar2" AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + cat >expected <<-EOF && + *foobar2 + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + SSH_ORIGINAL_COMMAND="disown foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 +' + +test_expect_success "Try to steal another user's package as a Trusted User." ' + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + cat >expected <<-EOF && + *foobar + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 +' + +test_expect_success "Try to disown another user's package as a regular user." ' + SSH_ORIGINAL_COMMAND="adopt foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="disown foobar2" AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + *foobar2 + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + SSH_ORIGINAL_COMMAND="disown foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 +' + +test_expect_success "Try to disown another user's package as a Trusted User." ' + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 +' + +test_expect_success "Adopt a package base and add co-maintainers." ' + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="set-comaintainers foobar user3 user4" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 5|3|1 + 6|3|2 + EOF + echo "SELECT * FROM PackageComaintainers ORDER BY Priority;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Update package base co-maintainers." ' + SSH_ORIGINAL_COMMAND="set-comaintainers foobar user2 user3 user4" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 4|3|1 + 5|3|2 + 6|3|3 + EOF + echo "SELECT * FROM PackageComaintainers ORDER BY Priority;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Try to add co-maintainers to an orphan package base." ' + SSH_ORIGINAL_COMMAND="set-comaintainers foobar2 user2 user3 user4" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 4|3|1 + 5|3|2 + 6|3|3 + EOF + echo "SELECT * FROM PackageComaintainers ORDER BY Priority;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Disown a package base and check (co-)maintainer list." ' + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + *foobar + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user2 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + cat >expected <<-EOF && + 5|3|1 + 6|3|2 + EOF + echo "SELECT * FROM PackageComaintainers ORDER BY Priority;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Force-disown a package base and check (co-)maintainer list." ' + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=tu AUR_PRIVILEGED=1 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user3 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 >actual && + test_cmp expected actual && + cat >expected <<-EOF && + EOF + echo "SELECT * FROM PackageComaintainers ORDER BY Priority;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + test_done From f3fb614f196a1feb2738c56364f6e877d474ff2d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 18 Sep 2016 15:55:49 +0200 Subject: [PATCH 0237/1891] Send reminders before the TU voting period ends Add a new script that checks for TU votes ending within the next 48 hours and sends reminder emails to all Trusted Users who did not cast their votes yet. The script is designed to be executed as a cron job, such that the check is performed periodically. Since the script does not remember users it already sent emails to, the interval should not be chosen too small to avoid spamming. Signed-off-by: Lukas Fleischer --- scripts/notify.py | 23 +++++++++++++++++++++++ scripts/tuvotereminder.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100755 scripts/tuvotereminder.py diff --git a/scripts/notify.py b/scripts/notify.py index 6ea25d12..a640e452 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -139,6 +139,15 @@ def get_request_recipients(cur, reqid): return [row[0] for row in cur.fetchall()] +def get_tu_vote_reminder_recipients(cur, vote_id): + cur.execute('SELECT Users.Email FROM Users WHERE AccountTypeID = 2 ' + + 'EXCEPT SELECT Users.Email FROM Users ' + + 'INNER JOIN TU_Votes ' + + 'ON TU_Votes.UserID = Users.ID ' + + 'WHERE TU_Votes.VoteID = %s', [vote_id]) + return [row[0] for row in cur.fetchall()] + + def get_comment(cur, comment_id): cur.execute('SELECT Comments FROM PackageComments WHERE ID = %s', [comment_id]) @@ -405,6 +414,19 @@ def request_close(cur, uid, reqid, reason): send_notification(to, subject, body, refs, headers) +def tu_vote_reminder(cur, vote_id): + to = get_tu_vote_reminder_recipients(cur, vote_id) + + vote_uri = aur_location + '/tu/?id=' + vote_id + + subject = 'TU Vote Reminder: Proposal %d' % (int(vote_id)) + body = 'Please remember to cast your vote on proposal %d [1]. ' \ + 'The voting period ends in less than 48 hours.' % (int(vote_id)) + refs = '[1] ' + vote_uri + + send_notification(to, subject, body, refs) + + if __name__ == '__main__': action = sys.argv[1] action_map = { @@ -420,6 +442,7 @@ if __name__ == '__main__': 'delete': delete, 'request-open': request_open, 'request-close': request_close, + 'tu-vote-reminder': tu_vote_reminder, } db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, diff --git a/scripts/tuvotereminder.py b/scripts/tuvotereminder.py new file mode 100755 index 00000000..0992623e --- /dev/null +++ b/scripts/tuvotereminder.py @@ -0,0 +1,32 @@ +#!/usr/bin/python3 + +import configparser +import mysql.connector +import os +import subprocess +import time + +config = configparser.RawConfigParser() +config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") + +aur_db_host = config.get('database', 'host') +aur_db_name = config.get('database', 'name') +aur_db_user = config.get('database', 'user') +aur_db_pass = config.get('database', 'password') +aur_db_socket = config.get('database', 'socket') +notify_cmd = config.get('notifications', 'notify-cmd') + +db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) +cur = db.cursor() + +now = int(time.time()) +filter_from = now + 500 +filter_to = now + 172800 + +cur.execute("SELECT ID FROM TU_VoteInfo WHERE End >= %s AND End <= %s", + [filter_from, filter_to]) + +for vote_id in [row[0] for row in cur.fetchall()]: + subprocess.Popen((notify_cmd, 'tu-vote-reminder', str(vote_id))) From 603b5b5db916da7d2a44e9e89587d62859840287 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 08:42:59 +0200 Subject: [PATCH 0238/1891] Add a main() method to all Python scripts Move the main program logic of all scripts to main() methods such that they can be used as modules and easily be invoked by setuptools wrapper scripts. Signed-off-by: Lukas Fleischer --- scripts/aurblup.py | 74 +++++++++++++++++++++------------------ scripts/mkpkglists.py | 44 +++++++++++++---------- scripts/notify.py | 6 +++- scripts/pkgmaint.py | 23 +++++++----- scripts/popupdate.py | 31 +++++++++------- scripts/tuvotereminder.py | 28 +++++++++------ 6 files changed, 122 insertions(+), 84 deletions(-) diff --git a/scripts/aurblup.py b/scripts/aurblup.py index 6733b45d..07119b5f 100755 --- a/scripts/aurblup.py +++ b/scripts/aurblup.py @@ -18,43 +18,49 @@ db_path = config.get('aurblup', 'db-path') sync_dbs = config.get('aurblup', 'sync-dbs').split(' ') servers = config.get('aurblup', 'servers').split(' ') -blacklist = set() -providers = set() -repomap = dict() -h = pyalpm.Handle("/", db_path) -for sync_db in sync_dbs: - repo = h.register_syncdb(sync_db, pyalpm.SIG_DATABASE_OPTIONAL) - repo.servers = [server.replace("%s", sync_db) for server in servers] - t = h.init_transaction() - repo.update(False) - t.release() +def main(): + blacklist = set() + providers = set() + repomap = dict() - for pkg in repo.pkgcache: - blacklist.add(pkg.name) - [blacklist.add(x) for x in pkg.replaces] - providers.add((pkg.name, pkg.name)) - repomap[(pkg.name, pkg.name)] = repo.name - for provision in pkg.provides: - provisionname = re.sub(r'(<|=|>).*', '', provision) - providers.add((pkg.name, provisionname)) - repomap[(pkg.name, provisionname)] = repo.name + h = pyalpm.Handle("/", db_path) + for sync_db in sync_dbs: + repo = h.register_syncdb(sync_db, pyalpm.SIG_DATABASE_OPTIONAL) + repo.servers = [server.replace("%s", sync_db) for server in servers] + t = h.init_transaction() + repo.update(False) + t.release() -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) -cur = db.cursor() + for pkg in repo.pkgcache: + blacklist.add(pkg.name) + [blacklist.add(x) for x in pkg.replaces] + providers.add((pkg.name, pkg.name)) + repomap[(pkg.name, pkg.name)] = repo.name + for provision in pkg.provides: + provisionname = re.sub(r'(<|=|>).*', '', provision) + providers.add((pkg.name, provisionname)) + repomap[(pkg.name, provisionname)] = repo.name -cur.execute("SELECT Name, Provides FROM OfficialProviders") -oldproviders = set(cur.fetchall()) + db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) + cur = db.cursor() -for pkg, provides in providers.difference(oldproviders): - repo = repomap[(pkg, provides)] - cur.execute("INSERT INTO OfficialProviders (Name, Repo, Provides) " - "VALUES (%s, %s, %s)", [pkg, repo, provides]) -for pkg, provides in oldproviders.difference(providers): - cur.execute("DELETE FROM OfficialProviders " - "WHERE Name = %s AND Provides = %s", [pkg, provides]) + cur.execute("SELECT Name, Provides FROM OfficialProviders") + oldproviders = set(cur.fetchall()) -db.commit() -db.close() + for pkg, provides in providers.difference(oldproviders): + repo = repomap[(pkg, provides)] + cur.execute("INSERT INTO OfficialProviders (Name, Repo, Provides) " + "VALUES (%s, %s, %s)", [pkg, repo, provides]) + for pkg, provides in oldproviders.difference(providers): + cur.execute("DELETE FROM OfficialProviders " + "WHERE Name = %s AND Provides = %s", [pkg, provides]) + + db.commit() + db.close() + + +if __name__ == '__main__': + main() diff --git a/scripts/mkpkglists.py b/scripts/mkpkglists.py index a6f8a197..8cab0a97 100755 --- a/scripts/mkpkglists.py +++ b/scripts/mkpkglists.py @@ -17,25 +17,33 @@ aur_db_user = config.get('database', 'user') aur_db_pass = config.get('database', 'password') aur_db_socket = config.get('database', 'socket') -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) -cur = db.cursor() -datestr = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") -pkglist_header = "# AUR package list, generated on " + datestr -pkgbaselist_header = "# AUR package base list, generated on " + datestr +def main(): + db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) + cur = db.cursor() -with gzip.open(docroot + "packages.gz", "w") as f: - f.write(bytes(pkglist_header + "\n", "UTF-8")) - cur.execute("SELECT Packages.Name FROM Packages INNER JOIN PackageBases " + - "ON PackageBases.ID = Packages.PackageBaseID " + - "WHERE PackageBases.PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + datestr = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") + pkglist_header = "# AUR package list, generated on " + datestr + pkgbaselist_header = "# AUR package base list, generated on " + datestr -with gzip.open(docroot + "pkgbase.gz", "w") as f: - f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) - cur.execute("SELECT Name FROM PackageBases WHERE PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + with gzip.open(docroot + "packages.gz", "w") as f: + f.write(bytes(pkglist_header + "\n", "UTF-8")) + cur.execute("SELECT Packages.Name FROM Packages " + + "INNER JOIN PackageBases " + + "ON PackageBases.ID = Packages.PackageBaseID " + + "WHERE PackageBases.PackagerUID IS NOT NULL") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) -db.close() + with gzip.open(docroot + "pkgbase.gz", "w") as f: + f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) + cur.execute("SELECT Name FROM PackageBases " + + "WHERE PackagerUID IS NOT NULL") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + + db.close() + + +if __name__ == '__main__': + main() diff --git a/scripts/notify.py b/scripts/notify.py index a640e452..e8210a87 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -427,7 +427,7 @@ def tu_vote_reminder(cur, vote_id): send_notification(to, subject, body, refs) -if __name__ == '__main__': +def main(): action = sys.argv[1] action_map = { 'send-resetkey': send_resetkey, @@ -454,3 +454,7 @@ if __name__ == '__main__': db.commit() db.close() + + +if __name__ == '__main__': + main() diff --git a/scripts/pkgmaint.py b/scripts/pkgmaint.py index 0eb94221..346b046f 100755 --- a/scripts/pkgmaint.py +++ b/scripts/pkgmaint.py @@ -13,13 +13,20 @@ aur_db_user = config.get('database', 'user') aur_db_pass = config.get('database', 'password') aur_db_socket = config.get('database', 'socket') -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) -cur = db.cursor() -cur.execute("DELETE FROM PackageBases WHERE " + - "UNIX_TIMESTAMP() - SubmittedTS > 86400 AND PackagerUID IS NULL") +def main(): + db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) + cur = db.cursor() -db.commit() -db.close() + cur.execute("DELETE FROM PackageBases WHERE " + + "UNIX_TIMESTAMP() - SubmittedTS > 86400 " + + "AND PackagerUID IS NULL") + + db.commit() + db.close() + + +if __name__ == '__main__': + main() diff --git a/scripts/popupdate.py b/scripts/popupdate.py index f3ba5131..26d83790 100755 --- a/scripts/popupdate.py +++ b/scripts/popupdate.py @@ -13,18 +13,25 @@ aur_db_user = config.get('database', 'user') aur_db_pass = config.get('database', 'password') aur_db_socket = config.get('database', 'socket') -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) -cur = db.cursor() -cur.execute("UPDATE PackageBases SET NumVotes = (SELECT COUNT(*) FROM " + - "PackageVotes WHERE PackageVotes.PackageBaseID = PackageBases.ID)") +def main(): + db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) + cur = db.cursor() -cur.execute("UPDATE PackageBases SET Popularity = (" + - "SELECT COALESCE(SUM(POWER(0.98, (UNIX_TIMESTAMP() - VoteTS) / 86400)), 0.0) " + - "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + - "PackageBases.ID AND NOT VoteTS IS NULL)") + cur.execute("UPDATE PackageBases SET NumVotes = (" + + "SELECT COUNT(*) FROM PackageVotes " + + "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") -db.commit() -db.close() + cur.execute("UPDATE PackageBases SET Popularity = (" + + "SELECT COALESCE(SUM(POWER(0.98, (UNIX_TIMESTAMP() - VoteTS) / 86400)), 0.0) " + + "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + + "PackageBases.ID AND NOT VoteTS IS NULL)") + + db.commit() + db.close() + + +if __name__ == '__main__': + main() diff --git a/scripts/tuvotereminder.py b/scripts/tuvotereminder.py index 0992623e..dc16397e 100755 --- a/scripts/tuvotereminder.py +++ b/scripts/tuvotereminder.py @@ -16,17 +16,23 @@ aur_db_pass = config.get('database', 'password') aur_db_socket = config.get('database', 'socket') notify_cmd = config.get('notifications', 'notify-cmd') -db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) -cur = db.cursor() -now = int(time.time()) -filter_from = now + 500 -filter_to = now + 172800 +def main(): + db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, + passwd=aur_db_pass, db=aur_db_name, + unix_socket=aur_db_socket, buffered=True) + cur = db.cursor() -cur.execute("SELECT ID FROM TU_VoteInfo WHERE End >= %s AND End <= %s", - [filter_from, filter_to]) + now = int(time.time()) + filter_from = now + 500 + filter_to = now + 172800 -for vote_id in [row[0] for row in cur.fetchall()]: - subprocess.Popen((notify_cmd, 'tu-vote-reminder', str(vote_id))) + cur.execute("SELECT ID FROM TU_VoteInfo WHERE End >= %s AND End <= %s", + [filter_from, filter_to]) + + for vote_id in [row[0] for row in cur.fetchall()]: + subprocess.Popen((notify_cmd, 'tu-vote-reminder', str(vote_id))) + + +if __name__ == '__main__': + main() From 3a352435e95207fd395a9dbd19227da57f243047 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 08:45:43 +0200 Subject: [PATCH 0239/1891] git-auth: Move entry point to a main() method Move the main program logic of git-auth to a main() method such that it can be used as a module and easily be invoked by setuptools wrapper scripts. Signed-off-by: Lukas Fleischer --- git-interface/git-auth.py | 56 +++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/git-interface/git-auth.py b/git-interface/git-auth.py index 45fd5772..d3b0188b 100755 --- a/git-interface/git-auth.py +++ b/git-interface/git-auth.py @@ -23,36 +23,40 @@ def format_command(env_vars, command, ssh_opts, ssh_key): return msg -valid_keytypes = config.get('auth', 'valid-keytypes').split() -username_regex = config.get('auth', 'username-regex') -git_serve_cmd = config.get('auth', 'git-serve-cmd') -ssh_opts = config.get('auth', 'ssh-options') +def main(): + valid_keytypes = config.get('auth', 'valid-keytypes').split() + username_regex = config.get('auth', 'username-regex') + git_serve_cmd = config.get('auth', 'git-serve-cmd') + ssh_opts = config.get('auth', 'ssh-options') -keytype = sys.argv[1] -keytext = sys.argv[2] -if keytype not in valid_keytypes: - exit(1) + keytype = sys.argv[1] + keytext = sys.argv[2] + if keytype not in valid_keytypes: + exit(1) -conn = db.Connection() + conn = db.Connection() -cur = conn.execute("SELECT Users.Username, Users.AccountTypeID FROM Users " + - "INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID " - "WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0", - (keytype + " " + keytext,)) + cur = conn.execute("SELECT Users.Username, Users.AccountTypeID FROM Users " + "INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID " + "WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0", + (keytype + " " + keytext,)) -row = cur.fetchone() -if not row or cur.fetchone(): - exit(1) + row = cur.fetchone() + if not row or cur.fetchone(): + exit(1) -user, account_type = row -if not re.match(username_regex, user): - exit(1) + user, account_type = row + if not re.match(username_regex, user): + exit(1) + + env_vars = { + 'AUR_USER': user, + 'AUR_PRIVILEGED': '1' if account_type > 1 else '0', + } + key = keytype + ' ' + keytext + + print(format_command(env_vars, git_serve_cmd, ssh_opts, key)) -env_vars = { - 'AUR_USER': user, - 'AUR_PRIVILEGED': '1' if account_type > 1 else '0', -} -key = keytype + ' ' + keytext - -print(format_command(env_vars, git_serve_cmd, ssh_opts, key)) +if __name__ == '__main__': + main() From b8318d25873f2294fc04bb98f14fbcbd55a4dc8a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 08:48:34 +0200 Subject: [PATCH 0240/1891] git-serve: Pass user and privileges as parameters Move the main program logic of git-server to a main() method such that it can be used as a module and easily be invoked by setuptools wrapper scripts. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 47e7df9a..ddec1444 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -76,7 +76,7 @@ def create_pkgbase(pkgbase, user): conn.close() -def pkgbase_adopt(pkgbase): +def pkgbase_adopt(pkgbase, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: die('{:s}: package base not found: {:s}'.format(action, pkgbase)) @@ -124,7 +124,7 @@ def pkgbase_get_comaintainers(pkgbase): return [row[0] for row in cur.fetchall()] -def pkgbase_set_comaintainers(pkgbase, userlist): +def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: die('{:s}: package base not found: {:s}'.format(action, pkgbase)) @@ -183,7 +183,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist): conn.close() -def pkgbase_disown(pkgbase): +def pkgbase_disown(pkgbase, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: die('{:s}: package base not found: {:s}'.format(action, pkgbase)) @@ -211,7 +211,7 @@ def pkgbase_disown(pkgbase): new_maintainer_userid = cur.fetchone()[0] comaintainers.remove(new_maintainer) - pkgbase_set_comaintainers(pkgbase, comaintainers) + pkgbase_set_comaintainers(pkgbase, comaintainers, user, privileged) cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ?", [new_maintainer_userid, pkgbase_id]) @@ -365,7 +365,7 @@ elif action == 'adopt': die_with_help("{:s}: too many arguments".format(action)) pkgbase = cmdargv[1] - pkgbase_adopt(pkgbase) + pkgbase_adopt(pkgbase, user, privileged) elif action == 'disown': if len(cmdargv) < 2: die_with_help("{:s}: missing repository name".format(action)) @@ -373,14 +373,14 @@ elif action == 'disown': die_with_help("{:s}: too many arguments".format(action)) pkgbase = cmdargv[1] - pkgbase_disown(pkgbase) + pkgbase_disown(pkgbase, user, privileged) elif action == 'set-comaintainers': if len(cmdargv) < 2: die_with_help("{:s}: missing repository name".format(action)) pkgbase = cmdargv[1] userlist = cmdargv[2:] - pkgbase_set_comaintainers(pkgbase, userlist) + pkgbase_set_comaintainers(pkgbase, userlist, user, privileged) elif action == 'help': cmds = { "adopt ": "Adopt a package base.", From 8468b6be4bada275f1fb8836f2fd9c161c103985 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 08:53:41 +0200 Subject: [PATCH 0241/1891] git-serve: Move entry point to a main() method Move the main program logic of git-serve to a main() method such that it can be used as a module and easily be invoked by setuptools wrapper scripts. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 198 +++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 96 deletions(-) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index ddec1444..8bcecd27 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -289,111 +289,117 @@ def usage(cmds): exit(0) -user = os.environ.get('AUR_USER') -privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1') -ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND') -ssh_client = os.environ.get('SSH_CLIENT') +def main(): + user = os.environ.get('AUR_USER') + privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1') + ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND') + ssh_client = os.environ.get('SSH_CLIENT') -if not ssh_cmd: - die_with_help("Interactive shell is disabled.") -cmdargv = shlex.split(ssh_cmd) -action = cmdargv[0] -remote_addr = ssh_client.split(' ')[0] if ssh_client else None + if not ssh_cmd: + die_with_help("Interactive shell is disabled.") + cmdargv = shlex.split(ssh_cmd) + action = cmdargv[0] + remote_addr = ssh_client.split(' ')[0] if ssh_client else None -if enable_maintenance: - if remote_addr not in maintenance_exc: - die("The AUR is down due to maintenance. We will be back soon.") + if enable_maintenance: + if remote_addr not in maintenance_exc: + die("The AUR is down due to maintenance. We will be back soon.") -if action == 'git-upload-pack' or action == 'git-receive-pack': - if len(cmdargv) < 2: - die_with_help("{:s}: missing path".format(action)) + if action == 'git-upload-pack' or action == 'git-receive-pack': + if len(cmdargv) < 2: + die_with_help("{:s}: missing path".format(action)) - path = cmdargv[1].rstrip('/') - if not path.startswith('/'): - path = '/' + path - if not path.endswith('.git'): - path = path + '.git' - pkgbase = path[1:-4] - if not re.match(repo_regex, pkgbase): - die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) + path = cmdargv[1].rstrip('/') + if not path.startswith('/'): + path = '/' + path + if not path.endswith('.git'): + path = path + '.git' + pkgbase = path[1:-4] + if not re.match(repo_regex, pkgbase): + die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) - if action == 'git-receive-pack' and pkgbase_exists(pkgbase): - if not privileged and not pkgbase_has_write_access(pkgbase, user): - die('{:s}: permission denied: {:s}'.format(action, user)) + if action == 'git-receive-pack' and pkgbase_exists(pkgbase): + if not privileged and not pkgbase_has_write_access(pkgbase, user): + die('{:s}: permission denied: {:s}'.format(action, user)) - os.environ["AUR_USER"] = user - os.environ["AUR_PKGBASE"] = pkgbase - os.environ["GIT_NAMESPACE"] = pkgbase - cmd = action + " '" + repo_path + "'" - os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd) -elif action == 'set-keywords': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - pkgbase_set_keywords(cmdargv[1], cmdargv[2:]) -elif action == 'list-repos': - if len(cmdargv) > 1: - die_with_help("{:s}: too many arguments".format(action)) - list_repos(user) -elif action == 'setup-repo': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) - warn('{:s} is deprecated. Use `git push` to create new repositories.'.format(action)) - create_pkgbase(cmdargv[1], user) -elif action == 'restore': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + os.environ["AUR_USER"] = user + os.environ["AUR_PKGBASE"] = pkgbase + os.environ["GIT_NAMESPACE"] = pkgbase + cmd = action + " '" + repo_path + "'" + os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd) + elif action == 'set-keywords': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + pkgbase_set_keywords(cmdargv[1], cmdargv[2:]) + elif action == 'list-repos': + if len(cmdargv) > 1: + die_with_help("{:s}: too many arguments".format(action)) + list_repos(user) + elif action == 'setup-repo': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) + warn('{:s} is deprecated. ' + 'Use `git push` to create new repositories.'.format(action)) + create_pkgbase(cmdargv[1], user) + elif action == 'restore': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) - pkgbase = cmdargv[1] - if not re.match(repo_regex, pkgbase): - die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) + pkgbase = cmdargv[1] + if not re.match(repo_regex, pkgbase): + die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) - if pkgbase_exists(pkgbase): - die('{:s}: package base exists: {:s}'.format(action, pkgbase)) - create_pkgbase(pkgbase, user) + if pkgbase_exists(pkgbase): + die('{:s}: package base exists: {:s}'.format(action, pkgbase)) + create_pkgbase(pkgbase, user) - os.environ["AUR_USER"] = user - os.environ["AUR_PKGBASE"] = pkgbase - os.execl(git_update_cmd, git_update_cmd, 'restore') -elif action == 'adopt': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + os.environ["AUR_USER"] = user + os.environ["AUR_PKGBASE"] = pkgbase + os.execl(git_update_cmd, git_update_cmd, 'restore') + elif action == 'adopt': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) - pkgbase = cmdargv[1] - pkgbase_adopt(pkgbase, user, privileged) -elif action == 'disown': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + pkgbase = cmdargv[1] + pkgbase_adopt(pkgbase, user, privileged) + elif action == 'disown': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) - pkgbase = cmdargv[1] - pkgbase_disown(pkgbase, user, privileged) -elif action == 'set-comaintainers': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) + pkgbase = cmdargv[1] + pkgbase_disown(pkgbase, user, privileged) + elif action == 'set-comaintainers': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) - pkgbase = cmdargv[1] - userlist = cmdargv[2:] - pkgbase_set_comaintainers(pkgbase, userlist, user, privileged) -elif action == 'help': - cmds = { - "adopt ": "Adopt a package base.", - "disown ": "Disown a package base.", - "help": "Show this help message and exit.", - "list-repos": "List all your repositories.", - "restore ": "Restore a deleted package base.", - "set-comaintainers [...]": "Set package base co-maintainers.", - "set-keywords [...]": "Change package base keywords.", - "setup-repo ": "Create a repository (deprecated).", - "git-receive-pack": "Internal command used with Git.", - "git-upload-pack": "Internal command used with Git.", - } - usage(cmds) -else: - die_with_help("invalid command: {:s}".format(action)) + pkgbase = cmdargv[1] + userlist = cmdargv[2:] + pkgbase_set_comaintainers(pkgbase, userlist, user, privileged) + elif action == 'help': + cmds = { + "adopt ": "Adopt a package base.", + "disown ": "Disown a package base.", + "help": "Show this help message and exit.", + "list-repos": "List all your repositories.", + "restore ": "Restore a deleted package base.", + "set-comaintainers [...]": "Set package base co-maintainers.", + "set-keywords [...]": "Change package base keywords.", + "setup-repo ": "Create a repository (deprecated).", + "git-receive-pack": "Internal command used with Git.", + "git-upload-pack": "Internal command used with Git.", + } + usage(cmds) + else: + die_with_help("invalid command: {:s}".format(action)) + + +if __name__ == '__main__': + main() From 1946486a67d6085318e00c753d341ab05d12904c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 09:08:33 +0200 Subject: [PATCH 0242/1891] git-update: Move entry point to a main() method Move the main program logic of git-update to a main() method such that it can be used as a module and easily be invoked by setuptools wrapper scripts. Signed-off-by: Lukas Fleischer --- git-interface/git-update.py | 304 +++++++++++++++++++----------------- 1 file changed, 159 insertions(+), 145 deletions(-) diff --git a/git-interface/git-update.py b/git-interface/git-update.py index be4c9be9..36c38ae8 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -233,173 +233,187 @@ def die_commit(msg, commit): exit(1) -repo = pygit2.Repository(repo_path) +def main(): + repo = pygit2.Repository(repo_path) -user = os.environ.get("AUR_USER") -pkgbase = os.environ.get("AUR_PKGBASE") -privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1') -warn_or_die = warn if privileged else die + user = os.environ.get("AUR_USER") + pkgbase = os.environ.get("AUR_PKGBASE") + privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1') + warn_or_die = warn if privileged else die -if len(sys.argv) == 2 and sys.argv[1] == "restore": - if 'refs/heads/' + pkgbase not in repo.listall_references(): - die('{:s}: repository not found: {:s}'.format(sys.argv[1], pkgbase)) - refname = "refs/heads/master" - sha1_old = sha1_new = repo.lookup_reference('refs/heads/' + pkgbase).target -elif len(sys.argv) == 4: - refname, sha1_old, sha1_new = sys.argv[1:4] -else: - die("invalid arguments") + if len(sys.argv) == 2 and sys.argv[1] == "restore": + if 'refs/heads/' + pkgbase not in repo.listall_references(): + die('{:s}: repository not found: {:s}'.format(sys.argv[1], + pkgbase)) + refname = "refs/heads/master" + branchref = 'refs/heads/' + pkgbase + sha1_old = sha1_new = repo.lookup_reference(branchref).target + elif len(sys.argv) == 4: + refname, sha1_old, sha1_new = sys.argv[1:4] + else: + die("invalid arguments") -if refname != "refs/heads/master": - die("pushing to a branch other than master is restricted") + if refname != "refs/heads/master": + die("pushing to a branch other than master is restricted") -conn = db.Connection() + conn = db.Connection() -# Detect and deny non-fast-forwards. -if sha1_old != "0000000000000000000000000000000000000000" and not privileged: - walker = repo.walk(sha1_old, pygit2.GIT_SORT_TOPOLOGICAL) - walker.hide(sha1_new) - if next(walker, None) is not None: - die("denying non-fast-forward (you should pull first)") + # Detect and deny non-fast-forwards. + if sha1_old != "0" * 40 and not privileged: + walker = repo.walk(sha1_old, pygit2.GIT_SORT_TOPOLOGICAL) + walker.hide(sha1_new) + if next(walker, None) is not None: + die("denying non-fast-forward (you should pull first)") -# Prepare the walker that validates new commits. -walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) -if sha1_old != "0000000000000000000000000000000000000000": - walker.hide(sha1_old) + # Prepare the walker that validates new commits. + walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) + if sha1_old != "0" * 40: + walker.hide(sha1_old) -# Validate all new commits. -for commit in walker: - for fname in ('.SRCINFO', 'PKGBUILD'): - if fname not in commit.tree: - die_commit("missing {:s}".format(fname), str(commit.id)) - - for treeobj in commit.tree: - blob = repo[treeobj.id] - - if isinstance(blob, pygit2.Tree): - die_commit("the repository must not contain subdirectories", - str(commit.id)) - - if not isinstance(blob, pygit2.Blob): - die_commit("not a blob object: {:s}".format(treeobj), - str(commit.id)) - - if blob.size > max_blob_size: - die_commit("maximum blob size ({:s}) exceeded".format(size_humanize(max_blob_size)), str(commit.id)) - - metadata_raw = repo[commit.tree['.SRCINFO'].id].data.decode() - (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) - if errors: - sys.stderr.write("error: The following errors occurred " - "when parsing .SRCINFO in commit\n") - sys.stderr.write("error: {:s}:\n".format(str(commit.id))) - for error in errors: - for err in error['error']: - sys.stderr.write("error: line {:d}: {:s}\n".format(error['line'], err)) - exit(1) - - metadata_pkgbase = metadata['pkgbase'] - if not re.match(repo_regex, metadata_pkgbase): - die_commit('invalid pkgbase: {:s}'.format(metadata_pkgbase), - str(commit.id)) - - for pkgname in set(metadata['packages'].keys()): - pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) - - for field in ('pkgver', 'pkgrel', 'pkgname'): - if field not in pkginfo: - die_commit('missing mandatory field: {:s}'.format(field), - str(commit.id)) - - if 'epoch' in pkginfo and not pkginfo['epoch'].isdigit(): - die_commit('invalid epoch: {:s}'.format(pkginfo['epoch']), - str(commit.id)) - - if not re.match(r'[a-z0-9][a-z0-9\.+_-]*$', pkginfo['pkgname']): - die_commit('invalid package name: {:s}'.format(pkginfo['pkgname']), - str(commit.id)) - - for field in ('pkgname', 'pkgdesc', 'url'): - if field in pkginfo and len(pkginfo[field]) > 255: - die_commit('{:s} field too long: {:s}'.format(field, pkginfo[field]), - str(commit.id)) - - for field in ('install', 'changelog'): - if field in pkginfo and not pkginfo[field] in commit.tree: - die_commit('missing {:s} file: {:s}'.format(field, pkginfo[field]), - str(commit.id)) - - for field in extract_arch_fields(pkginfo, 'source'): - fname = field['value'] - if "://" in fname or "lp:" in fname: - continue + # Validate all new commits. + for commit in walker: + for fname in ('.SRCINFO', 'PKGBUILD'): if fname not in commit.tree: - die_commit('missing source file: {:s}'.format(fname), + die_commit("missing {:s}".format(fname), str(commit.id)) + + for treeobj in commit.tree: + blob = repo[treeobj.id] + + if isinstance(blob, pygit2.Tree): + die_commit("the repository must not contain subdirectories", str(commit.id)) + if not isinstance(blob, pygit2.Blob): + die_commit("not a blob object: {:s}".format(treeobj), + str(commit.id)) -# Display a warning if .SRCINFO is unchanged. -if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): - srcinfo_id_old = repo[sha1_old].tree['.SRCINFO'].id - srcinfo_id_new = repo[sha1_new].tree['.SRCINFO'].id - if srcinfo_id_old == srcinfo_id_new: - warn(".SRCINFO unchanged. The package database will not be updated!") + if blob.size > max_blob_size: + die_commit("maximum blob size ({:s}) exceeded".format( + size_humanize(max_blob_size)), str(commit.id)) -# Read .SRCINFO from the HEAD commit. -metadata_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode() -(metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) + metadata_raw = repo[commit.tree['.SRCINFO'].id].data.decode() + (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) + if errors: + sys.stderr.write("error: The following errors occurred " + "when parsing .SRCINFO in commit\n") + sys.stderr.write("error: {:s}:\n".format(str(commit.id))) + for error in errors: + for err in error['error']: + sys.stderr.write("error: line {:d}: {:s}\n".format( + error['line'], err)) + exit(1) -# Ensure that the package base name matches the repository name. -metadata_pkgbase = metadata['pkgbase'] -if metadata_pkgbase != pkgbase: - die('invalid pkgbase: {:s}, expected {:s}'.format(metadata_pkgbase, pkgbase)) + metadata_pkgbase = metadata['pkgbase'] + if not re.match(repo_regex, metadata_pkgbase): + die_commit('invalid pkgbase: {:s}'.format(metadata_pkgbase), + str(commit.id)) -# Ensure that packages are neither blacklisted nor overwritten. -pkgbase = metadata['pkgbase'] -cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase]) -row = cur.fetchone() -pkgbase_id = row[0] if row else 0 + for pkgname in set(metadata['packages'].keys()): + pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) -cur = conn.execute("SELECT Name FROM PackageBlacklist") -blacklist = [row[0] for row in cur.fetchall()] + for field in ('pkgver', 'pkgrel', 'pkgname'): + if field not in pkginfo: + die_commit('missing mandatory field: {:s}'.format(field), + str(commit.id)) -cur = conn.execute("SELECT Name, Repo FROM OfficialProviders") -providers = dict(cur.fetchall()) + if 'epoch' in pkginfo and not pkginfo['epoch'].isdigit(): + die_commit('invalid epoch: {:s}'.format(pkginfo['epoch']), + str(commit.id)) -for pkgname in srcinfo.utils.get_package_names(metadata): - pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) - pkgname = pkginfo['pkgname'] + if not re.match(r'[a-z0-9][a-z0-9\.+_-]*$', pkginfo['pkgname']): + die_commit('invalid package name: {:s}'.format( + pkginfo['pkgname']), str(commit.id)) - if pkgname in blacklist: - warn_or_die('package is blacklisted: {:s}'.format(pkgname)) - if pkgname in providers: - warn_or_die('package already provided by [{:s}]: {:s}'.format(providers[pkgname], pkgname)) + for field in ('pkgname', 'pkgdesc', 'url'): + if field in pkginfo and len(pkginfo[field]) > 255: + die_commit('{:s} field too long: {:s}'.format(field, + pkginfo[field]), str(commit.id)) - cur = conn.execute("SELECT COUNT(*) FROM Packages WHERE Name = ? AND " + - "PackageBaseID <> ?", [pkgname, pkgbase_id]) - if cur.fetchone()[0] > 0: - die('cannot overwrite package: {:s}'.format(pkgname)) + for field in ('install', 'changelog'): + if field in pkginfo and not pkginfo[field] in commit.tree: + die_commit('missing {:s} file: {:s}'.format(field, + pkginfo[field]), str(commit.id)) -# Create a new package base if it does not exist yet. -if pkgbase_id == 0: - pkgbase_id = create_pkgbase(conn, pkgbase, user) + for field in extract_arch_fields(pkginfo, 'source'): + fname = field['value'] + if "://" in fname or "lp:" in fname: + continue + if fname not in commit.tree: + die_commit('missing source file: {:s}'.format(fname), + str(commit.id)) -# Store package base details in the database. -save_metadata(metadata, conn, user) + # Display a warning if .SRCINFO is unchanged. + if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): + srcinfo_id_old = repo[sha1_old].tree['.SRCINFO'].id + srcinfo_id_new = repo[sha1_new].tree['.SRCINFO'].id + if srcinfo_id_old == srcinfo_id_new: + warn(".SRCINFO unchanged. " + "The package database will not be updated!") -# Create (or update) a branch with the name of the package base for better -# accessibility. -repo.create_reference('refs/heads/' + pkgbase, sha1_new, True) + # Read .SRCINFO from the HEAD commit. + metadata_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode() + (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) -# Work around a Git bug: The HEAD ref is not updated when using gitnamespaces. -# This can be removed once the bug fix is included in Git mainline. See -# http://git.661346.n2.nabble.com/PATCH-receive-pack-Create-a-HEAD-ref-for-ref-namespace-td7632149.html -# for details. -repo.create_reference('refs/namespaces/' + pkgbase + '/HEAD', sha1_new, True) + # Ensure that the package base name matches the repository name. + metadata_pkgbase = metadata['pkgbase'] + if metadata_pkgbase != pkgbase: + die('invalid pkgbase: {:s}, expected {:s}'.format(metadata_pkgbase, + pkgbase)) -# Send package update notifications. -update_notify(conn, user, pkgbase_id) + # Ensure that packages are neither blacklisted nor overwritten. + pkgbase = metadata['pkgbase'] + cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase]) + row = cur.fetchone() + pkgbase_id = row[0] if row else 0 -# Close the database. -cur.close() -conn.close() + cur = conn.execute("SELECT Name FROM PackageBlacklist") + blacklist = [row[0] for row in cur.fetchall()] + + cur = conn.execute("SELECT Name, Repo FROM OfficialProviders") + providers = dict(cur.fetchall()) + + for pkgname in srcinfo.utils.get_package_names(metadata): + pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) + pkgname = pkginfo['pkgname'] + + if pkgname in blacklist: + warn_or_die('package is blacklisted: {:s}'.format(pkgname)) + if pkgname in providers: + warn_or_die('package already provided by [{:s}]: {:s}'.format( + providers[pkgname], pkgname)) + + cur = conn.execute("SELECT COUNT(*) FROM Packages WHERE Name = ? " + + "AND PackageBaseID <> ?", [pkgname, pkgbase_id]) + if cur.fetchone()[0] > 0: + die('cannot overwrite package: {:s}'.format(pkgname)) + + # Create a new package base if it does not exist yet. + if pkgbase_id == 0: + pkgbase_id = create_pkgbase(conn, pkgbase, user) + + # Store package base details in the database. + save_metadata(metadata, conn, user) + + # Create (or update) a branch with the name of the package base for better + # accessibility. + branchref = 'refs/heads/' + pkgbase + repo.create_reference(branchref, sha1_new, True) + + # Work around a Git bug: The HEAD ref is not updated when using + # gitnamespaces. This can be removed once the bug fix is included in Git + # mainline. See + # http://git.661346.n2.nabble.com/PATCH-receive-pack-Create-a-HEAD-ref-for-ref-namespace-td7632149.html + # for details. + headref = 'refs/namespaces/' + pkgbase + '/HEAD' + repo.create_reference(headref, sha1_new, True) + + # Send package update notifications. + update_notify(conn, user, pkgbase_id) + + # Close the database. + cur.close() + conn.close() + + +if __name__ == '__main__': + main() From dc3fd60715a5b17b9542ec888c6eaeb14c284e2b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 20:18:24 +0200 Subject: [PATCH 0243/1891] Use setuptools to install Python modules Instead of using relative imports, add support for installing the config and db Python modules to a proper location using setuptools. Change all git-interface scripts to access those modules from the search path. Signed-off-by: Lukas Fleischer --- aurweb/__init__.py | 0 {git-interface => aurweb}/config.py | 0 {git-interface => aurweb}/db.py | 16 ++++++------ git-interface/__init__.py | 0 git-interface/git-auth.py | 14 +++++----- git-interface/git-serve.py | 40 ++++++++++++++--------------- git-interface/git-update.py | 14 +++++----- git-interface/test/setup.sh | 4 +++ scripts/__init__.py | 0 setup.py | 20 +++++++++++++++ 10 files changed, 66 insertions(+), 42 deletions(-) create mode 100644 aurweb/__init__.py rename {git-interface => aurweb}/config.py (100%) rename {git-interface => aurweb}/db.py (73%) create mode 100644 git-interface/__init__.py create mode 100644 scripts/__init__.py create mode 100644 setup.py diff --git a/aurweb/__init__.py b/aurweb/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/git-interface/config.py b/aurweb/config.py similarity index 100% rename from git-interface/config.py rename to aurweb/config.py diff --git a/git-interface/db.py b/aurweb/db.py similarity index 73% rename from git-interface/db.py rename to aurweb/db.py index 75d2283d..0b581970 100644 --- a/git-interface/db.py +++ b/aurweb/db.py @@ -1,7 +1,7 @@ import mysql.connector import sqlite3 -import config +import aurweb.config class Connection: @@ -9,14 +9,14 @@ class Connection: _paramstyle = None def __init__(self): - aur_db_backend = config.get('database', 'backend') + aur_db_backend = aurweb.config.get('database', 'backend') if aur_db_backend == 'mysql': - aur_db_host = config.get('database', 'host') - aur_db_name = config.get('database', 'name') - aur_db_user = config.get('database', 'user') - aur_db_pass = config.get('database', 'password') - aur_db_socket = config.get('database', 'socket') + aur_db_host = aurweb.config.get('database', 'host') + aur_db_name = aurweb.config.get('database', 'name') + aur_db_user = aurweb.config.get('database', 'user') + aur_db_pass = aurweb.config.get('database', 'password') + aur_db_socket = aurweb.config.get('database', 'socket') self._conn = mysql.connector.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, @@ -25,7 +25,7 @@ class Connection: buffered=True) self._paramstyle = mysql.connector.paramstyle elif aur_db_backend == 'sqlite': - aur_db_name = config.get('database', 'name') + aur_db_name = aurweb.config.get('database', 'name') self._conn = sqlite3.connect(aur_db_name) self._paramstyle = sqlite3.paramstyle else: diff --git a/git-interface/__init__.py b/git-interface/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/git-interface/git-auth.py b/git-interface/git-auth.py index d3b0188b..022b0fff 100755 --- a/git-interface/git-auth.py +++ b/git-interface/git-auth.py @@ -4,8 +4,8 @@ import shlex import re import sys -import config -import db +import aurweb.config +import aurweb.db def format_command(env_vars, command, ssh_opts, ssh_key): @@ -24,17 +24,17 @@ def format_command(env_vars, command, ssh_opts, ssh_key): def main(): - valid_keytypes = config.get('auth', 'valid-keytypes').split() - username_regex = config.get('auth', 'username-regex') - git_serve_cmd = config.get('auth', 'git-serve-cmd') - ssh_opts = config.get('auth', 'ssh-options') + valid_keytypes = aurweb.config.get('auth', 'valid-keytypes').split() + username_regex = aurweb.config.get('auth', 'username-regex') + git_serve_cmd = aurweb.config.get('auth', 'git-serve-cmd') + ssh_opts = aurweb.config.get('auth', 'ssh-options') keytype = sys.argv[1] keytext = sys.argv[2] if keytype not in valid_keytypes: exit(1) - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT Users.Username, Users.AccountTypeID FROM Users " "INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID " diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 8bcecd27..5f3b26dd 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -7,23 +7,23 @@ import subprocess import sys import time -import config -import db +import aurweb.config +import aurweb.db -notify_cmd = config.get('notifications', 'notify-cmd') +notify_cmd = aurweb.config.get('notifications', 'notify-cmd') -repo_path = config.get('serve', 'repo-path') -repo_regex = config.get('serve', 'repo-regex') -git_shell_cmd = config.get('serve', 'git-shell-cmd') -git_update_cmd = config.get('serve', 'git-update-cmd') -ssh_cmdline = config.get('serve', 'ssh-cmdline') +repo_path = aurweb.config.get('serve', 'repo-path') +repo_regex = aurweb.config.get('serve', 'repo-regex') +git_shell_cmd = aurweb.config.get('serve', 'git-shell-cmd') +git_update_cmd = aurweb.config.get('serve', 'git-update-cmd') +ssh_cmdline = aurweb.config.get('serve', 'ssh-cmdline') -enable_maintenance = config.getboolean('options', 'enable-maintenance') -maintenance_exc = config.get('options', 'maintenance-exceptions').split() +enable_maintenance = aurweb.config.getboolean('options', 'enable-maintenance') +maintenance_exc = aurweb.config.get('options', 'maintenance-exceptions').split() def pkgbase_from_name(pkgbase): - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase]) row = cur.fetchone() @@ -35,7 +35,7 @@ def pkgbase_exists(pkgbase): def list_repos(user): - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] @@ -55,7 +55,7 @@ def create_pkgbase(pkgbase, user): if pkgbase_exists(pkgbase): die('{:s}: package base already exists: {:s}'.format(action, pkgbase)) - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] @@ -81,7 +81,7 @@ def pkgbase_adopt(pkgbase, user, privileged): if not pkgbase_id: die('{:s}: package base not found: {:s}'.format(action, pkgbase)) - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM PackageBases WHERE ID = ? AND " + "MaintainerUID IS NULL", [pkgbase_id]) @@ -111,7 +111,7 @@ def pkgbase_adopt(pkgbase, user, privileged): def pkgbase_get_comaintainers(pkgbase): - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT UserName FROM PackageComaintainers " + "INNER JOIN Users " + @@ -132,7 +132,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged): if not privileged and not pkgbase_has_full_access(pkgbase, user): die('{:s}: permission denied: {:s}'.format(action, user)) - conn = db.Connection() + conn = aurweb.db.Connection() userlist_old = set(pkgbase_get_comaintainers(pkgbase)) @@ -198,7 +198,7 @@ def pkgbase_disown(pkgbase, user, privileged): comaintainers = [] new_maintainer_userid = None - conn = db.Connection() + conn = aurweb.db.Connection() # Make the first co-maintainer the new maintainer, unless the action was # enforced by a Trusted User. @@ -232,7 +232,7 @@ def pkgbase_set_keywords(pkgbase, keywords): if not pkgbase_id: die('{:s}: package base not found: {:s}'.format(action, pkgbase)) - conn = db.Connection() + conn = aurweb.db.Connection() conn.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = ?", [pkgbase_id]) @@ -245,7 +245,7 @@ def pkgbase_set_keywords(pkgbase, keywords): def pkgbase_has_write_access(pkgbase, user): - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT COUNT(*) FROM PackageBases " + "LEFT JOIN PackageComaintainers " + @@ -259,7 +259,7 @@ def pkgbase_has_write_access(pkgbase, user): def pkgbase_has_full_access(pkgbase, user): - conn = db.Connection() + conn = aurweb.db.Connection() cur = conn.execute("SELECT COUNT(*) FROM PackageBases " + "INNER JOIN Users " + diff --git a/git-interface/git-update.py b/git-interface/git-update.py index 36c38ae8..73373410 100755 --- a/git-interface/git-update.py +++ b/git-interface/git-update.py @@ -10,15 +10,15 @@ import time import srcinfo.parse import srcinfo.utils -import config -import db +import aurweb.config +import aurweb.db -notify_cmd = config.get('notifications', 'notify-cmd') +notify_cmd = aurweb.config.get('notifications', 'notify-cmd') -repo_path = config.get('serve', 'repo-path') -repo_regex = config.get('serve', 'repo-regex') +repo_path = aurweb.config.get('serve', 'repo-path') +repo_regex = aurweb.config.get('serve', 'repo-regex') -max_blob_size = config.getint('update', 'max-blob-size') +max_blob_size = aurweb.config.getint('update', 'max-blob-size') def size_humanize(num): @@ -256,7 +256,7 @@ def main(): if refname != "refs/heads/master": die("pushing to a branch other than master is restricted") - conn = db.Connection() + conn = aurweb.db.Connection() # Detect and deny non-fast-forwards. if sha1_old != "0" * 40 and not privileged: diff --git a/git-interface/test/setup.sh b/git-interface/test/setup.sh index f9c16166..d269af66 100644 --- a/git-interface/test/setup.sh +++ b/git-interface/test/setup.sh @@ -2,6 +2,10 @@ TEST_DIRECTORY="$(pwd)" . ./sharness.sh +# Configure python search path. +PYTHONPATH="$TEST_DIRECTORY/../../" +export PYTHONPATH + # Configure paths to the Git interface scripts. GIT_AUTH="$TEST_DIRECTORY/../git-auth.py" GIT_SERVE="$TEST_DIRECTORY/../git-serve.py" diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..48eb1769 --- /dev/null +++ b/setup.py @@ -0,0 +1,20 @@ +import re +from setuptools import setup, find_packages +import sys + +version = None +with open('web/lib/version.inc.php', 'r') as f: + for line in f.readlines(): + match = re.match(r'^define\("AURWEB_VERSION", "v([0-9.]+)"\);$', line) + if match: + version = match.group(1) + +if not version: + sys.stderr.write('error: Failed to parse version file!') + sys.exit(1) + +setup( + name="aurweb", + version=version, + packages=find_packages(), +) From 8c99184f6d0922a7a4076d0c050a924e07a42b3d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 20:48:34 +0200 Subject: [PATCH 0244/1891] Use config and db in scripts Instead of using configparser and mysql.connector directly, change all Python scripts to use the config and db Python modules which are now accessible from a common location. Signed-off-by: Lukas Fleischer --- scripts/aurblup.py | 37 ++---- scripts/mkpkglists.py | 32 ++--- scripts/notify.py | 273 +++++++++++++++++++------------------- scripts/pkgmaint.py | 28 +--- scripts/popupdate.py | 36 ++--- scripts/tuvotereminder.py | 24 +--- 6 files changed, 182 insertions(+), 248 deletions(-) diff --git a/scripts/aurblup.py b/scripts/aurblup.py index 07119b5f..0009715f 100755 --- a/scripts/aurblup.py +++ b/scripts/aurblup.py @@ -1,22 +1,14 @@ #!/usr/bin/python3 -import configparser -import mysql.connector -import os import pyalpm import re -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") +import aurweb.config +import aurweb.db -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') -db_path = config.get('aurblup', 'db-path') -sync_dbs = config.get('aurblup', 'sync-dbs').split(' ') -servers = config.get('aurblup', 'servers').split(' ') +db_path = aurweb.config.get('aurblup', 'db-path') +sync_dbs = aurweb.config.get('aurblup', 'sync-dbs').split(' ') +servers = aurweb.config.get('aurblup', 'servers').split(' ') def main(): @@ -42,24 +34,21 @@ def main(): providers.add((pkg.name, provisionname)) repomap[(pkg.name, provisionname)] = repo.name - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) - cur = db.cursor() + conn = aurweb.db.Connection() - cur.execute("SELECT Name, Provides FROM OfficialProviders") + cur = conn.execute("SELECT Name, Provides FROM OfficialProviders") oldproviders = set(cur.fetchall()) for pkg, provides in providers.difference(oldproviders): repo = repomap[(pkg, provides)] - cur.execute("INSERT INTO OfficialProviders (Name, Repo, Provides) " - "VALUES (%s, %s, %s)", [pkg, repo, provides]) + conn.execute("INSERT INTO OfficialProviders (Name, Repo, Provides) " + "VALUES (?, ?, ?)", [pkg, repo, provides]) for pkg, provides in oldproviders.difference(providers): - cur.execute("DELETE FROM OfficialProviders " - "WHERE Name = %s AND Provides = %s", [pkg, provides]) + conn.execute("DELETE FROM OfficialProviders " + "WHERE Name = ? AND Provides = ?", [pkg, provides]) - db.commit() - db.close() + conn.commit() + conn.close() if __name__ == '__main__': diff --git a/scripts/mkpkglists.py b/scripts/mkpkglists.py index 8cab0a97..70cbd139 100755 --- a/scripts/mkpkglists.py +++ b/scripts/mkpkglists.py @@ -1,28 +1,16 @@ #!/usr/bin/python3 -import configparser import datetime import gzip -import mysql.connector import os +import aurweb.db + docroot = os.path.dirname(os.path.realpath(__file__)) + "/../web/html/" -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") - -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') - def main(): - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) - cur = db.cursor() + conn = aurweb.db.Connection() datestr = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") pkglist_header = "# AUR package list, generated on " + datestr @@ -30,19 +18,19 @@ def main(): with gzip.open(docroot + "packages.gz", "w") as f: f.write(bytes(pkglist_header + "\n", "UTF-8")) - cur.execute("SELECT Packages.Name FROM Packages " + - "INNER JOIN PackageBases " + - "ON PackageBases.ID = Packages.PackageBaseID " + - "WHERE PackageBases.PackagerUID IS NOT NULL") + cur = conn.execute("SELECT Packages.Name FROM Packages " + + "INNER JOIN PackageBases " + + "ON PackageBases.ID = Packages.PackageBaseID " + + "WHERE PackageBases.PackagerUID IS NOT NULL") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) with gzip.open(docroot + "pkgbase.gz", "w") as f: f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) - cur.execute("SELECT Name FROM PackageBases " + - "WHERE PackagerUID IS NOT NULL") + cur = conn.execute("SELECT Name FROM PackageBases " + + "WHERE PackagerUID IS NOT NULL") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - db.close() + conn.close() if __name__ == '__main__': diff --git a/scripts/notify.py b/scripts/notify.py index e8210a87..ddd6e49b 100755 --- a/scripts/notify.py +++ b/scripts/notify.py @@ -1,28 +1,19 @@ #!/usr/bin/python3 -import configparser import email.mime.text -import mysql.connector -import os import subprocess import sys import textwrap -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + '/../conf/config') +import aurweb.config +import aurweb.db -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') +aur_location = aurweb.config.get('options', 'aur_location') +aur_request_ml = aurweb.config.get('options', 'aur_request_ml') -aur_location = config.get('options', 'aur_location') -aur_request_ml = config.get('options', 'aur_request_ml') - -sendmail = config.get('notifications', 'sendmail') -sender = config.get('notifications', 'sender') -reply_to = config.get('notifications', 'reply-to') +sendmail = aurweb.config.get('notifications', 'sendmail') +sender = aurweb.config.get('notifications', 'sender') +reply_to = aurweb.config.get('notifications', 'reply-to') def headers_cc(cclist): @@ -60,120 +51,127 @@ def send_notification(to, subject, body, refs, headers={}): p.communicate(msg.as_bytes()) -def username_from_id(cur, uid): - cur.execute('SELECT UserName FROM Users WHERE ID = %s', [uid]) +def username_from_id(conn, uid): + cur = conn.execute('SELECT UserName FROM Users WHERE ID = ?', [uid]) return cur.fetchone()[0] -def pkgbase_from_id(cur, pkgbase_id): - cur.execute('SELECT Name FROM PackageBases WHERE ID = %s', [pkgbase_id]) +def pkgbase_from_id(conn, pkgbase_id): + cur = conn.execute('SELECT Name FROM PackageBases WHERE ID = ?', + [pkgbase_id]) return cur.fetchone()[0] -def pkgbase_from_pkgreq(cur, reqid): - cur.execute('SELECT PackageBaseID FROM PackageRequests WHERE ID = %s', - [reqid]) +def pkgbase_from_pkgreq(conn, reqid): + cur = conn.execute('SELECT PackageBaseID FROM PackageRequests ' + + 'WHERE ID = ?', [reqid]) return cur.fetchone()[0] -def get_user_email(cur, uid): - cur.execute('SELECT Email FROM Users WHERE ID = %s', [uid]) +def get_user_email(conn, uid): + cur = conn.execute('SELECT Email FROM Users WHERE ID = ?', [uid]) return cur.fetchone()[0] -def get_maintainer_email(cur, pkgbase_id): - cur.execute('SELECT Users.Email FROM Users ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.MaintainerUID = Users.ID WHERE ' + - 'PackageBases.ID = %s', [pkgbase_id]) +def get_maintainer_email(conn, pkgbase_id): + cur = conn.execute('SELECT Users.Email FROM Users ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.MaintainerUID = Users.ID WHERE ' + + 'PackageBases.ID = ?', [pkgbase_id]) return cur.fetchone()[0] -def get_recipients(cur, pkgbase_id, uid): - cur.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'PackageNotifications.UserID != %s AND ' + - 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) +def get_recipients(conn, pkgbase_id, uid): + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] -def get_comment_recipients(cur, pkgbase_id, uid): - cur.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.CommentNotify = 1 AND ' + - 'PackageNotifications.UserID != %s AND ' + - 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) +def get_comment_recipients(conn, pkgbase_id, uid): + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.CommentNotify = 1 AND ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] -def get_update_recipients(cur, pkgbase_id, uid): - cur.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.UpdateNotify = 1 AND ' + - 'PackageNotifications.UserID != %s AND ' + - 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) +def get_update_recipients(conn, pkgbase_id, uid): + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.UpdateNotify = 1 AND ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] -def get_ownership_recipients(cur, pkgbase_id, uid): - cur.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.OwnershipNotify = 1 AND ' + - 'PackageNotifications.UserID != %s AND ' + - 'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id]) +def get_ownership_recipients(conn, pkgbase_id, uid): + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.OwnershipNotify = 1 AND ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, pkgbase_id]) return [row[0] for row in cur.fetchall()] -def get_request_recipients(cur, reqid): - cur.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + - 'INNER JOIN Users ' + - 'ON Users.ID = PackageRequests.UsersID ' + - 'OR Users.ID = PackageBases.MaintainerUID ' + - 'WHERE PackageRequests.ID = %s', [reqid]) +def get_request_recipients(conn, reqid): + cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + + 'INNER JOIN Users ' + + 'ON Users.ID = PackageRequests.UsersID ' + + 'OR Users.ID = PackageBases.MaintainerUID ' + + 'WHERE PackageRequests.ID = ?', [reqid]) return [row[0] for row in cur.fetchall()] -def get_tu_vote_reminder_recipients(cur, vote_id): - cur.execute('SELECT Users.Email FROM Users WHERE AccountTypeID = 2 ' + - 'EXCEPT SELECT Users.Email FROM Users ' + - 'INNER JOIN TU_Votes ' + - 'ON TU_Votes.UserID = Users.ID ' + - 'WHERE TU_Votes.VoteID = %s', [vote_id]) +def get_tu_vote_reminder_recipients(conn, vote_id): + cur = conn.execute('SELECT Users.Email FROM Users ' + + 'WHERE AccountTypeID = 2 ' + + 'EXCEPT SELECT Users.Email FROM Users ' + + 'INNER JOIN TU_Votes ' + + 'ON TU_Votes.UserID = Users.ID ' + + 'WHERE TU_Votes.VoteID = ?', [vote_id]) return [row[0] for row in cur.fetchall()] -def get_comment(cur, comment_id): - cur.execute('SELECT Comments FROM PackageComments WHERE ID = %s', - [comment_id]) +def get_comment(conn, comment_id): + cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', + [comment_id]) return cur.fetchone()[0] -def get_flagger_comment(cur, pkgbase_id): - cur.execute('SELECT FlaggerComment FROM PackageBases WHERE ID = %s', - [pkgbase_id]) +def get_flagger_comment(conn, pkgbase_id): + cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ID = ?', + [pkgbase_id]) return cur.fetchone()[0] -def get_request_comment(cur, reqid): - cur.execute('SELECT Comments FROM PackageRequests WHERE ID = %s', [reqid]) +def get_request_comment(conn, reqid): + cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?', + [reqid]) return cur.fetchone()[0] -def get_request_closure_comment(cur, reqid): - cur.execute('SELECT ClosureComment FROM PackageRequests WHERE ID = %s', - [reqid]) +def get_request_closure_comment(conn, reqid): + cur = conn.execute('SELECT ClosureComment FROM PackageRequests ' + + 'WHERE ID = ?', [reqid]) return cur.fetchone()[0] -def send_resetkey(cur, uid): - cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', - [uid]) +def send_resetkey(conn, uid): + cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' + + 'WHERE ID = ?', [uid]) username, to, resetkey = cur.fetchone() subject = 'AUR Password Reset' @@ -186,9 +184,9 @@ def send_resetkey(cur, uid): send_notification([to], subject, body, refs) -def welcome(cur, uid): - cur.execute('SELECT UserName, Email, ResetKey FROM Users WHERE ID = %s', - [uid]) +def welcome(conn, uid): + cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' + + 'WHERE ID = ?', [uid]) username, to, resetkey = cur.fetchone() subject = 'Welcome to the Arch User Repository' @@ -201,11 +199,11 @@ def welcome(cur, uid): send_notification([to], subject, body, refs) -def comment(cur, uid, pkgbase_id, comment_id): - user = username_from_id(cur, uid) - pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = get_comment_recipients(cur, pkgbase_id, uid) - text = get_comment(cur, comment_id) +def comment(conn, uid, pkgbase_id, comment_id): + user = username_from_id(conn, uid) + pkgbase = pkgbase_from_id(conn, pkgbase_id) + to = get_comment_recipients(conn, pkgbase_id, uid) + text = get_comment(conn, comment_id) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -224,10 +222,10 @@ def comment(cur, uid, pkgbase_id, comment_id): send_notification(to, subject, body, refs, headers) -def update(cur, uid, pkgbase_id): - user = username_from_id(cur, uid) - pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = get_update_recipients(cur, pkgbase_id, uid) +def update(conn, uid, pkgbase_id): + user = username_from_id(conn, uid) + pkgbase = pkgbase_from_id(conn, pkgbase_id) + to = get_update_recipients(conn, pkgbase_id, uid) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -246,11 +244,11 @@ def update(cur, uid, pkgbase_id): send_notification(to, subject, body, refs, headers) -def flag(cur, uid, pkgbase_id): - user = username_from_id(cur, uid) - pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = [get_maintainer_email(cur, pkgbase_id)] - text = get_flagger_comment(cur, pkgbase_id) +def flag(conn, uid, pkgbase_id): + user = username_from_id(conn, uid) + pkgbase = pkgbase_from_id(conn, pkgbase_id) + to = [get_maintainer_email(conn, pkgbase_id)] + text = get_flagger_comment(conn, pkgbase_id) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -265,10 +263,10 @@ def flag(cur, uid, pkgbase_id): send_notification(to, subject, body, refs) -def adopt(cur, pkgbase_id, uid): - user = username_from_id(cur, uid) - pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = get_ownership_recipients(cur, pkgbase_id, uid) +def adopt(conn, pkgbase_id, uid): + user = username_from_id(conn, uid) + pkgbase = pkgbase_from_id(conn, pkgbase_id) + to = get_ownership_recipients(conn, pkgbase_id, uid) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -281,10 +279,10 @@ def adopt(cur, pkgbase_id, uid): send_notification(to, subject, body, refs) -def disown(cur, pkgbase_id, uid): - user = username_from_id(cur, uid) - pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = get_ownership_recipients(cur, pkgbase_id, uid) +def disown(conn, pkgbase_id, uid): + user = username_from_id(conn, uid) + pkgbase = pkgbase_from_id(conn, pkgbase_id) + to = get_ownership_recipients(conn, pkgbase_id, uid) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -297,9 +295,9 @@ def disown(cur, pkgbase_id, uid): send_notification(to, subject, body, refs) -def comaintainer_add(cur, pkgbase_id, uid): - pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = [get_user_email(cur, uid)] +def comaintainer_add(conn, pkgbase_id, uid): + pkgbase = pkgbase_from_id(conn, pkgbase_id) + to = [get_user_email(conn, uid)] pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -310,9 +308,9 @@ def comaintainer_add(cur, pkgbase_id, uid): send_notification(to, subject, body, refs) -def comaintainer_remove(cur, pkgbase_id, uid): - pkgbase = pkgbase_from_id(cur, pkgbase_id) - to = [get_user_email(cur, uid)] +def comaintainer_remove(conn, pkgbase_id, uid): + pkgbase = pkgbase_from_id(conn, pkgbase_id) + to = [get_user_email(conn, uid)] pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -324,12 +322,12 @@ def comaintainer_remove(cur, pkgbase_id, uid): send_notification(to, subject, body, refs) -def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): - user = username_from_id(cur, uid) - old_pkgbase = pkgbase_from_id(cur, old_pkgbase_id) +def delete(conn, uid, old_pkgbase_id, new_pkgbase_id=None): + user = username_from_id(conn, uid) + old_pkgbase = pkgbase_from_id(conn, old_pkgbase_id) if new_pkgbase_id: - new_pkgbase = pkgbase_from_id(cur, new_pkgbase_id) - to = get_recipients(cur, old_pkgbase_id, uid) + new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id) + to = get_recipients(conn, old_pkgbase_id, uid) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + old_pkgbase + '/' @@ -354,12 +352,12 @@ def delete(cur, uid, old_pkgbase_id, new_pkgbase_id=None): send_notification(to, subject, body, refs) -def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): - user = username_from_id(cur, uid) - pkgbase = pkgbase_from_id(cur, pkgbase_id) +def request_open(conn, uid, reqid, reqtype, pkgbase_id, merge_into=None): + user = username_from_id(conn, uid) + pkgbase = pkgbase_from_id(conn, pkgbase_id) to = [aur_request_ml] - cc = get_request_recipients(cur, reqid) - text = get_request_comment(cur, reqid) + cc = get_request_recipients(conn, reqid) + text = get_request_comment(conn, reqid) user_uri = aur_location + '/account/' + user + '/' pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' @@ -388,14 +386,14 @@ def request_open(cur, uid, reqid, reqtype, pkgbase_id, merge_into=None): send_notification(to, subject, body, refs, headers) -def request_close(cur, uid, reqid, reason): +def request_close(conn, uid, reqid, reason): to = [aur_request_ml] - cc = get_request_recipients(cur, reqid) - text = get_request_closure_comment(cur, reqid) + cc = get_request_recipients(conn, reqid) + text = get_request_closure_comment(conn, reqid) subject = '[PRQ#%d] Request %s' % (int(reqid), reason.title()) if int(uid): - user = username_from_id(cur, uid) + user = username_from_id(conn, uid) user_uri = aur_location + '/account/' + user + '/' body = 'Request #%d has been %s by %s [1]' % (int(reqid), reason, user) refs = '[1] ' + user_uri @@ -414,8 +412,8 @@ def request_close(cur, uid, reqid, reason): send_notification(to, subject, body, refs, headers) -def tu_vote_reminder(cur, vote_id): - to = get_tu_vote_reminder_recipients(cur, vote_id) +def tu_vote_reminder(conn, vote_id): + to = get_tu_vote_reminder_recipients(conn, vote_id) vote_uri = aur_location + '/tu/?id=' + vote_id @@ -445,15 +443,12 @@ def main(): 'tu-vote-reminder': tu_vote_reminder, } - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) - cur = db.cursor() + conn = aurweb.db.Connection() - action_map[action](cur, *sys.argv[2:]) + action_map[action](conn, *sys.argv[2:]) - db.commit() - db.close() + conn.commit() + conn.close() if __name__ == '__main__': diff --git a/scripts/pkgmaint.py b/scripts/pkgmaint.py index 346b046f..d0f8fe70 100755 --- a/scripts/pkgmaint.py +++ b/scripts/pkgmaint.py @@ -1,31 +1,17 @@ #!/usr/bin/python3 -import configparser -import mysql.connector -import os - -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") - -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') +import aurweb.db def main(): - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) - cur = db.cursor() + conn = aurweb.db.Connection() - cur.execute("DELETE FROM PackageBases WHERE " + - "UNIX_TIMESTAMP() - SubmittedTS > 86400 " + - "AND PackagerUID IS NULL") + conn.execute("DELETE FROM PackageBases WHERE " + + "UNIX_TIMESTAMP() - SubmittedTS > 86400 " + + "AND PackagerUID IS NULL") - db.commit() - db.close() + conn.commit() + conn.close() if __name__ == '__main__': diff --git a/scripts/popupdate.py b/scripts/popupdate.py index 26d83790..f5e09d97 100755 --- a/scripts/popupdate.py +++ b/scripts/popupdate.py @@ -1,36 +1,22 @@ #!/usr/bin/python3 -import configparser -import mysql.connector -import os - -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") - -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') +import aurweb.db def main(): - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) - cur = db.cursor() + conn = aurweb.db.Connection() - cur.execute("UPDATE PackageBases SET NumVotes = (" + - "SELECT COUNT(*) FROM PackageVotes " + - "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") + conn.execute("UPDATE PackageBases SET NumVotes = (" + + "SELECT COUNT(*) FROM PackageVotes " + + "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") - cur.execute("UPDATE PackageBases SET Popularity = (" + - "SELECT COALESCE(SUM(POWER(0.98, (UNIX_TIMESTAMP() - VoteTS) / 86400)), 0.0) " + - "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + - "PackageBases.ID AND NOT VoteTS IS NULL)") + conn.execute("UPDATE PackageBases SET Popularity = (" + + "SELECT COALESCE(SUM(POWER(0.98, (UNIX_TIMESTAMP() - VoteTS) / 86400)), 0.0) " + + "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + + "PackageBases.ID AND NOT VoteTS IS NULL)") - db.commit() - db.close() + conn.commit() + conn.close() if __name__ == '__main__': diff --git a/scripts/tuvotereminder.py b/scripts/tuvotereminder.py index dc16397e..a053608d 100755 --- a/scripts/tuvotereminder.py +++ b/scripts/tuvotereminder.py @@ -1,34 +1,24 @@ #!/usr/bin/python3 -import configparser -import mysql.connector -import os import subprocess import time -config = configparser.RawConfigParser() -config.read(os.path.dirname(os.path.realpath(__file__)) + "/../conf/config") +import aurweb.config +import aurweb.db -aur_db_host = config.get('database', 'host') -aur_db_name = config.get('database', 'name') -aur_db_user = config.get('database', 'user') -aur_db_pass = config.get('database', 'password') -aur_db_socket = config.get('database', 'socket') -notify_cmd = config.get('notifications', 'notify-cmd') +notify_cmd = aurweb.config.get('notifications', 'notify-cmd') def main(): - db = mysql.connector.connect(host=aur_db_host, user=aur_db_user, - passwd=aur_db_pass, db=aur_db_name, - unix_socket=aur_db_socket, buffered=True) - cur = db.cursor() + conn = aurweb.db.Connection() now = int(time.time()) filter_from = now + 500 filter_to = now + 172800 - cur.execute("SELECT ID FROM TU_VoteInfo WHERE End >= %s AND End <= %s", - [filter_from, filter_to]) + cur = conn.execute("SELECT ID FROM TU_VoteInfo " + + "WHERE End >= ? AND End <= ?", + [filter_from, filter_to]) for vote_id in [row[0] for row in cur.fetchall()]: subprocess.Popen((notify_cmd, 'tu-vote-reminder', str(vote_id))) From 1a999810e3a6da21181c91f6b383f69db399cf1c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 20:52:34 +0200 Subject: [PATCH 0245/1891] Make test suite paths top-level directory relative Determine the top-level directory before running tests and make all script paths relative to that directory. Signed-off-by: Lukas Fleischer --- git-interface/test/setup.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/git-interface/test/setup.sh b/git-interface/test/setup.sh index d269af66..0995f053 100644 --- a/git-interface/test/setup.sh +++ b/git-interface/test/setup.sh @@ -1,15 +1,16 @@ TEST_DIRECTORY="$(pwd)" +TOPLEVEL="$(cd ../.. && pwd)" . ./sharness.sh # Configure python search path. -PYTHONPATH="$TEST_DIRECTORY/../../" +PYTHONPATH="$TOPLEVEL" export PYTHONPATH # Configure paths to the Git interface scripts. -GIT_AUTH="$TEST_DIRECTORY/../git-auth.py" -GIT_SERVE="$TEST_DIRECTORY/../git-serve.py" -GIT_UPDATE="$TEST_DIRECTORY/../git-update.py" +GIT_AUTH="$TOPLEVEL/git-interface/git-auth.py" +GIT_SERVE="$TOPLEVEL/git-interface/git-serve.py" +GIT_UPDATE="$TOPLEVEL/git-interface/git-update.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF @@ -86,7 +87,7 @@ sed \ -e 's/ ENGINE = InnoDB//' \ -e 's/ [A-Z]* UNSIGNED NOT NULL AUTO_INCREMENT/ INTEGER NOT NULL/' \ -e 's/([0-9, ]*) UNSIGNED / UNSIGNED /' \ - "$TEST_DIRECTORY/../../schema/aur-schema.sql" | sqlite3 aur.db + "$TOPLEVEL/schema/aur-schema.sql" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 2);" | sqlite3 aur.db From 49c7e53572be8be7848ff99aa5e60ffd4dc316eb Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 20:53:44 +0200 Subject: [PATCH 0246/1891] Reorganize tests Move and rename the existing git-interface tests such that tests for other scripts can be added easily. In particular, the following changes are made: * Move the existing tests from git-interface/test/ to test/. * Rename t0001-auth.sh to t1100-git-auth.sh. * Rename t0002-serve.sh to t1200-git-serve.sh. * Rename t0003-update.sh to t1300-git-update.sh. Signed-off-by: Lukas Fleischer --- {git-interface/test => test}/Makefile | 0 {git-interface/test => test}/setup.sh | 2 +- {git-interface/test => test}/sharness.sh | 0 git-interface/test/t0001-auth.sh => test/t1100-git-auth.sh | 0 git-interface/test/t0002-serve.sh => test/t1200-git-serve.sh | 0 git-interface/test/t0003-update.sh => test/t1300-git-update.sh | 0 6 files changed, 1 insertion(+), 1 deletion(-) rename {git-interface/test => test}/Makefile (100%) rename {git-interface/test => test}/setup.sh (99%) rename {git-interface/test => test}/sharness.sh (100%) rename git-interface/test/t0001-auth.sh => test/t1100-git-auth.sh (100%) rename git-interface/test/t0002-serve.sh => test/t1200-git-serve.sh (100%) rename git-interface/test/t0003-update.sh => test/t1300-git-update.sh (100%) diff --git a/git-interface/test/Makefile b/test/Makefile similarity index 100% rename from git-interface/test/Makefile rename to test/Makefile diff --git a/git-interface/test/setup.sh b/test/setup.sh similarity index 99% rename from git-interface/test/setup.sh rename to test/setup.sh index 0995f053..232b14dc 100644 --- a/git-interface/test/setup.sh +++ b/test/setup.sh @@ -1,5 +1,5 @@ TEST_DIRECTORY="$(pwd)" -TOPLEVEL="$(cd ../.. && pwd)" +TOPLEVEL="$(cd .. && pwd)" . ./sharness.sh diff --git a/git-interface/test/sharness.sh b/test/sharness.sh similarity index 100% rename from git-interface/test/sharness.sh rename to test/sharness.sh diff --git a/git-interface/test/t0001-auth.sh b/test/t1100-git-auth.sh similarity index 100% rename from git-interface/test/t0001-auth.sh rename to test/t1100-git-auth.sh diff --git a/git-interface/test/t0002-serve.sh b/test/t1200-git-serve.sh similarity index 100% rename from git-interface/test/t0002-serve.sh rename to test/t1200-git-serve.sh diff --git a/git-interface/test/t0003-update.sh b/test/t1300-git-update.sh similarity index 100% rename from git-interface/test/t0003-update.sh rename to test/t1300-git-update.sh From dd59eea368ec1683b492cf59b20c36477fa59c1a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Sep 2016 21:02:43 +0200 Subject: [PATCH 0247/1891] Update README Add information on the new directory layout. Shared Python modules and tests now have their own subdirectories. Signed-off-by: Lukas Fleischer --- README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README b/README index 5ab84ab4..c110ef8d 100644 --- a/README +++ b/README @@ -17,6 +17,9 @@ The aurweb project includes Directory Layout ---------------- +aurweb:: + Shared aurweb Python modules. + conf:: Configuration and configuration templates. @@ -35,6 +38,9 @@ schema:: scripts:: Scripts for AUR maintenance. +test:: + Test suite and test cases. + upgrading:: Instructions for upgrading setups from one release to another. From ec5779c824f54f9bdc1303fb22e61b4d558ece39 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Sep 2016 08:11:59 +0200 Subject: [PATCH 0248/1891] mkpkglists: Make output files configurable Instead of writing the output to hardcoded files (relative to the document root), make the output paths of mkpkglists configurable. Signed-off-by: Lukas Fleischer --- conf/config.proto | 4 ++++ scripts/mkpkglists.py | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index c56141c2..e545977e 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -63,3 +63,7 @@ max-blob-size = 256000 db-path = /srv/http/aurweb/aurblup/ sync-dbs = core extra community multilib testing community-testing servers = ftp://mirrors.kernel.org/archlinux/%s/os/x86_64 + +[mkpkglists] +packagesfile = /srv/http/aurweb/web/html/packages.gz +pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz diff --git a/scripts/mkpkglists.py b/scripts/mkpkglists.py index 70cbd139..8a0f2e9d 100755 --- a/scripts/mkpkglists.py +++ b/scripts/mkpkglists.py @@ -2,11 +2,12 @@ import datetime import gzip -import os +import aurweb.config import aurweb.db -docroot = os.path.dirname(os.path.realpath(__file__)) + "/../web/html/" +packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') +pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') def main(): @@ -16,7 +17,7 @@ def main(): pkglist_header = "# AUR package list, generated on " + datestr pkgbaselist_header = "# AUR package base list, generated on " + datestr - with gzip.open(docroot + "packages.gz", "w") as f: + with gzip.open(packagesfile, "w") as f: f.write(bytes(pkglist_header + "\n", "UTF-8")) cur = conn.execute("SELECT Packages.Name FROM Packages " + "INNER JOIN PackageBases " + @@ -24,7 +25,7 @@ def main(): "WHERE PackageBases.PackagerUID IS NOT NULL") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - with gzip.open(docroot + "pkgbase.gz", "w") as f: + with gzip.open(pkgbasefile, "w") as f: f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) cur = conn.execute("SELECT Name FROM PackageBases " + "WHERE PackagerUID IS NOT NULL") From a48f8ccb131b059e6878efc647a8ebd5f887d7a7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Sep 2016 08:36:50 +0200 Subject: [PATCH 0249/1891] Add tests for mkpkglists Signed-off-by: Lukas Fleischer --- test/setup.sh | 5 +++++ test/t2100-mkpkglists.sh | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100755 test/t2100-mkpkglists.sh diff --git a/test/setup.sh b/test/setup.sh index 232b14dc..85faba03 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -11,6 +11,7 @@ export PYTHONPATH GIT_AUTH="$TOPLEVEL/git-interface/git-auth.py" GIT_SERVE="$TOPLEVEL/git-interface/git-serve.py" GIT_UPDATE="$TOPLEVEL/git-interface/git-update.py" +MKPKGLISTS="$TOPLEVEL/scripts/mkpkglists.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF @@ -40,6 +41,10 @@ ssh-cmdline = ssh aur@aur.archlinux.org [update] max-blob-size = 256000 + +[mkpkglists] +packagesfile = packages.gz +pkgbasefile = pkgbase.gz EOF cat >notify.sh <<-EOF diff --git a/test/t2100-mkpkglists.sh b/test/t2100-mkpkglists.sh new file mode 100755 index 00000000..a84a1b65 --- /dev/null +++ b/test/t2100-mkpkglists.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +test_description='mkpkglists tests' + +. ./setup.sh + +test_expect_success 'Test package list generation with no packages.' ' + echo "DELETE FROM Packages;" | sqlite3 aur.db && + echo "DELETE FROM PackageBases;" | sqlite3 aur.db && + "$MKPKGLISTS" && + test $(zcat packages.gz | wc -l) -eq 1 && + test $(zcat pkgbase.gz | wc -l) -eq 1 +' + +test_expect_success 'Test package list generation.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (1, "foobar", 1, 0, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (2, "foobar2", 2, 0, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (3, "foobar3", NULL, 0, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (4, "foobar4", 1, 0, 0); + INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (1, 1, "pkg1"); + INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (2, 1, "pkg2"); + INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (3, 1, "pkg3"); + INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (4, 2, "pkg4"); + INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (5, 3, "pkg5"); + EOD + "$MKPKGLISTS" && + cat <<-EOD >expected && + foobar + foobar2 + foobar4 + EOD + gunzip pkgbase.gz && + sed "/^#/d" pkgbase >actual && + test_cmp actual expected && + cat <<-EOD >expected && + pkg1 + pkg2 + pkg3 + pkg4 + EOD + gunzip packages.gz && + sed "/^#/d" packages >actual && + test_cmp actual expected +' + +test_done From cd2d90612b63711f9d92bff686698b6c37b79b2b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Sep 2016 08:49:18 +0200 Subject: [PATCH 0250/1891] Add tests for tuvotereminder Signed-off-by: Lukas Fleischer --- test/setup.sh | 4 +++- test/t2200-tuvotereminder.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100755 test/t2200-tuvotereminder.sh diff --git a/test/setup.sh b/test/setup.sh index 85faba03..e6a9a16f 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -12,6 +12,7 @@ GIT_AUTH="$TOPLEVEL/git-interface/git-auth.py" GIT_SERVE="$TOPLEVEL/git-interface/git-serve.py" GIT_UPDATE="$TOPLEVEL/git-interface/git-update.py" MKPKGLISTS="$TOPLEVEL/scripts/mkpkglists.py" +TUVOTEREMINDER="$TOPLEVEL/scripts/tuvotereminder.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF @@ -47,8 +48,9 @@ packagesfile = packages.gz pkgbasefile = pkgbase.gz EOF -cat >notify.sh <<-EOF +cat >notify.sh <<-\EOF #!/bin/sh +echo $* >>notify.out EOF chmod +x notify.sh diff --git a/test/t2200-tuvotereminder.sh b/test/t2200-tuvotereminder.sh new file mode 100755 index 00000000..438c0c34 --- /dev/null +++ b/test/t2200-tuvotereminder.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_description='tuvotereminder tests' + +. ./setup.sh + +test_expect_success 'Test Trusted User vote reminders.' ' + now=$(date -d now +%s) && + tomorrow=$(date -d tomorrow +%s) && + threedays=$(date -d "3 days" +%s) && + cat <<-EOD | sqlite3 aur.db && + INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (1, "Lorem ipsum.", "user", 0, $now, 0.00, 2); + INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (2, "Lorem ipsum.", "user", 0, $tomorrow, 0.00, 2); + INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (3, "Lorem ipsum.", "user", 0, $tomorrow, 0.00, 2); + INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (4, "Lorem ipsum.", "user", 0, $threedays, 0.00, 2); + EOD + >notify.out && + "$TUVOTEREMINDER" && + cat <<-EOD >expected && + tu-vote-reminder 2 + tu-vote-reminder 3 + EOD + test_cmp notify.out expected +' + +test_done From 91f649f5edaae42f616ad9fc2facb90f1d71f9b9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Sep 2016 09:05:56 +0200 Subject: [PATCH 0251/1891] scripts: Do not use UNIX_TIMESTAMP Avoid using UNIX_TIMESTAMP which is not part of the SQL standard. See f2a6bd2 (git-interface: Do not use UNIX_TIMESTAMP, 2016-08-05) for related changes. Signed-off-by: Lukas Fleischer --- scripts/pkgmaint.py | 6 ++++-- scripts/popupdate.py | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/pkgmaint.py b/scripts/pkgmaint.py index d0f8fe70..3ad9ed8d 100755 --- a/scripts/pkgmaint.py +++ b/scripts/pkgmaint.py @@ -1,14 +1,16 @@ #!/usr/bin/python3 +import time + import aurweb.db def main(): conn = aurweb.db.Connection() + limit_to = int(time.time()) - 86400 conn.execute("DELETE FROM PackageBases WHERE " + - "UNIX_TIMESTAMP() - SubmittedTS > 86400 " + - "AND PackagerUID IS NULL") + "SubmittedTS < ? AND PackagerUID IS NULL", [limit_to]) conn.commit() conn.close() diff --git a/scripts/popupdate.py b/scripts/popupdate.py index f5e09d97..58cd0185 100755 --- a/scripts/popupdate.py +++ b/scripts/popupdate.py @@ -1,5 +1,7 @@ #!/usr/bin/python3 +import time + import aurweb.db @@ -10,10 +12,11 @@ def main(): "SELECT COUNT(*) FROM PackageVotes " + "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") + now = int(time.time()) conn.execute("UPDATE PackageBases SET Popularity = (" + - "SELECT COALESCE(SUM(POWER(0.98, (UNIX_TIMESTAMP() - VoteTS) / 86400)), 0.0) " + + "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " + "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + - "PackageBases.ID AND NOT VoteTS IS NULL)") + "PackageBases.ID AND NOT VoteTS IS NULL)", [now]) conn.commit() conn.close() From d00f4c5197652563a61628461a39fd799264c9c4 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Sep 2016 09:13:49 +0200 Subject: [PATCH 0252/1891] Add tests for pkgmaint Signed-off-by: Lukas Fleischer --- test/setup.sh | 1 + test/t2300-pkgmaint.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100755 test/t2300-pkgmaint.sh diff --git a/test/setup.sh b/test/setup.sh index e6a9a16f..622aab03 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -13,6 +13,7 @@ GIT_SERVE="$TOPLEVEL/git-interface/git-serve.py" GIT_UPDATE="$TOPLEVEL/git-interface/git-update.py" MKPKGLISTS="$TOPLEVEL/scripts/mkpkglists.py" TUVOTEREMINDER="$TOPLEVEL/scripts/tuvotereminder.py" +PKGMAINT="$TOPLEVEL/scripts/pkgmaint.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF diff --git a/test/t2300-pkgmaint.sh b/test/t2300-pkgmaint.sh new file mode 100755 index 00000000..5c55aaf1 --- /dev/null +++ b/test/t2300-pkgmaint.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_description='pkgmaint tests' + +. ./setup.sh + +test_expect_success 'Test package base cleanup script.' ' + now=$(date -d now +%s) && + threedaysago=$(date -d "3 days ago" +%s) && + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (1, "foobar", 1, $now, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (2, "foobar2", 2, $threedaysago, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (3, "foobar3", NULL, $now, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (4, "foobar4", NULL, $threedaysago, 0); + EOD + "$PKGMAINT" && + cat <<-EOD >expected && + foobar + foobar2 + foobar3 + EOD + echo "SELECT Name FROM PackageBases;" | sqlite3 aur.db >actual && + test_cmp actual expected +' + +test_done From cc66259d339ec805265503662bf5da61f63512cc Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Sep 2016 21:50:17 +0200 Subject: [PATCH 0253/1891] aurblup: Drop support for multiple servers Support for multiple servers has never been used by the official aurweb setup and the current implementation makes it impossible to use server URIs that contain spaces. For simplicity, change the implementation such that only a single server is supported. Signed-off-by: Lukas Fleischer --- conf/config.proto | 2 +- scripts/aurblup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index e545977e..21441a9f 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -62,7 +62,7 @@ max-blob-size = 256000 [aurblup] db-path = /srv/http/aurweb/aurblup/ sync-dbs = core extra community multilib testing community-testing -servers = ftp://mirrors.kernel.org/archlinux/%s/os/x86_64 +server = ftp://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] packagesfile = /srv/http/aurweb/web/html/packages.gz diff --git a/scripts/aurblup.py b/scripts/aurblup.py index 0009715f..1b6de2f0 100755 --- a/scripts/aurblup.py +++ b/scripts/aurblup.py @@ -8,7 +8,7 @@ import aurweb.db db_path = aurweb.config.get('aurblup', 'db-path') sync_dbs = aurweb.config.get('aurblup', 'sync-dbs').split(' ') -servers = aurweb.config.get('aurblup', 'servers').split(' ') +server = aurweb.config.get('aurblup', 'server') def main(): @@ -19,7 +19,7 @@ def main(): h = pyalpm.Handle("/", db_path) for sync_db in sync_dbs: repo = h.register_syncdb(sync_db, pyalpm.SIG_DATABASE_OPTIONAL) - repo.servers = [server.replace("%s", sync_db) for server in servers] + repo.servers = [server.replace("%s", sync_db)] t = h.init_transaction() repo.update(False) t.release() From c8c37477864638ca37088433f0061e5b62f6986f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 21 Sep 2016 21:50:28 +0200 Subject: [PATCH 0254/1891] Add tests for aurblup Signed-off-by: Lukas Fleischer --- test/setup.sh | 6 +++++ test/t2400-aurblup.sh | 53 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100755 test/t2400-aurblup.sh diff --git a/test/setup.sh b/test/setup.sh index 622aab03..e379adad 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -14,6 +14,7 @@ GIT_UPDATE="$TOPLEVEL/git-interface/git-update.py" MKPKGLISTS="$TOPLEVEL/scripts/mkpkglists.py" TUVOTEREMINDER="$TOPLEVEL/scripts/tuvotereminder.py" PKGMAINT="$TOPLEVEL/scripts/pkgmaint.py" +AURBLUP="$TOPLEVEL/scripts/aurblup.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF @@ -44,6 +45,11 @@ ssh-cmdline = ssh aur@aur.archlinux.org [update] max-blob-size = 256000 +[aurblup] +db-path = $(pwd)/sync/ +sync-dbs = test +server = file://$(pwd)/remote/ + [mkpkglists] packagesfile = packages.gz pkgbasefile = pkgbase.gz diff --git a/test/t2400-aurblup.sh b/test/t2400-aurblup.sh new file mode 100755 index 00000000..708281c6 --- /dev/null +++ b/test/t2400-aurblup.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +test_description='aurblup tests' + +. ./setup.sh + +test_expect_success 'Test official provider update script.' ' + mkdir -p remote/test/foobar-1.0-1 && + cat <<-EOD >remote/test/foobar-1.0-1/desc && + %FILENAME% + foobar-1.0-any.pkg.tar.xz + + %NAME% + foobar + + %VERSION% + 1.0-1 + + %ARCH% + any + EOD + mkdir -p remote/test/foobar2-1.0-1 && + cat <<-EOD >remote/test/foobar2-1.0-1/desc && + %FILENAME% + foobar2-1.0-any.pkg.tar.xz + + %NAME% + foobar2 + + %VERSION% + 1.0-1 + + %ARCH% + any + + %PROVIDES% + foobar3 + foobar4 + EOD + ( cd remote/test && bsdtar -czf ../test.db * ) && + mkdir sync && + "$AURBLUP" && + cat <<-EOD >expected && + foobar|test|foobar + foobar2|test|foobar2 + foobar2|test|foobar3 + foobar2|test|foobar4 + EOD + echo "SELECT Name, Repo, Provides FROM OfficialProviders ORDER BY Provides;" | sqlite3 aur.db >actual && + test_cmp actual expected +' + +test_done From e1709e98ce623aee8062e98a859bcb43553e2faf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 29 Sep 2016 21:03:54 +0200 Subject: [PATCH 0255/1891] tuvotereminder: Wait for notify processes Signed-off-by: Lukas Fleischer --- scripts/tuvotereminder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tuvotereminder.py b/scripts/tuvotereminder.py index a053608d..97b1d12e 100755 --- a/scripts/tuvotereminder.py +++ b/scripts/tuvotereminder.py @@ -21,7 +21,7 @@ def main(): [filter_from, filter_to]) for vote_id in [row[0] for row in cur.fetchall()]: - subprocess.Popen((notify_cmd, 'tu-vote-reminder', str(vote_id))) + subprocess.Popen((notify_cmd, 'tu-vote-reminder', str(vote_id))).wait() if __name__ == '__main__': From eb367d97e28d157036c1bf4f1ee65b0d17d756ea Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 29 Sep 2016 20:45:58 +0200 Subject: [PATCH 0256/1891] Use the notify script in tests Instead of only checking whether the notification script is called with the correct parameters, actually invoke the real notify script and check whether proper notifications are generated. Signed-off-by: Lukas Fleischer --- test/setup.sh | 14 ++++++++++---- test/t2200-tuvotereminder.sh | 11 +++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/test/setup.sh b/test/setup.sh index e379adad..cd424791 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -15,6 +15,7 @@ MKPKGLISTS="$TOPLEVEL/scripts/mkpkglists.py" TUVOTEREMINDER="$TOPLEVEL/scripts/tuvotereminder.py" PKGMAINT="$TOPLEVEL/scripts/pkgmaint.py" AURBLUP="$TOPLEVEL/scripts/aurblup.py" +NOTIFY="$TOPLEVEL/scripts/notify.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF @@ -23,11 +24,16 @@ backend = sqlite name = aur.db [options] +aur_location = https://aur.archlinux.org +aur_request_ml = aur-requests@archlinux.org enable-maintenance = 0 maintenance-exceptions = 127.0.0.1 [notifications] -notify-cmd = ./notify.sh +notify-cmd = $NOTIFY +sendmail = ./sendmail.sh +sender = notify@aur.archlinux.org +reply-to = noreply@aur.archlinux.org [auth] valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 @@ -55,11 +61,11 @@ packagesfile = packages.gz pkgbasefile = pkgbase.gz EOF -cat >notify.sh <<-\EOF +cat >sendmail.sh <<-\EOF #!/bin/sh -echo $* >>notify.out +cat >>sendmail.out EOF -chmod +x notify.sh +chmod +x sendmail.sh cat >git-shell.sh <<-\EOF #!/bin/sh diff --git a/test/t2200-tuvotereminder.sh b/test/t2200-tuvotereminder.sh index 438c0c34..8477c92b 100755 --- a/test/t2200-tuvotereminder.sh +++ b/test/t2200-tuvotereminder.sh @@ -14,13 +14,12 @@ test_expect_success 'Test Trusted User vote reminders.' ' INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (3, "Lorem ipsum.", "user", 0, $tomorrow, 0.00, 2); INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (4, "Lorem ipsum.", "user", 0, $threedays, 0.00, 2); EOD - >notify.out && + >sendmail.out && "$TUVOTEREMINDER" && - cat <<-EOD >expected && - tu-vote-reminder 2 - tu-vote-reminder 3 - EOD - test_cmp notify.out expected + grep -q "Proposal 2" sendmail.out && + grep -q "Proposal 3" sendmail.out && + test_must_fail grep -q "Proposal 1" sendmail.out && + test_must_fail grep -q "Proposal 4" sendmail.out ' test_done From bc3a4f348d8d73821a80a8033c48e7e1eb020e5c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 29 Sep 2016 22:04:54 +0200 Subject: [PATCH 0257/1891] t2200: Check that only non-voters get reminders Add a test to make sure that Trusted Users, who already voted on a proposal, do not receive any reminders. Signed-off-by: Lukas Fleischer --- test/setup.sh | 3 +++ test/t2200-tuvotereminder.sh | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/test/setup.sh b/test/setup.sh index cd424791..dc9cff28 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -115,6 +115,9 @@ echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (3, echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (4, 'user2', '!', 'user2@localhost', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (5, 'user3', '!', 'user3@localhost', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (6, 'user4', '!', 'user4@localhost', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (7, 'tu2', '!', 'tu2@localhost', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (8, 'tu3', '!', 'tu3@localhost', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (9, 'tu4', '!', 'tu4@localhost', 2);" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (1, '$AUTH_FINGERPRINT_USER', '$AUTH_KEYTYPE_USER $AUTH_KEYTEXT_USER');" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FINGERPRINT_TU', '$AUTH_KEYTYPE_TU $AUTH_KEYTEXT_TU');" | sqlite3 aur.db diff --git a/test/t2200-tuvotereminder.sh b/test/t2200-tuvotereminder.sh index 8477c92b..c82ce874 100755 --- a/test/t2200-tuvotereminder.sh +++ b/test/t2200-tuvotereminder.sh @@ -22,4 +22,32 @@ test_expect_success 'Test Trusted User vote reminders.' ' test_must_fail grep -q "Proposal 4" sendmail.out ' +test_expect_success 'Check that only TUs who did not vote receive reminders.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO TU_Votes (VoteID, UserID) VALUES (1, 2); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (2, 2); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (3, 2); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (4, 2); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (1, 7); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (3, 7); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (2, 8); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (4, 8); + INSERT INTO TU_Votes (VoteID, UserID) VALUES (1, 9); + EOD + >sendmail.out && + "$TUVOTEREMINDER" && + cat <<-EOD >expected && + Subject: TU Vote Reminder: Proposal 2 + To: tu2@localhost + Subject: TU Vote Reminder: Proposal 2 + To: tu4@localhost + Subject: TU Vote Reminder: Proposal 3 + To: tu3@localhost + Subject: TU Vote Reminder: Proposal 3 + To: tu4@localhost + EOD + grep "^\(Subject\|To\)" sendmail.out >sendmail.parts && + test_cmp sendmail.parts expected +' + test_done From 5766a37e4ad2e41377f5eeae1240ceab4cf6e63f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 30 Sep 2016 17:48:49 +0200 Subject: [PATCH 0258/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index e773913a..22f27051 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.2.1\n" +"Project-Id-Version: AUR v4.3.0\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" +"POT-Creation-Date: 2016-09-30 17:48+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1103,6 +1103,10 @@ msgstr "" msgid "Active" msgstr "" +#: template/account_details.php +msgid "Registration date:" +msgstr "" + #: template/account_details.php msgid "Last Login" msgstr "" @@ -1124,6 +1128,11 @@ msgstr "" msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "" From df6bb72807408bc0eab59e729ea8c0b69fe39388 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 1 Oct 2016 21:48:14 +0200 Subject: [PATCH 0259/1891] git-serve: Support `git {receive,upload}-pack` Add support for the `git receive-pack` and `git upload-pack` commands which are aliases for git-receive-pack and git-upload-pack, respectively. Signed-off-by: Lukas Fleischer --- git-interface/git-serve.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-interface/git-serve.py b/git-interface/git-serve.py index 5f3b26dd..ebfef946 100755 --- a/git-interface/git-serve.py +++ b/git-interface/git-serve.py @@ -305,6 +305,10 @@ def main(): if remote_addr not in maintenance_exc: die("The AUR is down due to maintenance. We will be back soon.") + if action == 'git' and cmdargv[1] in ('upload-pack', 'receive-pack'): + action = action + '-' + cmdargv[1] + del cmdargv[1] + if action == 'git-upload-pack' or action == 'git-receive-pack': if len(cmdargv) < 2: die_with_help("{:s}: missing path".format(action)) From e182ba0c42a9d2b2afecb8da32d00f634999935e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 7 Oct 2016 21:52:07 +0200 Subject: [PATCH 0260/1891] Add clone hints to 404 error pages When clicking on the linked Git clone URL of a package base, users are faced with a 404 error page since the URL is not supposed to be opened in a web browser. Add some notes to 404 error pages corresponding to Git clone URLs that explain how to use them instead. Fixes FS#51266. Signed-off-by: Lukas Fleischer --- web/html/404.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/web/html/404.php b/web/html/404.php index a47ae1e4..757c4855 100644 --- a/web/html/404.php +++ b/web/html/404.php @@ -2,12 +2,45 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); +$path = $_SERVER['PATH_INFO']; +$tokens = explode('/', $path); + +if (preg_match('/^([a-z0-9][a-z0-9.+_-]*?)(\.git)?$/', $tokens[1], $matches)) { + $gitpkg = $matches[1]; + if (pkg_from_name($gitpkg)) { + $gitcmd = 'git clone ' . sprintf(config_get('options', 'git_clone_uri_anon'), htmlspecialchars($gitpkg)); + $gitlink = get_pkgbase_uri($gitpkg); + } else { + unset($gitpkg); + } +} else { + unset($gitpkg); +} + html_header( __("Page Not Found") ); ?>

    404 -

    + +
      +
    • + : + +
    • +
    • + ' . htmlspecialchars($gitpkg) . '', + '' . htmlspecialchars($gitcmd) . '') ?> +
    • +
    • + ', '', + '' . htmlspecialchars($gitpkg) . '') ?> +
    • +
    +
    Date: Sat, 8 Oct 2016 14:19:11 +0200 Subject: [PATCH 0261/1891] Reorganize Git interface scripts Move the Git interface scripts from git-interface/ to aurweb/git/. Use setuptools to automatically create wrappers which can be installed using `python3 setup.py install`. Update the configuration files, the test suite as well as the INSTALL and README files to reflect these changes. Signed-off-by: Lukas Fleischer --- INSTALL | 28 ++++++++----------- README | 5 +--- .../git-auth.py => aurweb/git/auth.py | 0 .../git-serve.py => aurweb/git/serve.py | 0 .../git-update.py => aurweb/git/update.py | 0 conf/config.proto | 4 +-- git-interface/Makefile | 18 ------------ git-interface/__init__.py | 0 git-interface/config.mk | 1 - git-interface/git-auth.sh.in | 3 -- setup.py | 7 +++++ test/setup.sh | 8 +++--- 12 files changed, 26 insertions(+), 48 deletions(-) rename git-interface/git-auth.py => aurweb/git/auth.py (100%) rename git-interface/git-serve.py => aurweb/git/serve.py (100%) rename git-interface/git-update.py => aurweb/git/update.py (100%) delete mode 100644 git-interface/Makefile delete mode 100644 git-interface/__init__.py delete mode 100644 git-interface/config.mk delete mode 100644 git-interface/git-auth.sh.in diff --git a/INSTALL b/INSTALL index dab48cc1..395915ae 100644 --- a/INSTALL +++ b/INSTALL @@ -37,11 +37,16 @@ Setup on Arch Linux $ mysql -uaur -p AUR git-auth.sh - chmod +x git-auth.sh - -install: git-auth.sh - install -Dm0755 git-auth.sh "$(DESTDIR)$(PREFIX)/bin/aur-git-auth" - -uninstall: - rm -f "$(DESTDIR)$(PREFIX)/bin/aur-git-auth" - -clean: - rm -f git-auth.sh - -.PHONY: install uninstall clean diff --git a/git-interface/__init__.py b/git-interface/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/git-interface/config.mk b/git-interface/config.mk deleted file mode 100644 index 4d794a1c..00000000 --- a/git-interface/config.mk +++ /dev/null @@ -1 +0,0 @@ -PREFIX = /usr/local diff --git a/git-interface/git-auth.sh.in b/git-interface/git-auth.sh.in deleted file mode 100644 index 223816ac..00000000 --- a/git-interface/git-auth.sh.in +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -%GIT_INTERFACE_DIR%/git-auth.py "$1" "$2" diff --git a/setup.py b/setup.py index 48eb1769..b64e71cb 100644 --- a/setup.py +++ b/setup.py @@ -17,4 +17,11 @@ setup( name="aurweb", version=version, packages=find_packages(), + entry_points={ + 'console_scripts': [ + 'aurweb-git-auth = aurweb.git.auth:main', + 'aurweb-git-serve = aurweb.git.serve:main', + 'aurweb-git-update = aurweb.git.update:main', + ], + }, ) diff --git a/test/setup.sh b/test/setup.sh index dc9cff28..d02d2981 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -8,9 +8,9 @@ PYTHONPATH="$TOPLEVEL" export PYTHONPATH # Configure paths to the Git interface scripts. -GIT_AUTH="$TOPLEVEL/git-interface/git-auth.py" -GIT_SERVE="$TOPLEVEL/git-interface/git-serve.py" -GIT_UPDATE="$TOPLEVEL/git-interface/git-update.py" +GIT_AUTH="$TOPLEVEL/aurweb/git/auth.py" +GIT_SERVE="$TOPLEVEL/aurweb/git/serve.py" +GIT_UPDATE="$TOPLEVEL/aurweb/git/update.py" MKPKGLISTS="$TOPLEVEL/scripts/mkpkglists.py" TUVOTEREMINDER="$TOPLEVEL/scripts/tuvotereminder.py" PKGMAINT="$TOPLEVEL/scripts/pkgmaint.py" @@ -38,7 +38,7 @@ reply-to = noreply@aur.archlinux.org [auth] valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ -git-serve-cmd = /srv/http/aurweb/git-interface/git-serve.py +git-serve-cmd = $GIT_SERVE ssh-options = restrict [serve] From fdccd272f0b8cb2550eac2db969421143a79b873 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 8 Oct 2016 14:35:26 +0200 Subject: [PATCH 0262/1891] Update .gitignore Remove obsolete files. Add byte-compiled Python files and test results. Signed-off-by: Lukas Fleischer --- .gitignore | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index c41bf3e8..2cb5bdc3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,8 @@ dummy-data.sql* po/*.mo po/*.po~ po/POTFILES -scripts/git-integration/__pycache__/ -scripts/git-integration/templates/ web/locale/*/ aur.git/ -git-interface/git-auth.sh +__pycache__/ +*.py[cod] +test/test-results/ From 0dce4c4bcabec79ae796d38c3c93d424a42f718c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 8 Oct 2016 14:59:33 +0200 Subject: [PATCH 0263/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index 22f27051..bbe34d63 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: AUR v4.3.0\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-09-30 17:48+0200\n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -26,6 +26,24 @@ msgstr "" msgid "Sorry, the page you've requested does not exist." msgstr "" +#: html/404.php template/pkgreq_close_form.php +msgid "Note" +msgstr "" + +#: html/404.php +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#: html/404.php +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#: html/404.php +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + #: html/503.php msgid "Service Unavailable" msgstr "" @@ -1530,10 +1548,6 @@ msgstr "" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -#: template/pkgreq_close_form.php -msgid "Note" -msgstr "" - #: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " From 1492444ecbe68e4498a6f7ae0258c39ebbd47138 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 11 Oct 2016 08:09:21 +0200 Subject: [PATCH 0264/1891] Make URL columns 8000 characters wide According to RFC 7230, URLs can be up too 8000 characters long. Resize all URL fields accordingly. Also, add a test to verify that URLs with more than 8000 characters are rejected by the update hook. Reported-by: Andreas Linz Signed-off-by: Lukas Fleischer --- aurweb/git/update.py | 5 +++-- schema/aur-schema.sql | 4 ++-- test/t1300-git-update.sh | 16 ++++++++++++++++ upgrading/4.4.0.txt | 12 ++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 upgrading/4.4.0.txt diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 73373410..af2dfed8 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -324,8 +324,9 @@ def main(): die_commit('invalid package name: {:s}'.format( pkginfo['pkgname']), str(commit.id)) - for field in ('pkgname', 'pkgdesc', 'url'): - if field in pkginfo and len(pkginfo[field]) > 255: + max_len = {'pkgname': 255, 'pkgdesc': 255, 'url': 8000} + for field in max_len.keys(): + if field in pkginfo and len(pkginfo[field]) > max_len[field]: die_commit('{:s} field too long: {:s}'.format(field, pkginfo[field]), str(commit.id)) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 030370b7..30209bd8 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -119,7 +119,7 @@ CREATE TABLE Packages ( Name VARCHAR(255) NOT NULL, Version VARCHAR(255) NOT NULL DEFAULT '', Description VARCHAR(255) NULL DEFAULT NULL, - URL VARCHAR(255) NULL DEFAULT NULL, + URL VARCHAR(8000) NULL DEFAULT NULL, PRIMARY KEY (ID), UNIQUE (Name), FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE @@ -227,7 +227,7 @@ CREATE INDEX RelationsRelName ON PackageRelations (RelName); -- CREATE TABLE PackageSources ( PackageID INTEGER UNSIGNED NOT NULL, - Source VARCHAR(255) NOT NULL DEFAULT "/dev/null", + Source VARCHAR(8000) NOT NULL DEFAULT "/dev/null", SourceArch VARCHAR(255) NULL DEFAULT NULL, FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE ) ENGINE = InnoDB; diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.sh index b642089c..abab7ead 100755 --- a/test/t1300-git-update.sh +++ b/test/t1300-git-update.sh @@ -309,6 +309,22 @@ test_expect_success 'Pushing .SRCINFO with invalid epoch.' ' grep -q "^error: invalid epoch: !$" actual ' +test_expect_success 'Pushing .SRCINFO with too long URL.' ' + old=$(git -C aur.git rev-parse HEAD) && + url="http://$(printf "%7993s" x | sed "s/ /x/g")/" && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s#.*url.*#\\0\\nurl = $url#" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Change URL" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: url field too long: $url\$" actual +' + test_expect_success 'Missing install file.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && diff --git a/upgrading/4.4.0.txt b/upgrading/4.4.0.txt new file mode 100644 index 00000000..1cc55b32 --- /dev/null +++ b/upgrading/4.4.0.txt @@ -0,0 +1,12 @@ +1. Resize the URL column of the Packages table: + +---- +ALTER TABLE Packages MODIFY URL VARCHAR(8000) NULL DEFAULT NULL; +---- + +2. Resize the Source column of the PackageSources table: + +---- +ALTER TABLE PackageSources + MODIFY Source VARCHAR(8000) NOT NULL DEFAULT "/dev/null"; +---- From 29a5f94dab27cc64da6262b2f37bd856641ed292 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 11 Oct 2016 08:22:03 +0200 Subject: [PATCH 0265/1891] git-update: Catch long source URLs Bail out early if the source array contains an entry with more than 8000 characters. Signed-off-by: Lukas Fleischer --- aurweb/git/update.py | 3 +++ test/t1300-git-update.sh | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index af2dfed8..3b84eb5d 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -337,6 +337,9 @@ def main(): for field in extract_arch_fields(pkginfo, 'source'): fname = field['value'] + if len(fname) > 8000: + die_commit('source entry too long: {:s}'.format(fname), + str(commit.id)) if "://" in fname or "lp:" in fname: continue if fname not in commit.tree: diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.sh index abab7ead..a65ca3a1 100755 --- a/test/t1300-git-update.sh +++ b/test/t1300-git-update.sh @@ -370,6 +370,22 @@ test_expect_success 'Missing source file.' ' grep -q "^error: missing source file: file$" actual ' +test_expect_success 'Pushing .SRCINFO with too long source URL.' ' + old=$(git -C aur.git rev-parse HEAD) && + url="http://$(printf "%7993s" x | sed "s/ /x/g")/" && + test_when_finished "git -C aur.git reset --hard $old" && + ( + cd aur.git && + sed "s#.*depends.*#\\0\\nsource = $url#" .SRCINFO >.SRCINFO.new + mv .SRCINFO.new .SRCINFO + git commit -q -am "Add huge source URL" + ) && + new=$(git -C aur.git rev-parse HEAD) && + AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: source entry too long: $url\$" actual +' + test_expect_success 'Pushing a blacklisted package.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && From 51101d21b972b6afcef299795430cb5aea81e373 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 11 Oct 2016 08:40:28 +0200 Subject: [PATCH 0266/1891] upgrading/4.4.0.txt: Warn about new scripts The location of the Git interface wrapper scripts was changed by commit d4fe77a (Reorganize Git interface scripts, 2016-10-08). Add a note to the upgrade instructions to remind users to update their configuration files. Signed-off-by: Lukas Fleischer --- upgrading/4.4.0.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/upgrading/4.4.0.txt b/upgrading/4.4.0.txt index 1cc55b32..afe01bea 100644 --- a/upgrading/4.4.0.txt +++ b/upgrading/4.4.0.txt @@ -10,3 +10,8 @@ ALTER TABLE Packages MODIFY URL VARCHAR(8000) NULL DEFAULT NULL; ALTER TABLE PackageSources MODIFY Source VARCHAR(8000) NOT NULL DEFAULT "/dev/null"; ---- + +3. The location of the Git interface scripts was changed. Make sure you update + your aurweb configuration, as well as the SSH daemon and AUR Git repository + configurations to point to the new wrapper scripts which are located in + /usr/local/bin/ by default. From fc6dc44295bed8c5d9c8014c2eab2d6bf33d2541 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 11 Oct 2016 07:44:21 +0200 Subject: [PATCH 0267/1891] git-serve: Close orphan requests upon disown When disowning a package base via the SSH interface, auto-accept all pending orphan requests for the affected package. Also, add a test case that checks whether (only) orphan requests belonging to disowned packages are closed correctly. Signed-off-by: Lukas Fleischer --- aurweb/git/serve.py | 44 ++++++++++++++++++++++++++++++++++++++++- test/t1200-git-serve.sh | 23 +++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index ebfef946..476aea86 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -183,6 +183,44 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged): conn.close() +def pkgreq_by_pkgbase(pkgbase_id, reqtype): + conn = aurweb.db.Connection() + + cur = conn.execute("SELECT PackageRequests.ID FROM PackageRequests " + + "INNER JOIN RequestTypes ON " + + "RequestTypes.ID = PackageRequests.ReqTypeID " + + "WHERE PackageRequests.Status = 0 " + + "AND PackageRequests.PackageBaseID = ?" + + "AND RequestTypes.Name = ?", [pkgbase_id, reqtype]) + + return [row[0] for row in cur.fetchall()] + + +def pkgreq_close(reqid, reason, comments, autoclose=False): + statusmap = {'accepted': 2, 'rejected': 3} + if reason not in statusmap: + die('{:s}: invalid reason: {:s}'.format(action, reason)) + status = statusmap[reason] + + conn = aurweb.db.Connection() + + if autoclose: + userid = 0 + else: + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + if userid == 0: + die('{:s}: unknown user: {:s}'.format(action, user)) + + conn.execute("UPDATE PackageRequests SET Status = ?, ClosureComment = ? " + + "WHERE ID = ?", [status, comments, reqid]) + conn.commit() + conn.close() + + subprocess.Popen((notify_cmd, 'request-close', str(userid), str(reqid), + reason)).wait() + + def pkgbase_disown(pkgbase, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: @@ -193,7 +231,11 @@ def pkgbase_disown(pkgbase, user, privileged): die('{:s}: permission denied: {:s}'.format(action, user)) # TODO: Support disowning package bases via package request. - # TODO: Scan through pending orphan requests and close them. + + # Scan through pending orphan requests and close them. + comment = 'The user {:s} disowned the package.'.format(user) + for reqid in pkgreq_by_pkgbase(pkgbase_id, 'orphan'): + pkgreq_close(reqid, 'accepted', comment, True) comaintainers = [] new_maintainer_userid = None diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index 2f1926e2..5054ce36 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -317,4 +317,27 @@ test_expect_success "Force-disown a package base and check (co-)maintainer list. test_cmp expected actual ' +test_expect_success "Check whether package requests are closed when disowning." ' + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID) VALUES (1, 2, 3, "foobar", 4); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID) VALUES (2, 3, 3, "foobar", 5); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID) VALUES (3, 2, 2, "foobar2", 6); + EOD + >sendmail.out && + SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat <<-EOD >expected && + Subject: [PRQ#1] Request Accepted + EOD + grep "^Subject.*PRQ" sendmail.out >sendmail.parts && + test_cmp sendmail.parts expected && + cat <<-EOD >expected && + 1|2|3|foobar||4||The user user disowned the package.|0|2 + EOD + echo "SELECT * FROM PackageRequests WHERE Status = 2;" | sqlite3 aur.db >actual && + test_cmp actual expected +' + test_done From 3f5bf622856525ae625d3a5133dc95e81987f30e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 15 Oct 2016 19:45:48 +0200 Subject: [PATCH 0268/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 30 ++++++++++--- po/ast.po | 30 ++++++++++--- po/ca.po | 30 ++++++++++--- po/cs.po | 30 ++++++++++--- po/da.po | 30 ++++++++++--- po/de.po | 30 ++++++++++--- po/el.po | 30 ++++++++++--- po/es.po | 44 +++++++++++++----- po/es_419.po | 58 ++++++++++++++++-------- po/fi.po | 30 ++++++++++--- po/fr.po | 31 ++++++++++--- po/he.po | 30 ++++++++++--- po/hr.po | 30 ++++++++++--- po/hu.po | 30 ++++++++++--- po/it.po | 30 ++++++++++--- po/ja.po | 30 ++++++++++--- po/nb.po | 30 ++++++++++--- po/nl.po | 30 ++++++++++--- po/pl.po | 60 +++++++++++++++++++------ po/pt_BR.po | 28 +++++++++--- po/pt_PT.po | 30 ++++++++++--- po/ro.po | 30 ++++++++++--- po/ru.po | 30 ++++++++++--- po/sk.po | 30 ++++++++++--- po/sr.po | 38 ++++++++++++---- po/tr.po | 124 ++++++++++++++++++++++++++++++++------------------- po/uk.po | 29 +++++++++--- po/zh_CN.po | 30 ++++++++++--- po/zh_TW.po | 28 +++++++++--- 29 files changed, 803 insertions(+), 237 deletions(-) diff --git a/po/ar.po b/po/ar.po index 836bfc36..7258e645 100644 --- a/po/ar.po +++ b/po/ar.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" "ar/)\n" "Language: ar\n" @@ -27,6 +27,20 @@ msgstr "لم يُعثر على الصّفحة" msgid "Sorry, the page you've requested does not exist." msgstr "آسفون، الصّفحة التي طلبتها غير موجودة." +msgid "Note" +msgstr "ملاحظة" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "الخدمة غير متوفّرة" @@ -883,6 +897,9 @@ msgstr "غير نشط منذ" msgid "Active" msgstr "نشط" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "آخر ولوج" @@ -899,6 +916,10 @@ msgstr "حرّر حساب هذا المستخدم" msgid "Click %shere%s if you want to permanently delete this account." msgstr "انقر %sهنا%s إن أردت حذف هذا الحساب نهائيًّا." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "مطلوب" @@ -1201,9 +1222,6 @@ msgstr "المصادر" msgid "Use this form to close the request for package base %s%s%s." msgstr "استخدم هذه الاستمارة لإغلاق طلب أساس الحزمة %s%s%s." -msgid "Note" -msgstr "ملاحظة" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/ast.po b/po/ast.po index 7444474c..2a80e03e 100644 --- a/po/ast.po +++ b/po/ast.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" "ast/)\n" "Language: ast\n" @@ -27,6 +27,20 @@ msgstr "Nun s'alcontró la páxina" msgid "Sorry, the page you've requested does not exist." msgstr "Perdón, la páxina que pidisti nun esiste." +msgid "Note" +msgstr "Nota" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Serviciu non disponible" @@ -865,6 +879,9 @@ msgstr "Inactivu dende" msgid "Active" msgstr "Activu" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "" @@ -881,6 +898,10 @@ msgstr "" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Primi %sequí%s si quies desaniciar esta cuenta dafechu." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "riquíu" @@ -1180,9 +1201,6 @@ msgstr "Fontes" msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa esti formulariu pa zarrar la solicitú pal paquete base %s%s%s." -msgid "Note" -msgstr "Nota" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/ca.po b/po/ca.po index fc7659c7..3cab9e51 100644 --- a/po/ca.po +++ b/po/ca.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" "ca/)\n" "Language: ca\n" @@ -27,6 +27,20 @@ msgstr "No s’ha trobat la pàgina" msgid "Sorry, the page you've requested does not exist." msgstr "Ho sentim, la pàgina que ha sol·licitat no existeix." +msgid "Note" +msgstr "" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "" @@ -870,6 +884,9 @@ msgstr "" msgid "Active" msgstr "Actiu" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "" @@ -886,6 +903,10 @@ msgstr "" msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "requerit" @@ -1184,9 +1205,6 @@ msgstr "Fonts" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -msgid "Note" -msgstr "" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/cs.po b/po/cs.po index 0301019e..d5abe1c4 100644 --- a/po/cs.po +++ b/po/cs.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" "Language: cs\n" "MIME-Version: 1.0\n" @@ -27,6 +27,20 @@ msgstr "Stránka nenalezena" msgid "Sorry, the page you've requested does not exist." msgstr "Omlouváme se, požadovaná stránka neexistuje." +msgid "Note" +msgstr "" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Služba nedostupná" @@ -852,6 +866,9 @@ msgstr "Neaktivní od" msgid "Active" msgstr "Aktivní" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Poslední přihlášení" @@ -868,6 +885,10 @@ msgstr "Upravit tento uživatelský účet" msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "vyžadováno" @@ -1167,9 +1188,6 @@ msgstr "Zdroje" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -msgid "Note" -msgstr "" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/da.po b/po/da.po index 66327dfd..2f31a152 100644 --- a/po/da.po +++ b/po/da.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" "da/)\n" "Language: da\n" @@ -26,6 +26,20 @@ msgstr "Siden blev ikke fundet" msgid "Sorry, the page you've requested does not exist." msgstr "Beklager, den forspurgte side findes ikke." +msgid "Note" +msgstr "" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Service utilgængelig" @@ -846,6 +860,9 @@ msgstr "Inaktiv siden" msgid "Active" msgstr "Aktiv" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Sidste login" @@ -862,6 +879,10 @@ msgstr "" msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "påkrævet" @@ -1160,9 +1181,6 @@ msgstr "Kilder" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -msgid "Note" -msgstr "" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/de.po b/po/de.po index d49870d6..5aa6e538 100644 --- a/po/de.po +++ b/po/de.po @@ -24,9 +24,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" "de/)\n" "Language: de\n" @@ -41,6 +41,20 @@ msgstr "Seite nicht gefunden" msgid "Sorry, the page you've requested does not exist." msgstr "Die angeforderte Seite existiert leider nicht." +msgid "Note" +msgstr "Anmerkung" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Dienst nicht verfügbr" @@ -946,6 +960,9 @@ msgstr "Nicht aktiv seit" msgid "Active" msgstr "Aktiv" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Letzter Login" @@ -963,6 +980,10 @@ msgid "Click %shere%s if you want to permanently delete this account." msgstr "" "Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchtest." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "Notwendig" @@ -1269,9 +1290,6 @@ msgstr "" "Benutze dieses Formular, um die Anfrage für die Paketbasis %s%s%s zu " "schließen." -msgid "Note" -msgstr "Anmerkung" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/el.po b/po/el.po index c241f35c..254c02a1 100644 --- a/po/el.po +++ b/po/el.po @@ -14,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" "Language: el\n" "MIME-Version: 1.0\n" @@ -30,6 +30,20 @@ msgstr "Η σελίδα δε βρέθηκε" msgid "Sorry, the page you've requested does not exist." msgstr "Μας συγχωρείτε, η σελίδα που ζητήσατε δεν υπάρχει." +msgid "Note" +msgstr "" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "" @@ -882,6 +896,9 @@ msgstr "Αδρανής από" msgid "Active" msgstr "Ενεργός" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Τελευταία σύνδεση" @@ -898,6 +915,10 @@ msgstr "Τροποποιήστε το λογαριασμό αυτού του χ msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "απαιτούμενο" @@ -1196,9 +1217,6 @@ msgstr "Πηγές" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -msgid "Note" -msgstr "" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/es.po b/po/es.po index 4dd702e8..c61e657d 100644 --- a/po/es.po +++ b/po/es.po @@ -12,13 +12,15 @@ # Pablo Roberto “Jristz” Lezaeta Reyes , 2012 # Pablo Roberto “Jristz” Lezaeta Reyes , 2016 # Pablo Roberto “Jristz” Lezaeta Reyes , 2013-2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" "es/)\n" "Language: es\n" @@ -33,6 +35,20 @@ msgstr "Página no encontrada" msgid "Sorry, the page you've requested does not exist." msgstr "La página solicitada no existe." +msgid "Note" +msgstr "Nota" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Servicio no disponible" @@ -89,7 +105,7 @@ msgid "Submit a proposal to vote on." msgstr "Envía una propuesta a la cual votar." msgid "Applicant/TU" -msgstr "Candidato/Usuario de confianza (TU)" +msgstr "Candidato/Usuario de confianza (UC)" msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" @@ -232,7 +248,7 @@ msgstr "" "detalles." msgid "The following SSH fingerprints are used for the AUR:" -msgstr "Las siguientes huellas SSH están en uso para AUR." +msgstr "Las siguientes huellas SSH están en uso para el AUR." msgid "Discussion" msgstr "Debate" @@ -366,7 +382,7 @@ msgid "" "message to the %saur-general%s mailing list." msgstr "" "Si olvidaste la dirección de correo que usaste para registrarte, envía un " -"mensaje a la %slista de correo aur-general%s." +"mensaje a la %slista de correo general del AUR%s." msgid "Enter your e-mail address:" msgstr "Introduce tu dirección de correo:" @@ -936,6 +952,9 @@ msgstr "Inactivo desde" msgid "Active" msgstr "Activo" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Última autentificación" @@ -952,6 +971,10 @@ msgstr "Editar la cuenta de este usuario" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Haz clic %saquí%s si deseas eliminar permanentemente esta cuenta." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "obligatorio" @@ -1261,9 +1284,6 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" "Usa este formulario para cerrar la solicitud para el paquete base %s%s%s." -msgid "Note" -msgstr "Nota" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." @@ -1356,8 +1376,8 @@ msgstr "Fecha" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "~%d día restante" +msgstr[1] "~%d días restantes" #, php-format msgid "~%d hour left" @@ -1460,6 +1480,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"La popularidad se calcula como la suma de todos los votos y cada uno " +"ponderado con un factor de %.2f por día desde la creación del paquete." msgid "Yes" msgstr "Sí" diff --git a/po/es_419.po b/po/es_419.po index de9196af..14adaf94 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -10,13 +10,15 @@ # Nicolás de la Torre , 2012 # Pablo Roberto “Jristz” Lezaeta Reyes , 2016 # Pablo Roberto “Jristz” Lezaeta Reyes , 2012,2015-2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" "aur/language/es_419/)\n" "Language: es_419\n" @@ -31,6 +33,20 @@ msgstr "Página no encontrada" msgid "Sorry, the page you've requested does not exist." msgstr "Disculpe, la página que solicitó no existe." +msgid "Note" +msgstr "Nota" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Servicio no disponible" @@ -87,7 +103,7 @@ msgid "Submit a proposal to vote on." msgstr "Envíe una propuesta a la cual votar." msgid "Applicant/TU" -msgstr "Candidato/Usuario de confianza (TU)" +msgstr "Candidato/Usuario de confianza (UC)" msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" @@ -96,13 +112,13 @@ msgid "Type" msgstr "Tipo" msgid "Addition of a TU" -msgstr "Agregar a un nuevo usuario de confianza" +msgstr "Agregar a un nuevo Usuario de Confianza" msgid "Removal of a TU" -msgstr "Remover a un usuario de confianza" +msgstr "Remover a un Usuario de Confianza" msgid "Removal of a TU (undeclared inactivity)" -msgstr "Remover a un usuario de confianza (no declarado inactivo)" +msgstr "Remover a un Usuario de Confianza (no declarado inactivo)" msgid "Amendment of Bylaws" msgstr "Enmienda a las Bylaws (Reglas de los TU)" @@ -128,7 +144,7 @@ msgid "" "Guidelines%s for more information." msgstr "" "¡Bienvenido al repositorio de usuarios de Arch! Lea la %sGuía del usuario " -"del AUR%s y la %sGuía del usuario de confianza del AUR%s para mayor " +"del AUR%s y la %sGuía del usuario de Confianza del AUR%s para mayor " "información." #, php-format @@ -153,8 +169,8 @@ msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -"Los paquetes en AUR son producidos por los usuarios. Cualquier uso de ellos " -"o sus archivos es a su propio riesgo." +"Los paquetes en el AUR son producidos por los usuarios. Cualquier uso de " +"ellos o sus archivos es a su propio riesgo." msgid "Learn more..." msgstr "Aprenda más..." @@ -229,7 +245,7 @@ msgstr "" "información." msgid "The following SSH fingerprints are used for the AUR:" -msgstr "Las siguientes huellas SSH están en uso para AUR." +msgstr "Las siguientes huellas SSH están en uso para el AUR." msgid "Discussion" msgstr "Debate" @@ -929,6 +945,9 @@ msgstr "Inactivo desde" msgid "Active" msgstr "Activo" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Última autentificación" @@ -945,6 +964,10 @@ msgstr "Editar la cuenta de este usuario" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Haga clic %saquí%s si desea borrar permanentemente esa cuenta." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "obligatorio" @@ -1061,7 +1084,7 @@ msgstr "Regresar a detalles" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -"Derechos de autor %s 2004 - %d, equipo desarrollador de la web del AUR." +"Derechos de autor %s 2004 - %d, equipo de desarrollo de la web del AUR." msgid "My Packages" msgstr "Mis paquetes" @@ -1253,9 +1276,6 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" "Use este formulario para cerrar la petición para el paquete base %s%s%s." -msgid "Note" -msgstr "Nota" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." @@ -1348,8 +1368,8 @@ msgstr "Fecha" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "~%d día restante" +msgstr[1] "~%d días restantes" #, php-format msgid "~%d hour left" @@ -1452,6 +1472,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"La Popularidad es calculada como la suma de todos los votos ponderados con " +"un factor de %.2f por día desde la creación del paquete." msgid "Yes" msgstr "Sí" @@ -1545,7 +1567,7 @@ msgid "Participation" msgstr "Participación" msgid "Last Votes by TU" -msgstr "Último voto del usuario de confianza" +msgstr "Último voto del Usuario de Confianza" msgid "Last vote" msgstr "Último voto" diff --git a/po/fi.po b/po/fi.po index 68499671..6e20ae22 100644 --- a/po/fi.po +++ b/po/fi.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" "fi/)\n" "Language: fi\n" @@ -26,6 +26,20 @@ msgstr "Sivua ei löydy." msgid "Sorry, the page you've requested does not exist." msgstr "Valitettavasti hakemaasi sivua ei ole olemassa." +msgid "Note" +msgstr "" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Palvelu ei saatavilla." @@ -900,6 +914,9 @@ msgstr "" msgid "Active" msgstr "Aktiivinen" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "" @@ -916,6 +933,10 @@ msgstr "" msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "vaaditaan" @@ -1214,9 +1235,6 @@ msgstr "Lähdetiedostot" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -msgid "Note" -msgstr "" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/fr.po b/po/fr.po index ec4cbf34..0c10f9fb 100644 --- a/po/fr.po +++ b/po/fr.po @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-08 09:34+0000\n" -"Last-Translator: Cedric Girard \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-11 20:06+0000\n" +"Last-Translator: Antoine Lubineau \n" "Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" "fr/)\n" "Language: fr\n" @@ -32,6 +32,21 @@ msgstr "Page non trouvée" msgid "Sorry, the page you've requested does not exist." msgstr "Désolé, la page que vous avez demandée n’existe pas." +msgid "Note" +msgstr "Note" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" +"Les URL de clone Git ne sont pas censées être ouvertes depuis un navigateur." + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "Pour cloner le dépôt Git de %s, exécutez %s." + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "Cliquez %sici%s pour retourner à la page des détails de %s." + msgid "Service Unavailable" msgstr "Service indisponible" @@ -949,6 +964,9 @@ msgstr "Inactif depuis" msgid "Active" msgstr "Actif" +msgid "Registration date:" +msgstr "Date d'enregistrement :" + msgid "Last Login" msgstr "Dernière connexion." @@ -965,6 +983,10 @@ msgstr "Éditer le compte de cet utilisateur." msgid "Click %shere%s if you want to permanently delete this account." msgstr "Cliquez %sici%s si vous voulez effacer ce compte de façon définitive." +#, php-format +msgid "Click %shere%s for user details." +msgstr "Cliquer %sici%s pour obtenir les détails de l'utilisateur." + msgid "required" msgstr "requis" @@ -1271,9 +1293,6 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" "Utiliser ce formulaire pour fermer la requête pour le paquet de base %s%s%s." -msgid "Note" -msgstr "Note" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/he.po b/po/he.po index c660b103..75321be6 100644 --- a/po/he.po +++ b/po/he.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-11 14:16+0000\n" -"Last-Translator: Yaron Shahrabani \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" "he/)\n" "Language: he\n" @@ -27,6 +27,20 @@ msgstr "העמוד לא נמצא" msgid "Sorry, the page you've requested does not exist." msgstr "העמוד שביקשת אינו קיים, עמך הסליחה." +msgid "Note" +msgstr "הערה" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "השירות אינו זמין" @@ -867,6 +881,9 @@ msgstr "אין פעילות מאז" msgid "Active" msgstr "פעיל" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "כניסה אחרונה" @@ -883,6 +900,10 @@ msgstr "עריכת החשבון של משתמש זה" msgid "Click %shere%s if you want to permanently delete this account." msgstr "נא ללחוץ %sכאן%s אם רצונך הוא למחוק את החשבון הזה לצמיתות." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "נדרש" @@ -1182,9 +1203,6 @@ msgstr "מקורות" msgid "Use this form to close the request for package base %s%s%s." msgstr "ניתן להשתמש בטופס זה כדי לסגור את הבקשה לבסיס החבילה %s%s%s." -msgid "Note" -msgstr "הערה" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/hr.po b/po/hr.po index 461dc288..2bf3963c 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" "hr/)\n" "Language: hr\n" @@ -26,6 +26,20 @@ msgstr "" msgid "Sorry, the page you've requested does not exist." msgstr "" +msgid "Note" +msgstr "" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "" @@ -846,6 +860,9 @@ msgstr "" msgid "Active" msgstr "Aktivan" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "" @@ -862,6 +879,10 @@ msgstr "" msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "obvezno" @@ -1161,9 +1182,6 @@ msgstr "Izvor" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -msgid "Note" -msgstr "" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/hu.po b/po/hu.po index 8287d14d..a2320696 100644 --- a/po/hu.po +++ b/po/hu.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-08 08:56+0000\n" -"Last-Translator: György Balló \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" "hu/)\n" "Language: hu\n" @@ -28,6 +28,20 @@ msgstr "Az oldal nem található" msgid "Sorry, the page you've requested does not exist." msgstr "Sajnálom, a megtekinteni kívánt oldal nem létezik." +msgid "Note" +msgstr "Megjegyzés" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Szolgáltatás nem elérhető" @@ -918,6 +932,9 @@ msgstr "Ezóta inaktív:" msgid "Active" msgstr "Aktív" +msgid "Registration date:" +msgstr "Regisztráció dátuma:" + msgid "Last Login" msgstr "Legutóbbi bejelentkezés" @@ -934,6 +951,10 @@ msgstr "Ezen felhasználó fiókjának szerkesztése" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kattints %side%s, ha véglegesen törölni szeretnéd ezt a fiókot." +#, php-format +msgid "Click %shere%s for user details." +msgstr "Kattints %side%s a felhasználó részleteihez." + msgid "required" msgstr "kötelező" @@ -1242,9 +1263,6 @@ msgstr "" "Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem " "lezárásához." -msgid "Note" -msgstr "Megjegyzés" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/it.po b/po/it.po index 042aaf36..e0047f3f 100644 --- a/po/it.po +++ b/po/it.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" "it/)\n" "Language: it\n" @@ -27,6 +27,20 @@ msgstr "Impossibile trovare la pagina" msgid "Sorry, the page you've requested does not exist." msgstr "Spiacenti, la pagina richiesta non esiste." +msgid "Note" +msgstr "Nota" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Servizio non disponibile" @@ -933,6 +947,9 @@ msgstr "Inattivo da" msgid "Active" msgstr "Attivo" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Ultimo accesso" @@ -949,6 +966,10 @@ msgstr "Modifica l'account di quest'utente" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clicca %squi%s se vuoi eliminare definitivamente questo account." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "obbligatorio" @@ -1253,9 +1274,6 @@ msgstr "Sorgenti" msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa questo modulo per chiudere la richiesta del pacchetto base %s%s%s." -msgid "Note" -msgstr "Nota" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/ja.po b/po/ja.po index d3547425..fae1a946 100644 --- a/po/ja.po +++ b/po/ja.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-13 16:24+0000\n" -"Last-Translator: kusakata\n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" "ja/)\n" "Language: ja\n" @@ -27,6 +27,20 @@ msgstr "ページが見つかりませんでした" msgid "Sorry, the page you've requested does not exist." msgstr "あなたがリクエストしたページは存在しませんでした。" +msgid "Note" +msgstr "ノート" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Service Unavailable" @@ -913,6 +927,9 @@ msgstr "休止開始" msgid "Active" msgstr "活動中" +msgid "Registration date:" +msgstr "登録日:" + msgid "Last Login" msgstr "最後のログイン" @@ -929,6 +946,10 @@ msgstr "このユーザーのアカウントを編集" msgid "Click %shere%s if you want to permanently delete this account." msgstr "このアカウントを恒久的に削除したい場合は%sこちら%sをクリック。" +#, php-format +msgid "Click %shere%s for user details." +msgstr "ユーザーの詳細は%sこちら%sをクリック。" + msgid "required" msgstr "必須" @@ -1235,9 +1256,6 @@ msgstr "" "このフォームを使ってパッケージベース %s%s%s のリクエストをクローズすることが" "できます。" -msgid "Note" -msgstr "ノート" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/nb.po b/po/nb.po index db09acfe..08597e50 100644 --- a/po/nb.po +++ b/po/nb.po @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" "language/nb/)\n" "Language: nb\n" @@ -30,6 +30,20 @@ msgstr "Finner ikke siden" msgid "Sorry, the page you've requested does not exist." msgstr "Den ønskede siden finnes ikke." +msgid "Note" +msgstr "OBS" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Tjenesten er utilgjengelig" @@ -884,6 +898,9 @@ msgstr "Inaktiv siden" msgid "Active" msgstr "Aktiv" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Sist logget inn" @@ -900,6 +917,10 @@ msgstr "Endre brukerkonto" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klikk %sher%s hvis du vil slette denne kontoen, for alltid." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "trengs" @@ -1200,9 +1221,6 @@ msgstr "Kilder" msgid "Use this form to close the request for package base %s%s%s." msgstr "Bruk dette skjemaet for å lukke forespørselen for grunnpakken %s%s%s." -msgid "Note" -msgstr "OBS" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/nl.po b/po/nl.po index 2a85dab4..99432f5f 100644 --- a/po/nl.po +++ b/po/nl.po @@ -12,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" "Language: nl\n" "MIME-Version: 1.0\n" @@ -28,6 +28,20 @@ msgstr "De pagina kon niet worden gevonden" msgid "Sorry, the page you've requested does not exist." msgstr "Sorry, de pagina die u heeft aangevraagd bestaat niet." +msgid "Note" +msgstr "Notitie" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "De dienst is niet beschikbaar" @@ -910,6 +924,9 @@ msgstr "Geen activiteit sinds" msgid "Active" msgstr "Actief" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Laatste Login" @@ -926,6 +943,10 @@ msgstr "Bewerk account van deze gebruiker" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klik %shier%s als u dit account permanent wilt verwijderen." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "verplicht" @@ -1229,9 +1250,6 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" "Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." -msgid "Note" -msgstr "Notitie" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/pl.po b/po/pl.po index bc423b5d..d7338cab 100644 --- a/po/pl.po +++ b/po/pl.po @@ -9,15 +9,16 @@ # Chris Warrick , 2012 # Kwpolska , 2011 # Lukas Fleischer , 2011 +# Michal T , 2016 # Nuc1eoN , 2014 # Piotr Strębski , 2013-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-12 09:11+0000\n" +"Last-Translator: Michal T \n" "Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" "pl/)\n" "Language: pl\n" @@ -33,6 +34,20 @@ msgstr "Nie znaleziono strony" msgid "Sorry, the page you've requested does not exist." msgstr "Przepraszamy, strona o którą prosiłeś nie istnieje." +msgid "Note" +msgstr "Uwaga" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "Adresy URL GIT clone nie są przeznaczone do otwierania w przeglądarce." + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "Aby sklonować repozytorium GIT-a %s, uruchom %s." + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "Kliknij %stutaj%s by powrócić do strony szczegółów %s." + msgid "Service Unavailable" msgstr "Usługa niedostępna" @@ -177,6 +192,8 @@ msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +"Wnioskuj o wyrzeczenie własności pakietu - np. gdy zarządzający jest " +"nieaktywny i pakiet został oznaczony jako przestarzały dawno temu." msgid "Deletion Request" msgstr "Prośba o usunięcie" @@ -212,7 +229,7 @@ msgid "" msgstr "" msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "Następujące odciski SSH są używane przez AUR:" msgid "Discussion" msgstr "Dyskusja" @@ -223,6 +240,10 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Ogólna dyskusja dotycząca Repozytorium Użytkowników Arch (AUR) i struktury " +"Zaufanych Użytkowników odbywa się na %saur-general%s. Dyskusja dotycząca " +"rozwoju interfejsu webowego AUR odbywa się zaś na liście dyskusyjnej %saur-" +"dev%s." msgid "Bug Reporting" msgstr "Zgłaszanie błędów" @@ -234,6 +255,10 @@ msgid "" "%sonly%s. To report packaging bugs contact the package maintainer or leave a " "comment on the appropriate package page." msgstr "" +"Jeśli znalazłeś błąd w interfejsie webowym AUR, zgłoś go w naszym %ssystemie " +"śledzenia błędów%s. Używaj go %swyłącznie%s do zgłaszania błędów związanych " +"z interfejsem webowym AUR. Błędy powiązane z pakietami zgłaszaj ich " +"opiekunom lub zostaw komentarz pod odpowiednim pakietem." msgid "Package Search" msgstr "Wyszukiwanie pakietów" @@ -347,6 +372,7 @@ msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +"Wybrane pakiety nie zostały porzucone, sprawdź pole wyboru potwierdzenia." msgid "Cannot find package to merge votes and comments into." msgstr "Nie można znaleźć pakietu do scalenia głosów i komentarzy." @@ -396,12 +422,16 @@ msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"Użyj tego formularza, aby złożyć prośbę wyrzeczenie własności bazie pakietu " +"%s%s%s, która zawiera następujące pakiety:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"Zaznaczając pole wyboru potwierdzasz, że chcesz porzucić pakiet i przenieść " +"własność na %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." @@ -872,7 +902,7 @@ msgid "Real Name" msgstr "Imię i nazwisko" msgid "Homepage" -msgstr "" +msgstr "Strona główna" msgid "IRC Nick" msgstr "Nick na IRC-u" @@ -889,6 +919,9 @@ msgstr "Nieaktywny od" msgid "Active" msgstr "Aktywne" +msgid "Registration date:" +msgstr "Data rejestracji:" + msgid "Last Login" msgstr "Ostatnie logowanie" @@ -905,6 +938,10 @@ msgstr "Edycja tego konta użytkownika" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknij %stutaj%s, jeśli chcesz nieodwracalnie usunąć to konto." +#, php-format +msgid "Click %shere%s for user details." +msgstr "Kliknij %stutaj%s by wyświetlić szczegóły użytkownika." + msgid "required" msgstr "wymagane" @@ -956,7 +993,7 @@ msgid "Notify of package updates" msgstr "Powiadom o aktualizacjach pakietu" msgid "Notify of ownership changes" -msgstr "" +msgstr "Powiadom o zmianie właściciela" msgid "Update" msgstr "Aktualizuj" @@ -1062,7 +1099,7 @@ msgid "Disable notifications" msgstr "Wyłącz powiadomienia" msgid "Enable notifications" -msgstr "" +msgstr "Włącz powiadomienia" msgid "Manage Co-Maintainers" msgstr "Zarządzanie współutrzymującymi" @@ -1211,9 +1248,6 @@ msgstr "Źródła" msgid "Use this form to close the request for package base %s%s%s." msgstr "Użyj tego formularza, aby zamknąć prośbę o bazę pakietów %s%s%s." -msgid "Note" -msgstr "Uwaga" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." @@ -1293,9 +1327,9 @@ msgstr "Data" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "pozostało ~%d dzień" +msgstr[1] "pozostało ~%d dni" +msgstr[2] "pozostało ~%d dni" #, php-format msgid "~%d hour left" diff --git a/po/pt_BR.po b/po/pt_BR.po index 27259703..f653b435 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 12:23+0000\n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 14:05+0000\n" "Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" "language/pt_BR/)\n" @@ -31,6 +31,20 @@ msgstr "Página não encontrada" msgid "Sorry, the page you've requested does not exist." msgstr "Desculpe, a página que você solicitou não existe." +msgid "Note" +msgstr "Nota" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "URLs de git-clone não servem para ser abertas em um navegador." + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "Para clonar o repositório Git de %s, execute %s." + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "Clique %saqui%s para retornar para a página de detalhes de %s." + msgid "Service Unavailable" msgstr "Serviço indisponível" @@ -923,6 +937,9 @@ msgstr "Inativo desde" msgid "Active" msgstr "Ativa" +msgid "Registration date:" +msgstr "Data de registro:" + msgid "Last Login" msgstr "Último login" @@ -939,6 +956,10 @@ msgstr "Edite a conta desse usuário" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clique %saqui%s se você deseja excluir permanentemente esta conta." +#, php-format +msgid "Click %shere%s for user details." +msgstr "Clique %saqui%s para os detalhes do usuário." + msgid "required" msgstr "obrigatório" @@ -1245,9 +1266,6 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" "Use esse formulário para fechar a requisição para o pacote base %s%s%s." -msgid "Note" -msgstr "Nota" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/pt_PT.po b/po/pt_PT.po index 395b3242..59ecb4f6 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -12,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" "aur/language/pt_PT/)\n" "Language: pt_PT\n" @@ -29,6 +29,20 @@ msgstr "Página Não Encontrada" msgid "Sorry, the page you've requested does not exist." msgstr "As nossas desculpas, a página que pediu não existe." +msgid "Note" +msgstr "" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Serviço não disponível" @@ -894,6 +908,9 @@ msgstr "Inativo desde" msgid "Active" msgstr "Activo" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Última sessão" @@ -910,6 +927,10 @@ msgstr "Editar a conta deste utilizador" msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "necessário" @@ -1208,9 +1229,6 @@ msgstr "Fontes" msgid "Use this form to close the request for package base %s%s%s." msgstr "" -msgid "Note" -msgstr "" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/ro.po b/po/ro.po index b93d53d2..85172d91 100644 --- a/po/ro.po +++ b/po/ro.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" "ro/)\n" "Language: ro\n" @@ -28,6 +28,20 @@ msgstr "Pagina nu a fost găsită" msgid "Sorry, the page you've requested does not exist." msgstr "Din păcate, pagina solicitată nu există." +msgid "Note" +msgstr "Notă" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "" @@ -876,6 +890,9 @@ msgstr "Inactiv din" msgid "Active" msgstr "Activ" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Ultima autentificare" @@ -892,6 +909,10 @@ msgstr "Modifică contul acestui utilizator" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clic %saici%s dacă dorești să ștergi definitiv acest cont." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "cerut" @@ -1193,9 +1214,6 @@ msgstr "" "Folosește acest formular pentru a închide cererea pentru pachetul de bază %s" "%s%s." -msgid "Note" -msgstr "Notă" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/ru.po b/po/ru.po index e75a688c..530947e1 100644 --- a/po/ru.po +++ b/po/ru.po @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" "ru/)\n" "Language: ru\n" @@ -34,6 +34,20 @@ msgstr "Страница не найдена" msgid "Sorry, the page you've requested does not exist." msgstr "Извините, запрошенная страница не существует." +msgid "Note" +msgstr "Примечание" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Сервис недоступен" @@ -913,6 +927,9 @@ msgstr "Неактивен с" msgid "Active" msgstr "Активный" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Последний вход" @@ -929,6 +946,10 @@ msgstr "Отредактировать этот аккаунт" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Нажмите %sздесь%s, если Вы хотите удалить данный аккаунт насовсем." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "необходимо" @@ -1235,9 +1256,6 @@ msgstr "Исходники" msgid "Use this form to close the request for package base %s%s%s." msgstr "Используйте эту форму, чтобы закрыть запрос о группе пакетов %s%s%s." -msgid "Note" -msgstr "Примечание" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/sk.po b/po/sk.po index 9a8c80a9..4a564e9f 100644 --- a/po/sk.po +++ b/po/sk.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" "sk/)\n" "Language: sk\n" @@ -26,6 +26,20 @@ msgstr "Stránka nebola nájdená" msgid "Sorry, the page you've requested does not exist." msgstr "Mrzí nás to, ale stránka, ktorú ste zadali, neexistuje." +msgid "Note" +msgstr "Poznámka" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "Služba nie je dostupná" @@ -905,6 +919,9 @@ msgstr "Neaktívny od" msgid "Active" msgstr "Aktívny" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "Posledné prihlásenie" @@ -921,6 +938,10 @@ msgstr "Editovať účet tohto užívateľa" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %ssem%s ak chcete natrvalo vymazať tento účet." +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "povinný" @@ -1226,9 +1247,6 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" "Použite tento formulár pre zatvorenie požiadavky na základňu balíčka %s%s%s." -msgid "Note" -msgstr "Poznámka" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/sr.po b/po/sr.po index b9b2f406..32a57394 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-11 14:07+0000\n" +"Last-Translator: Slobodan Terzić \n" "Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" "sr/)\n" "Language: sr\n" @@ -28,6 +28,20 @@ msgstr "Stranica nije nađena" msgid "Sorry, the page you've requested does not exist." msgstr "Stranica koju ste zahtevali ne postoji." +msgid "Note" +msgstr "Beleška" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "URL-ovi za Git kloniranje nisu namenjeni za otvaranje u pregledaču." + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "Da bi klonirali git riznicu %s, pokrenite %s." + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "Kliknite %sovde%s da bi se vratili na stranicu o %s." + msgid "Service Unavailable" msgstr "Servis nije dostupan" @@ -898,6 +912,9 @@ msgstr "Neaktivan od" msgid "Active" msgstr "Aktivan" +msgid "Registration date:" +msgstr "Datum registracije:" + msgid "Last Login" msgstr "Poslednje prijavljivanje" @@ -914,6 +931,10 @@ msgstr "Uređivanje naloga ovog korisnika" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %sovde%s ako želite trajno brisanje ovog naloga." +#, php-format +msgid "Click %shere%s for user details." +msgstr "Kliknite %sovde%s za podatke o korisniku." + msgid "required" msgstr "neophodno" @@ -1219,9 +1240,6 @@ msgstr "Izvori" msgid "Use this form to close the request for package base %s%s%s." msgstr "Ovim formularom zatvarate zahteve za osnovu paketa %s%s%s." -msgid "Note" -msgstr "Beleška" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." @@ -1312,9 +1330,9 @@ msgstr "Datum" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "Preostaje još ~%d dan" +msgstr[1] "Preostaje još ~%d dana" +msgstr[2] "Preostaje još ~%d dana" #, php-format msgid "~%d hour left" @@ -1419,6 +1437,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"Popularnost se izračunava kao suma svih glasova, gde svaki glas ima teži " +"%.2f po danu od kada je dat." msgid "Yes" msgstr "Da" diff --git a/po/tr.po b/po/tr.po index 9f843c22..b5ddf23c 100644 --- a/po/tr.po +++ b/po/tr.po @@ -9,14 +9,15 @@ # Lukas Fleischer , 2011 # Samed Beyribey , 2012 # Samed Beyribey , 2012 +# Serpil Acar , 2016 # Atilla Öntaş , 2012 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-09 05:38+0000\n" +"Last-Translator: Serpil Acar \n" "Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" "tr/)\n" "Language: tr\n" @@ -31,6 +32,20 @@ msgstr "Sayfa Bulunamadı" msgid "Sorry, the page you've requested does not exist." msgstr "Üzgünüz, talep ettiğiniz sayfa bulunamadı." +msgid "Note" +msgstr "Not" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "Git clone linkleri bir tarayıcıda açılamazlar." + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "%s'in Git deposunu kopyalamak için, %s komutunu çalıştırın." + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "Detaylar sayfasına %s geri dönmek için %sburaya%s tıklayınız." + msgid "Service Unavailable" msgstr "Hizmete Erişilemiyor" @@ -290,7 +305,7 @@ msgid "Enter login credentials" msgstr "Giriş bilgilerinizi doldurun" msgid "User name or email address" -msgstr "" +msgstr "Kullanıcı adı veya e-posta adresi" msgid "Password" msgstr "Parola" @@ -443,10 +458,10 @@ msgstr "" "bırakabilir." msgid "Flag Comment" -msgstr "" +msgstr "Yorumu İşaretle" msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Paketi güncel değil olarak işaretle" #, php-format msgid "" @@ -464,6 +479,8 @@ msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Paketin neden güncel olmadığıyla ilgili detayları aşağıya girin, tercihen " +"sürüm bildirilerinin veya yeni tarball sürümünün linklerini dahil ederek." msgid "Comments" msgstr "Yorumlar" @@ -473,6 +490,7 @@ msgstr "İşaretle" msgid "Only registered users can flag packages out-of-date." msgstr "" +"Sadece kayıtlı kullanıcılar paketleri güncel değil olarak işaretleyebilir." msgid "Package Merging" msgstr "Paket birleştirme" @@ -673,16 +691,16 @@ msgid "View account information for %s" msgstr "%s için hesap bilgilerini görüntüle" msgid "Package base ID or package base name missing." -msgstr "" +msgstr "Paket ID'si veya paket ismi eksik." msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Bu yorumu düzenlemek için yetkiniz yok." msgid "Comment does not exist." -msgstr "" +msgstr "Yorum bulunamadı." msgid "Comment cannot be empty." -msgstr "" +msgstr "Yorum boş olamaz." msgid "Comment has been added." msgstr "Yorum eklendi." @@ -694,16 +712,16 @@ msgid "Missing comment ID." msgstr "Yorum kimliği bulunamadı." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "5 taneden fazla yorum iğnelenemez." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Bu yorumu iğnelemek için yetkiniz yok." msgid "You are not allowed to unpin this comment." msgstr "" msgid "Comment has been pinned." -msgstr "" +msgstr "Yorum iğnelendi." msgid "Comment has been unpinned." msgstr "" @@ -721,7 +739,7 @@ msgid "You did not select any packages to flag." msgstr "İşaretlenecek paketleri seçmediniz." msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" +msgstr "Seçilen paketler işaretlenmedi, lütfen bir yorum giriniz." msgid "The selected packages have been flagged out-of-date." msgstr "Seçilen paketler güncelliğini yitirmiş olarak işaretlendi." @@ -789,10 +807,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "%s bildirim listesinden başarıyla çıktınız." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Bu silinmiş yorumu geri almak için yetkili değilsiniz." msgid "Comment has been undeleted." -msgstr "" +msgstr "Yorum silindi." msgid "You are not allowed to delete this comment." msgstr "Bu yorumu silme yetkiniz yok." @@ -801,7 +819,7 @@ msgid "Comment has been deleted." msgstr "Yorum silindi." msgid "Comment has been edited." -msgstr "" +msgstr "Yorum düzenlendi." msgid "You are not allowed to edit the keywords of this package base." msgstr "" @@ -826,7 +844,7 @@ msgstr "Paket detaylarını görüntüle" #, php-format msgid "requires %s" -msgstr "" +msgstr "%s'ye ihtiyaç duyuyor." msgid "You must be logged in to file package requests." msgstr "Paket gereksinimlerinin kaydını tutmalısın." @@ -882,13 +900,13 @@ msgid "Email Address" msgstr "E-posta adresi" msgid "hidden" -msgstr "" +msgstr "gizli" msgid "Real Name" msgstr "Gerçek İsim" msgid "Homepage" -msgstr "" +msgstr "Anasayfa" msgid "IRC Nick" msgstr "IRC Rumuzu" @@ -905,6 +923,9 @@ msgstr "Şu tarihten beri etkin değil:" msgid "Active" msgstr "Etkin" +msgid "Registration date:" +msgstr "Kayıt tarihi:" + msgid "Last Login" msgstr "Son giriş" @@ -921,6 +942,10 @@ msgstr "Bu kullanıcının hesabını düzenleyin" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Bu hesabı temelli olarak silmek istiyorsanız %sburaya%s tıklayın." +#, php-format +msgid "Click %shere%s for user details." +msgstr "Kullanıcı detayları için %sburaya%s tıklayın." + msgid "required" msgstr "gerekli" @@ -940,9 +965,11 @@ msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Lütfen e-posta adresinizi doğru girdiğinizden emin olun, aksi halde " +"hesabınız kilitlenecektir." msgid "Hide Email Address" -msgstr "" +msgstr "E-posta Adresini Gizle" msgid "Re-type password" msgstr "Parolayı tekrar girin" @@ -961,16 +988,16 @@ msgid "SSH Public Key" msgstr "SSH Kamu Anahtarı" msgid "Notification settings" -msgstr "" +msgstr "Bildirim ayarları" msgid "Notify of new comments" msgstr "Yeni yorumları bildir" msgid "Notify of package updates" -msgstr "" +msgstr "Paket güncellemelerini bildir" msgid "Notify of ownership changes" -msgstr "" +msgstr "Sahiplik değişikliklerini bildir." msgid "Update" msgstr "Güncelle" @@ -1017,7 +1044,7 @@ msgstr "Kaydet" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Güncel olmayan olarak işaretli yorum: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" @@ -1025,10 +1052,10 @@ msgstr "" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s güncel değil olarak işaretlenmedi." msgid "Return to Details" -msgstr "" +msgstr "Detaylara Geri Dön." #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." @@ -1057,7 +1084,7 @@ msgstr "Wikide ara" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Güncel değil olarak işaretlendi (%s)" msgid "Flag package out-of-date" msgstr "Güncelliğini yitirmiş olarak işaretle" @@ -1075,7 +1102,7 @@ msgid "Disable notifications" msgstr "Bildirimleri kapat" msgid "Enable notifications" -msgstr "" +msgstr "Bildirimleri etkinleştir" msgid "Manage Co-Maintainers" msgstr "Yardımcı Bakımcıları Yönet" @@ -1127,7 +1154,7 @@ msgstr "Son Güncelleme" #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Yorumu düzenle: %s" msgid "Add Comment" msgstr "Yorum Ekle" @@ -1136,43 +1163,43 @@ msgid "View all comments" msgstr "Tüm yorumları görünüle" msgid "Pinned Comments" -msgstr "" +msgstr "İğnelenmiş Yorumlar" msgid "Latest Comments" msgstr "Son Yorumlar" #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s, %s'e yorum yaptı." #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "%s'e isimsiz yorum" #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "%s'te, %s tarafından silindi." #, php-format msgid "deleted on %s" -msgstr "" +msgstr "%s'te silindi." #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "%s'te, %s tarafından düzenlendi" #, php-format msgid "edited on %s" -msgstr "" +msgstr "%s'te düzenlendi." msgid "Undelete comment" -msgstr "" +msgstr "Yorumu silmeyi geri al." msgid "Delete comment" msgstr "Yorumu sil" msgid "Pin comment" -msgstr "" +msgstr "Yorumu iğnele" msgid "Unpin comment" msgstr "" @@ -1224,9 +1251,6 @@ msgid "Use this form to close the request for package base %s%s%s." msgstr "" "Bu formu %s%s%s paket temeli için yapılan talebi kapatmak için kullanın." -msgid "Note" -msgstr "Not" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." @@ -1268,6 +1292,10 @@ msgid "" "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +"Silme talebi göndererek, Güvenilir Kullanıcıdan paketi silmesini " +"istiyorsunuz. Bu tür bir istek birden fazla olan paketlerde, geliştirilmesi " +"durdurulmuş yazılımlarda, ve aynı zamanda yasadışı ve onarılamaz bozuklukta " +"olan paketler için kullanılmalıdır." msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " @@ -1275,6 +1303,10 @@ msgid "" "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." msgstr "" +"Birleştirme talebi göndererek, Güvenilir Kullanıcıdan paketi silmesini ve bu " +"paketin oylarını ve yorumlarını diğer pakete transfer etmesini istiyorsunuz. " +"Bir paketi birleştirmek ilgili Git deposunu etkilemeyecektir. Hedef paketin " +"Git geçmişini bizzat güncellediğinizden emin olun. " msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " @@ -1305,8 +1337,8 @@ msgstr "Tarih" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "~%d gün kaldı" +msgstr[1] "~%d gün kaldı" #, php-format msgid "~%d hour left" @@ -1357,7 +1389,7 @@ msgid "Voted" msgstr "Oylanmış" msgid "Last modified" -msgstr "" +msgstr "Son düzenleme" msgid "Ascending" msgstr "Eskiden yeniye" @@ -1409,6 +1441,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"Popülarite, oluşturulmasından itibaren günlük %.2f oranı ile " +"ağırlaştırılarak bulunan her oyun toplamı ile ölçülür." msgid "Yes" msgstr "Evet" diff --git a/po/uk.po b/po/uk.po index 5f475c3a..8e26a4f7 100644 --- a/po/uk.po +++ b/po/uk.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 11:02+0000\n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 15:11+0000\n" "Last-Translator: Yarema aka Knedlyk \n" "Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" "uk/)\n" @@ -30,6 +30,21 @@ msgstr "Сторінку не знайдено" msgid "Sorry, the page you've requested does not exist." msgstr "На жаль, запитаної сторінки не існує." +msgid "Note" +msgstr "Примітка" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" +"Посилання на клонування сховища Git не вдасться відкрити в переглядарці." + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "Щоб клонувати сховище Git з %s, виконайте %s." + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "Клацніть %sтут%s для повернення на сторінку деталей %s." + msgid "Service Unavailable" msgstr "Сервіс недоступний" @@ -913,6 +928,9 @@ msgstr "Неактивний з" msgid "Active" msgstr "Активний" +msgid "Registration date:" +msgstr "Дата реєстрації:" + msgid "Last Login" msgstr "Останній вхід" @@ -929,6 +947,10 @@ msgstr "Редагування рахунку цього користувача" msgid "Click %shere%s if you want to permanently delete this account." msgstr "Натисніть %sтут%s, якщо Ви бажаєте безповоротно вилучити цей рахунок." +#, php-format +msgid "Click %shere%s for user details." +msgstr "Клацніть %sтут%s для деталей про користувача." + msgid "required" msgstr "обов'язково" @@ -1234,9 +1256,6 @@ msgstr "Сирці" msgid "Use this form to close the request for package base %s%s%s." msgstr "Використайте цю форму для закриття запиту щодо бази пакетів %s%s%s." -msgid "Note" -msgstr "Примітка" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/zh_CN.po b/po/zh_CN.po index 9c55ab98..453e7683 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -14,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-06 09:48+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" "language/zh_CN/)\n" "Language: zh_CN\n" @@ -31,6 +31,20 @@ msgstr "页面未找到" msgid "Sorry, the page you've requested does not exist." msgstr "请求的页面不存在。" +msgid "Note" +msgstr "提示" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "" + msgid "Service Unavailable" msgstr "服务不可用" @@ -877,6 +891,9 @@ msgstr "不活跃自" msgid "Active" msgstr "激活" +msgid "Registration date:" +msgstr "" + msgid "Last Login" msgstr "最后登陆" @@ -893,6 +910,10 @@ msgstr "编辑此用户的帐号" msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果你想要彻底删除这个帐号,请点击%s这里%s。" +#, php-format +msgid "Click %shere%s for user details." +msgstr "" + msgid "required" msgstr "必填" @@ -1190,9 +1211,6 @@ msgstr "源代码:" msgid "Use this form to close the request for package base %s%s%s." msgstr "使用这个表单来关闭对包基础 %s%s%s 的请求。" -msgid "Note" -msgstr "提示" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." diff --git a/po/zh_TW.po b/po/zh_TW.po index a888401c..5d1a4247 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-08-06 11:44+0200\n" -"PO-Revision-Date: 2016-08-08 07:33+0000\n" +"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"PO-Revision-Date: 2016-10-09 09:21+0000\n" "Last-Translator: Jeff Huang \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" "language/zh_TW/)\n" @@ -25,6 +25,20 @@ msgstr "頁面找不到" msgid "Sorry, the page you've requested does not exist." msgstr "抱歉,您所請求的頁面不存在。" +msgid "Note" +msgstr "注意" + +msgid "Git clone URLs are not meant to be opened in a browser." +msgstr "Git clone 的網址並不代表可以在瀏覽器中開啟。" + +#, php-format +msgid "To clone the Git repository of %s, run %s." +msgstr "要 clone %s 的 Git 倉庫,執行 %s。" + +#, php-format +msgid "Click %shere%s to return to the %s details page." +msgstr "點選 %s此處%s 以回到 %s 的詳細資訊頁面。" + msgid "Service Unavailable" msgstr "服務不可用" @@ -875,6 +889,9 @@ msgstr "不活躍自" msgid "Active" msgstr "活躍" +msgid "Registration date:" +msgstr "註冊日期:" + msgid "Last Login" msgstr "最後登入" @@ -891,6 +908,10 @@ msgstr "編輯此使用者的帳號" msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果您想要永久刪除此帳號,請點擊 %s這裡%s 。" +#, php-format +msgid "Click %shere%s for user details." +msgstr "點選 %s此處%s 來取得使用者的詳細資訊。" + msgid "required" msgstr "必填" @@ -1188,9 +1209,6 @@ msgstr "來源" msgid "Use this form to close the request for package base %s%s%s." msgstr "使用這個表單以關閉請求套件基礎 %s%s%s 。" -msgid "Note" -msgstr "注意" - msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." From fb07307638a17b7e150c54405d2b6fb6a1e98508 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 15 Oct 2016 19:46:51 +0200 Subject: [PATCH 0269/1891] Release 4.4.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 7918a7f0..25d365a1 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Mon, 17 Oct 2016 14:45:27 +0200 Subject: [PATCH 0270/1891] Do not show current day if registration date is unknown The registration date field on the account details page currently defaults to the current day if the user's registration date is unknown. To avoid confusion, show "unknown" in these cases instead. Fixes FS#51405. Signed-off-by: Lukas Fleischer --- web/template/account_details.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/template/account_details.php b/web/template/account_details.php index b79685be..024bd9c3 100644 --- a/web/template/account_details.php +++ b/web/template/account_details.php @@ -61,7 +61,11 @@
    + + + + From 9581069f49fbc305be3a37c2b46db0a24ede0564 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 17 Oct 2016 15:12:00 +0200 Subject: [PATCH 0271/1891] aurweb/git: Add missing __init__.py file Signed-off-by: Lukas Fleischer --- aurweb/git/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 aurweb/git/__init__.py diff --git a/aurweb/git/__init__.py b/aurweb/git/__init__.py new file mode 100644 index 00000000..e69de29b From 85866796a40923708f6b868c32ddc2f2f4417d1d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 17 Oct 2016 15:01:45 +0200 Subject: [PATCH 0272/1891] Move configuration to /etc/aurweb/config Since d4fe77a (Reorganize Git interface scripts, 2016-10-08), the key components of the aurweb SSH interface are installed system-wide. Update the default configuration path to point to a central location. Signed-off-by: Lukas Fleischer --- .gitignore | 1 - INSTALL | 4 ++-- aurweb/config.py | 3 +-- upgrading/4.4.1.txt | 3 +++ web/lib/confparser.inc.php | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 upgrading/4.4.1.txt diff --git a/.gitignore b/.gitignore index 2cb5bdc3..f0e462de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -conf/config dummy-data.sql* po/*.mo po/*.po~ diff --git a/INSTALL b/INSTALL index 395915ae..95cac4cf 100644 --- a/INSTALL +++ b/INSTALL @@ -30,8 +30,8 @@ Setup on Arch Linux } } -3) Copy conf/config.proto to conf/config and adjust the configuration (pay - attention to disable_http_login, enable_maintenance and aur_location). +3) Copy conf/config.proto to /etc/aurweb/config and adjust the configuration + (pay attention to disable_http_login, enable_maintenance and aur_location). 4) Create a new MySQL database and a user and import the AUR SQL schema: diff --git a/aurweb/config.py b/aurweb/config.py index aac188b1..a52d9422 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -12,8 +12,7 @@ def _get_parser(): if 'AUR_CONFIG' in os.environ: path = os.environ.get('AUR_CONFIG') else: - relpath = "/../conf/config" - path = os.path.dirname(os.path.realpath(__file__)) + relpath + path = "/etc/aurweb/config" _parser.read(path) return _parser diff --git a/upgrading/4.4.1.txt b/upgrading/4.4.1.txt new file mode 100644 index 00000000..b06696e0 --- /dev/null +++ b/upgrading/4.4.1.txt @@ -0,0 +1,3 @@ +1. The default configuration file search path now points to /etc/aurweb/config. + Make sure you copy your aurweb configuration to the new location before + upgrading. diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php index 6368b869..789300e1 100644 --- a/web/lib/confparser.inc.php +++ b/web/lib/confparser.inc.php @@ -4,7 +4,7 @@ function config_load() { global $AUR_CONFIG; if (!isset($AUR_CONFIG)) { - $AUR_CONFIG = parse_ini_file("../../conf/config", true, INI_SCANNER_RAW); + $AUR_CONFIG = parse_ini_file("/etc/aurweb/config", true, INI_SCANNER_RAW); } } From 37188603b52a3dac23df229ada82c7da0c3d9c00 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 17 Oct 2016 15:20:29 +0200 Subject: [PATCH 0273/1891] Make maintenance scripts installable Add wrappers for the maintenance scripts to the setuptools configuration. Signed-off-by: Lukas Fleischer --- {scripts => aurweb/scripts}/__init__.py | 0 {scripts => aurweb/scripts}/aurblup.py | 0 {scripts => aurweb/scripts}/mkpkglists.py | 0 {scripts => aurweb/scripts}/notify.py | 0 {scripts => aurweb/scripts}/pkgmaint.py | 0 {scripts => aurweb/scripts}/popupdate.py | 0 {scripts => aurweb/scripts}/tuvotereminder.py | 0 setup.py | 6 ++++++ upgrading/4.4.1.txt | 3 +++ 9 files changed, 9 insertions(+) rename {scripts => aurweb/scripts}/__init__.py (100%) rename {scripts => aurweb/scripts}/aurblup.py (100%) rename {scripts => aurweb/scripts}/mkpkglists.py (100%) rename {scripts => aurweb/scripts}/notify.py (100%) rename {scripts => aurweb/scripts}/pkgmaint.py (100%) rename {scripts => aurweb/scripts}/popupdate.py (100%) rename {scripts => aurweb/scripts}/tuvotereminder.py (100%) diff --git a/scripts/__init__.py b/aurweb/scripts/__init__.py similarity index 100% rename from scripts/__init__.py rename to aurweb/scripts/__init__.py diff --git a/scripts/aurblup.py b/aurweb/scripts/aurblup.py similarity index 100% rename from scripts/aurblup.py rename to aurweb/scripts/aurblup.py diff --git a/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py similarity index 100% rename from scripts/mkpkglists.py rename to aurweb/scripts/mkpkglists.py diff --git a/scripts/notify.py b/aurweb/scripts/notify.py similarity index 100% rename from scripts/notify.py rename to aurweb/scripts/notify.py diff --git a/scripts/pkgmaint.py b/aurweb/scripts/pkgmaint.py similarity index 100% rename from scripts/pkgmaint.py rename to aurweb/scripts/pkgmaint.py diff --git a/scripts/popupdate.py b/aurweb/scripts/popupdate.py similarity index 100% rename from scripts/popupdate.py rename to aurweb/scripts/popupdate.py diff --git a/scripts/tuvotereminder.py b/aurweb/scripts/tuvotereminder.py similarity index 100% rename from scripts/tuvotereminder.py rename to aurweb/scripts/tuvotereminder.py diff --git a/setup.py b/setup.py index b64e71cb..99dbfedf 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,12 @@ setup( 'aurweb-git-auth = aurweb.git.auth:main', 'aurweb-git-serve = aurweb.git.serve:main', 'aurweb-git-update = aurweb.git.update:main', + 'aurweb-aurblup = aurweb.scripts.aurblup:main', + 'aurweb-mkpkglists = aurweb.scripts.mkpkglists:main', + 'aurweb-notify = aurweb.scripts.notify:main', + 'aurweb-pkgmaint = aurweb.scripts.pkgmaint:main', + 'aurweb-popupdate = aurweb.scripts.popupdate:main', + 'aurweb-tuvotereminder = aurweb.scripts.tuvotereminder:main', ], }, ) diff --git a/upgrading/4.4.1.txt b/upgrading/4.4.1.txt index b06696e0..726f9e2b 100644 --- a/upgrading/4.4.1.txt +++ b/upgrading/4.4.1.txt @@ -1,3 +1,6 @@ 1. The default configuration file search path now points to /etc/aurweb/config. Make sure you copy your aurweb configuration to the new location before upgrading. + +2. The maintenance scripts have been prefixed by "aurweb-" and can now be + installed using `python3 setup.py install`. From c3f464f50fb35ffb7825b90437bd912051a994ee Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 17 Oct 2016 15:32:06 +0200 Subject: [PATCH 0274/1891] Release 4.4.1 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 25d365a1..dcf5666e 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Wed, 9 Nov 2016 18:54:37 -0500 Subject: [PATCH 0275/1891] Remove all usage of UNIX_TIMESTAMP in web interface UNIX_TIMESTAMP is not part of the SQL standard. Instead, all usage in the web interface is changed to use PHP's time() function. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 12 ++++++------ web/lib/aur.inc.php | 4 ++-- web/lib/pkgbasefuncs.inc.php | 14 +++++++------- web/lib/pkgreqfuncs.inc.php | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 172b9621..6dcf91d1 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -543,7 +543,7 @@ function try_login() { $new_sid = new_sid(); $q = "INSERT INTO Sessions (UsersID, SessionID, LastUpdateTS)" - ." VALUES (" . $userID . ", '" . $new_sid . "', UNIX_TIMESTAMP())"; + ." VALUES (" . $userID . ", '" . $new_sid . "', " . strval(time()) . ")"; $result = $dbh->exec($q); /* Query will fail if $new_sid is not unique. */ @@ -560,7 +560,7 @@ function try_login() { return array('SID' => $new_sid, 'error' => $login_error); } - $q = "UPDATE Users SET LastLogin = UNIX_TIMESTAMP(), "; + $q = "UPDATE Users SET LastLogin = " . strval(time()) . ", "; $q.= "LastLoginIPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']) . " "; $q.= "WHERE ID = $userID"; $dbh->exec($q); @@ -638,7 +638,7 @@ function valid_username($user) { function open_user_proposals($user) { $dbh = DB::connect(); $q = "SELECT * FROM TU_VoteInfo WHERE User = " . $dbh->quote($user) . " "; - $q.= "AND End > UNIX_TIMESTAMP()"; + $q.= "AND End > " . strval(time()); $result = $dbh->query($q); return ($result->fetchColumn() ? true : false); @@ -665,7 +665,7 @@ function add_tu_proposal($agenda, $user, $votelength, $quorum, $submitteruid) { $q = "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End, Quorum, "; $q.= "SubmitterID, ActiveTUs) VALUES "; $q.= "(" . $dbh->quote($agenda) . ", " . $dbh->quote($user) . ", "; - $q.= "UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + " . $dbh->quote($votelength); + $q.= strval(time()) . ", " . strval(time()) . " + " . $dbh->quote($votelength); $q.= ", " . $dbh->quote($quorum) . ", " . $submitteruid . ", "; $q.= $active_tus . ")"; $result = $dbh->exec($q); @@ -978,7 +978,7 @@ function clear_expired_sessions() { $dbh = DB::connect(); $timeout = config_get_int('options', 'login_timeout'); - $q = "DELETE FROM Sessions WHERE LastUpdateTS < (UNIX_TIMESTAMP() - " . $timeout . ")"; + $q = "DELETE FROM Sessions WHERE LastUpdateTS < (" . strval(time()) . " - " . $timeout . ")"; $dbh->query($q); return; @@ -1086,7 +1086,7 @@ function last_votes_list() { $q = "SELECT UserID, MAX(VoteID) AS LastVote FROM TU_Votes, "; $q .= "TU_VoteInfo, Users WHERE TU_VoteInfo.ID = TU_Votes.VoteID AND "; - $q .= "TU_VoteInfo.End < UNIX_TIMESTAMP() AND "; + $q .= "TU_VoteInfo.End < " . strval(time()) . " AND "; $q .= "Users.ID = TU_Votes.UserID AND (Users.AccountTypeID = 2 OR Users.AccountTypeID = 4) "; $q .= "GROUP BY UserID ORDER BY LastVote DESC, UserName ASC"; $result = $dbh->query($q); diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 9015ae8f..67dd1c14 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -38,7 +38,7 @@ function check_sid() { # the visitor is logged in, try and update the session # $dbh = DB::connect(); - $q = "SELECT LastUpdateTS, UNIX_TIMESTAMP() FROM Sessions "; + $q = "SELECT LastUpdateTS, " . strval(time()) . " FROM Sessions "; $q.= "WHERE SessionID = " . $dbh->quote($_COOKIE["AURSID"]); $result = $dbh->query($q); $row = $result->fetch(PDO::FETCH_NUM); @@ -77,7 +77,7 @@ function check_sid() { # This keeps 'remembered' sessions from being # overwritten. if ($last_update < time() + $timeout) { - $q = "UPDATE Sessions SET LastUpdateTS = UNIX_TIMESTAMP() "; + $q = "UPDATE Sessions SET LastUpdateTS = " . strval(time()) . " "; $q.= "WHERE SessionID = " . $dbh->quote($_COOKIE["AURSID"]); $dbh->exec($q); } diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index b0827844..4f102040 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -98,7 +98,7 @@ function pkgbase_add_comment($base_id, $uid, $comment) { $q = "INSERT INTO PackageComments "; $q.= "(PackageBaseID, UsersID, Comments, CommentTS) VALUES ("; $q.= intval($base_id) . ", " . $uid . ", "; - $q.= $dbh->quote($comment) . ", UNIX_TIMESTAMP())"; + $q.= $dbh->quote($comment) . ", " . strval(time()) . ")"; $dbh->exec($q); $comment_id = $dbh->lastInsertId(); @@ -144,7 +144,7 @@ function pkgbase_pin_comment($unpin=false) { $dbh = DB::connect(); $q = "UPDATE PackageComments "; if (!$unpin) { - $q.= "SET PinnedTS = UNIX_TIMESTAMP() "; + $q.= "SET PinnedTS = " . strval(time()) . " "; } else { $q.= "SET PinnedTS = 0 "; } @@ -395,7 +395,7 @@ function pkgbase_flag($base_ids, $comment) { $dbh = DB::connect(); $q = "UPDATE PackageBases SET "; - $q.= "OutOfDateTS = UNIX_TIMESTAMP(), FlaggerUID = " . $uid . ", "; + $q.= "OutOfDateTS = " . strval(time()) . ", FlaggerUID = " . $uid . ", "; $q.= "FlaggerComment = " . $dbh->quote($comment) . " "; $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; $q.= "AND OutOfDateTS IS NULL"; @@ -749,12 +749,12 @@ function pkgbase_vote ($base_ids, $action=true) { $first = 0; $vote_ids = $pid; if ($action) { - $vote_clauses = "($uid, $pid, UNIX_TIMESTAMP())"; + $vote_clauses = "($uid, $pid, " . strval(time()) . ")"; } } else { $vote_ids .= ", $pid"; if ($action) { - $vote_clauses .= ", ($uid, $pid, UNIX_TIMESTAMP())"; + $vote_clauses .= ", ($uid, $pid, " . strval(time()) . ")"; } } } @@ -972,7 +972,7 @@ function pkgbase_delete_comment($undelete=false) { $q = "UPDATE PackageComments "; $q.= "SET DelUsersID = ".$uid.", "; - $q.= "DelTS = UNIX_TIMESTAMP() "; + $q.= "DelTS = " . strval(time()) . " "; $q.= "WHERE ID = ".intval($comment_id); $dbh->exec($q); return array(true, __("Comment has been deleted.")); @@ -1005,7 +1005,7 @@ function pkgbase_edit_comment($comment) { $q = "UPDATE PackageComments "; $q.= "SET EditedUsersID = ".$uid.", "; $q.= "Comments = ".$dbh->quote($comment).", "; - $q.= "EditedTS = UNIX_TIMESTAMP() "; + $q.= "EditedTS = " . strval(time()) . " "; $q.= "WHERE ID = ".intval($comment_id); $dbh->exec($q); return array(true, __("Comment has been edited.")); diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index 8ceac8df..e4556a3f 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -149,7 +149,7 @@ function pkgreq_file($ids, $type, $merge_into, $comments) { $q.= "UsersID, Comments, RequestTS) VALUES (" . $type_id . ", "; $q.= $base_id . ", " . $dbh->quote($pkgbase_name) . ", "; $q.= $dbh->quote($merge_into) . ", " . $uid . ", "; - $q.= $dbh->quote($comments) . ", UNIX_TIMESTAMP())"; + $q.= $dbh->quote($comments) . ", " . strval(time()) . ")"; $dbh->exec($q); $request_id = $dbh->lastInsertId(); From 6502518d4e190b92ce771389d437a001687950d0 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Wed, 9 Nov 2016 18:54:38 -0500 Subject: [PATCH 0276/1891] Fix DB.class.php to match config and include SQLite support In commit baf8a22 (git-interface: Support SQLite as database backend, 2016-08-03), conf/config.proto was changed so that dsn_prefix was changed to backend and this fixes this in web/lib/DB.class.php. Since SQLite's dsn is different, this adds a check of which backend is desired and will quit if MySQL or SQLite are not the backend selected. SQLite2 may be supported, but is untested and will trigger an error if used. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/lib/DB.class.php | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/web/lib/DB.class.php b/web/lib/DB.class.php index b538e0d3..dfdbbf96 100644 --- a/web/lib/DB.class.php +++ b/web/lib/DB.class.php @@ -17,20 +17,30 @@ class DB { public static function connect() { if (self::$dbh === null) { try { - $dsn_prefix = config_get('database', 'dsn_prefix'); + $backend = config_get('database', 'backend'); $host = config_get('database', 'host'); $socket = config_get('database', 'socket'); $name = config_get('database', 'name'); $user = config_get('database', 'user'); $password = config_get('database', 'password'); - $dsn = $dsn_prefix . - ':host=' . $host . - ';unix_socket=' . $socket . - ';dbname=' . $name; + if ($backend == "mysql") { + $dsn = $backend . + ':host=' . $host . + ';unix_socket=' . $socket . + ';dbname=' . $name; + + self::$dbh = new PDO($dsn, $user, $password); + self::$dbh->exec("SET NAMES 'utf8' COLLATE 'utf8_general_ci';"); + } else if ($backend == "sqlite") { + $dsn = $backend . + ":" . $name; + + self::$dbh = new PDO($dsn, null, null); + } else { + die("Error - " . $backend . " is not supported by aurweb"); + } - self::$dbh = new PDO($dsn, $user, $password); - self::$dbh->exec("SET NAMES 'utf8' COLLATE 'utf8_general_ci';"); } catch (PDOException $e) { die('Error - Could not connect to AUR database'); } From ddbffcc4d57c5d27022e3f2a603c0b559bf6b05c Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Wed, 9 Nov 2016 21:48:30 -0500 Subject: [PATCH 0277/1891] Remove extraneous quote in translator.inc.php The quote is a leftover of legacy code and was meant to be removed by commit e171f6f (Migrate all DB code to use PDO, 2012-08-08). Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/lib/translator.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/translator.inc.php b/web/lib/translator.inc.php index d53bd530..58648c41 100644 --- a/web/lib/translator.inc.php +++ b/web/lib/translator.inc.php @@ -106,7 +106,7 @@ function set_lang() { $dbh = DB::connect(); $q = "SELECT LangPreference FROM Users, Sessions "; $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = '"; + $q.= "AND Sessions.SessionID = "; $q.= $dbh->quote($_COOKIE["AURSID"]); $result = $dbh->query($q); From d987d756b0cf9239425244b26b53d1756c384c4f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Nov 2016 15:33:02 +0100 Subject: [PATCH 0278/1891] test/setup.sh: Fix script paths The scripts were moved to aurweb/scripts/ in commit 3718860 (Make maintenance scripts installable, 2016-10-17). Update the paths in the test suite accordingly. Signed-off-by: Lukas Fleischer --- test/setup.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/setup.sh b/test/setup.sh index d02d2981..26873e8d 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -11,11 +11,11 @@ export PYTHONPATH GIT_AUTH="$TOPLEVEL/aurweb/git/auth.py" GIT_SERVE="$TOPLEVEL/aurweb/git/serve.py" GIT_UPDATE="$TOPLEVEL/aurweb/git/update.py" -MKPKGLISTS="$TOPLEVEL/scripts/mkpkglists.py" -TUVOTEREMINDER="$TOPLEVEL/scripts/tuvotereminder.py" -PKGMAINT="$TOPLEVEL/scripts/pkgmaint.py" -AURBLUP="$TOPLEVEL/scripts/aurblup.py" -NOTIFY="$TOPLEVEL/scripts/notify.py" +MKPKGLISTS="$TOPLEVEL/aurweb/scripts/mkpkglists.py" +TUVOTEREMINDER="$TOPLEVEL/aurweb/scripts/tuvotereminder.py" +PKGMAINT="$TOPLEVEL/aurweb/scripts/pkgmaint.py" +AURBLUP="$TOPLEVEL/aurweb/scripts/aurblup.py" +NOTIFY="$TOPLEVEL/aurweb/scripts/notify.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF From e9ac4b9b9ee797a1a0c09e9c3b14ae7d498ea8ea Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Nov 2016 15:35:37 +0100 Subject: [PATCH 0279/1891] Send out-of-date notifications to co-maintainers Currently, only package maintainers receive out-of-date notifications for their packages. Add package base co-maintainers to the list of recipients for out-of-date notifications. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index ddd6e49b..8fdfeb9a 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -73,12 +73,15 @@ def get_user_email(conn, uid): return cur.fetchone()[0] -def get_maintainer_email(conn, pkgbase_id): - cur = conn.execute('SELECT Users.Email FROM Users ' + +def get_flag_recipients(conn, pkgbase_id): + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'LEFT JOIN PackageComaintainers ' + + 'ON PackageComaintainers.UsersID = Users.ID ' + 'INNER JOIN PackageBases ' + - 'ON PackageBases.MaintainerUID = Users.ID WHERE ' + - 'PackageBases.ID = ?', [pkgbase_id]) - return cur.fetchone()[0] + 'ON PackageBases.MaintainerUID = Users.ID OR ' + + 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + + 'WHERE PackageBases.ID = ?', [pkgbase_id]) + return [row[0] for row in cur.fetchall()] def get_recipients(conn, pkgbase_id, uid): @@ -247,7 +250,7 @@ def update(conn, uid, pkgbase_id): def flag(conn, uid, pkgbase_id): user = username_from_id(conn, uid) pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = [get_maintainer_email(conn, pkgbase_id)] + to = get_flag_recipients(conn, pkgbase_id) text = get_flagger_comment(conn, pkgbase_id) user_uri = aur_location + '/account/' + user + '/' From 9dd0d92d61462860089f479e0f0f6cd957a3ec04 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Nov 2016 15:39:55 +0100 Subject: [PATCH 0280/1891] Add tests for out-of-date notifications Make sure that out-of-date notifications are sent to package base maintainers as well as co-maintainers. Signed-off-by: Lukas Fleischer --- test/t2500-notify.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 test/t2500-notify.sh diff --git a/test/t2500-notify.sh b/test/t2500-notify.sh new file mode 100755 index 00000000..1b209458 --- /dev/null +++ b/test/t2500-notify.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +test_description='notify tests' + +. ./setup.sh + +test_expect_success 'Test out-of-date notifications.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (1, "foobar", 1, 0, 0); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (2, "foobar2", 2, 0, 0); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (3, "foobar3", NULL, 0, 0); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (4, "foobar4", 1, 0, 0); + INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1, 2, 1); + INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1, 4, 2); + INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (2, 3, 1); + INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (2, 5, 2); + INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (3, 4, 1); + EOD + >sendmail.out && + "$NOTIFY" flag 1 1 && + cat <<-EOD >expected && + Subject: AUR Out-of-date Notification for foobar + To: tu@localhost + Subject: AUR Out-of-date Notification for foobar + To: user2@localhost + Subject: AUR Out-of-date Notification for foobar + To: user@localhost + EOD + grep "^\(Subject\|To\)" sendmail.out >sendmail.parts && + test_cmp sendmail.parts expected +' + +test_done From fd36125a21ad6e4d665e1b2f4db784b073846d94 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 12 Dec 2016 19:41:16 +0100 Subject: [PATCH 0281/1891] notify: Avoid EXCEPT in SQL statement Do not use the EXCEPT clause which is unsupported in MySQL. Instead, use a subquery which is standard-compliant and makes the query easier to read at the same time. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 8fdfeb9a..69164fba 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -139,12 +139,10 @@ def get_request_recipients(conn, reqid): def get_tu_vote_reminder_recipients(conn, vote_id): - cur = conn.execute('SELECT Users.Email FROM Users ' + - 'WHERE AccountTypeID = 2 ' + - 'EXCEPT SELECT Users.Email FROM Users ' + - 'INNER JOIN TU_Votes ' + - 'ON TU_Votes.UserID = Users.ID ' + - 'WHERE TU_Votes.VoteID = ?', [vote_id]) + cur = conn.execute('SELECT Email FROM Users ' + + 'WHERE AccountTypeID = 2 AND ID NOT IN ' + + '(SELECT UserID FROM TU_Votes ' + + 'WHERE TU_Votes.VoteID = ?)', [vote_id]) return [row[0] for row in cur.fetchall()] From ba89ad9b9f8b141683d7e661d951ae304cedf692 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Dec 2016 18:02:55 +0100 Subject: [PATCH 0282/1891] t1200: Test maintenance mode Add a test case to ensure that enabling the maintenance mode disables the SSH interface. Signed-off-by: Lukas Fleischer --- test/t1200-git-serve.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index 5054ce36..6fa6f957 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -20,6 +20,17 @@ test_expect_success 'Test help.' ' IFS=$save_IFS ' +test_expect_success 'Test maintenance mode.' ' + mv config config.old && + sed "s/^\(enable-maintenance = \)0$/\\11/" config.old >config && + SSH_ORIGINAL_COMMAND=help test_must_fail "$GIT_SERVE" 2>actual && + cat >expected <<-EOF && + The AUR is down due to maintenance. We will be back soon. + EOF + test_cmp expected actual && + mv config.old config +' + test_expect_success 'Test setup-repo and list-repos.' ' SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user \ "$GIT_SERVE" 2>&1 && From e0d94f54c32f39f3709694b81f55a8ec46d11d5a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 6 Dec 2016 20:20:26 +0100 Subject: [PATCH 0283/1891] git-serve: Add support for (un-)flagging packages Add support for flagging or unflagging packages from the SSH interface. The syntax is `flag ` resp. `unflag `. Signed-off-by: Lukas Fleischer --- aurweb/git/serve.py | 70 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 476aea86..08c65417 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -269,6 +269,52 @@ def pkgbase_disown(pkgbase, user, privileged): conn.close() +def pkgbase_flag(pkgbase, user, comment): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + + conn = aurweb.db.Connection() + + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + if userid == 0: + die('{:s}: unknown user: {:s}'.format(action, user)) + + now = int(time.time()) + conn.execute("UPDATE PackageBases SET " + + "OutOfDateTS = ?, FlaggerUID = ?, FlaggerComment = ? " + + "WHERE ID = ? AND OutOfDateTS IS NULL", + [now, userid, comment, pkgbase_id]) + + conn.commit() + + subprocess.Popen((notify_cmd, 'flag', str(userid), str(pkgbase_id))) + + +def pkgbase_unflag(pkgbase, user): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + + conn = aurweb.db.Connection() + + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + if userid == 0: + die('{:s}: unknown user: {:s}'.format(action, user)) + + if user in pkgbase_get_comaintainers(pkgbase): + conn.execute("UPDATE PackageBases SET OutOfDateTS = NULL " + + "WHERE ID = ?", [pkgbase_id]) + else: + conn.execute("UPDATE PackageBases SET OutOfDateTS = NULL " + + "WHERE ID = ? AND (MaintainerUID = ? OR FlaggerUID = ?)", + [pkgbase_id, userid, userid]) + + conn.commit() + + def pkgbase_set_keywords(pkgbase, keywords): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: @@ -422,6 +468,28 @@ def main(): pkgbase = cmdargv[1] pkgbase_disown(pkgbase, user, privileged) + elif action == 'flag': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) < 3: + die_with_help("{:s}: missing comment".format(action)) + if len(cmdargv) > 3: + die_with_help("{:s}: too many arguments".format(action)) + + pkgbase = cmdargv[1] + comment = cmdargv[2] + if len(comment) < 3: + die_with_help("{:s}: comment is too short".format(action)) + + pkgbase_flag(pkgbase, user, comment) + elif action == 'unflag': + if len(cmdargv) < 2: + die_with_help("{:s}: missing repository name".format(action)) + if len(cmdargv) > 2: + die_with_help("{:s}: too many arguments".format(action)) + + pkgbase = cmdargv[1] + pkgbase_unflag(pkgbase, user) elif action == 'set-comaintainers': if len(cmdargv) < 2: die_with_help("{:s}: missing repository name".format(action)) @@ -433,12 +501,14 @@ def main(): cmds = { "adopt ": "Adopt a package base.", "disown ": "Disown a package base.", + "flag ": "Flag a package base out-of-date.", "help": "Show this help message and exit.", "list-repos": "List all your repositories.", "restore ": "Restore a deleted package base.", "set-comaintainers [...]": "Set package base co-maintainers.", "set-keywords [...]": "Change package base keywords.", "setup-repo ": "Create a repository (deprecated).", + "unflag ": "Remove out-of-date flag from a package base.", "git-receive-pack": "Internal command used with Git.", "git-upload-pack": "Internal command used with Git.", } From 6d8edafe778809698246019c165b7c20b1e0afdf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 7 Dec 2016 08:58:34 +0100 Subject: [PATCH 0284/1891] t1200: Add tests for flag/unflag Signed-off-by: Lukas Fleischer --- test/t1200-git-serve.sh | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index 6fa6f957..d422c480 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -351,4 +351,67 @@ test_expect_success "Check whether package requests are closed when disowning." test_cmp actual expected ' +test_expect_success "Flag a package base out-of-date." ' + SSH_ORIGINAL_COMMAND="flag foobar Because." AUR_USER=user2 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 1|Because. + EOF + echo "SELECT OutOfDateTS IS NOT NULL, FlaggerComment FROM PackageBases WHERE ID = 3;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Unflag a package base as flagger." ' + SSH_ORIGINAL_COMMAND="unflag foobar" AUR_USER=user2 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 0|Because. + EOF + echo "SELECT OutOfDateTS IS NOT NULL, FlaggerComment FROM PackageBases WHERE ID = 3;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Unflag a package base as maintainer." ' + SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="flag foobar Because." AUR_USER=user2 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="unflag foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 0|Because. + EOF + echo "SELECT OutOfDateTS IS NOT NULL, FlaggerComment FROM PackageBases WHERE ID = 3;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Unflag a package base as random user." ' + SSH_ORIGINAL_COMMAND="flag foobar Because." AUR_USER=user2 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="unflag foobar" AUR_USER=user3 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 1|Because. + EOF + echo "SELECT OutOfDateTS IS NOT NULL, FlaggerComment FROM PackageBases WHERE ID = 3;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Flag using a comment which is too short." ' + SSH_ORIGINAL_COMMAND="unflag foobar" AUR_USER=user2 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + SSH_ORIGINAL_COMMAND="flag foobar xx" AUR_USER=user2 AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 0|Because. + EOF + echo "SELECT OutOfDateTS IS NOT NULL, FlaggerComment FROM PackageBases WHERE ID = 3;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + test_done From 8914a41db938194efc021f842c89d47ff6b522c9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 20 Dec 2016 17:56:09 +0100 Subject: [PATCH 0285/1891] git-serve: Use Python exceptions for error handling Make it easier to reuse the helper functions provided by git-serve from another Python script by throwing exceptions instead of terminating the program on errors. Signed-off-by: Lukas Fleischer --- aurweb/exceptions.py | 53 +++++++++++++++ aurweb/git/serve.py | 157 +++++++++++++++++++++---------------------- 2 files changed, 131 insertions(+), 79 deletions(-) create mode 100644 aurweb/exceptions.py diff --git a/aurweb/exceptions.py b/aurweb/exceptions.py new file mode 100644 index 00000000..5922b2df --- /dev/null +++ b/aurweb/exceptions.py @@ -0,0 +1,53 @@ +class AurwebException(Exception): + pass + + +class MaintenanceException(AurwebException): + pass + + +class PermissionDeniedException(AurwebException): + def __init__(self, user): + msg = 'permission denied: {:s}'.format(user) + super(PermissionDeniedException, self).__init__(msg) + + +class InvalidUserException(AurwebException): + def __init__(self, user): + msg = 'unknown user: {:s}'.format(user) + super(InvalidUserException, self).__init__(msg) + + +class InvalidPackageBaseException(AurwebException): + def __init__(self, pkgbase): + msg = 'package base not found: {:s}'.format(pkgbase) + super(InvalidPackageBaseException, self).__init__(msg) + + +class InvalidRepositoryNameException(AurwebException): + def __init__(self, pkgbase): + msg = 'invalid repository name: {:s}'.format(pkgbase) + super(InvalidRepositoryNameException, self).__init__(msg) + + +class PackageBaseExistsException(AurwebException): + def __init__(self, pkgbase): + msg = 'package base already exists: {:s}'.format(pkgbase) + super(PackageBaseExistsException, self).__init__(msg) + + +class InvalidReasonException(AurwebException): + def __init__(self, reason): + msg = 'invalid reason: {:s}'.format(reason) + super(InvalidReasonException, self).__init__(msg) + + +class InvalidCommentException(AurwebException): + def __init__(self, comment): + msg = 'comment is too short: {:s}'.format(comment) + super(InvalidCommentException, self).__init__(msg) + + +class InvalidArgumentsException(AurwebException): + def __init__(self, msg): + super(InvalidArgumentsException, self).__init__(msg) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 08c65417..e33fbeb4 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -9,6 +9,7 @@ import time import aurweb.config import aurweb.db +import aurweb.exceptions notify_cmd = aurweb.config.get('notifications', 'notify-cmd') @@ -40,7 +41,7 @@ def list_repos(user): cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) cur = conn.execute("SELECT Name, PackagerUID FROM PackageBases " + "WHERE MaintainerUID = ?", [userid]) @@ -51,16 +52,16 @@ def list_repos(user): def create_pkgbase(pkgbase, user): if not re.match(repo_regex, pkgbase): - die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase) if pkgbase_exists(pkgbase): - die('{:s}: package base already exists: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.PackageBaseExistsException(pkgbase) conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) now = int(time.time()) cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " + @@ -79,19 +80,19 @@ def create_pkgbase(pkgbase, user): def pkgbase_adopt(pkgbase, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: - die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM PackageBases WHERE ID = ? AND " + "MaintainerUID IS NULL", [pkgbase_id]) if not privileged and not cur.fetchone(): - die('{:s}: permission denied: {:s}'.format(action, user)) + raise aurweb.exceptions.PermissionDeniedException(user) cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ?", [userid, pkgbase_id]) @@ -127,10 +128,10 @@ def pkgbase_get_comaintainers(pkgbase): def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: - die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) if not privileged and not pkgbase_has_full_access(pkgbase, user): - die('{:s}: permission denied: {:s}'.format(action, user)) + raise aurweb.exceptions.PermissionDeniedException(user) conn = aurweb.db.Connection() @@ -142,7 +143,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged): [olduser]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) uids_old.add(userid) uids_new = set() @@ -151,7 +152,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged): [newuser]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) uids_new.add(userid) uids_add = uids_new - uids_old @@ -196,10 +197,10 @@ def pkgreq_by_pkgbase(pkgbase_id, reqtype): return [row[0] for row in cur.fetchall()] -def pkgreq_close(reqid, reason, comments, autoclose=False): +def pkgreq_close(reqid, user, reason, comments, autoclose=False): statusmap = {'accepted': 2, 'rejected': 3} if reason not in statusmap: - die('{:s}: invalid reason: {:s}'.format(action, reason)) + raise aurweb.exceptions.InvalidReasonException(reason) status = statusmap[reason] conn = aurweb.db.Connection() @@ -210,7 +211,7 @@ def pkgreq_close(reqid, reason, comments, autoclose=False): cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) conn.execute("UPDATE PackageRequests SET Status = ?, ClosureComment = ? " + "WHERE ID = ?", [status, comments, reqid]) @@ -224,18 +225,18 @@ def pkgreq_close(reqid, reason, comments, autoclose=False): def pkgbase_disown(pkgbase, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: - die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) initialized_by_owner = pkgbase_has_full_access(pkgbase, user) if not privileged and not initialized_by_owner: - die('{:s}: permission denied: {:s}'.format(action, user)) + raise aurweb.exceptions.PermissionDeniedException(user) # TODO: Support disowning package bases via package request. # Scan through pending orphan requests and close them. comment = 'The user {:s} disowned the package.'.format(user) for reqid in pkgreq_by_pkgbase(pkgbase_id, 'orphan'): - pkgreq_close(reqid, 'accepted', comment, True) + pkgreq_close(reqid, user, 'accepted', comment, True) comaintainers = [] new_maintainer_userid = None @@ -262,7 +263,7 @@ def pkgbase_disown(pkgbase, user, privileged): cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) subprocess.Popen((notify_cmd, 'disown', str(pkgbase_id), str(userid))) @@ -272,14 +273,16 @@ def pkgbase_disown(pkgbase, user, privileged): def pkgbase_flag(pkgbase, user, comment): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: - die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) + if len(comment) < 3: + raise aurweb.exceptions.InvalidCommentException(comment) conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) now = int(time.time()) conn.execute("UPDATE PackageBases SET " + @@ -295,14 +298,14 @@ def pkgbase_flag(pkgbase, user, comment): def pkgbase_unflag(pkgbase, user): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: - die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) conn = aurweb.db.Connection() cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - die('{:s}: unknown user: {:s}'.format(action, user)) + raise aurweb.exceptions.InvalidUserException(user) if user in pkgbase_get_comaintainers(pkgbase): conn.execute("UPDATE PackageBases SET OutOfDateTS = NULL " + @@ -318,7 +321,7 @@ def pkgbase_unflag(pkgbase, user): def pkgbase_set_keywords(pkgbase, keywords): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: - die('{:s}: package base not found: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) conn = aurweb.db.Connection() @@ -377,29 +380,33 @@ def usage(cmds): exit(0) -def main(): - user = os.environ.get('AUR_USER') - privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1') - ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND') - ssh_client = os.environ.get('SSH_CLIENT') +def checkarg_atleast(cmdargv, *argdesc): + if len(cmdargv) - 1 < len(argdesc): + msg = 'missing {:s}'.format(argdesc[len(cmdargv) - 1]) + raise aurweb.exceptions.InvalidArgumentsException(msg) - if not ssh_cmd: - die_with_help("Interactive shell is disabled.") - cmdargv = shlex.split(ssh_cmd) - action = cmdargv[0] - remote_addr = ssh_client.split(' ')[0] if ssh_client else None +def checkarg_atmost(cmdargv, *argdesc): + if len(cmdargv) - 1 > len(argdesc): + raise aurweb.exceptions.InvalidArgumentsException('too many arguments') + + +def checkarg(cmdargv, *argdesc): + checkarg_atleast(cmdargv, *argdesc) + checkarg_atmost(cmdargv, *argdesc) + + +def serve(action, cmdargv, user, privileged, remote_addr): if enable_maintenance: if remote_addr not in maintenance_exc: - die("The AUR is down due to maintenance. We will be back soon.") + raise aurweb.exceptions.MaintenanceException if action == 'git' and cmdargv[1] in ('upload-pack', 'receive-pack'): action = action + '-' + cmdargv[1] del cmdargv[1] if action == 'git-upload-pack' or action == 'git-receive-pack': - if len(cmdargv) < 2: - die_with_help("{:s}: missing path".format(action)) + checkarg(cmdargv, 'path') path = cmdargv[1].rstrip('/') if not path.startswith('/'): @@ -408,11 +415,11 @@ def main(): path = path + '.git' pkgbase = path[1:-4] if not re.match(repo_regex, pkgbase): - die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) + raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase) if action == 'git-receive-pack' and pkgbase_exists(pkgbase): if not privileged and not pkgbase_has_write_access(pkgbase, user): - die('{:s}: permission denied: {:s}'.format(action, user)) + raise aurweb.exceptions.PermissionDeniedException(user) os.environ["AUR_USER"] = user os.environ["AUR_PKGBASE"] = pkgbase @@ -420,79 +427,48 @@ def main(): cmd = action + " '" + repo_path + "'" os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd) elif action == 'set-keywords': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) + checkarg(cmdargv, 'repository name') pkgbase_set_keywords(cmdargv[1], cmdargv[2:]) elif action == 'list-repos': - if len(cmdargv) > 1: - die_with_help("{:s}: too many arguments".format(action)) + checkarg(cmdargv) list_repos(user) elif action == 'setup-repo': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + checkarg(cmdargv, 'repository name') warn('{:s} is deprecated. ' 'Use `git push` to create new repositories.'.format(action)) create_pkgbase(cmdargv[1], user) elif action == 'restore': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + checkarg(cmdargv, 'repository name') pkgbase = cmdargv[1] - if not re.match(repo_regex, pkgbase): - die('{:s}: invalid repository name: {:s}'.format(action, pkgbase)) - - if pkgbase_exists(pkgbase): - die('{:s}: package base exists: {:s}'.format(action, pkgbase)) create_pkgbase(pkgbase, user) os.environ["AUR_USER"] = user os.environ["AUR_PKGBASE"] = pkgbase os.execl(git_update_cmd, git_update_cmd, 'restore') elif action == 'adopt': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + checkarg(cmdargv, 'repository name') pkgbase = cmdargv[1] pkgbase_adopt(pkgbase, user, privileged) elif action == 'disown': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + checkarg(cmdargv, 'repository name') pkgbase = cmdargv[1] pkgbase_disown(pkgbase, user, privileged) elif action == 'flag': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) < 3: - die_with_help("{:s}: missing comment".format(action)) - if len(cmdargv) > 3: - die_with_help("{:s}: too many arguments".format(action)) + checkarg(cmdargv, 'repository name', 'comment') pkgbase = cmdargv[1] comment = cmdargv[2] - if len(comment) < 3: - die_with_help("{:s}: comment is too short".format(action)) - pkgbase_flag(pkgbase, user, comment) elif action == 'unflag': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) - if len(cmdargv) > 2: - die_with_help("{:s}: too many arguments".format(action)) + checkarg(cmdargv, 'repository name') pkgbase = cmdargv[1] pkgbase_unflag(pkgbase, user) elif action == 'set-comaintainers': - if len(cmdargv) < 2: - die_with_help("{:s}: missing repository name".format(action)) + checkarg_atleast(cmdargv, 'repository name') pkgbase = cmdargv[1] userlist = cmdargv[2:] @@ -514,7 +490,30 @@ def main(): } usage(cmds) else: - die_with_help("invalid command: {:s}".format(action)) + msg = 'invalid command: {:s}'.format(action) + raise aurweb.exceptions.InvalidArgumentsException(msg) + + +def main(): + user = os.environ.get('AUR_USER') + privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1') + ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND') + ssh_client = os.environ.get('SSH_CLIENT') + + if not ssh_cmd: + die_with_help("Interactive shell is disabled.") + cmdargv = shlex.split(ssh_cmd) + action = cmdargv[0] + remote_addr = ssh_client.split(' ')[0] if ssh_client else None + + try: + serve(action, cmdargv, user, privileged, remote_addr) + except aurweb.exceptions.MaintenanceException: + die("The AUR is down due to maintenance. We will be back soon.") + except aurweb.exceptions.InvalidArgumentsException as e: + die_with_help('{:s}: {}'.format(action, e)) + except aurweb.exceptions.AurwebException as e: + die('{:s}: {}'.format(action, e)) if __name__ == '__main__': From eb4ba5cfdbaab8d649406571f6c0c89869303d20 Mon Sep 17 00:00:00 2001 From: Alex Muller Date: Tue, 3 Jan 2017 23:03:35 +0000 Subject: [PATCH 0286/1891] Increase minimum password length to 8 characters There are 95 printable ASCII characters which with a minimum length of 4 gives 95^4 or 81 million possible passwords. Increasing the minimum length to 8 increases the number of possible passwords by a factor of about 10^7. Relates to FS#52297. Signed-off-by: Alex Muller Signed-off-by: Lukas Fleischer --- conf/config.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.proto b/conf/config.proto index 96fad807..63e24583 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -9,7 +9,7 @@ password = aur [options] username_min_len = 3 username_max_len = 16 -passwd_min_len = 4 +passwd_min_len = 8 default_lang = en sql_debug = 0 max_sessions_per_user = 8 From ecfa54e4928b61aeeedb43b341afa0bd802dea09 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 9 Jan 2017 01:14:29 +0100 Subject: [PATCH 0287/1891] INSTALL: Refer to the AUR backend as aurweb Signed-off-by: Lukas Fleischer --- INSTALL | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/INSTALL b/INSTALL index 95cac4cf..bad80de3 100644 --- a/INSTALL +++ b/INSTALL @@ -1,7 +1,7 @@ Setup on Arch Linux =================== -1) Clone the AUR project: +1) Clone the aurweb project: $ cd /srv/http/ $ git clone git://git.archlinux.org/aurweb.git @@ -33,7 +33,7 @@ Setup on Arch Linux 3) Copy conf/config.proto to /etc/aurweb/config and adjust the configuration (pay attention to disable_http_login, enable_maintenance and aur_location). -4) Create a new MySQL database and a user and import the AUR SQL schema: +4) Create a new MySQL database and a user and import the aurweb SQL schema: $ mysql -uaur -p AUR Date: Tue, 17 Jan 2017 08:49:41 +0100 Subject: [PATCH 0288/1891] Document garbage collection settings for Git Add a note to the Git/SSH interface documentation that we recommend to disable automatic garbage collection and use a maintenance script to cleanup and optimize the Git repository instead. Also, add a reference to the Git/SSH interface documentation to the Git repository setup instructions in INSTALL. Signed-off-by: Lukas Fleischer --- INSTALL | 3 +++ doc/git-interface.txt | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/INSTALL b/INSTALL index bad80de3..a472b277 100644 --- a/INSTALL +++ b/INSTALL @@ -57,6 +57,9 @@ Setup on Arch Linux # ln -s /usr/local/bin/aurweb-git-update hooks/update # chown -R aur . + It is recommended to read doc/git-interface.txt for more information on the + administration of the package Git repository. + 8) Configure sshd(8) for the AUR. Add the following lines at the end of your sshd_config(5) and restart the sshd. Note that OpenSSH 6.9 or newer is needed! diff --git a/doc/git-interface.txt b/doc/git-interface.txt index 14ff0c5d..475fda66 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -81,8 +81,8 @@ the GIT_NAMESPACE environment variable accordingly before forwarding a request. An example configuration for nginx and fcgiwrap can be found in the INSTALL instructions in the top-level directory. -Further Configuration ---------------------- +Further Configuration and Administration +---------------------------------------- When using Git namespaces, Git advertises refs outside the current namespace as so-called "have" lines. This is normally used to reduce traffic but it has the @@ -94,3 +94,10 @@ In order to omit these advertisements, one can add the strings "^refs/", "!refs/" and "!HEAD" to the transfer.hideRefs configuration setting. Note that the order of these patterns is important ("^refs/" must come first) and that Git 2.7 or newer is required for them to work. + +Since garbage collection always affects all objects (from all namespaces), it +is also recommended to disable automatic garbage collection by setting +receive.autogc to false. Remember to periodically run `git gc` manually or +setup a maintenance script which initiates the garbage collection if you follow +this advice. For gc.pruneExpire, we recommend "3.months.ago", such that commits +that became unreachable by TU intervention are kept for a while. From 608c48309084e4048d8226c3f7e363b240248040 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Fri, 20 Jan 2017 01:16:39 -0500 Subject: [PATCH 0289/1891] Add user set timezones Currently, aurweb displays all dates and times in UTC time. This patch adds a capability for each logged in user to set their preferred timezone. Implements FS#48729. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- conf/config.proto | 1 + schema/aur-schema.sql | 1 + upgrading/4.5.0.txt | 5 +++ web/html/account.php | 3 ++ web/html/register.php | 2 + web/html/voters.php | 2 +- web/lib/acctfuncs.inc.php | 27 ++++++++++--- web/lib/aur.inc.php | 3 ++ web/lib/pkgreqfuncs.inc.php | 2 +- web/lib/timezone.inc.php | 60 ++++++++++++++++++++++++++++ web/template/account_edit_form.php | 15 +++++++ web/template/flag_comment.php | 2 +- web/template/pkg_comments.php | 6 +-- web/template/pkg_details.php | 6 +-- web/template/pkgbase_details.php | 6 +-- web/template/pkgreq_results.php | 2 +- web/template/stats/updates_table.php | 2 +- web/template/tu_details.php | 4 +- web/template/tu_list.php | 4 +- 19 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 upgrading/4.5.0.txt create mode 100644 web/lib/timezone.inc.php diff --git a/conf/config.proto b/conf/config.proto index 63e24583..431697e2 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -11,6 +11,7 @@ username_min_len = 3 username_max_len = 16 passwd_min_len = 8 default_lang = en +default_timezone = UTC sql_debug = 0 max_sessions_per_user = 8 login_timeout = 7200 diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 30209bd8..13e3fd94 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -32,6 +32,7 @@ CREATE TABLE Users ( ResetKey CHAR(32) NOT NULL DEFAULT '', RealName VARCHAR(64) NOT NULL DEFAULT '', LangPreference VARCHAR(6) NOT NULL DEFAULT 'en', + Timezone VARCHAR(32) NOT NULL DEFAULT 'UTC', Homepage TEXT NULL DEFAULT NULL, IRCNick VARCHAR(32) NOT NULL DEFAULT '', PGPKey VARCHAR(40) NULL DEFAULT NULL, diff --git a/upgrading/4.5.0.txt b/upgrading/4.5.0.txt new file mode 100644 index 00000000..6c4ce807 --- /dev/null +++ b/upgrading/4.5.0.txt @@ -0,0 +1,5 @@ +1. Add Timezone column to Users: + +--- +ALTER TABLE Users ADD COLUMN Timezone VARCHAR(32) NOT NULL DEFAULT 'UTC'; +--- \ No newline at end of file diff --git a/web/html/account.php b/web/html/account.php index 2892f046..91e57038 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -34,6 +34,7 @@ if ($action == "UpdateAccount") { in_request("U"), in_request("T"), in_request("S"), in_request("E"), in_request("H"), in_request("P"), in_request("C"), in_request("R"), in_request("L"), + in_request("TZ"), in_request("HP"), in_request("I"), in_request("K"), in_request("PK"), in_request("J"), in_request("CN"), in_request("UN"), in_request("ON"), in_request("ID"), @@ -89,6 +90,7 @@ if (isset($_COOKIE["AURSID"])) { "", $row["RealName"], $row["LangPreference"], + $row["Timezone"], $row["Homepage"], $row["IRCNick"], $row["PGPKey"], @@ -141,6 +143,7 @@ if (isset($_COOKIE["AURSID"])) { in_request("C"), in_request("R"), in_request("L"), + in_request("TZ"), in_request("HP"), in_request("I"), in_request("K"), diff --git a/web/html/register.php b/web/html/register.php index 6c6d52e6..843fea97 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -31,6 +31,7 @@ if (in_request("Action") == "NewAccount") { '', in_request("R"), in_request("L"), + in_request("TZ"), in_request("HP"), in_request("I"), in_request("K"), @@ -53,6 +54,7 @@ if (in_request("Action") == "NewAccount") { '', in_request("R"), in_request("L"), + in_request("TZ"), in_request("HP"), in_request("I"), in_request("K"), diff --git a/web/html/voters.php b/web/html/voters.php index 8833be1e..997186d8 100644 --- a/web/html/voters.php +++ b/web/html/voters.php @@ -20,7 +20,7 @@ if (has_credential(CRED_PKGBASE_LIST_VOTERS)):
  • 0): ?> - () + ()
  • diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 6dcf91d1..b7288143 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -1,5 +1,4 @@ quote($salt); $R = $dbh->quote($R); $L = $dbh->quote($L); + $TZ = $dbh->quote($TZ); $HP = $dbh->quote($HP); $I = $dbh->quote($I); $K = $dbh->quote(str_replace(" ", "", $K)); $q = "INSERT INTO Users (AccountTypeID, Suspended, "; $q.= "InactivityTS, Username, Email, Passwd, Salt, "; - $q.= "RealName, LangPreference, Homepage, IRCNick, PGPKey) "; - $q.= "VALUES (1, 0, 0, $U, $E, $P, $salt, $R, $L, "; + $q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) "; + $q.= "VALUES (1, 0, 0, $U, $E, $P, $salt, $R, $L, $TZ "; $q.= "$HP, $I, $K)"; $result = $dbh->exec($q); if (!$result) { @@ -347,6 +356,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" } $q.= ", RealName = " . $dbh->quote($R); $q.= ", LangPreference = " . $dbh->quote($L); + $q.= ", Timezone = " . $dbh->quote($TZ); $q.= ", Homepage = " . $dbh->quote($HP); $q.= ", IRCNick = " . $dbh->quote($I); $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K)); @@ -359,6 +369,13 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $ssh_key_result = account_set_ssh_keys($UID, $ssh_keys, $ssh_fingerprints); + if (isset($_COOKIE["AURTZ"]) && ($_COOKIE["AURTZ"] != $TZ)) { + /* set new cookie for timezone */ + $timeout = intval(config_get("options", "persistent_cookie_timeout")); + $cookie_time = time() + $timeout; + setcookie("AURTZ", $TZ, $cookie_time, "/"); + } + if ($result === false || $ssh_key_result === false) { $message = __("No changes were made to the account, %s%s%s.", "", htmlspecialchars($U,ENT_QUOTES), ""); diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 67dd1c14..94a38499 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -18,6 +18,9 @@ include_once("cachefuncs.inc.php"); include_once("confparser.inc.php"); include_once("credentials.inc.php"); +include_once('timezone.inc.php'); +set_tz(); + /** * Check if a visitor is logged in * diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index e4556a3f..7a171ed4 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -172,7 +172,7 @@ function pkgreq_file($ids, $type, $merge_into, $comments) { * maintainer will not be included in the Cc list of the * request notification email. */ - $out_of_date_time = gmdate("Y-m-d", intval($details["OutOfDateTS"])); + $out_of_date_time = date("Y-m-d", intval($details["OutOfDateTS"])); pkgreq_close($request_id, "accepted", "The package base has been flagged out-of-date " . "since " . $out_of_date_time . ".", true); diff --git a/web/lib/timezone.inc.php b/web/lib/timezone.inc.php new file mode 100644 index 00000000..9fb24331 --- /dev/null +++ b/web/lib/timezone.inc.php @@ -0,0 +1,60 @@ + Displayed Description + */ +function generate_timezone_list() { + $php_timezones = DateTimeZone::listIdentifiers(DateTimeZone::ALL); + + $offsets = array(); + foreach ($php_timezones as $timezone) { + $tz = new DateTimeZone($timezone); + $offset = $tz->getOffset(new DateTime()); + $offsets[$timezone] = "(UTC" . ($offset < 0 ? "-" : "+") . gmdate("H:i", abs($offset)) . + ") " . $timezone; + } + + asort($offsets); + return $offsets; +} + +/** + * Set the timezone for the user. + * + * @return null + */ +function set_tz() { + $timezones = generate_timezone_list(); + $update_cookie = false; + + if (isset($_COOKIE["AURTZ"])) { + $timezone = $_COOKIE["AURTZ"]; + } elseif (isset($_COOKIE["AURSID"])) { + $dbh = DB::connect(); + $q = "SELECT Timezone FROM Users, Sessions "; + $q .= "WHERE Users.ID = Sessions.UsersID "; + $q .= "AND Sessions.SessionID = "; + $q .= $dbh->quote($_COOKIE["AURSID"]); + $result = $dbh->query($q); + + if ($result) { + $timezone = $result->fetchColumn(0); + } + + $update_cookie = true; + } + + if (!isset($timezone) || !array_key_exists($timezone, $timezones)) { + $timezone = config_get("options", "default_timezone"); + } + date_default_timezone_set($timezone); + + if ($update_cookie) { + $timeout = intval(config_get("options", "persistent_cookie_timeout")); + $cookie_time = time() + $timeout; + setcookie("AURTZ", $timezone, $cookie_time, "/"); + } +} diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 19821a0b..17c9d14e 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -126,6 +126,21 @@ print ""."\n"; } } +?> + +

    +

    + +

    diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php index 36af43ea..e8855fe8 100644 --- a/web/template/flag_comment.php +++ b/web/template/flag_comment.php @@ -5,7 +5,7 @@ ', html_format_username($message['Username']), '', '', htmlspecialchars($pkgbase_name), '', - '', gmdate('Y-m-d', $message['OutOfDateTS']), ''); ?> + '', date('Y-m-d', $message['OutOfDateTS']), ''); ?> ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index a28e41b0..fee1898c 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -17,7 +17,7 @@ if (!isset($count)) { ('; if ($row['DelUserName']) { $user_fmtd = html_format_username($row['DelUserName']); @@ -40,7 +40,7 @@ if (!isset($count)) { } $heading .= ')'; } elseif ($uid && $is_edited) { - $date_fmtd = gmdate('Y-m-d H:i', $row['EditedTS']); + $date_fmtd = date('Y-m-d H:i', $row['EditedTS']); $heading .= ' ('; if ($row['EditUserName']) { $user_fmtd = html_format_username($row['EditUserName']); diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index b9c66d47..32693948 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -34,9 +34,9 @@ $msg = __('unknown'); $license = empty($row['License']) ? $msg : $row['License']; # Print the timestamps for last updates -$updated_time = ($row["ModifiedTS"] == 0) ? $msg : gmdate("Y-m-d H:i", intval($row["ModifiedTS"])); -$submitted_time = ($row["SubmittedTS"] == 0) ? $msg : gmdate("Y-m-d H:i", intval($row["SubmittedTS"])); -$out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : gmdate("Y-m-d", intval($row["OutOfDateTS"])); +$updated_time = ($row["ModifiedTS"] == 0) ? $msg : date("Y-m-d H:i", intval($row["ModifiedTS"])); +$submitted_time = ($row["SubmittedTS"] == 0) ? $msg : date("Y-m-d H:i", intval($row["SubmittedTS"])); +$out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : date("Y-m-d", intval($row["OutOfDateTS"])); $lics = pkg_licenses($row["ID"]); $grps = pkg_groups($row["ID"]); diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index 1012c4e6..fe769596 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -31,9 +31,9 @@ $popularity = $row['Popularity']; $msg = __('unknown'); # Print the timestamps for last updates -$updated_time = ($row["ModifiedTS"] == 0) ? $msg : gmdate("Y-m-d H:i", intval($row["ModifiedTS"])); -$submitted_time = ($row["SubmittedTS"] == 0) ? $msg : gmdate("Y-m-d H:i", intval($row["SubmittedTS"])); -$out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : gmdate("Y-m-d", intval($row["OutOfDateTS"])); +$updated_time = ($row["ModifiedTS"] == 0) ? $msg : date("Y-m-d H:i", intval($row["ModifiedTS"])); +$submitted_time = ($row["SubmittedTS"] == 0) ? $msg : date("Y-m-d H:i", intval($row["SubmittedTS"])); +$out_of_date_time = ($row["OutOfDateTS"] == 0) ? $msg : date("Y-m-d", intval($row["OutOfDateTS"])); $pkgs = pkgbase_get_pkgnames($base_id); diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index b27963be..426c7f08 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -67,7 +67,7 @@
    - class="flagged"> + class="flagged"> diff --git a/web/template/tu_details.php b/web/template/tu_details.php index 38f6c0d0..d739060d 100644 --- a/web/template/tu_details.php +++ b/web/template/tu_details.php @@ -39,10 +39,10 @@ if ($yes > $active_tus / 2) {
    - +
    : - +
    : diff --git a/web/template/tu_list.php b/web/template/tu_list.php index b3e1073a..b7253f98 100644 --- a/web/template/tu_list.php +++ b/web/template/tu_list.php @@ -38,8 +38,8 @@ - - + + From b8df10e22732fd678a6d30e2bf4ac5eb14cf898e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 25 Jan 2017 18:40:38 +0100 Subject: [PATCH 0295/1891] config.proto: Update path to the notification script As of commit 3718860 (Make maintenance scripts installable, 2016-10-17), the notification script is installed as aurweb-notify. Update the sample configuration file accordingly. Signed-off-by: Lukas Fleischer --- conf/config.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.proto b/conf/config.proto index 431697e2..c1be2816 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -34,7 +34,7 @@ enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 [notifications] -notify-cmd = /srv/http/aurweb/scripts/notify.py +notify-cmd = /usr/local/bin/aurweb-notify sendmail = /usr/bin/sendmail sender = notify@aur.archlinux.org reply-to = noreply@aur.archlinux.org From f8916d7e9bda129a57143d769f7eb1f596614c80 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 25 Jan 2017 08:22:54 +0100 Subject: [PATCH 0296/1891] git-serve: Save last SSH login date and IP address In addition to logging the last login date and IP address on the web interface, store the time stamp and IP address of the last SSH login in the database. This simplifies user banning if one of the new SSH interface features, such as the voting mechanism implemented in 7ee2fdd (git-serve: Add support for (un-)voting, 2017-01-23), is abused. Signed-off-by: Lukas Fleischer --- aurweb/git/serve.py | 13 +++++++++++++ schema/aur-schema.sql | 2 ++ upgrading/4.5.0.txt | 10 +++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 4c03e3b6..cfd4910d 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -410,6 +410,18 @@ def pkgbase_has_full_access(pkgbase, user): return cur.fetchone()[0] > 0 +def log_ssh_login(user, remote_addr): + conn = aurweb.db.Connection() + + now = int(time.time()) + conn.execute("UPDATE Users SET LastSSHLogin = ?, " + + "LastSSHLoginIPAddress = ? WHERE Username = ?", + [now, remote_addr, user]) + + conn.commit() + conn.close() + + def die(msg): sys.stderr.write("{:s}\n".format(msg)) exit(1) @@ -451,6 +463,7 @@ def serve(action, cmdargv, user, privileged, remote_addr): if enable_maintenance: if remote_addr not in maintenance_exc: raise aurweb.exceptions.MaintenanceException + log_ssh_login(user, remote_addr) if action == 'git' and cmdargv[1] in ('upload-pack', 'receive-pack'): action = action + '-' + cmdargv[1] diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 13e3fd94..b0663eb5 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -38,6 +38,8 @@ CREATE TABLE Users ( PGPKey VARCHAR(40) NULL DEFAULT NULL, LastLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, LastLoginIPAddress VARCHAR(45) NULL DEFAULT NULL, + LastSSHLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, + LastSSHLoginIPAddress VARCHAR(45) NULL DEFAULT NULL, InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0, RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CommentNotify TINYINT(1) NOT NULL DEFAULT 1, diff --git a/upgrading/4.5.0.txt b/upgrading/4.5.0.txt index 6c4ce807..5cf0888c 100644 --- a/upgrading/4.5.0.txt +++ b/upgrading/4.5.0.txt @@ -2,4 +2,12 @@ --- ALTER TABLE Users ADD COLUMN Timezone VARCHAR(32) NOT NULL DEFAULT 'UTC'; ---- \ No newline at end of file +--- + +2. Add LastSSHLogin and LastSSHLoginIPAddress columns to the Users table: + +--- +ALTER TABLE Users + ADD COLUMN LastSSHLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, + ADD COLUMN LastSSHLoginIPAddress VARCHAR(45) NULL DEFAULT NULL; +--- From 70db022aa8287c57a2ee03328ae893ba8b83b192 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 25 Jan 2017 08:37:48 +0100 Subject: [PATCH 0297/1891] Store banned IP addresses as plain text Inspired by commit 32c8d0c (Store last login address as plain text, 2016-03-13). Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.5.0.txt | 7 +++++++ web/lib/acctfuncs.inc.php | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index b0663eb5..99f90834 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -376,7 +376,7 @@ CREATE TABLE IF NOT EXISTS TU_Votes ( -- Malicious user banning -- CREATE TABLE Bans ( - IPAddress INTEGER UNSIGNED NOT NULL DEFAULT 0, + IPAddress VARCHAR(45) NULL DEFAULT NULL, BanTS TIMESTAMP NOT NULL, PRIMARY KEY (IPAddress) ) ENGINE = InnoDB; diff --git a/upgrading/4.5.0.txt b/upgrading/4.5.0.txt index 5cf0888c..fb0a2993 100644 --- a/upgrading/4.5.0.txt +++ b/upgrading/4.5.0.txt @@ -11,3 +11,10 @@ ALTER TABLE Users ADD COLUMN LastSSHLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, ADD COLUMN LastSSHLoginIPAddress VARCHAR(45) NULL DEFAULT NULL; --- + +3. Convert the IPAddress column of the Bans table to VARCHAR(45). If the table + contains any active bans, convert them accordingly: + +---- +ALTER TABLE Bans MODIFY IPAddress VARCHAR(45) NULL DEFAULT NULL; +---- diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 08dbc671..b3cf6122 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -621,7 +621,7 @@ function try_login() { function is_ipbanned() { $dbh = DB::connect(); - $q = "SELECT * FROM Bans WHERE IPAddress = " . $dbh->quote(ip2long($_SERVER['REMOTE_ADDR'])); + $q = "SELECT * FROM Bans WHERE IPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']); $result = $dbh->query($q); return ($result->fetchColumn() ? true : false); From 0e34dd6542afecc0890f77fbcb497fb5d8690d5b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 25 Jan 2017 08:47:16 +0100 Subject: [PATCH 0298/1891] git-serve: Implement IP address bans Currently, IP address bans affect the web interface only. Make sure they are honored in the SSH interface as well. Signed-off-by: Lukas Fleischer --- aurweb/exceptions.py | 4 ++++ aurweb/git/serve.py | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/aurweb/exceptions.py b/aurweb/exceptions.py index 639f9e09..664db68c 100644 --- a/aurweb/exceptions.py +++ b/aurweb/exceptions.py @@ -6,6 +6,10 @@ class MaintenanceException(AurwebException): pass +class BannedException(AurwebException): + pass + + class PermissionDeniedException(AurwebException): def __init__(self, user): msg = 'permission denied: {:s}'.format(user) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index cfd4910d..44cce75d 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -422,6 +422,14 @@ def log_ssh_login(user, remote_addr): conn.close() +def bans_match(remote_addr): + conn = aurweb.db.Connection() + + cur = conn.execute("SELECT COUNT(*) FROM Bans WHERE IPAddress = ?", + [remote_addr]) + return cur.fetchone()[0] > 0 + + def die(msg): sys.stderr.write("{:s}\n".format(msg)) exit(1) @@ -463,6 +471,8 @@ def serve(action, cmdargv, user, privileged, remote_addr): if enable_maintenance: if remote_addr not in maintenance_exc: raise aurweb.exceptions.MaintenanceException + if bans_match(remote_addr): + raise aurweb.exceptions.BannedException log_ssh_login(user, remote_addr) if action == 'git' and cmdargv[1] in ('upload-pack', 'receive-pack'): @@ -586,6 +596,8 @@ def main(): serve(action, cmdargv, user, privileged, remote_addr) except aurweb.exceptions.MaintenanceException: die("The AUR is down due to maintenance. We will be back soon.") + except aurweb.exceptions.BannedException: + die("The SSH interface is disabled for your IP address.") except aurweb.exceptions.InvalidArgumentsException as e: die_with_help('{:s}: {}'.format(action, e)) except aurweb.exceptions.AurwebException as e: From 33095b3292bdb2fa5561bf257c86004eeddcfae9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 25 Jan 2017 18:27:06 +0100 Subject: [PATCH 0299/1891] t1200: Test IP address log and bans Signed-off-by: Lukas Fleischer --- test/setup.sh | 8 ++++++++ test/t1200-git-serve.sh | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/test/setup.sh b/test/setup.sh index 26873e8d..2959a4e6 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -98,6 +98,12 @@ AUTH_KEYTYPE_MISSING=sha-rsa AUTH_KEYTEXT_MISSING=AAAAB3NzaC1yc2EAAAADAQABAAABAQC9UTpssBunuTBCT3KFtv+yb+cN0VmI2C9O9U7wHlkEZWxNBK8is6tnDHXBxRuvRk0LHILkTidLLFX22ZF0+TFgSz7uuEvGZVNpa2Fn2+vKJJYMvZEvb/f8VHF5/Jddt21VOyu23royTN/duiT7WIZdCtEmq5C9Y43NPfsB8FbUc+FVSYT2Lq7g1/bzvFF+CZxwCrGjC3qC7p3pshICfFR8bbWgRN33ClxIQ7MvkcDtfNu38dLotJqdfEa7NdQgba5/S586f1A4OWKc/mQJFyTaGhRBxw/cBSjqonvO0442VYLHFxlrTHoUunKyOJ8+BJfKgjWmfENC9ESY3mL/IEn5 AUTH_FINGERPRINT_MISSING=SHA256:uB0B+30r2WA1TDMUmFcaEBjosjnFGzn33XFhiyvTL9w +# Setup fake SSH environment. +SSH_CLIENT='1.2.3.4 1234 22' +SSH_CONNECTION='1.2.3.4 1234 4.3.2.1 22' +SSH_TTY=/dev/pts/0 +export SSH_CLIENT SSH_CONNECTION SSH_TTY + # Initialize the test database. rm -f aur.db sed \ @@ -122,6 +128,8 @@ echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (9, echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (1, '$AUTH_FINGERPRINT_USER', '$AUTH_KEYTYPE_USER $AUTH_KEYTEXT_USER');" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FINGERPRINT_TU', '$AUTH_KEYTYPE_TU $AUTH_KEYTEXT_TU');" | sqlite3 aur.db +echo "INSERT INTO Bans (IPAddress, BanTS) VALUES ('1.3.3.7', 0);" | sqlite3 aur.db + echo "INSERT INTO PackageBlacklist (Name) VALUES ('forbidden');" | sqlite3 aur.db echo "INSERT INTO OfficialProviders (Name, Repo, Provides) VALUES ('official', 'core', 'official');" | sqlite3 aur.db diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index f986b625..07383aff 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -31,6 +31,27 @@ test_expect_success 'Test maintenance mode.' ' mv config.old config ' +test_expect_success 'Test IP address logging.' ' + SSH_ORIGINAL_COMMAND=help AUR_USER=user "$GIT_SERVE" 2>actual && + cat >expected <<-EOF && + 1.2.3.4 + EOF + echo "SELECT LastSSHLoginIPAddress FROM Users WHERE UserName = \"user\";" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success 'Test IP address bans.' ' + SSH_CLIENT_ORIG="$SSH_CLIENT" && + SSH_CLIENT="1.3.3.7 1337 22" && + SSH_ORIGINAL_COMMAND=help test_must_fail "$GIT_SERVE" 2>actual && + cat >expected <<-EOF && + The SSH interface is disabled for your IP address. + EOF + test_cmp expected actual && + SSH_CLIENT="$SSH_CLIENT_ORIG" +' + test_expect_success 'Test setup-repo and list-repos.' ' SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user \ "$GIT_SERVE" 2>&1 && From 6cb8c041bc2264d02f7c86545170f45cc92d6caf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 26 Jan 2017 09:02:46 +0100 Subject: [PATCH 0300/1891] Implement co-maintainer search Add an option to filter package search results by co-maintainer. Partly fixes FS#45591. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 8 ++++++++ web/template/pkg_search_form.php | 1 + 2 files changed, 9 insertions(+) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 4b0fdbac..8ca88352 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -670,6 +670,7 @@ function pkg_display_details($id=0, $row, $SID="") { * B - package base name (exact match) * k - package keyword(s) * m - package maintainer's username + * c - package co-maintainer's username * s - package submitter's username * do_Orphans - boolean. whether to search packages * without a maintainer @@ -746,6 +747,13 @@ function pkg_search_page($SID="") { /* Search by maintainer. */ $q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . " "; } + elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "c") { + /* Search by co-maintainer. */ + $q_where .= "AND EXISTS (SELECT * FROM PackageComaintainers "; + $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; + $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; + $q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . ")"; + } elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "s") { /* Search by submitter. */ $q_where .= "AND SubmitterUID = " . intval(uid_from_username($_GET['K'])) . " "; diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php index 795a796e..688cfcce 100644 --- a/web/template/pkg_search_form.php +++ b/web/template/pkg_search_form.php @@ -9,6 +9,7 @@ $searchby = array( 'B' => __('Exact Package Base'), 'k' => __('Keywords'), 'm' => __('Maintainer'), + 'c' => __('Co-maintainer'), 's' => __('Submitter') ); From ac745f656d4c8d19cdcf8d843d6855c6b45a3974 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 3 Feb 2017 23:52:31 +0100 Subject: [PATCH 0301/1891] Split out the search form from pkg_search_page() This makes it easier to display search results without showing the search form. Signed-off-by: Lukas Fleischer --- web/html/packages.php | 3 ++- web/lib/pkgfuncs.inc.php | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/web/html/packages.php b/web/html/packages.php index 1b892781..8fd3266a 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -80,8 +80,9 @@ $(document).ready(function() { fetch(PDO::FETCH_ASSOC)) { From 3b4c6e72a966c5344976990ed3214f2e184c90ad Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Feb 2017 00:04:22 +0100 Subject: [PATCH 0302/1891] Refactor pkg_search_page() * Pass search parameters using an associative array instead of $_GET. * Add a boolean parameter to enable and disable headers/footers. Signed-off-by: Lukas Fleischer --- web/html/packages.php | 4 +- web/lib/pkgfuncs.inc.php | 126 ++++++++++------------------ web/template/pkg_search_results.php | 8 +- 3 files changed, 53 insertions(+), 85 deletions(-) diff --git a/web/html/packages.php b/web/html/packages.php index 8fd3266a..ec6fc757 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -99,9 +99,9 @@ if (isset($pkgid)) { $_GET['SO'] = 'd'; } if (isset($_COOKIE["AURSID"])) { - pkg_search_page($_COOKIE["AURSID"]); + pkg_search_page($_GET, true, $_COOKIE["AURSID"]); } else { - pkg_search_page(); + pkg_search_page($_GET, true); } } diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 8a5cf57b..ee4ca525 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -642,53 +642,16 @@ function pkg_display_details($id=0, $row, $SID="") { } } -/* pkg_search_page(SID) - * outputs the body of search/search results page +/** + * Output the body of the search results page * - * parameters: - * SID - current Session ID - * preconditions: - * package search page has been accessed - * request variables have not been sanitized + * @param array $params Search parameters + * @param bool $show_headers True if statistics should be included + * @param string $SID The session ID of the visitor * - * request vars: - * O - starting result number - * PP - number of search hits per page - * K - package search string - * SO - search hit sort order: - * values: a - ascending - * d - descending - * SB - sort search hits by: - * values: n - package name - * v - number of votes - * m - maintainer username - * SeB- property that search string (K) represents - * values: n - package name - * nd - package name & description - * b - package base name - * N - package name (exact match) - * B - package base name (exact match) - * k - package keyword(s) - * m - package maintainer's username - * c - package co-maintainer's username - * s - package submitter's username - * do_Orphans - boolean. whether to search packages - * without a maintainer - * - * - * These two are actually handled in packages.php. - * - * IDs- integer array of ticked packages' IDs - * action - action to be taken on ticked packages - * values: do_Flag - Flag out-of-date - * do_UnFlag - Remove out-of-date flag - * do_Adopt - Adopt - * do_Disown - Disown - * do_Delete - Delete - * do_Notify - Enable notification - * do_UnNotify - Disable notification + * @return void */ -function pkg_search_page($SID="") { +function pkg_search_page($params, $show_headers=true, $SID="") { $dbh = DB::connect(); /* @@ -699,16 +662,16 @@ function pkg_search_page($SID="") { $myuid = uid_from_sid($SID); /* Sanitize paging variables. */ - if (isset($_GET['O'])) { - $_GET['O'] = max(intval($_GET['O']), 0); + if (isset($params['O'])) { + $params['O'] = max(intval($params['O']), 0); } else { - $_GET['O'] = 0; + $params['O'] = 0; } - if (isset($_GET["PP"])) { - $_GET["PP"] = bound(intval($_GET["PP"]), 50, 250); + if (isset($params["PP"])) { + $params["PP"] = bound(intval($params["PP"]), 50, 250); } else { - $_GET["PP"] = 50; + $params["PP"] = 50; } /* @@ -742,67 +705,67 @@ function pkg_search_page($SID="") { $q_where = 'WHERE PackageBases.PackagerUID IS NOT NULL '; - if (isset($_GET['K'])) { - if (isset($_GET["SeB"]) && $_GET["SeB"] == "m") { + if (isset($params['K'])) { + if (isset($params["SeB"]) && $params["SeB"] == "m") { /* Search by maintainer. */ - $q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . " "; + $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . " "; } - elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "c") { + elseif (isset($params["SeB"]) && $params["SeB"] == "c") { /* Search by co-maintainer. */ $q_where .= "AND EXISTS (SELECT * FROM PackageComaintainers "; $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; - $q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . ")"; + $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . ")"; } - elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "s") { + elseif (isset($params["SeB"]) && $params["SeB"] == "s") { /* Search by submitter. */ - $q_where .= "AND SubmitterUID = " . intval(uid_from_username($_GET['K'])) . " "; + $q_where .= "AND SubmitterUID = " . intval(uid_from_username($params['K'])) . " "; } - elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "n") { + elseif (isset($params["SeB"]) && $params["SeB"] == "n") { /* Search by name. */ - $K = "%" . addcslashes($_GET['K'], '%_') . "%"; + $K = "%" . addcslashes($params['K'], '%_') . "%"; $q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . ") "; } - elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "b") { + elseif (isset($params["SeB"]) && $params["SeB"] == "b") { /* Search by package base name. */ - $K = "%" . addcslashes($_GET['K'], '%_') . "%"; + $K = "%" . addcslashes($params['K'], '%_') . "%"; $q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") "; } - elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "k") { + elseif (isset($params["SeB"]) && $params["SeB"] == "k") { /* Search by keywords. */ - $q_where .= construct_keyword_search($dbh, false); + $q_where .= construct_keyword_search($dbh, $params['K'], false); } - elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "N") { + elseif (isset($params["SeB"]) && $params["SeB"] == "N") { /* Search by name (exact match). */ - $q_where .= "AND (Packages.Name = " . $dbh->quote($_GET['K']) . ") "; + $q_where .= "AND (Packages.Name = " . $dbh->quote($params['K']) . ") "; } - elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "B") { + elseif (isset($params["SeB"]) && $params["SeB"] == "B") { /* Search by package base name (exact match). */ - $q_where .= "AND (PackageBases.Name = " . $dbh->quote($_GET['K']) . ") "; + $q_where .= "AND (PackageBases.Name = " . $dbh->quote($params['K']) . ") "; } else { /* Keyword search (default). */ - $q_where .= construct_keyword_search($dbh, true); + $q_where .= construct_keyword_search($dbh, $params['K'], true); } } - if (isset($_GET["do_Orphans"])) { + if (isset($params["do_Orphans"])) { $q_where .= "AND MaintainerUID IS NULL "; } - if (isset($_GET['outdated'])) { - if ($_GET['outdated'] == 'on') { + if (isset($params['outdated'])) { + if ($params['outdated'] == 'on') { $q_where .= "AND OutOfDateTS IS NOT NULL "; } - elseif ($_GET['outdated'] == 'off') { + elseif ($params['outdated'] == 'off') { $q_where .= "AND OutOfDateTS IS NULL "; } } - $order = (isset($_GET["SO"]) && $_GET["SO"] == 'd') ? 'DESC' : 'ASC'; + $order = (isset($params["SO"]) && $params["SO"] == 'd') ? 'DESC' : 'ASC'; $q_sort = "ORDER BY "; - $sort_by = isset($_GET["SB"]) ? $_GET["SB"] : ''; + $sort_by = isset($params["SB"]) ? $params["SB"] : ''; switch ($sort_by) { case 'v': $q_sort .= "NumVotes " . $order . ", "; @@ -835,7 +798,7 @@ function pkg_search_page($SID="") { } $q_sort .= " Packages.Name " . $order . " "; - $q_limit = "LIMIT ".$_GET["PP"]." OFFSET ".$_GET["O"]; + $q_limit = "LIMIT ".$params["PP"]." OFFSET ".$params["O"]; $q = $q_select . $q_from . $q_from_extra . $q_where . $q_sort . $q_limit; $q_total = "SELECT COUNT(*) " . $q_from . $q_where; @@ -851,7 +814,7 @@ function pkg_search_page($SID="") { } if ($result && $total > 0) { - if (isset($_GET["SO"]) && $_GET["SO"] == "d"){ + if (isset($params["SO"]) && $params["SO"] == "d"){ $SO_next = "a"; } else { @@ -860,10 +823,10 @@ function pkg_search_page($SID="") { } /* Calculate the results to use. */ - $first = $_GET['O'] + 1; + $first = $params['O'] + 1; /* Calculation of pagination links. */ - $per_page = ($_GET['PP'] > 0) ? $_GET['PP'] : 50; + $per_page = ($params['PP'] > 0) ? $params['PP'] : 50; $current = ceil($first / $per_page); $pages = ceil($total / $per_page); $templ_pages = array(); @@ -904,17 +867,18 @@ function pkg_search_page($SID="") { * Construct the WHERE part of the sophisticated keyword search * * @param handle $dbh Database handle - * @param boolean $namedesc Search name and description fields + * @param string $keywords The search term + * @param bool $namedesc Search name and description fields * * @return string WHERE part of the SQL clause */ -function construct_keyword_search($dbh, $namedesc) { +function construct_keyword_search($dbh, $keywords, $namedesc) { $count = 0; $where_part = ""; $q_keywords = ""; $op = ""; - foreach (str_getcsv($_GET['K'], ' ') as $term) { + foreach (str_getcsv($keywords, ' ') as $term) { if ($term == "") { continue; } diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index 37a90328..7b6b00aa 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -5,6 +5,7 @@ if (!$result): ?>

    +

    @@ -24,12 +25,13 @@ if (!$result): ?>

    +
    - New! + New! From 76aea988f6ca200f0d4ecf54bb2fbfb0f85e4e19 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Dec 2015 00:45:40 +0100 Subject: [PATCH 0139/1891] cgitrc.proto: Add the aurweb favicon Signed-off-by: Lukas Fleischer --- conf/cgitrc.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/cgitrc.proto b/conf/cgitrc.proto index cb773672..1b3eacbd 100644 --- a/conf/cgitrc.proto +++ b/conf/cgitrc.proto @@ -1,6 +1,7 @@ virtual-root=/cgit/ clone-prefix=https://aur.archlinux.org noheader=0 +favicon=/images/favicon.ico logo= css=/css/cgit.css snapshots=tar.gz From 9abd44671d690f91440c22e2069060500811cd21 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 Dec 2015 17:25:49 +0100 Subject: [PATCH 0140/1891] Add a "more" link to the recent updates box Implements FS#46924. Signed-off-by: Lukas Fleischer --- web/template/stats/updates_table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index 7cad3fa4..cecfb9f5 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -1,4 +1,4 @@ -

    +

    ()

    RSS Feed From 51407d4a296563ccb3f488589a531babba7a8c22 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Dec 2015 20:57:06 +0100 Subject: [PATCH 0141/1891] Store current date and time when deleting comments Instead of modifying EditedTS when a comment is deleted, use a separate field DelTS. Use this field to determine whether a comment has been deleted, instead of checking DelUsersID which might be unset when the corresponding user is deleted. Fixes FS#47362. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 1 + upgrading/4.2.0.txt | 13 ++++++++++--- web/lib/pkgbasefuncs.inc.php | 8 ++++---- web/template/pkg_comments.php | 36 ++++++++++++++++++++--------------- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index f99833a5..0c1b08ad 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -260,6 +260,7 @@ CREATE TABLE PackageComments ( CommentTS BIGINT UNSIGNED NOT NULL DEFAULT 0, EditedTS BIGINT UNSIGNED NULL DEFAULT NULL, EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, + DelTS BIGINT UNSIGNED NULL DEFAULT NULL, DelUsersID INTEGER UNSIGNED NULL DEFAULT NULL, PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (ID), diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index 7482204d..851d3843 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -16,14 +16,21 @@ CREATE UNIQUE INDEX ProviderNameProvides ON OfficialProviders (Name, Provides); ALTER TABLE Users MODIFY Email VARCHAR(254) NOT NULL; ---- -3. Add new column in PackageComments for pinning system. +3. Add new columns to the PackageComments table: ---- -ALTER TABLE PackageComments ADD COLUMN PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0; +ALTER TABLE PackageComments + ADD COLUMN DelTS BIGINT UNSIGNED NULL DEFAULT NULL, + ADD COLUMN PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0; ---- +4. Update the deletion time stamp of all deleted comments: -3. Add new column to store the closure comment of package requests: +---- +UPDATE PackageComments SET DelTS = EditedTS WHERE DelUsersID IS NOT NULL; +---- + +5. Add new column to store the closure comment of package requests: ---- ALTER TABLE PackageRequests ADD COLUMN ClosureComment TEXT NOT NULL DEFAULT ''; diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 7b744d59..1abe426b 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -21,7 +21,7 @@ function pkgbase_comments_count($base_id, $include_deleted, $only_pinned=false) $q = "SELECT COUNT(*) FROM PackageComments "; $q.= "WHERE PackageBaseID = " . $base_id . " "; if (!$include_deleted) { - $q.= "AND DelUsersID IS NULL"; + $q.= "AND DelTS IS NULL"; } if ($only_pinned) { $q.= "AND NOT PinnedTS = 0"; @@ -53,7 +53,7 @@ function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false $dbh = DB::connect(); $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; - $q.= "PackageBaseID, CommentTS, EditedTS, B.UserName AS EditUserName, "; + $q.= "PackageBaseID, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; $q.= "DelUsersID, C.UserName AS DelUserName, "; $q.= "PinnedTS FROM PackageComments "; $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; @@ -62,7 +62,7 @@ function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false $q.= "WHERE PackageBaseID = " . $base_id . " "; if (!$include_deleted) { - $q.= "AND DelUsersID IS NULL "; + $q.= "AND DelTS IS NULL "; } if ($only_pinned) { $q.= "AND NOT PinnedTS = 0 "; @@ -918,7 +918,7 @@ function pkgbase_delete_comment() { if (can_delete_comment($comment_id)) { $q = "UPDATE PackageComments "; $q.= "SET DelUsersID = ".$uid.", "; - $q.= "EditedTS = UNIX_TIMESTAMP() "; + $q.= "DelTS = UNIX_TIMESTAMP() "; $q.= "WHERE ID = ".intval($comment_id); $dbh->exec($q); return array(true, __("Comment has been deleted.")); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 4f3ee3d4..5a15fabf 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -25,25 +25,30 @@ if (!isset($count)) { $heading = __('Anonymous comment on %s', $date_fmtd); } - if ($uid && $row['EditedTS']) { - $date_fmtd = gmdate('Y-m-d H:i', $row['EditedTS']); + $is_deleted = $row['DelTS']; + $is_edited = $row['EditedTS']; + $is_pinned = $row['PinnedTS']; + + if ($uid && $is_deleted) { + $date_fmtd = gmdate('Y-m-d H:i', $row['DelTS']); + $user_fmtd = html_format_username($row['DelUserName']); $heading .= ' ('; - if ($row['DelUsersID']) { - $user_fmtd = html_format_username($row['DelUserName']); - $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); - } else { - $user_fmtd = html_format_username($row['EditUserName']); - $heading .= __('last edited on %s by %s', $date_fmtd, $user_fmtd); - } + $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); + $heading .= ')'; + } elseif ($uid && $is_edited) { + $date_fmtd = gmdate('Y-m-d H:i', $row['EditedTS']); + $user_fmtd = html_format_username($row['EditUserName']); + $heading .= ' ('; + $heading .= __('edited on %s by %s', $date_fmtd, $user_fmtd); $heading .= ')'; } $row['DelUserName'] = html_format_username($row['DelUserName']); $row['EditUserName'] = html_format_username($row['EditUserName']); ?> -

    class="comment-deleted"> +

    class="comment-deleted"> - +
    @@ -53,11 +58,12 @@ if (!isset($count)) {
    - + + <?= __('Edit comment') ?> - = 5)): ?> + = 5)): ?>
    @@ -69,7 +75,7 @@ if (!isset($count)) { - +
    @@ -80,7 +86,7 @@ if (!isset($count)) {

    -
    +

    From 4653945226999003876d8334b9933bf5c6fd07fd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 13 Dec 2015 21:10:05 +0100 Subject: [PATCH 0142/1891] Hide names of deleted accounts in comment headings When the account of a user who edited/deleted a comment is removed, drop occurrences of his user name in comment headings instead of replacing the user name with "None". Signed-off-by: Lukas Fleischer --- web/template/pkg_comments.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 5a15fabf..d05c5127 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -31,20 +31,25 @@ if (!isset($count)) { if ($uid && $is_deleted) { $date_fmtd = gmdate('Y-m-d H:i', $row['DelTS']); - $user_fmtd = html_format_username($row['DelUserName']); $heading .= ' ('; - $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); + if ($row['DelUserName']) { + $user_fmtd = html_format_username($row['DelUserName']); + $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); + } else { + $heading .= __('deleted on %s', $date_fmtd); + } $heading .= ')'; } elseif ($uid && $is_edited) { $date_fmtd = gmdate('Y-m-d H:i', $row['EditedTS']); - $user_fmtd = html_format_username($row['EditUserName']); $heading .= ' ('; - $heading .= __('edited on %s by %s', $date_fmtd, $user_fmtd); + if ($row['EditUserName']) { + $user_fmtd = html_format_username($row['EditUserName']); + $heading .= __('edited on %s by %s', $date_fmtd, $user_fmtd); + } else { + $heading .= __('edited on %s', $date_fmtd); + } $heading .= ')'; } - - $row['DelUserName'] = html_format_username($row['DelUserName']); - $row['EditUserName'] = html_format_username($row['EditUserName']); ?>

    class="comment-deleted"> From 76a589257ef37402ad53b4b876e9383c19f8e18a Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Mon, 14 Dec 2015 16:18:15 -0500 Subject: [PATCH 0143/1891] Change FlaggerComment to TEXT Makes FlaggerComments a TEXT field to be more consistent with package comments. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.2.0.txt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 0c1b08ad..9645e137 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -83,7 +83,7 @@ CREATE TABLE PackageBases ( NumVotes INTEGER UNSIGNED NOT NULL DEFAULT 0, Popularity DECIMAL(10,6) UNSIGNED NOT NULL DEFAULT 0, OutOfDateTS BIGINT UNSIGNED NULL DEFAULT NULL, - FlaggerComment VARCHAR(255) NOT NULL, + FlaggerComment TEXT NOT NULL DEFAULT '', SubmittedTS BIGINT UNSIGNED NOT NULL, ModifiedTS BIGINT UNSIGNED NOT NULL, FlaggerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- who flagged the package out-of-date? diff --git a/upgrading/4.2.0.txt b/upgrading/4.2.0.txt index 851d3843..90fee971 100644 --- a/upgrading/4.2.0.txt +++ b/upgrading/4.2.0.txt @@ -35,3 +35,9 @@ UPDATE PackageComments SET DelTS = EditedTS WHERE DelUsersID IS NOT NULL; ---- ALTER TABLE PackageRequests ADD COLUMN ClosureComment TEXT NOT NULL DEFAULT ''; ---- + +4. Change FlaggerComment from varchar to text. + +---- +ALTER TABLE PackageBases MODIFY COLUMN FlaggerComment TEXT NOT NULL DEFAULT ''; +---- From e9fe1a9eb100b11fda80f05b5b3239ee97e3a905 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Mon, 14 Dec 2015 16:18:16 -0500 Subject: [PATCH 0144/1891] Add link to flag OOD comment Implements: FS#46546 Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 4 ++++ web/html/index.php | 3 +++ web/html/pkgflagcomment.php | 19 +++++++++++++++++++ web/lib/pkgbasefuncs.inc.php | 32 ++++++++++++++++++++++++++++++++ web/template/flag_comment.php | 25 +++++++++++++++++++++++++ web/template/pkgbase_actions.php | 2 +- 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 web/html/pkgflagcomment.php create mode 100644 web/template/flag_comment.php diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 82b83d9e..92ff8989 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -130,6 +130,10 @@ top: 4px; } +.flagged a { + color: inherit; +} + legend { padding: 1em 0; } diff --git a/web/html/index.php b/web/html/index.php index 8b5cb621..0a9fd05d 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -73,6 +73,9 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { case "unflag": $_POST['do_UnFlag'] = __('UnFlag'); break; + case "flag-comment": + include('pkgflagcomment.php'); + return; case "delete": include('pkgdel.php'); return; diff --git a/web/html/pkgflagcomment.php b/web/html/pkgflagcomment.php new file mode 100644 index 00000000..98680ef6 --- /dev/null +++ b/web/html/pkgflagcomment.php @@ -0,0 +1,19 @@ +query($q); + + $row = array(); + + if (!$result) { + $row['error'] = __("Error retrieving package details."); + } + else { + $row = $result->fetch(PDO::FETCH_ASSOC); + if (empty($row)) { + $row['error'] = __("Package details could not be found."); + } + } + + return $row; +} + /** * Delete package bases * diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php new file mode 100644 index 00000000..36af43ea --- /dev/null +++ b/web/template/flag_comment.php @@ -0,0 +1,25 @@ +
    +

    +

    + + ', html_format_username($message['Username']), '', + '', htmlspecialchars($pkgbase_name), '', + '', gmdate('Y-m-d', $message['OutOfDateTS']), ''); ?> + + ', htmlspecialchars($pkgbase_name), ''); ?> + +

    +

    +

    +

    +
    +

    +

    +

    + " /> +
    +

    +
    + diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php index f8968fb2..85b1c3b7 100644 --- a/web/template/pkgbase_actions.php +++ b/web/template/pkgbase_actions.php @@ -8,7 +8,7 @@
  • -
  • +
  • From bd85441cf66b39d887f01654913da58ef313d14c Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Tue, 19 Jan 2016 14:49:50 +0100 Subject: [PATCH 0145/1891] Add comment undeletion functionality Only Developers and Trusted Users can undelete comments. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 6 +++--- web/html/images/action-undo.min.svg | 3 +++ web/html/images/action-undo.svg | 32 +++++++++++++++++++++++++++++ web/html/index.php | 1 + web/html/pkgbase.php | 5 +++++ web/lib/credentials.inc.php | 2 ++ web/lib/pkgbasefuncs.inc.php | 22 ++++++++++++++++---- web/template/pkg_comments.php | 11 ++++++++++ 8 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 web/html/images/action-undo.min.svg create mode 100644 web/html/images/action-undo.svg diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 92ff8989..4c3fbe53 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -101,7 +101,7 @@ color: #999; } -.delete-comment-form, .pin-comment-form, .edit-comment { +.delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { float: right; margin-left: 8px; } @@ -112,13 +112,13 @@ top: 1px; } -.delete-comment, .edit-comment, .pin-comment { +.delete-comment, .undelete-comment, .edit-comment, .pin-comment { -webkit-filter: grayscale(100%); filter: grayscale(100%); opacity: 0.6; } -.delete-comment:hover, .edit-comment:hover, .pin-comment:hover { +.delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { -webkit-filter: none; filter: none; opacity: 1; diff --git a/web/html/images/action-undo.min.svg b/web/html/images/action-undo.min.svg new file mode 100644 index 00000000..eb47bc47 --- /dev/null +++ b/web/html/images/action-undo.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/html/images/action-undo.svg b/web/html/images/action-undo.svg new file mode 100644 index 00000000..b93ebb78 --- /dev/null +++ b/web/html/images/action-undo.svg @@ -0,0 +1,32 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/web/html/index.php b/web/html/index.php index 0a9fd05d..3787d4e4 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -180,6 +180,7 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { readfile("./$path"); break; case "/images/x.min.svg": + case "/images/action-undo.min.svg": case "/images/pencil.min.svg": case "/images/pin.min.svg": case "/images/unpin.min.svg": diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 45b8084b..11fdf74a 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -99,6 +99,11 @@ if (check_token()) { list($ret, $output) = pkgbase_notify($ids, false); } elseif (current_action("do_DeleteComment")) { list($ret, $output) = pkgbase_delete_comment(); + } elseif (current_action("do_UndeleteComment")) { + list($ret, $output) = pkgbase_delete_comment(true); + if ($ret && isset($_POST["comment_id"])) { + $fragment = '#comment-' . intval($_POST["comment_id"]); + } } elseif (current_action("do_PinComment")) { list($ret, $output) = pkgbase_pin_comment(); } elseif (current_action("do_UnpinComment")) { diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index 71bf5ffb..d8698a87 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -6,6 +6,7 @@ define("CRED_ACCOUNT_EDIT_DEV", 3); define("CRED_ACCOUNT_LAST_LOGIN", 4); define("CRED_ACCOUNT_SEARCH", 5); define("CRED_COMMENT_DELETE", 6); +define("CRED_COMMENT_UNDELETE", 27); define("CRED_COMMENT_VIEW_DELETED", 22); define("CRED_COMMENT_EDIT", 25); define("CRED_COMMENT_PIN", 26); @@ -59,6 +60,7 @@ function has_credential($credential, $approved_users=array()) { case CRED_ACCOUNT_LAST_LOGIN: case CRED_ACCOUNT_SEARCH: case CRED_COMMENT_DELETE: + case CRED_COMMENT_UNDELETE: case CRED_COMMENT_VIEW_DELETED: case CRED_COMMENT_EDIT: case CRED_COMMENT_PIN: diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 2b1201d5..20f5bb49 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -932,9 +932,10 @@ function pkgbase_notify ($base_ids, $action=true) { /** * Delete a package comment * + * @param boolean $undelete True if undeleting rather than deleting * @return array Tuple of success/failure indicator and error message */ -function pkgbase_delete_comment() { +function pkgbase_delete_comment($undelete=false) { $uid = uid_from_sid($_COOKIE["AURSID"]); if (!$uid) { return array(false, __("You must be logged in before you can edit package information.")); @@ -947,15 +948,28 @@ function pkgbase_delete_comment() { } $dbh = DB::connect(); - if (can_delete_comment($comment_id)) { + if ($undelete) { + if (!has_credential(CRED_COMMENT_UNDELETE)) { + return array(false, __("You are not allowed to undelete this comment.")); + } + + $q = "UPDATE PackageComments "; + $q.= "SET DelUsersID = NULL, "; + $q.= "DelTS = NULL "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been undeleted.")); + } else { + if (!can_delete_comment($comment_id)) { + return array(false, __("You are not allowed to delete this comment.")); + } + $q = "UPDATE PackageComments "; $q.= "SET DelUsersID = ".$uid.", "; $q.= "DelTS = UNIX_TIMESTAMP() "; $q.= "WHERE ID = ".intval($comment_id); $dbh->exec($q); return array(true, __("Comment has been deleted.")); - } else { - return array(false, __("You are not allowed to delete this comment.")); } } diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index d05c5127..c45e45b0 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -53,6 +53,17 @@ if (!isset($count)) { ?>

    class="comment-deleted"> + +
    +
    + + + + +
    +
    + +
    From b3a6809bada24c35dad7772b3b91685a2e24cb42 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Fri, 22 Jan 2016 18:15:33 -0500 Subject: [PATCH 0146/1891] Fix duplicate ids from pinned comments Fixed duplicate ids caused from pinned comments introduced in 7d4c0c9 (Implement capability to pin comments above others, 2015-12-12). Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/template/pkg_comments.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index c45e45b0..a28e41b0 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -51,7 +51,7 @@ if (!isset($count)) { $heading .= ')'; } ?> -

    class="comment-deleted"> +

    " class="comment-deleted"> From 2121982862f25488a0e0fae58b387c2cd4b1f208 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 17 Jan 2016 23:14:58 +0100 Subject: [PATCH 0147/1891] Rename constructors to __construct In PHP 7, constructor methods that have the same name as the class they are defined in are deprecated. Use __construct instead. http://php.net/manual/en/migration70.deprecated.php Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/lib/gettext.php | 2 +- web/lib/streams.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/lib/gettext.php b/web/lib/gettext.php index 4ccd75db..098f0e5e 100644 --- a/web/lib/gettext.php +++ b/web/lib/gettext.php @@ -98,7 +98,7 @@ class gettext_reader { * @param object Reader the StreamReader object * @param boolean enable_cache Enable or disable caching of strings (default on) */ - function gettext_reader($Reader, $enable_cache = true) { + function __construct($Reader, $enable_cache = true) { // If there isn't a StreamReader, turn on short circuit mode. if (! $Reader || isset($Reader->error) ) { $this->short_circuit = true; diff --git a/web/lib/streams.php b/web/lib/streams.php index 3cdc1584..00cf6cc5 100644 --- a/web/lib/streams.php +++ b/web/lib/streams.php @@ -49,7 +49,7 @@ class StringReader { var $_pos; var $_str; - function StringReader($str='') { + function __construct($str='') { $this->_str = $str; $this->_pos = 0; } @@ -86,7 +86,7 @@ class FileReader { var $_fd; var $_length; - function FileReader($filename) { + function __construct($filename) { if (file_exists($filename)) { $this->_length=filesize($filename); @@ -143,7 +143,7 @@ class FileReader { // Preloads entire file in memory first, then creates a StringReader // over it (it assumes knowledge of StringReader internals) class CachedFileReader extends StringReader { - function CachedFileReader($filename) { + function __construct($filename) { if (file_exists($filename)) { $length=filesize($filename); From 700df4f32fdf013f8ba7b067ab6054a47affc4d4 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 28 Jan 2016 22:59:59 +0100 Subject: [PATCH 0148/1891] Include parentheses in translatable string This string is easier to understand with the extra parentheses. Signed-off-by: Lukas Fleischer --- web/template/pkgbase_actions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php index 85b1c3b7..237e712f 100644 --- a/web/template/pkgbase_actions.php +++ b/web/template/pkgbase_actions.php @@ -8,7 +8,7 @@
  • -
  • +
  • From 6d6df72183970040839cc6c4e6066cc8a6094d65 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 28 Jan 2016 23:04:00 +0100 Subject: [PATCH 0149/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index c214761a..27622386 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: AUR v4.1.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2015-12-12 15:11+0100\n" +"POT-Creation-Date: 2016-01-28 23:03+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -500,6 +500,10 @@ msgstr "" msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php +msgid "Flag Comment" +msgstr "" + #: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" @@ -938,13 +942,21 @@ msgid "You have been removed from the comment notification list for %s." msgstr "" #: lib/pkgbasefuncs.inc.php -msgid "Comment has been deleted." +msgid "You are not allowed to undelete this comment." +msgstr "" + +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been undeleted." msgstr "" #: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php +msgid "Comment has been deleted." +msgstr "" + #: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" @@ -1211,6 +1223,25 @@ msgstr "" msgid "Save" msgstr "" +#: template/flag_comment.php +#, php-format +msgid "Flagged Out-of-Date Comment: %s" +msgstr "" + +#: template/flag_comment.php +#, php-format +msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" +msgstr "" + +#: template/flag_comment.php +#, php-format +msgid "%s%s%s is not flagged out-of-date." +msgstr "" + +#: template/flag_comment.php +msgid "Return to Details" +msgstr "" + #: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." @@ -1245,7 +1276,8 @@ msgid "Search wiki" msgstr "" #: template/pkgbase_actions.php -msgid "Flagged out-of-date" +#, php-format +msgid "Flagged out-of-date (%s)" msgstr "" #: template/pkgbase_actions.php @@ -1379,7 +1411,21 @@ msgstr "" #: template/pkg_comments.php #, php-format -msgid "last edited on %s by %s" +msgid "deleted on %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "edited on %s by %s" +msgstr "" + +#: template/pkg_comments.php +#, php-format +msgid "edited on %s" +msgstr "" + +#: template/pkg_comments.php +msgid "Undelete comment" msgstr "" #: template/pkg_comments.php @@ -1740,6 +1786,10 @@ msgstr "" msgid "Recent Updates" msgstr "" +#: template/stats/updates_table.php +msgid "more" +msgstr "" + #: template/stats/user_table.php msgid "My Statistics" msgstr "" From 6b766b8e77a633e147a697aaf9f86ad71bcf3dfb Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sat, 30 Jan 2016 01:04:23 +0100 Subject: [PATCH 0150/1891] Shorten maxlength of email input fields to 254 characters After 24734d0 (Shorten Email column to 254 characters, 2015-11-12) the maximum length of the input fields should be shortened, too. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/login.php | 2 +- web/template/account_edit_form.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/html/login.php b/web/html/login.php index 0a2a1c97..7345439d 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -29,7 +29,7 @@ html_header('AUR ' . __("Login"));

    - +

    diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 28da2032..cb0fa33b 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -69,7 +69,7 @@

    - () + ()

    From 73364ad7249ac9c4d7c4b2770f3b04f2cdea6b06 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 31 Jan 2016 19:48:43 +0100 Subject: [PATCH 0151/1891] Correctly encode ampersand in query string within HTML attribute Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/template/stats/updates_table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index cecfb9f5..e2f79b27 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -1,4 +1,4 @@ -

    ()

    +

    ()

    RSS Feed From 7d7fc184059e524882091343213f204fa67ff4d6 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 31 Jan 2016 19:48:34 +0100 Subject: [PATCH 0152/1891] Make RSS icon dark gray and only blue on hover The other new icons (in package comments) behave the same way. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 4c3fbe53..63fe01cd 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -112,13 +112,13 @@ top: 1px; } -.delete-comment, .undelete-comment, .edit-comment, .pin-comment { +.rss-icon, .delete-comment, .undelete-comment, .edit-comment, .pin-comment { -webkit-filter: grayscale(100%); filter: grayscale(100%); opacity: 0.6; } -.delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { +.rss-icon:hover, .delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { -webkit-filter: none; filter: none; opacity: 1; From 1664a24198a3f3ef3fb3529ce8761fd030325e43 Mon Sep 17 00:00:00 2001 From: Marcel Korpel Date: Sun, 31 Jan 2016 20:07:45 +0100 Subject: [PATCH 0153/1891] Remove 'new' tag from updates table It was hard to make it consistent with the other new icons from Open Iconic and it hadn't much use after all. Signed-off-by: Marcel Korpel Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 8 -------- web/html/images/new.svg | 3 --- web/lib/stats.inc.php | 2 +- web/template/stats/updates_table.php | 5 ----- 4 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 web/html/images/new.svg diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 63fe01cd..f5e10371 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -16,10 +16,6 @@ margin: 0 .25em; } -#pkg-updates td.pkg-new { - padding: 0 .5em; -} - #pkg-stats td.stat-desc { white-space: normal; } @@ -45,10 +41,6 @@ text-overflow: ellipsis; } -#pkg-updates td.pkg-new { - width: 16px; -} - #pkg-updates td.pkg-date { text-align:right; } diff --git a/web/html/images/new.svg b/web/html/images/new.svg deleted file mode 100644 index 87f1a4cc..00000000 --- a/web/html/images/new.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/lib/stats.inc.php b/web/lib/stats.inc.php index 5a245918..80619fe1 100644 --- a/web/lib/stats.inc.php +++ b/web/lib/stats.inc.php @@ -11,7 +11,7 @@ function updates_table() { $dbh = DB::connect(); $key = 'recent_updates'; if(!($newest_packages = get_cache_value($key))) { - $q = 'SELECT Packages.Name, Version, ModifiedTS, SubmittedTS '; + $q = 'SELECT Packages.Name, Version, ModifiedTS '; $q.= 'FROM Packages INNER JOIN PackageBases ON '; $q.= 'Packages.PackageBaseID = PackageBases.ID '; $q.= 'WHERE PackageBases.PackagerUID IS NOT NULL '; diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index e2f79b27..4e2d39d5 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -9,11 +9,6 @@

    " title=""> - - New! - -
    " rel="nofollow">
    ??
    format('Y-m-d') ?>
    format('Y-m-d') ?>
    diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index 580583b5..b4c6215f 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -10,7 +10,7 @@ " title=""> - +
    From 7ff50701903017b3b97ca3ca176e923769cdad43 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Fri, 20 Jan 2017 01:16:40 -0500 Subject: [PATCH 0290/1891] Update cookie for language setting when editing user information Currently, when a user edits their language setting from the edit user form, the changes aren't reflected until the user either lets the original cookie expire, deletes the cookie manually, or changes the language a second time via the dropdown menu on the top of the page. This patch makes the language cookie get updated when it is changed from the edit user form. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index b7288143..08dbc671 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -376,6 +376,13 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" setcookie("AURTZ", $TZ, $cookie_time, "/"); } + if (isset($_COOKIE["AURLANG"]) && ($_COOKIE["AURLANG"] != $L)) { + /* set new cookie for language */ + $timeout = intval(config_get("options", "persistent_cookie_timeout")); + $cookie_time = time() + $timeout; + setcookie("AURLANG", $L, $cookie_time, "/"); + } + if ($result === false || $ssh_key_result === false) { $message = __("No changes were made to the account, %s%s%s.", "", htmlspecialchars($U,ENT_QUOTES), ""); From fc2ecff949ced53849e0ae10923d02d74b895c32 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Fri, 20 Jan 2017 01:16:41 -0500 Subject: [PATCH 0291/1891] account.php: Reformat process_account_form() call Modify the call to process_account_form() to only having one parameter per line. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/html/account.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index 91e57038..0b757612 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -31,13 +31,25 @@ if ($action == "UpdateAccount") { /* Update the details for the existing account */ list($success, $update_account_message) = process_account_form( "edit", "UpdateAccount", - in_request("U"), in_request("T"), in_request("S"), - in_request("E"), in_request("H"), in_request("P"), - in_request("C"), in_request("R"), in_request("L"), + in_request("U"), + in_request("T"), + in_request("S"), + in_request("E"), + in_request("H"), + in_request("P"), + in_request("C"), + in_request("R"), + in_request("L"), in_request("TZ"), - in_request("HP"), in_request("I"), in_request("K"), - in_request("PK"), in_request("J"), in_request("CN"), - in_request("UN"), in_request("ON"), in_request("ID"), + in_request("HP"), + in_request("I"), + in_request("K"), + in_request("PK"), + in_request("J"), + in_request("CN"), + in_request("UN"), + in_request("ON"), + in_request("ID"), $row["Username"]); } } From 7ee2fddcca6ef924ccfd10e6de9a799a9eb1abeb Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 23 Jan 2017 09:07:45 +0100 Subject: [PATCH 0292/1891] git-serve: Add support for (un-)voting Add support for voting for packages and removing votes from the SSH interface. The syntax is `vote ` resp. `unvote `. Signed-off-by: Lukas Fleischer --- aurweb/exceptions.py | 12 +++++++++ aurweb/git/serve.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/aurweb/exceptions.py b/aurweb/exceptions.py index 5922b2df..639f9e09 100644 --- a/aurweb/exceptions.py +++ b/aurweb/exceptions.py @@ -48,6 +48,18 @@ class InvalidCommentException(AurwebException): super(InvalidCommentException, self).__init__(msg) +class AlreadyVotedException(AurwebException): + def __init__(self, comment): + msg = 'already voted for package base: {:s}'.format(comment) + super(AlreadyVotedException, self).__init__(msg) + + +class NotVotedException(AurwebException): + def __init__(self, comment): + msg = 'missing vote for package base: {:s}'.format(comment) + super(NotVotedException, self).__init__(msg) + + class InvalidArgumentsException(AurwebException): def __init__(self, msg): super(InvalidArgumentsException, self).__init__(msg) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index e33fbeb4..4c03e3b6 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -318,6 +318,57 @@ def pkgbase_unflag(pkgbase, user): conn.commit() +def pkgbase_vote(pkgbase, user): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) + + conn = aurweb.db.Connection() + + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + if userid == 0: + raise aurweb.exceptions.InvalidUserException(user) + + cur = conn.execute("SELECT COUNT(*) FROM PackageVotes " + + "WHERE UsersID = ? AND PackageBaseID = ?", + [userid, pkgbase_id]) + if cur.fetchone()[0] > 0: + raise aurweb.exceptions.AlreadyVotedException(pkgbase) + + now = int(time.time()) + conn.execute("INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) " + + "VALUES (?, ?, ?)", [userid, pkgbase_id, now]) + conn.execute("UPDATE PackageBases SET NumVotes = NumVotes + 1 " + + "WHERE ID = ?", [pkgbase_id]) + conn.commit() + + +def pkgbase_unvote(pkgbase, user): + pkgbase_id = pkgbase_from_name(pkgbase) + if not pkgbase_id: + raise aurweb.exceptions.InvalidPackageBaseException(pkgbase) + + conn = aurweb.db.Connection() + + cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) + userid = cur.fetchone()[0] + if userid == 0: + raise aurweb.exceptions.InvalidUserException(user) + + cur = conn.execute("SELECT COUNT(*) FROM PackageVotes " + + "WHERE UsersID = ? AND PackageBaseID = ?", + [userid, pkgbase_id]) + if cur.fetchone()[0] == 0: + raise aurweb.exceptions.NotVotedException(pkgbase) + + conn.execute("DELETE FROM PackageVotes WHERE UsersID = ? AND " + + "PackageBaseID = ?", [userid, pkgbase_id]) + conn.execute("UPDATE PackageBases SET NumVotes = NumVotes - 1 " + + "WHERE ID = ?", [pkgbase_id]) + conn.commit() + + def pkgbase_set_keywords(pkgbase, keywords): pkgbase_id = pkgbase_from_name(pkgbase) if not pkgbase_id: @@ -467,6 +518,16 @@ def serve(action, cmdargv, user, privileged, remote_addr): pkgbase = cmdargv[1] pkgbase_unflag(pkgbase, user) + elif action == 'vote': + checkarg(cmdargv, 'repository name') + + pkgbase = cmdargv[1] + pkgbase_vote(pkgbase, user) + elif action == 'unvote': + checkarg(cmdargv, 'repository name') + + pkgbase = cmdargv[1] + pkgbase_unvote(pkgbase, user) elif action == 'set-comaintainers': checkarg_atleast(cmdargv, 'repository name') @@ -485,6 +546,8 @@ def serve(action, cmdargv, user, privileged, remote_addr): "set-keywords [...]": "Change package base keywords.", "setup-repo ": "Create a repository (deprecated).", "unflag ": "Remove out-of-date flag from a package base.", + "unvote ": "Remove vote from a package base.", + "vote ": "Vote for a package base.", "git-receive-pack": "Internal command used with Git.", "git-upload-pack": "Internal command used with Git.", } From 0b09f200c50cd1e6737f6225b35f0af9d6f8bed8 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 23 Jan 2017 09:10:04 +0100 Subject: [PATCH 0293/1891] t1200: Add tests for vote/unvote Signed-off-by: Lukas Fleischer --- test/t1200-git-serve.sh | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index d422c480..f986b625 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -414,4 +414,70 @@ test_expect_success "Flag using a comment which is too short." ' test_cmp expected actual ' +test_expect_success "Vote for a package base." ' + SSH_ORIGINAL_COMMAND="vote foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 3|1 + EOF + echo "SELECT PackageBaseID, UsersID FROM PackageVotes;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual && + cat >expected <<-EOF && + 1 + EOF + echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Vote for a package base twice." ' + SSH_ORIGINAL_COMMAND="vote foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + 3|1 + EOF + echo "SELECT PackageBaseID, UsersID FROM PackageVotes;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual && + cat >expected <<-EOF && + 1 + EOF + echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Remove vote from a package base." ' + SSH_ORIGINAL_COMMAND="unvote foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + echo "SELECT PackageBaseID, UsersID FROM PackageVotes;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual && + cat >expected <<-EOF && + 0 + EOF + echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + +test_expect_success "Try to remove the vote again." ' + SSH_ORIGINAL_COMMAND="unvote foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + test_must_fail "$GIT_SERVE" 2>&1 && + cat >expected <<-EOF && + EOF + echo "SELECT PackageBaseID, UsersID FROM PackageVotes;" | \ + sqlite3 aur.db >actual && + test_cmp expected actual && + cat >expected <<-EOF && + 0 + EOF + echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + sqlite3 aur.db >actual && + test_cmp expected actual +' + test_done From 1ed847118222c72c1f97c8217bfce6d29bb99f51 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Mon, 23 Jan 2017 00:18:22 -0500 Subject: [PATCH 0294/1891] Show co-maintainers SSH clone URL on package base page On package base pages, if a co-maintainer visits, only the read-only URL is displayed which is inconsistent with how the individual packages of a package base's pages displays them. This adds the SSH clone URL to the package base's page for co-maintainers to see. Implements FS#52675. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/template/pkgbase_details.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index fe769596..e368872e 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -50,7 +50,7 @@ $base_uri = get_pkgbase_uri($row['Name']); () - +
    - + @@ -48,7 +50,7 @@ if (!$result): ?> - + @@ -85,6 +87,7 @@ if (!$result): ?>
     
    ]" value="1" /> ">
    +

    @@ -127,6 +130,7 @@ if (!$result): ?> " />

    +
    From b6aced9692dae4145b8848fb1da495901434a667 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Feb 2017 00:28:37 +0100 Subject: [PATCH 0303/1891] pkg_search_results.php: Split out package results box Do not print the wrapper div container when calling pkg_search_page(). Signed-off-by: Lukas Fleischer --- web/html/packages.php | 2 + web/template/pkg_search_results.php | 176 ++++++++++++++-------------- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/web/html/packages.php b/web/html/packages.php index ec6fc757..113a1145 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -98,11 +98,13 @@ if (isset($pkgid)) { $_GET['SB'] = 'p'; $_GET['SO'] = 'd'; } + echo '
    '; if (isset($_COOKIE["AURSID"])) { pkg_search_page($_GET, true, $_COOKIE["AURSID"]); } else { pkg_search_page($_GET, true); } + echo '
    '; } html_footer(AURWEB_VERSION); diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index 7b6b00aa..d596ec2d 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -1,52 +1,51 @@ -

    +

    -

    +

    -
    - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    + +
    +

    + + +

    + 1): ?> +

    + $pagestart): ?> + + + + + + + + +

    +
    + -
    - - - - - - - - - - - - - - - - - - - + +
     ?
    + + + + + + + + + + + + + + + + + + @@ -84,53 +83,52 @@ if (!$result): ?> - -
     ?
    + + - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - -

    - - - - + +

    +

    + + +

    + 1): ?> +

    + $pagestart): ?> + + + + + + - - - " /> -

    - + +

    - -
    +
    + + +

    + + + + + + + + " /> +

    + + + From 1049f9319131d7f6ffea6c1863739c39e3b30a8f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Feb 2017 00:13:09 +0100 Subject: [PATCH 0304/1891] Add dashboard For logged in users, the home page is replaced with an overview of the packages the user maintains or co-maintains. Signed-off-by: Lukas Fleischer --- web/html/home.php | 36 ++++++++++++++++++++++++++++++++++-- web/template/header.php | 7 ++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/web/html/home.php b/web/html/home.php index 475370bb..ff9caa7c 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -8,13 +8,42 @@ check_sid(); include_once('stats.inc.php'); -html_header( __("Home") ); +if (isset($_COOKIE["AURSID"])) { + html_header( __("Dashboard") ); +} else { + html_header( __("Home") ); +} ?>
    + +

    +

    + 50, + 'SeB' => 'm', + 'K' => username_from_sid($_COOKIE["AURSID"]), + 'SB' => 'l', + 'SO' => 'd' + ); + pkg_search_page($params, false, $_COOKIE["AURSID"]); + ?> +

    + 50, + 'SeB' => 'c', + 'K' => username_from_sid($_COOKIE["AURSID"]), + 'SB' => 'l', + 'SO' => 'd' + ); + pkg_search_page($params, false, $_COOKIE["AURSID"]); + ?> +

    AUR

    +
    +

    @@ -122,6 +153,7 @@ html_header( __("Home") );

    +
    @@ -140,7 +172,7 @@ html_header( __("Home") );
    - +
    diff --git a/web/template/header.php b/web/template/header.php index 874109a5..7343575e 100644 --- a/web/template/header.php +++ b/web/template/header.php @@ -53,10 +53,9 @@
      -
    • AUR
    • -
    • -
    • ">
    • +
    • +
    • @@ -67,6 +66,8 @@
    • +
    • AUR
    • +
    • From 7d7e07932677eaf584e593af6868eab89c711b8b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Feb 2017 10:55:05 +0100 Subject: [PATCH 0305/1891] Hide the table sorting links on the dashboard The tables on the dashboard always show the 50 most recent packages, ordered by last update. Do not make the table headers of these tables clickable. Signed-off-by: Lukas Fleischer --- web/template/pkg_search_results.php | 35 ++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index d596ec2d..7f92685a 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -1,4 +1,23 @@ '; + if ($sb) { + echo '' . $title . ''; + } else { + echo $title; + } + if ($hint) { + echo '?'; + } + echo ''; + }; +} else { + $fmtth = function($title, $sb=false, $so=false, $hint=false) { + echo '' . $title . ''; + }; +} + if (!$result): ?>

      @@ -33,16 +52,16 @@ if (!$result): ?>   - - - - ? + + + + - - + + - - + + From 555cdac2db5ebab48ef8abf66488fd27fb500aa7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Feb 2017 11:00:20 +0100 Subject: [PATCH 0306/1891] Return the number of results in pkg_search_page() Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index ee4ca525..063cc935 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -649,7 +649,7 @@ function pkg_display_details($id=0, $row, $SID="") { * @param bool $show_headers True if statistics should be included * @param string $SID The session ID of the visitor * - * @return void + * @return int The total number of packages matching the query */ function pkg_search_page($params, $show_headers=true, $SID="") { $dbh = DB::connect(); @@ -860,7 +860,7 @@ function pkg_search_page($params, $show_headers=true, $SID="") { include('pkg_search_results.php'); - return; + return $total; } /** From a1890d400b2eefeaf20c80701951af6b2a8ff55e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Feb 2017 11:04:26 +0100 Subject: [PATCH 0307/1891] Add links to all owned packages to the dashboard In addition to showing the 50 most recent maintained and co-maintained packages, add links to all packages one owns or co-maintains. Signed-off-by: Lukas Fleischer --- web/html/home.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/html/home.php b/web/html/home.php index ff9caa7c..08ae59f6 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -21,7 +21,7 @@ if (isset($_COOKIE["AURSID"])) {

      -

      +

      (">)

      50, @@ -32,7 +32,7 @@ if (isset($_COOKIE["AURSID"])) { ); pkg_search_page($params, false, $_COOKIE["AURSID"]); ?> -

      +

      (">)

      50, From 1613bd2f2980d5da7f2d3e0a0113f126b6deb155 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Feb 2017 23:54:54 +0100 Subject: [PATCH 0308/1891] confparser.inc.php: Support alternative config path Add a AUR_CONFIG environment variable that can be used to specify an alternative configuration file, similar to the feature introduced in ecbf32f (git-interface: Add AUR_CONFIG environment variable, 2016-08-03). Signed-off-by: Lukas Fleischer --- web/lib/confparser.inc.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php index 789300e1..e7128be6 100644 --- a/web/lib/confparser.inc.php +++ b/web/lib/confparser.inc.php @@ -4,7 +4,11 @@ function config_load() { global $AUR_CONFIG; if (!isset($AUR_CONFIG)) { - $AUR_CONFIG = parse_ini_file("/etc/aurweb/config", true, INI_SCANNER_RAW); + $path = getenv('AUR_CONFIG'); + if (!$path) { + $path = "/etc/aurweb/config"; + } + $AUR_CONFIG = parse_ini_file($path, true, INI_SCANNER_RAW); } } From 880d25e98c3efd406532a1b460e32b6350c9e39c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 7 Feb 2017 08:16:08 +0100 Subject: [PATCH 0309/1891] Allow to search for both maintainer and co-maintainer As a follow-up to commit 6cb8c04 (Implement co-maintainer search, 2017-01-26), add an option to search for both maintainers and co-maintainers at the same time. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 8 ++++++++ web/template/pkg_search_form.php | 1 + 2 files changed, 9 insertions(+) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 063cc935..030ec9a1 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -717,6 +717,14 @@ function pkg_search_page($params, $show_headers=true, $SID="") { $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . ")"; } + elseif (isset($params["SeB"]) && $params["SeB"] == "M") { + /* Search by maintainer and co-maintainer. */ + $q_where .= "AND (Users.Username = " . $dbh->quote($params['K']) . " "; + $q_where .= "OR EXISTS (SELECT * FROM PackageComaintainers "; + $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; + $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; + $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . "))"; + } elseif (isset($params["SeB"]) && $params["SeB"] == "s") { /* Search by submitter. */ $q_where .= "AND SubmitterUID = " . intval(uid_from_username($params['K'])) . " "; diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php index 688cfcce..3d0cde6c 100644 --- a/web/template/pkg_search_form.php +++ b/web/template/pkg_search_form.php @@ -10,6 +10,7 @@ $searchby = array( 'k' => __('Keywords'), 'm' => __('Maintainer'), 'c' => __('Co-maintainer'), + 'M' => __('Maintainer, Co-maintainer'), 's' => __('Submitter') ); From d45585e36d6cbd9483f4a5b18cbbc346757ca6a0 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 7 Feb 2017 08:20:34 +0100 Subject: [PATCH 0310/1891] Add flagged packages to the dashboard Implement a table that shows all packages which are flagged out-of-date and either maintained or co-maintained by the currently logged in user. Signed-off-by: Lukas Fleischer --- web/html/home.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/web/html/home.php b/web/html/home.php index 08ae59f6..62409af7 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -21,6 +21,18 @@ if (isset($_COOKIE["AURSID"])) {

      +

      + 50, + 'SeB' => 'M', + 'K' => username_from_sid($_COOKIE["AURSID"]), + 'outdated' => 'on', + 'SB' => 'l', + 'SO' => 'a' + ); + pkg_search_page($params, false, $_COOKIE["AURSID"]); + ?>

      (">)

      Date: Tue, 7 Feb 2017 08:25:41 +0100 Subject: [PATCH 0311/1891] Add an option to filter by user to pkgreq_list() When a user is specified, the function only returns package requests which are either opened by the given user or affecting packages maintained by the given user. Signed-off-by: Lukas Fleischer --- web/lib/pkgreqfuncs.inc.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index 7a171ed4..7dcab135 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -19,10 +19,11 @@ function pkgreq_count() { * * @param int $offset The index of the first request to return * @param int $limit The maximum number of requests to return + * @param int $uid Only return packages affecting the given user * * @return array List of pacakge requests with details */ -function pkgreq_list($offset, $limit) { +function pkgreq_list($offset, $limit, $uid=false) { $dbh = DB::connect(); $q = "SELECT PackageRequests.ID, "; @@ -35,6 +36,12 @@ function pkgreq_list($offset, $limit) { $q.= "FROM PackageRequests INNER JOIN RequestTypes ON "; $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; $q.= "INNER JOIN Users ON Users.ID = PackageRequests.UsersID "; + + if ($uid) { + $q.= "WHERE PackageRequests.UsersID = " . intval($uid). " "; + $q.= "OR Users.ID = " . intval($uid) . " "; + } + $q.= "ORDER BY Open DESC, RequestTS DESC "; $q.= "LIMIT " . $limit . " OFFSET " . $offset; From 05007d8b1a0a9c0b8371a7f5a0bcf5e8d240956a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 7 Feb 2017 08:29:53 +0100 Subject: [PATCH 0312/1891] pkgreq_results.php: Split out package results box Do not include the wrapper div container in the template. Signed-off-by: Lukas Fleischer --- web/html/pkgreq.php | 2 + web/template/pkgreq_results.php | 250 ++++++++++++++++---------------- 2 files changed, 126 insertions(+), 126 deletions(-) diff --git a/web/html/pkgreq.php b/web/html/pkgreq.php index 8348a4f3..e0ef6cfd 100644 --- a/web/html/pkgreq.php +++ b/web/html/pkgreq.php @@ -77,7 +77,9 @@ if (isset($base_id)) { $SID = $_COOKIE['AURSID']; html_header(__("Requests")); + echo '
      '; include('pkgreq_results.php'); + echo '
      '; } html_footer(AURWEB_VERSION); diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index 426c7f08..bd4fc6b9 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -1,129 +1,127 @@ -
      -
      -

      - - -

      - 1): ?> -

      - $pagestart): ?> - - - - - - - - -

      - -
      - - - - - - - - - - - - - - - - $idle_time); - if (!$due) { - $time_left = $idle_time - (time() - intval($row['RequestTS'])); - if ($time_left > 48 * 3600) { - $time_left_fmt = _n("~%d day left", "~%d days left", round($time_left / (24 * 3600))); - } elseif ($time_left > 3600) { - $time_left_fmt = _n("~%d hour left", "~%d hours left", round($time_left / 3600)); - } else { - $time_left_fmt = __("<1 hour left"); - } - } - ?> - - - +
      +

      + + +

      + 1): ?> +

      + $pagestart): ?> + + + + -

      + - - - - - - - - class="flagged"> - - - - - - - - - - - - - - - - - -
      "> - - - () - - - - - - - -
      - - -
      - -
      - - - -
      - - () -
      - - - -
      - -
      -

      - - -

      - 1): ?> -

      - $pagestart): ?> - - - - - - - - -

      - -
      + +

      + +
      + + + + + + + + + + + + + + + + $idle_time); + if (!$due) { + $time_left = $idle_time - (time() - intval($row['RequestTS'])); + if ($time_left > 48 * 3600) { + $time_left_fmt = _n("~%d day left", "~%d days left", round($time_left / (24 * 3600))); + } elseif ($time_left > 3600) { + $time_left_fmt = _n("~%d hour left", "~%d hours left", round($time_left / 3600)); + } else { + $time_left_fmt = __("<1 hour left"); + } + } + ?> + + + + + + + + + + + + + + class="flagged"> + + + + + + + + + + + + + + + + + +
      "> + + + () + + + + + + + +
      + + +
      + +
      + + + +
      + + () +
      + + + +
      + +
      +

      + + +

      + 1): ?> +

      + $pagestart): ?> + + + + + + + + +

      +
      From 403241baa34c75ed4942926cf667094f6036b773 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 7 Feb 2017 08:44:14 +0100 Subject: [PATCH 0313/1891] pkgreq_results.php: Add a flag to hide headers Introduce a new boolean flag that can be used to disable extended headers, pagination and forms. Signed-off-by: Lukas Fleischer --- web/html/pkgreq.php | 1 + web/template/pkgreq_results.php | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/web/html/pkgreq.php b/web/html/pkgreq.php index e0ef6cfd..f981c25d 100644 --- a/web/html/pkgreq.php +++ b/web/html/pkgreq.php @@ -78,6 +78,7 @@ if (isset($base_id)) { html_header(__("Requests")); echo '
      '; + $show_headers = true; include('pkgreq_results.php'); echo '
      '; } diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index bd4fc6b9..74fcb10d 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -1,3 +1,4 @@ +

      @@ -17,6 +18,7 @@

      + @@ -67,7 +69,7 @@ class="flagged"> - + - - + + + @@ -99,13 +102,13 @@ -
      @@ -89,8 +91,9 @@
      +

      @@ -125,3 +128,4 @@

      + From 2bc208c13e3a48980e295bd0b444c99ada163865 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 7 Feb 2017 08:51:15 +0100 Subject: [PATCH 0314/1891] Add requests to dashboard Add a new table which shows all package requests affecting the currently logged in user. Signed-off-by: Lukas Fleischer --- web/html/home.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/html/home.php b/web/html/home.php index 62409af7..381cb71f 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -33,6 +33,12 @@ if (isset($_COOKIE["AURSID"])) { ); pkg_search_page($params, false, $_COOKIE["AURSID"]); ?> +

      +

      (">)

      Date: Tue, 7 Feb 2017 08:54:50 +0100 Subject: [PATCH 0315/1891] Move my packages to separate dashboard sections Signed-off-by: Lukas Fleischer --- web/html/home.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/web/html/home.php b/web/html/home.php index 381cb71f..16525419 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -18,8 +18,8 @@ if (isset($_COOKIE["AURSID"])) {
      +
      -

      -

      (">)

      +
      +
      +

      (">)

      50, @@ -50,7 +52,9 @@ if (isset($_COOKIE["AURSID"])) { ); pkg_search_page($params, false, $_COOKIE["AURSID"]); ?> -

      (">)

      +
      +
      +

      (">)

      50, @@ -61,7 +65,9 @@ if (isset($_COOKIE["AURSID"])) { ); pkg_search_page($params, false, $_COOKIE["AURSID"]); ?> - +
      + +

      AUR

      -
      -

      From 3a167a109b240ef7c8c2fa7363156456c6861521 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 11 Feb 2017 22:21:03 +0100 Subject: [PATCH 0316/1891] Move package search links on the dashboard Move the package search links below the section headings. Signed-off-by: Lukas Fleischer --- web/html/home.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/html/home.php b/web/html/home.php index 16525419..ee7caf77 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -41,7 +41,8 @@ if (isset($_COOKIE["AURSID"])) { ?>
      -

      (">)

      +

      +

      ">

      50, @@ -54,7 +55,8 @@ if (isset($_COOKIE["AURSID"])) { ?>
      -

      (">)

      +

      +

      ">

      50, From 9df1bd5fe2f781d1b8341496378c605b34cde64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janne=20He=C3=9F?= Date: Sun, 12 Feb 2017 17:37:38 +0100 Subject: [PATCH 0317/1891] Add direct links to each source file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, each source file which is an external link (http://, https://, ...) is a clickable link. This commit extends the behaviour by making files from the repository clickable as well. The link brings the user to the corresponding cgit page. Also, the link to the PKGBUILD is altered to make the configuration more consistent. Signed-off-by: Janne Heß Signed-off-by: Lukas Fleischer --- conf/config.proto | 2 +- web/lib/pkgfuncs.inc.php | 6 ++++-- web/template/pkg_details.php | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/conf/config.proto b/conf/config.proto index c1be2816..01a907a6 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -27,7 +27,7 @@ aur_request_ml = aur-requests@archlinux.org request_idle_time = 1209600 auto_orphan_age = 15552000 auto_delete_age = 86400 -pkgbuild_uri = https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=%s +source_file_uri = https://aur.archlinux.org/cgit/aur.git/tree/%s?h=%s log_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 030ec9a1..adb21f66 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -481,17 +481,19 @@ function pkg_rel_html($name, $cond, $arch) { * * @param string $url The URL of the source * @param string $arch The source architecture + * @param string $package The name of the package * * @return string The HTML code of the label to display */ -function pkg_source_link($url, $arch) { +function pkg_source_link($url, $arch, $package) { $url = explode('::', $url); $parsed_url = parse_url($url[0]); if (isset($parsed_url['scheme']) || isset($url[1])) { $link = '' . htmlspecialchars($url[0]) . ''; } else { - $link = htmlspecialchars($url[0]); + $file_url = sprintf(config_get('options', 'source_file_uri'), htmlspecialchars($url[0]), $package); + $link = '' . htmlspecialchars($url[0]) . ''; } if ($arch) { diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 32693948..ed8974a3 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -1,6 +1,6 @@
        -
      • +
      From f4176a8ce1e1b50e7f7d2ce660464caabbc6723f Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Tue, 14 Feb 2017 20:17:11 +0100 Subject: [PATCH 0318/1891] Make aurjson error messages consistent All error messages in aurjson except two end with a period. Add the missing periods to make the messages consistent. Signed-off-by: Michael Straube Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 3bd9179c..e07522d4 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -387,7 +387,7 @@ class AurJSON { if ($search_by === 'name' || $search_by === 'name-desc') { if (strlen($keyword_string) < 2) { - return $this->json_error('Query arg too small'); + return $this->json_error('Query arg too small.'); } $keyword_string = $this->dbh->quote("%" . addcslashes($keyword_string, '%_') . "%"); @@ -441,7 +441,7 @@ class AurJSON { $names = $args['names']; if (!$ids && !$names) { - return $this->json_error('Invalid query arguments'); + return $this->json_error('Invalid query arguments.'); } $where_condition = ""; From b3fdd3f80389e2708dc64414f0e48ef7120fd852 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 15 Feb 2017 07:13:01 +0100 Subject: [PATCH 0319/1891] Add a parameter to skip old requests to pkgreq_list() Allow for hiding requests which were opened before a given time stamp. Signed-off-by: Lukas Fleischer --- web/lib/pkgreqfuncs.inc.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index 7dcab135..774ebe7e 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -20,10 +20,11 @@ function pkgreq_count() { * @param int $offset The index of the first request to return * @param int $limit The maximum number of requests to return * @param int $uid Only return packages affecting the given user + * @param int $from Do not return packages older than the given date * - * @return array List of pacakge requests with details + * @return array List of package requests with details */ -function pkgreq_list($offset, $limit, $uid=false) { +function pkgreq_list($offset, $limit, $uid=false, $from=false) { $dbh = DB::connect(); $q = "SELECT PackageRequests.ID, "; @@ -37,9 +38,15 @@ function pkgreq_list($offset, $limit, $uid=false) { $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; $q.= "INNER JOIN Users ON Users.ID = PackageRequests.UsersID "; - if ($uid) { - $q.= "WHERE PackageRequests.UsersID = " . intval($uid). " "; - $q.= "OR Users.ID = " . intval($uid) . " "; + if ($uid || $from) { + $q.= "WHERE "; + if ($uid) { + $q.= "(PackageRequests.UsersID = " . intval($uid). " "; + $q.= "OR Users.ID = " . intval($uid) . ") AND "; + } + if ($from) { + $q.= "RequestTS >= " . intval($from). " "; + } } $q.= "ORDER BY Open DESC, RequestTS DESC "; From 92049e8061d71dfe89b4cbd53a39d7ae74ac328a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 15 Feb 2017 07:20:50 +0100 Subject: [PATCH 0320/1891] Hide old requests from the dashboard Only show package requests created less than 6 months ago on the dashboard. Signed-off-by: Lukas Fleischer --- conf/config.proto | 1 + web/html/home.php | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/config.proto b/conf/config.proto index 01a907a6..df10b995 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -25,6 +25,7 @@ max_rpc_results = 5000 max_depends = 1000 aur_request_ml = aur-requests@archlinux.org request_idle_time = 1209600 +request_archive_time = 15552000 auto_orphan_age = 15552000 auto_delete_age = 86400 source_file_uri = https://aur.archlinux.org/cgit/aur.git/tree/%s?h=%s diff --git a/web/html/home.php b/web/html/home.php index ee7caf77..26754916 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -35,7 +35,9 @@ if (isset($_COOKIE["AURSID"])) { ?>

      From e724b123ec003aab4a24ace4e7eea934a6dad395 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 15 Feb 2017 21:59:20 +0100 Subject: [PATCH 0321/1891] pkgbase.php: Add default title Instead of triggering a PHP warning and using an empty title if no package base is specified, use a default title. Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 11fdf74a..23aa6c83 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -30,7 +30,7 @@ if (!isset($base_id) || !isset($pkgbase_name)) { } /* Set the title to package base name. */ -$title = $pkgbase_name; +$title = isset($pkgbase_name) ? $pkgbase_name : __("Package Bases"); /* Grab the list of package base IDs to be operated on. */ $ids = array(); From 5059056567161d616496a015804094371bfb5b48 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 15 Feb 2017 22:05:03 +0100 Subject: [PATCH 0322/1891] Fix several PHP short open tags Use " --- web/html/pkgdel.php | 2 +- web/html/pkgdisown.php | 2 +- web/html/pkgflag.php | 2 +- web/html/pkgmerge.php | 2 +- web/template/comaintainers_form.php | 2 +- web/template/pkgreq_close_form.php | 2 +- web/template/pkgreq_form.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/web/html/pkgdel.php b/web/html/pkgdel.php index 21a2677c..591ccce8 100644 --- a/web/html/pkgdel.php +++ b/web/html/pkgdel.php @@ -12,7 +12,7 @@ html_header(__("Package Deletion")); if (has_credential(CRED_PKGBASE_DELETE)): ?>
      -

      :

      +

      :

      ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/html/pkgdisown.php b/web/html/pkgdisown.php index f24a2d6d..036fe6d8 100644 --- a/web/html/pkgdisown.php +++ b/web/html/pkgdisown.php @@ -15,7 +15,7 @@ $comaintainers = pkgbase_get_comaintainers($base_id); if (has_credential(CRED_PKGBASE_DISOWN, $maintainer_uids)): ?>

      -

      :

      +

      :

      ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php index f50c2085..44849d88 100644 --- a/web/html/pkgflag.php +++ b/web/html/pkgflag.php @@ -43,7 +43,7 @@ html_header(__("Flag Package Out-Of-Date")); if (has_credential(CRED_PKGBASE_FLAG)): ?>

      -

      :

      +

      :

      ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/html/pkgmerge.php b/web/html/pkgmerge.php index c0ce655c..e8e7ca93 100644 --- a/web/html/pkgmerge.php +++ b/web/html/pkgmerge.php @@ -12,7 +12,7 @@ html_header(__("Package Merging")); if (has_credential(CRED_PKGBASE_DELETE)): ?>

      -

      :

      +

      :

      ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/template/comaintainers_form.php b/web/template/comaintainers_form.php index 70a74645..79e2b52c 100644 --- a/web/template/comaintainers_form.php +++ b/web/template/comaintainers_form.php @@ -1,5 +1,5 @@

      -

      :

      +

      :

      ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/template/pkgreq_close_form.php b/web/template/pkgreq_close_form.php index 59e9c8f4..6077b325 100644 --- a/web/template/pkgreq_close_form.php +++ b/web/template/pkgreq_close_form.php @@ -1,5 +1,5 @@

      -

      :

      +

      :

      ', htmlspecialchars($pkgbase_name), ''); ?> diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php index 35dbef57..904ab48f 100644 --- a/web/template/pkgreq_form.php +++ b/web/template/pkgreq_form.php @@ -1,5 +1,5 @@

      -

      :

      +

      :

      ', htmlspecialchars($pkgbase_name), ''); ?> From 65b75568cb3bbab39e03335bc84153ac4ac0379c Mon Sep 17 00:00:00 2001 From: Morten Linderud Date: Thu, 19 Jan 2017 23:28:44 +0100 Subject: [PATCH 0323/1891] Add security tracker into navbar Signed-off-by: Morten Linderud Signed-off-by: Lukas Fleischer --- web/template/cgit/header.html | 1 + web/template/header.php | 1 + 2 files changed, 2 insertions(+) diff --git a/web/template/cgit/header.html b/web/template/cgit/header.html index 0217f2fd..2d418702 100644 --- a/web/template/cgit/header.html +++ b/web/template/cgit/header.html @@ -7,6 +7,7 @@

    • Forums
    • Wiki
    • Bugs
    • +
    • Security
    • AUR
    • Download
    diff --git a/web/template/header.php b/web/template/header.php index 7343575e..f7409400 100644 --- a/web/template/header.php +++ b/web/template/header.php @@ -24,6 +24,7 @@
  • Forums
  • Wiki
  • Bugs
  • +
  • Security
  • AUR
  • Download
  • From 08f56e76d7e203ce128ec6653280984e426f3811 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 23 Feb 2017 07:42:25 +0100 Subject: [PATCH 0324/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 70 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index bbe34d63..580a1310 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.3.0\n" +"Project-Id-Version: AUR v4.4.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" +"POT-Creation-Date: 2017-02-23 07:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -159,10 +159,38 @@ msgstr "" msgid "Edit comment" msgstr "" +#: html/home.php template/header.php +msgid "Dashboard" +msgstr "" + #: html/home.php template/header.php msgid "Home" msgstr "" +#: html/home.php +msgid "My Flagged Packages" +msgstr "" + +#: html/home.php +msgid "My Requests" +msgstr "" + +#: html/home.php +msgid "My Packages" +msgstr "" + +#: html/home.php +msgid "Search for packages I maintain" +msgstr "" + +#: html/home.php +msgid "Co-Maintained Packages" +msgstr "" + +#: html/home.php +msgid "Search for packages I co-maintain" +msgstr "" + #: html/home.php #, php-format msgid "" @@ -429,6 +457,10 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "" +#: html/pkgbase.php +msgid "Package Bases" +msgstr "" + #: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " @@ -723,6 +755,10 @@ msgstr "" msgid "Language is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Timezone is not currently supported." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." @@ -1125,6 +1161,11 @@ msgstr "" msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php template/tu_details.php +msgid "unknown" +msgstr "" + #: template/account_details.php msgid "Last Login" msgstr "" @@ -1189,6 +1230,10 @@ msgstr "" msgid "Language" msgstr "" +#: template/account_edit_form.php +msgid "Timezone" +msgstr "" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to " @@ -1294,10 +1339,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -#: template/header.php -msgid "My Packages" -msgstr "" - #: template/header.php msgid " My Account" msgstr "" @@ -1366,11 +1407,6 @@ msgstr[1] "" msgid "Adopt Package" msgstr "" -#: template/pkgbase_details.php template/pkg_details.php -#: template/pkgreq_results.php template/tu_details.php -msgid "unknown" -msgstr "" - #: template/pkgbase_details.php msgid "Package Base Details" msgstr "" @@ -1668,6 +1704,10 @@ msgstr "" msgid "Close" msgstr "" +#: template/pkgreq_results.php +msgid "Pending" +msgstr "" + #: template/pkgreq_results.php msgid "Closed" msgstr "" @@ -1688,6 +1728,14 @@ msgstr "" msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php +msgid "Co-maintainer" +msgstr "" + +#: template/pkg_search_form.php +msgid "Maintainer, Co-maintainer" +msgstr "" + #: template/pkg_search_form.php msgid "All" msgstr "" From 31754909b1ebbc2a50f1faecbb0cf5058953b840 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 24 Feb 2017 20:28:09 +0100 Subject: [PATCH 0325/1891] Fix user name in disown notifications Do not overwrite the $uid variable when updating co-maintainers. Fixes FS#52225. Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 4f102040..57b307d8 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -680,15 +680,15 @@ function pkgbase_adopt ($base_ids, $action=true, $via) { $comaintainers = pkgbase_get_comaintainers($base_id); if (count($comaintainers) > 0) { - $uid = uid_from_username($comaintainers[0]); + $comaintainer_uid = uid_from_username($comaintainers[0]); $comaintainers = array_diff($comaintainers, array($comaintainers[0])); pkgbase_set_comaintainers($base_id, $comaintainers); } else { - $uid = "NULL"; + $comaintainer_uid = "NULL"; } $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = " . $uid . " "; + $q.= "SET MaintainerUID = " . $comaintainer_uid . " "; $q.= "WHERE ID = " . $base_id; $dbh->exec($q); } From 29a48708bb7c3e00e80275a6b898f557f63dff69 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 24 Feb 2017 19:52:28 +0100 Subject: [PATCH 0326/1891] Use bcrypt to hash passwords Replace the default hash function used for storing passwords by password_hash() which internally uses bcrypt. Legacy MD5 hashes are still supported and are immediately converted to the new format when a user logs in. Since big parts of the authentication system needed to be rewritten in this context, this patch also includes some simplification and refactoring of all code related to password checking and resetting. Fixes FS#52297. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- upgrading/4.5.0.txt | 6 ++ web/html/passreset.php | 5 +- web/lib/acctfuncs.inc.php | 152 ++++++++++++++++---------------------- web/lib/aur.inc.php | 57 -------------- 5 files changed, 72 insertions(+), 150 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 99f90834..b75a257c 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -27,7 +27,7 @@ CREATE TABLE Users ( Username VARCHAR(32) NOT NULL, Email VARCHAR(254) NOT NULL, HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0, - Passwd CHAR(32) NOT NULL, + Passwd VARCHAR(255) NOT NULL, Salt CHAR(32) NOT NULL DEFAULT '', ResetKey CHAR(32) NOT NULL DEFAULT '', RealName VARCHAR(64) NOT NULL DEFAULT '', diff --git a/upgrading/4.5.0.txt b/upgrading/4.5.0.txt index fb0a2993..37b2b810 100644 --- a/upgrading/4.5.0.txt +++ b/upgrading/4.5.0.txt @@ -18,3 +18,9 @@ ALTER TABLE Users ---- ALTER TABLE Bans MODIFY IPAddress VARCHAR(45) NULL DEFAULT NULL; ---- + +4. Resize the Passwd column of the Users table: + +--- +ALTER TABLE Users MODIFY Passwd VARCHAR(255) NOT NULL; +--- diff --git a/web/html/passreset.php b/web/html/passreset.php index cb2f6bcd..e89967d4 100644 --- a/web/html/passreset.php +++ b/web/html/passreset.php @@ -34,10 +34,7 @@ if (isset($_GET['resetkey'], $_POST['email'], $_POST['password'], $_POST['confir } if (empty($error)) { - $salt = generate_salt(); - $hash = salted_hash($password, $salt); - - $error = password_reset($hash, $salt, $resetkey, $email); + $error = password_reset($password, $resetkey, $email); } } elseif (isset($_POST['email'])) { $email = $_POST['email']; diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index b3cf6122..d0a7ff94 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -272,13 +272,12 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" if ($TYPE == "new") { /* Create an unprivileged user. */ - $salt = generate_salt(); if (empty($P)) { $send_resetkey = true; $email = $E; } else { $send_resetkey = false; - $P = salted_hash($P, $salt); + $P = password_hash($P, PASSWORD_DEFAULT); } $U = $dbh->quote($U); $E = $dbh->quote($E); @@ -291,9 +290,9 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $I = $dbh->quote($I); $K = $dbh->quote(str_replace(" ", "", $K)); $q = "INSERT INTO Users (AccountTypeID, Suspended, "; - $q.= "InactivityTS, Username, Email, Passwd, Salt, "; + $q.= "InactivityTS, Username, Email, Passwd , "; $q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) "; - $q.= "VALUES (1, 0, 0, $U, $E, $P, $salt, $R, $L, $TZ "; + $q.= "VALUES (1, 0, 0, $U, $E, $P, $R, $L, $TZ "; $q.= "$HP, $I, $K)"; $result = $dbh->exec($q); if (!$result) { @@ -350,9 +349,8 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $q.= ", HideEmail = 0"; } if ($P) { - $salt = generate_salt(); - $hash = salted_hash($P, $salt); - $q .= ", Passwd = '$hash', Salt = '$salt'"; + $hash = password_hash($P, PASSWORD_DEFAULT); + $q .= ", Passwd = " . $dbh->quote($hash); } $q.= ", RealName = " . $dbh->quote($R); $q.= ", LangPreference = " . $dbh->quote($L); @@ -528,19 +526,24 @@ function try_login() { if (user_suspended($userID)) { $login_error = __('Account suspended'); return array('SID' => '', 'error' => $login_error); - } elseif (passwd_is_empty($userID)) { - $login_error = __('Your password has been reset. ' . - 'If you just created a new account, please ' . - 'use the link from the confirmation email ' . - 'to set an initial password. Otherwise, ' . - 'please request a reset key on the %s' . - 'Password Reset%s page.', '', - ''); - return array('SID' => '', 'error' => $login_error); - } elseif (!valid_passwd($userID, $_REQUEST['passwd'])) { - $login_error = __("Bad username or password."); - return array('SID' => '', 'error' => $login_error); + } + + switch (check_passwd($userID, $_REQUEST['passwd'])) { + case -1: + $login_error = __('Your password has been reset. ' . + 'If you just created a new account, please ' . + 'use the link from the confirmation email ' . + 'to set an initial password. Otherwise, ' . + 'please request a reset key on the %s' . + 'Password Reset%s page.', '', + ''); + return array('SID' => '', 'error' => $login_error); + case 0: + $login_error = __("Bad username or password."); + return array('SID' => '', 'error' => $login_error); + case 1: + break; } $logged_in = 0; @@ -736,18 +739,18 @@ function send_resetkey($email, $welcome=false) { /** * Change a user's password in the database if reset key and e-mail are correct * - * @param string $hash New MD5 hash of a user's password - * @param string $salt New salt for the user's password + * @param string $password The new password * @param string $resetkey Code e-mailed to a user to reset a password * @param string $email E-mail address of the user resetting their password * * @return string|void Redirect page if successful, otherwise return error message */ -function password_reset($hash, $salt, $resetkey, $email) { +function password_reset($password, $resetkey, $email) { + $hash = password_hash($password, PASSWORD_DEFAULT); + $dbh = DB::connect(); - $q = "UPDATE Users "; - $q.= "SET Passwd = '$hash', "; - $q.= "Salt = '$salt', "; + $q = "UPDATE Users SET "; + $q.= "Passwd = " . $dbh->quote($hash) . ", "; $q.= "ResetKey = '' "; $q.= "WHERE ResetKey != '' "; $q.= "AND ResetKey = " . $dbh->quote($resetkey) . " "; @@ -778,75 +781,48 @@ function good_passwd($passwd) { /** * Determine if the password is correct and salt it if it hasn't been already * - * @param string $userID The user ID to check the password against + * @param int $user_id The user ID to check the password against * @param string $passwd The password the visitor sent * - * @return bool True if password was correct and properly salted, otherwise false + * @return int Positive if password is correct, negative if password is unset */ -function valid_passwd($userID, $passwd) { - $dbh = DB::connect(); - if ($passwd == "") { - return false; - } - - /* Get salt for this user. */ - $salt = get_salt($userID); - if ($salt) { - $q = "SELECT ID FROM Users "; - $q.= "WHERE ID = " . $userID . " "; - $q.= "AND Passwd = " . $dbh->quote(salted_hash($passwd, $salt)); - $result = $dbh->query($q); - if (!$result) { - return false; - } - - $row = $result->fetch(PDO::FETCH_NUM); - return ($row[0] > 0); - } else { - /* Check password without using salt. */ - $q = "SELECT ID FROM Users "; - $q.= "WHERE ID = " . $userID . " "; - $q.= "AND Passwd = " . $dbh->quote(md5($passwd)); - $result = $dbh->query($q); - if (!$result) { - return false; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if (!$row[0]) { - return false; - } - - /* Password correct, but salt it first! */ - if (!save_salt($userID, $passwd)) { - trigger_error("Unable to salt user's password;" . - " ID " . $userID, E_USER_WARNING); - return false; - } - - return true; - } -} - -/** - * Determine if a user's password is empty - * - * @param string $uid The user ID to check for an empty password - * - * @return bool True if the user's password is empty, otherwise false - */ -function passwd_is_empty($uid) { +function check_passwd($user_id, $passwd) { $dbh = DB::connect(); - $q = "SELECT * FROM Users WHERE ID = " . $dbh->quote($uid) . " "; - $q .= "AND Passwd = " . $dbh->quote(''); + /* Get password hash and salt. */ + $q = "SELECT Passwd, Salt FROM Users WHERE ID = " . intval($user_id); $result = $dbh->query($q); - - if ($result->fetchColumn()) { - return true; - } else { - return false; + if (!$result) { + return 0; } + $row = $result->fetch(PDO::FETCH_ASSOC); + if (!$row) { + return 0; + } + $hash = $row['Passwd']; + $salt = $row['Salt']; + if (!$hash) { + return -1; + } + + /* Verify the password hash. */ + if (!password_verify($passwd, $hash)) { + /* Invalid password, fall back to MD5. */ + if (md5($salt . $passwd) != $hash) { + return 0; + } + } + + /* Password correct, migrate the hash if necessary. */ + if (password_needs_rehash($hash, PASSWORD_DEFAULT)) { + $hash = password_hash($passwd, PASSWORD_DEFAULT); + + $q = "UPDATE Users SET Passwd = " . $dbh->quote($hash) . " "; + $q.= "WHERE ID = " . intval($user_id); + $dbh->query($q); + } + + return 1; } /** diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 94a38499..d58df406 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -537,63 +537,6 @@ function mkurl($append) { return substr($out, 5); } -/** - * Determine a user's salt from the database - * - * @param string $user_id The user ID of the user trying to log in - * - * @return string|void Return the salt for the requested user, otherwise void - */ -function get_salt($user_id) { - $dbh = DB::connect(); - $q = "SELECT Salt FROM Users WHERE ID = " . $user_id; - $result = $dbh->query($q); - if ($result) { - $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; - } - return; -} - -/** - * Save a user's salted password in the database - * - * @param string $user_id The user ID of the user who is salting their password - * @param string $passwd The password of the user logging in - */ -function save_salt($user_id, $passwd) { - $dbh = DB::connect(); - $salt = generate_salt(); - $hash = salted_hash($passwd, $salt); - $q = "UPDATE Users SET Salt = " . $dbh->quote($salt) . ", "; - $q.= "Passwd = " . $dbh->quote($hash) . " WHERE ID = " . $user_id; - return $dbh->exec($q); -} - -/** - * Generate a string to be used for salting passwords - * - * @return string MD5 hash of concatenated random number and current time - */ -function generate_salt() { - return md5(uniqid(mt_rand(), true)); -} - -/** - * Combine salt and password to form a hash - * - * @param string $passwd User plaintext password - * @param string $salt MD5 hash to be used as user salt - * - * @return string The MD5 hash of the concatenated salt and user password - */ -function salted_hash($passwd, $salt) { - if (strlen($salt) != 32) { - trigger_error('Salt does not look like an md5 hash', E_USER_WARNING); - } - return md5($salt . $passwd); -} - /** * Get a package comment * From b205275196ca60e2809937b651db8d41c77b90ac Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 25 Feb 2017 13:03:10 +0100 Subject: [PATCH 0327/1891] pkgreq_results.php: Hide empty table Display a message that no requests matched the filter criteria instead of showing an empty package requests table. Signed-off-by: Lukas Fleischer --- web/template/pkgreq_results.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index 74fcb10d..fb49dfae 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -1,3 +1,6 @@ + +

    +

    @@ -129,3 +132,4 @@

    + From d0a7a70e2dd06defeef78660ae4efb803c94d859 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 25 Feb 2017 13:41:22 +0100 Subject: [PATCH 0328/1891] Update message catalog --- po/aur.pot | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/po/aur.pot b/po/aur.pot index 580a1310..1434ab15 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: AUR v4.4.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-23 07:42+0100\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1650,6 +1650,10 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php +msgid "No requests matched your search criteria." +msgstr "" + #: template/pkgreq_results.php #, php-format msgid "%d package request found." From e4bc2e7af318a9b2876b0021a8dc8dcf72661e62 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 26 Feb 2017 10:28:03 +0100 Subject: [PATCH 0329/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 55 ++++++++++++++++--- po/ast.po | 55 ++++++++++++++++--- po/ca.po | 55 ++++++++++++++++--- po/cs.po | 55 ++++++++++++++++--- po/da.po | 55 ++++++++++++++++--- po/de.po | 135 +++++++++++++++++++++++++++++++++-------------- po/el.po | 55 ++++++++++++++++--- po/es.po | 64 ++++++++++++++++++----- po/es_419.po | 64 ++++++++++++++++++----- po/fi.po | 55 ++++++++++++++++--- po/fr.po | 57 ++++++++++++++++---- po/he.po | 55 ++++++++++++++++--- po/hr.po | 55 ++++++++++++++++--- po/hu.po | 55 ++++++++++++++++--- po/it.po | 55 ++++++++++++++++--- po/ja.po | 68 +++++++++++++++++++----- po/nb.po | 65 ++++++++++++++++++----- po/nl.po | 55 ++++++++++++++++--- po/pl.po | 72 ++++++++++++++++++++----- po/pt_BR.po | 57 ++++++++++++++++---- po/pt_PT.po | 55 ++++++++++++++++--- po/ro.po | 55 ++++++++++++++++--- po/ru.po | 55 ++++++++++++++++--- po/sk.po | 145 +++++++++++++++++++++++++++++++++++---------------- po/sr.po | 57 ++++++++++++++++---- po/tr.po | 63 +++++++++++++++++----- po/uk.po | 107 +++++++++++++++++++++++++------------ po/zh_CN.po | 55 ++++++++++++++++--- po/zh_TW.po | 57 ++++++++++++++++---- 29 files changed, 1536 insertions(+), 355 deletions(-) diff --git a/po/ar.po b/po/ar.po index 7258e645..02a03770 100644 --- a/po/ar.po +++ b/po/ar.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" "ar/)\n" @@ -127,9 +127,30 @@ msgstr "أدر المصينين المشاركين" msgid "Edit comment" msgstr "حرّر التّعليق" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "الرّئيسيّة" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "حزمي" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -365,6 +386,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "أدخل عنوان بريدك الإلكترونيّ:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -596,6 +620,9 @@ msgstr "لا يمكن زيادة صلاحيّات الحساب." msgid "Language is not currently supported." msgstr "اللغة غير مدعومة حاليًّا." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "اسم المستخدم %s%s%s مستخدم بالفعل." @@ -900,6 +927,9 @@ msgstr "نشط" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "مجهول" + msgid "Last Login" msgstr "آخر ولوج" @@ -949,6 +979,9 @@ msgstr "أعد كتابة كلمة المرور" msgid "Language" msgstr "اللغة" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1029,9 +1062,6 @@ msgstr "عُد إلى التّفاصيل" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "الحقوق محفوظة %s 2004-%d فريق تطوير aurweb." -msgid "My Packages" -msgstr "حزمي" - msgid " My Account" msgstr "حسابي" @@ -1088,9 +1118,6 @@ msgstr[5] "%d طلب منتظر" msgid "Adopt Package" msgstr "تبنّ الحزمة" -msgid "unknown" -msgstr "مجهول" - msgid "Package Base Details" msgstr "تفاصيل أساس الحزمة" @@ -1276,6 +1303,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1331,6 +1361,9 @@ msgstr "" msgid "Close" msgstr "أغلق" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "مغلق" @@ -1346,6 +1379,12 @@ msgstr "الاسم بالضّبط" msgid "Exact Package Base" msgstr "أساس الحزمة بالضّبط" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "الكلّ" diff --git a/po/ast.po b/po/ast.po index 2a80e03e..760aec42 100644 --- a/po/ast.po +++ b/po/ast.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" "ast/)\n" @@ -127,9 +127,30 @@ msgstr "" msgid "Edit comment" msgstr "" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Aniciu" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Los mios paquetes" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -349,6 +370,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Introduz la to direción de corréu:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -579,6 +603,9 @@ msgstr "Nun puen aumentase los permisos de la cuenta." msgid "Language is not currently supported." msgstr "La llingua nun ta anguaño sofitada." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nome d'usuariu, %s%s%s, yá ta n'usu." @@ -882,6 +909,9 @@ msgstr "Activu" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "Desconocíu" + msgid "Last Login" msgstr "" @@ -931,6 +961,9 @@ msgstr "Teclexa de nueves la contraseña" msgid "Language" msgstr "Llingua" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1012,9 +1045,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Los mios paquetes" - msgid " My Account" msgstr "La mio cuenta" @@ -1067,9 +1097,6 @@ msgstr[1] "" msgid "Adopt Package" msgstr "" -msgid "unknown" -msgstr "Desconocíu" - msgid "Package Base Details" msgstr "Detalles del paquete base" @@ -1255,6 +1282,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1298,6 +1328,9 @@ msgstr "Bloquiáu" msgid "Close" msgstr "Zarrar" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Zarráu" @@ -1313,6 +1346,12 @@ msgstr "Nome exautu" msgid "Exact Package Base" msgstr "Paquete base exautu" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Too" diff --git a/po/ca.po b/po/ca.po index 3cab9e51..c3c868fd 100644 --- a/po/ca.po +++ b/po/ca.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" "ca/)\n" @@ -127,9 +127,30 @@ msgstr "" msgid "Edit comment" msgstr "" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Inici" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Els meus paquets" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -347,6 +368,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Introduiu la vostra adreça de correu." +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -579,6 +603,9 @@ msgstr "No es possible augmentar els permisos del compte." msgid "Language is not currently supported." msgstr "L'idioma no està suportat actualment." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nom d'usuari, %s%s%s, ja s'està fent servir." @@ -887,6 +914,9 @@ msgstr "Actiu" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "desconegut" + msgid "Last Login" msgstr "" @@ -936,6 +966,9 @@ msgstr "Escriu altre cop la contrasenya" msgid "Language" msgstr "Idioma" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1016,9 +1049,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Els meus paquets" - msgid " My Account" msgstr "El meu Compte" @@ -1071,9 +1101,6 @@ msgstr[1] "" msgid "Adopt Package" msgstr "Adoptar Paquet" -msgid "unknown" -msgstr "desconegut" - msgid "Package Base Details" msgstr "" @@ -1257,6 +1284,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1300,6 +1330,9 @@ msgstr "" msgid "Close" msgstr "" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "" @@ -1315,6 +1348,12 @@ msgstr "" msgid "Exact Package Base" msgstr "" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Tots" diff --git a/po/cs.po b/po/cs.po index d5abe1c4..51e6e2c0 100644 --- a/po/cs.po +++ b/po/cs.po @@ -11,8 +11,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" "Language: cs\n" @@ -127,9 +127,30 @@ msgstr "" msgid "Edit comment" msgstr "Upravit komentář" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Domů" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Moje balíčky" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -343,6 +364,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Zadejte emailovou adresu:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -569,6 +593,9 @@ msgstr "" msgid "Language is not currently supported." msgstr "Jazyk není momentálné podporován." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" @@ -869,6 +896,9 @@ msgstr "Aktivní" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "neznámý" + msgid "Last Login" msgstr "Poslední přihlášení" @@ -918,6 +948,9 @@ msgstr "Heslo znovu" msgid "Language" msgstr "Jazyk" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -998,9 +1031,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Moje balíčky" - msgid " My Account" msgstr "Můj účet" @@ -1054,9 +1084,6 @@ msgstr[2] "%d čekajících požadavků" msgid "Adopt Package" msgstr "Adoptovat balíček" -msgid "unknown" -msgstr "neznámý" - msgid "Package Base Details" msgstr "" @@ -1240,6 +1267,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1286,6 +1316,9 @@ msgstr "Zamčeno" msgid "Close" msgstr "Uzavřít" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Uzavřeno" @@ -1301,6 +1334,12 @@ msgstr "Přesné jméno" msgid "Exact Package Base" msgstr "" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Vše" diff --git a/po/da.po b/po/da.po index 2f31a152..59de0846 100644 --- a/po/da.po +++ b/po/da.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" "da/)\n" @@ -126,9 +126,30 @@ msgstr "" msgid "Edit comment" msgstr "" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Hjem" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Mine pakker" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -338,6 +359,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Indtast din mail-adresse:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -564,6 +588,9 @@ msgstr "" msgid "Language is not currently supported." msgstr "Sproget er ikke understøttet på nuværende tidspunkt." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" @@ -863,6 +890,9 @@ msgstr "Aktiv" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "ukendt" + msgid "Last Login" msgstr "Sidste login" @@ -912,6 +942,9 @@ msgstr "Bekræft adgangskode" msgid "Language" msgstr "Sprog" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -992,9 +1025,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Mine pakker" - msgid " My Account" msgstr "Min konto" @@ -1047,9 +1077,6 @@ msgstr[1] "" msgid "Adopt Package" msgstr "Adopter pakke" -msgid "unknown" -msgstr "ukendt" - msgid "Package Base Details" msgstr "" @@ -1233,6 +1260,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1276,6 +1306,9 @@ msgstr "Låst" msgid "Close" msgstr "Luk" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Lukket" @@ -1291,6 +1324,12 @@ msgstr "Præcist navn" msgid "Exact Package Base" msgstr "" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Alle" diff --git a/po/de.po b/po/de.po index 5aa6e538..7eb709b9 100644 --- a/po/de.po +++ b/po/de.po @@ -7,7 +7,7 @@ # Alexander Griesbaum , 2013-2014 # bjo , 2013 # FabianS_ , 2012 -# go2sh , 2015 +# go2sh , 2015-2016 # FabianS_ , 2012 # Giuliano Schneider , 2015-2016 # go2sh , 2015 @@ -18,15 +18,16 @@ # Nuc1eoN , 2014 # Nuc1eoN , 2014 # Simon Schneider , 2011 +# Stefan Auditor , 2017 # Thomas_Do , 2013-2014 # Thomas_Do , 2012-2013 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 16:16+0000\n" +"Last-Translator: Stefan Auditor \n" "Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" "de/)\n" "Language: de\n" @@ -45,15 +46,15 @@ msgid "Note" msgstr "Anmerkung" msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "Git clone URLs sind nicht dafür gedacht im Browser geöffnet zu werden." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Um das Git Repository von %s zu clonen, führe %s aus." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Klicke %shere%s um zur %s Detailseite zurückzukehren." msgid "Service Unavailable" msgstr "Dienst nicht verfügbr" @@ -144,9 +145,30 @@ msgstr "Verwalte Ko-Maintainer" msgid "Edit comment" msgstr "Kommentar bearbeiten" +msgid "Dashboard" +msgstr "Dashboard" + msgid "Home" msgstr "Startseite" +msgid "My Flagged Packages" +msgstr "Mein markierten Pakete" + +msgid "My Requests" +msgstr "Meine Anfragen" + +msgid "My Packages" +msgstr "Meine Pakete" + +msgid "Search for packages I maintain" +msgstr "Suche nach Paketen die ich betreue" + +msgid "Co-Maintained Packages" +msgstr "Ko-Maintainer Pakete" + +msgid "Search for packages I co-maintain" +msgstr "Suche nach Paketen die ich betreue ko-maintaine" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -201,7 +223,7 @@ msgstr "" "Paketdetailseite eingereicht werden können:" msgid "Orphan Request" -msgstr "Verweisungsanfrage" +msgstr "Verwaisanfrage" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " @@ -211,7 +233,7 @@ msgstr "" "das Paket vor einer ganzen Weile als veraltet makiert wurde." msgid "Deletion Request" -msgstr "Lösch-Antrag" +msgstr "Löschanfrage" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " @@ -396,6 +418,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Gib Deine E-Mail-Adresse ein:" +msgid "Package Bases" +msgstr "Paketbasis" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -481,7 +506,7 @@ msgid "Only Trusted Users and Developers can disown packages." msgstr "Nur Tus und Developer können die Paket-Betreuung abgeben." msgid "Flag Comment" -msgstr "" +msgstr "Kommentar markieren" msgid "Flag Package Out-Of-Date" msgstr "Paket als \"veraltet\" makieren" @@ -557,7 +582,7 @@ msgstr "" "Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." msgid "Submit Request" -msgstr "" +msgstr "Anfrage absenden" msgid "Close Request" msgstr "Anfrage schließen" @@ -653,6 +678,9 @@ msgstr "Die Zugriffsrechte des Kontos können nicht erweitert werden." msgid "Language is not currently supported." msgstr "Diese Sprache wird momentan noch nicht unterstützt." +msgid "Timezone is not currently supported." +msgstr "Diese Zeitzone wird momentan noch nicht unterstützt." + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Der Nutzername %s%s%s ist bereits vergeben." @@ -747,19 +775,19 @@ msgid "Missing comment ID." msgstr "Kommentar-ID fehlt." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "Mehr als 5 Kommentare können nicht angeheftet werden." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Du bist nicht berechtigt diesen Kommentar anzuheften." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "Du bist nicht berechtigt diesen Kommentar loszuheften." msgid "Comment has been pinned." -msgstr "" +msgstr "Kommentar wurde angeheftet." msgid "Comment has been unpinned." -msgstr "" +msgstr "Kommentar wurde losgeheftet." msgid "Error retrieving package details." msgstr "Fehler beim Aufrufen der Paket-Details." @@ -943,7 +971,7 @@ msgid "Real Name" msgstr "Echter Name" msgid "Homepage" -msgstr "" +msgstr "Homepage" msgid "IRC Nick" msgstr "IRC-Name" @@ -961,7 +989,10 @@ msgid "Active" msgstr "Aktiv" msgid "Registration date:" -msgstr "" +msgstr "Registrierungsdatum:" + +msgid "unknown" +msgstr "unbekannt" msgid "Last Login" msgstr "Letzter Login" @@ -982,7 +1013,7 @@ msgstr "" #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "Klicke %shere%s für Benutzerdetails." msgid "required" msgstr "Notwendig" @@ -1015,6 +1046,9 @@ msgstr "Bestätige das Passwort" msgid "Language" msgstr "Sprache" +msgid "Timezone" +msgstr "Zeitzone" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1026,16 +1060,16 @@ msgid "SSH Public Key" msgstr "Öffentlicher SSH Schlüssel" msgid "Notification settings" -msgstr "" +msgstr "Benachrichtigungseinstellungen" msgid "Notify of new comments" msgstr "Über neue Kommentare benachrichtigen" msgid "Notify of package updates" -msgstr "" +msgstr "Benachrichtige Paketaktualisierungen" msgid "Notify of ownership changes" -msgstr "" +msgstr "Benachrichtige Besitzeränderungen" msgid "Update" msgstr "Aktualisieren" @@ -1047,7 +1081,7 @@ msgid "Reset" msgstr "Zurücksetzen" msgid "No results matched your search criteria." -msgstr "Deine Suche enthält leider keine Ergebnisse." +msgstr "Die Suchkriterien erzielten keine Treffer." msgid "Edit Account" msgstr "Konto bearbeiten" @@ -1082,26 +1116,23 @@ msgstr "Speichern" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Markiert als \"veraltet\" Kommentar: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" +msgstr "%s%s%s markiert %s%s%s als \"veraltet\" am %s%s%s auf Grund von:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s wurde nicht als \"veraltet\" markiert." msgid "Return to Details" -msgstr "" +msgstr "Zu den Details zurückkehren" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." -msgid "My Packages" -msgstr "Meine Pakete" - msgid " My Account" msgstr "Mein Konto" @@ -1140,7 +1171,7 @@ msgid "Disable notifications" msgstr "Benachrichtigungen deaktivieren" msgid "Enable notifications" -msgstr "" +msgstr "Benachritigungen aktivieren" msgid "Manage Co-Maintainers" msgstr "Verwalte Ko-Maintainer" @@ -1154,9 +1185,6 @@ msgstr[1] "%d ausstehende Anfragen" msgid "Adopt Package" msgstr "Paket übernehmen" -msgid "unknown" -msgstr "unbekannt" - msgid "Package Base Details" msgstr "Paketbasis Details" @@ -1201,7 +1229,7 @@ msgid "View all comments" msgstr "Zeige alle Kommentare" msgid "Pinned Comments" -msgstr "" +msgstr "Angeheftete Kommentare" msgid "Latest Comments" msgstr "Neueste Kommentare" @@ -1237,10 +1265,10 @@ msgid "Delete comment" msgstr "Kommentar löschen" msgid "Pin comment" -msgstr "" +msgstr "Kommentar anheften" msgid "Unpin comment" -msgstr "" +msgstr "Kommentar losheften" msgid "All comments" msgstr "Alle Kommentare" @@ -1331,6 +1359,10 @@ msgid "" "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +"Durch das Absenden einer Löschanfrage wird ein vertrauenswürdiger Benutzer " +"gefragt die Paketbasis zu löschen. Dieser Typ von Anfragen soll für doppelte " +"Pakete, vom Upstream aufgegebene Software sowie illegale und unreparierbar " +"kaputte Pakete verwendet werden." msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " @@ -1338,6 +1370,11 @@ msgid "" "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." msgstr "" +"Durch das Absenden einer Zusammenfüranfrage wird ein vertrauenswürdiger " +"Benutzer gefragt die Paketbasis zu löschen und die Stimmen und Kommentare zu " +"einer anderen Paketbasis zu transferieren. Das Zusammenführen eines Paketes " +"betrifft nicht die zugehörigen Git Repositories. Stelle sicher, dass die Git " +"Historie des Zielpakets von dir aktualisiert wird." msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " @@ -1345,6 +1382,13 @@ msgid "" "the maintainer is MIA and you already tried to contact the maintainer " "previously." msgstr "" +"Durch das absenden eines Verwaisanfrage wird ein vertrauenswürdiger Benutzer " +"gefragt die Paketbasis zu enteignen. Bitte mache das nur, wenn das Paket " +"Aktionen vom Betreuer braucht, der Betreuer nicht reagiert und du ihn vorher " +"bereits versucht hast zu kontaktieren." + +msgid "No requests matched your search criteria." +msgstr "Die Suchkriterien erzielten keine Treffer in Anfragen." #, php-format msgid "%d package request found." @@ -1368,8 +1412,8 @@ msgstr "Datum" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "noch ~%d Tag" +msgstr[1] "noch ~%d Tage" #, php-format msgid "~%d hour left" @@ -1389,6 +1433,9 @@ msgstr "Gesperrt" msgid "Close" msgstr "Schließen" +msgid "Pending" +msgstr "Ausstehend" + msgid "Closed" msgstr "Geschlossen" @@ -1404,6 +1451,12 @@ msgstr "Exakter Name" msgid "Exact Package Base" msgstr "Exakte Paketbasis" +msgid "Co-maintainer" +msgstr "Ko-Maintainer" + +msgid "Maintainer, Co-maintainer" +msgstr "Betreuer, Ko-Maintainer" + msgid "All" msgstr "Alle" @@ -1456,7 +1509,7 @@ msgid "Error retrieving package list." msgstr "Fehler beim Aufrufen der Paket-Liste." msgid "No packages matched your search criteria." -msgstr "Keine Pakete entsprachen deinen Suchkriterien." +msgstr "Die Suchkriterien erzielten keine Treffer in Pakete." #, php-format msgid "%d package found." @@ -1472,6 +1525,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"Die Beliebtheit wird als die Summe aller Stimmen berechnet, wobei jede " +"Stimme mit dem Faktor %.2f pro Tag seit der Erstellung gewichtet wird." msgid "Yes" msgstr "Ja" diff --git a/po/el.po b/po/el.po index 254c02a1..b4d7902c 100644 --- a/po/el.po +++ b/po/el.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" "Language: el\n" @@ -131,9 +131,30 @@ msgstr "" msgid "Edit comment" msgstr "" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Αρχική" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Τα πακέτα μου" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -354,6 +375,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Εισάγετε την διεύθυνση e-mail σας:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -587,6 +611,9 @@ msgstr "Δε γίνεται να αυξηθούν τα δικαιώματα το msgid "Language is not currently supported." msgstr "Η γλώσσα αυτή δεν υποστηρίζεται ακόμη." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Το όνομα, %s%s%s, χρησιμοποιείται ήδη." @@ -899,6 +926,9 @@ msgstr "Ενεργός" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "άγνωστο" + msgid "Last Login" msgstr "Τελευταία σύνδεση" @@ -948,6 +978,9 @@ msgstr "Πληκτρολογήστε ξανά τον κωδικό σας." msgid "Language" msgstr "Γλώσσα" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1028,9 +1061,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Τα πακέτα μου" - msgid " My Account" msgstr "Ο λογαριασμός μου" @@ -1083,9 +1113,6 @@ msgstr[1] "" msgid "Adopt Package" msgstr "Υιοθετήστε το Πακέτο" -msgid "unknown" -msgstr "άγνωστο" - msgid "Package Base Details" msgstr "" @@ -1269,6 +1296,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1312,6 +1342,9 @@ msgstr "" msgid "Close" msgstr "" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "" @@ -1327,6 +1360,12 @@ msgstr "" msgid "Exact Package Base" msgstr "" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Όλα" diff --git a/po/es.po b/po/es.po index c61e657d..a141ff57 100644 --- a/po/es.po +++ b/po/es.po @@ -18,8 +18,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" "es/)\n" @@ -40,14 +40,15 @@ msgstr "Nota" msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +"Las direcciones de clonado de Git no deberían ser habiertas en un navegador." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Para clonar el repositorio Git de %s, ejecuta %s." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Haz clic %saquí%s para regresar a la página de detalles de %s." msgid "Service Unavailable" msgstr "Servicio no disponible" @@ -137,9 +138,30 @@ msgstr "Administrar coencargados" msgid "Edit comment" msgstr "Editar comentario" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Inicio" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Mis paquetes" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -387,6 +409,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Introduce tu dirección de correo:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -640,6 +665,9 @@ msgstr "No se puede incrementar los permisos de la cuenta." msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." @@ -953,7 +981,10 @@ msgid "Active" msgstr "Activo" msgid "Registration date:" -msgstr "" +msgstr "Fecha de registración:" + +msgid "unknown" +msgstr "desconocido" msgid "Last Login" msgstr "Última autentificación" @@ -973,7 +1004,7 @@ msgstr "Haz clic %saquí%s si deseas eliminar permanentemente esta cuenta." #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "Haz clic %saquí%s para ver los detalles del usuario." msgid "required" msgstr "obligatorio" @@ -1006,6 +1037,9 @@ msgstr "Reescribe la contraseña" msgid "Language" msgstr "Idioma" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1094,9 +1128,6 @@ msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" "Derechos de autor %s 2004 - %d, equipo desarrollador de la web del AUR." -msgid "My Packages" -msgstr "Mis paquetes" - msgid " My Account" msgstr "Mi cuenta" @@ -1149,9 +1180,6 @@ msgstr[1] "Hay %d solicitudes pendientes" msgid "Adopt Package" msgstr "Adoptar paquete" -msgid "unknown" -msgstr "desconocido" - msgid "Package Base Details" msgstr "Detalles del paquete base" @@ -1354,6 +1382,9 @@ msgstr "" "mantenención, el encargado no presenta signos de actividad y ya intentaste " "ponerte en contacto con él anteriormente." +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1397,6 +1428,9 @@ msgstr "Bloqueada" msgid "Close" msgstr "Cerrar" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Cerrada" @@ -1412,6 +1446,12 @@ msgstr "Nombre exacto" msgid "Exact Package Base" msgstr "Paquete base exacto" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Todos" diff --git a/po/es_419.po b/po/es_419.po index 14adaf94..d065cf9c 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -16,8 +16,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" "aur/language/es_419/)\n" @@ -38,14 +38,15 @@ msgstr "Nota" msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +"Las direcciones de clonado de Git no deberían ser habiertas en un navegador." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Para clonar el repositorio Git de %s, ejecute %s." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Haga clic %saquí%s para regresar a la página de detalles de %s." msgid "Service Unavailable" msgstr "Servicio no disponible" @@ -135,9 +136,30 @@ msgstr "Administrar coencargados" msgid "Edit comment" msgstr "Editar comentario" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Inicio" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Mis paquetes" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -384,6 +406,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Introduzca su dirección de correo:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -636,6 +661,9 @@ msgstr "No se puede incrementar los permisos de la cuenta." msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." @@ -946,7 +974,10 @@ msgid "Active" msgstr "Activo" msgid "Registration date:" -msgstr "" +msgstr "Fecha de registración:" + +msgid "unknown" +msgstr "desconocido" msgid "Last Login" msgstr "Última autentificación" @@ -966,7 +997,7 @@ msgstr "Haga clic %saquí%s si desea borrar permanentemente esa cuenta." #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "Haga clic %saquí%s para ver los detalles del usuario." msgid "required" msgstr "obligatorio" @@ -999,6 +1030,9 @@ msgstr "Reescriba la contraseña" msgid "Language" msgstr "Idioma" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1086,9 +1120,6 @@ msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" "Derechos de autor %s 2004 - %d, equipo de desarrollo de la web del AUR." -msgid "My Packages" -msgstr "Mis paquetes" - msgid " My Account" msgstr "Mi cuenta" @@ -1141,9 +1172,6 @@ msgstr[1] "Hay %d peticiones pendientes" msgid "Adopt Package" msgstr "Adoptar paquete" -msgid "unknown" -msgstr "desconocido" - msgid "Package Base Details" msgstr "Detalles del paquete base" @@ -1346,6 +1374,9 @@ msgstr "" "mantenención para funcionar, el encargado no presenta da de actividad y ya " "intentó ponerse en contacto con él anteriormente." +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1389,6 +1420,9 @@ msgstr "Bloqueada" msgid "Close" msgstr "Cerrar" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Cerrada" @@ -1404,6 +1438,12 @@ msgstr "Nombre exacto" msgid "Exact Package Base" msgstr "Paquete base exacto" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Todos" diff --git a/po/fi.po b/po/fi.po index 6e20ae22..86601c0f 100644 --- a/po/fi.po +++ b/po/fi.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" "fi/)\n" @@ -126,9 +126,30 @@ msgstr "" msgid "Edit comment" msgstr "Muokkaa kommenttia" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Etusivu" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Omat paketit" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -368,6 +389,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Sähköpostiosoitteesi:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -616,6 +640,9 @@ msgstr "Käyttäjätunnuksen oikeuksia ei voitu korottaa." msgid "Language is not currently supported." msgstr "Kieli ei ole vielä tuettuna." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Käyttäjänimi %s%s%s on jo käytössä." @@ -917,6 +944,9 @@ msgstr "Aktiivinen" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "tuntematon" + msgid "Last Login" msgstr "" @@ -966,6 +996,9 @@ msgstr "Salasana uudelleen:" msgid "Language" msgstr "Kieli" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1046,9 +1079,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Omat paketit" - msgid " My Account" msgstr "Omat tiedot" @@ -1101,9 +1131,6 @@ msgstr[1] "%d käsittelemätöntä hallintapyyntöä" msgid "Adopt Package" msgstr "Ryhdy ylläpitäjäksi" -msgid "unknown" -msgstr "tuntematon" - msgid "Package Base Details" msgstr "" @@ -1287,6 +1314,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1330,6 +1360,9 @@ msgstr "" msgid "Close" msgstr "" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "" @@ -1345,6 +1378,12 @@ msgstr "" msgid "Exact Package Base" msgstr "" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Kaikki" diff --git a/po/fr.po b/po/fr.po index 0c10f9fb..0bb3ccd4 100644 --- a/po/fr.po +++ b/po/fr.po @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-11 20:06+0000\n" -"Last-Translator: Antoine Lubineau \n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" "fr/)\n" "Language: fr\n" @@ -136,9 +136,30 @@ msgstr "Gérer les co-mainteneurs" msgid "Edit comment" msgstr "Éditer le commentaire" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Accueil" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Mes paquets" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -387,6 +408,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Entrez votre adresse e-mail :" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -645,6 +669,9 @@ msgstr "Ne peut pas augmenter les autorisations du compte." msgid "Language is not currently supported." msgstr "Cette langue n'est pas supportée pour le moment." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Le nom d’utilisateur %s%s%s, est déjà utilisé." @@ -967,6 +994,9 @@ msgstr "Actif" msgid "Registration date:" msgstr "Date d'enregistrement :" +msgid "unknown" +msgstr "inconnu" + msgid "Last Login" msgstr "Dernière connexion." @@ -1018,6 +1048,9 @@ msgstr "Retapez le mot de passe" msgid "Language" msgstr "Langue" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1103,9 +1136,6 @@ msgstr "Retourner aux détails" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." -msgid "My Packages" -msgstr "Mes paquets" - msgid " My Account" msgstr "Mon compte" @@ -1158,9 +1188,6 @@ msgstr[1] "%d requêtes en attente" msgid "Adopt Package" msgstr "Adopter ce paquet" -msgid "unknown" -msgstr "inconnu" - msgid "Package Base Details" msgstr "Détails du paquet de base" @@ -1363,6 +1390,9 @@ msgstr "" "mainteneur ne répond pas et que vous avez préalablement essayé de contacter " "le mainteneur." +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1406,6 +1436,9 @@ msgstr "Verrouillé" msgid "Close" msgstr "Fermer" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Fermé" @@ -1421,6 +1454,12 @@ msgstr "Nom exact" msgid "Exact Package Base" msgstr "Paquet de base exact" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Tout" diff --git a/po/he.po b/po/he.po index 75321be6..2cf535a1 100644 --- a/po/he.po +++ b/po/he.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" "he/)\n" @@ -127,9 +127,30 @@ msgstr "ניהול שותפים לתחזוקה" msgid "Edit comment" msgstr "עריכת תגובה" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "בית" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "החבילות שלי" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -353,6 +374,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "נא להזין את כתובת הדוא״ל שלך:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -583,6 +607,9 @@ msgstr "לא ניתן להגדיל את הרשאות החשבון." msgid "Language is not currently supported." msgstr "שפה כרגע לא נתמכת." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "שם המשתמש, %s%s%s, כבר נמצא בשימוש." @@ -884,6 +911,9 @@ msgstr "פעיל" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "לא מוכר" + msgid "Last Login" msgstr "כניסה אחרונה" @@ -933,6 +963,9 @@ msgstr "הקלדת הססמה מחדש" msgid "Language" msgstr "שפה" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1014,9 +1047,6 @@ msgstr "חזרה לפרטים" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "כל הזכויות שמורות %s 2004-%d לצוות הפיתוח של aurweb." -msgid "My Packages" -msgstr "החבילות שלי" - msgid " My Account" msgstr "החשבון שלי" @@ -1069,9 +1099,6 @@ msgstr[1] "%d בקשות ממתינות" msgid "Adopt Package" msgstr "אימוץ חבילה" -msgid "unknown" -msgstr "לא מוכר" - msgid "Package Base Details" msgstr "פרטי בסיס החבילה" @@ -1255,6 +1282,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1298,6 +1328,9 @@ msgstr "ננעל" msgid "Close" msgstr "סגירה" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "סגור" @@ -1313,6 +1346,12 @@ msgstr "שם מדויק" msgid "Exact Package Base" msgstr "בסיס החבילה המדויק" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "הכול" diff --git a/po/hr.po b/po/hr.po index 2bf3963c..71a1ae82 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" "hr/)\n" @@ -126,9 +126,30 @@ msgstr "" msgid "Edit comment" msgstr "" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Početna" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Moji paketi" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -338,6 +359,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -564,6 +588,9 @@ msgstr "" msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" @@ -863,6 +890,9 @@ msgstr "Aktivan" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "nepoznato" + msgid "Last Login" msgstr "" @@ -912,6 +942,9 @@ msgstr "Ponovno upišite lozinku" msgid "Language" msgstr "Jezik" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -992,9 +1025,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Moji paketi" - msgid " My Account" msgstr "" @@ -1048,9 +1078,6 @@ msgstr[2] "" msgid "Adopt Package" msgstr "" -msgid "unknown" -msgstr "nepoznato" - msgid "Package Base Details" msgstr "" @@ -1234,6 +1261,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1280,6 +1310,9 @@ msgstr "" msgid "Close" msgstr "" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "" @@ -1295,6 +1328,12 @@ msgstr "" msgid "Exact Package Base" msgstr "" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "" diff --git a/po/hu.po b/po/hu.po index a2320696..4501a4aa 100644 --- a/po/hu.po +++ b/po/hu.po @@ -11,8 +11,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" "hu/)\n" @@ -129,9 +129,30 @@ msgstr "Társkarbantartók kezelése" msgid "Edit comment" msgstr "Hozzászólás szerkesztése" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Honlap" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Csomagjaim" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -376,6 +397,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Add meg az e-mail címedet:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -629,6 +653,9 @@ msgstr "Nem lehet megnövelni a fiók jogosultságait." msgid "Language is not currently supported." msgstr "A nyelv jelenleg nem támogatott." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "A(z) %s%s%s felhasználónév már használatban van." @@ -935,6 +962,9 @@ msgstr "Aktív" msgid "Registration date:" msgstr "Regisztráció dátuma:" +msgid "unknown" +msgstr "ismeretlen" + msgid "Last Login" msgstr "Legutóbbi bejelentkezés" @@ -986,6 +1016,9 @@ msgstr "Megismételt jelszó" msgid "Language" msgstr "Nyelv" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1072,9 +1105,6 @@ msgstr "Vissza a részletekhez" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb fejlesztői csapat." -msgid "My Packages" -msgstr "Csomagjaim" - msgid " My Account" msgstr " Fiókom" @@ -1127,9 +1157,6 @@ msgstr[1] "%d függő kérelem" msgid "Adopt Package" msgstr "Csomag örökbe fogadása" -msgid "unknown" -msgstr "ismeretlen" - msgid "Package Base Details" msgstr "Alapcsomag részletei" @@ -1332,6 +1359,9 @@ msgstr "" "igényel fenntartói műveletet, a fenntartó eltűnt, és előzőleg már " "megpróbáltad felvenni a kapcsolatot a fenntartóval." +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1375,6 +1405,9 @@ msgstr "Zárolva" msgid "Close" msgstr "Lezárás" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Lezárva" @@ -1390,6 +1423,12 @@ msgstr "Pontos név" msgid "Exact Package Base" msgstr "Pontos alapcsomag" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Összes" diff --git a/po/it.po b/po/it.po index e0047f3f..e84c1e07 100644 --- a/po/it.po +++ b/po/it.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" "it/)\n" @@ -129,9 +129,30 @@ msgstr "Gestisci i co-manutentori" msgid "Edit comment" msgstr "Edita il commento" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Home" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "I miei pacchetti" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -378,6 +399,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Inserisci il tuo indirizzo email:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -632,6 +656,9 @@ msgstr "Non è possibile incrementare i permessi dell'account." msgid "Language is not currently supported." msgstr "Lingua attualmente non supportata." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Il nome utente %s%s%s è già in uso." @@ -950,6 +977,9 @@ msgstr "Attivo" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "sconosciuta" + msgid "Last Login" msgstr "Ultimo accesso" @@ -1001,6 +1031,9 @@ msgstr "Riscrivi la password" msgid "Language" msgstr "Lingua" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1085,9 +1118,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." -msgid "My Packages" -msgstr "I miei pacchetti" - msgid " My Account" msgstr "Il mio account" @@ -1140,9 +1170,6 @@ msgstr[1] "%d richieste in attesa" msgid "Adopt Package" msgstr "Adotta il pacchetto" -msgid "unknown" -msgstr "sconosciuta" - msgid "Package Base Details" msgstr "Dettagli del pacchetto base" @@ -1330,6 +1357,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1373,6 +1403,9 @@ msgstr "Bloccato" msgid "Close" msgstr "Chiudi" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Chiuso" @@ -1388,6 +1421,12 @@ msgstr "Nome esatto" msgid "Exact Package Base" msgstr "Pacchetto base esatto" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Tutti" diff --git a/po/ja.po b/po/ja.po index fae1a946..a649f077 100644 --- a/po/ja.po +++ b/po/ja.po @@ -5,13 +5,14 @@ # Translators: # kusakata, 2013 # kusakata, 2013 -# kusakata, 2013-2016 +# kusakata, 2013-2017 +# 尾ノ上卓朗 , 2017 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" "ja/)\n" @@ -31,18 +32,18 @@ msgid "Note" msgstr "ノート" msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "Git のクローン URL はブラウザで開いてはいけません。" #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "%s の Git リポジトリを複製するには、%s を実行してください。" #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "%sこちら%sをクリックすると %s の詳細ページに戻ります。" msgid "Service Unavailable" -msgstr "Service Unavailable" +msgstr "サービスは利用できません。" msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." @@ -129,9 +130,30 @@ msgstr "共同メンテナの管理" msgid "Edit comment" msgstr "コメントを編集" +msgid "Dashboard" +msgstr "ダッシュボード" + msgid "Home" msgstr "ホーム" +msgid "My Flagged Packages" +msgstr "自分のフラグが立っているパッケージ" + +msgid "My Requests" +msgstr "自分のリクエスト" + +msgid "My Packages" +msgstr "自分のパッケージ" + +msgid "Search for packages I maintain" +msgstr "メンテしているパッケージを検索" + +msgid "Co-Maintained Packages" +msgstr "共同メンテしているパッケージ" + +msgid "Search for packages I co-maintain" +msgstr "共同メンテしているパッケージを検索" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -374,6 +396,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "メールアドレスを入力:" +msgid "Package Bases" +msgstr "パッケージベース" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -623,6 +648,9 @@ msgstr "アカウント権限を増やすことはできません。" msgid "Language is not currently supported." msgstr "言語は現在サポートされていません。" +msgid "Timezone is not currently supported." +msgstr "タイムゾーンは現在サポートされていません。" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "%s%s%s というユーザー名は既に使われています。" @@ -930,6 +958,9 @@ msgstr "活動中" msgid "Registration date:" msgstr "登録日:" +msgid "unknown" +msgstr "不明" + msgid "Last Login" msgstr "最後のログイン" @@ -981,6 +1012,9 @@ msgstr "パスワードの再入力" msgid "Language" msgstr "言語" +msgid "Timezone" +msgstr "タイムゾーン" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1066,9 +1100,6 @@ msgstr "詳細に戻る" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." -msgid "My Packages" -msgstr "自分のパッケージ" - msgid " My Account" msgstr "アカウント" @@ -1120,9 +1151,6 @@ msgstr[0] "%d 件の保留リクエスト。" msgid "Adopt Package" msgstr "パッケージを承継する" -msgid "unknown" -msgstr "不明" - msgid "Package Base Details" msgstr "パッケージベースの詳細" @@ -1324,6 +1352,9 @@ msgstr "" "り、現在のメンテナが行方不明で、メンテナに連絡を取ろうとしても返答がない場合" "にのみ、リクエストを送信してください。" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1364,6 +1395,9 @@ msgstr "ロックされています" msgid "Close" msgstr "クローズ" +msgid "Pending" +msgstr "保留中" + msgid "Closed" msgstr "クローズされました" @@ -1379,6 +1413,12 @@ msgstr "名前完全一致" msgid "Exact Package Base" msgstr "パッケージベース完全一致" +msgid "Co-maintainer" +msgstr "共同メンテナ" + +msgid "Maintainer, Co-maintainer" +msgstr "メンテナ, 共同メンテナ" + msgid "All" msgstr "全て" @@ -1532,7 +1572,7 @@ msgid "No" msgstr "いいえ" msgid "Abstain" -msgstr "Abstain" +msgstr "棄権" msgid "Total" msgstr "合計" diff --git a/po/nb.po b/po/nb.po index 08597e50..2961989f 100644 --- a/po/nb.po +++ b/po/nb.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# Alexander F Rødseth , 2015 +# Alexander F Rødseth , 2015,2017 # Alexander F Rødseth , 2011,2013-2014 # Harald H. , 2015 # Kim Nordmo , 2016 @@ -13,8 +13,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" "language/nb/)\n" @@ -34,15 +34,15 @@ msgid "Note" msgstr "OBS" msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "Git clone URL-er er ikke ment til å åpnes i nettleseren." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "For å klone et Git arkiv fra %s, kjør %s." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Trykk %sher%s for å returnere til detalj-siden for %s." msgid "Service Unavailable" msgstr "Tjenesten er utilgjengelig" @@ -130,9 +130,30 @@ msgstr "Administrer Med-Vedlikeholdere" msgid "Edit comment" msgstr "Rediger kommentar" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Hjem" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Mine pakker" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -179,6 +200,8 @@ msgid "" "There are three types of requests that can be filed in the %sPackage Actions" "%s box on the package details page:" msgstr "" +"Det er tre forskjellige forespørsler som kan velges i %sPakkenhandling%s-" +"boksen på siden til en pakke:" msgid "Orphan Request" msgstr "Foreldreløs-forespørsel" @@ -362,6 +385,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Angi din e-postadresse:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -595,6 +621,9 @@ msgstr "Kan ikke gi flere tillatelser til kontoen." msgid "Language is not currently supported." msgstr "Språket støttes ikke på dette tidspunktet." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Brukernavnet, %s%s%s, er allerede i bruk." @@ -901,6 +930,9 @@ msgstr "Aktiv" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "ukjent" + msgid "Last Login" msgstr "Sist logget inn" @@ -952,6 +984,9 @@ msgstr "Skriv inn passordet på nytt" msgid "Language" msgstr "Språk" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1032,9 +1067,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Mine pakker" - msgid " My Account" msgstr " Min konto" @@ -1087,9 +1119,6 @@ msgstr[1] "%d ventende forespørsler" msgid "Adopt Package" msgstr "Adopter pakke" -msgid "unknown" -msgstr "ukjent" - msgid "Package Base Details" msgstr "Grunnpakkedetaljer" @@ -1277,6 +1306,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1320,6 +1352,9 @@ msgstr "Låst" msgid "Close" msgstr "Lukk" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Lukket" @@ -1335,6 +1370,12 @@ msgstr "Eksakt navn" msgid "Exact Package Base" msgstr "Eksakt grunnpakke" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Alle" diff --git a/po/nl.po b/po/nl.po index 99432f5f..4dd221f5 100644 --- a/po/nl.po +++ b/po/nl.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" "Language: nl\n" @@ -130,9 +130,30 @@ msgstr "Mede-onderhouders beheren" msgid "Edit comment" msgstr "" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Startgedeelte" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Mijn pakketten" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -371,6 +392,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Vul uw e-mail adres in:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -614,6 +638,9 @@ msgstr "Kan de account permissies niet verhogen." msgid "Language is not currently supported." msgstr "Taal wordt momenteel niet ondersteund." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "De gebruikersnaam %s%s%s is al in gebruik." @@ -927,6 +954,9 @@ msgstr "Actief" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "onbekend" + msgid "Last Login" msgstr "Laatste Login" @@ -976,6 +1006,9 @@ msgstr "Voer wachtwoord opnieuw in" msgid "Language" msgstr "Taal" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1060,9 +1093,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Mijn pakketten" - msgid " My Account" msgstr "Mijn Account" @@ -1115,9 +1145,6 @@ msgstr[1] "%d verzoeken in wachtrij" msgid "Adopt Package" msgstr "Adopteer Pakket" -msgid "unknown" -msgstr "onbekend" - msgid "Package Base Details" msgstr "Details van Basispakket" @@ -1306,6 +1333,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1349,6 +1379,9 @@ msgstr "Vergrendeld" msgid "Close" msgstr "Sluit" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Gesloten" @@ -1364,6 +1397,12 @@ msgstr "Exacte Naam" msgid "Exact Package Base" msgstr "Exact Basispakket" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Alle" diff --git a/po/pl.po b/po/pl.po index d7338cab..ad2918f3 100644 --- a/po/pl.po +++ b/po/pl.po @@ -9,6 +9,7 @@ # Chris Warrick , 2012 # Kwpolska , 2011 # Lukas Fleischer , 2011 +# m4sk1n , 2017 # Michal T , 2016 # Nuc1eoN , 2014 # Piotr Strębski , 2013-2016 @@ -16,17 +17,18 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-12 09:11+0000\n" -"Last-Translator: Michal T \n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" "pl/)\n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n" +"%100<12 || n%100>=14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" +"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" msgid "Page Not Found" msgstr "Nie znaleziono strony" @@ -136,9 +138,30 @@ msgstr "Zarządzanie współutrzymującymi" msgid "Edit comment" msgstr "Edytuj komentarz" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Start" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Moje pakiety" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -186,7 +209,7 @@ msgid "" msgstr "" msgid "Orphan Request" -msgstr "" +msgstr "Zgłoszenie osieroconego pakietu" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " @@ -368,6 +391,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Wpisz swój adres e-mail:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -615,6 +641,9 @@ msgstr "Nie można zwiększyć uprawnień konta." msgid "Language is not currently supported." msgstr "Język nie jest obecnie obsługiwany." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Nazwa użytkownika, %s%s%s, jest już używana." @@ -922,6 +951,9 @@ msgstr "Aktywne" msgid "Registration date:" msgstr "Data rejestracji:" +msgid "unknown" +msgstr "nieznana" + msgid "Last Login" msgstr "Ostatnie logowanie" @@ -973,6 +1005,9 @@ msgstr "Hasło (ponownie)" msgid "Language" msgstr "Język" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1058,9 +1093,6 @@ msgstr "Powrót do szczegółów" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Prawa autorskie %s 2004-%d Zespół Programistów aurweb." -msgid "My Packages" -msgstr "Moje pakiety" - msgid " My Account" msgstr "Moje konto" @@ -1110,13 +1142,11 @@ msgid_plural "%d pending requests" msgstr[0] "%d prośba w toku" msgstr[1] "%d prośby w toku" msgstr[2] "%d próśb w toku" +msgstr[3] "%d próśb w toku" msgid "Adopt Package" msgstr "Przejmij pakiet" -msgid "unknown" -msgstr "nieznana" - msgid "Package Base Details" msgstr "Szczegóły bazy pakietu" @@ -1227,7 +1257,7 @@ msgid "Groups" msgstr "Grupy" msgid "Conflicts" -msgstr "Konflikty" +msgstr "Konfliktuje z" msgid "Provides" msgstr "Zapewnia" @@ -1304,12 +1334,16 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d prośba odnaleziona." msgstr[1] "%d prośby odnalezione." msgstr[2] "%d próśb odnaleziono." +msgstr[3] "%d próśb odnaleziono." #, php-format msgid "Page %d of %d." @@ -1330,6 +1364,7 @@ msgid_plural "~%d days left" msgstr[0] "pozostało ~%d dzień" msgstr[1] "pozostało ~%d dni" msgstr[2] "pozostało ~%d dni" +msgstr[3] "pozostało ~%d dni" #, php-format msgid "~%d hour left" @@ -1337,6 +1372,7 @@ msgid_plural "~%d hours left" msgstr[0] "pozostała ~%d godzina" msgstr[1] "pozostały ~%d godziny" msgstr[2] "pozostało ~%d godzin" +msgstr[3] "pozostało ~%d godzin" msgid "<1 hour left" msgstr "pozostała <1 godzina" @@ -1350,6 +1386,9 @@ msgstr "Zablokowane" msgid "Close" msgstr "Zamknij" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Zamknięte" @@ -1365,6 +1404,12 @@ msgstr "Dokładna nazwa" msgid "Exact Package Base" msgstr "Dokładna baza pakietu" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Wszystkie" @@ -1425,6 +1470,7 @@ msgid_plural "%d packages found." msgstr[0] "%d pakiet znaleziono" msgstr[1] "%d pakiety znaleziono" msgstr[2] "%d pakietów znaleziono" +msgstr[3] "%d pakietów znaleziono" msgid "Version" msgstr "Wersja" diff --git a/po/pt_BR.po b/po/pt_BR.po index f653b435..04848217 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -6,7 +6,7 @@ # Albino Biasutti Neto Bino , 2011 # Fábio Nogueira , 2016 # Rafael Fontenelle , 2012-2015 -# Rafael Fontenelle , 2011,2015-2016 +# Rafael Fontenelle , 2011,2015-2017 # Rafael Fontenelle , 2011 # Sandro , 2011 # Sandro , 2011 @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 14:05+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 15:12+0000\n" "Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" "language/pt_BR/)\n" @@ -133,9 +133,30 @@ msgstr "Gerenciar co-mantenedores" msgid "Edit comment" msgstr "Editar comentário" +msgid "Dashboard" +msgstr "Dashboard" + msgid "Home" msgstr "Início" +msgid "My Flagged Packages" +msgstr "Meus pacotes sinalizados" + +msgid "My Requests" +msgstr "Minhas requisições" + +msgid "My Packages" +msgstr "Meus pacotes" + +msgid "Search for packages I maintain" +msgstr "Pesquisar por pacotes que eu mantenho" + +msgid "Co-Maintained Packages" +msgstr "Pacote comantidos" + +msgid "Search for packages I co-maintain" +msgstr "Pesquisar por pacotes que eu comantenho" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -381,6 +402,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Digite o seu endereço de e-mail:" +msgid "Package Bases" +msgstr "Pacotes base" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -628,6 +652,9 @@ msgstr "Não foi possível aumentar as permissões da conta." msgid "Language is not currently supported." msgstr "Idioma sem suporte no momento." +msgid "Timezone is not currently supported." +msgstr "Fuso horário sem suporte no momento." + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de usuário, %s%s%s, já está sendo usado." @@ -940,6 +967,9 @@ msgstr "Ativa" msgid "Registration date:" msgstr "Data de registro:" +msgid "unknown" +msgstr "desconhecido" + msgid "Last Login" msgstr "Último login" @@ -991,6 +1021,9 @@ msgstr "Re-digite a senha" msgid "Language" msgstr "Idioma" +msgid "Timezone" +msgstr "Fuso horário" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1076,9 +1109,6 @@ msgstr "Retornar para Detalhes" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d Equipe de Desenvolvimento do aurweb." -msgid "My Packages" -msgstr "Meus pacotes" - msgid " My Account" msgstr " Minha conta" @@ -1131,9 +1161,6 @@ msgstr[1] "%d requisições pentendes" msgid "Adopt Package" msgstr "Adotar pacote" -msgid "unknown" -msgstr "desconhecido" - msgid "Package Base Details" msgstr "Detalhes do pacote base" @@ -1335,6 +1362,9 @@ msgstr "" "ação do mantenedor, estando este ausente por muito tempo, e você já tentou - " "e não conseguiu - contatá-lo anteriormente." +msgid "No requests matched your search criteria." +msgstr "Nenhuma requisição correspondeu aos seus critérios de pesquisa." + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1378,6 +1408,9 @@ msgstr "Travado" msgid "Close" msgstr "Fechar" +msgid "Pending" +msgstr "Pendente" + msgid "Closed" msgstr "Fechada" @@ -1393,6 +1426,12 @@ msgstr "Nome exato" msgid "Exact Package Base" msgstr "Pacote base exato" +msgid "Co-maintainer" +msgstr "Comantenedor" + +msgid "Maintainer, Co-maintainer" +msgstr "Mantenedor, comantenedor" + msgid "All" msgstr "Todos" diff --git a/po/pt_PT.po b/po/pt_PT.po index 59ecb4f6..e00b5b83 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" "aur/language/pt_PT/)\n" @@ -131,9 +131,30 @@ msgstr "Gerir responsáveis" msgid "Edit comment" msgstr "Editar comentário" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Início" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Os meus pacotes" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -369,6 +390,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Introduza o endereço de e-mail:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -603,6 +627,9 @@ msgstr "Incapaz de aumentar as permissões da conta." msgid "Language is not currently supported." msgstr "Língua não suportada actualmente." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de utilizador, %s%s%s, já se encontra a ser utilizado." @@ -911,6 +938,9 @@ msgstr "Activo" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "desconhecido" + msgid "Last Login" msgstr "Última sessão" @@ -960,6 +990,9 @@ msgstr "Reintroduza a palavra-passe" msgid "Language" msgstr "Língua" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1040,9 +1073,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Os meus pacotes" - msgid " My Account" msgstr "A minha Conta" @@ -1095,9 +1125,6 @@ msgstr[1] "%d pedidos por atender" msgid "Adopt Package" msgstr "Adotar Pacote" -msgid "unknown" -msgstr "desconhecido" - msgid "Package Base Details" msgstr "Pacote Base Detalhes" @@ -1283,6 +1310,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1326,6 +1356,9 @@ msgstr "" msgid "Close" msgstr "Fechar" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Fechado" @@ -1341,6 +1374,12 @@ msgstr "Nome exacto" msgid "Exact Package Base" msgstr "Pacote Base Exacto" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Todos" diff --git a/po/ro.po b/po/ro.po index 85172d91..801e5dd7 100644 --- a/po/ro.po +++ b/po/ro.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" "ro/)\n" @@ -130,9 +130,30 @@ msgstr "" msgid "Edit comment" msgstr "" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Acasă" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Pachetele mele" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -350,6 +371,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Introdu adresa ta de e-mail:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -583,6 +607,9 @@ msgstr "Permisiunile contului nu pot fi ridicate." msgid "Language is not currently supported." msgstr "Limba nu este încă suportată." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Numele de utilizator %s%s%s este deja folosit." @@ -893,6 +920,9 @@ msgstr "Activ" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "necunoscut" + msgid "Last Login" msgstr "Ultima autentificare" @@ -942,6 +972,9 @@ msgstr "Rescrie parola" msgid "Language" msgstr "Limbă" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1022,9 +1055,6 @@ msgstr "" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Pachetele mele" - msgid " My Account" msgstr "Contul meu" @@ -1078,9 +1108,6 @@ msgstr[2] "%d de cereri în așteptare" msgid "Adopt Package" msgstr "Adoptă pachet" -msgid "unknown" -msgstr "necunoscut" - msgid "Package Base Details" msgstr "Detalii pachet de bază" @@ -1270,6 +1297,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1316,6 +1346,9 @@ msgstr "Blocat" msgid "Close" msgstr "Închide" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Închis" @@ -1331,6 +1364,12 @@ msgstr "Nume exact" msgid "Exact Package Base" msgstr "Pachet de bază exact" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Toate" diff --git a/po/ru.po b/po/ru.po index 530947e1..41f6534c 100644 --- a/po/ru.po +++ b/po/ru.po @@ -15,8 +15,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" "ru/)\n" @@ -135,9 +135,30 @@ msgstr "Управление ответственными" msgid "Edit comment" msgstr "Редактировать комментарий" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Главная" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Мои пакеты" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -382,6 +403,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Введите свой адрес электронной почты:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -623,6 +647,9 @@ msgstr "Невозможно повысить привилегии." msgid "Language is not currently supported." msgstr "Язык пока не поддерживается." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Имя %s%s%s уже занято." @@ -930,6 +957,9 @@ msgstr "Активный" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "неизвестно" + msgid "Last Login" msgstr "Последний вход" @@ -981,6 +1011,9 @@ msgstr "Введите пароль еще раз" msgid "Language" msgstr "Язык" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1065,9 +1098,6 @@ msgstr "Вернуться к деталям" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." -msgid "My Packages" -msgstr "Мои пакеты" - msgid " My Account" msgstr "Моя учётная запись" @@ -1122,9 +1152,6 @@ msgstr[3] "%d запросов в обработке" msgid "Adopt Package" msgstr "Усыновить пакет" -msgid "unknown" -msgstr "неизвестно" - msgid "Package Base Details" msgstr "Информация по группе пакетов" @@ -1323,6 +1350,9 @@ msgstr "" "действиях обслуживающего, который недоступен и вы уже пытались связаться с " "ним ранее." +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1372,6 +1402,9 @@ msgstr "Заблокировано" msgid "Close" msgstr "Закрыть" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Закрыт" @@ -1387,6 +1420,12 @@ msgstr "Точное имя" msgid "Exact Package Base" msgstr "Точное имя группы" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Все" diff --git a/po/sk.po b/po/sk.po index 4a564e9f..051a6864 100644 --- a/po/sk.po +++ b/po/sk.po @@ -3,14 +3,14 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# archetyp , 2013-2015 +# archetyp , 2013-2016 # Matej Ľach , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" "sk/)\n" @@ -31,14 +31,16 @@ msgstr "Poznámka" msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +"URL adresy na klonovanie Git repozitárov nie sú určené pre otváranie v " +"prehliadači." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Na klonovanie Git repozitáre pre %s spustite %s." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Kliknite %ssem%s pre návrat na stránku s detailami o %s." msgid "Service Unavailable" msgstr "Služba nie je dostupná" @@ -127,9 +129,30 @@ msgstr "Manažovať spolupracovníkov" msgid "Edit comment" msgstr "Editovať komentár" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Domov" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Moje balíčky" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -371,6 +394,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Zadajte svoju e-mailovú adresu:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -452,7 +478,7 @@ msgid "Only Trusted Users and Developers can disown packages." msgstr "Len dôverovaní užívatelia a vývojári môžu vyvlastňovať balíčky." msgid "Flag Comment" -msgstr "" +msgstr "Označ komentár" msgid "Flag Package Out-Of-Date" msgstr "Označ balíček ako zastaranú verziu" @@ -523,10 +549,10 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "Len dôverovaní užívatelia a vývojári môžu zlúčiť balíčky." msgid "Submit Request" -msgstr "" +msgstr "Odoslať žiadosť" msgid "Close Request" -msgstr "Zatvorit žiadosť" +msgstr "Zatvoriť žiadosť" msgid "First" msgstr "Prvý" @@ -617,6 +643,9 @@ msgstr "Nepodarilo sa rozšíriť práva účtu." msgid "Language is not currently supported." msgstr "Jazyk nie je momentálne podporovaný." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Užívateľské meno %s%s%s sa už používa." @@ -710,19 +739,19 @@ msgid "Missing comment ID." msgstr "Chýba ID komentára." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "Nemôže byť pripnutých viac ako 5 komentárov." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Nemáte oprávnenie na pripnutie tohoto komentára." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "Nemáte oprávnenie na odopnutie tohoto komentára." msgid "Comment has been pinned." -msgstr "" +msgstr "Komentár bol pripnutý." msgid "Comment has been unpinned." -msgstr "" +msgstr "Komentár bol odopnutý." msgid "Error retrieving package details." msgstr "Chyba pri získavaní informácií o balíčku." @@ -805,10 +834,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "Boli ste odobraný z notifikačného zoznamu komentárov pre %s." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Nemáte práva na obnovenie tohto komentára." msgid "Comment has been undeleted." -msgstr "" +msgstr "Komentár bol obnovený." msgid "You are not allowed to delete this comment." msgstr "Nemáte práva na vymazanie tohto komentára." @@ -902,7 +931,7 @@ msgid "Real Name" msgstr "Skutočné meno" msgid "Homepage" -msgstr "" +msgstr "Domovská stránka" msgid "IRC Nick" msgstr "IRC prezývka" @@ -920,7 +949,10 @@ msgid "Active" msgstr "Aktívny" msgid "Registration date:" -msgstr "" +msgstr "Dátum registrácie" + +msgid "unknown" +msgstr "neznámy" msgid "Last Login" msgstr "Posledné prihlásenie" @@ -940,7 +972,7 @@ msgstr "Kliknite %ssem%s ak chcete natrvalo vymazať tento účet." #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "Kliknite %ssem%s pre informácie o užívateľovi." msgid "required" msgstr "povinný" @@ -972,6 +1004,9 @@ msgstr "Potvrďte heslo" msgid "Language" msgstr "Jazyk" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -983,16 +1018,16 @@ msgid "SSH Public Key" msgstr "Verejný SSH kľúč" msgid "Notification settings" -msgstr "" +msgstr "Nastavenia upozornení" msgid "Notify of new comments" msgstr "Upozorni na nové komentáre" msgid "Notify of package updates" -msgstr "" +msgstr "Upozorni na aktualizácie balíčkov" msgid "Notify of ownership changes" -msgstr "" +msgstr "Upozorni na zmeny vo vlastníctve balíčka" msgid "Update" msgstr "Aktualizácia" @@ -1039,25 +1074,23 @@ msgstr "Uložiť" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Komentár k označeniu balíčka ako zastaranej verzie: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +"%s%s%s bol označený %s%s%s ako zastaraný %s%s%s z nasledujúceho dôvodu:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s nie je označený ako zastarný." msgid "Return to Details" -msgstr "" +msgstr "Návrat na detaily" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" - -msgid "My Packages" -msgstr "Moje balíčky" +msgstr "Copyright %s 2004-%d aurweb Development Team." msgid " My Account" msgstr "Môj účet" @@ -1079,7 +1112,7 @@ msgstr "Prehľadať wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Označený ako zastaraný (%s)" msgid "Flag package out-of-date" msgstr "Označ balíček ako neaktuálny" @@ -1097,7 +1130,7 @@ msgid "Disable notifications" msgstr "Vypni upozornenia" msgid "Enable notifications" -msgstr "" +msgstr "Povoliť upozornenia" msgid "Manage Co-Maintainers" msgstr "Manažovať spolupracovníkov" @@ -1112,9 +1145,6 @@ msgstr[2] "%d ostávajúcich žiadostí" msgid "Adopt Package" msgstr "Adoptuj balíček" -msgid "unknown" -msgstr "neznámy" - msgid "Package Base Details" msgstr "Detaily základne balíčka" @@ -1159,7 +1189,7 @@ msgid "View all comments" msgstr "Pozrieť všetky komentáre" msgid "Pinned Comments" -msgstr "" +msgstr "Pripnuté komentáre" msgid "Latest Comments" msgstr "Posledné komentáre" @@ -1178,27 +1208,27 @@ msgstr "vymazal %s %s" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "vymazaný %s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "editovaný %s %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "editovaný %s" msgid "Undelete comment" -msgstr "" +msgstr "Obnoviť komentár" msgid "Delete comment" msgstr "Vymaž komentár" msgid "Pin comment" -msgstr "" +msgstr "Pripnúť komentár" msgid "Unpin comment" -msgstr "" +msgstr "Odopnúť komentár" msgid "All comments" msgstr "Všetky komentáre" @@ -1288,6 +1318,10 @@ msgid "" "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +"Odoslaním žiadosti na vymazanie balíčka žiadate dôverovaného užívateľa t.j. " +"Trusted User, aby vymazal balíček aj s jeho základňou. Tento typ požiadavky " +"by mal použitý pre duplikáty, softvér ku ktorému už nie sú zdroje ako aj " +"nelegálne a neopraviteľné balíčky." msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " @@ -1295,6 +1329,11 @@ msgid "" "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." msgstr "" +"Odoslaním žiadosti na zlúčenie balíčka žiadate dôverovaného užívateľa t.j. " +"Trusted User, aby vymazal balíček aj s jeho základňou a preniesol hlasy a " +"komentáre na inú základňu balíčka. Zlúčenie balíčka nezasiahne prináležiace " +"Git repozitáre, preto sa uistite, že Git história cieľového balíčka je " +"aktuálna." msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " @@ -1302,6 +1341,13 @@ msgid "" "the maintainer is MIA and you already tried to contact the maintainer " "previously." msgstr "" +"Odoslaním žiadosti na osirotenie balíčka žiadate dôverovaného užívateľa t.j. " +"Trusted User, aby vyvlastnil balíček aj s jeho základňou. Toto urobte len " +"vtedy, ak balíček vyžaduje zásah od vlastníka, vlastník nie je zastihnuteľný " +"a už ste sa niekoľkokrát pokúšali vlastníka kontaktovať." + +msgid "No requests matched your search criteria." +msgstr "" #, php-format msgid "%d package request found." @@ -1326,9 +1372,9 @@ msgstr "Dátum" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "ostáva ~%d deň" +msgstr[1] "ostáva ~%d dni" +msgstr[2] "ostáva ~%d dní" #, php-format msgid "~%d hour left" @@ -1349,6 +1395,9 @@ msgstr "Uzamknuté" msgid "Close" msgstr "Zatvoriť" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Zatvorené" @@ -1364,6 +1413,12 @@ msgstr "Presné meno" msgid "Exact Package Base" msgstr "Presná základňa balíčka" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Všetky" @@ -1433,6 +1488,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"Popularita sa počíta ako súčet všetkých hlasov, pričom každý hlas je " +"prenásobený váhovým koeficientom %.2f každý deň od jeho pridania." msgid "Yes" msgstr "Áno" @@ -1492,7 +1549,7 @@ msgid "Recent Updates" msgstr "Nedávne aktualizácie" msgid "more" -msgstr "" +msgstr "viac" msgid "My Statistics" msgstr "Moja štatistika" diff --git a/po/sr.po b/po/sr.po index 32a57394..4cf8d12c 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-11 14:07+0000\n" -"Last-Translator: Slobodan Terzić \n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" "sr/)\n" "Language: sr\n" @@ -129,9 +129,30 @@ msgstr "Upravljanje koodržavaocima" msgid "Edit comment" msgstr "Uređivanje komentara" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Početna" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Moji paketi" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -372,6 +393,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Unesite adresu e-pošte:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -610,6 +634,9 @@ msgstr "Ne mogu da uvećam dozvole naloga." msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Korisničko ime %s%s%s je već u upotrebi." @@ -915,6 +942,9 @@ msgstr "Aktivan" msgid "Registration date:" msgstr "Datum registracije:" +msgid "unknown" +msgstr "nepoznata" + msgid "Last Login" msgstr "Poslednje prijavljivanje" @@ -966,6 +996,9 @@ msgstr "Ponovo unesite lozinku" msgid "Language" msgstr "Jezik" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1050,9 +1083,6 @@ msgstr "Nazad na detalje" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." -msgid "My Packages" -msgstr "Moji paketi" - msgid " My Account" msgstr "Moj nalog" @@ -1106,9 +1136,6 @@ msgstr[2] "%d zahteva na čekanju" msgid "Adopt Package" msgstr "Usvoji paket" -msgid "unknown" -msgstr "nepoznata" - msgid "Package Base Details" msgstr "Podaci o bazi paketa" @@ -1307,6 +1334,9 @@ msgstr "" "zahteva održavanje, a održavalac je nedosupan i već ste pokušali da ga " "kontaktirate." +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1353,6 +1383,9 @@ msgstr "Zaključano" msgid "Close" msgstr "Zatvori" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Zatvoreno" @@ -1368,6 +1401,12 @@ msgstr "Tačno ime" msgid "Exact Package Base" msgstr "Tačna osnova paketa" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "svi" diff --git a/po/tr.po b/po/tr.po index b5ddf23c..9490001e 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3,21 +3,21 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# Atilla Öntaş , 2011,2013-2015 -# Atilla Öntaş , 2012,2014 +# tarakbumba , 2011,2013-2015 +# tarakbumba , 2012,2014 # Demiray Muhterem , 2015 # Lukas Fleischer , 2011 # Samed Beyribey , 2012 # Samed Beyribey , 2012 # Serpil Acar , 2016 -# Atilla Öntaş , 2012 +# tarakbumba , 2012 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-09 05:38+0000\n" -"Last-Translator: Serpil Acar \n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" "tr/)\n" "Language: tr\n" @@ -134,9 +134,30 @@ msgstr "Yardımcı bakımcıları Yönet" msgid "Edit comment" msgstr "Yorumu düzenle" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "Anasayfa" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "Paketlerim" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -376,6 +397,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "E-posta adresinizi girin:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -620,6 +644,9 @@ msgstr "Hesap izinleri yükseltilemiyor." msgid "Language is not currently supported." msgstr "Dil henüz desteklenmiyor." +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Kullanıcı adı, %s%s%s, zaten kullanılıyor." @@ -926,6 +953,9 @@ msgstr "Etkin" msgid "Registration date:" msgstr "Kayıt tarihi:" +msgid "unknown" +msgstr "bilinmiyor" + msgid "Last Login" msgstr "Son giriş" @@ -977,6 +1007,9 @@ msgstr "Parolayı tekrar girin" msgid "Language" msgstr "Dil" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1061,9 +1094,6 @@ msgstr "Detaylara Geri Dön." msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" -msgid "My Packages" -msgstr "Paketlerim" - msgid " My Account" msgstr "Hesabım" @@ -1116,9 +1146,6 @@ msgstr[1] "%d adet bekleyen talep" msgid "Adopt Package" msgstr "Paketi Sahiplen" -msgid "unknown" -msgstr "bilinmiyor" - msgid "Package Base Details" msgstr "Paket Temeli Ayrıntıları" @@ -1315,6 +1342,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1358,6 +1388,9 @@ msgstr "Kilitli" msgid "Close" msgstr "Kapat" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "Kapandı" @@ -1373,6 +1406,12 @@ msgstr "Tam Ad" msgid "Exact Package Base" msgstr "Tam Paket Temeli" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "Tümü" diff --git a/po/uk.po b/po/uk.po index 8e26a4f7..f6267e65 100644 --- a/po/uk.po +++ b/po/uk.po @@ -6,14 +6,14 @@ # Lukas Fleischer , 2011 # Rax Garfield , 2012 # Rax Garfield , 2012 -# Yarema aka Knedlyk , 2011-2016 +# Yarema aka Knedlyk , 2011-2017 # Данило Коростіль , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 15:11+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 16:47+0000\n" "Last-Translator: Yarema aka Knedlyk \n" "Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" "uk/)\n" @@ -43,7 +43,7 @@ msgstr "Щоб клонувати сховище Git з %s, виконайте % #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "Клацніть %sтут%s для повернення на сторінку деталей %s." +msgstr "Клацніть %sтут%s для повернення на сторінку інформації %s." msgid "Service Unavailable" msgstr "Сервіс недоступний" @@ -128,14 +128,35 @@ msgid "Submit" msgstr "Надіслати пакунок" msgid "Manage Co-maintainers" -msgstr "Керування супровідниками" +msgstr "Керування ко-супровідниками" msgid "Edit comment" msgstr "Редагувати коментар" +msgid "Dashboard" +msgstr "Панель знарядь" + msgid "Home" msgstr "Початкова сторінка" +msgid "My Flagged Packages" +msgstr "Мої відмічені пакунки" + +msgid "My Requests" +msgstr "Мої запити" + +msgid "My Packages" +msgstr "Мої пакунки" + +msgid "Search for packages I maintain" +msgstr "Пошук пакунків які я підтримую" + +msgid "Co-Maintained Packages" +msgstr "Пакунки з сумісним супроводом" + +msgid "Search for packages I co-maintain" +msgstr "Пошук пакунків з сумісним супроводом" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -378,6 +399,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "Введіть адресу електронної пошти:" +msgid "Package Bases" +msgstr "Бази пакунків" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -405,7 +429,9 @@ msgstr "Вилучити пакунок" msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Використовуйте цю форму для вилучення пакунку %s%s%s з AUR. " +msgstr "" +"Використовуйте цю форму для вилучення бази пакунків %s%s%s і наступних " +"пакунків з AUR. " msgid "Deletion of a package is permanent. " msgstr "Вилучення пакунку є безповоротне." @@ -430,7 +456,7 @@ msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" -"Використайте ці форму для позбавлення базового пакунка %s%s%s власника, який " +"Використайте ці форму для позбавлення бази пакунків %s%s%s власника, яка " "містить наступні пакунки:" #, php-format @@ -467,7 +493,7 @@ msgid "" "Use this form to flag the package base %s%s%s and the following packages out-" "of-date: " msgstr "" -"Використовуйте цю форму для позначення базового пакунку %s%s%s і наступні " +"Використовуйте цю форму для позначення бази пакунків %s%s%s і наступні " "пакунки як застарілі:" #, php-format @@ -503,7 +529,8 @@ msgstr "Об’єднати пакунок" #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "Використовуйте цю форму для злиття пакунку %s%s%s з іншим пакунком." +msgstr "" +"Використовуйте цю форму для злиття бази пакунків %s%s%s з іншим пакунком." msgid "The following packages will be deleted: " msgstr "Наступні пакунки будуть вилучені:" @@ -621,6 +648,9 @@ msgstr "Неможливо збільшити дозволи рахунку." msgid "Language is not currently supported." msgstr "Наразі ця мова не підтримується." +msgid "Timezone is not currently supported." +msgstr "Наразі часова зона не підтримується." + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Назва користувача %s%s%s вже використовується." @@ -695,7 +725,7 @@ msgid "View account information for %s" msgstr "Показати інформацію про рахунок для %s" msgid "Package base ID or package base name missing." -msgstr "ID базового пакунку або ж назва базового пакунку пропущена." +msgstr "ID бази пакунків або ж назва бази пакунків пропущена." msgid "You are not allowed to edit this comment." msgstr "У вас немає прав, щоб редагувати цей коментар." @@ -828,21 +858,20 @@ msgid "Comment has been edited." msgstr "Коментар редаговано." msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"Ви не маєте прав для редагування ключових слів для цього базового пакунку." +msgstr "Ви не маєте прав для редагування ключових слів для цієї бази пакунків." msgid "The package base keywords have been updated." -msgstr "Ключові слова базового пакунку оновлено." +msgstr "Ключові слова бази пакунків оновлено." msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Ви не має прав для керування супровідниками цього базового пакунку." +msgstr "Ви не має прав для керування ко-супровідниками цієї бази пакунків." #, php-format msgid "Invalid user name: %s" msgstr "Неправильна назва користувача: %s" msgid "The package base co-maintainers have been updated." -msgstr "Оновлено супровідників базового пакунку." +msgstr "Оновлено ко-супровідників бази пакунків." msgid "View packages details for" msgstr "Показати деталі пакунку для " @@ -931,6 +960,9 @@ msgstr "Активний" msgid "Registration date:" msgstr "Дата реєстрації:" +msgid "unknown" +msgstr "невідомо" + msgid "Last Login" msgstr "Останній вхід" @@ -949,7 +981,7 @@ msgstr "Натисніть %sтут%s, якщо Ви бажаєте безпов #, php-format msgid "Click %shere%s for user details." -msgstr "Клацніть %sтут%s для деталей про користувача." +msgstr "Клацніть %sтут%s, щоб дізнатися більше про користувача." msgid "required" msgstr "обов'язково" @@ -982,6 +1014,9 @@ msgstr "Введіть пароль ще раз" msgid "Language" msgstr "Мова" +msgid "Timezone" +msgstr "Часова зона" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1038,7 +1073,7 @@ msgstr "Більше немає результатів." msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -"Використайте цю форму для додавання супровідника для %s%s%s (одна назва " +"Використайте цю форму для додавання ко-супровідника для %s%s%s (одна назва " "користувача в одній стрічці):" msgid "Users" @@ -1066,9 +1101,6 @@ msgstr "Повернення до подробиць." msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Всі права застережено %s 2004-%d Команда Розробників aurweb." -msgid "My Packages" -msgstr "Мої пакунки" - msgid " My Account" msgstr "Мій рахунок" @@ -1110,7 +1142,7 @@ msgid "Enable notifications" msgstr "Включити сповіщення" msgid "Manage Co-Maintainers" -msgstr "Керування Супровідниками" +msgstr "Керування ко-супровідниками" #, php-format msgid "%d pending request" @@ -1122,9 +1154,6 @@ msgstr[2] "%d запитів в обробці" msgid "Adopt Package" msgstr "Прийняти пакунок" -msgid "unknown" -msgstr "невідомо" - msgid "Package Base Details" msgstr "Деталі бази пакунків" @@ -1254,7 +1283,7 @@ msgstr "Сирці" #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Використайте цю форму для закриття запиту щодо бази пакетів %s%s%s." +msgstr "Використайте цю форму для закриття запиту щодо бази пакунків %s%s%s." msgid "" "The comments field can be left empty. However, it is highly recommended to " @@ -1298,8 +1327,9 @@ msgid "" "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" "Надсилаючи запит на вилучення, Ви просите Довіреного Користувача вилучити " -"пакунок з бази. Цей тип запиту повинен використовуватися для дублікатів, " -"неоновлюваних програм, а також нелегальних і невиправно пошкоджених пакунків." +"пакунок з бази пакунків. Цей тип запиту повинен використовуватися для " +"дублікатів, неоновлюваних програм, а також нелегальних і невиправно " +"пошкоджених пакунків." msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " @@ -1308,9 +1338,9 @@ msgid "" "update the Git history of the target package yourself." msgstr "" "Надсилаючи запит на об'єднання, Ви просите Довіреного Користувача вилучити " -"пакунок і перенести всі його голосування і коментарі до іншого пакунку. " -"Об'єднання пакунку не впливає на відповідні сховища Git. Впевніться, що Ви " -"оновили самі історію Git доцільового пакунку." +"базу пакунків і перенести всі його голосування і коментарі до іншої бази " +"пакунків. Об'єднання пакунку не впливає на відповідні сховища Git. " +"Впевніться, що Ви самостійно оновили історію Git доцільового пакунку." msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " @@ -1319,8 +1349,12 @@ msgid "" "previously." msgstr "" "Надсилаючи запит на зречення, Ви просите Довіреного Користувача позбавити " -"пакунок власника. Робіть це, якщо пакунок потребує якоїсь дії, супровідник " -"не робить жодних дій і Ви вже попередньо намагалися зв'язатися з ним." +"базу пакунків власника. Робіть це, якщо пакунок потребує якоїсь дії від " +"супровідника, супровідник не робить жодних дій і Ви вже попередньо " +"намагалися зв'язатися з ним." + +msgid "No requests matched your search criteria." +msgstr "Жоден запит не відповідає Вашим критеріям пошуку." #, php-format msgid "%d package request found." @@ -1368,6 +1402,9 @@ msgstr "Замкнено" msgid "Close" msgstr "Закрити" +msgid "Pending" +msgstr "В очікуванні" + msgid "Closed" msgstr "Замкнено" @@ -1383,6 +1420,12 @@ msgstr "Точна назва" msgid "Exact Package Base" msgstr "Точна база пакунків" +msgid "Co-maintainer" +msgstr "Ко-супровідник" + +msgid "Maintainer, Co-maintainer" +msgstr "Супровідник, ко-супровідник" + msgid "All" msgstr "Всі" diff --git a/po/zh_CN.po b/po/zh_CN.po index 453e7683..d5e306cf 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-08 12:59+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-25 12:41+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" "language/zh_CN/)\n" @@ -131,9 +131,30 @@ msgstr "管理共同维护者" msgid "Edit comment" msgstr "编辑评论" +msgid "Dashboard" +msgstr "" + msgid "Home" msgstr "首页" +msgid "My Flagged Packages" +msgstr "" + +msgid "My Requests" +msgstr "" + +msgid "My Packages" +msgstr "我的软件包" + +msgid "Search for packages I maintain" +msgstr "" + +msgid "Co-Maintained Packages" +msgstr "" + +msgid "Search for packages I co-maintain" +msgstr "" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -361,6 +382,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "输入您的邮箱地址:" +msgid "Package Bases" +msgstr "" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -591,6 +615,9 @@ msgstr "不能提高账户权限。" msgid "Language is not currently supported." msgstr "目前不支持此语言。" +msgid "Timezone is not currently supported." +msgstr "" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "用户名 %s%s%s 已被使用。" @@ -894,6 +921,9 @@ msgstr "激活" msgid "Registration date:" msgstr "" +msgid "unknown" +msgstr "未知" + msgid "Last Login" msgstr "最后登陆" @@ -943,6 +973,9 @@ msgstr "确认密码" msgid "Language" msgstr "语言" +msgid "Timezone" +msgstr "" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1023,9 +1056,6 @@ msgstr "返回详情" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "版权所有 %s 2004-%d aurweb 开发组" -msgid "My Packages" -msgstr "我的软件包" - msgid " My Account" msgstr "我的帐户" @@ -1077,9 +1107,6 @@ msgstr[0] "%d 个未处理的请求" msgid "Adopt Package" msgstr "接管软件包" -msgid "unknown" -msgstr "未知" - msgid "Package Base Details" msgstr "包基础详情" @@ -1263,6 +1290,9 @@ msgid "" "previously." msgstr "" +msgid "No requests matched your search criteria." +msgstr "" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1303,6 +1333,9 @@ msgstr "已锁定" msgid "Close" msgstr "关闭" +msgid "Pending" +msgstr "" + msgid "Closed" msgstr "已关闭" @@ -1318,6 +1351,12 @@ msgstr "确切的名字" msgid "Exact Package Base" msgstr "准确包基础" +msgid "Co-maintainer" +msgstr "" + +msgid "Maintainer, Co-maintainer" +msgstr "" + msgid "All" msgstr "全部" diff --git a/po/zh_TW.po b/po/zh_TW.po index 5d1a4247..7c155188 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -3,13 +3,13 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# Jeff Huang , 2014-2016 +# Jeff Huang , 2014-2017 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2016-10-08 14:59+0200\n" -"PO-Revision-Date: 2016-10-09 09:21+0000\n" +"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"PO-Revision-Date: 2017-02-26 03:10+0000\n" "Last-Translator: Jeff Huang \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" "language/zh_TW/)\n" @@ -125,9 +125,30 @@ msgstr "管理共同維護者" msgid "Edit comment" msgstr "編輯評論" +msgid "Dashboard" +msgstr "儀表板" + msgid "Home" msgstr "首頁" +msgid "My Flagged Packages" +msgstr "我標記的套件" + +msgid "My Requests" +msgstr "我的請求" + +msgid "My Packages" +msgstr "我的套件" + +msgid "Search for packages I maintain" +msgstr "搜尋我維護的套件" + +msgid "Co-Maintained Packages" +msgstr "共同維護的套件" + +msgid "Search for packages I co-maintain" +msgstr "搜尋我共同維護的套件" + #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " @@ -358,6 +379,9 @@ msgstr "" msgid "Enter your e-mail address:" msgstr "輸入您的電子郵件地址:" +msgid "Package Bases" +msgstr "套件基礎" + msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." @@ -589,6 +613,9 @@ msgstr "無法提升帳號權限。" msgid "Language is not currently supported." msgstr "目前不支援此語言。" +msgid "Timezone is not currently supported." +msgstr "目前不支援時區。" + #, php-format msgid "The username, %s%s%s, is already in use." msgstr "使用者名稱 %s%s%s 已被使用。" @@ -892,6 +919,9 @@ msgstr "活躍" msgid "Registration date:" msgstr "註冊日期:" +msgid "unknown" +msgstr "未知" + msgid "Last Login" msgstr "最後登入" @@ -941,6 +971,9 @@ msgstr "重新輸入密碼" msgid "Language" msgstr "語言" +msgid "Timezone" +msgstr "時區" + msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." @@ -1021,9 +1054,6 @@ msgstr "回到詳情" msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb 開發團隊。" -msgid "My Packages" -msgstr "我的套件" - msgid " My Account" msgstr "我的帳號" @@ -1075,9 +1105,6 @@ msgstr[0] "%d 個擱置的請求" msgid "Adopt Package" msgstr "接管套件" -msgid "unknown" -msgstr "未知" - msgid "Package Base Details" msgstr "套件基礎詳細資訊" @@ -1268,6 +1295,9 @@ msgstr "" "透過遞交棄置請求,您會請求受信使用者棄置套件基礎。請僅在該套件需要有維護者動" "作、維護者突然消失且您先前已經連絡過維護者時做此動作。" +msgid "No requests matched your search criteria." +msgstr "沒有符合您搜尋條件的搜尋結果。" + #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1308,6 +1338,9 @@ msgstr "已鎖定" msgid "Close" msgstr "關閉" +msgid "Pending" +msgstr "擱置中" + msgid "Closed" msgstr "已關閉" @@ -1323,6 +1356,12 @@ msgstr "確切的名稱" msgid "Exact Package Base" msgstr "確切的套件基礎" +msgid "Co-maintainer" +msgstr "共同維護者" + +msgid "Maintainer, Co-maintainer" +msgstr "維護者、共同維護者" + msgid "All" msgstr "全部" From 5fd417d70154470d145c83a4b60693c8d877b016 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 26 Feb 2017 10:28:34 +0100 Subject: [PATCH 0330/1891] Release 4.5.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index dcf5666e..e18873e3 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Sun, 26 Feb 2017 21:58:05 +0100 Subject: [PATCH 0331/1891] Fix SQL query used for creating new accounts Fixes a regression introduced in 608c483 (Add user set timezones, 2017-01-20). Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index d0a7ff94..5f7f1f4c 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -292,7 +292,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $q = "INSERT INTO Users (AccountTypeID, Suspended, "; $q.= "InactivityTS, Username, Email, Passwd , "; $q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) "; - $q.= "VALUES (1, 0, 0, $U, $E, $P, $R, $L, $TZ "; + $q.= "VALUES (1, 0, 0, $U, $E, $P, $R, $L, $TZ, "; $q.= "$HP, $I, $K)"; $result = $dbh->exec($q); if (!$result) { From 22e8ff0bb6806811f9bd45ad9edb6ef52ec8cebf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 26 Feb 2017 21:59:23 +0100 Subject: [PATCH 0332/1891] Always use source_file_uri instead of pkgbuild_uri The pkgbuild_uri option was replaced by source_file_uri in 9df1bd5 (Add direct links to each source file, 2017-02-12). Change one remaining reference to pkgbuild_uri accordingly. Signed-off-by: Lukas Fleischer --- web/template/pkgbase_details.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index e368872e..de55da03 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -1,6 +1,6 @@ Date: Sun, 26 Feb 2017 22:01:47 +0100 Subject: [PATCH 0333/1891] Do not quote legacy variable The $salt variable is no longer needed as of 29a4870 (Use bcrypt to hash passwords, 2017-02-24). Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 5f7f1f4c..63ab4b4a 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -282,7 +282,6 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $U = $dbh->quote($U); $E = $dbh->quote($E); $P = $dbh->quote($P); - $salt = $dbh->quote($salt); $R = $dbh->quote($R); $L = $dbh->quote($L); $TZ = $dbh->quote($TZ); From 333689a885fb50fdfc8068b5885c41b9d3cf1510 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 26 Feb 2017 22:03:23 +0100 Subject: [PATCH 0334/1891] Suppress warning on unset SSH key Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 63ab4b4a..a6eab274 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -244,7 +244,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" "", htmlspecialchars($E,ENT_QUOTES), ""); } } - if (!$error && count($ssh_keys) > 0) { + if (!$error && isset($ssh_keys) && count($ssh_keys) > 0) { /* * Check whether any of the SSH public keys is already in use. * TODO: Fix race condition. From 9ec1cfa1923ffc28a7fb23aa94f408e16cd70837 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 17:56:20 +0100 Subject: [PATCH 0335/1891] 404.php: Squelch warning on empty PATH_INFO Signed-off-by: Lukas Fleischer --- web/html/404.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/404.php b/web/html/404.php index 757c4855..9f81d115 100644 --- a/web/html/404.php +++ b/web/html/404.php @@ -5,7 +5,7 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); $path = $_SERVER['PATH_INFO']; $tokens = explode('/', $path); -if (preg_match('/^([a-z0-9][a-z0-9.+_-]*?)(\.git)?$/', $tokens[1], $matches)) { +if (isset($tokens[1]) && preg_match('/^([a-z0-9][a-z0-9.+_-]*?)(\.git)?$/', $tokens[1], $matches)) { $gitpkg = $matches[1]; if (pkg_from_name($gitpkg)) { $gitcmd = 'git clone ' . sprintf(config_get('options', 'git_clone_uri_anon'), htmlspecialchars($gitpkg)); From f1d95c09a87c726a0fa294fe373dc3c80334c58f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 18:00:32 +0100 Subject: [PATCH 0336/1891] pkgflag.php: Remove stray variable Drop the fragment part of the redirection code which is an artifact of the original code copy-pasted in commit ca954fe (Do not redirect when showing errors during flagging, 2015-10-21). Signed-off-by: Lukas Fleischer --- web/html/pkgflag.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php index 44849d88..25c8ccbb 100644 --- a/web/html/pkgflag.php +++ b/web/html/pkgflag.php @@ -28,7 +28,7 @@ if (check_token()) { } if ($ret) { - header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); + header('Location: ' . get_pkgbase_uri($pkgbase_name)); exit(); } } From 1bedf736e89fc4cd82f4522ea0747851ff901510 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 18:04:38 +0100 Subject: [PATCH 0337/1891] Fix more warnings occurring with unset SSH keys Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index a6eab274..3c8f9edb 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -301,7 +301,9 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" } $uid = $dbh->lastInsertId(); - account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints); + if (isset($ssh_keys) && count($ssh_keys) > 0) { + account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints); + } $message = __("The account, %s%s%s, has been successfully created.", "", htmlspecialchars($U,ENT_QUOTES), ""); @@ -364,7 +366,11 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $q.= " WHERE ID = ".intval($UID); $result = $dbh->exec($q); - $ssh_key_result = account_set_ssh_keys($UID, $ssh_keys, $ssh_fingerprints); + if (isset($ssh_keys) && count($ssh_keys) > 0) { + $ssh_key_result = account_set_ssh_keys($UID, $ssh_keys, $ssh_fingerprints); + } else { + $ssh_key_result = true; + } if (isset($_COOKIE["AURTZ"]) && ($_COOKIE["AURTZ"] != $TZ)) { /* set new cookie for timezone */ From 62341a3b3409befb0ca24e00e82a8a3c6a59def6 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 18:05:32 +0100 Subject: [PATCH 0338/1891] Fix warning with invalid time zone The SQL query retrieving the time zone from the database may return an empty result set if the session timeout was reached. Handle such cases gracefully by leaving the timezone variable unset. Signed-off-by: Lukas Fleischer --- web/lib/timezone.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/lib/timezone.inc.php b/web/lib/timezone.inc.php index 9fb24331..949f846d 100644 --- a/web/lib/timezone.inc.php +++ b/web/lib/timezone.inc.php @@ -42,6 +42,9 @@ function set_tz() { if ($result) { $timezone = $result->fetchColumn(0); + if (!$timezone) { + unset($timezone); + } } $update_cookie = true; From c557f348c42309fa761eaed0a7957d6b67cc0d74 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 18:09:57 +0100 Subject: [PATCH 0339/1891] Fix SQL query to retrieve language setting In commit e171f6f (Migrate all DB code to use PDO, 2012-08-08), PDOStatement::fetchAll() was introduced as a drop-in replacement for mysql_fetch_array(). However, PDOStatement::fetchAll() returns a list of all results while mysql_fetch_array() returns a single result only. Instead of adding the missing indirection, simplify the code by using PDO::fetchColumn(). Also add some safeguards to prevent warnings if the result set returned by the query is empty. Signed-off-by: Lukas Fleischer --- web/lib/translator.inc.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web/lib/translator.inc.php b/web/lib/translator.inc.php index 58648c41..d10f8e90 100644 --- a/web/lib/translator.inc.php +++ b/web/lib/translator.inc.php @@ -111,14 +111,16 @@ function set_lang() { $result = $dbh->query($q); if ($result) { - $row = $result->fetchAll(); - $LANG = $row[0]; + $LANG = $result->fetchColumn(0); + if (!$LANG) { + unset($LANG); + } } $update_cookie = 1; } # Set $LANG to default if nothing is valid. - if (!array_key_exists($LANG, $SUPPORTED_LANGS)) { + if (!isset($LANG) || !array_key_exists($LANG, $SUPPORTED_LANGS)) { $LANG = config_get('options', 'default_lang'); } From 483c8f5178c6d0f093a56aecc760cefba03352d9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 19:53:25 +0100 Subject: [PATCH 0340/1891] Remove bogus if-statement from pkgbase_delete() The variable $action is always undefined in pkgbase_delete() which makes the if-statement always true and triggers a warning whenever a package base is removed. Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 57b307d8..b20c2ffb 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -522,15 +522,13 @@ function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) { } /* Scan through pending deletion requests and close them. */ - if (!$action) { - $username = username_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - $pkgreq_ids = array_merge(pkgreq_by_pkgbase($base_id)); - foreach ($pkgreq_ids as $pkgreq_id) { - pkgreq_close(intval($pkgreq_id), 'accepted', - 'The user ' . $username . - ' deleted the package.', true); - } + $username = username_from_sid($_COOKIE['AURSID']); + foreach ($base_ids as $base_id) { + $pkgreq_ids = array_merge(pkgreq_by_pkgbase($base_id)); + foreach ($pkgreq_ids as $pkgreq_id) { + pkgreq_close(intval($pkgreq_id), 'accepted', + 'The user ' . $username . + ' deleted the package.', true); } } From 92f140c5ca121bcde0bb3cb283075e151f865d0d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 20:01:50 +0100 Subject: [PATCH 0341/1891] flag_comment.php: Hide comment for unflagged packages Only show the comment paragraph if the package base is actually flagged out-of-date. Signed-off-by: Lukas Fleischer --- web/template/flag_comment.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php index e8855fe8..05eeacb2 100644 --- a/web/template/flag_comment.php +++ b/web/template/flag_comment.php @@ -11,11 +11,13 @@ '', htmlspecialchars($pkgbase_name), ''); ?>

    +

    +

    " /> From 06cf067d4f135a5ec1e36e3316e2b8b75644a86d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Feb 2017 20:09:15 +0100 Subject: [PATCH 0342/1891] Squelch warning in pkgbase_vote() Do not trigger a PHP warning if there are no votes to be added or removed. Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index b20c2ffb..cd4b2713 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -735,6 +735,8 @@ function pkgbase_vote ($base_ids, $action=true) { $uid = uid_from_sid($_COOKIE["AURSID"]); $first = 1; + $vote_ids = ""; + $vote_clauses = ""; foreach ($base_ids as $pid) { if ($action) { $check = !isset($my_votes[$pid]); @@ -758,23 +760,25 @@ function pkgbase_vote ($base_ids, $action=true) { } } - /* Only add votes for packages the user hasn't already voted for. */ - $op = $action ? "+" : "-"; - $q = "UPDATE PackageBases SET NumVotes = NumVotes $op 1 "; - $q.= "WHERE ID IN ($vote_ids)"; + if (!empty($vote_ids)) { + /* Only add votes for packages the user hasn't already voted for. */ + $op = $action ? "+" : "-"; + $q = "UPDATE PackageBases SET NumVotes = NumVotes $op 1 "; + $q.= "WHERE ID IN ($vote_ids)"; - $dbh->exec($q); + $dbh->exec($q); - if ($action) { - $q = "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) VALUES "; - $q.= $vote_clauses; - } else { - $q = "DELETE FROM PackageVotes WHERE UsersID = $uid "; - $q.= "AND PackageBaseID IN ($vote_ids)"; + if ($action) { + $q = "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) VALUES "; + $q.= $vote_clauses; + } else { + $q = "DELETE FROM PackageVotes WHERE UsersID = $uid "; + $q.= "AND PackageBaseID IN ($vote_ids)"; + } + + $dbh->exec($q); } - $dbh->exec($q); - if ($action) { return array(true, __("Your votes have been cast for the selected packages.")); } else { From eb6ae0c6852f69a62b4e8226f80e337a67ce636e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 28 Feb 2017 07:09:51 +0100 Subject: [PATCH 0343/1891] account.php: Always initialize $success Signed-off-by: Lukas Fleischer --- web/html/account.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/html/account.php b/web/html/account.php index 0b757612..549f8524 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -24,6 +24,7 @@ if (in_array($action, $need_userinfo)) { * which could be changed by process_account_form() */ if ($action == "UpdateAccount") { + $success = false; $update_account_message = ''; /* Details for account being updated */ /* Verify user permissions and that the request is a valid POST */ From cc84e0b7fd7d491e1ba987786c45ddaf5bcd58d4 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 28 Feb 2017 07:14:21 +0100 Subject: [PATCH 0344/1891] pkgbase.php: Squelch PHP warning Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 23aa6c83..ab409845 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -145,17 +145,21 @@ if (check_token()) { } } -$pkgs = pkgbase_get_pkgnames($base_id); -if (!$output && count($pkgs) == 1) { - /* Not a split package. Redirect to the package page. */ - if (empty($_SERVER['QUERY_STRING'])) { - header('Location: ' . get_pkg_uri($pkgs[0]) . $fragment); - } else { - header('Location: ' . get_pkg_uri($pkgs[0]) . '?' . $_SERVER['QUERY_STRING'] . $fragment); +if (isset($base_id)) { + $pkgs = pkgbase_get_pkgnames($base_id); + if (!$output && count($pkgs) == 1) { + /* Not a split package. Redirect to the package page. */ + if (empty($_SERVER['QUERY_STRING'])) { + header('Location: ' . get_pkg_uri($pkgs[0]) . $fragment); + } else { + header('Location: ' . get_pkg_uri($pkgs[0]) . '?' . $_SERVER['QUERY_STRING'] . $fragment); + } } -} -$details = pkgbase_get_details($base_id); + $details = pkgbase_get_details($base_id); +} else { + $details = array(); +} html_header($title, $details); ?> @@ -169,10 +173,12 @@ html_header($title, $details); Date: Tue, 28 Feb 2017 19:29:36 +0100 Subject: [PATCH 0345/1891] pkgbase.php: Fix PHP notice Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index ab409845..a593af10 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -44,6 +44,7 @@ if (isset($_POST['IDs'])) { } /* Perform package base actions. */ +$via = isset($_POST['via']) ? $_POST['via'] : NULL; $ret = false; $output = ""; $fragment = ""; @@ -56,7 +57,6 @@ if (check_token()) { list($ret, $output) = pkgbase_adopt($ids, true, NULL); } elseif (current_action("do_Disown")) { if (isset($_POST['confirm'])) { - $via = isset($_POST['via']) ? $_POST['via'] : NULL; list($ret, $output) = pkgbase_adopt($ids, false, $via); } else { $output = __("The selected packages have not been disowned, check the confirmation checkbox."); @@ -68,7 +68,6 @@ if (check_token()) { list($ret, $output) = pkgbase_vote($ids, false); } elseif (current_action("do_Delete")) { if (isset($_POST['confirm'])) { - $via = isset($_POST['via']) ? $_POST['via'] : NULL; if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) { list($ret, $output) = pkgbase_delete($ids, NULL, $via); unset($_GET['ID']); @@ -129,7 +128,7 @@ if (check_token()) { if ($ret) { if (current_action("do_CloseRequest") || - (current_action("do_Delete") && $_POST['via'])) { + (current_action("do_Delete") && $via)) { /* Redirect back to package request page on success. */ header('Location: ' . get_pkgreq_route()); exit(); From 48f28375255a2614269e4c6c38ecd6c61fe44cfd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 1 Mar 2017 20:01:10 +0100 Subject: [PATCH 0346/1891] aur-schema.sql: Do not recreate the database Modify the schema such that it only creates the necessary tables, indices and predefined data. This makes it easier to import the schema into a database with a name other than "AUR". Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 3 --- 1 file changed, 3 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index b75a257c..418e5323 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -1,9 +1,6 @@ -- The MySQL database layout for the AUR. Certain data -- is also included such as AccountTypes, etc. -- -DROP DATABASE IF EXISTS AUR; -CREATE DATABASE AUR DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; -USE AUR; -- Define the Account Types for the AUR. -- From da4bd3b59efe63899e2271980cf1c7751b9fa6dc Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 1 Mar 2017 20:12:57 +0100 Subject: [PATCH 0347/1891] Add a Makefile to build an SQLite-compatible schema Allow for automatically converting the schema into a schema that works with SQLite by running `make` from the schema/ subdirectory. Use the new Makefile in the test suite. Signed-off-by: Lukas Fleischer --- schema/Makefile | 11 +++++++++++ test/Makefile | 8 ++++++-- test/setup.sh | 9 +-------- 3 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 schema/Makefile diff --git a/schema/Makefile b/schema/Makefile new file mode 100644 index 00000000..e0448add --- /dev/null +++ b/schema/Makefile @@ -0,0 +1,11 @@ +aur-schema-sqlite.sql: aur-schema.sql + sed \ + -e 's/ ENGINE = InnoDB//' \ + -e 's/ [A-Z]* UNSIGNED NOT NULL AUTO_INCREMENT/ INTEGER NOT NULL/' \ + -e 's/([0-9, ]*) UNSIGNED / UNSIGNED /' \ + $< >$@ + +clean: + rm -rf aur-schema-sqlite.sql + +.PHONY: clean diff --git a/test/Makefile b/test/Makefile index d6f0f740..4ce9b9be 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,6 +1,10 @@ +FOREIGN_TARGETS = ../schema/aur-schema-sqlite.sql T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) -check: $(T) +check: $(FOREIGN_TARGETS) $(T) + +$(FOREIGN_TARGETS): + $(MAKE) -C $(dir $@) $(notdir $@) clean: $(RM) -r test-results/ @@ -8,4 +12,4 @@ clean: $(T): @echo "*** $@ ***"; $(SHELL) $@ -.PHONY: check clean $(T) +.PHONY: check $(FOREIGN_TARGETS) clean $(T) diff --git a/test/setup.sh b/test/setup.sh index 2959a4e6..64ba88f2 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -106,14 +106,7 @@ export SSH_CLIENT SSH_CONNECTION SSH_TTY # Initialize the test database. rm -f aur.db -sed \ - -e '/^DROP DATABASE /d' \ - -e '/^CREATE DATABASE /d' \ - -e '/^USE /d' \ - -e 's/ ENGINE = InnoDB//' \ - -e 's/ [A-Z]* UNSIGNED NOT NULL AUTO_INCREMENT/ INTEGER NOT NULL/' \ - -e 's/([0-9, ]*) UNSIGNED / UNSIGNED /' \ - "$TOPLEVEL/schema/aur-schema.sql" | sqlite3 aur.db +sqlite3 aur.db <"$TOPLEVEL/schema/aur-schema-sqlite.sql" echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 2);" | sqlite3 aur.db From 28f33e7bb1d1ecb1b52ae2b2d876438cd25e3662 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Wed, 1 Mar 2017 01:46:19 -0500 Subject: [PATCH 0348/1891] Fix quote for Source column default Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 418e5323..b42b45d1 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -227,7 +227,7 @@ CREATE INDEX RelationsRelName ON PackageRelations (RelName); -- CREATE TABLE PackageSources ( PackageID INTEGER UNSIGNED NOT NULL, - Source VARCHAR(8000) NOT NULL DEFAULT "/dev/null", + Source VARCHAR(8000) NOT NULL DEFAULT '/dev/null', SourceArch VARCHAR(255) NULL DEFAULT NULL, FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE ) ENGINE = InnoDB; From c19284c78364e9c1663d69a963b9b0a89fdb2852 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Wed, 1 Mar 2017 01:46:20 -0500 Subject: [PATCH 0349/1891] gendummydata.py: Fix to make it less db specific Sqlite3 does not support the MD5 function like MySQL does, instead of the database program hash the passwords, have Python's hashlib module do it instead. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- schema/gendummydata.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 9dd2f455..373f82ea 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -9,6 +9,7 @@ usage: gendummydata.py outputfilename.sql # package names. It generates the SQL statements to # insert these users/packages into the AUR database. # +import hashlib import random import time import os @@ -170,9 +171,11 @@ for u in user_keys: # pass + h = hashlib.new('md5') + h.update(u.encode()); s = ("INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd)" - " VALUES (%d, %d, '%s', '%s@example.com', MD5('%s'));\n") - s = s % (seen_users[u], account_type, u, u, u) + " VALUES (%d, %d, '%s', '%s@example.com', '%s');\n") + s = s % (seen_users[u], account_type, u, u, h.hexdigest()) out.write(s) log.debug("Number of developers: %d" % len(developers)) @@ -202,9 +205,9 @@ for p in list(seen_pkgs.keys()): uuid = genUID() # the submitter/user - s = ("INSERT INTO PackageBases (ID, Name, SubmittedTS, " - "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', %d, %d, %s, %s);\n") - s = s % (seen_pkgs[p], p, NOW, uuid, muid, puid) + s = ("INSERT INTO PackageBases (ID, Name, SubmittedTS, ModifiedTS, " + "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', %d, %d, %d, %s, %s);\n") + s = s % (seen_pkgs[p], p, NOW, NOW, uuid, muid, puid) out.write(s) s = ("INSERT INTO Packages (ID, PackageBaseID, Name, Version) VALUES " @@ -303,7 +306,7 @@ for t in range(0, OPEN_PROPOSALS+CLOSE_PROPOSALS): user = user_keys[random.randrange(0,len(user_keys))] suid = trustedusers[random.randrange(0,len(trustedusers))] s = ("INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End," - " SubmitterID) VALUES ('%s', '%s', %d, %d, %d);\n") + " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n") s = s % (genFortune(), user, start, end, suid) out.write(s) count += 1 From 7ee97933de51ace985a732f63906a6f8c8102d34 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 2 Mar 2017 21:44:29 +0100 Subject: [PATCH 0350/1891] account_delete.php: Fix variable name Signed-off-by: Lukas Fleischer --- web/template/account_delete.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/account_delete.php b/web/template/account_delete.php index 74f386da..718b172f 100644 --- a/web/template/account_delete.php +++ b/web/template/account_delete.php @@ -7,7 +7,7 @@
    - +
    From 9de633b1f2b5c9462624e00d2d17d947436bc83f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 3 Mar 2017 20:30:57 +0100 Subject: [PATCH 0351/1891] test/setup.sh: Error out on missing SQLite schema Instead of making all tests fail, error out during initialization if the SQLite schema has not been generated. Signed-off-by: Lukas Fleischer --- test/setup.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/setup.sh b/test/setup.sh index 64ba88f2..b71e73e8 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -105,8 +105,10 @@ SSH_TTY=/dev/pts/0 export SSH_CLIENT SSH_CONNECTION SSH_TTY # Initialize the test database. +DBSCHEMA="$TOPLEVEL/schema/aur-schema-sqlite.sql" +[ -f "$DBSCHEMA" ] || error 'SQLite database schema not found' rm -f aur.db -sqlite3 aur.db <"$TOPLEVEL/schema/aur-schema-sqlite.sql" +sqlite3 aur.db <"$DBSCHEMA" echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 2);" | sqlite3 aur.db From 682de0ead75318ce9d19675152cafc370abc287c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 4 Mar 2017 13:20:37 +0100 Subject: [PATCH 0352/1891] index.php: Remove routes for dropped images Signed-off-by: Lukas Fleischer --- web/html/index.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/web/html/index.php b/web/html/index.php index 78ab6ad7..364d399c 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -170,8 +170,6 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { case "/css/archnavbar/archlogo.png": case "/css/archnavbar/aurlogo.png": case "/images/favicon.ico": - case "/images/titlelogo.png": - case "/images/x.png": header("Content-Type: image/png"); readfile("./$path"); break; @@ -181,7 +179,6 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { case "/images/pin.min.svg": case "/images/unpin.min.svg": case "/images/rss.svg": - case "/images/new.svg": header("Content-Type: image/svg+xml"); readfile("./$path"); break; From 0ba88c4795284a3bac967a52a3a395f1ca2f50d7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 9 Mar 2017 06:18:06 +0100 Subject: [PATCH 0353/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/de.po | 6 +- po/es.po | 34 ++++----- po/es_419.po | 32 ++++---- po/fr.po | 32 ++++---- po/ja.po | 6 +- po/nb.po | 205 +++++++++++++++++++++++++++++++-------------------- po/sr.po | 32 ++++---- 7 files changed, 196 insertions(+), 151 deletions(-) diff --git a/po/de.po b/po/de.po index 7eb709b9..1de9b15e 100644 --- a/po/de.po +++ b/po/de.po @@ -26,7 +26,7 @@ msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 16:16+0000\n" +"PO-Revision-Date: 2017-02-26 19:30+0000\n" "Last-Translator: Stefan Auditor \n" "Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" "de/)\n" @@ -152,7 +152,7 @@ msgid "Home" msgstr "Startseite" msgid "My Flagged Packages" -msgstr "Mein markierten Pakete" +msgstr "Meine markierten Pakete" msgid "My Requests" msgstr "Meine Anfragen" @@ -167,7 +167,7 @@ msgid "Co-Maintained Packages" msgstr "Ko-Maintainer Pakete" msgid "Search for packages I co-maintain" -msgstr "Suche nach Paketen die ich betreue ko-maintaine" +msgstr "Suche nach Paketen die ich mitbetreue" #, php-format msgid "" diff --git a/po/es.po b/po/es.po index a141ff57..ce9cdf99 100644 --- a/po/es.po +++ b/po/es.po @@ -12,15 +12,15 @@ # Pablo Roberto “Jristz” Lezaeta Reyes , 2012 # Pablo Roberto “Jristz” Lezaeta Reyes , 2016 # Pablo Roberto “Jristz” Lezaeta Reyes , 2013-2016 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016-2017 # Pablo Roberto “Jristz” Lezaeta Reyes , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" -"Last-Translator: Lukas Fleischer \n" +"PO-Revision-Date: 2017-03-01 05:08+0000\n" +"Last-Translator: Pablo Roberto “Jristz” Lezaeta Reyes \n" "Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" "es/)\n" "Language: es\n" @@ -139,28 +139,28 @@ msgid "Edit comment" msgstr "Editar comentario" msgid "Dashboard" -msgstr "" +msgstr "Tablero" msgid "Home" msgstr "Inicio" msgid "My Flagged Packages" -msgstr "" +msgstr "Mis paquetes marcados" msgid "My Requests" -msgstr "" +msgstr "Mis solicitudes" msgid "My Packages" msgstr "Mis paquetes" msgid "Search for packages I maintain" -msgstr "" +msgstr "Buscar paquetes que mantengo" msgid "Co-Maintained Packages" -msgstr "" +msgstr "Paquetes que soy coencargado" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Buscar paquetes que soy coencargado" #, php-format msgid "" @@ -410,7 +410,7 @@ msgid "Enter your e-mail address:" msgstr "Introduce tu dirección de correo:" msgid "Package Bases" -msgstr "" +msgstr "Paquetes base" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -666,7 +666,7 @@ msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." msgid "Timezone is not currently supported." -msgstr "" +msgstr "El huso horario no es admitido actualmente." #, php-format msgid "The username, %s%s%s, is already in use." @@ -1038,7 +1038,7 @@ msgid "Language" msgstr "Idioma" msgid "Timezone" -msgstr "" +msgstr "Huso horario" msgid "" "The following information is only required if you want to submit packages to " @@ -1383,7 +1383,7 @@ msgstr "" "ponerte en contacto con él anteriormente." msgid "No requests matched your search criteria." -msgstr "" +msgstr "Ninguna solicitud coincide con tu criterio de búsqueda." #, php-format msgid "%d package request found." @@ -1429,7 +1429,7 @@ msgid "Close" msgstr "Cerrar" msgid "Pending" -msgstr "" +msgstr "Pendiente" msgid "Closed" msgstr "Cerrada" @@ -1447,10 +1447,10 @@ msgid "Exact Package Base" msgstr "Paquete base exacto" msgid "Co-maintainer" -msgstr "" +msgstr "Coencargado" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Encargado y coencargado" msgid "All" msgstr "Todos" @@ -1504,7 +1504,7 @@ msgid "Error retrieving package list." msgstr "Error al recuperar la lista de paquetes." msgid "No packages matched your search criteria." -msgstr "Ningún paquete coincide con su criterio de búsqueda." +msgstr "Ningún paquete coincide con tu criterio de búsqueda." #, php-format msgid "%d package found." diff --git a/po/es_419.po b/po/es_419.po index d065cf9c..fc845de0 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -10,15 +10,15 @@ # Nicolás de la Torre , 2012 # Pablo Roberto “Jristz” Lezaeta Reyes , 2016 # Pablo Roberto “Jristz” Lezaeta Reyes , 2012,2015-2016 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Roberto “Jristz” Lezaeta Reyes , 2016-2017 # Pablo Roberto “Jristz” Lezaeta Reyes , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" -"Last-Translator: Lukas Fleischer \n" +"PO-Revision-Date: 2017-03-01 05:08+0000\n" +"Last-Translator: Pablo Roberto “Jristz” Lezaeta Reyes \n" "Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" "aur/language/es_419/)\n" "Language: es_419\n" @@ -137,28 +137,28 @@ msgid "Edit comment" msgstr "Editar comentario" msgid "Dashboard" -msgstr "" +msgstr "Tablero" msgid "Home" msgstr "Inicio" msgid "My Flagged Packages" -msgstr "" +msgstr "Mis paquetes marcados" msgid "My Requests" -msgstr "" +msgstr "Mis peticiones" msgid "My Packages" msgstr "Mis paquetes" msgid "Search for packages I maintain" -msgstr "" +msgstr "Buscar paquetes que soy encargado" msgid "Co-Maintained Packages" -msgstr "" +msgstr "Paquetes que soy coencargado" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Buscar paquetes que soy coencargado" #, php-format msgid "" @@ -407,7 +407,7 @@ msgid "Enter your e-mail address:" msgstr "Introduzca su dirección de correo:" msgid "Package Bases" -msgstr "" +msgstr "Paquetes base" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -662,7 +662,7 @@ msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." msgid "Timezone is not currently supported." -msgstr "" +msgstr "La zona horaria no se admite actualmente." #, php-format msgid "The username, %s%s%s, is already in use." @@ -1031,7 +1031,7 @@ msgid "Language" msgstr "Idioma" msgid "Timezone" -msgstr "" +msgstr "Zona horaria" msgid "" "The following information is only required if you want to submit packages to " @@ -1375,7 +1375,7 @@ msgstr "" "intentó ponerse en contacto con él anteriormente." msgid "No requests matched your search criteria." -msgstr "" +msgstr "Ninguna peticiones coincide con su criterio de búsqueda." #, php-format msgid "%d package request found." @@ -1421,7 +1421,7 @@ msgid "Close" msgstr "Cerrar" msgid "Pending" -msgstr "" +msgstr "Pendiente" msgid "Closed" msgstr "Cerrada" @@ -1439,10 +1439,10 @@ msgid "Exact Package Base" msgstr "Paquete base exacto" msgid "Co-maintainer" -msgstr "" +msgstr "Coencargado" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Encargado y coencargado" msgid "All" msgstr "Todos" diff --git a/po/fr.po b/po/fr.po index 0bb3ccd4..80094a03 100644 --- a/po/fr.po +++ b/po/fr.po @@ -10,14 +10,14 @@ # lordheavy , 2013-2014 # lordheavy , 2011-2012 # Lukas Fleischer , 2011 -# Xorg , 2015 +# Xorg , 2015,2017 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" -"Last-Translator: Lukas Fleischer \n" +"PO-Revision-Date: 2017-02-28 19:55+0000\n" +"Last-Translator: Xorg \n" "Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" "fr/)\n" "Language: fr\n" @@ -137,28 +137,28 @@ msgid "Edit comment" msgstr "Éditer le commentaire" msgid "Dashboard" -msgstr "" +msgstr "Tableau de bord" msgid "Home" msgstr "Accueil" msgid "My Flagged Packages" -msgstr "" +msgstr "Mes paquets périmés" msgid "My Requests" -msgstr "" +msgstr "Mes requêtes" msgid "My Packages" msgstr "Mes paquets" msgid "Search for packages I maintain" -msgstr "" +msgstr "Rechercher les paquets que je maintiens" msgid "Co-Maintained Packages" -msgstr "" +msgstr "Paquets co-maintenus" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Rechercher les paquets que je co-maintiens" #, php-format msgid "" @@ -409,7 +409,7 @@ msgid "Enter your e-mail address:" msgstr "Entrez votre adresse e-mail :" msgid "Package Bases" -msgstr "" +msgstr "Bases du paquet" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -670,7 +670,7 @@ msgid "Language is not currently supported." msgstr "Cette langue n'est pas supportée pour le moment." msgid "Timezone is not currently supported." -msgstr "" +msgstr "Le fuseau horaire n'est actuellement pas pris en charge" #, php-format msgid "The username, %s%s%s, is already in use." @@ -1049,7 +1049,7 @@ msgid "Language" msgstr "Langue" msgid "Timezone" -msgstr "" +msgstr "Fuseau horaire" msgid "" "The following information is only required if you want to submit packages to " @@ -1391,7 +1391,7 @@ msgstr "" "le mainteneur." msgid "No requests matched your search criteria." -msgstr "" +msgstr "Aucune requête ne correspond à vos critères de recherche." #, php-format msgid "%d package request found." @@ -1437,7 +1437,7 @@ msgid "Close" msgstr "Fermer" msgid "Pending" -msgstr "" +msgstr "En attente" msgid "Closed" msgstr "Fermé" @@ -1455,10 +1455,10 @@ msgid "Exact Package Base" msgstr "Paquet de base exact" msgid "Co-maintainer" -msgstr "" +msgstr "Co-mainteneurs" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Mainteneur, co-mainteneur" msgid "All" msgstr "Tout" diff --git a/po/ja.po b/po/ja.po index a649f077..85168f08 100644 --- a/po/ja.po +++ b/po/ja.po @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" -"Last-Translator: Lukas Fleischer \n" +"PO-Revision-Date: 2017-02-27 14:39+0000\n" +"Last-Translator: kusakata\n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" "ja/)\n" "Language: ja\n" @@ -1353,7 +1353,7 @@ msgstr "" "にのみ、リクエストを送信してください。" msgid "No requests matched your search criteria." -msgstr "" +msgstr "検索条件に一致するリクエストがありません。" #, php-format msgid "%d package request found." diff --git a/po/nb.po b/po/nb.po index 2961989f..7c2a0274 100644 --- a/po/nb.po +++ b/po/nb.po @@ -14,8 +14,8 @@ msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" -"Last-Translator: Lukas Fleischer \n" +"PO-Revision-Date: 2017-03-02 10:39+0000\n" +"Last-Translator: Alexander F Rødseth \n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" "language/nb/)\n" "Language: nb\n" @@ -131,28 +131,28 @@ msgid "Edit comment" msgstr "Rediger kommentar" msgid "Dashboard" -msgstr "" +msgstr "Instrumentpanel" msgid "Home" msgstr "Hjem" msgid "My Flagged Packages" -msgstr "" +msgstr "Mine pakker med anmerkninger" msgid "My Requests" -msgstr "" +msgstr "Mine forespørsler" msgid "My Packages" msgstr "Mine pakker" msgid "Search for packages I maintain" -msgstr "" +msgstr "Søk etter pakker jeg vedlikeholder" msgid "Co-Maintained Packages" -msgstr "" +msgstr "Med-vedlikeholdte pakker" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Søk etter pakker jeg er med på å vedlikeholde" #, php-format msgid "" @@ -240,6 +240,8 @@ msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"Hvis du vil diskutere en forespørsel kan du bruke %saur-request%s e-post " +"listen. Vennligst ikke send nye forespørsler dit." msgid "Submitting Packages" msgstr "Innsending av pakker" @@ -266,6 +268,10 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"Generell diskusjon rundt Arch sitt brukerstyrte pakkebibliotek (AUR) og " +"strukturen rundt betrodde brukere, foregår på %saur-general%s. For " +"diskusjoner relatert til utviklingen av AUR web-grensesnittet, bruk %saur-dev" +"%s e-postlisten." msgid "Bug Reporting" msgstr "Feilrapportering" @@ -277,6 +283,11 @@ msgid "" "%sonly%s. To report packaging bugs contact the package maintainer or leave a " "comment on the appropriate package page." msgstr "" +"Vennligst fyll ut en feilrapport i %sfeilrapporteringssystemet%s dersom du " +"finner en feil i AUR sitt web-grensesnitt. Bruk denne %skun%s til å " +"rapportere feil som gjelder AUR sitt web-grensesnitt. For å rapportere feil " +"med pakker, kontakt personen som vedlikeholder pakken eller legg igjen en " +"kommentar på siden til den aktuelle pakken." msgid "Package Search" msgstr "Pakkesøk" @@ -386,12 +397,14 @@ msgid "Enter your e-mail address:" msgstr "Angi din e-postadresse:" msgid "Package Bases" -msgstr "" +msgstr "Pakkebaser" msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +"De valgte pakkene har ikke blitt gjort foreldreløse, husk å krysse av i " +"boksen for å bekrefte." msgid "Cannot find package to merge votes and comments into." msgstr "Kunne ikke finne pakke for å flette stemmer og kommentarer inn i." @@ -441,48 +454,60 @@ msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"Bruk dette skjemaet for å gjøre pakkebasen %s%s%s foreldreløs. Den " +"inkluderer følgende pakker:" #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +"Ved å krysse av i boksen bekrefter du at du ønsker å si fra deg pakken samt " +"overføre eierskapet til %s%s%s." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +"Ved å krysse av i boksen bekrefter du at du ønsker å gjøre pakken " +"foreldreløs." msgid "Confirm to disown the package" -msgstr "" +msgstr "Bekreft at du ønsker å gjøre pakken foreldreløs." msgid "Disown" msgstr "Gjør foreldreløs" msgid "Only Trusted Users and Developers can disown packages." -msgstr "" +msgstr "Bare betrodde brukere og Arch utviklere kan gjøre pakker foreldreløse." msgid "Flag Comment" -msgstr "" +msgstr "Flagg kommentar" msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Flagg pakke som utdatert" #, php-format msgid "" "Use this form to flag the package base %s%s%s and the following packages out-" "of-date: " msgstr "" +"Bruk skjemaet for å flagge pakkebasen %s%s%s og følgende pakker som " +"utdaterte:" #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"Vennligst %sikke%s bruk dette skjemaet for å rapportere feil. Bruk " +"kommentarfeltet for pakken istedenfor." msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +"Skriv inn hvorfor pakken er utdatert nedenfor, helst med lenker til teksten " +"som annonserer slippet av den nye versjonen, eller den nye kildekodepakken." msgid "Comments" msgstr "Kommentarer" @@ -491,7 +516,7 @@ msgid "Flag" msgstr "Markering" msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "Bare registrerte brukere kan flagge pakker som utdaterte." msgid "Package Merging" msgstr "Pakkesammenslåing" @@ -526,7 +551,7 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "Bare betrodde brukere og utviklere kan slå sammen pakker." msgid "Submit Request" -msgstr "" +msgstr "Send inn forespørsel" msgid "Close Request" msgstr "Lukk forespørsel" @@ -613,7 +638,7 @@ msgid "The PGP key fingerprint is invalid." msgstr "PGP fingeravtrykket er ikke gyldig." msgid "The SSH public key is invalid." -msgstr "" +msgstr "Den offentlige SSH-nøkkelen er ugyldig." msgid "Cannot increase account permissions." msgstr "Kan ikke gi flere tillatelser til kontoen." @@ -622,7 +647,7 @@ msgid "Language is not currently supported." msgstr "Språket støttes ikke på dette tidspunktet." msgid "Timezone is not currently supported." -msgstr "" +msgstr "Den tidssonen støttes ikke akkurat nå" #, php-format msgid "The username, %s%s%s, is already in use." @@ -634,7 +659,7 @@ msgstr "Adressen, %s%s%s, er allerede i bruk." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "Den offentlige SSH-nøkkelen, %s%s%s, er allerede i bruk." #, php-format msgid "Error trying to create account, %s%s%s." @@ -696,16 +721,16 @@ msgid "View account information for %s" msgstr "Vis kontoinformasjon for %s" msgid "Package base ID or package base name missing." -msgstr "" +msgstr "ID eller navn for pakkebasen mangler." msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Du får ikke lov til å redigere denne kommentaren." msgid "Comment does not exist." -msgstr "" +msgstr "Kommentaren finnes ikke." msgid "Comment cannot be empty." -msgstr "" +msgstr "Kommentaren kan ikke være tom." msgid "Comment has been added." msgstr "Kommentar har blitt lagt til." @@ -717,19 +742,19 @@ msgid "Missing comment ID." msgstr "Mangler kommentar-ID." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "Maks 5 kommentarer kan festes." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Du får ikke lov til å feste denne kommentaren." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "Du får ikke lov til å løsrive denne kommentaren." msgid "Comment has been pinned." -msgstr "" +msgstr "Kommentar har blitt festet." msgid "Comment has been unpinned." -msgstr "" +msgstr "Kommentar har blitt løsrevet." msgid "Error retrieving package details." msgstr "Kunne ikke finne frem pakkedetaljer." @@ -745,6 +770,7 @@ msgstr "Ingen pakker ble valgt for å bli markert." msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +"De valgte pakkene har ikke blitt flagget. Vennligst skriv inn en kommentar." msgid "The selected packages have been flagged out-of-date." msgstr "De valgte pakkene har nå blitt markert som utdaterte." @@ -813,10 +839,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "Du har blitt fjernet fra kommentarpåminnelselisten for %s." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Du får ikke lov til å angre på å slette denne kommentaren." msgid "Comment has been undeleted." -msgstr "" +msgstr "Kommentaren har ikke blitt slettet allikevel." msgid "You are not allowed to delete this comment." msgstr "Du har ikke tilgang til å slette denne kommentaren." @@ -825,30 +851,31 @@ msgid "Comment has been deleted." msgstr "Kommentar slettet." msgid "Comment has been edited." -msgstr "" +msgstr "Kommentaren har blitt redigert." msgid "You are not allowed to edit the keywords of this package base." -msgstr "" +msgstr "Du får ikke lov til å redigere nøkkelordene til denne pakkebasen." msgid "The package base keywords have been updated." -msgstr "" +msgstr "Pakkebasenøkkelordene har blitt oppdatert." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +"Du får ikke lov til å håndtere med-vedlikeholdere for denne pakkebasen." #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Ugyldig brukernavn: %s" msgid "The package base co-maintainers have been updated." -msgstr "" +msgstr "Med-vedlikeholdere for denne pakkebasen har blitt oppdatert." msgid "View packages details for" msgstr "Vis pakkedetaljer for" #, php-format msgid "requires %s" -msgstr "" +msgstr "behøver %s" msgid "You must be logged in to file package requests." msgstr "Du må være logget inn for å kunne sende inn forespørsler om pakker." @@ -904,13 +931,13 @@ msgid "Email Address" msgstr "E-postadresse" msgid "hidden" -msgstr "" +msgstr "gjemt" msgid "Real Name" msgstr "Ekte navn" msgid "Homepage" -msgstr "" +msgstr "Hjemmeside" msgid "IRC Nick" msgstr "IRC-kallenavn" @@ -928,7 +955,7 @@ msgid "Active" msgstr "Aktiv" msgid "Registration date:" -msgstr "" +msgstr "Registreringsdato:" msgid "unknown" msgstr "ukjent" @@ -951,7 +978,7 @@ msgstr "Klikk %sher%s hvis du vil slette denne kontoen, for alltid." #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "Klikk %sher%s for brukerdetaljer." msgid "required" msgstr "trengs" @@ -976,7 +1003,7 @@ msgstr "" "låst ute." msgid "Hide Email Address" -msgstr "" +msgstr "Gjem e-postadresse" msgid "Re-type password" msgstr "Skriv inn passordet på nytt" @@ -985,27 +1012,29 @@ msgid "Language" msgstr "Språk" msgid "Timezone" -msgstr "" +msgstr "Tidssone" msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"Følgende informasjon trengs bare dersom du vil sende inn pakker til Arch " +"sitt brukerstyrte pakkebibliotek." msgid "SSH Public Key" -msgstr "" +msgstr "Offentlig SSH-nøkkel" msgid "Notification settings" -msgstr "" +msgstr "Varslingsinstillinger" msgid "Notify of new comments" msgstr "Gi beskjed om nye kommentarer" msgid "Notify of package updates" -msgstr "" +msgstr "Varsle om pakkeoppdateringer" msgid "Notify of ownership changes" -msgstr "" +msgstr "Varsle om endring av eierskap" msgid "Update" msgstr "Oppdater" @@ -1041,31 +1070,33 @@ msgstr "Ingen flere resultater å vise." msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +"Bruk dette skjemaet for å legge til med-vedlikeholdere for %s%s%s (ett " +"brukernavn per linje):" msgid "Users" -msgstr "" +msgstr "Brukere" msgid "Save" -msgstr "" +msgstr "Lagre" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Flagget kommentar som utdatert: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" +msgstr "%s%s%s flagget %s%s%s som utdatert den %s%s%s av følgende årsak:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s er ikke flagget som utdatert." msgid "Return to Details" -msgstr "" +msgstr "Returner til detaljer" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "Kopibeskyttet %s 2004-%d aurweb utviklingsgruppe." msgid " My Account" msgstr " Min konto" @@ -1077,17 +1108,17 @@ msgid "View PKGBUILD" msgstr "Vis PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Vis endringer" msgid "Download snapshot" -msgstr "" +msgstr "Last ned fryst bilde" msgid "Search wiki" msgstr "Søk wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Flagget som utdatert (%s)" msgid "Flag package out-of-date" msgstr "Marker pakke som utdatert" @@ -1105,10 +1136,10 @@ msgid "Disable notifications" msgstr "Slå av beskjeder" msgid "Enable notifications" -msgstr "" +msgstr "Få beskjed" msgid "Manage Co-Maintainers" -msgstr "" +msgstr "Behandle med-vedlikeholdere" #, php-format msgid "%d pending request" @@ -1123,10 +1154,10 @@ msgid "Package Base Details" msgstr "Grunnpakkedetaljer" msgid "Git Clone URL" -msgstr "" +msgstr "Git clone URL" msgid "read-only" -msgstr "" +msgstr "skrivebeskyttet" msgid "Keywords" msgstr "Nøkkelord" @@ -1144,7 +1175,7 @@ msgid "Votes" msgstr "Stemmer" msgid "Popularity" -msgstr "" +msgstr "Popularitet" msgid "First Submitted" msgstr "Først innsendt" @@ -1154,7 +1185,7 @@ msgstr "Sist oppdatert" #, php-format msgid "Edit comment for: %s" -msgstr "" +msgstr "Rediger kommentar for: %s" msgid "Add Comment" msgstr "Legg til kommentar" @@ -1163,46 +1194,46 @@ msgid "View all comments" msgstr "Vis alle kommentarer" msgid "Pinned Comments" -msgstr "" +msgstr "La stå" msgid "Latest Comments" msgstr "Siste kommentarer" #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s kommenterte %s" #, php-format msgid "Anonymous comment on %s" -msgstr "" +msgstr "Anonym kommenterte %s" #, php-format msgid "deleted on %s by %s" -msgstr "" +msgstr "slettet %s av %s" #, php-format msgid "deleted on %s" -msgstr "" +msgstr "slettet %s" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "redigert %s av %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "redigert %s" msgid "Undelete comment" -msgstr "" +msgstr "Angre sletting av kommentar" msgid "Delete comment" msgstr "Slett kommentar" msgid "Pin comment" -msgstr "" +msgstr "Fest kommentar" msgid "Unpin comment" -msgstr "" +msgstr "Løsne kommentar" msgid "All comments" msgstr "Alle kommentarer" @@ -1291,6 +1322,10 @@ msgid "" "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +"Ved å sende inn en forespørsel om sletting spør du en betrodd bruker om å " +"slette pakken. Slike forespørsler bør brukes om duplikater, forlatt " +"programvare samt ulovlige eller pakker som er så ødelagte at de ikke lenger " +"kan fikses." msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " @@ -1298,6 +1333,10 @@ msgid "" "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." msgstr "" +"Ved å sende inn en forespørsel om sammenslåing spør du en betrodd bruker om " +"å slette pakken. Stemmer og kommentarer vil bli overført til en annen pakke. " +"Å slå sammen en pakke har ingen effekt på korresponderende Git repo. Pass på " +"å oppdatere Git historikken til målpakken selv." msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " @@ -1305,9 +1344,13 @@ msgid "" "the maintainer is MIA and you already tried to contact the maintainer " "previously." msgstr "" +"Ved å sende inn en forespørsel om å gjøre en pakke foreldreløs spør du en " +"betrodd bruker om å utføre dette. Vennligst bare send inn forespørselen " +"dersom pakken trenger vedlikehold, nåværende vedlikeholder er fraværende og " +"du allerede har prøvd å kontakte den som vedlikeholder pakken." msgid "No requests matched your search criteria." -msgstr "" +msgstr "Ingen treff på forespørsler." #, php-format msgid "%d package request found." @@ -1331,8 +1374,8 @@ msgstr "Dato" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "~%d dag igjen" +msgstr[1] "~%d dager igjen" #, php-format msgid "~%d hour left" @@ -1353,7 +1396,7 @@ msgid "Close" msgstr "Lukk" msgid "Pending" -msgstr "" +msgstr "I kø" msgid "Closed" msgstr "Lukket" @@ -1371,10 +1414,10 @@ msgid "Exact Package Base" msgstr "Eksakt grunnpakke" msgid "Co-maintainer" -msgstr "" +msgstr "Med-vedlikeholder" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Vedlikeholder, med-vedlikeholder" msgid "All" msgstr "Alle" @@ -1392,7 +1435,7 @@ msgid "Voted" msgstr "Stemt" msgid "Last modified" -msgstr "" +msgstr "Sist endret" msgid "Ascending" msgstr "Stigende" @@ -1444,6 +1487,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"Populariteten beregnes som summen av alle stemmer der hver stemme vekktes " +"med en faktor på %.2f per dag siden den ble avlagt." msgid "Yes" msgstr "Ja" @@ -1500,10 +1545,10 @@ msgid "Trusted Users" msgstr "Betrodde Brukere" msgid "Recent Updates" -msgstr "Nylige oppdateringer" +msgstr "Nylig oppdatert" msgid "more" -msgstr "" +msgstr "mer" msgid "My Statistics" msgstr "Min statistikk" diff --git a/po/sr.po b/po/sr.po index 4cf8d12c..5e2268c0 100644 --- a/po/sr.po +++ b/po/sr.po @@ -4,15 +4,15 @@ # # Translators: # Lukas Fleischer , 2011 -# Slobodan Terzić , 2011-2012,2015-2016 +# Slobodan Terzić , 2011-2012,2015-2017 # Slobodan Terzić , 2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" -"Last-Translator: Lukas Fleischer \n" +"PO-Revision-Date: 2017-02-26 16:21+0000\n" +"Last-Translator: Slobodan Terzić \n" "Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" "sr/)\n" "Language: sr\n" @@ -130,28 +130,28 @@ msgid "Edit comment" msgstr "Uređivanje komentara" msgid "Dashboard" -msgstr "" +msgstr "Komandna tabla" msgid "Home" msgstr "Početna" msgid "My Flagged Packages" -msgstr "" +msgstr "Moji označeni paketi" msgid "My Requests" -msgstr "" +msgstr "Moji zahtevi" msgid "My Packages" msgstr "Moji paketi" msgid "Search for packages I maintain" -msgstr "" +msgstr "Pretraži pakete koje održavam" msgid "Co-Maintained Packages" -msgstr "" +msgstr "Koodržavani paketi" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Pretraži pakete koje koodržavam" #, php-format msgid "" @@ -394,7 +394,7 @@ msgid "Enter your e-mail address:" msgstr "Unesite adresu e-pošte:" msgid "Package Bases" -msgstr "" +msgstr "Osnove paketa" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -635,7 +635,7 @@ msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." msgid "Timezone is not currently supported." -msgstr "" +msgstr "Vremenska zona trenutno nije podržana." #, php-format msgid "The username, %s%s%s, is already in use." @@ -997,7 +997,7 @@ msgid "Language" msgstr "Jezik" msgid "Timezone" -msgstr "" +msgstr "Vremenska zona" msgid "" "The following information is only required if you want to submit packages to " @@ -1335,7 +1335,7 @@ msgstr "" "kontaktirate." msgid "No requests matched your search criteria." -msgstr "" +msgstr "Nema zahteva koji odgovaraju kriterijumu pretrage." #, php-format msgid "%d package request found." @@ -1384,7 +1384,7 @@ msgid "Close" msgstr "Zatvori" msgid "Pending" -msgstr "" +msgstr "Na čekanju" msgid "Closed" msgstr "Zatvoreno" @@ -1402,10 +1402,10 @@ msgid "Exact Package Base" msgstr "Tačna osnova paketa" msgid "Co-maintainer" -msgstr "" +msgstr "Koodržavalac" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Održavalac, koodržavalac" msgid "All" msgstr "svi" From a7606d0e1be37a565ca4dd48efca49a34314970c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 9 Mar 2017 06:18:34 +0100 Subject: [PATCH 0354/1891] Release 4.5.1 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index e18873e3..20132d80 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Thu, 6 Apr 2017 05:56:28 +0200 Subject: [PATCH 0355/1891] git-update: Check for missing pkgname entries Reject commits containing .SRCINFO files without any pkgname entries. Suggested-by: Bruno Pagani Signed-off-by: Lukas Fleischer --- aurweb/git/update.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 3b84eb5d..532db92d 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -308,6 +308,9 @@ def main(): die_commit('invalid pkgbase: {:s}'.format(metadata_pkgbase), str(commit.id)) + if not metadata['packages']: + die_commit('missing pkgname entry', str(commit.id)) + for pkgname in set(metadata['packages'].keys()): pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) From 906a8f12cc3f0d9cfd595421c450bbcffde67c18 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Wed, 12 Apr 2017 00:56:16 -0400 Subject: [PATCH 0356/1891] Add TESTING instructions for web interface Add instructions to test aurweb's web interface via the PHP built-in web server. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- INSTALL | 8 ++++++++ TESTING | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 TESTING diff --git a/INSTALL b/INSTALL index a472b277..8c9c4dd1 100644 --- a/INSTALL +++ b/INSTALL @@ -1,6 +1,14 @@ Setup on Arch Linux =================== +For testing aurweb patches before submission, you can use the instructions in +TESTING for testing the web interface only. + +Note that you can only do limited testing using the PHP built-in web server. +In particular, the cgit interface will be unusable as well as the ssh+git +interface. For a detailed description on how to setup a full aurweb server, +read the instructions below. + 1) Clone the aurweb project: $ cd /srv/http/ diff --git a/TESTING b/TESTING new file mode 100644 index 00000000..d2c97d9d --- /dev/null +++ b/TESTING @@ -0,0 +1,32 @@ +Setup Testing Environment +========================= + +Note that this setup is only to test the web interface. If you need to have a +full aurweb instance with cgit, ssh interface, etc, follow the directions in +INSTALL. + +1) Clone the aurweb project: + + $ git clone git://git.archlinux.org/aurweb.git + +2) Install php and necessary modules: + + # pacman -S php php-sqlite sqlite + +3) Prepare the testing database: + + $ cd /path/to/aurweb/schema + $ make + $ ./gendummydata.py out.sql + $ sqlite3 ../aurweb.sqlite3 < aur-schema-sqlite.sql + $ sqlite3 ../aurweb.sqlite3 < out.sql + +4) Copy conf/config.proto to conf/config and adjust the configuration + (pay attention to disable_http_login, enable_maintenance and aur_location). + + Be sure to change backend to sqlite and name to the file location of your + created test database. + +5) Run the PHP built-in web server: + + $ AUR_CONFIG='/path/to/aurweb/conf/config' php -S localhost:8080 -t /path/to/aurweb/web/html From 09cb61ab83af531a1b4ea43fd96313314d964726 Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Sat, 15 Apr 2017 20:31:37 +0200 Subject: [PATCH 0357/1891] schema: Remove invalid default values for TEXT columns When running in strict mode, mysql throws an error upon encountering these definitions since they are not supported. References: https://dev.mysql.com/doc/refman/5.7/en/data-type-defaults.html Signed-off-by: Florian Pritz Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index b42b45d1..b3e4ecbb 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -80,7 +80,7 @@ CREATE TABLE PackageBases ( NumVotes INTEGER UNSIGNED NOT NULL DEFAULT 0, Popularity DECIMAL(10,6) UNSIGNED NOT NULL DEFAULT 0, OutOfDateTS BIGINT UNSIGNED NULL DEFAULT NULL, - FlaggerComment TEXT NOT NULL DEFAULT '', + FlaggerComment TEXT NOT NULL, SubmittedTS BIGINT UNSIGNED NOT NULL, ModifiedTS BIGINT UNSIGNED NOT NULL, FlaggerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- who flagged the package out-of-date? @@ -253,7 +253,7 @@ CREATE TABLE PackageComments ( ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, PackageBaseID INTEGER UNSIGNED NOT NULL, UsersID INTEGER UNSIGNED NULL DEFAULT NULL, - Comments TEXT NOT NULL DEFAULT '', + Comments TEXT NOT NULL, CommentTS BIGINT UNSIGNED NOT NULL DEFAULT 0, EditedTS BIGINT UNSIGNED NULL DEFAULT NULL, EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, @@ -331,8 +331,8 @@ CREATE TABLE PackageRequests ( PackageBaseName VARCHAR(255) NOT NULL, MergeBaseName VARCHAR(255) NULL, UsersID INTEGER UNSIGNED NULL DEFAULT NULL, - Comments TEXT NOT NULL DEFAULT '', - ClosureComment TEXT NOT NULL DEFAULT '', + Comments TEXT NOT NULL, + ClosureComment TEXT NOT NULL, RequestTS BIGINT UNSIGNED NOT NULL DEFAULT 0, Status TINYINT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (ID), From 102dad49e727059441d5566d317e8a57def08b2d Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Sat, 15 Apr 2017 20:31:38 +0200 Subject: [PATCH 0358/1891] schema: Fix invalid NULL on primary key >From the mysql 5.7 breaking change page: Columns in a PRIMARY KEY must be NOT NULL, but if declared explicitly as NULL produced no error. Now an error occurs. For example, a statement such as CREATE TABLE t (i INT NULL PRIMARY KEY) is rejected. The same occurs for similar ALTER TABLE statements. (Bug #13995622, Bug #66987, Bug #15967545, Bug #16545198) References: http://stackoverflow.com/a/22314073 Signed-off-by: Florian Pritz Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index b3e4ecbb..89167b32 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -373,7 +373,7 @@ CREATE TABLE IF NOT EXISTS TU_Votes ( -- Malicious user banning -- CREATE TABLE Bans ( - IPAddress VARCHAR(45) NULL DEFAULT NULL, + IPAddress VARCHAR(45) NOT NULL, BanTS TIMESTAMP NOT NULL, PRIMARY KEY (IPAddress) ) ENGINE = InnoDB; From 5553d01ab362e7731da0bb238cc188faacdd3d7e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 18 Apr 2017 08:28:08 +0200 Subject: [PATCH 0359/1891] Check query return value in pkgbase_user_notify() Instead of unconditionally calling fetch on the return value of query(), error out early if the value evaluates to false. Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index cd4b2713..57933e86 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -852,12 +852,11 @@ function pkgbase_user_notify($uid, $base_id) { $q.= " AND PackageBaseID = " . $dbh->quote($base_id); $result = $dbh->query($q); - if ($result->fetch(PDO::FETCH_NUM)) { - return true; - } - else { + if (!$result) { return false; } + + return ($result->fetch(PDO::FETCH_NUM) > 0); } /** From 6090c2ae8b6b33af79cae2ed63ebe5209d0729b3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 18 Apr 2017 08:36:29 +0200 Subject: [PATCH 0360/1891] Check query return value in search_results_page() Instead of unconditionally calling fetch on the return value of query(), error out early if the value evaluates to false. Also, make sure that the results array is always initialized, even if the result set is empty. Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 3c8f9edb..22b3ca8d 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -495,8 +495,11 @@ function search_results_page($O=0,$SB="",$U="",$T="", $result = $dbh->query($q); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $userinfo[] = $row; + $userinfo = array(); + if ($result) { + while ($row = $result->fetch(PDO::FETCH_ASSOC)) { + $userinfo[] = $row; + } } include("account_search_results.php"); From 4f662c773dd70145640074f2659954e8f8a3daef Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 18 Apr 2017 08:36:29 +0200 Subject: [PATCH 0361/1891] Check query return value in db_cache_value() Instead of unconditionally calling fetch on the return value of query(), error out early if the value evaluates to false. Signed-off-by: Lukas Fleischer --- web/lib/cachefuncs.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/lib/cachefuncs.inc.php b/web/lib/cachefuncs.inc.php index d558be44..faeae5a2 100644 --- a/web/lib/cachefuncs.inc.php +++ b/web/lib/cachefuncs.inc.php @@ -73,6 +73,9 @@ function db_cache_value($dbq, $key, $ttl=600) { $value = get_cache_value($key, $status); if (!$status) { $result = $dbh->query($dbq); + if (!$result) { + return false; + } $row = $result->fetch(PDO::FETCH_NUM); $value = $row[0]; set_cache_value($key, $value, $ttl); From 15501972bce458ad7862786311ca8264f5f34081 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 18 Apr 2017 08:44:24 +0200 Subject: [PATCH 0362/1891] Check return value of get_extended_fields() Make sure that the get_extended_fields() invocation succeeded before merging regular and extended fields in process_query(). Signed-off-by: Lukas Fleischer --- web/lib/aurjson.class.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index e07522d4..9eeaafde 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -313,7 +313,10 @@ class AurJSON { } if ($this->version >= 2 && ($type == 'info' || $type == 'multiinfo')) { - $row = array_merge($row, $this->get_extended_fields($row['ID'], $row['PackageBaseID'])); + $extfields = $this->get_extended_fields($row['ID'], $row['PackageBaseID']); + if ($extfields) { + $row = array_merge($row, $extfields); + } } if ($this->version < 3) { From 44858e06188946c0082bb09061fcfa6cbb33938b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 19 Apr 2017 08:53:30 +0200 Subject: [PATCH 0363/1891] Store dependency descriptions in a separate column Split optional dependency descriptions from dependency names before storing them in the database and use a separate column to store the descriptions. This allows us to simplify and optimize the SQL queries in pkg_dependencies() as well as pkg_required(). Suggested-by: Florian Pritz Signed-off-by: Lukas Fleischer --- aurweb/git/update.py | 16 +++++++--------- schema/aur-schema.sql | 1 + upgrading/4.6.0.txt | 11 +++++++++++ web/lib/pkgfuncs.inc.php | 33 ++++++++------------------------- web/template/pkg_details.php | 2 +- 5 files changed, 28 insertions(+), 35 deletions(-) create mode 100644 upgrading/4.6.0.txt diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 532db92d..09a57ef0 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -52,10 +52,7 @@ def parse_dep(depstring): depname = re.sub(r'(<|=|>).*', '', dep) depcond = dep[len(depname):] - if (desc): - return (depname + ': ' + desc, depcond) - else: - return (depname, depcond) + return (depname, desc, depcond) def create_pkgbase(conn, pkgbase, user): @@ -141,12 +138,13 @@ def save_metadata(metadata, conn, user): [deptype]) deptypeid = cur.fetchone()[0] for dep_info in extract_arch_fields(pkginfo, deptype): - depname, depcond = parse_dep(dep_info['value']) + depname, depdesc, depcond = parse_dep(dep_info['value']) deparch = dep_info['arch'] conn.execute("INSERT INTO PackageDepends (PackageID, " + - "DepTypeID, DepName, DepCondition, DepArch) " + - "VALUES (?, ?, ?, ?, ?)", - [pkgid, deptypeid, depname, depcond, deparch]) + "DepTypeID, DepName, DepDesc, DepCondition, " + + "DepArch) VALUES (?, ?, ?, ?, ?, ?)", + [pkgid, deptypeid, depname, depdesc, depcond, + deparch]) # Add package relations (conflicts, provides, replaces). for reltype in ('conflicts', 'provides', 'replaces'): @@ -154,7 +152,7 @@ def save_metadata(metadata, conn, user): [reltype]) reltypeid = cur.fetchone()[0] for rel_info in extract_arch_fields(pkginfo, reltype): - relname, relcond = parse_dep(rel_info['value']) + relname, _, relcond = parse_dep(rel_info['value']) relarch = rel_info['arch'] conn.execute("INSERT INTO PackageRelations (PackageID, " + "RelTypeID, RelName, RelCondition, RelArch) " + diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 89167b32..be6f3e54 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -187,6 +187,7 @@ CREATE TABLE PackageDepends ( PackageID INTEGER UNSIGNED NOT NULL, DepTypeID TINYINT UNSIGNED NOT NULL, DepName VARCHAR(255) NOT NULL, + DepDesc VARCHAR(255) NULL DEFAULT NULL, DepCondition VARCHAR(255), DepArch VARCHAR(255) NULL DEFAULT NULL, FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE, diff --git a/upgrading/4.6.0.txt b/upgrading/4.6.0.txt new file mode 100644 index 00000000..45740f40 --- /dev/null +++ b/upgrading/4.6.0.txt @@ -0,0 +1,11 @@ +1. Add DepDesc column to PackageDepends and split dependency names: + +--- +ALTER TABLE PackageDepends ADD COLUMN DepDesc VARCHAR(255) NULL DEFAULT NULL; +UPDATE PackageDepends + SET DepDesc = SUBSTRING(DepName FROM POSITION(': ' IN DepName) + 2) + WHERE POSITION(': ' IN DepName) > 0; +UPDATE PackageDepends + SET DepName = SUBSTRING(DepName FROM 1 FOR POSITION(': ' IN DepName) - 1) + WHERE POSITION(': ' IN DepName) > 0; +--- diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index adb21f66..5c48a8ea 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -239,9 +239,10 @@ function pkg_dependencies($pkgid, $limit) { $pkgid = intval($pkgid); if ($pkgid > 0) { $dbh = DB::connect(); - $q = "SELECT pd.DepName, dt.Name, pd.DepCondition, pd.DepArch, p.ID FROM PackageDepends pd "; + $q = "SELECT pd.DepName, dt.Name, pd.DepDesc, "; + $q.= "pd.DepCondition, pd.DepArch, p.ID "; + $q.= "FROM PackageDepends pd "; $q.= "LEFT JOIN Packages p ON pd.DepName = p.Name "; - $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) = p.Name "; $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; $q.= "WHERE pd.PackageID = ". $pkgid . " "; $q.= "ORDER BY pd.DepName LIMIT " . intval($limit); @@ -354,21 +355,14 @@ function pkg_provider_link($name, $official) { * * @param string $name The name of the dependency * @param string $type The name of the dependency type + * @param string $desc The (optional) description of the dependency * @param string $cond The package dependency condition string * @param string $arch The package dependency architecture * @param int $pkg_id The package of the package to display the dependency for * * @return string The HTML code of the label to display */ -function pkg_depend_link($name, $type, $cond, $arch, $pkg_id) { - if ($type == 'optdepends' && strpos($name, ':') !== false) { - $tokens = explode(':', $name, 2); - $name = $tokens[0]; - $desc = $tokens[1]; - } else { - $desc = ''; - } - +function pkg_depend_link($name, $type, $desc, $cond, $arch, $pkg_id) { /* * TODO: We currently perform one SQL query per nonexistent package * dependency. It would be much better if we could annotate dependency @@ -432,25 +426,14 @@ function pkg_depend_link($name, $type, $cond, $arch, $pkg_id) { * @return string The HTML code of the link to display */ function pkg_requiredby_link($name, $depends, $type, $arch, $pkgname) { - if ($type == 'optdepends' && strpos($name, ':') !== false) { - $tokens = explode(':', $name, 2); - $name = $tokens[0]; - } - $link = ''; $link .= htmlspecialchars($name) . ''; if ($depends != $pkgname) { - $depname = $depends; - if (strpos($depends, ':') !== false) { - $tokens = explode(':', $depname, 2); - $depname = $tokens[0]; - } - $link .= ' ('; - $link .= __('requires %s', htmlspecialchars($depname)); + $link .= __('requires %s', htmlspecialchars($depends)); $link .= ')'; } @@ -522,11 +505,11 @@ function pkg_required($name="", $provides, $limit) { $name_list .= ',' . $dbh->quote($p[0]); } - $q = "SELECT p.Name, pd.DepName, dt.Name, pd.DepArch FROM PackageDepends pd "; + $q = "SELECT p.Name, pd.DepName, dt.Name, pd.DepArch "; + $q.= "FROM PackageDepends pd "; $q.= "LEFT JOIN Packages p ON p.ID = pd.PackageID "; $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; $q.= "WHERE pd.DepName IN (" . $name_list . ") "; - $q.= "OR SUBSTRING(pd.DepName FROM 1 FOR POSITION(': ' IN pd.DepName) - 1) IN (" . $name_list . ") "; $q.= "ORDER BY p.Name LIMIT " . intval($limit); $result = $dbh->query($q); if (!$result) {return array();} diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index ed8974a3..8a934173 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -277,7 +277,7 @@ endif; 0): ?>
      -
    • +
    From 4abde895a5b579fb798e062806c8fef2289f0d8f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 19 Apr 2017 17:21:15 +0200 Subject: [PATCH 0364/1891] Use JavaScript to collapse long comments Instead of using CSS to limit the height of package comments as implemented in 7b13203 (Limit comment height to 15 lines, 2016-03-12), use JavaScript to collapse long comments and add a link to expand them. Clicking the same link twice results in the corresponding comment being collapsed again. If JavaScript is disabled, the full comments are shown (without any possibility to collapse or expand). Signed-off-by: Lukas Fleischer --- web/html/css/aurweb.css | 5 ----- web/html/packages.php | 35 +++++++++++++++++++++++++++++++++++ web/template/pkg_comments.php | 2 +- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index f777ab83..f5e10371 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -148,8 +148,3 @@ label.confirmation, color: red; font-weight: bold; } - -#news div p { - max-height: 15em; - overflow: auto; -} diff --git a/web/html/packages.php b/web/html/packages.php index 113a1145..8d76c76d 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -72,10 +72,45 @@ function collapseDependsList(list) { }); } +function collapseComment(div) { + var linkid = div.attr('id') + 'link', + par = div.find('p'), + height = par.height(), + maxheight = 200; + + if (height <= maxheight) + return; + + par.css({ 'overflow': 'hidden', 'height': maxheight + 'px' }); + par.addClass('collapsed'); + par.after('

    Show More…

    '); + + $('#' + linkid).click(function(event) { + var newheight; + + if (par.hasClass('collapsed')) { + par.css({ 'height': 'auto' }); + newheight = par.height(); + par.css({ 'height': maxheight }); + $(this).text('Collapse'); + } else { + newheight = maxheight; + $(this).text('Show More…'); + } + + par.animate({ 'height': newheight }); + par.toggleClass('collapsed'); + event.preventDefault(); + }); +} + $(document).ready(function() { collapseDependsList("#pkgdepslist"); collapseDependsList("#pkgreqslist"); collapseDependsList("#pkgsrcslist"); + $(".article-content").each(function() { + collapseComment($(this)); + }); }); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index fee1898c..c23ec421 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -102,7 +102,7 @@ if (!isset($count)) { -
    +
    -content" class="article-content comment-deleted">

    From 016b40f99d679f0787f7c8a5f61f4a411b6c3632 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 23 Apr 2017 12:46:48 +0200 Subject: [PATCH 0365/1891] Render comments when storing them in the database Instead of converting package comments from plain text to HTML code when they are displayed, do the conversion when the comment is posted and store the rendered result in the database. The conversion itself is done by a Python script which uses Bleach for sanitizing the text. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 35 +++++++++++++++++++++++++++++ conf/config.proto | 1 + schema/aur-schema.sql | 1 + setup.py | 1 + test/setup.sh | 1 + test/t2600-rendercomment.sh | 22 ++++++++++++++++++ upgrading/4.6.0.txt | 6 +++++ web/lib/pkgbasefuncs.inc.php | 40 +++++++++++++++++++++++++++++---- web/template/pkg_comments.php | 4 ++++ 9 files changed, 107 insertions(+), 4 deletions(-) create mode 100755 aurweb/scripts/rendercomment.py create mode 100755 test/t2600-rendercomment.sh diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py new file mode 100755 index 00000000..593cd36a --- /dev/null +++ b/aurweb/scripts/rendercomment.py @@ -0,0 +1,35 @@ +#!/usr/bin/python3 + +import sys +import bleach + +import aurweb.db + + +def get_comment(conn, commentid): + cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', + [commentid]) + return cur.fetchone()[0] + + +def save_rendered_comment(conn, commentid, html): + conn.execute('UPDATE PackageComments SET RenderedComment = ? WHERE ID = ?', + [html, commentid]) + + +def main(): + commentid = int(sys.argv[1]) + + conn = aurweb.db.Connection() + + html = get_comment(conn, commentid) + html = html.replace('\n', '
    ') + html = bleach.clean(html, tags=['br']) + save_rendered_comment(conn, commentid, html) + + conn.commit() + conn.close() + + +if __name__ == '__main__': + main() diff --git a/conf/config.proto b/conf/config.proto index df10b995..094d8211 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -33,6 +33,7 @@ log_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 +render-comment-cmd = /usr/local/bin/aurweb-rendercomment [notifications] notify-cmd = /usr/local/bin/aurweb-notify diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index be6f3e54..e5841652 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -255,6 +255,7 @@ CREATE TABLE PackageComments ( PackageBaseID INTEGER UNSIGNED NOT NULL, UsersID INTEGER UNSIGNED NULL DEFAULT NULL, Comments TEXT NOT NULL, + RenderedComment TEXT NOT NULL, CommentTS BIGINT UNSIGNED NOT NULL DEFAULT 0, EditedTS BIGINT UNSIGNED NULL DEFAULT NULL, EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, diff --git a/setup.py b/setup.py index 99dbfedf..9d10cc1c 100644 --- a/setup.py +++ b/setup.py @@ -27,6 +27,7 @@ setup( 'aurweb-notify = aurweb.scripts.notify:main', 'aurweb-pkgmaint = aurweb.scripts.pkgmaint:main', 'aurweb-popupdate = aurweb.scripts.popupdate:main', + 'aurweb-rendercomment = aurweb.scripts.rendercomment:main', 'aurweb-tuvotereminder = aurweb.scripts.tuvotereminder:main', ], }, diff --git a/test/setup.sh b/test/setup.sh index b71e73e8..f29695a6 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -16,6 +16,7 @@ TUVOTEREMINDER="$TOPLEVEL/aurweb/scripts/tuvotereminder.py" PKGMAINT="$TOPLEVEL/aurweb/scripts/pkgmaint.py" AURBLUP="$TOPLEVEL/aurweb/scripts/aurblup.py" NOTIFY="$TOPLEVEL/aurweb/scripts/notify.py" +RENDERCOMMENT="$TOPLEVEL/aurweb/scripts/rendercomment.py" # Create the configuration file and a dummy notification script. cat >config <<-EOF diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh new file mode 100755 index 00000000..8d79336d --- /dev/null +++ b/test/t2600-rendercomment.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +test_description='rendercomment tests' + +. ./setup.sh + +test_expect_success 'Test comment rendering.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (1, 1, "Hello world! + This is a comment.", ""); + EOD + "$RENDERCOMMENT" 1 && + cat <<-EOD >expected && + Hello world!
    This is a comment. + EOD + cat <<-EOD | sqlite3 aur.db >actual && + SELECT RenderedComment FROM PackageComments WHERE ID = 1; + EOD + test_cmp actual expected +' + +test_done diff --git a/upgrading/4.6.0.txt b/upgrading/4.6.0.txt index 45740f40..b051baca 100644 --- a/upgrading/4.6.0.txt +++ b/upgrading/4.6.0.txt @@ -9,3 +9,9 @@ UPDATE PackageDepends SET DepName = SUBSTRING(DepName FROM 1 FOR POSITION(': ' IN DepName) - 1) WHERE POSITION(': ' IN DepName) > 0; --- + +2. Add RenderedComment column to PackageComments: + +--- +ALTER TABLE PackageComments ADD COLUMN RenderedComment TEXT NOT NULL; +--- diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 57933e86..3e783094 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -54,7 +54,7 @@ function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false $dbh = DB::connect(); $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; $q.= "PackageBaseID, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName, "; + $q.= "DelUsersID, C.UserName AS DelUserName, RenderedComment, "; $q.= "PinnedTS FROM PackageComments "; $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; @@ -79,6 +79,36 @@ function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false return $result->fetchAll(); } +/* + * Invoke the comment rendering script. + * + * @param int $id ID of the comment to render + * + * @return void + */ +function render_comment($id) { + $cmd = config_get('options', 'render-comment-cmd'); + $cmd .= ' ' . intval($id); + + $descspec = array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ); + + $p = proc_open($cmd, $descspec, $pipes); + + if (!is_resource($p)) { + return false; + } + + fclose($pipes[0]); + fclose($pipes[1]); + fclose($pipes[2]); + + return proc_close($p); +} + /** * Add a comment to a package page and send out appropriate notifications * @@ -96,12 +126,14 @@ function pkgbase_add_comment($base_id, $uid, $comment) { } $q = "INSERT INTO PackageComments "; - $q.= "(PackageBaseID, UsersID, Comments, CommentTS) VALUES ("; - $q.= intval($base_id) . ", " . $uid . ", "; - $q.= $dbh->quote($comment) . ", " . strval(time()) . ")"; + $q.= "(PackageBaseID, UsersID, Comments, RenderedComment, CommentTS) "; + $q.= "VALUES (" . intval($base_id) . ", " . $uid . ", "; + $q.= $dbh->quote($comment) . ", '', " . strval(time()) . ")"; $dbh->exec($q); $comment_id = $dbh->lastInsertId(); + render_comment($comment_id); + notify(array('comment', $uid, $base_id, $comment_id)); return array(true, __('Comment has been added.')); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index c23ec421..f973b74d 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -103,9 +103,13 @@ if (!isset($count)) {
    -content" class="article-content comment-deleted"> + + +

    +
    From 9aa4203c7efd5ef1015eb32eca5e0764a5afe183 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 23 Apr 2017 13:54:21 +0200 Subject: [PATCH 0366/1891] Add Markdown support to package comments Support Markdown syntax in package comments. Among other things, this makes it easier to paste command line output and patches. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 8 +++++--- test/t2600-rendercomment.sh | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 593cd36a..7e8a16b8 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -2,6 +2,7 @@ import sys import bleach +import markdown import aurweb.db @@ -22,9 +23,10 @@ def main(): conn = aurweb.db.Connection() - html = get_comment(conn, commentid) - html = html.replace('\n', '
    ') - html = bleach.clean(html, tags=['br']) + text = get_comment(conn, commentid) + html = markdown.markdown(text, extensions=['nl2br']) + allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p', 'br'] + html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) conn.commit() diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index 8d79336d..50a5adb9 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -11,7 +11,8 @@ test_expect_success 'Test comment rendering.' ' EOD "$RENDERCOMMENT" 1 && cat <<-EOD >expected && - Hello world!
    This is a comment. +

    Hello world!
    + This is a comment.

    EOD cat <<-EOD | sqlite3 aur.db >actual && SELECT RenderedComment FROM PackageComments WHERE ID = 1; From a9ac385cb90d0251253a2a3925f72a71af52f97b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 23 Apr 2017 14:48:01 +0200 Subject: [PATCH 0367/1891] Reintroduce backwards-compatible hyperlink syntax Before switching to the new comment rendering script and Markdown, no special syntax was needed to make URLs clickable. Reintroduce this feature and automatically detect links in addition to the hyperlink syntax already supported by Markdown. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 7e8a16b8..c8921f8f 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -1,5 +1,6 @@ #!/usr/bin/python3 +import re import sys import bleach import markdown @@ -7,6 +8,19 @@ import markdown import aurweb.db +class LinkifyPreprocessor(markdown.preprocessors.Preprocessor): + _urlre = re.compile(r'(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' + r'(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))') + + def run(self, lines): + return [self._urlre.sub(r'<\1>', line) for line in lines] + + +class LinkifyExtension(markdown.extensions.Extension): + def extendMarkdown(self, md, md_globals): + md.preprocessors.add('linkify', LinkifyPreprocessor(md), '_end') + + def get_comment(conn, commentid): cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', [commentid]) @@ -24,7 +38,7 @@ def main(): conn = aurweb.db.Connection() text = get_comment(conn, commentid) - html = markdown.markdown(text, extensions=['nl2br']) + html = markdown.markdown(text, extensions=['nl2br', LinkifyExtension()]) allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p', 'br'] html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) From bb623fc545f0e0187cc9b32386c383b732bcc9ae Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 23 Apr 2017 14:56:07 +0200 Subject: [PATCH 0368/1891] Make references to Git commits clickable Automatically detect Git commit identifiers, shorten them, and make them link to the cgit interface. Implements FS#43290. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 59 ++++++++++++++++++++++++++++++--- conf/config.proto | 1 + test/setup.sh | 1 + test/t2600-rendercomment.sh | 1 + 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index c8921f8f..659e18ad 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -1,12 +1,17 @@ #!/usr/bin/python3 import re +import pygit2 import sys import bleach import markdown +import aurweb.config import aurweb.db +repo_path = aurweb.config.get('serve', 'repo-path') +commit_uri = aurweb.config.get('options', 'commit_uri') + class LinkifyPreprocessor(markdown.preprocessors.Preprocessor): _urlre = re.compile(r'(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' @@ -21,10 +26,53 @@ class LinkifyExtension(markdown.extensions.Extension): md.preprocessors.add('linkify', LinkifyPreprocessor(md), '_end') +class GitCommitsPreprocessor(markdown.preprocessors.Preprocessor): + _oidre = re.compile(r'(\b)([0-9a-f]{7,40})(\b)') + _repo = pygit2.Repository(repo_path) + _head = None + + def __init__(self, md, head): + self._head = head + super(markdown.preprocessors.Preprocessor, self).__init__(md) + + def handleMatch(self, m): + oid = m.group(2) + if oid not in self._repo: + return oid + + prefixlen = 12 + while prefixlen < 40: + if oid[:prefixlen] in self._repo: + break + prefixlen += 1 + + html = '[`' + oid[:prefixlen] + '`]' + html += '(' + commit_uri % (self._head, oid[:prefixlen]) + ')' + + return html + + def run(self, lines): + return [self._oidre.sub(self.handleMatch, line) for line in lines] + + +class GitCommitsExtension(markdown.extensions.Extension): + _head = None + + def __init__(self, head): + self._head = head + super(markdown.extensions.Extension, self).__init__() + + def extendMarkdown(self, md, md_globals): + preprocessor = GitCommitsPreprocessor(md, self._head) + md.preprocessors.add('git-commits', preprocessor, '_end') + + def get_comment(conn, commentid): - cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', - [commentid]) - return cur.fetchone()[0] + cur = conn.execute('SELECT PackageComments.Comments, PackageBases.Name ' + 'FROM PackageComments INNER JOIN PackageBases ' + 'ON PackageBases.ID = PackageComments.PackageBaseID ' + 'WHERE PackageComments.ID = ?', [commentid]) + return cur.fetchone() def save_rendered_comment(conn, commentid, html): @@ -37,8 +85,9 @@ def main(): conn = aurweb.db.Connection() - text = get_comment(conn, commentid) - html = markdown.markdown(text, extensions=['nl2br', LinkifyExtension()]) + text, pkgbase = get_comment(conn, commentid) + html = markdown.markdown(text, extensions=['nl2br', LinkifyExtension(), + GitCommitsExtension(pkgbase)]) allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p', 'br'] html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) diff --git a/conf/config.proto b/conf/config.proto index 094d8211..6c637b02 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -30,6 +30,7 @@ auto_orphan_age = 15552000 auto_delete_age = 86400 source_file_uri = https://aur.archlinux.org/cgit/aur.git/tree/%s?h=%s log_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s +commit_uri = https://aur.archlinux.org/cgit/aur.git/commit/?h=%s&id=%s snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 diff --git a/test/setup.sh b/test/setup.sh index f29695a6..efa1ab86 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -29,6 +29,7 @@ aur_location = https://aur.archlinux.org aur_request_ml = aur-requests@archlinux.org enable-maintenance = 0 maintenance-exceptions = 127.0.0.1 +commit_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s&id=%s [notifications] notify-cmd = $NOTIFY diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index 50a5adb9..6db9467d 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -6,6 +6,7 @@ test_description='rendercomment tests' test_expect_success 'Test comment rendering.' ' cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, 0, 0, ""); INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (1, 1, "Hello world! This is a comment.", ""); EOD From 482bd10a8bf4906e79fa6e056b94dc90e3a74901 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 23 Apr 2017 21:20:37 +0200 Subject: [PATCH 0369/1891] t2600: Test Markdown and HTML sanitizing Signed-off-by: Lukas Fleischer --- test/t2600-rendercomment.sh | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index 6db9467d..8da15291 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -21,4 +21,46 @@ test_expect_success 'Test comment rendering.' ' test_cmp actual expected ' +test_expect_success 'Test Markdown conversion.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (2, 1, "*Hello* [world](https://www.archlinux.org/)!", ""); + EOD + "$RENDERCOMMENT" 2 && + cat <<-EOD >expected && +

    Hello world!

    + EOD + cat <<-EOD | sqlite3 aur.db >actual && + SELECT RenderedComment FROM PackageComments WHERE ID = 2; + EOD + test_cmp actual expected +' + +test_expect_success 'Test HTML sanitizing.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (3, 1, "", ""); + EOD + "$RENDERCOMMENT" 3 && + cat <<-EOD >expected && + <script>alert("XSS!");</script> + EOD + cat <<-EOD | sqlite3 aur.db >actual && + SELECT RenderedComment FROM PackageComments WHERE ID = 3; + EOD + test_cmp actual expected +' + +test_expect_success 'Test link conversion.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (4, 1, "Visit https://www.archlinux.org/.", ""); + EOD + "$RENDERCOMMENT" 4 && + cat <<-EOD >expected && +

    Visit https://www.archlinux.org/.

    + EOD + cat <<-EOD | sqlite3 aur.db >actual && + SELECT RenderedComment FROM PackageComments WHERE ID = 4; + EOD + test_cmp actual expected +' + test_done From 136171e509b78d89b095bc5599bc158acd1250e7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 23 Apr 2017 21:22:52 +0200 Subject: [PATCH 0370/1891] Rerender package comments after editing Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 3e783094..ff1bc901 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -1041,6 +1041,9 @@ function pkgbase_edit_comment($comment) { $q.= "EditedTS = " . strval(time()) . " "; $q.= "WHERE ID = ".intval($comment_id); $dbh->exec($q); + + render_comment($comment_id); + return array(true, __("Comment has been edited.")); } else { return array(false, __("You are not allowed to edit this comment.")); From 362ee754e7d28c36f74b7feee03e529a380dd379 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 24 Apr 2017 17:39:40 +0200 Subject: [PATCH 0371/1891] Do not keep line breaks in comments With the new Markdown support, text paragraphs are now properly converted to HTML paragraphs, so we no longer need to keep line breaks. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 4 ++-- test/t2600-rendercomment.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 659e18ad..c23ef8de 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -86,9 +86,9 @@ def main(): conn = aurweb.db.Connection() text, pkgbase = get_comment(conn, commentid) - html = markdown.markdown(text, extensions=['nl2br', LinkifyExtension(), + html = markdown.markdown(text, extensions=[LinkifyExtension(), GitCommitsExtension(pkgbase)]) - allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p', 'br'] + allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p'] html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index 8da15291..edf290cd 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -12,7 +12,7 @@ test_expect_success 'Test comment rendering.' ' EOD "$RENDERCOMMENT" 1 && cat <<-EOD >expected && -

    Hello world!
    +

    Hello world! This is a comment.

    EOD cat <<-EOD | sqlite3 aur.db >actual && From fd880a7a84f6d644bf220199f69da3738f2672cb Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 24 Apr 2017 17:42:37 +0200 Subject: [PATCH 0372/1891] Support fenced code in package comments Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index c23ef8de..f32c8274 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -86,9 +86,10 @@ def main(): conn = aurweb.db.Connection() text, pkgbase = get_comment(conn, commentid) - html = markdown.markdown(text, extensions=[LinkifyExtension(), + html = markdown.markdown(text, extensions=['fenced_code', + LinkifyExtension(), GitCommitsExtension(pkgbase)]) - allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p'] + allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p', 'pre'] html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) From 4be9aa6350430703383b9df26be2aa37ce840cdc Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 24 Apr 2017 18:10:16 +0200 Subject: [PATCH 0373/1891] Fix the comment collapse feature In commit 4abde89 (Use JavaScript to collapse long comments, 2017-04-19), support for collapsing/expanding long comments was added. This was broken by the recent Markdown support since comments no longer live inside a single HTML paragraph. Fix this by wrapping each comment in another div container. Signed-off-by: Lukas Fleischer --- web/html/packages.php | 23 ++++++++++++----------- web/template/pkg_comments.php | 16 +++++++++------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/web/html/packages.php b/web/html/packages.php index 8d76c76d..7d5b2075 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -74,32 +74,33 @@ function collapseDependsList(list) { function collapseComment(div) { var linkid = div.attr('id') + 'link', - par = div.find('p'), - height = par.height(), + inner = div.find('div'), + height = inner.height(), maxheight = 200; if (height <= maxheight) return; - par.css({ 'overflow': 'hidden', 'height': maxheight + 'px' }); - par.addClass('collapsed'); - par.after('

    Show More…

    '); + inner.css({ 'overflow': 'hidden', 'height': maxheight + 'px' }); + inner.addClass('collapsed'); + inner.after('

    Show More…

    '); $('#' + linkid).click(function(event) { + var inner = $(this).parent().parent().find('div'); var newheight; - if (par.hasClass('collapsed')) { - par.css({ 'height': 'auto' }); - newheight = par.height(); - par.css({ 'height': maxheight }); + if (inner.hasClass('collapsed')) { + inner.css({ 'height': 'auto' }); + newheight = inner.height(); + inner.css({ 'height': maxheight }); $(this).text('Collapse'); } else { newheight = maxheight; $(this).text('Show More…'); } - par.animate({ 'height': newheight }); - par.toggleClass('collapsed'); + inner.animate({ 'height': newheight }); + inner.toggleClass('collapsed'); event.preventDefault(); }); } diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index f973b74d..7d9bedcc 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -103,13 +103,15 @@ if (!isset($count)) {
    -content" class="article-content comment-deleted"> - - - -

    - -

    - +
    + + + +

    + +

    + +
    From 90ab7c7b838a706ae7f4e63f95ccdc706ce10977 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 25 Apr 2017 06:50:00 +0200 Subject: [PATCH 0374/1891] t1300: Factor out package dumping Signed-off-by: Lukas Fleischer --- test/t1300-git-update.sh | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.sh index a65ca3a1..dbe60292 100755 --- a/test/t1300-git-update.sh +++ b/test/t1300-git-update.sh @@ -4,6 +4,14 @@ test_description='git-update tests' . ./setup.sh +dump_package_info() { + for t in Packages Licenses PackageLicenses Groups PackageGroups \ + PackageDepends PackageRelations PackageSources \ + PackageNotifications; do + echo "SELECT * FROM $t;" | sqlite3 aur.db + done +} + test_expect_success 'Test update hook on a fresh repository.' ' old=0000000000000000000000000000000000000000 && new=$(git -C aur.git rev-parse HEAD^) && @@ -16,12 +24,7 @@ test_expect_success 'Test update hook on a fresh repository.' ' 1|1|python-pygit2|| 1|1 EOF - >actual && - for t in Packages Licenses PackageLicenses Groups PackageGroups \ - PackageDepends PackageRelations PackageSources \ - PackageNotifications; do - echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual - done && + dump_package_info >actual && test_cmp expected actual ' @@ -44,12 +47,7 @@ test_expect_success 'Test update hook on another fresh repository.' ' 1|1 2|1 EOF - >actual && - for t in Packages Licenses PackageLicenses Groups PackageGroups \ - PackageDepends PackageRelations PackageSources \ - PackageNotifications; do - echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual - done && + dump_package_info >actual && test_cmp expected actual ' @@ -70,12 +68,7 @@ test_expect_success 'Test update hook on an updated repository.' ' 1|1 2|1 EOF - >actual && - for t in Packages Licenses PackageLicenses Groups PackageGroups \ - PackageDepends PackageRelations PackageSources \ - PackageNotifications; do - echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual - done && + dump_package_info >actual && test_cmp expected actual ' @@ -94,12 +87,7 @@ test_expect_success 'Test restore mode.' ' 1|1 2|1 EOF - >actual && - for t in Packages Licenses PackageLicenses Groups PackageGroups \ - PackageDepends PackageRelations PackageSources \ - PackageNotifications; do - echo "SELECT * FROM $t;" | sqlite3 aur.db >>actual - done && + dump_package_info >actual && test_cmp expected actual ' From f4e2d143adca93b6ebba051e5f1c3e97266bb747 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 24 Apr 2017 21:16:04 +0200 Subject: [PATCH 0375/1891] Explicitly initialize PackageBases.FlaggerComment Since commit 09cb61a (schema: Remove invalid default values for TEXT columns, 2017-04-15), the PackageBases.FlaggerComment field no longer has a default value. Initialize this field explicitly whenever a new row is added to the PackageBases table. Signed-off-by: Lukas Fleischer --- aurweb/git/serve.py | 5 +++-- aurweb/git/update.py | 5 +++-- test/t1300-git-update.sh | 14 +++++++------- test/t2100-mkpkglists.sh | 8 ++++---- test/t2300-pkgmaint.sh | 8 ++++---- test/t2500-notify.sh | 8 ++++---- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 44cce75d..3eef26a7 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -65,8 +65,9 @@ def create_pkgbase(pkgbase, user): now = int(time.time()) cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " + - "ModifiedTS, SubmitterUID, MaintainerUID) VALUES " + - "(?, ?, ?, ?, ?)", [pkgbase, now, now, userid, userid]) + "ModifiedTS, SubmitterUID, MaintainerUID, " + + "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')", + [pkgbase, now, now, userid, userid]) pkgbase_id = cur.lastrowid cur = conn.execute("INSERT INTO PackageNotifications " + diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 09a57ef0..c9a98d07 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -61,8 +61,9 @@ def create_pkgbase(conn, pkgbase, user): now = int(time.time()) cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " + - "ModifiedTS, SubmitterUID, MaintainerUID) VALUES " + - "(?, ?, ?, ?, ?)", [pkgbase, now, now, userid, userid]) + "ModifiedTS, SubmitterUID, MaintainerUID, " + + "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')", + [pkgbase, now, now, userid, userid]) pkgbase_id = cur.lastrowid cur = conn.execute("INSERT INTO PackageNotifications " + diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.sh index dbe60292..f16e2ad4 100755 --- a/test/t1300-git-update.sh +++ b/test/t1300-git-update.sh @@ -21,7 +21,7 @@ test_expect_success 'Test update hook on a fresh repository.' ' 1|1|foobar|1-1|aurweb test package.|https://aur.archlinux.org/ 1|GPL 1|1 - 1|1|python-pygit2|| + 1|1|python-pygit2||| 1|1 EOF dump_package_info >actual && @@ -42,8 +42,8 @@ test_expect_success 'Test update hook on another fresh repository.' ' 2|MIT 1|1 2|2 - 1|1|python-pygit2|| - 2|1|python-pygit2|| + 1|1|python-pygit2||| + 2|1|python-pygit2||| 1|1 2|1 EOF @@ -63,8 +63,8 @@ test_expect_success 'Test update hook on an updated repository.' ' 2|MIT 2|2 3|1 - 2|1|python-pygit2|| - 3|1|python-pygit2|| + 2|1|python-pygit2||| + 3|1|python-pygit2||| 1|1 2|1 EOF @@ -82,8 +82,8 @@ test_expect_success 'Test restore mode.' ' 2|MIT 2|2 3|1 - 2|1|python-pygit2|| - 3|1|python-pygit2|| + 2|1|python-pygit2||| + 3|1|python-pygit2||| 1|1 2|1 EOF diff --git a/test/t2100-mkpkglists.sh b/test/t2100-mkpkglists.sh index a84a1b65..1e2edc38 100755 --- a/test/t2100-mkpkglists.sh +++ b/test/t2100-mkpkglists.sh @@ -14,10 +14,10 @@ test_expect_success 'Test package list generation with no packages.' ' test_expect_success 'Test package list generation.' ' cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (1, "foobar", 1, 0, 0); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (2, "foobar2", 2, 0, 0); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (3, "foobar3", NULL, 0, 0); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (4, "foobar4", 1, 0, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, 0, 0, ""); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (2, "foobar2", 2, 0, 0, ""); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (3, "foobar3", NULL, 0, 0, ""); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (4, "foobar4", 1, 0, 0, ""); INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (1, 1, "pkg1"); INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (2, 1, "pkg2"); INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (3, 1, "pkg3"); diff --git a/test/t2300-pkgmaint.sh b/test/t2300-pkgmaint.sh index 5c55aaf1..478df526 100755 --- a/test/t2300-pkgmaint.sh +++ b/test/t2300-pkgmaint.sh @@ -8,10 +8,10 @@ test_expect_success 'Test package base cleanup script.' ' now=$(date -d now +%s) && threedaysago=$(date -d "3 days ago" +%s) && cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (1, "foobar", 1, $now, 0); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (2, "foobar2", 2, $threedaysago, 0); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (3, "foobar3", NULL, $now, 0); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS) VALUES (4, "foobar4", NULL, $threedaysago, 0); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, $now, 0, ""); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (2, "foobar2", 2, $threedaysago, 0, ""); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (3, "foobar3", NULL, $now, 0, ""); + INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (4, "foobar4", NULL, $threedaysago, 0, ""); EOD "$PKGMAINT" && cat <<-EOD >expected && diff --git a/test/t2500-notify.sh b/test/t2500-notify.sh index 1b209458..39976820 100755 --- a/test/t2500-notify.sh +++ b/test/t2500-notify.sh @@ -6,10 +6,10 @@ test_description='notify tests' test_expect_success 'Test out-of-date notifications.' ' cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (1, "foobar", 1, 0, 0); - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (2, "foobar2", 2, 0, 0); - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (3, "foobar3", NULL, 0, 0); - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS) VALUES (4, "foobar4", 1, 0, 0); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, 0, 0, ""); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (2, "foobar2", 2, 0, 0, ""); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (3, "foobar3", NULL, 0, 0, ""); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (4, "foobar4", 1, 0, 0, ""); INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1, 2, 1); INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1, 4, 2); INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (2, 3, 1); From dec9077339b4cb280430a98204df97ca84bac784 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 24 Apr 2017 21:17:29 +0200 Subject: [PATCH 0376/1891] Initialize PackageRequests.{Comments,ClosureComment} Since commit 09cb61a (schema: Remove invalid default values for TEXT columns, 2017-04-15), the PackageRequests.Comments and PackageRequests.ClosureComment fields no longer have a default value. Initialize these fields explicitly whenever a new row is added to the PackageRequests table. Signed-off-by: Lukas Fleischer --- test/t1200-git-serve.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index 07383aff..038a7989 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -353,9 +353,9 @@ test_expect_success "Check whether package requests are closed when disowning." SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ "$GIT_SERVE" 2>&1 && cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID) VALUES (1, 2, 3, "foobar", 4); - INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID) VALUES (2, 3, 3, "foobar", 5); - INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID) VALUES (3, 2, 2, "foobar2", 6); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (1, 2, 3, "foobar", 4, "", ""); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (2, 3, 3, "foobar", 5, "", ""); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (3, 2, 2, "foobar2", 6, "", ""); EOD >sendmail.out && SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ From e4dcd913d15d813cc227df90a8129d1c3685ea07 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 26 Apr 2017 06:37:31 +0200 Subject: [PATCH 0377/1891] Support headings in package comments Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index f32c8274..9c0aa6a3 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -67,6 +67,20 @@ class GitCommitsExtension(markdown.extensions.Extension): md.preprocessors.add('git-commits', preprocessor, '_end') +class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor): + def run(self, doc): + for elem in doc: + if elem.tag == 'h1': + elem.tag = 'h5' + elif elem.tag in ['h2', 'h3', 'h4', 'h5']: + elem.tag = 'h6' + + +class HeadingExtension(markdown.extensions.Extension): + def extendMarkdown(self, md, md_globals): + md.treeprocessors.add('heading', HeadingTreeprocessor(md), '_end') + + def get_comment(conn, commentid): cur = conn.execute('SELECT PackageComments.Comments, PackageBases.Name ' 'FROM PackageComments INNER JOIN PackageBases ' @@ -88,8 +102,10 @@ def main(): text, pkgbase = get_comment(conn, commentid) html = markdown.markdown(text, extensions=['fenced_code', LinkifyExtension(), - GitCommitsExtension(pkgbase)]) - allowed_tags = bleach.sanitizer.ALLOWED_TAGS + ['p', 'pre'] + GitCommitsExtension(pkgbase), + HeadingExtension()]) + allowed_tags = bleach.sanitizer.ALLOWED_TAGS + \ + ['p', 'pre', 'h4', 'h5', 'h6'] html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) From 6892ec7791bf04361ac2973b38d0025b50fa4727 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 27 Apr 2017 08:07:44 +0200 Subject: [PATCH 0378/1891] Call check_sid() from a central location Instead of calling check_sid() from every single PHP script representing a web page, add the call to aur.inc.php which is sourced by all of them. Also, remove set_lang() calls from the scripts since these are also already included in aur.inc.php. Signed-off-by: Lukas Fleischer --- web/html/account.php | 3 --- web/html/addvote.php | 2 -- web/html/comaintainers.php | 3 --- web/html/commentedit.php | 3 --- web/html/home.php | 3 --- web/html/login.php | 2 -- web/html/logout.php | 1 - web/html/packages.php | 2 -- web/html/passreset.php | 3 --- web/html/pkgbase.php | 2 -- web/html/pkgdel.php | 3 --- web/html/pkgdisown.php | 3 --- web/html/pkgflag.php | 3 --- web/html/pkgflagcomment.php | 3 --- web/html/pkgmerge.php | 3 --- web/html/pkgreq.php | 3 --- web/html/register.php | 3 --- web/html/tu.php | 2 -- web/lib/aur.inc.php | 2 ++ 19 files changed, 2 insertions(+), 47 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index 549f8524..c30a89aa 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once('aur.inc.php'); # access AUR common functions include_once('acctfuncs.inc.php'); # access Account specific functions -set_lang(); # this sets up the visitor's language -check_sid(); # see if they're still logged in - $action = in_request("Action"); $need_userinfo = array( diff --git a/web/html/addvote.php b/web/html/addvote.php index d1529412..3672c031 100644 --- a/web/html/addvote.php +++ b/web/html/addvote.php @@ -3,8 +3,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); -set_lang(); -check_sid(); $title = __("Add Proposal"); diff --git a/web/html/comaintainers.php b/web/html/comaintainers.php index 23d8d19b..9733558d 100644 --- a/web/html/comaintainers.php +++ b/web/html/comaintainers.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgbasefuncs.inc.php"); -set_lang(); -check_sid(); - if (!isset($base_id) || !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) { header('Location: /'); exit(); diff --git a/web/html/commentedit.php b/web/html/commentedit.php index 2a0628e3..53ec2891 100644 --- a/web/html/commentedit.php +++ b/web/html/commentedit.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgbasefuncs.inc.php"); -set_lang(); -check_sid(); - $comment_id = intval($_REQUEST['comment_id']); list($user_id, $comment) = comment_by_id($comment_id); diff --git a/web/html/home.php b/web/html/home.php index 26754916..0ce89f40 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -3,9 +3,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); -set_lang(); -check_sid(); - include_once('stats.inc.php'); if (isset($_COOKIE["AURSID"])) { diff --git a/web/html/login.php b/web/html/login.php index 7345439d..a55ce057 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -2,8 +2,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); -set_lang(); -check_sid(); $disable_http_login = config_get_bool('options', 'disable_http_login'); if (!$disable_http_login || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'])) { diff --git a/web/html/logout.php b/web/html/logout.php index 5e8e8f43..14022001 100644 --- a/web/html/logout.php +++ b/web/html/logout.php @@ -5,7 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); # access AUR common functions include_once("acctfuncs.inc.php"); # access AUR common functions - # if they've got a cookie, log them out - need to do this before # sending any HTML output. # diff --git a/web/html/packages.php b/web/html/packages.php index 7d5b2075..db9606d9 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -3,9 +3,7 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); # access AUR common functions -set_lang(); # this sets up the visitor's language include_once('pkgfuncs.inc.php'); # package specific functions -check_sid(); # see if they're still logged in # Retrieve package ID and name, unless initialized by the routing framework if (!isset($pkgid) || !isset($pkgname)) { diff --git a/web/html/passreset.php b/web/html/passreset.php index e89967d4..9e7cee88 100644 --- a/web/html/passreset.php +++ b/web/html/passreset.php @@ -4,9 +4,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); # access AUR common functions -set_lang(); # this sets up the visitor's language -check_sid(); # see if they're still logged in - if (isset($_COOKIE["AURSID"])) { header('Location: /'); exit(); diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index a593af10..03b0eee4 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -3,9 +3,7 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); -set_lang(); include_once('pkgfuncs.inc.php'); -check_sid(); /* * Retrieve package base ID and name, unless initialized by the routing diff --git a/web/html/pkgdel.php b/web/html/pkgdel.php index 591ccce8..4620beb6 100644 --- a/web/html/pkgdel.php +++ b/web/html/pkgdel.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgfuncs.inc.php"); -set_lang(); -check_sid(); - html_header(__("Package Deletion")); if (has_credential(CRED_PKGBASE_DELETE)): ?> diff --git a/web/html/pkgdisown.php b/web/html/pkgdisown.php index 036fe6d8..4b04e85e 100644 --- a/web/html/pkgdisown.php +++ b/web/html/pkgdisown.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgfuncs.inc.php"); -set_lang(); -check_sid(); - html_header(__("Disown Package")); $maintainer_uids = array(pkgbase_maintainer_uid($base_id)); diff --git a/web/html/pkgflag.php b/web/html/pkgflag.php index 25c8ccbb..61346b90 100644 --- a/web/html/pkgflag.php +++ b/web/html/pkgflag.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgfuncs.inc.php"); -set_lang(); -check_sid(); - /* Grab the list of package base IDs to be operated on. */ $ids = array(); if (isset($_POST['IDs'])) { diff --git a/web/html/pkgflagcomment.php b/web/html/pkgflagcomment.php index 98680ef6..c0363c89 100644 --- a/web/html/pkgflagcomment.php +++ b/web/html/pkgflagcomment.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgbasefuncs.inc.php"); -set_lang(); -check_sid(); - if (!isset($base_id)) { header('Location: /'); exit(); diff --git a/web/html/pkgmerge.php b/web/html/pkgmerge.php index e8e7ca93..6ee7423d 100644 --- a/web/html/pkgmerge.php +++ b/web/html/pkgmerge.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgfuncs.inc.php"); -set_lang(); -check_sid(); - html_header(__("Package Merging")); if (has_credential(CRED_PKGBASE_DELETE)): ?> diff --git a/web/html/pkgreq.php b/web/html/pkgreq.php index f981c25d..d2f94613 100644 --- a/web/html/pkgreq.php +++ b/web/html/pkgreq.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgfuncs.inc.php"); -set_lang(); -check_sid(); - if (isset($base_id)) { if (!has_credential(CRED_PKGREQ_FILE)) { header('Location: /'); diff --git a/web/html/register.php b/web/html/register.php index 843fea97..368999a5 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -5,9 +5,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once('aur.inc.php'); # access AUR common functions include_once('acctfuncs.inc.php'); # access Account specific functions -set_lang(); # this sets up the visitor's language -check_sid(); # see if they're still logged in - if (isset($_COOKIE["AURSID"])) { header('Location: /'); exit(); diff --git a/web/html/tu.php b/web/html/tu.php index cc77d625..34e64eae 100644 --- a/web/html/tu.php +++ b/web/html/tu.php @@ -3,8 +3,6 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); -set_lang(); -check_sid(); $title = __("Trusted User"); diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index d58df406..063de8fc 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -21,6 +21,8 @@ include_once("credentials.inc.php"); include_once('timezone.inc.php'); set_tz(); +check_sid(); + /** * Check if a visitor is logged in * From a8ac2004d3f25877d9e7b4fa58f10009c39f8acf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 27 Apr 2017 09:24:11 +0200 Subject: [PATCH 0379/1891] Add support for Terms of Service documents This allows for adding Terms of Service documents to the database that registered users need to accept before using the AUR. A revision field can be used to indicate whether a document was updated. If it is increased, all users are again asked to accept the new terms. Signed-off-by: Lukas Fleischer --- schema/aur-schema.sql | 20 +++++++++++ upgrading/4.6.0.txt | 20 +++++++++++ web/html/tos.php | 50 ++++++++++++++++++++++++++ web/lib/acctfuncs.inc.php | 74 +++++++++++++++++++++++++++++++++++++++ web/lib/aur.inc.php | 23 ++++++++++++ web/lib/routing.inc.php | 1 + 6 files changed, 188 insertions(+) create mode 100644 web/html/tos.php diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index e5841652..45272bbe 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -379,3 +379,23 @@ CREATE TABLE Bans ( BanTS TIMESTAMP NOT NULL, PRIMARY KEY (IPAddress) ) ENGINE = InnoDB; + +-- Terms and Conditions +-- +CREATE TABLE Terms ( + ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + Description VARCHAR(255) NOT NULL, + URL VARCHAR(8000) NOT NULL, + Revision INTEGER UNSIGNED NOT NULL DEFAULT 1, + PRIMARY KEY (ID) +) ENGINE = InnoDB; + +-- Terms and Conditions accepted by users +-- +CREATE TABLE AcceptedTerms ( + UsersID INTEGER UNSIGNED NOT NULL, + TermsID INTEGER UNSIGNED NOT NULL, + Revision INTEGER UNSIGNED NOT NULL DEFAULT 0, + FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, + FOREIGN KEY (TermsID) REFERENCES Terms(ID) ON DELETE CASCADE +) ENGINE = InnoDB; diff --git a/upgrading/4.6.0.txt b/upgrading/4.6.0.txt index b051baca..816409d5 100644 --- a/upgrading/4.6.0.txt +++ b/upgrading/4.6.0.txt @@ -15,3 +15,23 @@ UPDATE PackageDepends --- ALTER TABLE PackageComments ADD COLUMN RenderedComment TEXT NOT NULL; --- + +3. Add Terms and AcceptedTerms tables: + +--- +CREATE TABLE Terms ( + ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + Description VARCHAR(255) NOT NULL, + URL VARCHAR(8000) NOT NULL, + Revision INTEGER UNSIGNED NOT NULL DEFAULT 1, + PRIMARY KEY (ID) +) ENGINE = InnoDB; + +CREATE TABLE AcceptedTerms ( + UsersID INTEGER UNSIGNED NOT NULL, + TermsID INTEGER UNSIGNED NOT NULL, + Revision INTEGER UNSIGNED NOT NULL DEFAULT 0, + FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, + FOREIGN KEY (TermsID) REFERENCES Terms(ID) ON DELETE CASCADE +) ENGINE = InnoDB; +--- diff --git a/web/html/tos.php b/web/html/tos.php new file mode 100644 index 00000000..fc5d8765 --- /dev/null +++ b/web/html/tos.php @@ -0,0 +1,50 @@ + +
    +

    AUR

    + +
    +
    +

    + ' . username_from_sid($_COOKIE["AURSID"]) . ''); ?> +

    +

    + +

    +
      + +
    • "> ()
    • + +
    +

    + + ]" value="" /> + + +

    +

    + " /> +

    +
    +
    + +
    +query($q); + + if ($result) { + return $result->fetchAll(); + } else { + return array(); + } +} + +/* + * Accept a list of given terms. + * + * @param int $uid The ID of the user to accept the terms. + * @param array $termrev An array mapping each term to the accepted revision. + * + * @return void + */ +function accept_terms($uid, $termrev) { + $dbh = DB::connect(); + + $q = "SELECT TermsID, Revision FROM AcceptedTerms "; + $q .= "WHERE UsersID = " . intval($uid); + + $result = $dbh->query($q); + + if (!$result) { + return; + } + + $termrev_update = array(); + while ($row = $result->fetch(PDO::FETCH_ASSOC)) { + $id = $row['TermsID']; + if (!array_key_exists($id, $termrev)) { + continue; + } + if ($row['Revision'] < $termrev[$id]) { + $termrev_update[$id] = $termrev[$id]; + } + } + $termrev_add = array_diff_key($termrev, $termrev_update); + + foreach ($termrev_add as $id => $rev) { + $q = "INSERT INTO AcceptedTerms (TermsID, UsersID, Revision) "; + $q .= "VALUES (" . intval($id) . ", " . intval($uid) . ", "; + $q .= intval($rev) . ")"; + $dbh->exec($q); + } + + foreach ($termrev_update as $id => $rev) { + $q = "UPDATE AcceptedTerms "; + $q .= "SET Revision = " . intval($rev) . " "; + $q .= "WHERE TermsID = " . intval($id) . " AND "; + $q .= "UsersID = " . intval($uid); + $dbh->exec($q); + } +} diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 063de8fc..ce569ea7 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -22,6 +22,7 @@ include_once('timezone.inc.php'); set_tz(); check_sid(); +check_tos(); /** * Check if a visitor is logged in @@ -91,6 +92,28 @@ function check_sid() { return; } +/** + * Redirect user to the Terms of Service agreement if there are updated terms. + * + * @return void + */ +function check_tos() { + if (!isset($_COOKIE["AURSID"])) { + return; + } + + $path = $_SERVER['PATH_INFO']; + $route = get_route($path); + if (!$route || $route == "tos.php") { + return; + } + + if (count(fetch_updated_terms(uid_from_sid($_COOKIE["AURSID"]))) > 0) { + header('Location: ' . get_uri('/tos')); + exit(); + } +} + /** * Verify the supplied CSRF token matches expected token * diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php index 8c45c626..7d9750a0 100644 --- a/web/lib/routing.inc.php +++ b/web/lib/routing.inc.php @@ -16,6 +16,7 @@ $ROUTES = array( '/passreset' => 'passreset.php', '/rpc' => 'rpc.php', '/rss' => 'rss.php', + '/tos' => 'tos.php', '/tu' => 'tu.php', '/addvote' => 'addvote.php', ); From 0c6a415cb36ef8f245c787dfe68d107066f9dfbd Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Tue, 2 May 2017 09:58:07 -0400 Subject: [PATCH 0380/1891] gendummydata.py: Fix NOT NULL constraint problems PackageBases.FlaggerComment and PackageComments.RenderedComment cannot be NULL and would cause problems in the output file for sqlite users. This patch adds empty strings ("") as values for these fields. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- schema/gendummydata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 373f82ea..5ed63327 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -205,8 +205,8 @@ for p in list(seen_pkgs.keys()): uuid = genUID() # the submitter/user - s = ("INSERT INTO PackageBases (ID, Name, SubmittedTS, ModifiedTS, " - "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', %d, %d, %d, %s, %s);\n") + s = ("INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, " + "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', '', %d, %d, %d, %s, %s);\n") s = s % (seen_pkgs[p], p, NOW, NOW, uuid, muid, puid) out.write(s) @@ -223,7 +223,7 @@ for p in list(seen_pkgs.keys()): for i in range(0, num_comments): now = NOW + random.randrange(400, 86400*3) s = ("INSERT INTO PackageComments (PackageBaseID, UsersID," - " Comments, CommentTS) VALUES (%d, %d, '%s', %d);\n") + " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n") s = s % (seen_pkgs[p], genUID(), genFortune(), now) out.write(s) From ad4acfb9aafe3cbee9c91570d039fcf4873c5762 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 22 Jul 2017 17:45:46 +0200 Subject: [PATCH 0381/1891] Document new git-serve commands Signed-off-by: Lukas Fleischer --- doc/git-interface.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/git-interface.txt b/doc/git-interface.txt index 475fda66..77585126 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -41,11 +41,15 @@ The Shell: git-serve The git-serve command, the "aurweb shell", provides different subcommands: +* The adopt/disown commands can be used to change ownership of a package base. +* The flag/unflag commands can be used to flag/unflag a package. * The help command shows a list of available commands. * The list-repos command lists all repositories of the authenticated user. +* The restore command can be used to restore a deleted package base. +* The set-comaintainers command modifies the co-maintainers of a package base. * The set-keywords command modifies the keywords assigned to a package base. * The setup-repo command can be used to create a new repository. -* The restore command can be used to restore a deleted package base. +* The vote/unvote command can be used to vote/unvote for a package base. * The git-{receive,upload}-pack commands are redirected to git-shell(1). The command is extracted from the SSH_ORIGINAL_COMMAND environment variable From 243fb92273de1c8bf5c938a62cb06bd198c97c4c Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 20 Jul 2017 17:51:43 -0400 Subject: [PATCH 0382/1891] Fix setting keywords in the SSH interface This was broken in commit 8914a41db938194efc021f842c89d47ff6b522c9 which refactored the argument parsing. Instead of checking for at least the set-keywords command and a pkgbase name, we were checking for *exactly* the command and pkgbase name, leaving no room for keywords... As a result, while we could clear the keywords, we could not set them. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- aurweb/git/serve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 3eef26a7..eea0c9c5 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -502,7 +502,7 @@ def serve(action, cmdargv, user, privileged, remote_addr): cmd = action + " '" + repo_path + "'" os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd) elif action == 'set-keywords': - checkarg(cmdargv, 'repository name') + checkarg_atleast(cmdargv, 'repository name') pkgbase_set_keywords(cmdargv[1], cmdargv[2:]) elif action == 'list-repos': checkarg(cmdargv) From c5302d3a33028f483cc2e01225226d4ae047dd4a Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 24 Jul 2017 23:31:19 -0400 Subject: [PATCH 0383/1891] Require TUs to explicitly request to overwrite a pkgbase AUR_PRIVILEGED allows people with privileged AUR accounts to evade the block on non-fast-forward commits. While valid in this case, we should not do so by default, since in at least one case a TU did this without realizing there was an existing package. ( https://aur.archlinux.org/packages/rtmidi/ ) Switch to using allow_overwrite to check for destructive actions. Use .ssh/config "SendEnv" on the TU's side and and sshd_config "AcceptEnv" in the AUR server to specifically request overwrite access. TUs should use: `AUR_OVERWRITE=1 git push --force` Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- INSTALL | 1 + aurweb/git/auth.py | 2 ++ aurweb/git/update.py | 3 ++- doc/git-interface.txt | 6 ++++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index 8c9c4dd1..369e1e3f 100644 --- a/INSTALL +++ b/INSTALL @@ -76,6 +76,7 @@ read the instructions below. PasswordAuthentication no AuthorizedKeysCommand /usr/local/bin/aurweb-git-auth "%t" "%k" AuthorizedKeysCommandUser aur + AcceptEnv AUR_OVERWRITE 9) If you want to enable smart HTTP support with nginx and fcgiwrap, you can use the following directives: diff --git a/aurweb/git/auth.py b/aurweb/git/auth.py index 022b0fff..d02390da 100755 --- a/aurweb/git/auth.py +++ b/aurweb/git/auth.py @@ -1,5 +1,6 @@ #!/usr/bin/python3 +import os import shlex import re import sys @@ -52,6 +53,7 @@ def main(): env_vars = { 'AUR_USER': user, 'AUR_PRIVILEGED': '1' if account_type > 1 else '0', + 'AUR_OVERWRITE' : os.environ.get('AUR_OVERWRITE', '0') if account_type > 1 else '0', } key = keytype + ' ' + keytext diff --git a/aurweb/git/update.py b/aurweb/git/update.py index c9a98d07..16fa2b07 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -238,6 +238,7 @@ def main(): user = os.environ.get("AUR_USER") pkgbase = os.environ.get("AUR_PKGBASE") privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1') + allow_overwrite = (os.environ.get("AUR_OVERWRITE", '0') == '1') warn_or_die = warn if privileged else die if len(sys.argv) == 2 and sys.argv[1] == "restore": @@ -258,7 +259,7 @@ def main(): conn = aurweb.db.Connection() # Detect and deny non-fast-forwards. - if sha1_old != "0" * 40 and not privileged: + if sha1_old != "0" * 40 and not allow_overwrite: walker = repo.walk(sha1_old, pygit2.GIT_SORT_TOPOLOGICAL) walker.hide(sha1_new) if next(walker, None) is not None: diff --git a/doc/git-interface.txt b/doc/git-interface.txt index 77585126..f9409612 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -33,6 +33,11 @@ users cannot access anything on the server except for the aurweb SSH interface. The forced command can be configured in the aurweb configuration file and it usually points to the git-serve program. +If SSH has been configured to pass on the AUR_OVERWRITE environment variable +(via SendEnv, see ssh_config(5) for details) and the user's account is a +registered Trusted User or Developer, this will be passed on to the git-update +program in order to enable a non-fast-forward push. + The INSTALL file in the top-level directory contains detailed instructions on how to configure sshd(8) to use git-auth for authentication. @@ -67,6 +72,7 @@ The Git update hook, called git-update, performs several subtasks: * Prevent from creating branches or tags other than master. * Deny non-fast-forwards, except for Trusted Users and Developers. +* Deny blacklisted packages, except for Trusted Users and Developers. * Verify each new commit (validate meta data, impose file size limits, ...) * Update package base information and package information in the database. * Update the named branch and the namespaced HEAD ref of the package. From e06773add6bbecdf9ce797412ff0125780ba635d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 1 Aug 2017 06:59:49 +0200 Subject: [PATCH 0384/1891] Unset PackagerUID before deleting an account When removing an account, remove the user from all last packager fields before deletion to make sure that no package bases are deleted, even if propagation constraints are missing. Fixes FS#53956. Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index e45d735b..bdcaaa82 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -924,7 +924,7 @@ function user_delete($id) { $fields_set_null = array( array("PackageBases", "SubmitterUID"), array("PackageBases", "MaintainerUID"), - array("PackageBases", "SubmitterUID"), + array("PackageBases", "PackagerUID"), array("PackageComments", "UsersID"), array("PackageComments", "DelUsersID"), array("PackageRequests", "UsersID"), From d9883ee64215ee91bfe1cc3e75c83ec6e6875671 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 1 Aug 2017 07:08:29 +0200 Subject: [PATCH 0385/1891] mkpkglists: Generate a list of user names In addition to the packages list and the package base list, also create a list of registered user names. Signed-off-by: Lukas Fleischer --- aurweb/scripts/mkpkglists.py | 7 +++++++ conf/config.proto | 1 + test/setup.sh | 1 + test/t2100-mkpkglists.sh | 18 ++++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 8a0f2e9d..686ee7d0 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -8,6 +8,7 @@ import aurweb.db packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') +userfile = aurweb.config.get('mkpkglists', 'userfile') def main(): @@ -16,6 +17,7 @@ def main(): datestr = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") pkglist_header = "# AUR package list, generated on " + datestr pkgbaselist_header = "# AUR package base list, generated on " + datestr + userlist_header = "# AUR user name list, generated on " + datestr with gzip.open(packagesfile, "w") as f: f.write(bytes(pkglist_header + "\n", "UTF-8")) @@ -31,6 +33,11 @@ def main(): "WHERE PackagerUID IS NOT NULL") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + with gzip.open(userfile, "w") as f: + f.write(bytes(userlist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT UserName FROM Users") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + conn.close() diff --git a/conf/config.proto b/conf/config.proto index 6c637b02..17509299 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -71,3 +71,4 @@ server = ftp://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] packagesfile = /srv/http/aurweb/web/html/packages.gz pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz +userfile = /srv/http/aurweb/web/html/users.gz diff --git a/test/setup.sh b/test/setup.sh index efa1ab86..d98c49c6 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -61,6 +61,7 @@ server = file://$(pwd)/remote/ [mkpkglists] packagesfile = packages.gz pkgbasefile = pkgbase.gz +userfile = users.gz EOF cat >sendmail.sh <<-\EOF diff --git a/test/t2100-mkpkglists.sh b/test/t2100-mkpkglists.sh index 1e2edc38..fc11d073 100755 --- a/test/t2100-mkpkglists.sh +++ b/test/t2100-mkpkglists.sh @@ -44,4 +44,22 @@ test_expect_success 'Test package list generation.' ' test_cmp actual expected ' +test_expect_success 'Test user list generation.' ' + "$MKPKGLISTS" && + cat <<-EOD >expected && + dev + tu + tu2 + tu3 + tu4 + user + user2 + user3 + user4 + EOD + gunzip users.gz && + sed "/^#/d" users >actual && + test_cmp actual expected +' + test_done From 449909a872f738043890f521fcc297265836c983 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 1 Aug 2017 07:11:04 +0200 Subject: [PATCH 0386/1891] INSTALL: Add new dependencies Add installation instructions for python-bleach and python-markdown which are required for the rendercomment script. Signed-off-by: Lukas Fleischer --- INSTALL | 1 + 1 file changed, 1 insertion(+) diff --git a/INSTALL b/INSTALL index 369e1e3f..ba24a450 100644 --- a/INSTALL +++ b/INSTALL @@ -48,6 +48,7 @@ read the instructions below. 5) Install Python modules and dependencies: # pacman -S python-mysql-connector python-pygit2 python-srcinfo + # pacman -S python-bleach python-markdown # python3 setup.py install 6) Create a new user: From e0d3fbfdf1fa421800051c265e1f4f2f9d2466cb Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 8 Aug 2017 15:26:59 +0200 Subject: [PATCH 0387/1891] t1300: Fix test cases for non-fast-forward pushes Since commit c5302d3 (Require TUs to explicitly request to overwrite a pkgbase, 2017-07-24), non-fast-forward pushes are denied even for Trusted Users, unless the AUR_OVERWRITE environment variable is set. Mark the test case performing a non-fast-forward push from a TU account as test_must_fail and add another test case performing the same operation with AUR_OVERWRITE=1. Signed-off-by: Lukas Fleischer --- test/t1300-git-update.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.sh index f16e2ad4..109351a9 100755 --- a/test/t1300-git-update.sh +++ b/test/t1300-git-update.sh @@ -125,7 +125,18 @@ test_expect_success 'Performing a non-fast-forward ref update.' ' test_expect_success 'Performing a non-fast-forward ref update as Trusted User.' ' old=$(git -C aur.git rev-parse HEAD) && new=$(git -C aur.git rev-parse HEAD^) && + cat >expected <<-EOD && + error: denying non-fast-forward (you should pull first) + EOD AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ + test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && + test_cmp expected actual +' + +test_expect_success 'Performing a non-fast-forward ref update with AUR_OVERWRITE=1.' ' + old=$(git -C aur.git rev-parse HEAD) && + new=$(git -C aur.git rev-parse HEAD^) && + AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 AUR_OVERWRITE=1 \ "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 ' From 624d168b22ef48b304d09c4ef8c58b78dc061e92 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 8 Aug 2017 15:33:25 +0200 Subject: [PATCH 0388/1891] git-serve: Fix broken SQL statement Add a missing space to the SQL statement performing the disown operation. Fixes FS#55068. Note that the broken query was not discovered by the test suite since SQLite parses "?AND" inside prepared statements gracefully while MySQL does not. Signed-off-by: Lukas Fleischer --- aurweb/git/serve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index eea0c9c5..dfaddd13 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -192,7 +192,7 @@ def pkgreq_by_pkgbase(pkgbase_id, reqtype): "INNER JOIN RequestTypes ON " + "RequestTypes.ID = PackageRequests.ReqTypeID " + "WHERE PackageRequests.Status = 0 " + - "AND PackageRequests.PackageBaseID = ?" + + "AND PackageRequests.PackageBaseID = ? " + "AND RequestTypes.Name = ?", [pkgbase_id, reqtype]) return [row[0] for row in cur.fetchall()] From 2d2bef3513c81e434775c004eb78fc1d73ebae2e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 10 Aug 2017 15:17:06 +0200 Subject: [PATCH 0389/1891] t1100: Test AUR_OVERWRITE Since c5302d3 (Require TUs to explicitly request to overwrite a pkgbase, 2017-07-24), non-fast-forward pushes require setting the AUR_OVERWRITE environment variable. Make sure that git-auth passes this variable to git-serve when it should (and does not pass it if it shouldn't). Signed-off-by: Lukas Fleischer --- test/t1100-git-auth.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/t1100-git-auth.sh b/test/t1100-git-auth.sh index 71d526f2..dd20bea1 100755 --- a/test/t1100-git-auth.sh +++ b/test/t1100-git-auth.sh @@ -25,4 +25,21 @@ test_expect_success 'Test authentication with a wrong key.' ' test_must_be_empty out ' +test_expect_success 'Test AUR_OVERWRITE passthrough.' ' + AUR_OVERWRITE=1 \ + "$GIT_AUTH" "$AUTH_KEYTYPE_TU" "$AUTH_KEYTEXT_TU" >out && + grep -q AUR_OVERWRITE=1 out +' + +test_expect_success 'Make sure that AUR_OVERWRITE is unset by default.' ' + "$GIT_AUTH" "$AUTH_KEYTYPE_TU" "$AUTH_KEYTEXT_TU" >out && + grep -q AUR_OVERWRITE=0 out +' + +test_expect_success 'Make sure regular users cannot set AUR_OVERWRITE.' ' + AUR_OVERWRITE=1 \ + "$GIT_AUTH" "$AUTH_KEYTYPE_USER" "$AUTH_KEYTEXT_USER" >out && + grep -q AUR_OVERWRITE=0 out +' + test_done From cb307bf01aba9f76df5c1f800ae2296091a31fce Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 25 Aug 2017 06:53:02 +0200 Subject: [PATCH 0390/1891] Do not hardcode path to the Python interpreter Use `/usr/bin/env python3` instead of `/usr/bin/python3` in the shebang of Python scripts. This adds support for non-standard Python interpreter paths such as the paths used in virtualenv environments. Signed-off-by: Lukas Fleischer --- aurweb/git/auth.py | 2 +- aurweb/git/serve.py | 2 +- aurweb/git/update.py | 2 +- aurweb/scripts/aurblup.py | 2 +- aurweb/scripts/mkpkglists.py | 2 +- aurweb/scripts/notify.py | 2 +- aurweb/scripts/pkgmaint.py | 2 +- aurweb/scripts/popupdate.py | 2 +- aurweb/scripts/rendercomment.py | 2 +- aurweb/scripts/tuvotereminder.py | 2 +- schema/gendummydata.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/aurweb/git/auth.py b/aurweb/git/auth.py index d02390da..b7819a95 100755 --- a/aurweb/git/auth.py +++ b/aurweb/git/auth.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import os import shlex diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index dfaddd13..93ff34cf 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import os import re diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 16fa2b07..f681ddb9 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import os import pygit2 diff --git a/aurweb/scripts/aurblup.py b/aurweb/scripts/aurblup.py index 1b6de2f0..1433173c 100755 --- a/aurweb/scripts/aurblup.py +++ b/aurweb/scripts/aurblup.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import pyalpm import re diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 686ee7d0..6724141a 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import datetime import gzip diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 69164fba..2d0f7575 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import email.mime.text import subprocess diff --git a/aurweb/scripts/pkgmaint.py b/aurweb/scripts/pkgmaint.py index 3ad9ed8d..36da126f 100755 --- a/aurweb/scripts/pkgmaint.py +++ b/aurweb/scripts/pkgmaint.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import time diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index 58cd0185..b64deedb 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import time diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 9c0aa6a3..22aa856f 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import re import pygit2 diff --git a/aurweb/scripts/tuvotereminder.py b/aurweb/scripts/tuvotereminder.py index 97b1d12e..eb3874e1 100755 --- a/aurweb/scripts/tuvotereminder.py +++ b/aurweb/scripts/tuvotereminder.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import subprocess import time diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 5ed63327..1f3d0476 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 """ usage: gendummydata.py outputfilename.sql """ From 7ef1427678f754de128d4fb34f9fe6011cba1218 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 25 Aug 2017 06:57:22 +0200 Subject: [PATCH 0391/1891] Fix use of test_must_fail with environment variables Signed-off-by: Lukas Fleischer --- test/t1200-git-serve.sh | 64 ++++++++++++++-------- test/t1300-git-update.sh | 115 +++++++++++++++++++++++---------------- 2 files changed, 111 insertions(+), 68 deletions(-) diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index 038a7989..94a5ff61 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -23,7 +23,9 @@ test_expect_success 'Test help.' ' test_expect_success 'Test maintenance mode.' ' mv config config.old && sed "s/^\(enable-maintenance = \)0$/\\11/" config.old >config && - SSH_ORIGINAL_COMMAND=help test_must_fail "$GIT_SERVE" 2>actual && + test_must_fail \ + env SSH_ORIGINAL_COMMAND=help \ + "$GIT_SERVE" 2>actual && cat >expected <<-EOF && The AUR is down due to maintenance. We will be back soon. EOF @@ -44,7 +46,9 @@ test_expect_success 'Test IP address logging.' ' test_expect_success 'Test IP address bans.' ' SSH_CLIENT_ORIG="$SSH_CLIENT" && SSH_CLIENT="1.3.3.7 1337 22" && - SSH_ORIGINAL_COMMAND=help test_must_fail "$GIT_SERVE" 2>actual && + test_must_fail \ + env SSH_ORIGINAL_COMMAND=help \ + "$GIT_SERVE" 2>actual && cat >expected <<-EOF && The SSH interface is disabled for your IP address. EOF @@ -78,9 +82,10 @@ test_expect_success 'Test git-receive-pack.' ' ' test_expect_success 'Test git-receive-pack with an invalid repository name.' ' - SSH_ORIGINAL_COMMAND="git-receive-pack /!.git/" \ + test_must_fail \ + env SSH_ORIGINAL_COMMAND="git-receive-pack /!.git/" \ AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 >actual + "$GIT_SERVE" 2>&1 >actual ' test_expect_success "Test git-upload-pack." ' @@ -108,9 +113,10 @@ test_expect_success "Try to pull from someone else's repository." ' ' test_expect_success "Try to push to someone else's repository." ' - SSH_ORIGINAL_COMMAND="git-receive-pack /foobar2.git/" \ + test_must_fail \ + env SSH_ORIGINAL_COMMAND="git-receive-pack /foobar2.git/" \ AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 + "$GIT_SERVE" 2>&1 ' test_expect_success "Try to push to someone else's repository as Trusted User." ' @@ -138,8 +144,10 @@ test_expect_success "Test restore." ' ' test_expect_success "Try to restore an existing package base." ' - SSH_ORIGINAL_COMMAND="restore foobar2" AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 + test_must_fail \ + env SSH_ORIGINAL_COMMAND="restore foobar2" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 ' test_expect_success "Disown all package bases." ' @@ -169,8 +177,10 @@ test_expect_success "Adopt a package base as a regular user." ' ' test_expect_success "Adopt an already adopted package base." ' - SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 + test_must_fail \ + env SSH_ORIGINAL_COMMAND="adopt foobar" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 ' test_expect_success "Adopt a package base as a Trusted User." ' @@ -207,8 +217,10 @@ test_expect_success "Disown one's own package base as a Trusted User." ' test_expect_success "Try to steal another user's package as a regular user." ' SSH_ORIGINAL_COMMAND="adopt foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ "$GIT_SERVE" 2>&1 && - SSH_ORIGINAL_COMMAND="adopt foobar2" AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 && + test_must_fail \ + env SSH_ORIGINAL_COMMAND="adopt foobar2" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && EOF SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ @@ -247,8 +259,10 @@ test_expect_success "Try to steal another user's package as a Trusted User." ' test_expect_success "Try to disown another user's package as a regular user." ' SSH_ORIGINAL_COMMAND="adopt foobar2" AUR_USER=tu AUR_PRIVILEGED=1 \ "$GIT_SERVE" 2>&1 && - SSH_ORIGINAL_COMMAND="disown foobar2" AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 && + test_must_fail \ + env SSH_ORIGINAL_COMMAND="disown foobar2" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && *foobar2 EOF @@ -303,9 +317,10 @@ test_expect_success "Update package base co-maintainers." ' ' test_expect_success "Try to add co-maintainers to an orphan package base." ' - SSH_ORIGINAL_COMMAND="set-comaintainers foobar2 user2 user3 user4" \ + test_must_fail \ + env SSH_ORIGINAL_COMMAND="set-comaintainers foobar2 user2 user3 user4" \ AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 && + "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && 4|3|1 5|3|2 @@ -425,8 +440,10 @@ test_expect_success "Unflag a package base as random user." ' test_expect_success "Flag using a comment which is too short." ' SSH_ORIGINAL_COMMAND="unflag foobar" AUR_USER=user2 AUR_PRIVILEGED=0 \ "$GIT_SERVE" 2>&1 && - SSH_ORIGINAL_COMMAND="flag foobar xx" AUR_USER=user2 AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 && + test_must_fail \ + env SSH_ORIGINAL_COMMAND="flag foobar xx" \ + AUR_USER=user2 AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && 0|Because. EOF @@ -453,8 +470,9 @@ test_expect_success "Vote for a package base." ' ' test_expect_success "Vote for a package base twice." ' - SSH_ORIGINAL_COMMAND="vote foobar" AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 && + test_must_fail \ + env SSH_ORIGINAL_COMMAND="vote foobar" AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && 3|1 EOF @@ -486,8 +504,10 @@ test_expect_success "Remove vote from a package base." ' ' test_expect_success "Try to remove the vote again." ' - SSH_ORIGINAL_COMMAND="unvote foobar" AUR_USER=user AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_SERVE" 2>&1 && + test_must_fail \ + env SSH_ORIGINAL_COMMAND="unvote foobar" \ + AUR_USER=user AUR_PRIVILEGED=0 \ + "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && EOF echo "SELECT PackageBaseID, UsersID FROM PackageVotes;" | \ diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.sh index 109351a9..b9c4f53a 100755 --- a/test/t1300-git-update.sh +++ b/test/t1300-git-update.sh @@ -95,8 +95,9 @@ test_expect_success 'Test restore mode on a non-existent repository.' ' cat >expected <<-EOD && error: restore: repository not found: foobar3 EOD - AUR_USER=user AUR_PKGBASE=foobar3 AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" restore >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar3 AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" restore >actual 2>&1 && test_cmp expected actual ' @@ -106,8 +107,9 @@ test_expect_success 'Pushing to a branch other than master.' ' cat >expected <<-EOD && error: pushing to a branch other than master is restricted EOD - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/pu "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/pu "$old" "$new" >actual 2>&1 && test_cmp expected actual ' @@ -117,8 +119,9 @@ test_expect_success 'Performing a non-fast-forward ref update.' ' cat >expected <<-EOD && error: denying non-fast-forward (you should pull first) EOD - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && test_cmp expected actual ' @@ -128,8 +131,9 @@ test_expect_success 'Performing a non-fast-forward ref update as Trusted User.' cat >expected <<-EOD && error: denying non-fast-forward (you should pull first) EOD - AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && + test_must_fail \ + env AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && test_cmp expected actual ' @@ -146,8 +150,9 @@ test_expect_success 'Removing .SRCINFO.' ' git -C aur.git rm -q .SRCINFO && git -C aur.git commit -q -m "Remove .SRCINFO" && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing .SRCINFO$" actual ' @@ -158,8 +163,9 @@ test_expect_success 'Removing .SRCINFO with a follow-up fix.' ' git -C aur.git commit -q -m "Remove .SRCINFO" && git -C aur.git revert --no-edit HEAD && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing .SRCINFO$" actual ' @@ -169,8 +175,9 @@ test_expect_success 'Removing PKGBUILD.' ' git -C aur.git rm -q PKGBUILD && git -C aur.git commit -q -m "Remove PKGBUILD" && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing PKGBUILD$" actual ' @@ -182,8 +189,9 @@ test_expect_success 'Pushing a tree with a subdirectory.' ' git -C aur.git add subdir/file && git -C aur.git commit -q -m "Add subdirectory" && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: the repository must not contain subdirectories$" actual ' @@ -194,8 +202,9 @@ test_expect_success 'Pushing a tree with a large blob.' ' git -C aur.git add file && git -C aur.git commit -q -m "Add large blob" && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual ' @@ -209,8 +218,9 @@ test_expect_success 'Pushing .SRCINFO with a non-matching package base.' ' git commit -q -am "Change package base" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: invalid pkgbase: foobar2, expected foobar$" actual ' @@ -224,8 +234,9 @@ test_expect_success 'Pushing .SRCINFO with invalid syntax.' ' git commit -q -am "Break .SRCINFO" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 ' test_expect_success 'Pushing .SRCINFO without pkgver.' ' @@ -238,8 +249,9 @@ test_expect_success 'Pushing .SRCINFO without pkgver.' ' git commit -q -am "Remove pkgver" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing mandatory field: pkgver$" actual ' @@ -253,8 +265,9 @@ test_expect_success 'Pushing .SRCINFO without pkgrel.' ' git commit -q -am "Remove pkgrel" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing mandatory field: pkgrel$" actual ' @@ -288,8 +301,9 @@ test_expect_success 'Pushing .SRCINFO with invalid pkgname.' ' git commit -q -am "Change pkgname" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: invalid package name: !$" actual ' @@ -303,8 +317,9 @@ test_expect_success 'Pushing .SRCINFO with invalid epoch.' ' git commit -q -am "Change epoch" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: invalid epoch: !$" actual ' @@ -319,8 +334,9 @@ test_expect_success 'Pushing .SRCINFO with too long URL.' ' git commit -q -am "Change URL" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: url field too long: $url\$" actual ' @@ -334,8 +350,9 @@ test_expect_success 'Missing install file.' ' git commit -q -am "Add install field" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing install file: install$" actual ' @@ -349,8 +366,9 @@ test_expect_success 'Missing changelog file.' ' git commit -q -am "Add changelog field" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing changelog file: changelog$" actual ' @@ -364,8 +382,9 @@ test_expect_success 'Missing source file.' ' git commit -q -am "Add file to the source array" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: missing source file: file$" actual ' @@ -380,8 +399,9 @@ test_expect_success 'Pushing .SRCINFO with too long source URL.' ' git commit -q -am "Add huge source URL" ) && new=$(git -C aur.git rev-parse HEAD) && - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && grep -q "^error: source entry too long: $url\$" actual ' @@ -394,8 +414,9 @@ test_expect_success 'Pushing a blacklisted package.' ' cat >expected <<-EOD && error: package is blacklisted: forbidden EOD - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && test_cmp expected actual ' @@ -422,8 +443,9 @@ test_expect_success 'Pushing a package already in the official repositories.' ' cat >expected <<-EOD && error: package already provided by [core]: official EOD - AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && test_cmp expected actual ' @@ -455,8 +477,9 @@ test_expect_success 'Trying to hijack a package.' ' cat >expected <<-EOD && error: cannot overwrite package: foobar EOD - AUR_USER=user AUR_PKGBASE=foobar2 AUR_PRIVILEGED=0 \ - test_must_fail "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar2 AUR_PRIVILEGED=0 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && test_cmp expected actual ' From 36f26033d8505576041467ec3d8d6204d65e2025 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 25 Aug 2017 06:59:56 +0200 Subject: [PATCH 0392/1891] Add basic Travis CI support Add a Travis CI configuration file to setup a test environment with all the required dependencies and run the test suite. Signed-off-by: Lukas Fleischer --- .travis.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..5bbfda1f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +language: python + +python: 3.6 + +addons: + apt: + packages: + - bsdtar + - libarchive-dev + - libgpgme11-dev + - libprotobuf-dev + +install: + - curl https://codeload.github.com/libgit2/libgit2/tar.gz/v0.26.0 | tar -xz + - curl https://sources.archlinux.org/other/pacman/pacman-5.0.2.tar.gz | tar -xz + - curl https://git.archlinux.org/pyalpm.git/snapshot/pyalpm-0.8.1.tar.gz | tar -xz + - ( cd libgit2-0.26.0 && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr && make && sudo make install ) + - ( cd pacman-5.0.2 && ./configure --prefix=/usr && make && sudo make install ) + - ( cd pyalpm-0.8.1 && python setup.py build && python setup.py install ) + - pip install mysql-connector-python-rf pygit2==0.26 srcinfo + - pip install bleach Markdown + +script: make -C test From 6c95fa3d1e4b5f7911b2dbdb94517baeafce11b3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 5 Nov 2017 08:24:51 +0100 Subject: [PATCH 0393/1891] Point out that the user name is public when registering Signed-off-by: Lukas Fleischer --- web/template/account_edit_form.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 17c9d14e..833e74a8 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -20,6 +20,9 @@ ()

    +

    + +

    Date: Sun, 5 Nov 2017 08:36:23 +0100 Subject: [PATCH 0394/1891] Set X-Frame-Options to DENY for all pages Do not allow to render aurweb pages in a frame to protect against clickjacking. Fixes FS#56168. Signed-off-by: Lukas Fleischer --- web/lib/aur.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index ce569ea7..6cd04515 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -4,6 +4,7 @@ header('Content-Type: text/html; charset=utf-8'); header('Cache-Control: no-cache, must-revalidate'); header('Expires: Tue, 11 Oct 1988 22:00:00 GMT'); // quite a special day header('Pragma: no-cache'); +header('X-Frame-Options: DENY'); date_default_timezone_set('UTC'); From 4efba18f8688431fae58ae1b826b80f95957aec8 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 5 Nov 2017 08:48:25 +0100 Subject: [PATCH 0395/1891] Only allow valid HTTP(s) URLs as home page The home page specified in the account settings is converted to a clickable link on the user's profile. Make sure it is a valid URL which uses the http or https scheme. Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 4 ++++ web/lib/aur.inc.php | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index bdcaaa82..b8d9dc54 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -162,6 +162,10 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $error = __("The email address is invalid."); } + if (!$error && !valid_homepage($HP)) { + $error = __("The home page is invalid, please specify the full HTTP(s) URL."); + } + if (!$error && $K != '' && !valid_pgp_fingerprint($K)) { $error = __("The PGP key fingerprint is invalid."); } diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 6cd04515..feb4006b 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -150,6 +150,26 @@ function valid_email($addy) { return true; } +/** + * Verify that a given URL is valid and uses the HTTP(s) protocol + * + * @param string $url URL of the home page to be validated + * + * @return bool True if URL passes validity checks, false otherwise + */ +function valid_homepage($url) { + if (filter_var($url, FILTER_VALIDATE_URL) === false) { + return false; + } + + $url_components = parse_url($url); + if (!in_array($url_components['scheme'], array('http', 'https'))) { + return false; + } + + return true; +} + /** * Generate a unique session ID * From e2fa5ea6fa0bf90043e041c7cfc6fa036834758c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 5 Nov 2017 11:27:36 +0100 Subject: [PATCH 0396/1891] login.php: Escape quotes in the referer field Replace special characters in the referer GET parameter using htmlspecialchars() before inserting it into the login form fields to prevent from XSS attacks. Fixes FS#55286. Signed-off-by: Lukas Fleischer --- web/html/login.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/login.php b/web/html/login.php index a55ce057..df517055 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -41,7 +41,7 @@ html_header('AUR ' . __("Login")); " /> [] - + From 8c98db0b82cc85a4498589e5d60299fefd93b421 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 6 Nov 2017 16:57:12 +0100 Subject: [PATCH 0397/1891] Allow package co-maintainers to pin comments Implements FS#56255. Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 5c48a8ea..dbcf63e8 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -85,8 +85,9 @@ function can_edit_comment_array($comment) { /** * Determine if the user can pin a specific package comment * - * Only the Package Maintainer, Trusted Users, and Developers can pin - * comments. This function is used for the backend side of comment pinning. + * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and + * Developers can pin comments. This function is used for the backend side of + * comment pinning. * * @param string $comment_id The comment ID in the database * @@ -97,6 +98,11 @@ function can_pin_comment($comment_id=0) { $q = "SELECT MaintainerUID FROM PackageBases AS pb "; $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment_id) . " "; + $q.= "UNION "; + $q = "SELECT pcm.UsersID FROM PackageComaintainers AS pcm "; + $q.= "LEFT JOIN PackageComments AS pc "; + $q.= "ON pcm.PackageBaseID = pc.PackageBaseID "; $q.= "WHERE pc.ID = " . intval($comment_id); $result = $dbh->query($q); @@ -104,16 +110,17 @@ function can_pin_comment($comment_id=0) { return false; } - $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + $uids = $result->fetchAll(PDO::FETCH_COLUMN, 0); - return has_credential(CRED_COMMENT_PIN, array($uid)); + return has_credential(CRED_COMMENT_PIN, $uids); } /** * Determine if the user can edit a specific package comment using an array * - * Only the Package Maintainer, Trusted Users, and Developers can pin - * comments. This function is used for the frontend side of comment pinning. + * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and + * Developers can pin comments. This function is used for the frontend side of + * comment pinning. * * @param array $comment All database information relating a specific comment * From 0aa67b278ab8572f771603e74a92ef7ba56f006b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 7 Nov 2017 21:36:42 +0100 Subject: [PATCH 0398/1891] Fix sorting order when clicking table headings A bug introduced in commit 7d7e079 (Hide the table sorting links on the dashboard, 2017-02-04) resulted in multiple clicks on a table heading in the package search results table no longer having any effect, instead of changing the sorting order. Fix this by removing erroneous spaces from the GET parameters in the search URL. Fixes FS#56261. Signed-off-by: Lukas Fleischer --- web/template/pkg_search_results.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index 7f92685a..d7512b1e 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -3,7 +3,7 @@ if ($show_headers) { $fmtth = function($title, $sb=false, $so=false, $hint=false) { echo ''; if ($sb) { - echo '' . $title . ''; + echo '' . $title . ''; } else { echo $title; } From efa8da5ca2972e1f721215d174f8b85495c6948c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 8 Nov 2017 07:44:56 +0100 Subject: [PATCH 0399/1891] Auto-link bug reports in comments Automatically detect references to Flyspray bug reports in comments and convert them to links to the Arch Linux bug tracker. Implements FS#52008. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 22aa856f..4b642273 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -26,6 +26,20 @@ class LinkifyExtension(markdown.extensions.Extension): md.preprocessors.add('linkify', LinkifyPreprocessor(md), '_end') +class FlysprayLinksPreprocessor(markdown.preprocessors.Preprocessor): + _fsre = re.compile(r'\b(FS#(\d+))\b') + _sub = r'[\1](https://bugs.archlinux.org/task/\2)' + + def run(self, lines): + return [self._fsre.sub(self._sub, line) for line in lines] + + +class FlysprayLinksExtension(markdown.extensions.Extension): + def extendMarkdown(self, md, md_globals): + preprocessor = FlysprayLinksPreprocessor(md) + md.preprocessors.add('flyspray-links', preprocessor, '_end') + + class GitCommitsPreprocessor(markdown.preprocessors.Preprocessor): _oidre = re.compile(r'(\b)([0-9a-f]{7,40})(\b)') _repo = pygit2.Repository(repo_path) @@ -102,6 +116,7 @@ def main(): text, pkgbase = get_comment(conn, commentid) html = markdown.markdown(text, extensions=['fenced_code', LinkifyExtension(), + FlysprayLinksExtension(), GitCommitsExtension(pkgbase), HeadingExtension()]) allowed_tags = bleach.sanitizer.ALLOWED_TAGS + \ From 3be28d016fb7d9a52366cebe0e61ac9f9e978980 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 27 Nov 2017 16:12:02 +0100 Subject: [PATCH 0400/1891] Sync CSS with archweb This partially fixes FS#56472. Signed-off-by: Lukas Fleischer --- web/html/css/archnavbar/archlogo.png | Bin 4192 -> 5359 bytes web/html/css/archnavbar/archnavbar.css | 6 +-- web/html/css/archweb.css | 49 +++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/web/html/css/archnavbar/archlogo.png b/web/html/css/archnavbar/archlogo.png index e873e94b1a38b58963e15252f6e175fc1c6f1ec7..3d2cd40fb499b2b37651ea67ec6f3b4400e3d157 100644 GIT binary patch delta 5335 zcmV;|6e#Q9Anz%VC4Xl@O+f$vv5yPfP?@5`Tzg`fam}K zbua(`>RI+y?e7jT@qQ9J+u00v@9M??Vs0RI60puMM)00009a7bBm000ie000ie z0hKEb8vp9(_n9!TX5H^vSzONjz0dyb-*-QLR~Q7u z;>`d8j1#3D=znQ#s2hx?ODJKlz!}80s(_nR7_YLgr&U4;*)f=cKOMLX_&h-EqLzI< zw-QRohye?JEZzj-I>48Jk-(RMQ7XEx=T<@q8BsRyCInO_0B3s-rUQQiEM?(J_@`6% z^&Iz0sP-v_DE1yY07MGpiIdKw_S)M~*Nq@@AWDZgbbqwYsbg$>wO>jA-CBR#zMl4e zg8^y$F^ktAM(EE54)Y#Y02hHqW09(TJ-_`5s*0*cRn=D%-vS;7zE*6Tv9I2Ss*XV9 zF5p>&6IG!m-b{i>nM>q+m&k0FvNF#JQ330Tuxc=%0YqMRoE25QAado(vqH@~j$|)l;rg z(^%3nDHsKeCn@v;gn&uE1|J9@$eX}Jzz+mA?CXi|PbgaOWASE0wH&w*7#33Gyz(A7 zqGaQyAt;^UiuK~}f>gzzaFRWfW<-i2s z6WGagH1G!SL!eAmKZ)5bM`0Vg3V0Ownb(E@2VlnJ1fUk<>@M&D@D9eQTY*H%M#)BV z%2ahEaG=*-53s}g>x8gP*Qe+epV}9R+JAU6A|mSQ5EaT%T%faD%Mv@CkJ(v&Qqk{k ze?!57U(>h-z(E-fd=D50d@@7v2yg{1KaWHr?Sn900d4^PK1aEufX@QgV8-3|RCQZG zXbuOS048F7bOC;Z3Gmke|0MHmpzXl-z0ZdN7hztMqp%GSTt~%x^6vt_1s+k=KY!qz z79rS%d0WoKyknDrG1%rz06T$=z{|k1s`@7VHdC6M3&7ZWTd3R8=Ro0dO zItpYOFa&sBRl7x`O5rqBJriLfP=(M7Z0(WWRTWe`J7i(YU&K*u_wukj_h=N`{NsTp zpe>s%QN4H_j@yHZ6BXqkfhg+!8Gl4o90VPqwuTvPlCg`|cnd8NRY?G}%_)pZ7i`>$ zI-oKhm01E+=gUB}rz~=Xy4q35ODRm_JBo{p$21e(WM_B-h+>>J3?~3HL8y)oD26f~ z)3S;gv2Oz_fS-GRD}RBuka`usc_d#>7!R(b|I2f+&HNnDj%n>eh2F=<7***G^xc6e zkCW;D9`;}Yy&l*?Iz@79E%_H9ddfk=A+w8A>65dx=U^w(KVzrLJ;2$5T&5~_Mje(Q zEI_y%b6Ky(Ht~&UWQ-WY@Yl&-)13B&3OL%oo_fQPJ@OiGhky6{mJiFj&u~Ti5*}lV zn!O4#6Qi-afu)Fa6zU+(TjSR*Y9S#B9Cc=4yFZ8nfKLS`lZq&C6}Z22h-@oth-u?} z1T$RUz^KA5@4JNecPMZt$=o3yld$9dgB*QyVM6)~U>)#R;CkSgkg|$xv?kz9Z!9q^ zUuhCXrMiIyz<&cN^~R*MwcG3SQQ*(m2B^YL)p;TPp9aKcOc=50l`Xr1&n2awOdA5s zQE&(_58)x8r*+Pheg$Lk<{sch&>KJ=2aW^%6!5DYeS||5bsR|2G;vfwz^w#9ev0a3 z;5y8PoUNi8tM6;_4j7IAZoyP5?O<_;GAe zGi}9PRCx|~1v~1`z&tw#W7;|aYyy^H`7fWr1kXnmrs1*){)d>x`7!1a1=~n7L&|ny zLfVK4{hq)YjKMrl^DsJdH%ZMMCM0_>?j9%Lz418wdTjIkCq@N)M1ZoPWqq%r5U-9u zh6-STqJIyFN+QgdY^$#$*4PBF66G1-A28u765yYc65hiS_#OlP4tNvMJ5ae8Gq&4-TR}F7xP`{bJ` z7=IA@v%H14fN-Jr5yg)1XjpT>1yA{I2j-nfqy(^zrvJ$SX8bKAUFfZ05&v(4h`jIr zKMOWuc0eY$_y>JzUx1hoKP_@gkcRXpB>txzh~}bxNOEhr8T!Z@g5YubzVSLLeGRtN z*Wsv;h`7JUPQgy#dQ@(~lwK6LM~S=u(0|%6wUF-nkW=t$8k^}D;(}3}Ba7-Ki8A0S zlCHgcaR|oS4z;$rm{hc4-1j!j5c(yixd#glFg)b>W*F4eg?zMTXc@`< z$WyQVWIPz|&7DW+M3T*<_mQ{I`-M{qhW6jqPzR#jz`p~lFr~Q#v%z)@G~q6*;Mc}m za1aOc!;jC=mhWENPWBh+0ACU16Mr~)tyLLtYRFhuVYKHm;8x7P{bh`fy_KP@LbD>3 zaEdXcz;^QKC)f8HUPn^f2-C)rLc#mW7D>#D*7%}!_5|xVAu8m8c;9qufg0~~C2$aV zD9v2RDEJ4(SD`2_Ivoq)XTu6$7G{Ni0eG0qA$l+lKHKSvP_sDa1j(&KGX%2Ohz13^9wxml_P1us^*Skdc@J;RxV8%quq^<;XmhW=3T6>LjQ@Agb_>WDne|2CfFyD=vcb4(8s2WS}c- z`d7L`5>JXN8+cmb+>8?u(to4D+xnKj5Pg7^ASEwZVr=}OcN>;aPlSl-;1`9lH!U9&8VqTqZ z3tShAH}4Kop850VdrKnKn8E~$%k+5vcB*Q*hztwW_%)3!{)(Lne19>^;JbjkLDqxP zUOx?QARl2tn|HF*od{g1ip1W@nrG3Axdel##?4tTq?rk9A&ym`j357VN~ZtzzGOe6f=as zPWmZPEH7D)1))-L9_DeV10wzyym5@iB99LMKfzqF*-*4`8-MbBWs;a!upq zA^k?k>pG>Pq7$$*7HdAxp6B8j3(Uv({S&|gh~nD4Vc*4h^R}VAC#yp2zJ7|c8%wr( z6CICAP~d7s zBe9T7yudO3B7f;YpcA|aHez(_1}u{L5d9;ITd};DB)iP^R?^W0+>fP41mR%D^)f72 zH5bdqybJR#ecyY5hkNzU$7d-~!rZ`Rz^BzMBbFhn zGLXi64ar~S=o?pUycscyas#IE*J56rT~(10IJSA0Vt>KDgMr%+VkE5o{Q2{Jx&uZ} z-HM6|Fvif1{p?LQuq93Ky&ZQTrtQOAc|ol2m4sIIR%H5qBbHAdgo|YXuJyi~CCG_6 z6weCa`H<&_V8XTp6SNDwvHN%f?8^X&?aDs zd?P7N@PGYv%T_0c#_zXxl4bMJ`RQ)kzzuiZ3ivAbVsUzpM}%15m-NOhTt_V4geX;* zP+x()8wgSz71Zt}T!YERZJ_G`Hhyh_<=m_Gcx$~J%Nm`h;+AJfVHWQlDn^mc1^xo` z_7nWk@g{!_&ck+Gt{1T#;O)5?<61jN*VKM4i+`W-xD?BU8ImQM`!ROJttEe~1AdC- zbrkIa@D?tC<)q(1adCpTFq>xw;U~{PHGZZ?NdebTcV>P*8F5kz2|#;&9fEXVr|d3F zi~kViB18|4#ha^QjZGsHk;D-ovs8E#dymVpQxO7NQbi|XS*Ig_`w?9V5Hw)bEd$Y3 zjDPBG2EHoloR327;-vhD$VT9u-rin-77;XNIx*W7q@y8*nA?65-lE z6&+ZlaW+PYGGQ<{ex^BQJ7MyoJeEAx?|q>#U&z`Jk$X%2;7ZIPtbM*Xup0E0Ndx>^a@5RhXS{V$YFlkj)*XFSVfQMD}-DouWRG&N3l7kdfW@9PFx!~Xh7DmTcvpxLh>3^#5 ze&8qr4)X^85URH$Y_3_8Sm3G&F?2Pyd5QGmgYG)KOVhp??b#kUs)H zL7Zi{J+w9S7ksb13Bb3pjdU2c5i+gpOTb)|CUKP3Ia9+6_P;(@jaljuOt`j@q*kLa zL+L|L0D>E6D7Gm+#I#h-Ut`EH4#%6*NG!PGcrW=wjMlh*zkxcn-nzVpQN`Wa`uFOT zVKM^Rh{w{kc9^&8p4 z|KsA#^s0j+8U@^*a;LX)cY;mxlJ#Qowe&EYa(0fyt{{&0)}#yAEbykN(+;Yx(e5hm zUf3=WZEcuBWqc)7R8@F&++1l1u|>@wi~@R8`MAA+RClpKH-m_S>VKVB23#t7F|D~A z(@tvywu(s4p&i|9E06H@-1Hw@h{c;xh={rOj=?T~&%kpjh4k}l>>~Gob1_ONAsdo{ zZ@KPEvEOv`(Sh;h$ARY%XEUlrWyRGtHX*3E>Ws$RN*7{0KX?^CG0JTr|mzB87)JwXzTr=tWdP0t;j_Gd|-hNDZ@MgS7CnmQNTPET^LC?Y`wnt zoa+)w$OMTsHXnfUBg{~Yqx>3SH?B+DAZhqq@HSsL7WiqvB7eG<0B@DFehGU65{oxa z2aXna7W4xpLR)>V^qIYb+ITZ+7mCjUcB%4$ltbIKCE+h&a8U-V74tc}ttr8R|7*0? z*AZ)M-h;9Xk#dP>KKV5zlu$7K7r*fEqP3u(9smFUC3HntbYx+4WjbSWWnpw>05UK! zH!UzTEif}wF+wvsFfuwcG%GMUIxsN218Xt>001R)MObuXVRU6WZEs|0W_bWIFflhR pFf%PMGgL7%IxsRiG&CzPIXW;f&0f=vkwzy9002ovPDHLkV1lSW=|TVi delta 4160 zcmV-G5Wny5Dc~TGB_VS{NmK|32nc)#WQYI&010qNS#tmY4c7nw4c7reD4Tebz7!{a z58X*bK~#90?VNjjRn?WpzxyO4+WI7toFEQXKzW1{6sdl6#-eR4w$nN~gI0@*en!)V z8*$V!(+AZQ@$D$&1i?6;S_*9yY&-3U(@tmFsal^%a-bjdIuO4k6C+57G6OG2La`>_!p8^dVphrE6XJN&jBX`N0v)}*s%|E zA5$(_hbqdY_(87CT+?<`ndBd8m;l@a{215;yaJq5s?bK;X*F#pUR!P4n%QpJ>nEF? z&LY)bR@e4V8YQzjrtM4u&JDOU9{3FK@1@Rh2x1;E+t*eOBQY6hK&53hwfELgr+Mzu}gN{jQ;BX{B%3)nGBM?O5|!?7Psk;MyWpj)Chg9Fm2~s@tD`7j@O8>-`3>M# zz?n#iL@v0%Z-BdjCj+j31^5KegiwmTz!cyZ;4<&ilFTI-=YQf%*P*A#aRK`~`Av<9zLX z!1q0we*@eIoSkFdri|bJ8R$ed-vO`9@9Nx(DEu#w%@c$K@R-+scU@2i<+(bUtPa2l z_xBDTs7`!YV?5f|*0dR5ROiOJgxmim493LgSaU%bpf~FhUqR_gCSbr8qcCH&e=vIBAx^`gA_Uop;nQX7` z=s9&)TXWz&4!Pfdht>|$*G(OWI$tJ=_3^I&CIMdnHXvMd40$*~s3lwJN`YTl!=R9j zIWwf+allh#D?Pvx(P2QH7FzlnuIs+g z(AjfQ_Ow->Raz|vTJx+w3$Cu(q7>hyzvegq1*)ObS!F2oe8b`mXXP8))ZSau&_C?A zjh*Y~6f$RO$%PIuZKoD_kVzZ|EJhUTKY_s3`U`fpM>At^1B4bBTDGU ze&9jiA>iVFBIiCG_&Z84B7pYy*x^T0P!qufHHumg^>E6&zd0Mm1!d2CZDx0}NA!yQ*Q)hK5`N zch?Op08ZCh&mVF3D+Oo0i*a>Y304l%`{bMJR`Sz-pHa~ayazmw_~o0t&lV&Iodnzf zoZ=fd4T(ASMVx0V&;zVN+?UxQ{Ra_u<|6^u{snPUAnodmCENJy0Dg+x56HdF1P=4{ zy9~I?Tc1E_9mE$Yl$+&UxoPevVXy>EztZaJzPBeY*SFwi^xOpeykXIX2dQ#@0-Wih zZzD5*W>VTMCI6-e2U3Ik+9ofox1F;TTtJokm}>v^C;f58$jR;a6Y&pTyL zp>q~w@lD$~3JFw;#pPb6w^ZDS1e~7&x)5tL8gac&1pXTdeE;YhSHn;yD%aC`15vD# zkUFGg^V6t-tb}zU6jSgFjPi^ z9;Rxp0Nzk=PQ&ow_hb$j{?OW^U9Fb`28xcIvB^QCMJNh&b-s$YHpRkVsGC$Q-U4oa zM&b(x@wt}(cL2+gx4=ULQZFT_}=@y_8q{(fQ1Cr zGszwQB=I0{ONNY0yov~vBGn`-)NY{bZ|KhpikyaMM-A+q9|w$ng) zN)RqGZRfNS#+yh0dMD!20$q?m_!C$vzhd^yZ7Mvun7O&qfpSrfzOD)mig&h6wvjjQM=|t|wN^_3 zlvZDjUvF(FX09Y6DZXhtCn0=)eYtRfX**Hrz)akVB$|SdARQ3qLowDVh-O?{gq(Z` zTUWT^Clx%4)iJVVr+s`>F$(Jrrp73A^i4Swq0hoKs;>n$f*K1P3+f4PLzIN57XLPc z(=8_owfYL-vHe(wFh%tU|2_)IC~uD_GYW$4yLaCMur7ON63TXJAmkMC_hgkfHtBO$k z^yUiOSYg9ujiP^p!4_YEs&W&Lpg2xxp4RXb3TuzrSF+X5%W#-~wlf`=5h7zVaB)0l z`3tdHk)%&P%Xo%qJD-oote=G~6j8o+ful0o{0XW|7|2^9AEG|+Um`I?=Kt$hghCB+ zzcSH`(5|^M+EEc*xw2`+>`hapHQ@=~+*4?u#TVU;EO6u^=j6dEaUq8VusQ$@9Zs88 zd>$>l`t{YcMUFo`R+;!b4NS=h2mX=1~v78GvZRcXb z{n&lLBYCc`LF(f3p_%BlDt@X_0pA0jLEbRuB5C|yB-xgUWacwd2?}}Oa|q6!&P9@F z-$F9S=OLMY<)@Kq&RQg=u$ufO)Fmr^%H>d5raZsw#v_YhbuukJ$*+;A2`erGsj5`k zxIWe3v-smWHr1k72^t5o2F)Kl^rSzlSn==ecks2L8&O#~{ z{|hn^k>TRXZ>j*a-Uk`i`C( zBQAM=4dS-f0lRZq{MlsqNO|yDgg!whmR!V2u0alIoImkAg=BmEMP9|= zr;vR87K~Sb1>Wz)xH{pAnu}f0**w0=;PEHzJiMgfc6aR59Y}dKz_pF``oL0xkxMpA zXzXyF)S8Y>qhnYQzP zhG{!LG&_41n4LWy&PUI7^kn<;V(CCYVWQ2UE@Ao=+QlMsZ-x) z47`(ToB}msaraomsG5e>(@^?oFxI2AQ%z0xwmIWd8@$2pK0Bcgtj~03#&v9}eb?Q8 zOw{@zbE#ABy6#Bt4Gd$ zI>H(%sGw-16yLO+M#Pfj;-ue3g1g6o|A@z|f=WU?|NT7RZxKohjZM-!ev!ayx77f#Xc19y7kFG>~auC0FLOf>u&%vC#fCA1H@z2)_Bai2B9_|_0~{B@rP9^s2~)op`&Lia+2stV17Jiz5GEg$h4hiMCm^V zoc=+tr-DNh)kxj?+3}e5Y*^?24|sIu=S|x=6IokD@hd1h{tt!|wjGp1kc7 Date: Mon, 27 Nov 2017 16:23:54 +0100 Subject: [PATCH 0401/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index 1434ab15..2d0ac607 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.4.1\n" +"Project-Id-Version: AUR v4.5.1\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -353,7 +353,7 @@ msgstr "" msgid "Login" msgstr "" -#: html/login.php +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "" @@ -442,7 +442,7 @@ msgstr "" msgid "Confirm your new password:" msgstr "" -#: html/passreset.php +#: html/passreset.php html/tos.php msgid "Continue" msgstr "" @@ -668,6 +668,24 @@ msgstr "" msgid "Use this form to create an account." msgstr "" +#: html/tos.php +msgid "Terms of Service" +msgstr "" + +#: html/tos.php +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#: html/tos.php +#, php-format +msgid "revision %d" +msgstr "" + +#: html/tos.php +msgid "I accept the terms and conditions above." +msgstr "" + #: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "" @@ -739,6 +757,10 @@ msgstr "" msgid "The email address is invalid." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" @@ -1196,6 +1218,12 @@ msgstr "" msgid "required" msgstr "" +#: template/account_edit_form.php +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + #: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "" From f44705a640e233dac22edb1aa4b1caf08edfdc79 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 2 Dec 2017 21:30:44 +0100 Subject: [PATCH 0402/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 26 +++++- po/ast.po | 40 +++++++-- po/ca.po | 28 +++++- po/cs.po | 229 +++++++++++++++++++++++++++++-------------------- po/da.po | 26 +++++- po/de.po | 107 ++++++++++++++--------- po/el.po | 26 +++++- po/es.po | 75 ++++++++++------ po/es_419.po | 46 ++++++++-- po/fi.po | 26 +++++- po/fr.po | 28 +++++- po/he.po | 135 +++++++++++++++++++++-------- po/hr.po | 26 +++++- po/hu.po | 32 +++++-- po/it.po | 28 +++++- po/ja.po | 28 +++++- po/nb.po | 237 ++++++++++++++++++++++++++++----------------------- po/nl.po | 26 +++++- po/pl.po | 101 +++++++++++++--------- po/pt_BR.po | 31 ++++++- po/pt_PT.po | 30 ++++++- po/ro.po | 26 +++++- po/ru.po | 84 ++++++++++++------ po/sk.po | 26 +++++- po/sr.po | 30 ++++++- po/tr.po | 26 +++++- po/uk.po | 28 +++++- po/zh_CN.po | 86 +++++++++++++------ po/zh_TW.po | 26 +++++- 29 files changed, 1197 insertions(+), 466 deletions(-) diff --git a/po/ar.po b/po/ar.po index 02a03770..02de226f 100644 --- a/po/ar.po +++ b/po/ar.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" "ar/)\n" @@ -552,6 +552,20 @@ msgstr "سجّل" msgid "Use this form to create an account." msgstr "استخدم هذه الاستمارة لإنشاء حساب." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "مستخدم موثوق" @@ -608,6 +622,9 @@ msgstr "يمكنه احتواء نقطة واحدة، أو شرطة سفليّة msgid "The email address is invalid." msgstr "عنوان البريد الإلكترونيّ غير صالح." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "بصمة مفتاح PGP غير صالحة." @@ -953,6 +970,11 @@ msgstr "" msgid "required" msgstr "مطلوب" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "مستخدم عاديّ" diff --git a/po/ast.po b/po/ast.po index 760aec42..0b1ca085 100644 --- a/po/ast.po +++ b/po/ast.po @@ -3,15 +3,15 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# enolp , 2014-2015 +# enolp , 2014-2015,2017 # Ḷḷumex03 , 2014 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2014-2015 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2014-2015 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" "ast/)\n" @@ -89,7 +89,7 @@ msgid "Proposal cannot be empty." msgstr "La propuesta nun pue tar balera" msgid "New proposal submitted." -msgstr "" +msgstr "Unvióse la propuesta nueva." msgid "Submit a proposal to vote on." msgstr "" @@ -269,16 +269,16 @@ msgid "Package Search" msgstr "Gueta de paquetes" msgid "Adopt" -msgstr "" +msgstr "Adoptar" msgid "Vote" -msgstr "" +msgstr "Votar" msgid "UnVote" -msgstr "" +msgstr "Retirar votu" msgid "Notify" -msgstr "" +msgstr "Avisar" msgid "UnNotify" msgstr "" @@ -537,6 +537,20 @@ msgstr "Rexistrase" msgid "Use this form to create an account." msgstr "Usa esti formulariu pa crear una cuenta." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "" @@ -591,6 +605,9 @@ msgstr "" msgid "The email address is invalid." msgstr "La direición de corréu nun ye válida." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "La buelga de la clave PGP nun ye válida." @@ -935,6 +952,11 @@ msgstr "" msgid "required" msgstr "riquíu" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Usuariu normal" diff --git a/po/ca.po b/po/ca.po index c3c868fd..ef2de9b6 100644 --- a/po/ca.po +++ b/po/ca.po @@ -3,15 +3,15 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# Adolfo Jayme-Barrientos, 2014 +# Adolfo Jayme Barrientos, 2014 # Hector Mtz-Seara , 2011,2013 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" "ca/)\n" @@ -535,6 +535,20 @@ msgstr "Registrar-se" msgid "Use this form to create an account." msgstr "Utilitzeu aquest formulari per a crear un compte." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Usuari de Confiança" @@ -591,6 +605,9 @@ msgstr "Només pot contenir un punt, guió o guió baix." msgid "The email address is invalid." msgstr "L'adreça del correu-e no és vàlida." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "L'empremta de la clau PGP no és vàlida." @@ -940,6 +957,11 @@ msgstr "" msgid "required" msgstr "requerit" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Usuari normal" diff --git a/po/cs.po b/po/cs.po index 51e6e2c0..a8749526 100644 --- a/po/cs.po +++ b/po/cs.po @@ -3,16 +3,18 @@ # This file is distributed under the same license as the AUR package. # # Translators: +# Daniel Milde , 2017 # Jaroslav Lichtblau , 2015-2016 # Jaroslav Lichtblau , 2014 +# Jiří Vírava , 2017 # Lukas Fleischer , 2011 # Pavel Ševeček , 2014 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" "Language: cs\n" @@ -28,18 +30,20 @@ msgid "Sorry, the page you've requested does not exist." msgstr "Omlouváme se, požadovaná stránka neexistuje." msgid "Note" -msgstr "" +msgstr "Poznámka" msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +"URL adresy pro klonování Git repozitáře nejsou určeny k otevření v " +"prohlížeči." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Pro naklonování Git repozitáře %s, spusťte %s." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Klikněte %s zde %s pro návrat na %s stránku detailu." msgid "Service Unavailable" msgstr "Služba nedostupná" @@ -104,13 +108,13 @@ msgid "Type" msgstr "Typ" msgid "Addition of a TU" -msgstr "" +msgstr "Přidání TU" msgid "Removal of a TU" -msgstr "" +msgstr "Odebrání TU" msgid "Removal of a TU (undeclared inactivity)" -msgstr "" +msgstr "Odebrání TU (nehlášená neaktivita)" msgid "Amendment of Bylaws" msgstr "Úprava směrnic" @@ -122,34 +126,34 @@ msgid "Submit" msgstr "Odeslat" msgid "Manage Co-maintainers" -msgstr "" +msgstr "Správa spolu-správců" msgid "Edit comment" msgstr "Upravit komentář" msgid "Dashboard" -msgstr "" +msgstr "Dashboard" msgid "Home" msgstr "Domů" msgid "My Flagged Packages" -msgstr "" +msgstr "Moje označené balíčky" msgid "My Requests" -msgstr "" +msgstr "Moje požadavky" msgid "My Packages" msgstr "Moje balíčky" msgid "Search for packages I maintain" -msgstr "" +msgstr "Hledat balíčky, které spravuji" msgid "Co-Maintained Packages" -msgstr "" +msgstr "Spolu-spravované balíčky" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Hledat balíčky, které spolu-spravuji" #, php-format msgid "" @@ -178,9 +182,11 @@ msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +"Obsah balíčků AUR je vytvořen uživateli. Jakékoli použití poskytnutých " +"souborů je na vlastní nebezpečí." msgid "Learn more..." -msgstr "" +msgstr "Další informace ..." msgid "Support" msgstr "Podpora" @@ -195,7 +201,7 @@ msgid "" msgstr "" msgid "Orphan Request" -msgstr "" +msgstr "Žádost o osiření" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " @@ -203,7 +209,7 @@ msgid "" msgstr "" msgid "Deletion Request" -msgstr "" +msgstr "Žádost o smazání" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " @@ -212,7 +218,7 @@ msgid "" msgstr "" msgid "Merge Request" -msgstr "" +msgstr "Žádost o sloučení" msgid "" "Request a package to be merged into another one. Can be used when a package " @@ -226,7 +232,7 @@ msgid "" msgstr "" msgid "Submitting Packages" -msgstr "" +msgstr "Odeslání balíčků" #, php-format msgid "" @@ -236,7 +242,7 @@ msgid "" msgstr "" msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "Pro AUR se používají následující otisky SSH" msgid "Discussion" msgstr "Diskuze" @@ -281,7 +287,7 @@ msgid "UnFlag" msgstr "Odznačit" msgid "Login" -msgstr "Přihlašovací jméno" +msgstr "Přihlásit" #, php-format msgid "Logged-in as: %s" @@ -294,7 +300,7 @@ msgid "Enter login credentials" msgstr "Vložit přihlašovací údaje" msgid "User name or email address" -msgstr "" +msgstr "Uživatelské jméno nebo e-mailová adresa" msgid "Password" msgstr "Heslo" @@ -309,6 +315,8 @@ msgstr "Zapomenuté heslo" msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +"Přihlášení přes HTTP je zakázáno. . Pokud se chcete přihlásit, prosíme " +"%spřejděte na HTTPs%s ." msgid "Search Criteria" msgstr "Vyhledávací kritéria" @@ -336,7 +344,7 @@ msgid "Password Reset" msgstr "Reset hesla" msgid "Check your e-mail for the confirmation link." -msgstr "" +msgstr "Pro potvrzovací odkaz zkontrolujte e-mail." msgid "Your password has been reset successfully." msgstr "Heslo bylo úspěšně resetováno." @@ -373,7 +381,7 @@ msgid "" msgstr "" msgid "Cannot find package to merge votes and comments into." -msgstr "" +msgstr "Nelze najít balíček pro sloučení hlasů a komentářů." msgid "Cannot merge a package base with itself." msgstr "" @@ -473,14 +481,14 @@ msgid "Package Merging" msgstr "Spojení balíčku" msgid "Merge Package" -msgstr "" +msgstr "Sloučit balíček" #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" msgid "The following packages will be deleted: " -msgstr "" +msgstr "Následující balíkčy budou smazány:" msgid "Once the package has been merged it cannot be reversed. " msgstr "" @@ -489,7 +497,7 @@ msgid "Enter the package name you wish to merge the package into. " msgstr "" msgid "Merge into:" -msgstr "" +msgstr "Sloučit do:" msgid "Confirm package merge" msgstr "Potvrdit spojení balíčku" @@ -501,7 +509,7 @@ msgid "Only Trusted Users and Developers can merge packages." msgstr "" msgid "Submit Request" -msgstr "" +msgstr "Odeslat požadavek" msgid "Close Request" msgstr "Uzavřít požadavek" @@ -527,6 +535,20 @@ msgstr "Registrovat" msgid "Use this form to create an account." msgstr "Použíte tento formulář k založení účtu." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Důvěryhodný uživatel" @@ -561,6 +583,8 @@ msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +"Registrace účtu byla pro vaši IP adresu zakázána, pravděpodobně kvůli " +"trvalým spamovým útokům. Omluvám se za nepříjemnost." msgid "Missing User ID" msgstr "Chybějící Uživateské ID" @@ -581,59 +605,64 @@ msgstr "Může obsahovat pouze jednu tečku, podtržítko nebo spojovník." msgid "The email address is invalid." msgstr "Vadná emailová adresa." -msgid "The PGP key fingerprint is invalid." +msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +msgid "The PGP key fingerprint is invalid." +msgstr "PGP otisk je neplatný." + msgid "The SSH public key is invalid." -msgstr "" +msgstr "Neplatný veřejný klíč SSH." msgid "Cannot increase account permissions." -msgstr "" +msgstr "Nelze zvýšit oprávnění účtu." msgid "Language is not currently supported." msgstr "Jazyk není momentálné podporován." msgid "Timezone is not currently supported." -msgstr "" +msgstr "Časové pásmo momentálně není podporováno." #, php-format msgid "The username, %s%s%s, is already in use." -msgstr "" +msgstr "Uživatelské jméno, %s%s%s, je již používáno." #, php-format msgid "The address, %s%s%s, is already in use." -msgstr "" +msgstr "Adresa, %s%s%s, je již použita." #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "Veřejný SSH klíč, %s%s%s, je již použit." #, php-format msgid "Error trying to create account, %s%s%s." -msgstr "" +msgstr "Chyba při vytváření účtu, %s%s%s." #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "" +msgstr "Účet, %s%s%s, byl úspěšně vytvořen." msgid "A password reset key has been sent to your e-mail address." -msgstr "" +msgstr "Na vaši e-mailovou adresu byl odeslán klíč pro obnovení hesla." msgid "Click on the Login link above to use your account." -msgstr "" +msgstr "Kliknutím na odkaz Přihlásit se výše použijte svůj účet." #, php-format msgid "No changes were made to the account, %s%s%s." -msgstr "" +msgstr "Na účtu nebyly provedeny žádné změny,, %s%s%s." #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "" +msgstr "Účet, %s%s%s, byl úspěšně změněn." msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +"Přihlašovací formulář je momentálně pro vaši IP adresu zakázán, " +"pravděpodobně kvůli trvalým spamovým útokům. Omluvám se za nepříjemnost." msgid "Account suspended" msgstr "Účet pozastaven" @@ -644,34 +673,37 @@ msgid "" "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." msgstr "" +"Vaše heslo bylo resetováno. Pokud jste právě vytvořili nový účet, použijte " +"odkaz z potvrzovacího e-mailu a nastavte počáteční heslo. V opačném případě " +"požádejte o resetovací klíč na stránce %s Reset hesla %s ." msgid "Bad username or password." msgstr "Chybné uživatelské jméno nebo heslo." msgid "An error occurred trying to generate a user session." -msgstr "" +msgstr "Došlo k chybě při pokusu generovat uživatelskou relaci." msgid "Invalid e-mail and reset key combination." -msgstr "" +msgstr "Neplatná kombinace resetovacího klíče a e-mailu." msgid "None" msgstr "" #, php-format msgid "View account information for %s" -msgstr "" +msgstr "Zobrazení informací o účtu pro %s" msgid "Package base ID or package base name missing." msgstr "" msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Nemáte oprávnění upravit tento komentář." msgid "Comment does not exist." -msgstr "" +msgstr "Komentář neexistuje." msgid "Comment cannot be empty." -msgstr "" +msgstr "Komentář nemůže být prázdný." msgid "Comment has been added." msgstr "Komentář byl přidán" @@ -684,19 +716,19 @@ msgid "Missing comment ID." msgstr "Chybějící ID komentáře." msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "Nelze připnout více než 5 komentářů." msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Nemáte oprávnění připnout tento komentář." msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "Nemáte oprávnění k odepnout tento komentář." msgid "Comment has been pinned." -msgstr "" +msgstr "Komentář byl připnut." msgid "Comment has been unpinned." -msgstr "" +msgstr "Zrušeno připnutí komentáře." msgid "Error retrieving package details." msgstr "Došlo k chybě při získávání detailů o balíčku." @@ -726,7 +758,7 @@ msgid "The selected packages have been unflagged." msgstr "Zvoleným bálíčkům bylo odebráno označení." msgid "You do not have permission to delete packages." -msgstr "" +msgstr "Nemáte oprávnění k odstranění balíčků." msgid "You did not select any packages to delete." msgstr "Nevybrali jste žádné balíčky ke smazání." @@ -779,10 +811,10 @@ msgid "You have been removed from the comment notification list for %s." msgstr "Byli jste odebrání ze seznamu upozornění ohledně %s." msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Nemáte oprávnění k obnovení tohoto komentáře." msgid "Comment has been undeleted." -msgstr "" +msgstr "Komentář byl obnoven." msgid "You are not allowed to delete this comment." msgstr "Nemáte oprávnění pro smazání tohoto komentáře." @@ -791,10 +823,10 @@ msgid "Comment has been deleted." msgstr "Komentář byl smazán." msgid "Comment has been edited." -msgstr "" +msgstr "Komentář byl upraven." msgid "You are not allowed to edit the keywords of this package base." -msgstr "" +msgstr "Nemáte oprávnění upravit klíčová slova tohoto balíčku." msgid "The package base keywords have been updated." msgstr "" @@ -804,17 +836,17 @@ msgstr "" #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Neplatné uživatelské jméno: %s" msgid "The package base co-maintainers have been updated." msgstr "" msgid "View packages details for" -msgstr "" +msgstr "Zobrazit podrobnosti o balíčcích pro" #, php-format msgid "requires %s" -msgstr "" +msgstr "vyžaduje %s" msgid "You must be logged in to file package requests." msgstr "" @@ -823,30 +855,30 @@ msgid "Invalid name: only lowercase letters are allowed." msgstr "Chybný název: jsou povolena pouze malá písmena." msgid "The comment field must not be empty." -msgstr "" +msgstr "Pole s komentáři nesmí být prázdné." msgid "Invalid request type." -msgstr "" +msgstr "Neplatný typ požadavku." msgid "Added request successfully." -msgstr "" +msgstr "Požadavek byl úspěšně přidán." msgid "Invalid reason." -msgstr "" +msgstr "Neplatný důvod." msgid "Only TUs and developers can close requests." msgstr "" msgid "Request closed successfully." -msgstr "" +msgstr "Požadavek byla úspěšně uzavřen." #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" +msgstr "Tento formulář můžete použít k trvalému odstranění účtu AUR %s." #, php-format msgid "%sWARNING%s: This action cannot be undone." -msgstr "" +msgstr "%sVAROVÁNÍ%s: Tuto akci nelze vrátit zpět." msgid "Confirm deletion" msgstr "Potvrdit smazání" @@ -864,7 +896,7 @@ msgid "Developer" msgstr "Vyvojář" msgid "Trusted User & Developer" -msgstr "" +msgstr "Důvěryhodný uživatel a vývojář" msgid "Email Address" msgstr "Emailová adresa" @@ -876,13 +908,13 @@ msgid "Real Name" msgstr "Skutečné jméno" msgid "Homepage" -msgstr "" +msgstr "Domovská stránka" msgid "IRC Nick" msgstr "IRC přezdívka" msgid "PGP Key Fingerprint" -msgstr "" +msgstr "Otisk klíče PGP" msgid "Status" msgstr "Status" @@ -894,7 +926,7 @@ msgid "Active" msgstr "Aktivní" msgid "Registration date:" -msgstr "" +msgstr "Datum registrace:" msgid "unknown" msgstr "neznámý" @@ -922,6 +954,11 @@ msgstr "" msgid "required" msgstr "vyžadováno" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Obyčejný uživatel" @@ -938,6 +975,8 @@ msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +"Ujistěte se, že jste správně zadali svou e-mailovou adresu, jinak budete " +"zablokováni." msgid "Hide Email Address" msgstr "Skrýt email" @@ -949,27 +988,29 @@ msgid "Language" msgstr "Jazyk" msgid "Timezone" -msgstr "" +msgstr "Časové pásmo" msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" +"Následující informace jsou požadovány pouze v případě, že chcete odeslat " +"balíčky do Arch User Repository." msgid "SSH Public Key" -msgstr "" +msgstr "Veřejný SSH klíč" msgid "Notification settings" -msgstr "" +msgstr "Nastavení upozornění" msgid "Notify of new comments" msgstr "Oznamovat nové komentáře" msgid "Notify of package updates" -msgstr "" +msgstr "Oznámení o aktualizacích balíčku" msgid "Notify of ownership changes" -msgstr "" +msgstr "Oznámit změnu vlastnictví" msgid "Update" msgstr "Aktualizovat" @@ -1029,7 +1070,7 @@ msgstr "" #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "Autorská práva %s 2004-%d vývojový tým aurweb." msgid " My Account" msgstr "Můj účet" @@ -1041,10 +1082,10 @@ msgid "View PKGBUILD" msgstr "Zobrazit PKGBUILD" msgid "View Changes" -msgstr "" +msgstr "Zobrazit změny" msgid "Download snapshot" -msgstr "" +msgstr "Stáhnout snímek" msgid "Search wiki" msgstr "Prohledat wiki" @@ -1069,7 +1110,7 @@ msgid "Disable notifications" msgstr "Vypnout oznámení" msgid "Enable notifications" -msgstr "" +msgstr "Zapnout oznámení" msgid "Manage Co-Maintainers" msgstr "" @@ -1091,7 +1132,7 @@ msgid "Git Clone URL" msgstr "" msgid "read-only" -msgstr "" +msgstr "jen pro čtení" msgid "Keywords" msgstr "Klíčová slova" @@ -1109,7 +1150,7 @@ msgid "Votes" msgstr "Hlasy" msgid "Popularity" -msgstr "" +msgstr "Popularita" msgid "First Submitted" msgstr "" @@ -1128,14 +1169,14 @@ msgid "View all comments" msgstr "Zobrazit všechny komentáře" msgid "Pinned Comments" -msgstr "" +msgstr "Připnuté komentáře" msgid "Latest Comments" msgstr "Nejnovější komentáře" #, php-format msgid "%s commented on %s" -msgstr "" +msgstr "%s přidal komentář %s" #, php-format msgid "Anonymous comment on %s" @@ -1151,11 +1192,11 @@ msgstr "" #, php-format msgid "edited on %s by %s" -msgstr "" +msgstr "upraveno %s upravil %s" #, php-format msgid "edited on %s" -msgstr "" +msgstr "upraveno %s" msgid "Undelete comment" msgstr "" @@ -1164,10 +1205,10 @@ msgid "Delete comment" msgstr "Smazat komentář" msgid "Pin comment" -msgstr "" +msgstr "Připnout komentář" msgid "Unpin comment" -msgstr "" +msgstr "Odepnout komentář" msgid "All comments" msgstr "Všechny komentáře" @@ -1242,10 +1283,10 @@ msgid "Deletion" msgstr "Smazání" msgid "Orphan" -msgstr "" +msgstr "Sirotek" msgid "Merge into" -msgstr "" +msgstr "Sloučit do" msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " @@ -1268,7 +1309,7 @@ msgid "" msgstr "" msgid "No requests matched your search criteria." -msgstr "" +msgstr "Žádné požadavky neodpovídaly vašim kritériím vyhledávání." #, php-format msgid "%d package request found." @@ -1356,7 +1397,7 @@ msgid "Voted" msgstr "Hlasováno" msgid "Last modified" -msgstr "" +msgstr "Naposledy změněno" msgid "Ascending" msgstr "Vzestupně" @@ -1409,6 +1450,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"Popularita je vypočtena jako součet všech hlasů, přičemž každý hlas je vážen " +"faktorem %.2f za den od jeho vytvoření.." msgid "Yes" msgstr "Ano" diff --git a/po/da.po b/po/da.po index 59de0846..181d8294 100644 --- a/po/da.po +++ b/po/da.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" "da/)\n" @@ -522,6 +522,20 @@ msgstr "Register" msgid "Use this form to create an account." msgstr "Brug denne formular til at oprette en konto." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Betroet bruger (TU)" @@ -576,6 +590,9 @@ msgstr "Kan kun indeholde ét punktum, én bundstreg eller én bindestreg." msgid "The email address is invalid." msgstr "E-mail adressen er ugyldig." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "" @@ -916,6 +933,11 @@ msgstr "" msgid "required" msgstr "påkrævet" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Normal bruger" diff --git a/po/de.po b/po/de.po index 1de9b15e..e46c5b3c 100644 --- a/po/de.po +++ b/po/de.po @@ -19,14 +19,14 @@ # Nuc1eoN , 2014 # Simon Schneider , 2011 # Stefan Auditor , 2017 -# Thomas_Do , 2013-2014 -# Thomas_Do , 2012-2013 +# Thomas_Do , 2013-2014 +# Thomas_Do , 2012-2013 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-26 19:30+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-30 12:23+0000\n" "Last-Translator: Stefan Auditor \n" "Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" "de/)\n" @@ -50,7 +50,7 @@ msgstr "Git clone URLs sind nicht dafür gedacht im Browser geöffnet zu werden. #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "Um das Git Repository von %s zu clonen, führe %s aus." +msgstr "Um das Git-Repository von %s zu clonen, führe %s aus." #, php-format msgid "Click %shere%s to return to the %s details page." @@ -63,7 +63,7 @@ msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" "Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir " -"werden gleich zurück sein ..." +"werden gleich zurück sein." msgid "Account" msgstr "Konto" @@ -94,7 +94,7 @@ msgid "Invalid token for user action." msgstr "Ungültiges Zeichen für eine Benutzer-Aktion." msgid "Username does not exist." -msgstr "Der Nutzername existiert nicht." +msgstr "Der Benutzername existiert nicht." #, php-format msgid "%s already has proposal running for them." @@ -140,7 +140,7 @@ msgid "Submit" msgstr "Abschicken" msgid "Manage Co-maintainers" -msgstr "Verwalte Ko-Maintainer" +msgstr "Verwalte Mit-Betreuer" msgid "Edit comment" msgstr "Kommentar bearbeiten" @@ -164,7 +164,7 @@ msgid "Search for packages I maintain" msgstr "Suche nach Paketen die ich betreue" msgid "Co-Maintained Packages" -msgstr "Ko-Maintainer Pakete" +msgstr "Mitbetreute Pakete" msgid "Search for packages I co-maintain" msgstr "Suche nach Paketen die ich mitbetreue" @@ -203,7 +203,7 @@ msgid "" "your own risk." msgstr "" "AUR Pakete sind von Benutzern erstellter Inhalt. Die Benutzung der " -"angebotenen Dateien erfolgt auf eingenes Risiko." +"angebotenen Dateien erfolgt auf eigenes Risiko." msgid "Learn more..." msgstr "Erfahre mehr ..." @@ -229,8 +229,8 @@ msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -"Anfrage eine Pakte abzugeben, z.B. wenn der Verwalten nicht aktiv ist und " -"das Paket vor einer ganzen Weile als veraltet makiert wurde." +"Anfrage eine Pakte abzugeben, z.B. wenn der Betreuer nicht aktiv ist und das " +"Paket vor einer ganzen Weile als veraltet makiert wurde." msgid "Deletion Request" msgstr "Löschanfrage" @@ -241,9 +241,9 @@ msgid "" "the package maintainer and file orphan request if necessary." msgstr "" "Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte " -"benutzen Sie diese nicht, wenn das Paket kaputt ist und leich repariert " -"werden kann. Sondern kontaktieren Sie den Paketverwalter und reichen Sie " -"eine Verwaisungsanfrage ein wenn nötig." +"benutze diese nicht, wenn das Paket kaputt ist und leich repariert werden " +"kann. Sondern kontaktiere den Betreuer und reiche eine Verwaisungsanfrage " +"ein, wenn nötig." msgid "Merge Request" msgstr "Zusammenführungsanfrage" @@ -260,9 +260,8 @@ msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" -"Wenn Sie eine Anfrage diskutieren wollen, können sie die %saur-requests%s " -"Mailingliste benutzen. Jedoch benutzen Sie diese nicht um Anfragen " -"einzureichen." +"Wenn Du eine Anfrage diskutieren willst, kannst Du die %saur-requests%s " +"Mailingliste benutzen. Benutze diese jedoch nicht um Anfragen einzureichen." msgid "Submitting Packages" msgstr "Pakete einreichen" @@ -291,8 +290,8 @@ msgid "" msgstr "" "Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und " "vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für " -"Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface nutzen Sie " -"die %saur-dev%s Mailingliste." +"Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface benutze die " +"%saur-dev%s Mailingliste." msgid "Bug Reporting" msgstr "Fehler melden" @@ -307,7 +306,7 @@ msgstr "" "Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-" "Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um " "Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte direkt " -"an den zuständigen Maintainer, oder hinterlaß einen Kommentar auf der " +"an den zuständigen Betreuer, oder hinterlasse einen Kommentar auf der " "entsprechenden Seite des Paketes." msgid "Package Search" @@ -479,7 +478,7 @@ msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" -"Benutzen Sie dieses Formular um die Paketbasis %s%s%s, welche die folgenden " +"Benutze dieses Formular um die Paketbasis %s%s%s, welche die folgenden " "Pakete enhält, abzugeben:" #, php-format @@ -487,8 +486,8 @@ msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" -"Durch das markieren des Kontrollkästchen bestätigen Sie, dass Sie das Pakte " -"abegen und den Besitz an %s%s%s übergeben wollen." +"Durch das markieren des Kontrollkästchen bestätigtst Du, dass Du das Paket " +"abegen und den Besitz an %s%s%s übergeben willst." msgid "" "By selecting the checkbox, you confirm that you want to disown the package." @@ -608,6 +607,21 @@ msgstr "Registrieren" msgid "Use this form to create an account." msgstr "Benutze dieses Formular, um ein Konto zu erstellen." +msgid "Terms of Service" +msgstr "Nutzungsbedingungen" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" +"Die folgenden Dokumente wurden aktualisiert, bitte aufmerksam überprüfen:" + +#, php-format +msgid "revision %d" +msgstr "Revision %d" + +msgid "I accept the terms and conditions above." +msgstr "Ich akzeptiere die obigen Nutzungsbedingungen." + msgid "Trusted User" msgstr "Vertrauenswürdiger Benutzer (TU)" @@ -651,7 +665,7 @@ msgid "Missing User ID" msgstr "Benutzer-ID fehlt" msgid "The username is invalid." -msgstr "Der Nutzername ist ungültig." +msgstr "Der Benutzername ist ungültig." #, php-format msgid "It must be between %s and %s characters long" @@ -666,6 +680,10 @@ msgstr "Kann nur einen Punkt, Unter- oder Bindestrich enthalten." msgid "The email address is invalid." msgstr "Die E-Mail-Adresse ist ungültig." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" +"Diese Adresse ist ungültig, bitte eine vollständige HTTP(S) URL angeben." + msgid "The PGP key fingerprint is invalid." msgstr "Der PGP-Schlüssel-Fingerabdruck ist ungültig." @@ -683,7 +701,7 @@ msgstr "Diese Zeitzone wird momentan noch nicht unterstützt." #, php-format msgid "The username, %s%s%s, is already in use." -msgstr "Der Nutzername %s%s%s ist bereits vergeben." +msgstr "Der Benutzername %s%s%s ist bereits vergeben." #, php-format msgid "The address, %s%s%s, is already in use." @@ -738,7 +756,7 @@ msgstr "" "%sPasswort zurücksetzen%s Seite an." msgid "Bad username or password." -msgstr "Falscher Nutzername oder falsches Passwort." +msgstr "Falscher Benutzername oder falsches Passwort." msgid "An error occurred trying to generate a user session." msgstr "Es geschah ein Fehler beim Versuch eine Nutzersitzung zu erstellen." @@ -893,14 +911,14 @@ msgid "The package base keywords have been updated." msgstr "Die Schlagwörter der Paketbasis wurden aktualisiert." msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Du darfst die Mitbetreuer für diese Paketbasis nicht verwalten." +msgstr "Du darfst die Mit-Betreuer für diese Paketbasis nicht verwalten." #, php-format msgid "Invalid user name: %s" -msgstr "Ungültiger Nutzername: %s" +msgstr "Ungültiger Benutzername: %s" msgid "The package base co-maintainers have been updated." -msgstr "Die Mitbetreuer der Paketbasis wurden aktualisiert." +msgstr "Die Mit-Betreuer der Paketbasis wurden aktualisiert." msgid "View packages details for" msgstr "Paket-Informationen aufrufen für" @@ -947,7 +965,7 @@ msgid "Confirm deletion" msgstr "Bestätige das Entfernen" msgid "Username" -msgstr "Nutzername" +msgstr "Benutzername" msgid "Account Type" msgstr "Konto-Typ" @@ -1004,7 +1022,7 @@ msgid "View this user's packages" msgstr "Alle Pakete dieses Benutzers anzeigen" msgid "Edit this user's account" -msgstr "Konto dieses Nutzers bearbeiten" +msgstr "Konto dieses Benutzers bearbeiten" #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1018,6 +1036,13 @@ msgstr "Klicke %shere%s für Benutzerdetails." msgid "required" msgstr "Notwendig" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" +"Der Benutzername ist der Name, der für die Anmeldung benutzt wird. Er ist " +"öffentlich sichtbar, auch wenn das Konto inaktiv ist." + msgid "Normal user" msgstr "Normaler Benutzer" @@ -1105,7 +1130,7 @@ msgstr "Keine weiteren Ergebnisse." msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" -"Benutze dieses Formular um Mitbetreuer für %s%s%s hinzuzufügen (ein " +"Benutze dieses Formular um Mit-Betreuer für %s%s%s hinzuzufügen (ein " "Benutzername pro Zeile):" msgid "Users" @@ -1120,7 +1145,7 @@ msgstr "Markiert als \"veraltet\" Kommentar: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "%s%s%s markiert %s%s%s als \"veraltet\" am %s%s%s auf Grund von:" +msgstr "%s%s%s markiert %s%s%s als veraltet am %s%s%s aufgrund von:" #, php-format msgid "%s%s%s is not flagged out-of-date." @@ -1174,7 +1199,7 @@ msgid "Enable notifications" msgstr "Benachritigungen aktivieren" msgid "Manage Co-Maintainers" -msgstr "Verwalte Ko-Maintainer" +msgstr "Verwalte Mit-Betreuer" #, php-format msgid "%d pending request" @@ -1382,10 +1407,10 @@ msgid "" "the maintainer is MIA and you already tried to contact the maintainer " "previously." msgstr "" -"Durch das absenden eines Verwaisanfrage wird ein vertrauenswürdiger Benutzer " -"gefragt die Paketbasis zu enteignen. Bitte mache das nur, wenn das Paket " -"Aktionen vom Betreuer braucht, der Betreuer nicht reagiert und du ihn vorher " -"bereits versucht hast zu kontaktieren." +"Durch das absenden einer Verwaisanfrage wird ein vertrauenswürdiger Benutzer " +"gebeten die Paketbasis zu enteignen. Bitte tue das nur, wenn das Paket " +"Aufmerksamkeit des Betreuers benötigt, der Betreuer nicht reagiert und Du " +"vorher bereits versucht hast ihn zu kontaktieren." msgid "No requests matched your search criteria." msgstr "Die Suchkriterien erzielten keine Treffer in Anfragen." @@ -1452,10 +1477,10 @@ msgid "Exact Package Base" msgstr "Exakte Paketbasis" msgid "Co-maintainer" -msgstr "Ko-Maintainer" +msgstr "Mit-Betreuer" msgid "Maintainer, Co-maintainer" -msgstr "Betreuer, Ko-Maintainer" +msgstr "Betreuer, Mit-Betreuer" msgid "All" msgstr "Alle" diff --git a/po/el.po b/po/el.po index b4d7902c..aac17bb2 100644 --- a/po/el.po +++ b/po/el.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" "Language: el\n" @@ -543,6 +543,20 @@ msgstr "Εγγραφείτε" msgid "Use this form to create an account." msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να δημιουργήσετε λογαριασμό." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Trusted User" @@ -599,6 +613,9 @@ msgstr "Μπορεί να περιλαμβάνει μόνο μία τελεία, msgid "The email address is invalid." msgstr "Αυτή η διεύθυνση email δεν είναι έγκυρη." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "Το fingerprint του PGP κλειδιού δεν είναι έγκυρο." @@ -952,6 +969,11 @@ msgstr "" msgid "required" msgstr "απαιτούμενο" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Απλός χρήστης" diff --git a/po/es.po b/po/es.po index ce9cdf99..cabcc007 100644 --- a/po/es.po +++ b/po/es.po @@ -3,24 +3,25 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# Adolfo Jayme-Barrientos, 2015 +# Adolfo Jayme Barrientos, 2015 # Angel Velasquez , 2011 # juantascon , 2011 # Lukas Fleischer , 2011 # neiko , 2011 # Nicolás de la Torre , 2012 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2012 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2013-2016 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016-2017 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2012 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016-2017 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2013-2016 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016-2017 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-03-01 05:08+0000\n" -"Last-Translator: Pablo Roberto “Jristz” Lezaeta Reyes \n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-29 14:11+0000\n" +"Last-Translator: Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] \n" "Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" "es/)\n" "Language: es\n" @@ -221,7 +222,7 @@ msgid "" "the package has been flagged out-of-date for a long time." msgstr "" "Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está " -"inactivo y el paquete se ha marcado como desactualizado por un largo tiempo." +"inactivo y el paquete se ha marcado como obsoleto por un largo tiempo." msgid "Deletion Request" msgstr "Solicitud de eliminación" @@ -502,7 +503,7 @@ msgid "Flag Comment" msgstr "Marcar comentario" msgid "Flag Package Out-Of-Date" -msgstr "Marcado como desactualizado" +msgstr "Marcado como obsoleto" #, php-format msgid "" @@ -510,7 +511,7 @@ msgid "" "of-date: " msgstr "" "Usa este formulario para marcar el paquete base %s%s%s y los siguientes " -"paquetes en el AUR como desactualizados:" +"paquetes en el AUR como obsoletos:" #, php-format msgid "" @@ -524,9 +525,8 @@ msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" -"Introduce el porqué del marcado del paquete como desactualizado, " -"peferiblentemente incluye un enlace al anuncio de la nueva versión o al " -"paquete comprimido." +"Introduce el porqué del marcado del paquete como obsoleto, preferiblemente " +"incluye un enlace al anuncio de la nueva versión o al paquete comprimido." msgid "Comments" msgstr "Comentarios" @@ -535,7 +535,7 @@ msgid "Flag" msgstr "Marcar" msgid "Only registered users can flag packages out-of-date." -msgstr "Solamente los usuario registrados pueden marcar como desactualizado." +msgstr "Solamente los usuario registrados pueden marcar como obsoleto." msgid "Package Merging" msgstr "Unión de paquetes" @@ -596,6 +596,21 @@ msgstr "Registro" msgid "Use this form to create an account." msgstr "Usa este formulario para crear una cuenta." +msgid "Terms of Service" +msgstr "Terminos y condiciones" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" +"Los siguientes documentos han sido actualizados. revísalos cuidadosamente:" + +#, php-format +msgid "revision %d" +msgstr "Revisión %d" + +msgid "I accept the terms and conditions above." +msgstr "Acepto los términos y condiciones anteriores." + msgid "Trusted User" msgstr "Usuario de confianza" @@ -653,6 +668,10 @@ msgstr "Solamente puede contener un punto, guion bajo o guion." msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" +"La página de inicio no es válida. Especifica la dirección HTTP(S) completa." + msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." @@ -796,7 +815,7 @@ msgstr "" "escribe un comentario." msgid "The selected packages have been flagged out-of-date." -msgstr "Los paquetes seleccionados han sido marcados como desactualizados." +msgstr "Los paquetes seleccionados han sido marcados como obsoletos." msgid "You must be logged in before you can unflag packages." msgstr "Debes autentificarte antes de poder desmarcar paquetes." @@ -1009,6 +1028,13 @@ msgstr "Haz clic %saquí%s para ver los detalles del usuario." msgid "required" msgstr "obligatorio" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" +"Tu nombre de usuario es el nombre que usarás para iniciar sesión. Es visible " +"para el público en general, incluso si tu cuenta no está activa." + msgid "Normal user" msgstr "Usuario normal" @@ -1025,7 +1051,7 @@ msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -"Asegúrate de escribir tu dirección de correc correctamente o estarás " +"Asegúrate de escribir tu dirección de correo correctamente o terminarás " "bloqueado." msgid "Hide Email Address" @@ -1108,17 +1134,16 @@ msgstr "Guardar" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "Marcar comentario como desactualizado: %s" +msgstr "Marcar comentario como obsoleto: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" -"%s%s%s se ha marcado %s%s%s como desactualizado %s%s%s por la siguiente " -"razón:" +"%s%s%s se ha marcado %s%s%s como obsoleto %s%s%s por la siguiente razón:" #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "%s%s%s no está marcado como desactualizado." +msgstr "%s%s%s no está marcado como obsoleto." msgid "Return to Details" msgstr "Regresar a detalles" @@ -1148,10 +1173,10 @@ msgstr "Buscar en la wiki" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "Marcado como desactualizado (%s)" +msgstr "Marcado como obsoleto (%s)" msgid "Flag package out-of-date" -msgstr "Marcar paquete como desactualizado" +msgstr "Marcar paquete como obsoleto" msgid "Unflag package" msgstr "Desmarcar paquete" @@ -1533,7 +1558,7 @@ msgid "Actions" msgstr "Acciones" msgid "Unflag Out-of-date" -msgstr "Marcar como actualizado" +msgstr "Desmarcar como obsoleto" msgid "Adopt Packages" msgstr "Adoptar paquetes" diff --git a/po/es_419.po b/po/es_419.po index fc845de0..23953197 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -8,17 +8,18 @@ # Lukas Fleischer , 2011 # neiko , 2011 # Nicolás de la Torre , 2012 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2012,2015-2016 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016-2017 -# Pablo Roberto “Jristz” Lezaeta Reyes , 2016 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016-2017 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2012,2015-2016 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016-2017 +# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-03-01 05:08+0000\n" -"Last-Translator: Pablo Roberto “Jristz” Lezaeta Reyes \n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-29 14:11+0000\n" +"Last-Translator: Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] \n" "Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" "aur/language/es_419/)\n" "Language: es_419\n" @@ -592,6 +593,22 @@ msgstr "Registro" msgid "Use this form to create an account." msgstr "Use este formulario para crear una cuenta." +msgid "Terms of Service" +msgstr "Terminos y condiciones" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" +"Los siguientes documentos han sido actualizados. Por favor revíselos " +"cuidadosamente:" + +#, php-format +msgid "revision %d" +msgstr "Revisión %d" + +msgid "I accept the terms and conditions above." +msgstr "Acepto las Terminos y condiciones anteriores." + msgid "Trusted User" msgstr "Usuario de Confianza" @@ -649,6 +666,10 @@ msgstr "Solo puede contener un punto, guion bajo o guion." msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" +"La página de inicio no es válida. Especifique la URL en HTTP(S) completa." + msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." @@ -1002,6 +1023,13 @@ msgstr "Haga clic %saquí%s para ver los detalles del usuario." msgid "required" msgstr "obligatorio" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" +"Su nombre de usuario es el nombre que usará para iniciar sesión. Es visible " +"al público en general, incluso si su cuenta está inactiva." + msgid "Normal user" msgstr "Usuario normal" @@ -1018,7 +1046,7 @@ msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" -"Asegúrese de escribir su correo correctamente o de lo contrario terminará " +"Asegúrese de escribir su correo correctamente o de lo contrario quedará " "bloqueado." msgid "Hide Email Address" @@ -1525,7 +1553,7 @@ msgid "Actions" msgstr "Acciones" msgid "Unflag Out-of-date" -msgstr "Marcar como actualizado" +msgstr "Desmarcar como actualizado" msgid "Adopt Packages" msgstr "Adoptar paquetes" diff --git a/po/fi.po b/po/fi.po index 86601c0f..bd77b538 100644 --- a/po/fi.po +++ b/po/fi.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" "fi/)\n" @@ -572,6 +572,20 @@ msgstr "Rekisteröidy" msgid "Use this form to create an account." msgstr "Käytä tätä lomaketta uuden käyttäjätilin luomiseen." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Luotettu käyttäjä (TU)" @@ -628,6 +642,9 @@ msgstr "Voi sisältää vain yhden väliviivan, alaviivan tai pisteen." msgid "The email address is invalid." msgstr "Sähköpostiosoite ei ole kelvollinen." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "PGP-avaimen sormenjälki ei ole kelvollinen." @@ -970,6 +987,11 @@ msgstr "" msgid "required" msgstr "vaaditaan" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Tavallinen käyttäjä" diff --git a/po/fr.po b/po/fr.po index 80094a03..eb22f19c 100644 --- a/po/fr.po +++ b/po/fr.po @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-28 19:55+0000\n" -"Last-Translator: Xorg \n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" "fr/)\n" "Language: fr\n" @@ -601,6 +601,20 @@ msgstr "S’inscrire" msgid "Use this form to create an account." msgstr "Utilisez ce formulaire pour créer un compte." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Utilisateur de confiance (TU)" @@ -657,6 +671,9 @@ msgstr "ne peut contenir qu'un seul point, tiret bas ou virgule," msgid "The email address is invalid." msgstr "L'adresse email n'est pas valide." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "L’empreinte de clé PGP est invalide." @@ -1020,6 +1037,11 @@ msgstr "Cliquer %sici%s pour obtenir les détails de l'utilisateur." msgid "required" msgstr "requis" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Utilisateur normal" diff --git a/po/he.po b/po/he.po index 2cf535a1..8f6c2493 100644 --- a/po/he.po +++ b/po/he.po @@ -5,13 +5,13 @@ # Translators: # GenghisKhan , 2016 # Lukas Fleischer , 2011 -# Yaron Shahrabani , 2016 +# Yaron Shahrabani , 2016-2017 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" "he/)\n" @@ -31,15 +31,15 @@ msgid "Note" msgstr "הערה" msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "כתובות שיבוט של Git לא אמורות להיפתח בדפדפן." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "כדי לשבט את מאגר ה־Git של %s, יש להפעיל את %s." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "יש ללחוץ %sכאן%s כדי לחזור אל הפרטים על %s." msgid "Service Unavailable" msgstr "השירות אינו זמין" @@ -113,7 +113,7 @@ msgid "Removal of a TU (undeclared inactivity)" msgstr "הסרת משתמש מהימן (חוסר פעילות בלתי מוצהרת)" msgid "Amendment of Bylaws" -msgstr "" +msgstr "תיקון חוקי עזר" msgid "Proposal" msgstr "הצעה" @@ -128,28 +128,28 @@ msgid "Edit comment" msgstr "עריכת תגובה" msgid "Dashboard" -msgstr "" +msgstr "לוח בקרה" msgid "Home" msgstr "בית" msgid "My Flagged Packages" -msgstr "" +msgstr "החבילות המסומנות שלי" msgid "My Requests" -msgstr "" +msgstr "הבקשות שלי" msgid "My Packages" msgstr "החבילות שלי" msgid "Search for packages I maintain" -msgstr "" +msgstr "חיפוש אחר חבילות בתחזוקה" msgid "Co-Maintained Packages" -msgstr "" +msgstr "חבילות בתחזוקת משנה" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "חיפוש אחר חבילה שאני מתחזק המשנה שלה" #, php-format msgid "" @@ -201,7 +201,7 @@ msgstr "" "החבילה:" msgid "Orphan Request" -msgstr "בקשה יתומה" +msgstr "בקשת יתומה" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " @@ -218,6 +218,9 @@ msgid "" "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +"ניתן לבקש הסרת חבילה ממאגר המשתמשים של ארץ׳. אין להשתמש בזה אם יש תקלה " +"בחבילה וניתן לתקן אותה בקלות. במקום זאת, יש ליצור קשר עם מתחזק החבילה ולהגיש " +"בקשת יתומה אם יש צורך." msgid "Merge Request" msgstr "בקשת מיזוג" @@ -226,12 +229,16 @@ msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +"הגשת בקשה למיזוג חבילה אחת לתוך חבילה אחרת. ניתן להשתמש כאשר צריך לשנות שם " +"של חבילה או להחליף אותה בחבילה מפוצלת." #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +"כדי לדון בבקשה, ניתן להשתמש בקבוצת הדיונים %saur-requests%s. עם זאת, נא לא " +"להשתמש ברשימה הזאת כדי להגיש בקשות." msgid "Submitting Packages" msgstr "שליחת חבילות" @@ -257,6 +264,9 @@ msgid "" "structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +"הדיון הכללי על מאגר המשתמשים של ארץ׳ (AUR) ומבנה המשתמשים המהימנים מתנהל " +"ברשימה %saur-general%s. לדיון בנוגע לפיתוח של המנשק של AUR, יש להשתמש ברשימה " +"%saur-dev%s." msgid "Bug Reporting" msgstr "דיווח על באגים" @@ -268,6 +278,10 @@ msgid "" "%sonly%s. To report packaging bugs contact the package maintainer or leave a " "comment on the appropriate package page." msgstr "" +"אם נתקלת בתקלה במנשק הדפדפן של AUR, נא להגיש דיווח על תקלה ב%sמערכת ניהול " +"התקלות%s שלנו. יש להשתמש במערכת ניהול התקלות כדי לדווח על תקלות במנשק הדפדפן " +"%sבלבד%s. כדי לדווח על תקלות עם אריזה יש ליצור קשר עם מתחזק החבילה או להשאיר " +"הערה בעמוד החבילה בהתאם." msgid "Package Search" msgstr "חיפוש חבילות" @@ -375,7 +389,7 @@ msgid "Enter your e-mail address:" msgstr "נא להזין את כתובת הדוא״ל שלך:" msgid "Package Bases" -msgstr "" +msgstr "בסיסי חבילות" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -403,6 +417,7 @@ msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +"ניתן להשתמש בטופס זה כדי למחוק את בסיס החבילה %s%s%s ואת החבילות הבאות מ־AUR:" msgid "Deletion of a package is permanent. " msgstr "מחיקת חבילה היא לצמיתות." @@ -427,6 +442,8 @@ msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" +"ניתן להשתמש בטופס זה כדי לשלול את הבעלות על בסיס החבילה %s%s%s שכוללת את " +"החבילות הבאות:" #, php-format msgid "" @@ -460,12 +477,15 @@ msgid "" "Use this form to flag the package base %s%s%s and the following packages out-" "of-date: " msgstr "" +"יש להשתמש בטופס זה כדי לסמן את בסיס החבילה %s%s%s ואת החבילות הבאות לבלתי " +"עדכניות:" #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +"נא %sלא%s להשתמש בטופס הזה כדי לדווח על תקלות. יש להשתמש בהערות החבילה במקום." msgid "" "Enter details on why the package is out-of-date below, preferably including " @@ -491,7 +511,7 @@ msgstr "מיזוג חבילה" #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" +msgstr "ניתן להשתמש בטופס זה כדי למזג את בסיס החבילה %s%s%s לתוך חבילה אחרת." msgid "The following packages will be deleted: " msgstr "החבילות הבאות תימחקנה:" @@ -541,8 +561,22 @@ msgstr "הרשמה" msgid "Use this form to create an account." msgstr "ניתן להשתמש בטופס זה על מנת ליצור חשבון." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" -msgstr "משתמש אמין" +msgstr "משתמש מהימן" msgid "Could not retrieve proposal details." msgstr "לא ניתן לקבל נתוני הצעה." @@ -575,6 +609,8 @@ msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +"הרשמה לחשבון הושבתה לכתובת ה־IP שלך עקב מתקפות זבל מתמשכות. אנו מתנצלים על " +"אי הנוחות." msgid "Missing User ID" msgstr "מס׳ הזיהוי של המשתמש חסר" @@ -595,6 +631,9 @@ msgstr "יכול הכיל רק נקודה אחת, קו תחתון או מקף." msgid "The email address is invalid." msgstr "כתובת הדוא״ל שהוזנה אינה תקינה." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "טביעת האצבע מסוג PGP שגויה." @@ -605,10 +644,10 @@ msgid "Cannot increase account permissions." msgstr "לא ניתן להגדיל את הרשאות החשבון." msgid "Language is not currently supported." -msgstr "שפה כרגע לא נתמכת." +msgstr "השפה אינה נתמכת כרגע." msgid "Timezone is not currently supported." -msgstr "" +msgstr "אין תמיכה באזור זמן נכון לעכשיו." #, php-format msgid "The username, %s%s%s, is already in use." @@ -660,6 +699,9 @@ msgid "" "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." msgstr "" +"הססמה שלך עברה איפוס. אם הרגע יצרת חשבון חדש, נא להשתמש בקישור מהודעת האימות " +"כדי להגדיר ססמה ראשונית. בכל מצב אחר, נא לבקר מפתח איפוס בעמוד %sאיפוס ססמה" +"%s." msgid "Bad username or password." msgstr "שם המשתמש או הססמה שגויים." @@ -678,7 +720,7 @@ msgid "View account information for %s" msgstr "הצגת פרטי החשבון %s" msgid "Package base ID or package base name missing." -msgstr "" +msgstr "מזהה בסיס החבילה או שם בסיס החבילה חסר." msgid "You are not allowed to edit this comment." msgstr "אין לך הרשאה לערוך את התגובה הזו." @@ -809,10 +851,10 @@ msgid "Comment has been edited." msgstr "התגובה נערכה." msgid "You are not allowed to edit the keywords of this package base." -msgstr "" +msgstr "אין לך הרשאה לערוך את מילות המפתח של בסיס חבילה זו." msgid "The package base keywords have been updated." -msgstr "" +msgstr "מילות המפתח של בסיס החבילה עודכנו." msgid "You are not allowed to manage co-maintainers of this package base." msgstr "אין לך הרשאה לנהל את מתחזקי המשנה לבסיס חבילה זה." @@ -829,7 +871,7 @@ msgstr "הצגת פרטי החבילה עבור" #, php-format msgid "requires %s" -msgstr "" +msgstr "דורשת את %s" msgid "You must be logged in to file package requests." msgstr "עליך להיכנס כדי להגיש בקשות חבילה." @@ -885,7 +927,7 @@ msgid "Email Address" msgstr "כתובת דוא״ל" msgid "hidden" -msgstr "" +msgstr "מוסתר" msgid "Real Name" msgstr "שם אמתי" @@ -909,7 +951,7 @@ msgid "Active" msgstr "פעיל" msgid "Registration date:" -msgstr "" +msgstr "תאריך ההרשמה:" msgid "unknown" msgstr "לא מוכר" @@ -932,11 +974,16 @@ msgstr "נא ללחוץ %sכאן%s אם רצונך הוא למחוק את החש #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "יש ללחוץ %sכאן%s לפרטים על המשתמש." msgid "required" msgstr "נדרש" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "משתמש רגיל" @@ -964,7 +1011,7 @@ msgid "Language" msgstr "שפה" msgid "Timezone" -msgstr "" +msgstr "אזור זמן" msgid "" "The following information is only required if you want to submit packages to " @@ -1030,7 +1077,7 @@ msgstr "שמירה" #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "הערת סימון כלא עדכנית: %s" #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" @@ -1067,10 +1114,10 @@ msgstr "חיפוש בוויקי" #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "סימון כלא עדכנית (%s)" msgid "Flag package out-of-date" -msgstr "" +msgstr "סימון החבילה כבלתי עדכנית" msgid "Unflag package" msgstr "ביטול סימון חבילה" @@ -1112,7 +1159,7 @@ msgid "Keywords" msgstr "מילות מפתח" msgid "Submitter" -msgstr "" +msgstr "מגיש" msgid "Maintainer" msgstr "מתחזק" @@ -1130,7 +1177,7 @@ msgid "First Submitted" msgstr "נשלחה לראשונה" msgid "Last Updated" -msgstr "עודכנה באחרונה" +msgstr "עדכון אחרון" #, php-format msgid "Edit comment for: %s" @@ -1234,6 +1281,7 @@ msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +"שדה ההערות יכול להישאר ריק. עם זאת, מומלץ מאוד להוסיף הערה כשדוחים בקשה." msgid "Reason" msgstr "סיבה" @@ -1249,6 +1297,8 @@ msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +"ניתן להשתמש בטופס זה כדי להגיש את הבקשה לבסיס החבילה %s%s%s שכולל את החבילות " +"הבאות:" msgid "Request type" msgstr "סוג הבקשה" @@ -1267,6 +1317,9 @@ msgid "" "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +"בהגשת בקשה למחיקה, משתמש מהימן ישקול אם למחוק בסיס חבילה. סוג כזה של בקשה " +"יכול לשמש במקרים של כפילויות, תכנית שנזנחה במקור לצד חבילה בלתי חוקית או " +"שבורה באופן שלא ניתן לשקם." msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " @@ -1274,6 +1327,9 @@ msgid "" "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." msgstr "" +"הגשת בקשת מיזוג מופנית למשתמש מהימן לטובת מחיקת בסיס חבילה והעברת ההצבעות " +"וההערות שלו לבסיס חבילה אחר. מיזוג חבילה לא משפיע על מאגרי ה־Git הקשורים " +"אליו. יש לוודא שעדכנת את היסטוריית ה־Git של חבילת היעד בעצמך." msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " @@ -1281,9 +1337,12 @@ msgid "" "the maintainer is MIA and you already tried to contact the maintainer " "previously." msgstr "" +"הגשת בקשת יתומה מופנית למשתמש מהימן לטובת ביטול שייכות בסיס חבילה. נא להגיש " +"בקשה זו רק אם החבילה דורשת פעולת תחזוקה, המתחזק אינו זמין וכבר ניסית ליצור " +"קשר עם המתחזק בעבר." msgid "No requests matched your search criteria." -msgstr "" +msgstr "אין בקשות שתואמות את תנאי החיפוש שלך." #, php-format msgid "%d package request found." @@ -1329,7 +1388,7 @@ msgid "Close" msgstr "סגירה" msgid "Pending" -msgstr "" +msgstr "בהמתנה" msgid "Closed" msgstr "סגור" @@ -1347,10 +1406,10 @@ msgid "Exact Package Base" msgstr "בסיס החבילה המדויק" msgid "Co-maintainer" -msgstr "" +msgstr "מתחזק משנה" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "מתחזק, מתחזק משנה" msgid "All" msgstr "הכול" @@ -1420,6 +1479,8 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"הפופולריות מחושבת כסכום של כל ההצבעות כאשר כל הצבעה נשקלת עם מקדם של %.2f " +"ליום מאז שנוצרה." msgid "Yes" msgstr "כן" @@ -1519,7 +1580,7 @@ msgid "Last vote" msgstr "הצבעה אחרונה" msgid "No results found." -msgstr "תוצאות לא נמצאו." +msgstr "לא נמצאו תוצאות." msgid "Start" msgstr "התחלה" diff --git a/po/hr.po b/po/hr.po index 71a1ae82..586507bc 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" "hr/)\n" @@ -522,6 +522,20 @@ msgstr "" msgid "Use this form to create an account." msgstr "Koristite ovaj formular za kreiranje računa." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Pouzdan korisnik" @@ -576,6 +590,9 @@ msgstr "Može sadržavati samo jednu točku, donju crticu ili povlaku." msgid "The email address is invalid." msgstr "Email adresa je neispravna." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "" @@ -916,6 +933,11 @@ msgstr "" msgid "required" msgstr "obvezno" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Običan korisnik" diff --git a/po/hu.po b/po/hu.po index 4501a4aa..409f0805 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3,16 +3,16 @@ # This file is distributed under the same license as the AUR package. # # Translators: -# György Balló , 2013 -# György Balló , 2011,2013-2016 -# György Balló , 2016 +# Balló György , 2013 +# Balló György , 2011,2013-2016 +# Balló György , 2016 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" "hu/)\n" @@ -585,6 +585,20 @@ msgstr "Regisztráció" msgid "Use this form to create an account." msgstr "Használd ezt a űrlapot felhasználói fiók létrehozására." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Megbízható felhasználó" @@ -641,6 +655,9 @@ msgstr "Csak egyetlen pontot, aláhúzást vagy kötőjelet tartalmazhat." msgid "The email address is invalid." msgstr "Érvénytelen e-mail cím." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "A PGP kulcs ujjlenyomata érvénytelen." @@ -988,6 +1005,11 @@ msgstr "Kattints %side%s a felhasználó részleteihez." msgid "required" msgstr "kötelező" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Normál felhasználó" diff --git a/po/it.po b/po/it.po index e84c1e07..bb311284 100644 --- a/po/it.po +++ b/po/it.po @@ -4,14 +4,14 @@ # # Translators: # Giovanni Scafora , 2011-2015 -# Lorenzo Porta , 2014 +# Lorenzo Porta , 2014 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" "it/)\n" @@ -587,6 +587,20 @@ msgstr "Registrati" msgid "Use this form to create an account." msgstr "Usa questo modulo per creare un account." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "TU" @@ -644,6 +658,9 @@ msgstr "Può contenere solo un punto, un trattino basso o un trattino." msgid "The email address is invalid." msgstr "L'indirizzo email non risulta valido." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "La fingerprint della chiave PGP non è valida." @@ -1003,6 +1020,11 @@ msgstr "" msgid "required" msgstr "obbligatorio" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Utente normale" diff --git a/po/ja.po b/po/ja.po index 85168f08..ea1a021d 100644 --- a/po/ja.po +++ b/po/ja.po @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-27 14:39+0000\n" -"Last-Translator: kusakata\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" "ja/)\n" "Language: ja\n" @@ -580,6 +580,20 @@ msgstr "登録" msgid "Use this form to create an account." msgstr "このフォームを使ってアカウントを作成してください。" +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Trusted User" @@ -636,6 +650,9 @@ msgstr "ピリオド、アンダーライン、ハイフンはひとつだけ含 msgid "The email address is invalid." msgstr "メールアドレスが不正です。" +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "PGP 鍵のフィンガープリントが不正です。" @@ -984,6 +1001,11 @@ msgstr "ユーザーの詳細は%sこちら%sをクリック。" msgid "required" msgstr "必須" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "ノーマルユーザー" diff --git a/po/nb.po b/po/nb.po index 7c2a0274..58c9501f 100644 --- a/po/nb.po +++ b/po/nb.po @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-03-02 10:39+0000\n" -"Last-Translator: Alexander F Rødseth \n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"Last-Translator: Lukas Fleischer \n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" "language/nb/)\n" "Language: nb\n" @@ -34,7 +34,7 @@ msgid "Note" msgstr "OBS" msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "Git clone URL-er er ikke ment til å åpnes i nettleseren." +msgstr "Nettleseren kan ikke åpne Git URL-er." #, php-format msgid "To clone the Git repository of %s, run %s." @@ -42,7 +42,7 @@ msgstr "For å klone et Git arkiv fra %s, kjør %s." #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "Trykk %sher%s for å returnere til detalj-siden for %s." +msgstr "Klikk %sher%s for å returnere til detalj-siden for %s." msgid "Service Unavailable" msgstr "Tjenesten er utilgjengelig" @@ -61,25 +61,25 @@ msgid "You are not allowed to access this area." msgstr "Du har ikke adgang til dette området." msgid "Could not retrieve information for the specified user." -msgstr "Kunne ikke motta informasjon for den valgte brukeren." +msgstr "Kunne ikke hente informasjon om den valgte brukeren." msgid "You do not have permission to edit this account." -msgstr "Du har ikke adgang til å endre denne kontoen." +msgstr "Du har ikke tilgang til å endre denne kontoen." msgid "Use this form to search existing accounts." -msgstr "Bruk dette skjemaet for å lete etter eksisterende kontoer." +msgstr "Bruk skjemaet for å søke etter eksisterende kontoer." msgid "You must log in to view user information." -msgstr "Du må logge inn for å se brukerinformasjon." +msgstr "Du må logge inn for å kunne se brukerinformasjon." msgid "Add Proposal" msgstr "Legg til forslag" msgid "Invalid token for user action." -msgstr "Ugyldig billett for brukerens handling." +msgstr "Ugyldig billett for brukerhandling." msgid "Username does not exist." -msgstr "Brukernavn finnes ikke." +msgstr "Brukernavnet finnes ikke." #, php-format msgid "%s already has proposal running for them." @@ -107,13 +107,13 @@ msgid "Type" msgstr "Type" msgid "Addition of a TU" -msgstr "Oppnevnelse av TU" +msgstr "Utnevnelse av TU" msgid "Removal of a TU" msgstr "Fjerning av TU" msgid "Removal of a TU (undeclared inactivity)" -msgstr "Fjerning av TU (uannonsert inaktivitet)" +msgstr "Fjerning av TU (inaktiv uten å si i fra)" msgid "Amendment of Bylaws" msgstr "Endring av vedtekter" @@ -125,7 +125,7 @@ msgid "Submit" msgstr "Send inn" msgid "Manage Co-maintainers" -msgstr "Administrer Med-Vedlikeholdere" +msgstr "Administrer med-vedlikeholdere" msgid "Edit comment" msgstr "Rediger kommentar" @@ -137,7 +137,7 @@ msgid "Home" msgstr "Hjem" msgid "My Flagged Packages" -msgstr "Mine pakker med anmerkninger" +msgstr "Mine flaggede pakker" msgid "My Requests" msgstr "Mine forespørsler" @@ -183,17 +183,17 @@ msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" -"AUR pakker er bruker produsert innhold. All bruk av de tilgjengelige filene " -"er på eget ansvar." +"Pakker i AUR kan lages av hvem som helst. All bruk av filer herfra skjer på " +"eget ansvar." msgid "Learn more..." msgstr "Lær mer..." msgid "Support" -msgstr "Støtte" +msgstr "Brukerstøtte" msgid "Package Requests" -msgstr "Pakke Forespørsler" +msgstr "Pakkeforespørsler" #, php-format msgid "" @@ -204,36 +204,36 @@ msgstr "" "boksen på siden til en pakke:" msgid "Orphan Request" -msgstr "Foreldreløs-forespørsel" +msgstr "Forespør at pakken gjøres eierløs" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" -"Forespør at pakken frigjøres fra eieren, dvs. at når vedlikeholderen er " -"inaktiv og pakken har vært markert som utdatert i en lengre periode." +"Forespør at pakken gjøres eierløs, f.eks. når vedlikeholderen er inaktiv og " +"pakken har vært flagget som utdatert i en lengre periode." msgid "Deletion Request" -msgstr "Slettingsforespørsel" +msgstr "Forespør sletting" msgid "" "Request a package to be removed from the Arch User Repository. Please do not " "use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" -"Forespør at pakken fjernes fra Arch User Repository. Ikke bruk dette hvis " -"pakken er ødelagt og kan relativt lett rettes. Ta i stedet kontakt med " -"vedlikeholderen og send i verste fall en foreldreløs-forespørsel." +"Forespør at pakken fjernes fra Arch User Repository. Ikke gjør dette hvis " +"pakken er ødelagt og lett kan fikses. Ta kontakt med vedlikeholderen i " +"stedet, eller forespør at pakken gjøres eierløs." msgid "Merge Request" -msgstr "Flettingsforespørsel" +msgstr "Fletteforespørsel" msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" -"Forespør at pakken blir flettet inn i en annen en. Kan brukes når en pakke " -"trenger et navnebytte eller å bli erstattet av en oppsplittet pakke." +"Forespør at pakken flettes inn i en annen. Kan brukes når en pakke trenger å " +"bytte navn eller å bli erstattet av en oppsplittet pakke." #, php-format msgid "" @@ -257,7 +257,7 @@ msgstr "" "nærmere detaljer." msgid "The following SSH fingerprints are used for the AUR:" -msgstr "De følgende SSH-fingeravtrykkene brukes for AUR-en:" +msgstr "Følgende SSH-fingeravtrykk brukes for AUR:" msgid "Discussion" msgstr "Diskusjon" @@ -308,7 +308,7 @@ msgid "UnNotify" msgstr "Fjern påminnelse" msgid "UnFlag" -msgstr "Fjern markering" +msgstr "Ta bort flagg" msgid "Login" msgstr "Logg inn" @@ -347,7 +347,7 @@ msgid "Packages" msgstr "Pakker" msgid "Error trying to retrieve package details." -msgstr "Feil oppstod ved uthenting av pakkedetaljer." +msgstr "Feil oppstod ved henting av pakkedetaljer." msgid "Missing a required field." msgstr "Mangler et nødvendig felt." @@ -357,7 +357,7 @@ msgstr "Passord-feltene stemmer ikke overens." #, php-format msgid "Your password must be at least %s characters." -msgstr "Passordet ditt må være minst %s tegn." +msgstr "Passordet må være på minst %s tegn." msgid "Invalid e-mail." msgstr "Ugyldig e-post." @@ -367,17 +367,16 @@ msgstr "Tilbakestill passord" msgid "Check your e-mail for the confirmation link." msgstr "" -"Sjekk e-posten din og bruk den tilsendte lenken for å bekrefte " -"registreringen." +"Sjekk e-posten og bruk den tilsendte lenken for å bekrefte registreringen." msgid "Your password has been reset successfully." -msgstr "Passordet ditt har blitt tilbakestilt." +msgstr "Passordet ditt er nullstilt." msgid "Confirm your e-mail address:" msgstr "Bekreft e-postadressen din:" msgid "Enter your new password:" -msgstr "Angi ditt nye passord:" +msgstr "Angi et nytt passord:" msgid "Confirm your new password:" msgstr "Bekreft ditt nye passord:" @@ -403,8 +402,8 @@ msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" -"De valgte pakkene har ikke blitt gjort foreldreløse, husk å krysse av i " -"boksen for å bekrefte." +"De valgte pakkene har ikke blitt gjort eierløse, kryss av i boksen for å " +"bekrefte." msgid "Cannot find package to merge votes and comments into." msgstr "Kunne ikke finne pakke for å flette stemmer og kommentarer inn i." @@ -415,7 +414,7 @@ msgstr "Kan ikke slå sammen en basispakke med seg selv." msgid "" "The selected packages have not been deleted, check the confirmation checkbox." msgstr "" -"Den valgte pakken har ikke blitt slettet, kryss av i boksen for å bekrefte." +"De valgte pakkene har ikke blitt slettet, kryss av i boksen for å bekrefte." msgid "Package Deletion" msgstr "Sletting av pakke" @@ -428,11 +427,11 @@ msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" -"Bruk dette skjemaet for å slette grunnpakken %s%s%s og følgende pakker fra " +"Bruk dette skjemaet for å slette basispakken %s%s%s og følgende pakker fra " "AUR:" msgid "Deletion of a package is permanent. " -msgstr "Slettingen av en pakke er permanent. " +msgstr "Slettingen av en pakke er endelig. " msgid "Select the checkbox to confirm action." msgstr "Kryss av i boksen for å bekrefte." @@ -447,15 +446,15 @@ msgid "Only Trusted Users and Developers can delete packages." msgstr "Bare betrodde brukere og utviklere kan slette pakker." msgid "Disown Package" -msgstr "Gjør foreldreløs" +msgstr "Gjør eierløs" #, php-format msgid "" "Use this form to disown the package base %s%s%s which includes the following " "packages: " msgstr "" -"Bruk dette skjemaet for å gjøre pakkebasen %s%s%s foreldreløs. Den " -"inkluderer følgende pakker:" +"Bruk dette skjemaet for å gjøre pakkebasen %s%s%s eierløs. Den inkluderer " +"følgende pakker:" #, php-format msgid "" @@ -468,23 +467,22 @@ msgstr "" msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" -"Ved å krysse av i boksen bekrefter du at du ønsker å gjøre pakken " -"foreldreløs." +"Ved å krysse av i boksen bekrefter du at du ønsker å gjøre pakken eierløs." msgid "Confirm to disown the package" -msgstr "Bekreft at du ønsker å gjøre pakken foreldreløs." +msgstr "Bekreft at du ønsker å gjøre pakken eierløs." msgid "Disown" -msgstr "Gjør foreldreløs" +msgstr "Gjør eierløs" msgid "Only Trusted Users and Developers can disown packages." -msgstr "Bare betrodde brukere og Arch utviklere kan gjøre pakker foreldreløse." +msgstr "Bare betrodde brukere og Arch utviklere kan gjøre pakker eierløse." msgid "Flag Comment" msgstr "Flagg kommentar" msgid "Flag Package Out-Of-Date" -msgstr "Flagg pakke som utdatert" +msgstr "Rapporter utdatert pakke" #, php-format msgid "" @@ -510,10 +508,10 @@ msgstr "" "som annonserer slippet av den nye versjonen, eller den nye kildekodepakken." msgid "Comments" -msgstr "Kommentarer" +msgstr "Kommentar" msgid "Flag" -msgstr "Markering" +msgstr "Flagg" msgid "Only registered users can flag packages out-of-date." msgstr "Bare registrerte brukere kan flagge pakker som utdaterte." @@ -522,18 +520,18 @@ msgid "Package Merging" msgstr "Pakkesammenslåing" msgid "Merge Package" -msgstr "Slå sammen pakke" +msgstr "Slå sammen med en annen" #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" -"Bruk dette skjemaet for å slå sammen grunnpakken %s%s%s med en annen pakke." +"Bruk dette skjemaet for å slå sammen basispakken %s%s%s med en annen pakke." msgid "The following packages will be deleted: " msgstr "Følgende pakker vil slettes:" msgid "Once the package has been merged it cannot be reversed. " -msgstr "Når pakken har blitt sammenslått, så kan det ikke angres. " +msgstr "Når pakken har blitt slått sammen med en annen, kan det ikke angres." msgid "Enter the package name you wish to merge the package into. " msgstr "Angi navnet på pakken du ønsker å slå denne pakken sammen med." @@ -577,6 +575,20 @@ msgstr "Registrer" msgid "Use this form to create an account." msgstr "Bruk dette feltet for å opprette en konto." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Betrodd bruker" @@ -599,10 +611,10 @@ msgid "Vote ID not valid." msgstr "Stemme-ID ikke gyldig." msgid "Current Votes" -msgstr "Foreløpige stemmer" +msgstr "Pågående avstemninger" msgid "Past Votes" -msgstr "Tidligere stemmer" +msgstr "Tidligere avstemninger" msgid "Voters" msgstr "Velgere" @@ -616,7 +628,7 @@ msgstr "" "ulempen dette medfører." msgid "Missing User ID" -msgstr "Mangler bruker-ID" +msgstr "Manglende bruker-ID" msgid "The username is invalid." msgstr "Brukernavnet er ugyldig." @@ -634,6 +646,9 @@ msgstr "Kan kun innehold ett punktum, en understrek, eller en bindestrek." msgid "The email address is invalid." msgstr "E-postadressen er ugyldig." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "PGP fingeravtrykket er ikke gyldig." @@ -773,17 +788,16 @@ msgstr "" "De valgte pakkene har ikke blitt flagget. Vennligst skriv inn en kommentar." msgid "The selected packages have been flagged out-of-date." -msgstr "De valgte pakkene har nå blitt markert som utdaterte." +msgstr "De valgte pakkene har nå blitt flagget som utdaterte." msgid "You must be logged in before you can unflag packages." -msgstr "" -"Du må være logget inn for å kunne fjerne \"utdatert\"-markeringen fra pakker." +msgstr "Du må være logget inn for å kunne fjerne flagg fra pakker." msgid "You did not select any packages to unflag." -msgstr "Ingen pakker ble valgt for å fjerne markeringer fra." +msgstr "Ingen pakker ble valgt for å fjerne flagg fra." msgid "The selected packages have been unflagged." -msgstr "De valgte pakkene har nå fått fjernet markeringen." +msgstr "De valgte pakkene har nå fått fjernet flaggene." msgid "You do not have permission to delete packages." msgstr "Du har ikke rettighetene som skal til for å kunne slette pakker." @@ -798,19 +812,19 @@ msgid "You must be logged in before you can adopt packages." msgstr "Du må være logget inn for å kunne adoptere pakker." msgid "You must be logged in before you can disown packages." -msgstr "Du må være logget inn for å kunne gjøre pakker foreldreløse." +msgstr "Du må være logget inn for å kunne gjøre pakker eierløse." msgid "You did not select any packages to adopt." msgstr "Du valgte ingen pakker for adopsjon." msgid "You did not select any packages to disown." -msgstr "Du valgte ingen pakker for å gjøre de foreldreløse." +msgstr "Du valgte ingen pakker som skal gjøres eierløse." msgid "The selected packages have been adopted." msgstr "Den valgte pakken har blitt adoptert." msgid "The selected packages have been disowned." -msgstr "De valgte pakkene er nå foreldreløse." +msgstr "De valgte pakkene er nå eierløse." msgid "You must be logged in before you can vote for packages." msgstr "Du må være logget inn for å kunne stemme på pakker." @@ -848,7 +862,7 @@ msgid "You are not allowed to delete this comment." msgstr "Du har ikke tilgang til å slette denne kommentaren." msgid "Comment has been deleted." -msgstr "Kommentar slettet." +msgstr "Kommentaren har blitt slettet." msgid "Comment has been edited." msgstr "Kommentaren har blitt redigert." @@ -875,7 +889,7 @@ msgstr "Vis pakkedetaljer for" #, php-format msgid "requires %s" -msgstr "behøver %s" +msgstr "trenger %s" msgid "You must be logged in to file package requests." msgstr "Du må være logget inn for å kunne sende inn forespørsler om pakker." @@ -974,7 +988,7 @@ msgstr "Endre brukerkonto" #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "Klikk %sher%s hvis du vil slette denne kontoen, for alltid." +msgstr "Klikk %sher%s hvis du vil slette denne kontoen for alltid." #, php-format msgid "Click %shere%s for user details." @@ -983,6 +997,11 @@ msgstr "Klikk %sher%s for brukerdetaljer." msgid "required" msgstr "trengs" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Vanlig bruker" @@ -1000,7 +1019,7 @@ msgid "" "be locked out." msgstr "" "Kontroller at du har skrevet e-postadressen din korrekt, ellers vil du bli " -"låst ute." +"utestengt." msgid "Hide Email Address" msgstr "Gjem e-postadresse" @@ -1018,8 +1037,8 @@ msgid "" "The following information is only required if you want to submit packages to " "the Arch User Repository." msgstr "" -"Følgende informasjon trengs bare dersom du vil sende inn pakker til Arch " -"sitt brukerstyrte pakkebibliotek." +"Følgende informasjon behøves bare hvis du har tenkt til å sende inn pakker " +"til Arch sitt brukerstyrte pakkebibliotek." msgid "SSH Public Key" msgstr "Offentlig SSH-nøkkel" @@ -1031,10 +1050,10 @@ msgid "Notify of new comments" msgstr "Gi beskjed om nye kommentarer" msgid "Notify of package updates" -msgstr "Varsle om pakkeoppdateringer" +msgstr "Gi beskjed om pakkeoppdateringer" msgid "Notify of ownership changes" -msgstr "Varsle om endring av eierskap" +msgstr "Gi beskjed om endring av eierskap" msgid "Update" msgstr "Oppdater" @@ -1043,7 +1062,7 @@ msgid "Create" msgstr "Opprett" msgid "Reset" -msgstr "Omstart" +msgstr "Nullstill" msgid "No results matched your search criteria." msgstr "Ingen treff for de oppgitte søkekriteriene." @@ -1111,20 +1130,20 @@ msgid "View Changes" msgstr "Vis endringer" msgid "Download snapshot" -msgstr "Last ned fryst bilde" +msgstr "Last ned kildekode" msgid "Search wiki" -msgstr "Søk wiki" +msgstr "Søk på wiki" #, php-format msgid "Flagged out-of-date (%s)" msgstr "Flagget som utdatert (%s)" msgid "Flag package out-of-date" -msgstr "Marker pakke som utdatert" +msgstr "Marker som utdatert" msgid "Unflag package" -msgstr "Fjern markering" +msgstr "Fjern flagg" msgid "Remove vote" msgstr "Angre stemme" @@ -1136,10 +1155,10 @@ msgid "Disable notifications" msgstr "Slå av beskjeder" msgid "Enable notifications" -msgstr "Få beskjed" +msgstr "Gi beskjed" msgid "Manage Co-Maintainers" -msgstr "Behandle med-vedlikeholdere" +msgstr "Med-vedlikeholdere" #, php-format msgid "%d pending request" @@ -1151,10 +1170,10 @@ msgid "Adopt Package" msgstr "Adopter pakke" msgid "Package Base Details" -msgstr "Grunnpakkedetaljer" +msgstr "Basispakkedetaljer" msgid "Git Clone URL" -msgstr "Git clone URL" +msgstr "Git-arkiv" msgid "read-only" msgstr "skrivebeskyttet" @@ -1166,10 +1185,10 @@ msgid "Submitter" msgstr "Innsender" msgid "Maintainer" -msgstr "Vedlikeholder" +msgstr "Eier" msgid "Last Packager" -msgstr "Siste innpakker" +msgstr "Forrige innpakker" msgid "Votes" msgstr "Stemmer" @@ -1178,7 +1197,7 @@ msgid "Popularity" msgstr "Popularitet" msgid "First Submitted" -msgstr "Først innsendt" +msgstr "Opprettet" msgid "Last Updated" msgstr "Sist oppdatert" @@ -1239,16 +1258,16 @@ msgid "All comments" msgstr "Alle kommentarer" msgid "Package Details" -msgstr "Pakkedetaljer" +msgstr "Om pakken" msgid "Package Base" -msgstr "Grunnpakke" +msgstr "Basispakke" msgid "Description" msgstr "Beskrivelse" msgid "Upstream URL" -msgstr "Prosjektets URL" +msgstr "Prosjektside" msgid "Visit the website for" msgstr "Besøk nettsiden til" @@ -1279,7 +1298,7 @@ msgstr "Kilder" #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Bruk dette skjemaet for å lukke forespørselen for grunnpakken %s%s%s." +msgstr "Bruk dette skjemaet for å lukke forespørselen for basispakken %s%s%s." msgid "" "The comments field can be left empty. However, it is highly recommended to " @@ -1302,7 +1321,7 @@ msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" -"Bruk dette skjemaet for å registrere en forespørsel for grunnpakken %s%s%s " +"Bruk dette skjemaet for å registrere en forespørsel for basispakken %s%s%s " "som inkluderer følgende pakker:" msgid "Request type" @@ -1312,7 +1331,7 @@ msgid "Deletion" msgstr "Sletting" msgid "Orphan" -msgstr "Foreldreløs" +msgstr "Eierløs" msgid "Merge into" msgstr "Flett med" @@ -1344,7 +1363,7 @@ msgid "" "the maintainer is MIA and you already tried to contact the maintainer " "previously." msgstr "" -"Ved å sende inn en forespørsel om å gjøre en pakke foreldreløs spør du en " +"Ved å sende inn en forespørsel om å gjøre en pakke eierløs spør du en " "betrodd bruker om å utføre dette. Vennligst bare send inn forespørselen " "dersom pakken trenger vedlikehold, nåværende vedlikeholder er fraværende og " "du allerede har prøvd å kontakte den som vedlikeholder pakken." @@ -1411,7 +1430,7 @@ msgid "Exact Name" msgstr "Eksakt navn" msgid "Exact Package Base" -msgstr "Eksakt grunnpakke" +msgstr "Eksakt basispakke" msgid "Co-maintainer" msgstr "Med-vedlikeholder" @@ -1432,7 +1451,7 @@ msgid "Name" msgstr "Navn" msgid "Voted" -msgstr "Stemt" +msgstr "Din stemme" msgid "Last modified" msgstr "Sist endret" @@ -1450,28 +1469,28 @@ msgid "Search by" msgstr "Søk etter" msgid "Out of Date" -msgstr "Foreldet" +msgstr "Ut på dato" msgid "Sort by" msgstr "Sorter etter" msgid "Sort order" -msgstr "Sorteringsrekkefølge" +msgstr "Sortering" msgid "Per page" -msgstr "Per side" +msgstr "Treff per side" msgid "Go" -msgstr "Utfør" +msgstr "Søk nå" msgid "Orphans" -msgstr "Foreldreløse" +msgstr "Eierløse" msgid "Error retrieving package list." msgstr "Feil ved mottagelse av pakkeliste." msgid "No packages matched your search criteria." -msgstr "Ingen pakker passer til dine søkekriterier." +msgstr "Ingen pakker her." #, php-format msgid "%d package found." @@ -1494,19 +1513,19 @@ msgid "Yes" msgstr "Ja" msgid "orphan" -msgstr "foreldreløs" +msgstr "eierløs" msgid "Actions" msgstr "Handlinger" msgid "Unflag Out-of-date" -msgstr "Fjern markering" +msgstr "Fjern flagg" msgid "Adopt Packages" msgstr "Adopter pakker" msgid "Disown Packages" -msgstr "Gjør pakker foreldreløse" +msgstr "Gjør pakker eierløse" msgid "Delete Packages" msgstr "Slett pakker" @@ -1524,7 +1543,7 @@ msgid "Statistics" msgstr "Statistikk" msgid "Orphan Packages" -msgstr "Foreldreløse pakker" +msgstr "Eierløse pakker" msgid "Packages added in the past 7 days" msgstr "Lagt til de siste 7 dagene" @@ -1542,7 +1561,7 @@ msgid "Registered Users" msgstr "Registrerte brukere" msgid "Trusted Users" -msgstr "Betrodde Brukere" +msgstr "Betrodde brukere" msgid "Recent Updates" msgstr "Nylig oppdatert" @@ -1582,10 +1601,10 @@ msgid "Participation" msgstr "Deltagelse" msgid "Last Votes by TU" -msgstr "Siste stemmer fra TU" +msgstr "Betrodde brukeres avgitte stemmer" msgid "Last vote" -msgstr "Siste stemme" +msgstr "Forrige avstemning" msgid "No results found." msgstr "Ingen resultater." diff --git a/po/nl.po b/po/nl.po index 4dd221f5..607efea8 100644 --- a/po/nl.po +++ b/po/nl.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" "Language: nl\n" @@ -570,6 +570,20 @@ msgstr "Registreren" msgid "Use this form to create an account." msgstr "Gebruik dit formulier om een ​​account aan te maken." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Trusted User" @@ -626,6 +640,9 @@ msgstr "Kan maar één punt, komma of koppelteken bevatten." msgid "The email address is invalid." msgstr "Het e-mailadres is ongeldig." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "De vingerafdruk van de PGP sleutel is ongeldig." @@ -980,6 +997,11 @@ msgstr "" msgid "required" msgstr "verplicht" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Normale gebruiker" diff --git a/po/pl.po b/po/pl.po index ad2918f3..b6ca8ed2 100644 --- a/po/pl.po +++ b/po/pl.po @@ -9,16 +9,17 @@ # Chris Warrick , 2012 # Kwpolska , 2011 # Lukas Fleischer , 2011 -# m4sk1n , 2017 +# m4sk1n , 2017 # Michal T , 2016 # Nuc1eoN , 2014 -# Piotr Strębski , 2013-2016 +# Piotr Strębski , 2017 +# Piotr Strębski , 2013-2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" "pl/)\n" @@ -27,7 +28,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n" -"%100<12 || n%100>=14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" +"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" "%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" msgid "Page Not Found" @@ -139,22 +140,22 @@ msgid "Edit comment" msgstr "Edytuj komentarz" msgid "Dashboard" -msgstr "" +msgstr "Tablica rozdzielcza" msgid "Home" msgstr "Start" msgid "My Flagged Packages" -msgstr "" +msgstr "Moje oflagowane pakiety" msgid "My Requests" -msgstr "" +msgstr "Moje prośby" msgid "My Packages" msgstr "Moje pakiety" msgid "Search for packages I maintain" -msgstr "" +msgstr "Wyszukaj pakiety, którymi się opiekuję" msgid "Co-Maintained Packages" msgstr "" @@ -572,6 +573,20 @@ msgstr "Zarejestruj się" msgid "Use this form to create an account." msgstr "Przy użyciu tego formularza możesz utworzyć konto." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Zaufany Użytkownik" @@ -629,6 +644,9 @@ msgstr "Może zawierać tylko jedną kropkę, podkreślnik lub myślnik." msgid "The email address is invalid." msgstr "Adres e-mail jest nieprawidłowy." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "Odcisk palca klucza PGP jest nieprawidłowy." @@ -977,6 +995,11 @@ msgstr "Kliknij %stutaj%s by wyświetlić szczegóły użytkownika." msgid "required" msgstr "wymagane" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Zwykły użytkownik" @@ -1006,7 +1029,7 @@ msgid "Language" msgstr "Język" msgid "Timezone" -msgstr "" +msgstr "Strefa czasowa" msgid "" "The following information is only required if you want to submit packages to " @@ -1396,37 +1419,37 @@ msgid "Name, Description" msgstr "Nazwa, Opis" msgid "Name Only" -msgstr "Tylko nazwa" +msgstr "Tylko nazwy" msgid "Exact Name" -msgstr "Dokładna nazwa" +msgstr "Dokładnej nazwy" msgid "Exact Package Base" -msgstr "Dokładna baza pakietu" +msgstr "Dokładnej bazy pakietu" msgid "Co-maintainer" -msgstr "" +msgstr "Współopiekuna" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Opiekuna, współopiekuna" msgid "All" -msgstr "Wszystkie" +msgstr "Wszystko" msgid "Flagged" -msgstr "Oznaczony" +msgstr "Oznaczone" msgid "Not Flagged" -msgstr "Nieoznaczony" +msgstr "Nieoznaczone" msgid "Name" -msgstr "Nazwa" +msgstr "Nazwy" msgid "Voted" -msgstr "Zagłosowany" +msgstr "Liczby głosów" msgid "Last modified" -msgstr "Ostatnio zmienione" +msgstr "Ostatniej modyfikacji" msgid "Ascending" msgstr "Rosnąco" @@ -1435,34 +1458,34 @@ msgid "Descending" msgstr "Malejąco" msgid "Enter search criteria" -msgstr "Podaj kryteria wyszukiwania" +msgstr "Wprowadź kryteria wyszukiwania" msgid "Search by" msgstr "Szukaj według" msgid "Out of Date" -msgstr "Nieaktualny" +msgstr "Nieaktualne" msgid "Sort by" msgstr "Sortuj według" msgid "Sort order" -msgstr "Porządek" +msgstr "Porządek sortowania" msgid "Per page" -msgstr "Na stronie" +msgstr "Elementów na stronę" msgid "Go" -msgstr "Wykonaj" +msgstr "Szukaj" msgid "Orphans" -msgstr "Bez opiekuna" +msgstr "Osierocone pakiety" msgid "Error retrieving package list." -msgstr "Błąd podczas pobierania listy pakietów." +msgstr "Wystąpił błąd podczas otrzymywania listy pakietów." msgid "No packages matched your search criteria." -msgstr "Żaden pakiet nie spełnia podanych kryteriów." +msgstr "Nie znaleziono pakietów spełniających kryteria wyszukiwania." #, php-format msgid "%d package found." @@ -1485,13 +1508,13 @@ msgid "Yes" msgstr "Tak" msgid "orphan" -msgstr "bez opiekuna" +msgstr "pakiet osierocony" msgid "Actions" msgstr "Działania" msgid "Unflag Out-of-date" -msgstr "Usuń flagę nieaktualności" +msgstr "Odznacz jako nieaktualny" msgid "Adopt Packages" msgstr "Przejmij pakiety" @@ -1506,7 +1529,7 @@ msgid "Confirm" msgstr "Potwierdź" msgid "Any type" -msgstr "Dowolny rodzaj" +msgstr "Dowolnego typu" msgid "Search" msgstr "Szukaj" @@ -1515,28 +1538,28 @@ msgid "Statistics" msgstr "Statystyki" msgid "Orphan Packages" -msgstr "Osierocone" +msgstr "Osierocone pakiety" msgid "Packages added in the past 7 days" -msgstr "Dodane przez ostatnie 7 dni" +msgstr "Pakiety dodane w ciągu ostatniego tygodnia" msgid "Packages updated in the past 7 days" -msgstr "Zaktualizowane przez ostatnie 7 dni" +msgstr "Pakiety zaktualizowane w ciągu ostatniego tygodnia" msgid "Packages updated in the past year" -msgstr "Zaktualizowane przez ostatni rok" +msgstr "Pakiety zaktualizowane w ostatnim roku" msgid "Packages never updated" -msgstr "Nigdy nieaktualizowane" +msgstr "Pakiety nigdy nie aktualizowane" msgid "Registered Users" msgstr "Zarejestrowani użytkownicy" msgid "Trusted Users" -msgstr "Zaufani Użytkownicy" +msgstr "Zaufani użytkownicy" msgid "Recent Updates" -msgstr "Ostatnie aktualizacje" +msgstr "Ostatnio aktualizowane" msgid "more" msgstr "więcej" diff --git a/po/pt_BR.po b/po/pt_BR.po index 04848217..0f862a08 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 15:12+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 22:00+0000\n" "Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" "language/pt_BR/)\n" @@ -584,6 +584,22 @@ msgstr "Registrar" msgid "Use this form to create an account." msgstr "Utilize este formulário para criar uma conta." +msgid "Terms of Service" +msgstr "Termos de Serviço" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" +"Os seguintes documentos foram atualizados. Por favor, revise-os " +"cuidadosamente:" + +#, php-format +msgid "revision %d" +msgstr "revisão %d" + +msgid "I accept the terms and conditions above." +msgstr "Eu aceito os termos e condições acima." + msgid "Trusted User" msgstr "Usuário confiável" @@ -640,6 +656,10 @@ msgstr "Pode conter somente um ponto, traço inferior ou hífen." msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" +"A página inicial é inválida. Por favor especificar a URL HTTP(s) completa." + msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." @@ -993,6 +1013,13 @@ msgstr "Clique %saqui%s para os detalhes do usuário." msgid "required" msgstr "obrigatório" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" +"Seu nome de usuário é o nome que você vai usar para se autenticar. É visível " +"para o público geral, mesmo se sua contas estiver inativa." + msgid "Normal user" msgstr "Usuário normal" diff --git a/po/pt_PT.po b/po/pt_PT.po index e00b5b83..3002f5a7 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -6,14 +6,14 @@ # Gaspar Santos , 2011 # R00KIE , 2013,2016 # R00KIE , 2011 -# DarkVenger , 2013-2015 -# DarkVenger , 2012 +# DarkVenger, 2013-2015 +# DarkVenger, 2012 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" "aur/language/pt_PT/)\n" @@ -558,6 +558,20 @@ msgstr "Registar" msgid "Use this form to create an account." msgstr "Para criar uma conta utilize este formulário." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Utilizador de Confiança" @@ -615,6 +629,9 @@ msgstr "Apenas pode conter um ponto, underscore ou hífen." msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." @@ -964,6 +981,11 @@ msgstr "" msgid "required" msgstr "necessário" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Utilizador normal" diff --git a/po/ro.po b/po/ro.po index 801e5dd7..f3ee1ced 100644 --- a/po/ro.po +++ b/po/ro.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" "ro/)\n" @@ -538,6 +538,20 @@ msgstr "Înregistrare" msgid "Use this form to create an account." msgstr "Folosește acest formular pentru a crea un cont." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Trusted User" @@ -595,6 +609,9 @@ msgstr "Poate conține doar o virgulă, linie joasă sau cratimă." msgid "The email address is invalid." msgstr "Adresa de email nu este validă." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "Amprenta cheii PGP este nevalidă." @@ -946,6 +963,11 @@ msgstr "" msgid "required" msgstr "cerut" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Utilizator obișnuit" diff --git a/po/ru.po b/po/ru.po index 41f6534c..da152833 100644 --- a/po/ru.po +++ b/po/ru.po @@ -5,18 +5,20 @@ # Translators: # Evgeniy Alekseev , 2014-2015 # Evgeniy Alekseev , 2014-2015, 2016 +# Igor , 2017 # Kyrylo Silin , 2011 # Kyrylo Silin , 2011 # Lukas Fleischer , 2011 # Rustam Tsurik , 2013 # Sergey Shepelev , 2014,2016 +# Александр Яворский , 2017 # Аскольд , 2016 msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" "ru/)\n" @@ -38,15 +40,16 @@ msgid "Note" msgstr "Примечание" msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "Клонирование репозитория Git не подразумевает открытие в браузере." #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Для клонирования репозитория Git «%s» выполните «%s»." #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +"Нажмите %sздесь%s, для возврата на страницу с подробной информацией о «%s»." msgid "Service Unavailable" msgstr "Сервис недоступен" @@ -130,34 +133,34 @@ msgid "Submit" msgstr "Прислать" msgid "Manage Co-maintainers" -msgstr "Управление ответственными" +msgstr "Управление сопровождающими" msgid "Edit comment" msgstr "Редактировать комментарий" msgid "Dashboard" -msgstr "" +msgstr "Панель настроек" msgid "Home" msgstr "Главная" msgid "My Flagged Packages" -msgstr "" +msgstr "Мои отмеченные пакеты" msgid "My Requests" -msgstr "" +msgstr "Мои заявки" msgid "My Packages" msgstr "Мои пакеты" msgid "Search for packages I maintain" -msgstr "" +msgstr "Искать пакеты, которые я сопровождаю" msgid "Co-Maintained Packages" -msgstr "" +msgstr "Пакеты, в сопровождении которых я участвую" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Поиск пакетов, в которых я сопровождающий" #, php-format msgid "" @@ -404,7 +407,7 @@ msgid "Enter your e-mail address:" msgstr "Введите свой адрес электронной почты:" msgid "Package Bases" -msgstr "" +msgstr "Группы пакетов" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -579,6 +582,20 @@ msgstr "Регистрация" msgid "Use this form to create an account." msgstr "Используйте эту форму для создания учетной записи." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Доверенный пользователь" @@ -635,6 +652,9 @@ msgstr "Может содержать только одну точку, подч msgid "The email address is invalid." msgstr "Неправильный адрес электронной почты." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "Неверный отпечаток ключа PGP." @@ -648,7 +668,7 @@ msgid "Language is not currently supported." msgstr "Язык пока не поддерживается." msgid "Timezone is not currently supported." -msgstr "" +msgstr "Часовые пояса пока не поддерживаются." #, php-format msgid "The username, %s%s%s, is already in use." @@ -955,7 +975,7 @@ msgid "Active" msgstr "Активный" msgid "Registration date:" -msgstr "" +msgstr "Дата регистрации:" msgid "unknown" msgstr "неизвестно" @@ -978,11 +998,16 @@ msgstr "Нажмите %sздесь%s, если Вы хотите удалить #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "Нажмите %sздесь%s, чтобы просмотреть данные о пользователе." msgid "required" msgstr "необходимо" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Обычный пользователь" @@ -1012,7 +1037,7 @@ msgid "Language" msgstr "Язык" msgid "Timezone" -msgstr "" +msgstr "Часовой пояс" msgid "" "The following information is only required if you want to submit packages to " @@ -1058,10 +1083,10 @@ msgid "Edit" msgstr "Редактировать" msgid "Less" -msgstr "Назад" +msgstr "Меньше" msgid "More" -msgstr "Далее" +msgstr "Больше" msgid "No more results to display." msgstr "Больше нет результатов." @@ -1211,11 +1236,11 @@ msgstr "Анонимный комментарий для %s" #, php-format msgid "deleted on %s by %s" -msgstr "удален для %s %s" +msgstr "удалён %s %s" #, php-format msgid "deleted on %s" -msgstr "удален %s" +msgstr "удалён %s" #, php-format msgid "edited on %s by %s" @@ -1351,7 +1376,7 @@ msgstr "" "ним ранее." msgid "No requests matched your search criteria." -msgstr "" +msgstr "Нет запросов по выбранному критерию поиска." #, php-format msgid "%d package request found." @@ -1377,10 +1402,10 @@ msgstr "Дата" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" +msgstr[0] "остался ~%d день" +msgstr[1] "осталось ~%d дня" +msgstr[2] "осталось ~%d дней" +msgstr[3] "осталось ~%d дней" #, php-format msgid "~%d hour left" @@ -1403,7 +1428,7 @@ msgid "Close" msgstr "Закрыть" msgid "Pending" -msgstr "" +msgstr "Ожидает" msgid "Closed" msgstr "Закрыт" @@ -1421,10 +1446,10 @@ msgid "Exact Package Base" msgstr "Точное имя группы" msgid "Co-maintainer" -msgstr "" +msgstr "Сопровождающий" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Ответственный, сопровождающий" msgid "All" msgstr "Все" @@ -1496,6 +1521,9 @@ msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +"Популярность считается, как сумма всех голосов, где каждый голос взвешен с " +"коэффициентом %.2f за каждый день разницы между днём голосования и днём " +"загрузки пакета." msgid "Yes" msgstr "Да" diff --git a/po/sk.po b/po/sk.po index 051a6864..ccd1edd9 100644 --- a/po/sk.po +++ b/po/sk.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" "sk/)\n" @@ -575,6 +575,20 @@ msgstr "Registrovať" msgid "Use this form to create an account." msgstr "Použite tento formulár pre vytvorenie účtu. " +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Dôverovaný užívateľ (TU)" @@ -631,6 +645,9 @@ msgstr "Môže obsahovať len jednu bodku, podčiarkovník alebo pomlčku." msgid "The email address is invalid." msgstr "E-mailová adresa nie je platná." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "PGP otlačok kľúča je neplatný." @@ -977,6 +994,11 @@ msgstr "Kliknite %ssem%s pre informácie o užívateľovi." msgid "required" msgstr "povinný" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Normálny užívateľ" diff --git a/po/sr.po b/po/sr.po index 5e2268c0..722a5700 100644 --- a/po/sr.po +++ b/po/sr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-26 16:21+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-12-02 00:35+0000\n" "Last-Translator: Slobodan Terzić \n" "Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" "sr/)\n" @@ -566,6 +566,20 @@ msgstr "Registracija" msgid "Use this form to create an account." msgstr "Ovim formularom pravite nalog." +msgid "Terms of Service" +msgstr "Uslovi korišćenja" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "Sledeći dokumenti su ažurirani. Molimo da ih pažljivo pročitate:" + +#, php-format +msgid "revision %d" +msgstr "revizija %d" + +msgid "I accept the terms and conditions above." +msgstr "Prihvatam gore navedene uslove." + msgid "Trusted User" msgstr "Poverljivi korisnik" @@ -622,6 +636,9 @@ msgstr "Može sadržati samo jedan razmak, podvlaku ili crticu." msgid "The email address is invalid." msgstr "Neispravna adresa e-pošte." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "Domaća stranica je neispravna, molimo navedite puni HTTP(s) URL." + msgid "The PGP key fingerprint is invalid." msgstr "Otisak PGP ključa nije ispravan." @@ -968,6 +985,13 @@ msgstr "Kliknite %sovde%s za podatke o korisniku." msgid "required" msgstr "neophodno" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" +"Vaše korisničko ime kojim se prijavljujete. Vidljivo je u javnosti, čak i " +"ako je vaš nalog neaktivan." + msgid "Normal user" msgstr "Običan korisnik" @@ -1310,7 +1334,7 @@ msgid "" msgstr "" "Podnošenjem zahteva za brisanje tražili ste of poverljivog korisnika da " "obriše bazu paketa. Ovaj tip zahteva treba koristiti za duplikate, uzvodno " -"napišten softver, kao i nelegalne ili nepopravljivo pokvarene pakete." +"napušten softver, kao i nelegalne ili nepopravljivo pokvarene pakete." msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " diff --git a/po/tr.po b/po/tr.po index 9490001e..e87cb141 100644 --- a/po/tr.po +++ b/po/tr.po @@ -15,8 +15,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" "tr/)\n" @@ -576,6 +576,20 @@ msgstr "Kayıt ol" msgid "Use this form to create an account." msgstr "Yeni bir hesap oluşturmak için bu formu kullanın." +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "Güvenilen Kullanıcı" @@ -632,6 +646,9 @@ msgstr "Sadece bir nokta, alt çizgi veya tire barındırabilir." msgid "The email address is invalid." msgstr "E-posta adresi geçerli değil." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "PGP anahtarı parmak izi hatalı." @@ -979,6 +996,11 @@ msgstr "Kullanıcı detayları için %sburaya%s tıklayın." msgid "required" msgstr "gerekli" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "Normal kullanıcı" diff --git a/po/uk.po b/po/uk.po index f6267e65..ab034a21 100644 --- a/po/uk.po +++ b/po/uk.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 16:47+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-29 13:25+0000\n" "Last-Translator: Yarema aka Knedlyk \n" "Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" "uk/)\n" @@ -580,6 +580,20 @@ msgstr "Зареєструватись" msgid "Use this form to create an account." msgstr "Створіть обліковий запис за допомогою цієї форми." +msgid "Terms of Service" +msgstr "Умови обслуговування" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "Наступні документи оновлено. Перевірте їх уважно: " + +#, php-format +msgid "revision %d" +msgstr "перегляд %d" + +msgid "I accept the terms and conditions above." +msgstr "Я приймаю подані вище терміни і умови. " + msgid "Trusted User" msgstr "Довірений користувач" @@ -636,6 +650,9 @@ msgstr "Може містити тільки один період, підкре msgid "The email address is invalid." msgstr "Адреса електронної пошти неправильна." +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "Неправильна домашня сторінка, вкажіть повну адресу HTTP(s)." + msgid "The PGP key fingerprint is invalid." msgstr "Відбиток ключа PGP недійсний." @@ -986,6 +1003,13 @@ msgstr "Клацніть %sтут%s, щоб дізнатися більше пр msgid "required" msgstr "обов'язково" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" +"Ваша назва користувача є назвою, що буде використовуватися для входу. Вона " +"буде видимою для всіх, навіть якщо Ваш рахунок неактивний." + msgid "Normal user" msgstr "Звичайний користувач" diff --git a/po/zh_CN.po b/po/zh_CN.po index d5e306cf..ceacdea5 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -7,6 +7,7 @@ # dongfengweixiao , 2015 # Felix Yan , 2014 # Lukas Fleischer , 2011 +# pingplug , 2017 # leonfeng , 2012 # Weiwen Zhao , 2013 # Xiaodong Qi , 2016 @@ -14,8 +15,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-25 12:41+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 07:52+0000\n" "Last-Translator: Lukas Fleischer \n" "Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" "language/zh_CN/)\n" @@ -35,15 +36,15 @@ msgid "Note" msgstr "提示" msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "Git 克隆地址并不意味着能被浏览器打开" #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "要克隆 Git 项目 %s,运行 %s。" #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "点击 %s这里%s 以回到 %s 的软件包详情页面" msgid "Service Unavailable" msgstr "服务不可用" @@ -132,28 +133,28 @@ msgid "Edit comment" msgstr "编辑评论" msgid "Dashboard" -msgstr "" +msgstr "仪表面板" msgid "Home" msgstr "首页" msgid "My Flagged Packages" -msgstr "" +msgstr "被标记的软件包" msgid "My Requests" -msgstr "" +msgstr "我的请求" msgid "My Packages" msgstr "我的软件包" msgid "Search for packages I maintain" -msgstr "" +msgstr "搜索我维护的软件包" msgid "Co-Maintained Packages" -msgstr "" +msgstr "共同维护的软件包" msgid "Search for packages I co-maintain" -msgstr "" +msgstr "搜索共同维护的软件包" #, php-format msgid "" @@ -217,7 +218,7 @@ msgid "" "the package maintainer and file orphan request if necessary." msgstr "" "请求软件包从 AUR 中移除。如果这个包虽然损坏了但是可以被轻易地修好,请不要进行" -"此操作,您应该联系包的维护者或者有必要的情况下发送 orphan request。" +"此操作,您应该联系包的维护者或者有必要的情况下发送弃置请求。" msgid "Merge Request" msgstr "合并请求" @@ -383,7 +384,7 @@ msgid "Enter your e-mail address:" msgstr "输入您的邮箱地址:" msgid "Package Bases" -msgstr "" +msgstr "包基础" msgid "" "The selected packages have not been disowned, check the confirmation " @@ -547,6 +548,20 @@ msgstr "注册" msgid "Use this form to create an account." msgstr "使用此表单创建帐号。" +msgid "Terms of Service" +msgstr "" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "" + +#, php-format +msgid "revision %d" +msgstr "" + +msgid "I accept the terms and conditions above." +msgstr "" + msgid "Trusted User" msgstr "受信用户" @@ -603,6 +618,9 @@ msgstr "最多包含一个“.”,“_”,或“-”" msgid "The email address is invalid." msgstr "错误的 Email 地址。" +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "" + msgid "The PGP key fingerprint is invalid." msgstr "PGP 密钥指纹无效。" @@ -616,7 +634,7 @@ msgid "Language is not currently supported." msgstr "目前不支持此语言。" msgid "Timezone is not currently supported." -msgstr "" +msgstr "目前不支持此时区。" #, php-format msgid "The username, %s%s%s, is already in use." @@ -901,7 +919,7 @@ msgid "Real Name" msgstr "真实名字" msgid "Homepage" -msgstr "" +msgstr "首页" msgid "IRC Nick" msgstr "IRC昵称" @@ -919,7 +937,7 @@ msgid "Active" msgstr "激活" msgid "Registration date:" -msgstr "" +msgstr "注册日期:" msgid "unknown" msgstr "未知" @@ -942,11 +960,16 @@ msgstr "如果你想要彻底删除这个帐号,请点击%s这里%s。" #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "点击 %s这里%s 访问用户详情页面" msgid "required" msgstr "必填" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "" + msgid "Normal user" msgstr "普通用户" @@ -974,7 +997,7 @@ msgid "Language" msgstr "语言" msgid "Timezone" -msgstr "" +msgstr "时区" msgid "" "The following information is only required if you want to submit packages to " @@ -994,7 +1017,7 @@ msgid "Notify of package updates" msgstr "软件包更新提醒" msgid "Notify of ownership changes" -msgstr "" +msgstr "所有权更改提醒" msgid "Update" msgstr "更新" @@ -1094,7 +1117,7 @@ msgid "Disable notifications" msgstr "禁用通知" msgid "Enable notifications" -msgstr "" +msgstr "启用通知" msgid "Manage Co-Maintainers" msgstr "管理共同维护者" @@ -1275,6 +1298,8 @@ msgid "" "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +"通过提交删除请求,您请求受信用户进行包基础的删除。这种请求应当被用于重复,软" +"件被上游放弃,非法或损坏且无法修复的软件包。" msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " @@ -1282,6 +1307,9 @@ msgid "" "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." msgstr "" +"通过提交合并请求,您请求受信用户进行包基础的删除,并转移其投票和评论到另一包" +"基础。合并一个软件包不会影响对应的 Git 项目,因此您需要自己更新目标软件包的 " +"Git 项目。" msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " @@ -1289,9 +1317,11 @@ msgid "" "the maintainer is MIA and you already tried to contact the maintainer " "previously." msgstr "" +"通过提交弃置请求,您请求受信用户进行包基础的弃置。请仅在软件包需要维护者操" +"作,您之前已经尝试联系过维护者但没有回应时提交请求。" msgid "No requests matched your search criteria." -msgstr "" +msgstr "没有请求符合您的搜索条件。" #, php-format msgid "%d package request found." @@ -1314,15 +1344,15 @@ msgstr "日期" #, php-format msgid "~%d day left" msgid_plural "~%d days left" -msgstr[0] "" +msgstr[0] "剩余约 %d 天" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "剩余~%d小时" +msgstr[0] "剩余约 %d 小时" msgid "<1 hour left" -msgstr "剩余<1小时" +msgstr "剩余不到 1 小时" msgid "Accept" msgstr "接受" @@ -1334,7 +1364,7 @@ msgid "Close" msgstr "关闭" msgid "Pending" -msgstr "" +msgstr "等待中" msgid "Closed" msgstr "已关闭" @@ -1352,10 +1382,10 @@ msgid "Exact Package Base" msgstr "准确包基础" msgid "Co-maintainer" -msgstr "" +msgstr "共同维护者" msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "维护者,共同维护者" msgid "All" msgstr "全部" @@ -1423,7 +1453,7 @@ msgstr "版本" msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" +msgstr "受欢迎度通过将每次投票以系数为每天 %.2f 的权重加权求和计算。" msgid "Yes" msgstr "是" diff --git a/po/zh_TW.po b/po/zh_TW.po index 7c155188..ad90859c 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Arch User Repository (AUR)\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-02-25 13:41+0100\n" -"PO-Revision-Date: 2017-02-26 03:10+0000\n" +"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"PO-Revision-Date: 2017-11-28 11:49+0000\n" "Last-Translator: Jeff Huang \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" "language/zh_TW/)\n" @@ -545,6 +545,20 @@ msgstr "註冊" msgid "Use this form to create an account." msgstr "使用此表單來新建一個帳號。" +msgid "Terms of Service" +msgstr "服務條款" + +msgid "" +"The following documents have been updated. Please review them carefully:" +msgstr "以下的文件已更新。請小心審閱它們:" + +#, php-format +msgid "revision %d" +msgstr "修訂版本:%d" + +msgid "I accept the terms and conditions above." +msgstr "我接受上述條款與條件。" + msgid "Trusted User" msgstr "受信使用者" @@ -601,6 +615,9 @@ msgstr "最多包含一個「.」、「_」或「-」。" msgid "The email address is invalid." msgstr "電子郵件地址無效。" +msgid "The home page is invalid, please specify the full HTTP(s) URL." +msgstr "首頁無效,請指定完整的 HTTP(s) URL。" + msgid "The PGP key fingerprint is invalid." msgstr "PGP 密鑰指紋無效。" @@ -945,6 +962,11 @@ msgstr "點選 %s此處%s 來取得使用者的詳細資訊。" msgid "required" msgstr "必填" +msgid "" +"Your user name is the name you will use to login. It is visible to the " +"general public, even if your account is inactive." +msgstr "您的使用者名稱是您要用於登入的名稱。它是公開的,即使您的帳號已停用。" + msgid "Normal user" msgstr "一般使用者" From 0333d475fa60acebdc57a195ff9fb3fc0bd4771d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 3 Dec 2017 10:23:46 +0100 Subject: [PATCH 0403/1891] Release 4.6.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 20132d80..dc8e87f1 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Sun, 3 Dec 2017 13:51:21 +0100 Subject: [PATCH 0404/1891] Allow setting an empty home page Since commit 4efba18 (Only allow valid HTTP(s) URLs as home page, 2017-11-05), the home page field in the account settings must be a valid URL. However, this new check prevents from leaving the field empty. Keep the check in place but skip it if the home page field is left empty. Fixes FS#56550. Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index b8d9dc54..df573755 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -162,7 +162,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $error = __("The email address is invalid."); } - if (!$error && !valid_homepage($HP)) { + if (!$error && !empty($HP) && !valid_homepage($HP)) { $error = __("The home page is invalid, please specify the full HTTP(s) URL."); } From a04fe6a13ec772c948efa67e0dcd46eefa834e63 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 3 Dec 2017 13:59:54 +0100 Subject: [PATCH 0405/1891] Add route for /users.gz Signed-off-by: Lukas Fleischer --- web/html/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/html/index.php b/web/html/index.php index 364d399c..2c53cddd 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -188,6 +188,7 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { break; case "/packages.gz": case "/pkgbase.gz": + case "/users.gz": header("Content-Type: text/plain"); header("Content-Encoding: gzip"); readfile("./$path"); From ac29097ce8585b99ebe7c5d9570b0567236d45f3 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 20 Dec 2017 22:27:43 -0500 Subject: [PATCH 0406/1891] Fix regression that stopped maintainers from pinning comments In commit 8c98db0b82cc85a4498589e5d60299fefd93b421 support was added for package co-maintainers to pin comments in addition to maintainers. Due to a typo, the SQL query was reset halfway through and only added the co-maintainer IDs to the list of allowed users. Fixes FS#56783. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index dbcf63e8..d022ebe5 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -100,7 +100,7 @@ function can_pin_comment($comment_id=0) { $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; $q.= "WHERE pc.ID = " . intval($comment_id) . " "; $q.= "UNION "; - $q = "SELECT pcm.UsersID FROM PackageComaintainers AS pcm "; + $q.= "SELECT pcm.UsersID FROM PackageComaintainers AS pcm "; $q.= "LEFT JOIN PackageComments AS pc "; $q.= "ON pcm.PackageBaseID = pc.PackageBaseID "; $q.= "WHERE pc.ID = " . intval($comment_id); From e5b43760c275130623ff4fda5a96f628cf17156e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sun, 21 Jan 2018 17:51:02 +0100 Subject: [PATCH 0407/1891] Move AUR_OVERWRITE privilege check from git/auth to git/update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git/auth is run as an AutherizedKeysCommand which does not get the environment variables passed to it, so AUR_OVERWRITE always got hard-set to '0' by it. Instead we need to perform the actual privilege check in git/update instead. Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- aurweb/git/auth.py | 1 - aurweb/git/update.py | 2 +- test/t1100-git-auth.sh | 17 ----------------- test/t1300-git-update.sh | 14 +++++++++++++- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/aurweb/git/auth.py b/aurweb/git/auth.py index b7819a95..828ed4e2 100755 --- a/aurweb/git/auth.py +++ b/aurweb/git/auth.py @@ -53,7 +53,6 @@ def main(): env_vars = { 'AUR_USER': user, 'AUR_PRIVILEGED': '1' if account_type > 1 else '0', - 'AUR_OVERWRITE' : os.environ.get('AUR_OVERWRITE', '0') if account_type > 1 else '0', } key = keytype + ' ' + keytext diff --git a/aurweb/git/update.py b/aurweb/git/update.py index f681ddb9..da48eb31 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -238,7 +238,7 @@ def main(): user = os.environ.get("AUR_USER") pkgbase = os.environ.get("AUR_PKGBASE") privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1') - allow_overwrite = (os.environ.get("AUR_OVERWRITE", '0') == '1') + allow_overwrite = (os.environ.get("AUR_OVERWRITE", '0') == '1') and privileged warn_or_die = warn if privileged else die if len(sys.argv) == 2 and sys.argv[1] == "restore": diff --git a/test/t1100-git-auth.sh b/test/t1100-git-auth.sh index dd20bea1..71d526f2 100755 --- a/test/t1100-git-auth.sh +++ b/test/t1100-git-auth.sh @@ -25,21 +25,4 @@ test_expect_success 'Test authentication with a wrong key.' ' test_must_be_empty out ' -test_expect_success 'Test AUR_OVERWRITE passthrough.' ' - AUR_OVERWRITE=1 \ - "$GIT_AUTH" "$AUTH_KEYTYPE_TU" "$AUTH_KEYTEXT_TU" >out && - grep -q AUR_OVERWRITE=1 out -' - -test_expect_success 'Make sure that AUR_OVERWRITE is unset by default.' ' - "$GIT_AUTH" "$AUTH_KEYTYPE_TU" "$AUTH_KEYTEXT_TU" >out && - grep -q AUR_OVERWRITE=0 out -' - -test_expect_success 'Make sure regular users cannot set AUR_OVERWRITE.' ' - AUR_OVERWRITE=1 \ - "$GIT_AUTH" "$AUTH_KEYTYPE_USER" "$AUTH_KEYTEXT_USER" >out && - grep -q AUR_OVERWRITE=0 out -' - test_done diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.sh index b9c4f53a..06d14984 100755 --- a/test/t1300-git-update.sh +++ b/test/t1300-git-update.sh @@ -137,7 +137,19 @@ test_expect_success 'Performing a non-fast-forward ref update as Trusted User.' test_cmp expected actual ' -test_expect_success 'Performing a non-fast-forward ref update with AUR_OVERWRITE=1.' ' +test_expect_success 'Performing a non-fast-forward ref update as normal user with AUR_OVERWRITE=1.' ' + old=$(git -C aur.git rev-parse HEAD) && + new=$(git -C aur.git rev-parse HEAD^) && + cat >expected <<-EOD && + error: denying non-fast-forward (you should pull first) + EOD + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 AUR_OVERWRITE=1 \ + "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 && + test_cmp expected actual +' + +test_expect_success 'Performing a non-fast-forward ref update as Trusted User with AUR_OVERWRITE=1.' ' old=$(git -C aur.git rev-parse HEAD) && new=$(git -C aur.git rev-parse HEAD^) && AUR_USER=tu AUR_PKGBASE=foobar AUR_PRIVILEGED=1 AUR_OVERWRITE=1 \ From 34a0d399103a3b866995e54f03ac75740fdd26a0 Mon Sep 17 00:00:00 2001 From: Remy Marquis Date: Sat, 6 Jan 2018 14:27:53 +0100 Subject: [PATCH 0408/1891] Document required PHP extensions in php.ini To people unfamiliar with the code, it is not obvious that the pdo_* PHP extensions must be enabled. Signed-off-by: Lukas Fleischer --- INSTALL | 2 ++ TESTING | 2 ++ 2 files changed, 4 insertions(+) diff --git a/INSTALL b/INSTALL index ba24a450..7fcf7246 100644 --- a/INSTALL +++ b/INSTALL @@ -38,6 +38,8 @@ read the instructions below. } } + Ensure to enable the pdo_mysql extension in php.ini. + 3) Copy conf/config.proto to /etc/aurweb/config and adjust the configuration (pay attention to disable_http_login, enable_maintenance and aur_location). diff --git a/TESTING b/TESTING index d2c97d9d..e45f35f7 100644 --- a/TESTING +++ b/TESTING @@ -13,6 +13,8 @@ INSTALL. # pacman -S php php-sqlite sqlite + Ensure to enable the pdo_sqlite extension in php.ini. + 3) Prepare the testing database: $ cd /path/to/aurweb/schema From f51d4c32cd8bed69d2f6b0c50424280613c68496 Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Wed, 21 Feb 2018 15:49:05 +0100 Subject: [PATCH 0409/1891] Remove disjunction in pkg_providers query For some reason, running the SELECT .. WHERE .. OR .. query takes e.g. 58ms on a randomly generated db for some dependency name. Splitting the OR into two dedicated queries and UNIONing the result takes only 0.42ms. On the Arch Linux installation, searching for the providers of e.g. mongodb takes >=110ms when not cached by the query cache. The new query takes <1ms even when not cached. Signed-off-by: Florian Pritz Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index d022ebe5..ad254746 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -212,10 +212,12 @@ function pkg_groups($pkgid) { function pkg_providers($name) { $dbh = DB::connect(); $q = "SELECT p.ID, p.Name FROM Packages p "; + $q.= "WHERE p.Name = " . $dbh->quote($name) . " "; + $q.= "UNION "; + $q.= "SELECT p.ID, p.Name FROM Packages p "; $q.= "LEFT JOIN PackageRelations pr ON pr.PackageID = p.ID "; $q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; - $q.= "WHERE p.Name = " . $dbh->quote($name) . " "; - $q.= "OR (rt.Name = 'provides' "; + $q.= "WHERE (rt.Name = 'provides' "; $q.= "AND pr.RelName = " . $dbh->quote($name) . ")"; $q.= "UNION "; $q.= "SELECT 0, Name FROM OfficialProviders "; From 27654afadb5088dda4eafd83f07410c2a48fa4b0 Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Thu, 1 Feb 2018 11:55:44 +0100 Subject: [PATCH 0410/1891] Add rate limit support to API This allows us to prevent users from hammering the API every few seconds to check if any of their packages were updated. Real world users check as often as every 5 or 10 seconds. Signed-off-by: Florian Pritz Signed-off-by: Lukas Fleischer --- conf/config.proto | 4 ++ schema/aur-schema.sql | 10 +++++ upgrading/4.7.0.txt | 11 +++++ web/lib/aurjson.class.php | 86 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 upgrading/4.7.0.txt diff --git a/conf/config.proto b/conf/config.proto index 17509299..934d3697 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -36,6 +36,10 @@ enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 render-comment-cmd = /usr/local/bin/aurweb-rendercomment +[ratelimit] +request_limit = 4000 +window_length = 86400 + [notifications] notify-cmd = /usr/local/bin/aurweb-notify sendmail = /usr/bin/sendmail diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index 45272bbe..79de3f27 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -399,3 +399,13 @@ CREATE TABLE AcceptedTerms ( FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, FOREIGN KEY (TermsID) REFERENCES Terms(ID) ON DELETE CASCADE ) ENGINE = InnoDB; + +-- Rate limits for API +-- +CREATE TABLE `ApiRateLimit` ( + IP VARCHAR(45) NOT NULL, + Requests INT(11) NOT NULL, + WindowStart BIGINT(20) NOT NULL, + PRIMARY KEY (`ip`) +) ENGINE = InnoDB; +CREATE INDEX ApiRateLimitWindowStart ON ApiRateLimit (WindowStart); diff --git a/upgrading/4.7.0.txt b/upgrading/4.7.0.txt new file mode 100644 index 00000000..820e4540 --- /dev/null +++ b/upgrading/4.7.0.txt @@ -0,0 +1,11 @@ +1. Add ApiRateLimit table: + +--- +CREATE TABLE `ApiRateLimit` ( + IP VARCHAR(45) NOT NULL, + Requests INT(11) NOT NULL, + WindowStart BIGINT(20) NOT NULL, + PRIMARY KEY (`ip`) +) ENGINE = InnoDB; +CREATE INDEX ApiRateLimitWindowStart ON ApiRateLimit (WindowStart); +--- diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 9eeaafde..b4cced04 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -96,6 +96,11 @@ class AurJSON { $this->dbh = DB::connect(); + if ($this->check_ratelimit($_SERVER['REMOTE_ADDR'])) { + header("HTTP/1.1 429 Too Many Requests"); + return $this->json_error('Rate limit reached'); + } + $type = str_replace('-', '_', $http_data['type']); if ($type == 'info' && $this->version >= 5) { $type = 'multiinfo'; @@ -130,6 +135,87 @@ class AurJSON { } } + /* + * Check if an IP needs to be rate limited. + * + * @param $ip IP of the current request + * + * @return true if IP needs to be rate limited, false otherwise. + */ + private function check_ratelimit($ip) { + $limit = config_get("ratelimit", "request_limit"); + if ($limit == 0) { + return false; + } + + $window_length = config_get("ratelimit", "window_length"); + $this->update_ratelimit($ip); + $stmt = $this->dbh->prepare(" + SELECT Requests FROM ApiRateLimit + WHERE IP = :ip"); + $stmt->bindParam(":ip", $ip); + $result = $stmt->execute(); + + if (!$result) { + return false; + } + + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if ($row['Requests'] > $limit) { + return true; + } + return false; + } + + /* + * Update a rate limit for an IP by increasing it's requests value by one. + * + * @param $ip IP of the current request + * + * @return void + */ + private function update_ratelimit($ip) { + $window_length = config_get("ratelimit", "window_length"); + $db_backend = config_get("database", "backend"); + $time = time(); + + // Clean up old windows + $deletion_time = $time - $window_length; + $stmt = $this->dbh->prepare(" + DELETE FROM ApiRateLimit + WHERE WindowStart < :time"); + $stmt->bindParam(":time", $deletion_time); + $stmt->execute(); + + if ($db_backend == "mysql") { + $stmt = $this->dbh->prepare(" + INSERT INTO ApiRateLimit + (IP, Requests, WindowStart) + VALUES (:ip, 1, :window_start) + ON DUPLICATE KEY UPDATE Requests=Requests+1"); + $stmt->bindParam(":ip", $ip); + $stmt->bindParam(":window_start", $time); + $stmt->execute(); + } elseif ($db_backend == "sqlite") { + $stmt = $this->dbh->prepare(" + INSERT OR IGNORE INTO ApiRateLimit + (IP, Requests, WindowStart) + VALUES (:ip, 0, :window_start);"); + $stmt->bindParam(":ip", $ip); + $stmt->bindParam(":window_start", $time); + $stmt->execute(); + + $stmt = $this->dbh->prepare(" + UPDATE ApiRateLimit + SET Requests = Requests + 1 + WHERE IP = :ip"); + $stmt->bindParam(":ip", $ip); + $stmt->execute(); + } else { + throw new RuntimeException("Unknown database backend"); + } + } + /* * Returns a JSON formatted error string. * From f15c700ad2ed2f5512a5574ab29f85c4848039e4 Mon Sep 17 00:00:00 2001 From: Mark Weiman Date: Mon, 5 Feb 2018 21:54:56 -0500 Subject: [PATCH 0411/1891] Add capability for co-maintainers to disown packages Implements FS#53832. Signed-off-by: Mark Weiman Signed-off-by: Lukas Fleischer --- web/html/pkgbase.php | 3 +++ web/html/pkgdisown.php | 13 ++++++++++--- web/lib/pkgbasefuncs.inc.php | 12 ++++++++++-- web/template/pkgbase_actions.php | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index 03b0eee4..cf9a6c60 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -60,6 +60,9 @@ if (check_token()) { $output = __("The selected packages have not been disowned, check the confirmation checkbox."); $ret = false; } + } elseif (current_action("do_DisownComaintainer")) { + $uid = uid_from_sid($_COOKIE["AURSID"]); + list($ret, $output) = pkgbase_remove_comaintainer($base_id, $uid); } elseif (current_action("do_Vote")) { list($ret, $output) = pkgbase_vote($ids, true); } elseif (current_action("do_UnVote")) { diff --git a/web/html/pkgdisown.php b/web/html/pkgdisown.php index 4b04e85e..8da08cfe 100644 --- a/web/html/pkgdisown.php +++ b/web/html/pkgdisown.php @@ -7,10 +7,13 @@ include_once("pkgfuncs.inc.php"); html_header(__("Disown Package")); +$action = "do_Disown"; + $maintainer_uids = array(pkgbase_maintainer_uid($base_id)); $comaintainers = pkgbase_get_comaintainers($base_id); +$comaintainer_uids = pkgbase_get_comaintainer_uids(array($base_id)); -if (has_credential(CRED_PKGBASE_DISOWN, $maintainer_uids)): ?> +if (has_credential(CRED_PKGBASE_DISOWN, array_merge($maintainer_uids, $comaintainer_uids))): ?>

    :

    @@ -23,7 +26,11 @@ if (has_credential(CRED_PKGBASE_DISOWN, $maintainer_uids)): ?>

    - 0 && !has_credential(CRED_PKGBASE_DISOWN)): ?> + + + + 0 && !has_credential(CRED_PKGBASE_DISOWN)): ?> ', $comaintainers[0], ''); ?> @@ -40,7 +47,7 @@ if (has_credential(CRED_PKGBASE_DISOWN, $maintainer_uids)): ?>

    " />

    +

    " />

    diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index ff1bc901..16f95dac 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -1158,11 +1158,12 @@ function pkgbase_get_comaintainer_uids($base_ids) { * * @param int $base_id The package base ID to update the co-maintainers of * @param array $users Array of co-maintainer user names + * @param boolean $override Override credential check if true * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_set_comaintainers($base_id, $users) { - if (!has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) { +function pkgbase_set_comaintainers($base_id, $users, $override=false) { + if (!$override && !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) { return array(false, __("You are not allowed to manage co-maintainers of this package base.")); } @@ -1213,3 +1214,10 @@ function pkgbase_set_comaintainers($base_id, $users) { return array(true, __("The package base co-maintainers have been updated.")); } + +function pkgbase_remove_comaintainer($base_id, $uid) { + $uname = username_from_id($uid); + $names = pkgbase_get_comaintainers($base_id); + $names = array_diff($names, array($uname)); + return pkgbase_set_comaintainers($base_id, $names, true); +} diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php index d3f05921..5eee5478 100644 --- a/web/template/pkgbase_actions.php +++ b/web/template/pkgbase_actions.php @@ -41,7 +41,7 @@
  • - +
  • From 1ff409874eda74dfc8c875e9fc1d0d512127746e Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Wed, 31 Jan 2018 20:54:14 +0100 Subject: [PATCH 0412/1891] RPC: Allow to search packages by "*depends" fields It is now possible to search for packages that depend on a given package, for instance: /rpc/?v=5&type=search&by=depends&arg=ocaml It is similarly possible to match on "makedepends", "checkdepends" and "optdepends". Signed-off-by: Baptiste Jonglez Signed-off-by: Lukas Fleischer --- doc/rpc.txt | 8 +++++++- web/lib/aurjson.class.php | 21 +++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/doc/rpc.txt b/doc/rpc.txt index f353ff01..3148ebea 100644 --- a/doc/rpc.txt +++ b/doc/rpc.txt @@ -11,6 +11,10 @@ search argument and _field_ is one of the following values: * `name` (search by package name only) * `name-desc` (search by package name and description) * `maintainer` (search by package maintainer) +* `depends` (search for packages that depend on _keywords_) +* `makedepends` (search for packages that makedepend on _keywords_) +* `optdepends` (search for packages that optdepend on _keywords_) +* `checkdepends` (search for packages that checkdepend on _keywords_) The _by_ parameter can be skipped and defaults to `name-desc`. @@ -30,7 +34,9 @@ Examples `search`:: `/rpc/?v=5&type=search&arg=foobar` `search` by maintainer:: - `/rpc/?v=5&type=search&search_by=maintainer&arg=john` + `/rpc/?v=5&type=search&by=maintainer&arg=john` +`search` packages that have _boost_ as `makedepends`:: + `/rpc/?v=5&type=search&by=makedepends&arg=boost` `search` with callback:: `/rpc/?v=5&type=search&arg=foobar&callback=jsonp1192244621103` `info`:: diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index b4cced04..c51e9c26 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -17,7 +17,11 @@ class AurJSON { 'suggest-pkgbase', 'get-comment-form' ); private static $exposed_fields = array( - 'name', 'name-desc', 'maintainer' + 'name', 'name-desc', 'maintainer', + 'depends', 'makedepends', 'checkdepends', 'optdepends' + ); + private static $exposed_depfields = array( + 'depends', 'makedepends', 'checkdepends', 'optdepends' ); private static $fields_v1 = array( 'Packages.ID', 'Packages.Name', @@ -329,7 +333,7 @@ class AurJSON { /* * Retrieve package information (used in info, multiinfo, search and - * msearch requests). + * depends requests). * * @param $type The request type. * @param $where_condition An SQL WHERE-condition to filter packages. @@ -493,6 +497,19 @@ class AurJSON { $keyword_string = $this->dbh->quote($keyword_string); $where_condition = "Users.Username = $keyword_string "; } + } else if (in_array($search_by, self::$exposed_depfields)) { + if (empty($keyword_string)) { + return $this->json_error('Query arg is empty.'); + } else { + $keyword_string = $this->dbh->quote($keyword_string); + $search_by = $this->dbh->quote($search_by); + $subquery = "SELECT PackageDepends.DepName FROM PackageDepends "; + $subquery .= "LEFT JOIN DependencyTypes "; + $subquery .= "ON PackageDepends.DepTypeID = DependencyTypes.ID "; + $subquery .= "WHERE PackageDepends.PackageID = Packages.ID "; + $subquery .= "AND DependencyTypes.Name = $search_by"; + $where_condition = "$keyword_string IN ($subquery)"; + } } return $this->process_query('search', $where_condition); From c3bca45973c8ec351f8b41421705dec7d7a620e2 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Wed, 28 Feb 2018 21:58:50 +0100 Subject: [PATCH 0413/1891] Remove unused variable $dbh in pkgbase_display_details Signed-off-by: Jelle van der Waa Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 16f95dac..72c33b6d 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -264,8 +264,6 @@ function pkgbase_get_details($base_id) { * @return void */ function pkgbase_display_details($base_id, $row, $SID="") { - $dbh = DB::connect(); - if (isset($row['error'])) { print "

    " . $row['error'] . "

    \n"; } From ca6332de6e33be645e1abab3434237805b8f7dfa Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Fri, 9 Mar 2018 23:42:51 +0100 Subject: [PATCH 0414/1891] Update cache code to INI style configuration Change the defines to config_get and add one cache option and one option to define memcache_servers. Mention the required dependency to get memcached working in the INSTALL file. Signed-off-by: Jelle van der Waa Signed-off-by: Lukas Fleischer --- INSTALL | 6 ++++++ conf/config.proto | 3 +++ web/lib/cachefuncs.inc.php | 10 +++------- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/INSTALL b/INSTALL index 7fcf7246..c72c4a2e 100644 --- a/INSTALL +++ b/INSTALL @@ -95,3 +95,9 @@ read the instructions below. } Sample systemd unit files for fcgiwrap can be found under conf/. + +10) If you want memcache to cache MySQL data. + + # pacman -S php-memcached + + And edit the configuration file to enabled memcache caching. diff --git a/conf/config.proto b/conf/config.proto index 934d3697..be37f430 100644 --- a/conf/config.proto +++ b/conf/config.proto @@ -35,6 +35,9 @@ snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 render-comment-cmd = /usr/local/bin/aurweb-rendercomment +# memcache or apc +cache = none +memcache_servers = 127.0.0.1:11211 [ratelimit] request_limit = 4000 diff --git a/web/lib/cachefuncs.inc.php b/web/lib/cachefuncs.inc.php index faeae5a2..881ad8f2 100644 --- a/web/lib/cachefuncs.inc.php +++ b/web/lib/cachefuncs.inc.php @@ -1,22 +1,18 @@ Date: Tue, 13 Mar 2018 21:04:31 +0100 Subject: [PATCH 0415/1891] notify: Send vote reminders to TUs that are also devs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 2d0f7575..693abffc 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -140,7 +140,7 @@ def get_request_recipients(conn, reqid): def get_tu_vote_reminder_recipients(conn, vote_id): cur = conn.execute('SELECT Email FROM Users ' + - 'WHERE AccountTypeID = 2 AND ID NOT IN ' + + 'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' + '(SELECT UserID FROM TU_Votes ' + 'WHERE TU_Votes.VoteID = ?)', [vote_id]) return [row[0] for row in cur.fetchall()] From 82ef1d09b9b3a480bcf6859004407c88ac86d250 Mon Sep 17 00:00:00 2001 From: nodivbyzero Date: Tue, 13 Mar 2018 20:11:09 +0000 Subject: [PATCH 0416/1891] TESTING: Add two required packages Signed-off-by: Lukas Fleischer --- TESTING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TESTING b/TESTING index e45f35f7..53ffef24 100644 --- a/TESTING +++ b/TESTING @@ -11,7 +11,7 @@ INSTALL. 2) Install php and necessary modules: - # pacman -S php php-sqlite sqlite + # pacman -S php php-sqlite sqlite words fortune-mod Ensure to enable the pdo_sqlite extension in php.ini. From bcd795c3399baf824c9f4d1c4d2e849e62777764 Mon Sep 17 00:00:00 2001 From: nodivbyzero Date: Tue, 13 Mar 2018 20:11:32 +0000 Subject: [PATCH 0417/1891] schema/Makefile: Replace MySQL with SQLite in comment Signed-off-by: Lukas Fleischer --- schema/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/schema/Makefile b/schema/Makefile index e0448add..62d08567 100644 --- a/schema/Makefile +++ b/schema/Makefile @@ -3,6 +3,7 @@ aur-schema-sqlite.sql: aur-schema.sql -e 's/ ENGINE = InnoDB//' \ -e 's/ [A-Z]* UNSIGNED NOT NULL AUTO_INCREMENT/ INTEGER NOT NULL/' \ -e 's/([0-9, ]*) UNSIGNED / UNSIGNED /' \ + -e 's/ MySQL / SQLite /' \ $< >$@ clean: From 3d90623154eeae9864e6d659d3d46f9774abb458 Mon Sep 17 00:00:00 2001 From: nodivbyzero Date: Fri, 16 Mar 2018 20:17:03 +0000 Subject: [PATCH 0418/1891] Terminate execution if config file is missing Signed-off-by: Lukas Fleischer --- web/lib/confparser.inc.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php index e7128be6..499481df 100644 --- a/web/lib/confparser.inc.php +++ b/web/lib/confparser.inc.php @@ -8,7 +8,11 @@ function config_load() { if (!$path) { $path = "/etc/aurweb/config"; } - $AUR_CONFIG = parse_ini_file($path, true, INI_SCANNER_RAW); + if (file_exists($path)) { + $AUR_CONFIG = parse_ini_file($path, true, INI_SCANNER_RAW); + } else { + die("aurweb config file not found"); + } } } From eccd328d428cbe1445118d24b1bf789c5b3b83c9 Mon Sep 17 00:00:00 2001 From: nodivbyzero Date: Tue, 20 Mar 2018 20:47:44 +0000 Subject: [PATCH 0419/1891] Handle empty resultset getting recent 10 packages Signed-off-by: Lukas Fleischer --- web/lib/stats.inc.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web/lib/stats.inc.php b/web/lib/stats.inc.php index 80619fe1..f5692f96 100644 --- a/web/lib/stats.inc.php +++ b/web/lib/stats.inc.php @@ -19,10 +19,12 @@ function updates_table() { $result = $dbh->query($q); $newest_packages = new ArrayObject(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $newest_packages->append($row); + if ($result) { + while ($row = $result->fetch(PDO::FETCH_ASSOC)) { + $newest_packages->append($row); + } + set_cache_value($key, $newest_packages); } - set_cache_value($key, $newest_packages); } include('stats/updates_table.php'); } From 2b280ea3d864d80da1a49c982867d261ec865e43 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 8 Apr 2018 09:33:32 +0200 Subject: [PATCH 0420/1891] Allow manual breaks and horizontal lines in comments When sanitizing rendered comments, keep
    tags and
    tags. The former are generated when using "---" in Markdown comments, the latter are used when putting two spaces at the end of a line. Fixes FS#56649. --- aurweb/scripts/rendercomment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 4b642273..5e18fd59 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -119,8 +119,8 @@ def main(): FlysprayLinksExtension(), GitCommitsExtension(pkgbase), HeadingExtension()]) - allowed_tags = bleach.sanitizer.ALLOWED_TAGS + \ - ['p', 'pre', 'h4', 'h5', 'h6'] + allowed_tags = (bleach.sanitizer.ALLOWED_TAGS + + ['p', 'pre', 'h4', 'h5', 'h6', 'br', 'hr']) html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) From 97c5bcec136eb549b57cdb74ebd9da7ca1338e90 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Sun, 15 Apr 2018 10:29:43 -0400 Subject: [PATCH 0421/1891] config: allow reading both the defaults file and the modified config In the process, rename config.proto to config.defaults (because that is what it is now). Also use dict.get('key', default_value) when querying os.environ, rather than an if block, as it is more pythonic/readable/concise, and reduces the number of dict lookups. This change allows aurweb configuration to be done via either: - copying config.defaults to config and modifying values - creating a new config only containing modified values, next to a config.defaults containing unmodified values The motivation for this change is to enable ansible configuration in our flagship deployment by storing only changed values, and deferring to config.defaults otherwise. A side benefit is, it is easier to see what has changed by inspecting only the site configuration file. If a config.defaults file does not exist next to $AUR_CONFIG or in $AUR_CONFIG_DEFAULTS, it is ignored and *all* values are expected to live in the modified config file. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- INSTALL | 6 ++++-- TESTING | 2 +- aurweb/config.py | 10 ++++++---- conf/{config.proto => config.defaults} | 0 web/lib/confparser.inc.php | 12 +++++++++++- 5 files changed, 22 insertions(+), 8 deletions(-) rename conf/{config.proto => config.defaults} (100%) diff --git a/INSTALL b/INSTALL index c72c4a2e..7170aea1 100644 --- a/INSTALL +++ b/INSTALL @@ -40,8 +40,10 @@ read the instructions below. Ensure to enable the pdo_mysql extension in php.ini. -3) Copy conf/config.proto to /etc/aurweb/config and adjust the configuration - (pay attention to disable_http_login, enable_maintenance and aur_location). +3) Optionally copy conf/config.defaults to /etc/aurweb/. Create or copy + /etc/aurweb/config (this is expected to contain all configuration settings + if the defaults file does not exist) and adjust the configuration (pay + attention to disable_http_login, enable_maintenance and aur_location). 4) Create a new MySQL database and a user and import the aurweb SQL schema: diff --git a/TESTING b/TESTING index 53ffef24..b0a5f628 100644 --- a/TESTING +++ b/TESTING @@ -23,7 +23,7 @@ INSTALL. $ sqlite3 ../aurweb.sqlite3 < aur-schema-sqlite.sql $ sqlite3 ../aurweb.sqlite3 < out.sql -4) Copy conf/config.proto to conf/config and adjust the configuration +4) Copy conf/config.defaults to conf/config and adjust the configuration (pay attention to disable_http_login, enable_maintenance and aur_location). Be sure to change backend to sqlite and name to the file location of your diff --git a/aurweb/config.py b/aurweb/config.py index a52d9422..52ec461e 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -8,11 +8,13 @@ def _get_parser(): global _parser if not _parser: + path = os.environ.get('AUR_CONFIG', '/etc/aurweb/config') + defaults = os.environ.get('AUR_CONFIG_DEFAULTS', path + '.defaults') + _parser = configparser.RawConfigParser() - if 'AUR_CONFIG' in os.environ: - path = os.environ.get('AUR_CONFIG') - else: - path = "/etc/aurweb/config" + if os.path.isfile(defaults): + with open(defaults) as f: + _parser.read_file(f) _parser.read(path) return _parser diff --git a/conf/config.proto b/conf/config.defaults similarity index 100% rename from conf/config.proto rename to conf/config.defaults diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php index 499481df..29f17e83 100644 --- a/web/lib/confparser.inc.php +++ b/web/lib/confparser.inc.php @@ -8,11 +8,21 @@ function config_load() { if (!$path) { $path = "/etc/aurweb/config"; } + $defaults_path = getenv('AUR_CONFIG_DEFAULTS'); + if (!$defaults_path) { + $defaults_path = path . ".defaults"; + } + if (file_exists($defaults_path)) { + $default_config = parse_ini_file($defaults_path, true, INI_SCANNER_RAW); + } else { + $default_config = []; + } if (file_exists($path)) { - $AUR_CONFIG = parse_ini_file($path, true, INI_SCANNER_RAW); + $config = parse_ini_file($path, true, INI_SCANNER_RAW); } else { die("aurweb config file not found"); } + $AUR_CONFIG = array_replace_recursive($default_config, $config) } } From 4381a0d7c23203d19d8c33afc6264fa584ba0a4f Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 1 May 2018 15:12:38 -0400 Subject: [PATCH 0422/1891] Update copyright year in the cgit footer template Four years just passed in the blink of an eye :) Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/template/cgit/footer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/cgit/footer.html b/web/template/cgit/footer.html index 36e0f1b1..6ceec289 100644 --- a/web/template/cgit/footer.html +++ b/web/template/cgit/footer.html @@ -1,6 +1,6 @@ From ce93360257f3b4ef60035a75708148fc814811c1 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 10 May 2018 21:38:25 +0200 Subject: [PATCH 0423/1891] Erase login IP addresses after seven days Add a script to periodically remove old IP addresses from the users database. The login IP addresses are stored for spam protection and to prevent from abuse. It is quite unlikely that we ever need the IP address of a user whose last login is more than a week old. It makes sense to remove such IP addresses to protect our users' privacy. Signed-off-by: Lukas Fleischer --- aurweb/scripts/usermaint.py | 22 +++++++++++++++++ setup.py | 1 + test/setup.sh | 1 + test/t2700-usermaint.sh | 49 +++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100755 aurweb/scripts/usermaint.py create mode 100755 test/t2700-usermaint.sh diff --git a/aurweb/scripts/usermaint.py b/aurweb/scripts/usermaint.py new file mode 100755 index 00000000..1621d410 --- /dev/null +++ b/aurweb/scripts/usermaint.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import time + +import aurweb.db + + +def main(): + conn = aurweb.db.Connection() + + limit_to = int(time.time()) - 86400 * 7 + conn.execute("UPDATE Users SET LastLoginIPAddress = NULL " + + "WHERE LastLogin < ?", [limit_to]) + conn.execute("UPDATE Users SET LastSSHLoginIPAddress = NULL " + + "WHERE LastSSHLogin < ?", [limit_to]) + + conn.commit() + conn.close() + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index 9d10cc1c..ca26f0d8 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ setup( 'aurweb-popupdate = aurweb.scripts.popupdate:main', 'aurweb-rendercomment = aurweb.scripts.rendercomment:main', 'aurweb-tuvotereminder = aurweb.scripts.tuvotereminder:main', + 'aurweb-usermaint = aurweb.scripts.usermaint:main', ], }, ) diff --git a/test/setup.sh b/test/setup.sh index d98c49c6..5e10fec8 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -14,6 +14,7 @@ GIT_UPDATE="$TOPLEVEL/aurweb/git/update.py" MKPKGLISTS="$TOPLEVEL/aurweb/scripts/mkpkglists.py" TUVOTEREMINDER="$TOPLEVEL/aurweb/scripts/tuvotereminder.py" PKGMAINT="$TOPLEVEL/aurweb/scripts/pkgmaint.py" +USERMAINT="$TOPLEVEL/aurweb/scripts/usermaint.py" AURBLUP="$TOPLEVEL/aurweb/scripts/aurblup.py" NOTIFY="$TOPLEVEL/aurweb/scripts/notify.py" RENDERCOMMENT="$TOPLEVEL/aurweb/scripts/rendercomment.py" diff --git a/test/t2700-usermaint.sh b/test/t2700-usermaint.sh new file mode 100755 index 00000000..4f625142 --- /dev/null +++ b/test/t2700-usermaint.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='usermaint tests' + +. ./setup.sh + +test_expect_success 'Test removal of login IP addresses.' ' + now=$(date -d now +%s) && + threedaysago=$(date -d "3 days ago" +%s) && + tendaysago=$(date -d "10 days ago" +%s) && + cat <<-EOD | sqlite3 aur.db && + UPDATE Users SET LastLogin = $threedaysago, LastLoginIPAddress = "1.2.3.4" WHERE ID = 1; + UPDATE Users SET LastLogin = $tendaysago, LastLoginIPAddress = "2.3.4.5" WHERE ID = 2; + UPDATE Users SET LastLogin = $now, LastLoginIPAddress = "3.4.5.6" WHERE ID = 3; + UPDATE Users SET LastLogin = 0, LastLoginIPAddress = "4.5.6.7" WHERE ID = 4; + UPDATE Users SET LastLogin = 0, LastLoginIPAddress = "5.6.7.8" WHERE ID = 5; + UPDATE Users SET LastLogin = $tendaysago, LastLoginIPAddress = "6.7.8.9" WHERE ID = 6; + EOD + "$USERMAINT" && + cat <<-EOD >expected && + 1.2.3.4 + 3.4.5.6 + EOD + echo "SELECT LastLoginIPAddress FROM Users WHERE LastLoginIPAddress IS NOT NULL;" | sqlite3 aur.db >actual && + test_cmp actual expected +' + +test_expect_success 'Test removal of SSH login IP addresses.' ' + now=$(date -d now +%s) && + threedaysago=$(date -d "3 days ago" +%s) && + tendaysago=$(date -d "10 days ago" +%s) && + cat <<-EOD | sqlite3 aur.db && + UPDATE Users SET LastSSHLogin = $now, LastSSHLoginIPAddress = "1.2.3.4" WHERE ID = 1; + UPDATE Users SET LastSSHLogin = $threedaysago, LastSSHLoginIPAddress = "2.3.4.5" WHERE ID = 2; + UPDATE Users SET LastSSHLogin = $tendaysago, LastSSHLoginIPAddress = "3.4.5.6" WHERE ID = 3; + UPDATE Users SET LastSSHLogin = 0, LastSSHLoginIPAddress = "4.5.6.7" WHERE ID = 4; + UPDATE Users SET LastSSHLogin = 0, LastSSHLoginIPAddress = "5.6.7.8" WHERE ID = 5; + UPDATE Users SET LastSSHLogin = $tendaysago, LastSSHLoginIPAddress = "6.7.8.9" WHERE ID = 6; + EOD + "$USERMAINT" && + cat <<-EOD >expected && + 1.2.3.4 + 2.3.4.5 + EOD + echo "SELECT LastSSHLoginIPAddress FROM Users WHERE LastSSHLoginIPAddress IS NOT NULL;" | sqlite3 aur.db >actual && + test_cmp actual expected +' + +test_done From 0ffa0679d214016511d07509774fcab5f3c56687 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 10 May 2018 17:17:05 -0400 Subject: [PATCH 0424/1891] Use a link to accept orphan requests Currently, a form is used instead of a link. This forwards to a confirmation page, and currently drops the "via" parameter in the process. As a result, accepted orphan requests usually show: Request #XXXXXX has been accepted automatically by the Arch User Repository package request system: The user YYYYYYY disowned the package. This is wrong, and should show (will show, if you manually add it or use the close button instead of the accept button): Request #XXXXXX has been rejected by YYYYYYY [1]: Fixes FS#56606. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/template/pkgreq_results.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index fb49dfae..3c824c0d 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -82,11 +82,7 @@
    -
    - - - -
    + ()
    From ad9422ca19d29089ab934e079c65a4614ace26a1 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 May 2018 12:25:21 +0200 Subject: [PATCH 0425/1891] confparser.inc.php: Add missing semicolon Fixes a regression introduced in 97c5bce (config: allow reading both the defaults file and the modified config, 2018-04-15). Signed-off-by: Lukas Fleischer --- web/lib/confparser.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php index 29f17e83..cb51e02a 100644 --- a/web/lib/confparser.inc.php +++ b/web/lib/confparser.inc.php @@ -22,7 +22,7 @@ function config_load() { } else { die("aurweb config file not found"); } - $AUR_CONFIG = array_replace_recursive($default_config, $config) + $AUR_CONFIG = array_replace_recursive($default_config, $config); } } From 5c48302aaf3e8ca9cde07fb59afdc426d83dff34 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 May 2018 12:25:21 +0200 Subject: [PATCH 0426/1891] confparser.inc.php: Add missing dollar sign Fixes a regression introduced in 97c5bce (config: allow reading both the defaults file and the modified config, 2018-04-15). Signed-off-by: Lukas Fleischer --- web/lib/confparser.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php index cb51e02a..1152e132 100644 --- a/web/lib/confparser.inc.php +++ b/web/lib/confparser.inc.php @@ -10,7 +10,7 @@ function config_load() { } $defaults_path = getenv('AUR_CONFIG_DEFAULTS'); if (!$defaults_path) { - $defaults_path = path . ".defaults"; + $defaults_path = $path . ".defaults"; } if (file_exists($defaults_path)) { $default_config = parse_ini_file($defaults_path, true, INI_SCANNER_RAW); From 8838490665c1bc7f682a4853be18c2b758328fb0 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 May 2018 12:31:42 +0200 Subject: [PATCH 0427/1891] Add newline after accept link for orphan requests Fixes a regression introduced in 0ffa067 (Use a link to accept orphan requests, 2018-05-10). Signed-off-by: Lukas Fleischer --- web/template/pkgreq_results.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index 3c824c0d..e02cff3e 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -77,16 +77,14 @@ -
    -
    () -
    +
    From 4b8b2e3eb139518ea1abd5875135bb39a9f0c187 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 12 May 2018 13:35:11 +0200 Subject: [PATCH 0428/1891] Stop using each() The each() function has been deprecated as of PHP 7.2.0. Use foreach loops instead. Signed-off-by: Lukas Fleischer --- web/html/rss.php | 2 +- web/html/voters.php | 4 ++-- web/template/account_edit_form.php | 4 ++-- web/template/account_search_results.php | 12 ++++++------ web/template/pkg_comments.php | 4 ++-- web/template/pkg_details.php | 12 ++++++------ web/template/pkg_search_results.php | 4 ++-- web/template/pkgbase_details.php | 4 ++-- web/template/pkgreq_results.php | 4 ++-- web/template/tu_last_votes_list.php | 4 ++-- web/template/tu_list.php | 4 ++-- 11 files changed, 29 insertions(+), 29 deletions(-) diff --git a/web/html/rss.php b/web/html/rss.php index 8585d81d..d6e7825a 100644 --- a/web/html/rss.php +++ b/web/html/rss.php @@ -40,7 +40,7 @@ $rss->image = $image; #Get the latest packages and add items for them $packages = latest_pkgs(20); -while (list($indx, $row) = each($packages)) { +foreach ($packages as $indx => $row) { $item = new FeedItem(); $item->title = $row["Name"]; $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); diff --git a/web/html/voters.php b/web/html/voters.php index 997186d8..bacbcfc8 100644 --- a/web/html/voters.php +++ b/web/html/voters.php @@ -16,14 +16,14 @@ if (has_credential(CRED_PKGBASE_LIST_VOTERS)):

    Votes for

      - + $row): ?>
    • 0): ?> ()
    • - +
    diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 833e74a8..6eff81bd 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -122,7 +122,7 @@ $val) { if ($TZ == $key) { print "\n"; } else { diff --git a/web/template/account_search_results.php b/web/template/account_search_results.php index 43f2d1d6..81cd8185 100644 --- a/web/template/account_search_results.php +++ b/web/template/account_search_results.php @@ -18,7 +18,7 @@ else: $row): if ($i % 2): $c = "even"; else: @@ -51,7 +51,7 @@ else: @@ -64,10 +64,10 @@ else: $ind): ?> - + " /> @@ -79,10 +79,10 @@ else: $ind): ?> - + -->" /> diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 7d9bedcc..3e5e5cc5 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -15,7 +15,7 @@ if (!isset($count)) { - + $row): ?>
    - + 10 && !isset($_GET['comments']) && !isset($pinned)): ?>

    diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 8a934173..650c245c 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -276,9 +276,9 @@ endif;

    0): ?>
      - + $darr): ?>
    • - +
    @@ -286,9 +286,9 @@ endif;

    0): ?>
      - + $darr): ?>
    • - +
    @@ -298,9 +298,9 @@ endif; 0): ?>
      - + $src): ?>
    • - +
    diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index d7512b1e..7c5ad03b 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -66,7 +66,7 @@ if (!$result): ?> - + $row): ?> ]" value="1" /> @@ -100,7 +100,7 @@ if (!$result): ?> - + diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index de55da03..8a6e2b44 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -126,10 +126,10 @@ endif; 0): ?>
      $pkg): ?>
    • - +
    diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php index e02cff3e..1a565c3e 100644 --- a/web/template/pkgreq_results.php +++ b/web/template/pkgreq_results.php @@ -36,7 +36,7 @@ - + $row): ?> $idle_time); @@ -100,7 +100,7 @@ - + diff --git a/web/template/tu_last_votes_list.php b/web/template/tu_last_votes_list.php index 5cff248c..6e852581 100644 --- a/web/template/tu_last_votes_list.php +++ b/web/template/tu_last_votes_list.php @@ -11,7 +11,7 @@ - $row): if ($indx % 2): $c = "even"; else: @@ -28,7 +28,7 @@ diff --git a/web/template/tu_list.php b/web/template/tu_list.php index b7253f98..204c89ea 100644 --- a/web/template/tu_list.php +++ b/web/template/tu_list.php @@ -26,7 +26,7 @@ - + $row): ?> - + From 7e452fdfb02ace8c207af0a6a5c7d7d184b7593a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 16 May 2018 17:57:08 +0200 Subject: [PATCH 0429/1891] notify.py: Do not add stray newlines Make sure we are consistent with not adding newlines at the end of notification emails. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 693abffc..4fed6ad0 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -35,7 +35,7 @@ def send_notification(to, subject, body, refs, headers={}): if refs: body = wrapped + '\n' + refs else: - body = wrapped + body = wrapped.rstrip() for recipient in to: msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') @@ -304,7 +304,7 @@ def comaintainer_add(conn, pkgbase_id, uid): subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase) body = 'You were added to the co-maintainer list of %s [1].' % (pkgbase) - refs = '[1] ' + pkgbase_uri + '\n' + refs = '[1] ' + pkgbase_uri send_notification(to, subject, body, refs) @@ -318,7 +318,7 @@ def comaintainer_remove(conn, pkgbase_id, uid): subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase) body = ('You were removed from the co-maintainer list of %s [1].' % (pkgbase)) - refs = '[1] ' + pkgbase_uri + '\n' + refs = '[1] ' + pkgbase_uri send_notification(to, subject, body, refs) @@ -378,7 +378,7 @@ def request_open(conn, uid, reqid, reqtype, pkgbase_id, merge_into=None): (user, reqtype, pkgbase) body += '\n\n' + text refs = '[1] ' + user_uri + '\n' - refs += '[2] ' + pkgbase_uri + '\n' + refs += '[2] ' + pkgbase_uri thread_id = '' # Use a deterministic Message-ID for the first email referencing a request. headers = headers_msgid(thread_id) From fec253a65de91e0790f818dde162c80186a092f8 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Wed, 16 May 2018 17:57:34 +0200 Subject: [PATCH 0430/1891] t2500: Add test cases for all notifications Check that for all kinds of notifications, the generated messages match what we expect. Signed-off-by: Lukas Fleischer --- test/t2500-notify.sh | 350 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 348 insertions(+), 2 deletions(-) diff --git a/test/t2500-notify.sh b/test/t2500-notify.sh index 39976820..46c2753e 100755 --- a/test/t2500-notify.sh +++ b/test/t2500-notify.sh @@ -6,7 +6,7 @@ test_description='notify tests' test_expect_success 'Test out-of-date notifications.' ' cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, 0, 0, ""); + INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, 0, 0, "This is a test OOD comment."); INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (2, "foobar2", 2, 0, 0, ""); INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (3, "foobar3", NULL, 0, 0, ""); INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (4, "foobar4", 1, 0, 0, ""); @@ -27,7 +27,353 @@ test_expect_success 'Test out-of-date notifications.' ' To: user@localhost EOD grep "^\(Subject\|To\)" sendmail.out >sendmail.parts && - test_cmp sendmail.parts expected + test_cmp sendmail.parts expected && + cat <<-EOD | sqlite3 aur.db + DELETE FROM PackageComaintainers; + EOD +' + +test_expect_success 'Test subject and body of reset key notifications.' ' + cat <<-EOD | sqlite3 aur.db && + UPDATE Users SET ResetKey = "12345678901234567890123456789012" WHERE ID = 1; + EOD + >sendmail.out && + "$NOTIFY" send-resetkey 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Password Reset + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + A password reset request was submitted for the account user associated + with your email address. If you wish to reset your password follow the + link [1] below, otherwise ignore this message and nothing will happen. + + [1] https://aur.archlinux.org/passreset/?resetkey=12345678901234567890123456789012 + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of welcome notifications.' ' + cat <<-EOD | sqlite3 aur.db && + UPDATE Users SET ResetKey = "12345678901234567890123456789012" WHERE ID = 1; + EOD + >sendmail.out && + "$NOTIFY" welcome 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: Welcome to the Arch User Repository + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + Welcome to the Arch User Repository! In order to set an initial + password for your new account, please click the link [1] below. If the + link does not work, try copying and pasting it into your browser. + + [1] https://aur.archlinux.org/passreset/?resetkey=12345678901234567890123456789012 + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of comment notifications.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageComments (ID, PackageBaseID, UsersID, Comments, RenderedComment) VALUES (1, 1, 1, "This is a test comment.", "This is a test comment."); + INSERT INTO PackageNotifications (PackageBaseID, UserID) VALUES (1, 2); + UPDATE Users SET CommentNotify = 1 WHERE ID = 2; + EOD + >sendmail.out && + "$NOTIFY" comment 1 1 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Comment for foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + user [1] added the following comment to foobar [2]: + + This is a test comment. + + If you no longer wish to receive notifications about this package, + please go to the package page [2] and select "Disable notifications". + + [1] https://aur.archlinux.org/account/user/ + [2] https://aur.archlinux.org/pkgbase/foobar/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of update notifications.' ' + cat <<-EOD | sqlite3 aur.db && + UPDATE Users SET UpdateNotify = 1 WHERE ID = 2; + EOD + >sendmail.out && + "$NOTIFY" update 1 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Package Update: foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + user [1] pushed a new commit to foobar [2]. + + If you no longer wish to receive notifications about this package, + please go to the package page [2] and select "Disable notifications". + + [1] https://aur.archlinux.org/account/user/ + [2] https://aur.archlinux.org/pkgbase/foobar/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of out-of-date notifications.' ' + >sendmail.out && + "$NOTIFY" flag 1 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Out-of-date Notification for foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + Your package foobar [1] has been flagged out-of-date by user [2]: + + This is a test OOD comment. + + [1] https://aur.archlinux.org/pkgbase/foobar/ + [2] https://aur.archlinux.org/account/user/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of adopt notifications.' ' + >sendmail.out && + "$NOTIFY" adopt 1 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Ownership Notification for foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + The package foobar [1] was adopted by user [2]. + + [1] https://aur.archlinux.org/pkgbase/foobar/ + [2] https://aur.archlinux.org/account/user/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of co-maintainer addition notifications.' ' + >sendmail.out && + "$NOTIFY" comaintainer-add 1 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Co-Maintainer Notification for foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + You were added to the co-maintainer list of foobar [1]. + + [1] https://aur.archlinux.org/pkgbase/foobar/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of co-maintainer removal notifications.' ' + >sendmail.out && + "$NOTIFY" comaintainer-remove 1 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Co-Maintainer Notification for foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + You were removed from the co-maintainer list of foobar [1]. + + [1] https://aur.archlinux.org/pkgbase/foobar/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of delete notifications.' ' + >sendmail.out && + "$NOTIFY" delete 1 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Package deleted: foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + user [1] deleted foobar [2]. + + You will no longer receive notifications about this package. + + [1] https://aur.archlinux.org/account/user/ + [2] https://aur.archlinux.org/pkgbase/foobar/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of merge notifications.' ' + >sendmail.out && + "$NOTIFY" delete 1 1 2 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: AUR Package deleted: foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + user [1] merged foobar [2] into foobar2 [3]. + + If you no longer wish receive notifications about the new package, + please go to [3] and click "Disable notifications". + + [1] https://aur.archlinux.org/account/user/ + [2] https://aur.archlinux.org/pkgbase/foobar/ + [3] https://aur.archlinux.org/pkgbase/foobar2/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of request open notifications.' ' + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageRequests (ID, PackageBaseID, PackageBaseName, UsersID, ReqTypeID, Comments, ClosureComment) VALUES (1, 1, "foobar", 1, 1, "This is a request test comment.", ""); + EOD + >sendmail.out && + "$NOTIFY" request-open 1 1 orphan 1 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: [PRQ#1] Orphan Request for foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + user [1] filed a orphan request for foobar [2]: + + This is a request test comment. + + [1] https://aur.archlinux.org/account/user/ + [2] https://aur.archlinux.org/pkgbase/foobar/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of request open notifications for merge requests.' ' + >sendmail.out && + "$NOTIFY" request-open 1 1 merge 1 foobar2 && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: [PRQ#1] Merge Request for foobar + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + user [1] filed a request to merge foobar [2] into foobar2 [3]: + + This is a request test comment. + + [1] https://aur.archlinux.org/account/user/ + [2] https://aur.archlinux.org/pkgbase/foobar/ + [3] https://aur.archlinux.org/pkgbase/foobar2/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of request close notifications.' ' + >sendmail.out && + "$NOTIFY" request-close 1 1 accepted && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: [PRQ#1] Request Accepted + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + Request #1 has been accepted by user [1]. + + [1] https://aur.archlinux.org/account/user/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of request close notifications (auto-accept).' ' + >sendmail.out && + "$NOTIFY" request-close 0 1 accepted && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: [PRQ#1] Request Accepted + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + Request #1 has been accepted automatically by the Arch User Repository + package request system. + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of request close notifications with closure comment.' ' + cat <<-EOD | sqlite3 aur.db && + UPDATE PackageRequests SET ClosureComment = "This is a test closure comment." WHERE ID = 1; + EOD + >sendmail.out && + "$NOTIFY" request-close 1 1 accepted && + grep ^Subject: sendmail.out >actual && + cat <<-EOD >expected && + Subject: [PRQ#1] Request Accepted + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + Request #1 has been accepted by user [1]: + + This is a test closure comment. + + [1] https://aur.archlinux.org/account/user/ + EOD + test_cmp actual expected +' + +test_expect_success 'Test subject and body of TU vote reminders.' ' + >sendmail.out && + "$NOTIFY" tu-vote-reminder 1 && + grep ^Subject: sendmail.out | head -1 >actual && + cat <<-EOD >expected && + Subject: TU Vote Reminder: Proposal 1 + EOD + test_cmp actual expected && + sed -n "/^\$/,\$p" sendmail.out | head -4 | base64 -d >actual && + echo >>actual && + cat <<-EOD >expected && + Please remember to cast your vote on proposal 1 [1]. The voting period + ends in less than 48 hours. + + [1] https://aur.archlinux.org/tu/?id=1 + EOD + test_cmp actual expected ' test_done From f3b4c5c6bc6cd1f7320505ca725c46c78e1362f3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 17 May 2018 19:49:34 +0200 Subject: [PATCH 0431/1891] Refactor the notification script Reimplement most of the notification script logic. Create a separate class for each notification type. Each class provides methods for generating the list of recipients, the message subject, the message body, the references to add at the end of the message and the message headers. Additionally, a method for sending notification emails is provided. One major benefit of the new implementation is that both the generation of recipients and message contents are much more flexible. For example, it is now easily possible to make user-specific adjustments to every single notification of a batch. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 822 ++++++++++++++++++++------------------- 1 file changed, 429 insertions(+), 393 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 4fed6ad0..a6370133 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -9,11 +9,6 @@ import aurweb.config import aurweb.db aur_location = aurweb.config.get('options', 'aur_location') -aur_request_ml = aurweb.config.get('options', 'aur_request_ml') - -sendmail = aurweb.config.get('notifications', 'sendmail') -sender = aurweb.config.get('notifications', 'sender') -reply_to = aurweb.config.get('notifications', 'reply-to') def headers_cc(cclist): @@ -28,29 +23,6 @@ def headers_reply(thread_id): return {'In-Reply-To': thread_id, 'References': thread_id} -def send_notification(to, subject, body, refs, headers={}): - wrapped = '' - for line in body.splitlines(): - wrapped += textwrap.fill(line, break_long_words=False) + '\n' - if refs: - body = wrapped + '\n' + refs - else: - body = wrapped.rstrip() - - for recipient in to: - msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') - msg['Subject'] = subject - msg['From'] = sender - msg['Reply-to'] = reply_to - msg['To'] = recipient - - for key, value in headers.items(): - msg[key] = value - - p = subprocess.Popen([sendmail, '-t', '-oi'], stdin=subprocess.PIPE) - p.communicate(msg.as_bytes()) - - def username_from_id(conn, uid): cur = conn.execute('SELECT UserName FROM Users WHERE ID = ?', [uid]) return cur.fetchone()[0] @@ -73,380 +45,444 @@ def get_user_email(conn, uid): return cur.fetchone()[0] -def get_flag_recipients(conn, pkgbase_id): - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'LEFT JOIN PackageComaintainers ' + - 'ON PackageComaintainers.UsersID = Users.ID ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.MaintainerUID = Users.ID OR ' + - 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + - 'WHERE PackageBases.ID = ?', [pkgbase_id]) - return [row[0] for row in cur.fetchall()] - - -def get_recipients(conn, pkgbase_id, uid): - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', - [uid, pkgbase_id]) - return [row[0] for row in cur.fetchall()] - - -def get_comment_recipients(conn, pkgbase_id, uid): - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.CommentNotify = 1 AND ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', - [uid, pkgbase_id]) - return [row[0] for row in cur.fetchall()] - - -def get_update_recipients(conn, pkgbase_id, uid): - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.UpdateNotify = 1 AND ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', - [uid, pkgbase_id]) - return [row[0] for row in cur.fetchall()] - - -def get_ownership_recipients(conn, pkgbase_id, uid): - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.OwnershipNotify = 1 AND ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', - [uid, pkgbase_id]) - return [row[0] for row in cur.fetchall()] - - -def get_request_recipients(conn, reqid): - cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + - 'INNER JOIN Users ' + - 'ON Users.ID = PackageRequests.UsersID ' + - 'OR Users.ID = PackageBases.MaintainerUID ' + - 'WHERE PackageRequests.ID = ?', [reqid]) - return [row[0] for row in cur.fetchall()] - - -def get_tu_vote_reminder_recipients(conn, vote_id): - cur = conn.execute('SELECT Email FROM Users ' + - 'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' + - '(SELECT UserID FROM TU_Votes ' + - 'WHERE TU_Votes.VoteID = ?)', [vote_id]) - return [row[0] for row in cur.fetchall()] - - -def get_comment(conn, comment_id): - cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', - [comment_id]) - return cur.fetchone()[0] - - -def get_flagger_comment(conn, pkgbase_id): - cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ID = ?', - [pkgbase_id]) - return cur.fetchone()[0] - - -def get_request_comment(conn, reqid): - cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?', - [reqid]) - return cur.fetchone()[0] - - -def get_request_closure_comment(conn, reqid): - cur = conn.execute('SELECT ClosureComment FROM PackageRequests ' + - 'WHERE ID = ?', [reqid]) - return cur.fetchone()[0] - - -def send_resetkey(conn, uid): - cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' + - 'WHERE ID = ?', [uid]) - username, to, resetkey = cur.fetchone() - - subject = 'AUR Password Reset' - body = 'A password reset request was submitted for the account %s ' \ - 'associated with your email address. If you wish to reset your ' \ - 'password follow the link [1] below, otherwise ignore this ' \ - 'message and nothing will happen.' % (username) - refs = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey - - send_notification([to], subject, body, refs) - - -def welcome(conn, uid): - cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' + - 'WHERE ID = ?', [uid]) - username, to, resetkey = cur.fetchone() - - subject = 'Welcome to the Arch User Repository' - body = 'Welcome to the Arch User Repository! In order to set an initial ' \ - 'password for your new account, please click the link [1] below. ' \ - 'If the link does not work, try copying and pasting it into your ' \ - 'browser.' - refs = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey - - send_notification([to], subject, body, refs) - - -def comment(conn, uid, pkgbase_id, comment_id): - user = username_from_id(conn, uid) - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = get_comment_recipients(conn, pkgbase_id, uid) - text = get_comment(conn, comment_id) - - user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = 'AUR Comment for %s' % (pkgbase) - body = '%s [1] added the following comment to %s [2]:' % (user, pkgbase) - body += '\n\n' + text + '\n\n' - body += 'If you no longer wish to receive notifications about this ' \ - 'package, please go to the package page [2] and select "%s".' % \ - ('Disable notifications') - refs = '[1] ' + user_uri + '\n' - refs += '[2] ' + pkgbase_uri - thread_id = '' - headers = headers_reply(thread_id) - - send_notification(to, subject, body, refs, headers) - - -def update(conn, uid, pkgbase_id): - user = username_from_id(conn, uid) - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = get_update_recipients(conn, pkgbase_id, uid) - - user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = 'AUR Package Update: %s' % (pkgbase) - body = '%s [1] pushed a new commit to %s [2].' % (user, pkgbase) - body += '\n\n' - body += 'If you no longer wish to receive notifications about this ' \ - 'package, please go to the package page [2] and select "%s".' % \ - ('Disable notifications') - refs = '[1] ' + user_uri + '\n' - refs += '[2] ' + pkgbase_uri - thread_id = '' - headers = headers_reply(thread_id) - - send_notification(to, subject, body, refs, headers) - - -def flag(conn, uid, pkgbase_id): - user = username_from_id(conn, uid) - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = get_flag_recipients(conn, pkgbase_id) - text = get_flagger_comment(conn, pkgbase_id) - - user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = 'AUR Out-of-date Notification for %s' % (pkgbase) - body = 'Your package %s [1] has been flagged out-of-date by %s [2]:' % \ - (pkgbase, user) - body += '\n\n' + text - refs = '[1] ' + pkgbase_uri + '\n' - refs += '[2] ' + user_uri - - send_notification(to, subject, body, refs) - - -def adopt(conn, pkgbase_id, uid): - user = username_from_id(conn, uid) - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = get_ownership_recipients(conn, pkgbase_id, uid) - - user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = 'AUR Ownership Notification for %s' % (pkgbase) - body = 'The package %s [1] was adopted by %s [2].' % (pkgbase, user) - refs = '[1] ' + pkgbase_uri + '\n' - refs += '[2] ' + user_uri - - send_notification(to, subject, body, refs) - - -def disown(conn, pkgbase_id, uid): - user = username_from_id(conn, uid) - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = get_ownership_recipients(conn, pkgbase_id, uid) - - user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = 'AUR Ownership Notification for %s' % (pkgbase) - body = 'The package %s [1] was disowned by %s [2].' % (pkgbase, user) - refs = '[1] ' + pkgbase_uri + '\n' - refs += '[2] ' + user_uri - - send_notification(to, subject, body, refs) - - -def comaintainer_add(conn, pkgbase_id, uid): - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = [get_user_email(conn, uid)] - - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase) - body = 'You were added to the co-maintainer list of %s [1].' % (pkgbase) - refs = '[1] ' + pkgbase_uri - - send_notification(to, subject, body, refs) - - -def comaintainer_remove(conn, pkgbase_id, uid): - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = [get_user_email(conn, uid)] - - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase) - body = ('You were removed from the co-maintainer list of %s [1].' % - (pkgbase)) - refs = '[1] ' + pkgbase_uri - - send_notification(to, subject, body, refs) - - -def delete(conn, uid, old_pkgbase_id, new_pkgbase_id=None): - user = username_from_id(conn, uid) - old_pkgbase = pkgbase_from_id(conn, old_pkgbase_id) - if new_pkgbase_id: - new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id) - to = get_recipients(conn, old_pkgbase_id, uid) - - user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + old_pkgbase + '/' - - subject = 'AUR Package deleted: %s' % (old_pkgbase) - if new_pkgbase_id: - new_pkgbase_uri = aur_location + '/pkgbase/' + new_pkgbase + '/' - body = '%s [1] merged %s [2] into %s [3].\n\n' \ - 'If you no longer wish receive notifications about the new ' \ - 'package, please go to [3] and click "%s".' %\ - (user, old_pkgbase, new_pkgbase, 'Disable notifications') - refs = '[1] ' + user_uri + '\n' - refs += '[2] ' + pkgbase_uri + '\n' - refs += '[3] ' + new_pkgbase_uri - else: - body = '%s [1] deleted %s [2].\n\n' \ - 'You will no longer receive notifications about this ' \ - 'package.' % (user, old_pkgbase) - refs = '[1] ' + user_uri + '\n' - refs += '[2] ' + pkgbase_uri - - send_notification(to, subject, body, refs) - - -def request_open(conn, uid, reqid, reqtype, pkgbase_id, merge_into=None): - user = username_from_id(conn, uid) - pkgbase = pkgbase_from_id(conn, pkgbase_id) - to = [aur_request_ml] - cc = get_request_recipients(conn, reqid) - text = get_request_comment(conn, reqid) - - user_uri = aur_location + '/account/' + user + '/' - pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/' - - subject = '[PRQ#%d] %s Request for %s' % \ - (int(reqid), reqtype.title(), pkgbase) - if merge_into: - merge_into_uri = aur_location + '/pkgbase/' + merge_into + '/' - body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \ - (user, pkgbase, merge_into) - body += '\n\n' + text - refs = '[1] ' + user_uri + '\n' - refs += '[2] ' + pkgbase_uri + '\n' - refs += '[3] ' + merge_into_uri - else: - body = '%s [1] filed a %s request for %s [2]:' % \ - (user, reqtype, pkgbase) - body += '\n\n' + text - refs = '[1] ' + user_uri + '\n' - refs += '[2] ' + pkgbase_uri - thread_id = '' - # Use a deterministic Message-ID for the first email referencing a request. - headers = headers_msgid(thread_id) - headers.update(headers_cc(cc)) - - send_notification(to, subject, body, refs, headers) - - -def request_close(conn, uid, reqid, reason): - to = [aur_request_ml] - cc = get_request_recipients(conn, reqid) - text = get_request_closure_comment(conn, reqid) - - subject = '[PRQ#%d] Request %s' % (int(reqid), reason.title()) - if int(uid): - user = username_from_id(conn, uid) - user_uri = aur_location + '/account/' + user + '/' - body = 'Request #%d has been %s by %s [1]' % (int(reqid), reason, user) - refs = '[1] ' + user_uri - else: - body = 'Request #%d has been %s automatically by the Arch User ' \ - 'Repository package request system' % (int(reqid), reason) - refs = None - if text.strip() == '': - body += '.' - else: - body += ':\n\n' + text - thread_id = '' - headers = headers_reply(thread_id) - headers.update(headers_cc(cc)) - - send_notification(to, subject, body, refs, headers) - - -def tu_vote_reminder(conn, vote_id): - to = get_tu_vote_reminder_recipients(conn, vote_id) - - vote_uri = aur_location + '/tu/?id=' + vote_id - - subject = 'TU Vote Reminder: Proposal %d' % (int(vote_id)) - body = 'Please remember to cast your vote on proposal %d [1]. ' \ - 'The voting period ends in less than 48 hours.' % (int(vote_id)) - refs = '[1] ' + vote_uri - - send_notification(to, subject, body, refs) +class Notification: + def get_refs(self): + return () + + def get_headers(self): + return {} + + def send(self): + body = '' + for line in self.get_body().splitlines(): + body += textwrap.fill(line, break_long_words=False) + '\n' + for i, ref in enumerate(self.get_refs()): + body += '\n' + '[%d] %s' % (i + 1, ref) + body = body.rstrip() + + sendmail = aurweb.config.get('notifications', 'sendmail') + sender = aurweb.config.get('notifications', 'sender') + reply_to = aurweb.config.get('notifications', 'reply-to') + + for recipient in self.get_recipients(): + msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') + msg['Subject'] = self.get_subject() + msg['From'] = sender + msg['Reply-to'] = reply_to + msg['To'] = recipient + + for key, value in self.get_headers().items(): + msg[key] = value + + p = subprocess.Popen([sendmail, '-t', '-oi'], + stdin=subprocess.PIPE) + p.communicate(msg.as_bytes()) + + +class ResetKeyNotification(Notification): + def __init__(self, conn, uid): + cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' + + 'WHERE ID = ?', [uid]) + self._username, self._to, self._resetkey = cur.fetchone() + + def get_recipients(self): + return [self._to] + + def get_subject(self): + return 'AUR Password Reset' + + def get_body(self): + return 'A password reset request was submitted for the account %s ' \ + 'associated with your email address. If you wish to reset ' \ + 'your password follow the link [1] below, otherwise ignore ' \ + 'this message and nothing will happen.' % (self._username) + + def get_refs(self): + return (aur_location + '/passreset/?resetkey=' + self._resetkey,) + + +class WelcomeNotification(ResetKeyNotification): + def get_subject(self): + return 'Welcome to the Arch User Repository' + + def get_body(self): + return 'Welcome to the Arch User Repository! In order to set an ' \ + 'initial password for your new account, please click the ' \ + 'link [1] below. If the link does not work, try copying and ' \ + 'pasting it into your browser.' + + +class CommentNotification(Notification): + def __init__(self, conn, uid, pkgbase_id, comment_id): + self._user = username_from_id(conn, uid) + self._pkgbase = pkgbase_from_id(conn, pkgbase_id) + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.CommentNotify = 1 AND ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, pkgbase_id]) + self._to = [row[0] for row in cur.fetchall()] + cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', + [comment_id]) + self._text = cur.fetchone()[0] + + def get_recipients(self): + return self._to + + def get_subject(self): + return 'AUR Comment for %s' % (self._pkgbase) + + def get_body(self): + body = '%s [1] added the following comment to %s [2]:' % \ + (self._user, self._pkgbase) + body += '\n\n' + self._text + '\n\n' + body += 'If you no longer wish to receive notifications about this ' \ + 'package, please go to the package page [2] and select ' \ + '"%s".' % ('Disable notifications') + return body + + def get_refs(self): + return (aur_location + '/account/' + self._user + '/', + aur_location + '/pkgbase/' + self._pkgbase + '/') + + def get_headers(self): + thread_id = '' + return headers_reply(thread_id) + + +class UpdateNotification(Notification): + def __init__(self, conn, uid, pkgbase_id): + self._user = username_from_id(conn, uid) + self._pkgbase = pkgbase_from_id(conn, pkgbase_id) + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.UpdateNotify = 1 AND ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, pkgbase_id]) + self._to = [row[0] for row in cur.fetchall()] + + def get_recipients(self): + return self._to + + def get_subject(self): + return 'AUR Package Update: %s' % (self._pkgbase) + + def get_body(self): + body = '%s [1] pushed a new commit to %s [2].' % \ + (self._user, self._pkgbase) + body += '\n\n' + body += 'If you no longer wish to receive notifications about this ' \ + 'package, please go to the package page [2] and select ' \ + '"%s".' % ('Disable notifications') + return body + + def get_refs(self): + return (aur_location + '/account/' + self._user + '/', + aur_location + '/pkgbase/' + self._pkgbase + '/') + + def get_headers(self): + thread_id = '' + return headers_reply(thread_id) + + +class FlagNotification(Notification): + def __init__(self, conn, uid, pkgbase_id): + self._user = username_from_id(conn, uid) + self._pkgbase = pkgbase_from_id(conn, pkgbase_id) + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'LEFT JOIN PackageComaintainers ' + + 'ON PackageComaintainers.UsersID = Users.ID ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.MaintainerUID = Users.ID OR ' + + 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + + 'WHERE PackageBases.ID = ?', [pkgbase_id]) + self._to = [row[0] for row in cur.fetchall()] + cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + + 'ID = ?', [pkgbase_id]) + self._text = cur.fetchone()[0] + + def get_recipients(self): + return self._to + + def get_subject(self): + return 'AUR Out-of-date Notification for %s' % (self._pkgbase) + + def get_body(self): + body = 'Your package %s [1] has been flagged out-of-date by ' \ + '%s [2]:' % (self._pkgbase, self._user) + body += '\n\n' + self._text + return body + + def get_refs(self): + return (aur_location + '/pkgbase/' + self._pkgbase + '/', + aur_location + '/account/' + self._user + '/') + + +class OwnershipEventNotification(Notification): + def __init__(self, conn, uid, pkgbase_id): + self._user = username_from_id(conn, uid) + self._pkgbase = pkgbase_from_id(conn, pkgbase_id) + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'Users.OwnershipNotify = 1 AND ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, pkgbase_id]) + self._to = [row[0] for row in cur.fetchall()] + cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + + 'ID = ?', [pkgbase_id]) + self._text = cur.fetchone()[0] + + def get_recipients(self): + return self._to + + def get_subject(self): + return 'AUR Ownership Notification for %s' % (self._pkgbase) + + def get_refs(self): + return (aur_location + '/pkgbase/' + self._pkgbase + '/', + aur_location + '/account/' + self._user + '/') + + +class AdoptNotification(OwnershipEventNotification): + def get_body(self): + return 'The package %s [1] was adopted by %s [2].' % \ + (self._pkgbase, self._user) + + +class DisownNotification(OwnershipEventNotification): + def get_body(self): + return 'The package %s [1] was disowned by %s [2].' % \ + (self._pkgbase, self._user) + + +class ComaintainershipEventNotification(Notification): + def __init__(self, conn, uid, pkgbase_id): + self._pkgbase = pkgbase_from_id(conn, pkgbase_id) + self._to = get_user_email(conn, uid) + + def get_recipients(self): + return [self._to] + + def get_subject(self): + return 'AUR Co-Maintainer Notification for %s' % (self._pkgbase) + + def get_refs(self): + return (aur_location + '/pkgbase/' + self._pkgbase + '/',) + + +class ComaintainerAddNotification(ComaintainershipEventNotification): + def get_body(self): + return 'You were added to the co-maintainer list of %s [1].' % \ + (self._pkgbase) + + +class ComaintainerRemoveNotification(ComaintainershipEventNotification): + def get_body(self): + return 'You were removed from the co-maintainer list of %s [1].' % \ + (self._pkgbase) + + +class DeleteNotification(Notification): + def __init__(self, conn, uid, old_pkgbase_id, new_pkgbase_id=None): + self._user = username_from_id(conn, uid) + self._old_pkgbase = pkgbase_from_id(conn, old_pkgbase_id) + if new_pkgbase_id: + self._new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id) + else: + self._new_pkgbase = None + cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + 'INNER JOIN PackageNotifications ' + + 'ON PackageNotifications.UserID = Users.ID WHERE ' + + 'PackageNotifications.UserID != ? AND ' + + 'PackageNotifications.PackageBaseID = ?', + [uid, old_pkgbase_id]) + self._to = [row[0] for row in cur.fetchall()] + + def get_recipients(self): + return self._to + + def get_subject(self): + return 'AUR Package deleted: %s' % (self._old_pkgbase) + + def get_body(self): + if self._new_pkgbase: + return '%s [1] merged %s [2] into %s [3].\n\n' \ + 'If you no longer wish receive notifications about the ' \ + 'new package, please go to [3] and click "%s".' % \ + (self._user, self._old_pkgbase, self._new_pkgbase, + 'Disable notifications') + else: + return '%s [1] deleted %s [2].\n\n' \ + 'You will no longer receive notifications about this ' \ + 'package.' % (self._user, self._old_pkgbase) + + def get_refs(self): + refs = (aur_location + '/account/' + self._user + '/', + aur_location + '/pkgbase/' + self._old_pkgbase + '/') + if self._new_pkgbase: + refs += (aur_location + '/pkgbase/' + self._new_pkgbase + '/',) + return refs + + +class RequestOpenNotification(Notification): + def __init__(self, conn, uid, reqid, reqtype, pkgbase_id, merge_into=None): + self._user = username_from_id(conn, uid) + self._pkgbase = pkgbase_from_id(conn, pkgbase_id) + cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + + 'INNER JOIN Users ' + + 'ON Users.ID = PackageRequests.UsersID ' + + 'OR Users.ID = PackageBases.MaintainerUID ' + + 'WHERE PackageRequests.ID = ?', [reqid]) + self._to = aurweb.config.get('options', 'aur_request_ml') + self._cc = [row[0] for row in cur.fetchall()] + cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?', + [reqid]) + self._text = cur.fetchone()[0] + self._reqid = int(reqid) + self._reqtype = reqtype + self._merge_into = merge_into + + def get_recipients(self): + return [self._to] + + def get_subject(self): + return '[PRQ#%d] %s Request for %s' % \ + (self._reqid, self._reqtype.title(), self._pkgbase) + + def get_body(self): + if self._merge_into: + body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \ + (self._user, self._pkgbase, self._merge_into) + body += '\n\n' + self._text + else: + body = '%s [1] filed a %s request for %s [2]:' % \ + (self._user, self._reqtype, self._pkgbase) + body += '\n\n' + self._text + return body + + def get_refs(self): + refs = (aur_location + '/account/' + self._user + '/', + aur_location + '/pkgbase/' + self._pkgbase + '/') + if self._merge_into: + refs += (aur_location + '/pkgbase/' + self._merge_into + '/',) + return refs + + def get_headers(self): + thread_id = '' + # Use a deterministic Message-ID for the first email referencing a + # request. + headers = headers_msgid(thread_id) + headers.update(headers_cc(self._cc)) + return headers + + +class RequestCloseNotification(Notification): + def __init__(self, conn, uid, reqid, reason): + self._user = username_from_id(conn, uid) if int(uid) else None + cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + + 'INNER JOIN Users ' + + 'ON Users.ID = PackageRequests.UsersID ' + + 'OR Users.ID = PackageBases.MaintainerUID ' + + 'WHERE PackageRequests.ID = ?', [reqid]) + self._to = aurweb.config.get('options', 'aur_request_ml') + self._cc = [row[0] for row in cur.fetchall()] + cur = conn.execute('SELECT ClosureComment FROM PackageRequests ' + + 'WHERE ID = ?', [reqid]) + self._text = cur.fetchone()[0] + self._reqid = int(reqid) + self._reason = reason + + def get_recipients(self): + return [self._to] + + def get_subject(self): + return '[PRQ#%d] Request %s' % (self._reqid, self._reason.title()) + + def get_body(self): + if self._user: + body = 'Request #%d has been %s by %s [1]' % \ + (self._reqid, self._reason, self._user) + else: + body = 'Request #%d has been %s automatically by the Arch User ' \ + 'Repository package request system' % \ + (self._reqid, self._reason) + if self._text.strip() == '': + body += '.' + else: + body += ':\n\n' + self._text + return body + + def get_refs(self): + if self._user: + return (aur_location + '/account/' + self._user + '/',) + else: + return () + + def get_headers(self): + thread_id = '' + headers = headers_reply(thread_id) + headers.update(headers_cc(self._cc)) + return headers + + +class TUVoteReminderNotification(Notification): + def __init__(self, conn, vote_id): + self._vote_id = int(vote_id) + cur = conn.execute('SELECT Email FROM Users ' + + 'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' + + '(SELECT UserID FROM TU_Votes ' + + 'WHERE TU_Votes.VoteID = ?)', [vote_id]) + self._to = [row[0] for row in cur.fetchall()] + + def get_recipients(self): + return self._to + + def get_subject(self): + return 'TU Vote Reminder: Proposal %d' % (self._vote_id) + + def get_body(self): + return 'Please remember to cast your vote on proposal %d [1]. ' \ + 'The voting period ends in less than 48 hours.' % \ + (self._vote_id) + + def get_refs(self): + return (aur_location + '/tu/?id=' + str(self._vote_id),) def main(): action = sys.argv[1] action_map = { - 'send-resetkey': send_resetkey, - 'welcome': welcome, - 'comment': comment, - 'update': update, - 'flag': flag, - 'adopt': adopt, - 'disown': disown, - 'comaintainer-add': comaintainer_add, - 'comaintainer-remove': comaintainer_remove, - 'delete': delete, - 'request-open': request_open, - 'request-close': request_close, - 'tu-vote-reminder': tu_vote_reminder, + 'send-resetkey': ResetKeyNotification, + 'welcome': WelcomeNotification, + 'comment': CommentNotification, + 'update': UpdateNotification, + 'flag': FlagNotification, + 'adopt': AdoptNotification, + 'disown': DisownNotification, + 'comaintainer-add': ComaintainerAddNotification, + 'comaintainer-remove': ComaintainerRemoveNotification, + 'delete': DeleteNotification, + 'request-open': RequestOpenNotification, + 'request-close': RequestCloseNotification, + 'tu-vote-reminder': TUVoteReminderNotification, } conn = aurweb.db.Connection() - action_map[action](conn, *sys.argv[2:]) + notification = action_map[action](conn, *sys.argv[2:]) + notification.send() conn.commit() conn.close() From f7a57c82bceeeae33b3244ba33b4844f5b692298 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 17 May 2018 22:05:01 +0200 Subject: [PATCH 0432/1891] Localize notification emails Add support for translating notification emails and send localized notifications, based on the user's language preferences. Also, update the translations Makefile to add strings from the notification script to the message catalog. Implements FS#31850. Signed-off-by: Lukas Fleischer --- aurweb/l10n.py | 16 +++ aurweb/scripts/notify.py | 258 ++++++++++++++++++++++----------------- po/Makefile | 21 +++- test/setup.sh | 18 +-- 4 files changed, 189 insertions(+), 124 deletions(-) create mode 100644 aurweb/l10n.py diff --git a/aurweb/l10n.py b/aurweb/l10n.py new file mode 100644 index 00000000..e58e3fe2 --- /dev/null +++ b/aurweb/l10n.py @@ -0,0 +1,16 @@ +import gettext + + +class Translator: + def __init__(self): + self._translator = {} + + def translate(self, s, lang): + if lang == 'en': + return s + if lang not in self._translator: + self._translator[lang] = gettext.translation("aur", + "../../web/locale", + languages=[lang]) + self._translator[lang].install() + return _(s) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index a6370133..9f1f7a5d 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -7,6 +7,7 @@ import textwrap import aurweb.config import aurweb.db +import aurweb.l10n aur_location = aurweb.config.get('options', 'aur_location') @@ -40,36 +41,37 @@ def pkgbase_from_pkgreq(conn, reqid): return cur.fetchone()[0] -def get_user_email(conn, uid): - cur = conn.execute('SELECT Email FROM Users WHERE ID = ?', [uid]) - return cur.fetchone()[0] - - class Notification: + def __init__(self): + self._l10n = aurweb.l10n.Translator() + def get_refs(self): return () def get_headers(self): return {} - def send(self): + def get_body_fmt(self, lang): body = '' - for line in self.get_body().splitlines(): + for line in self.get_body(lang).splitlines(): body += textwrap.fill(line, break_long_words=False) + '\n' for i, ref in enumerate(self.get_refs()): body += '\n' + '[%d] %s' % (i + 1, ref) - body = body.rstrip() + return body.rstrip() + def send(self): sendmail = aurweb.config.get('notifications', 'sendmail') sender = aurweb.config.get('notifications', 'sender') reply_to = aurweb.config.get('notifications', 'reply-to') for recipient in self.get_recipients(): - msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') - msg['Subject'] = self.get_subject() + to, lang = recipient + msg = email.mime.text.MIMEText(self.get_body_fmt(lang), + 'plain', 'utf-8') + msg['Subject'] = self.get_subject(lang) msg['From'] = sender msg['Reply-to'] = reply_to - msg['To'] = recipient + msg['To'] = to for key, value in self.get_headers().items(): msg[key] = value @@ -81,66 +83,76 @@ class Notification: class ResetKeyNotification(Notification): def __init__(self, conn, uid): - cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' + - 'WHERE ID = ?', [uid]) - self._username, self._to, self._resetkey = cur.fetchone() + cur = conn.execute('SELECT UserName, Email, LangPreference, ' + + 'ResetKey FROM Users WHERE ID = ?', [uid]) + self._username, self._to, self._lang, self._resetkey = cur.fetchone() + super().__init__() def get_recipients(self): - return [self._to] + return [(self._to, self._lang)] - def get_subject(self): - return 'AUR Password Reset' + def get_subject(self, lang): + return self._l10n.translate('AUR Password Reset', lang) - def get_body(self): - return 'A password reset request was submitted for the account %s ' \ - 'associated with your email address. If you wish to reset ' \ - 'your password follow the link [1] below, otherwise ignore ' \ - 'this message and nothing will happen.' % (self._username) + def get_body(self, lang): + return self._l10n.translate( + 'A password reset request was submitted for the account %s ' + 'associated with your email address. If you wish to reset ' + 'your password follow the link [1] below, otherwise ignore ' + 'this message and nothing will happen.', lang) % \ + (self._username) def get_refs(self): return (aur_location + '/passreset/?resetkey=' + self._resetkey,) class WelcomeNotification(ResetKeyNotification): - def get_subject(self): - return 'Welcome to the Arch User Repository' + def get_subject(self, lang): + return self._l10n.translate('Welcome to the Arch User Repository', + lang) - def get_body(self): - return 'Welcome to the Arch User Repository! In order to set an ' \ - 'initial password for your new account, please click the ' \ - 'link [1] below. If the link does not work, try copying and ' \ - 'pasting it into your browser.' + def get_body(self, lang): + return self._l10n.translate( + 'Welcome to the Arch User Repository! In order to set an ' + 'initial password for your new account, please click the ' + 'link [1] below. If the link does not work, try copying and ' + 'pasting it into your browser.', lang) class CommentNotification(Notification): def __init__(self, conn, uid, pkgbase_id, comment_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + + cur = conn.execute('SELECT DISTINCT Users.Email, Users.LangPreference ' + 'FROM Users INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.CommentNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', [comment_id]) self._text = cur.fetchone()[0] + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Comment for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Comment for %s', lang) % \ + (self._pkgbase) - def get_body(self): - body = '%s [1] added the following comment to %s [2]:' % \ - (self._user, self._pkgbase) + def get_body(self, lang): + body = self._l10n.translate( + '%s [1] added the following comment to %s [2]:', lang) % \ + (self._user, self._pkgbase) body += '\n\n' + self._text + '\n\n' - body += 'If you no longer wish to receive notifications about this ' \ - 'package, please go to the package page [2] and select ' \ - '"%s".' % ('Disable notifications') + dnlabel = self._l10n.translate('Disable notifications', lang) + body += self._l10n.translate( + 'If you no longer wish to receive notifications about this ' + 'package, please go to the package page [2] and select ' + '"%s".', lang) % dnlabel return body def get_refs(self): @@ -157,28 +169,33 @@ class UpdateNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.UpdateNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Package Update: %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Package Update: %s', lang) % \ + (self._pkgbase) - def get_body(self): - body = '%s [1] pushed a new commit to %s [2].' % \ - (self._user, self._pkgbase) + def get_body(self, lang): + body = self._l10n.translate('%s [1] pushed a new commit to %s [2].', + lang) % (self._user, self._pkgbase) body += '\n\n' - body += 'If you no longer wish to receive notifications about this ' \ - 'package, please go to the package page [2] and select ' \ - '"%s".' % ('Disable notifications') + dnlabel = self._l10n.translate('Disable notifications', lang) + body += self._l10n.translate( + 'If you no longer wish to receive notifications about this ' + 'package, please go to the package page [2] and select ' + '"%s".', lang) % dnlabel return body def get_refs(self): @@ -195,27 +212,31 @@ class FlagNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'LEFT JOIN PackageComaintainers ' + 'ON PackageComaintainers.UsersID = Users.ID ' + 'INNER JOIN PackageBases ' + 'ON PackageBases.MaintainerUID = Users.ID OR ' + 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + 'WHERE PackageBases.ID = ?', [pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + 'ID = ?', [pkgbase_id]) self._text = cur.fetchone()[0] + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Out-of-date Notification for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Out-of-date Notification for %s', + lang) % (self._pkgbase) - def get_body(self): - body = 'Your package %s [1] has been flagged out-of-date by ' \ - '%s [2]:' % (self._pkgbase, self._user) + def get_body(self, lang): + body = self._l10n.translate( + 'Your package %s [1] has been flagged out-of-date by ' + '%s [2]:', lang) % (self._pkgbase, self._user) body += '\n\n' + self._text return body @@ -228,23 +249,26 @@ class OwnershipEventNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.OwnershipNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + 'ID = ?', [pkgbase_id]) self._text = cur.fetchone()[0] + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Ownership Notification for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Ownership Notification for %s', + lang) % (self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/', @@ -252,42 +276,50 @@ class OwnershipEventNotification(Notification): class AdoptNotification(OwnershipEventNotification): - def get_body(self): - return 'The package %s [1] was adopted by %s [2].' % \ - (self._pkgbase, self._user) + def get_body(self, lang): + return self._l10n.translate( + 'The package %s [1] was adopted by %s [2].', lang) % \ + (self._pkgbase, self._user) class DisownNotification(OwnershipEventNotification): def get_body(self): - return 'The package %s [1] was disowned by %s [2].' % \ - (self._pkgbase, self._user) + return self._l10n.translate( + 'The package %s [1] was disowned by %s [2].', lang) % \ + (self._pkgbase, self._user) class ComaintainershipEventNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - self._to = get_user_email(conn, uid) + cur = conn.execute('SELECT Email, LangPreference FROM Users ' + + 'WHERE ID = ?', [uid]) + self._to, self._lang = cur.fetchone() + super().__init__() def get_recipients(self): - return [self._to] + return [(self._to, self._lang)] - def get_subject(self): - return 'AUR Co-Maintainer Notification for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Co-Maintainer Notification for %s', + lang) % (self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/',) class ComaintainerAddNotification(ComaintainershipEventNotification): - def get_body(self): - return 'You were added to the co-maintainer list of %s [1].' % \ - (self._pkgbase) + def get_body(self, lang): + return self._l10n.translate( + 'You were added to the co-maintainer list of %s [1].', + lang) % (self._pkgbase) class ComaintainerRemoveNotification(ComaintainershipEventNotification): - def get_body(self): - return 'You were removed from the co-maintainer list of %s [1].' % \ - (self._pkgbase) + def get_body(self, lang): + return self._l10n.translate( + 'You were removed from the co-maintainer list of %s [1].', + lang) % (self._pkgbase) class DeleteNotification(Notification): @@ -298,31 +330,36 @@ class DeleteNotification(Notification): self._new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id) else: self._new_pkgbase = None - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, old_pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Package deleted: %s' % (self._old_pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Package deleted: %s', lang) % \ + (self._old_pkgbase) - def get_body(self): + def get_body(self, lang): if self._new_pkgbase: - return '%s [1] merged %s [2] into %s [3].\n\n' \ - 'If you no longer wish receive notifications about the ' \ - 'new package, please go to [3] and click "%s".' % \ - (self._user, self._old_pkgbase, self._new_pkgbase, - 'Disable notifications') + dnlabel = self._l10n.translate('Disable notifications', lang) + return self._l10n.translate( + '%s [1] merged %s [2] into %s [3].\n\n' + 'If you no longer wish receive notifications about the ' + 'new package, please go to [3] and click "%s".', lang) % \ + (self._user, self._old_pkgbase, self._new_pkgbase, dnlabel) else: - return '%s [1] deleted %s [2].\n\n' \ - 'You will no longer receive notifications about this ' \ - 'package.' % (self._user, self._old_pkgbase) + return self._l10n.translate( + '%s [1] deleted %s [2].\n\n' + 'You will no longer receive notifications about this ' + 'package.', lang) % (self._user, self._old_pkgbase) def get_refs(self): refs = (aur_location + '/account/' + self._user + '/', @@ -353,13 +390,13 @@ class RequestOpenNotification(Notification): self._merge_into = merge_into def get_recipients(self): - return [self._to] + return [(self._to, 'en')] - def get_subject(self): + def get_subject(self, lang): return '[PRQ#%d] %s Request for %s' % \ (self._reqid, self._reqtype.title(), self._pkgbase) - def get_body(self): + def get_body(self, lang): if self._merge_into: body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \ (self._user, self._pkgbase, self._merge_into) @@ -405,12 +442,12 @@ class RequestCloseNotification(Notification): self._reason = reason def get_recipients(self): - return [self._to] + return [(self._to, 'en')] - def get_subject(self): + def get_subject(self, lang): return '[PRQ#%d] Request %s' % (self._reqid, self._reason.title()) - def get_body(self): + def get_body(self, lang): if self._user: body = 'Request #%d has been %s by %s [1]' % \ (self._reqid, self._reason, self._user) @@ -440,22 +477,25 @@ class RequestCloseNotification(Notification): class TUVoteReminderNotification(Notification): def __init__(self, conn, vote_id): self._vote_id = int(vote_id) - cur = conn.execute('SELECT Email FROM Users ' + + cur = conn.execute('SELECT Email, LangPreference FROM Users ' + 'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' + '(SELECT UserID FROM TU_Votes ' + 'WHERE TU_Votes.VoteID = ?)', [vote_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'TU Vote Reminder: Proposal %d' % (self._vote_id) + def get_subject(self, lang): + return self._l10n.translate('TU Vote Reminder: Proposal %d', lang) % \ + (self._vote_id) - def get_body(self): - return 'Please remember to cast your vote on proposal %d [1]. ' \ - 'The voting period ends in less than 48 hours.' % \ - (self._vote_id) + def get_body(self, lang): + return self._l10n.translate( + 'Please remember to cast your vote on proposal %d [1]. ' + 'The voting period ends in less than 48 hours.', lang) % \ + (self._vote_id) def get_refs(self): return (aur_location + '/tu/?id=' + str(self._vote_id),) diff --git a/po/Makefile b/po/Makefile index d0ed7418..78073f86 100644 --- a/po/Makefile +++ b/po/Makefile @@ -48,23 +48,32 @@ all: ${MOFILES} lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ msgmerge -U --no-location --lang="$$lang" $< aur.pot -POTFILES: - find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES +POTFILES-php: + find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES-php -update-pot: POTFILES +POTFILES-py: + find ../aurweb -type f -name '*.py' -printf '%P\n' | sort >POTFILES-py + +update-pot: POTFILES-php POTFILES-py pkgname=AUR; \ pkgver=`sed -n 's/.*"AURWEB_VERSION", "\(.*\)".*/\1/p' ../web/lib/version.inc.php`; \ xgettext --default-domain=aur -L php --keyword=__ --keyword=_n:1,2 \ --add-location=file --add-comments=TRANSLATORS: \ --package-name="$$pkgname" --package-version="$$pkgver" \ --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ - --directory ../web --files-from POTFILES -o aur.pot + --directory ../web --files-from POTFILES-php -o aur.pot; \ + xgettext --default-domain=aur -L python --join-existing \ + --keyword=translate \ + --add-location=file --add-comments=TRANSLATORS: \ + --package-name="$$pkgname" --package-version="$$pkgver" \ + --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ + --directory ../aurweb --files-from POTFILES-py -o aur.pot update-po: ${MAKE} ${UPDATEPOFILES} clean: - rm -f *.mo *.po\~ POTFILES + rm -f *.mo *.po\~ POTFILES-php POTFILES-py install: all for l in ${LOCALES}; do mkdir -p ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done @@ -73,4 +82,4 @@ install: all uninstall: for l in ${LOCALES}; do rm -rf ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done -.PHONY: all update-pot update-po clean install uninstall POTFILES +.PHONY: all update-pot update-po clean install uninstall POTFILES-php POTFILES-py diff --git a/test/setup.sh b/test/setup.sh index 5e10fec8..535e8190 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -114,15 +114,15 @@ DBSCHEMA="$TOPLEVEL/schema/aur-schema-sqlite.sql" rm -f aur.db sqlite3 aur.db <"$DBSCHEMA" -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 2);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (3, 'dev', '!', 'dev@localhost', 3);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (4, 'user2', '!', 'user2@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (5, 'user3', '!', 'user3@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (6, 'user4', '!', 'user4@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (7, 'tu2', '!', 'tu2@localhost', 2);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (8, 'tu3', '!', 'tu3@localhost', 2);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (9, 'tu4', '!', 'tu4@localhost', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 'en', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (3, 'dev', '!', 'dev@localhost', 'en', 3);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (4, 'user2', '!', 'user2@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (5, 'user3', '!', 'user3@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (6, 'user4', '!', 'user4@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (7, 'tu2', '!', 'tu2@localhost', 'en', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (8, 'tu3', '!', 'tu3@localhost', 'en', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (9, 'tu4', '!', 'tu4@localhost', 'en', 2);" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (1, '$AUTH_FINGERPRINT_USER', '$AUTH_KEYTYPE_USER $AUTH_KEYTEXT_USER');" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FINGERPRINT_TU', '$AUTH_KEYTYPE_TU $AUTH_KEYTEXT_TU');" | sqlite3 aur.db From 6367dfd245ccf87f6cccdd82393d1c7fe0095573 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 17 May 2018 22:50:42 +0200 Subject: [PATCH 0433/1891] Use modern format strings in notification messages User modern Python format() strings with curly braces. Also, convert all placeholders to named arguments. This allows translators to reorder messages. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 96 ++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 9f1f7a5d..beca8b48 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -96,11 +96,11 @@ class ResetKeyNotification(Notification): def get_body(self, lang): return self._l10n.translate( - 'A password reset request was submitted for the account %s ' - 'associated with your email address. If you wish to reset ' - 'your password follow the link [1] below, otherwise ignore ' - 'this message and nothing will happen.', lang) % \ - (self._username) + 'A password reset request was submitted for the account ' + '{user} associated with your email address. If you wish to ' + 'reset your password follow the link [1] below, otherwise ' + 'ignore this message and nothing will happen.', + lang).format(user=self._username) def get_refs(self): return (aur_location + '/passreset/?resetkey=' + self._resetkey,) @@ -140,19 +140,19 @@ class CommentNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Comment for %s', lang) % \ - (self._pkgbase) + return self._l10n.translate('AUR Comment for {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_body(self, lang): body = self._l10n.translate( - '%s [1] added the following comment to %s [2]:', lang) % \ - (self._user, self._pkgbase) + '{user} [1] added the following comment to {pkgbase} [2]:', + lang).format(user=self._user, pkgbase=self._pkgbase) body += '\n\n' + self._text + '\n\n' dnlabel = self._l10n.translate('Disable notifications', lang) body += self._l10n.translate( 'If you no longer wish to receive notifications about this ' 'package, please go to the package page [2] and select ' - '"%s".', lang) % dnlabel + '"{label}".', lang).format(label=dnlabel) return body def get_refs(self): @@ -184,18 +184,20 @@ class UpdateNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Package Update: %s', lang) % \ - (self._pkgbase) + return self._l10n.translate('AUR Package Update: {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_body(self, lang): - body = self._l10n.translate('%s [1] pushed a new commit to %s [2].', - lang) % (self._user, self._pkgbase) + body = self._l10n.translate('{user} [1] pushed a new commit to ' + '{pkgbase} [2].', lang).format( + user=self._user, + pkgbase=self._pkgbase) body += '\n\n' dnlabel = self._l10n.translate('Disable notifications', lang) body += self._l10n.translate( 'If you no longer wish to receive notifications about this ' 'package, please go to the package page [2] and select ' - '"%s".', lang) % dnlabel + '"{label}".', lang).format(label=dnlabel) return body def get_refs(self): @@ -230,13 +232,15 @@ class FlagNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Out-of-date Notification for %s', - lang) % (self._pkgbase) + return self._l10n.translate('AUR Out-of-date Notification for ' + '{pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_body(self, lang): body = self._l10n.translate( - 'Your package %s [1] has been flagged out-of-date by ' - '%s [2]:', lang) % (self._pkgbase, self._user) + 'Your package {pkgbase} [1] has been flagged out-of-date by ' + '{user} [2]:', lang).format(pkgbase=self._pkgbase, + user=self._user) body += '\n\n' + self._text return body @@ -267,8 +271,8 @@ class OwnershipEventNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Ownership Notification for %s', - lang) % (self._pkgbase) + return self._l10n.translate('AUR Ownership Notification for {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/', @@ -278,15 +282,16 @@ class OwnershipEventNotification(Notification): class AdoptNotification(OwnershipEventNotification): def get_body(self, lang): return self._l10n.translate( - 'The package %s [1] was adopted by %s [2].', lang) % \ - (self._pkgbase, self._user) + 'The package {pkgbase} [1] was adopted by {user} [2].', + lang).format(pkgbase=self._pkgbase, user=self._user) class DisownNotification(OwnershipEventNotification): - def get_body(self): + def get_body(self, lang): return self._l10n.translate( - 'The package %s [1] was disowned by %s [2].', lang) % \ - (self._pkgbase, self._user) + 'The package {pkgbase} [1] was disowned by {user} ' + '[2].', lang).format(pkgbase=self._pkgbase, + user=self._user) class ComaintainershipEventNotification(Notification): @@ -301,8 +306,9 @@ class ComaintainershipEventNotification(Notification): return [(self._to, self._lang)] def get_subject(self, lang): - return self._l10n.translate('AUR Co-Maintainer Notification for %s', - lang) % (self._pkgbase) + return self._l10n.translate('AUR Co-Maintainer Notification for ' + '{pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/',) @@ -311,15 +317,15 @@ class ComaintainershipEventNotification(Notification): class ComaintainerAddNotification(ComaintainershipEventNotification): def get_body(self, lang): return self._l10n.translate( - 'You were added to the co-maintainer list of %s [1].', - lang) % (self._pkgbase) + 'You were added to the co-maintainer list of {pkgbase} [1].', + lang).format(pkgbase=self._pkgbase) class ComaintainerRemoveNotification(ComaintainershipEventNotification): def get_body(self, lang): return self._l10n.translate( - 'You were removed from the co-maintainer list of %s [1].', - lang) % (self._pkgbase) + 'You were removed from the co-maintainer list of {pkgbase} ' + '[1].', lang).format(pkgbase=self._pkgbase) class DeleteNotification(Notification): @@ -344,22 +350,24 @@ class DeleteNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Package deleted: %s', lang) % \ - (self._old_pkgbase) + return self._l10n.translate('AUR Package deleted: {pkgbase}', + lang).format(pkgbase=self._old_pkgbase) def get_body(self, lang): if self._new_pkgbase: dnlabel = self._l10n.translate('Disable notifications', lang) return self._l10n.translate( - '%s [1] merged %s [2] into %s [3].\n\n' + '{user} [1] merged {old} [2] into {new} [3].\n\n' 'If you no longer wish receive notifications about the ' - 'new package, please go to [3] and click "%s".', lang) % \ - (self._user, self._old_pkgbase, self._new_pkgbase, dnlabel) + 'new package, please go to [3] and click "{label}".', + lang).format(user=self._user, old=self._old_pkgbase, + new=self._new_pkgbase, label=dnlabel) else: return self._l10n.translate( - '%s [1] deleted %s [2].\n\n' + '{user} [1] deleted {pkgbase} [2].\n\n' 'You will no longer receive notifications about this ' - 'package.', lang) % (self._user, self._old_pkgbase) + 'package.', lang).format(user=self._user, + pkgbase=self._old_pkgbase) def get_refs(self): refs = (aur_location + '/account/' + self._user + '/', @@ -488,14 +496,14 @@ class TUVoteReminderNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('TU Vote Reminder: Proposal %d', lang) % \ - (self._vote_id) + return self._l10n.translate('TU Vote Reminder: Proposal {id}', + lang).format(id=self._vote_id) def get_body(self, lang): return self._l10n.translate( - 'Please remember to cast your vote on proposal %d [1]. ' - 'The voting period ends in less than 48 hours.', lang) % \ - (self._vote_id) + 'Please remember to cast your vote on proposal {id} [1]. ' + 'The voting period ends in less than 48 hours.', + lang).format(id=self._vote_id) def get_refs(self): return (aur_location + '/tu/?id=' + str(self._vote_id),) From d24737f3f5b36b7dc541d2a00c0174e8105fb34a Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 17 May 2018 22:58:35 +0200 Subject: [PATCH 0434/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aur.pot | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 3 deletions(-) diff --git a/po/aur.pot b/po/aur.pot index 2d0ac607..e49dc132 100644 --- a/po/aur.pot +++ b/po/aur.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.5.1\n" +"Project-Id-Version: AUR v4.6.0\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -526,6 +526,12 @@ msgid "" "packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + #: html/pkgdisown.php #, php-format msgid "" @@ -1412,7 +1418,7 @@ msgstr "" msgid "Vote for this package" msgstr "" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "" @@ -1999,3 +2005,127 @@ msgstr "" #: template/tu_list.php msgid "Back" msgstr "" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for " +"your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go " +"to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go " +"to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" From 16795eaf467ef479dd0e37cce6f6623a59584e1f Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 17 May 2018 20:44:51 -0400 Subject: [PATCH 0435/1891] git-update: accept any arch in arch-dependent metadata Currently we hardcode the architectures the official repos historically supported, which seems both inefficient because of hardcoding, and simply wrong, because many packages support various ARM platforms too. If we were to say "only officially supported arches will be supported in the AUR" we'd have to disable i686, which seems silly and arbitrarily restrictive. Also there's better places to implement such a blacklist (via die_commit in the main loop, via a config option to list supported arches, would make much more sense in terms of logic). As for the metadata extraction itself, there's no reason to hardcode the arches to check for at all. We can get this information too, from the .SRCINFO itself. Detecting this dynamically is not incompatible with a blacklist, should we ever decide to implement such a thing. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- aurweb/git/update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index da48eb31..0614e9ea 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -39,7 +39,7 @@ def extract_arch_fields(pkginfo, field): for val in pkginfo[field]: values.append({"value": val, "arch": None}) - for arch in ['i686', 'x86_64']: + for arch in pkginfo['arch']: if field + '_' + arch in pkginfo: for val in pkginfo[field + '_' + arch]: values.append({"value": val, "arch": arch}) From b70f048bc3ba08b62b9841d185549466f66ef714 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 20 May 2018 16:45:00 +0200 Subject: [PATCH 0436/1891] Add package base name in request close notifications Mention both the package base name and the request type in the subject of request closure notification. Implements FS#41607. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 16 ++++++++++++---- test/t1200-git-serve.sh | 2 +- test/t2500-notify.sh | 6 +++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index beca8b48..44eec84c 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -443,9 +443,14 @@ class RequestCloseNotification(Notification): 'WHERE PackageRequests.ID = ?', [reqid]) self._to = aurweb.config.get('options', 'aur_request_ml') self._cc = [row[0] for row in cur.fetchall()] - cur = conn.execute('SELECT ClosureComment FROM PackageRequests ' + - 'WHERE ID = ?', [reqid]) - self._text = cur.fetchone()[0] + cur = conn.execute('SELECT PackageRequests.ClosureComment, ' + + 'RequestTypes.Name, ' + + 'PackageRequests.PackageBaseName ' + + 'FROM PackageRequests ' + + 'INNER JOIN RequestTypes ' + + 'ON RequestTypes.ID = PackageRequests.ReqTypeID ' + + 'WHERE PackageRequests.ID = ?', [reqid]) + self._text, self._reqtype, self._pkgbase = cur.fetchone() self._reqid = int(reqid) self._reason = reason @@ -453,7 +458,10 @@ class RequestCloseNotification(Notification): return [(self._to, 'en')] def get_subject(self, lang): - return '[PRQ#%d] Request %s' % (self._reqid, self._reason.title()) + return '[PRQ#%d] %s Request for %s %s' % (self._reqid, + self._reqtype.title(), + self._pkgbase, + self._reason.title()) def get_body(self, lang): if self._user: diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.sh index 94a5ff61..473065fc 100755 --- a/test/t1200-git-serve.sh +++ b/test/t1200-git-serve.sh @@ -376,7 +376,7 @@ test_expect_success "Check whether package requests are closed when disowning." SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ "$GIT_SERVE" 2>&1 && cat <<-EOD >expected && - Subject: [PRQ#1] Request Accepted + Subject: [PRQ#1] Orphan Request for foobar Accepted EOD grep "^Subject.*PRQ" sendmail.out >sendmail.parts && test_cmp sendmail.parts expected && diff --git a/test/t2500-notify.sh b/test/t2500-notify.sh index 46c2753e..b2bad1c8 100755 --- a/test/t2500-notify.sh +++ b/test/t2500-notify.sh @@ -304,7 +304,7 @@ test_expect_success 'Test subject and body of request close notifications.' ' "$NOTIFY" request-close 1 1 accepted && grep ^Subject: sendmail.out >actual && cat <<-EOD >expected && - Subject: [PRQ#1] Request Accepted + Subject: [PRQ#1] Deletion Request for foobar Accepted EOD test_cmp actual expected && sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && @@ -322,7 +322,7 @@ test_expect_success 'Test subject and body of request close notifications (auto- "$NOTIFY" request-close 0 1 accepted && grep ^Subject: sendmail.out >actual && cat <<-EOD >expected && - Subject: [PRQ#1] Request Accepted + Subject: [PRQ#1] Deletion Request for foobar Accepted EOD test_cmp actual expected && sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && @@ -342,7 +342,7 @@ test_expect_success 'Test subject and body of request close notifications with c "$NOTIFY" request-close 1 1 accepted && grep ^Subject: sendmail.out >actual && cat <<-EOD >expected && - Subject: [PRQ#1] Request Accepted + Subject: [PRQ#1] Deletion Request for foobar Accepted EOD test_cmp actual expected && sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && From 41a4189d2078e1571d784068e34e7a753bcb8f22 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 7 Jul 2018 15:57:47 +0200 Subject: [PATCH 0437/1891] Sync CSS with archweb Signed-off-by: Lukas Fleischer --- web/html/css/archweb.css | 43 ++++++---------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/web/html/css/archweb.css b/web/html/css/archweb.css index d8c66aa3..209561f9 100644 --- a/web/html/css/archweb.css +++ b/web/html/css/archweb.css @@ -608,17 +608,6 @@ div.widget { margin-bottom: 1.5em; } -/* home: other stuff */ -#konami { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - opacity: 0.6; -} - /* feeds page */ #rss-feeds .rss { padding-right: 20px; @@ -983,8 +972,13 @@ table td.country { width: auto; } -/* dev: dashboard: dashboard and stats area */ +/* tables rows: highlight on mouse-vover */ +#article-list tr:hover, +#clocks-table tr:hover, #dev-dashboard tr:hover, +#dev-todo-lists tr:hover, +#dev-todo-pkglist tr:hover, +#pkglist-results tr:hover, #stats-area tr:hover { background: #ffd; } @@ -1036,7 +1030,6 @@ ul.admin-actions { .todo-table .complete, .signoff-yes, #key-status .signed-yes, -#releng-result .success-yes, #release-list .available-yes { color: green; } @@ -1044,7 +1037,6 @@ ul.admin-actions { .todo-table .incomplete, .signoff-no, #key-status .signed-no, -#releng-result .success-no, #release-list .available-no { color: red; } @@ -1095,25 +1087,6 @@ ul.signoff-list { color: gray; } -/* iso testing feedback form */ -#releng-feedback label { - width: auto; - display: inline; - font-weight: normal; -} - -#releng-feedback ul { - padding-left: 1em; -} - -#releng-feedback li { - list-style: none; -} - -#releng-feedback ul+.helptext { - position: relative; top: -0.9em; -} - /* highlight current website in the navbar */ #archnavbar.anb-home ul li#anb-home a, #archnavbar.anb-packages ul li#anb-packages a, @@ -1126,10 +1099,6 @@ ul.signoff-list { margin: 0.5em 0.33em; } - .visualize-buttons button.active { - depressed: true; - } - .visualize-chart { position: relative; height: 500px; From 840ee20f7b9327fd5e3445af2652b299fdd0ff7f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 7 Jul 2018 16:04:39 +0200 Subject: [PATCH 0438/1891] Rename translation resources from aur to aurweb * Rename the aur project to aurweb on Transifex. * Rename aur.pot to aurweb.pot. * Update documentation and Makefile. Signed-off-by: Lukas Fleischer --- .tx/config | 5 ++--- doc/i18n.txt | 8 ++++---- po/Makefile | 16 ++++++++-------- po/{aur.pot => aurweb.pot} | 0 4 files changed, 14 insertions(+), 15 deletions(-) rename po/{aur.pot => aurweb.pot} (100%) diff --git a/.tx/config b/.tx/config index f6f728dd..e986f81c 100644 --- a/.tx/config +++ b/.tx/config @@ -1,8 +1,7 @@ [main] host = https://www.transifex.com -[aur.aurpot] +[aurweb.aurwebpot] file_filter = po/.po -source_file = po/aur.pot +source_file = po/aurweb.pot source_lang = en - diff --git a/doc/i18n.txt b/doc/i18n.txt index a1c21fe6..8216c084 100644 --- a/doc/i18n.txt +++ b/doc/i18n.txt @@ -5,7 +5,7 @@ This document describes how to create and maintain aurweb translations. Creating an aurweb translation requires a Transifex (http://www.transifex.com/) account. You will need to register with a translation team on the aurweb -project page (http://www.transifex.com/projects/p/aur/). +project page (http://www.transifex.com/projects/p/aurweb/). Creating a New Translation @@ -26,11 +26,11 @@ $ git clone git://git.archlinux.org/aurweb.git aurweb-git 2. Go into the "po/" directory in the aurweb source and run msginit(1) to create a initial translation file from our translation catalog: -$ cd aur-git +$ cd aurweb-git $ git checkout master $ git pull $ cd po -$ msginit -l -o .po -i aur.pot +$ msginit -l -o .po -i aurweb.pot 3. Use some editor or a translation helper like poedit to add translations: @@ -58,4 +58,4 @@ $ poedit po/.po 3. Push the updated translation file back to Transifex. Using transifex-client, this works as follows: -$ tx push -r aur.aurpot -t -l +$ tx push -r aurweb.aurwebpot -t -l diff --git a/po/Makefile b/po/Makefile index 78073f86..57fa9f77 100644 --- a/po/Makefile +++ b/po/Makefile @@ -44,9 +44,9 @@ all: ${MOFILES} %.mo: %.po msgfmt --check -o $@ $< -%.po-update: %.po aur.pot +%.po-update: %.po aurweb.pot lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ - msgmerge -U --no-location --lang="$$lang" $< aur.pot + msgmerge -U --no-location --lang="$$lang" $< aurweb.pot POTFILES-php: find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES-php @@ -55,19 +55,19 @@ POTFILES-py: find ../aurweb -type f -name '*.py' -printf '%P\n' | sort >POTFILES-py update-pot: POTFILES-php POTFILES-py - pkgname=AUR; \ + pkgname=AURWEB; \ pkgver=`sed -n 's/.*"AURWEB_VERSION", "\(.*\)".*/\1/p' ../web/lib/version.inc.php`; \ - xgettext --default-domain=aur -L php --keyword=__ --keyword=_n:1,2 \ + xgettext --default-domain=aurweb -L php --keyword=__ --keyword=_n:1,2 \ --add-location=file --add-comments=TRANSLATORS: \ --package-name="$$pkgname" --package-version="$$pkgver" \ --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ - --directory ../web --files-from POTFILES-php -o aur.pot; \ - xgettext --default-domain=aur -L python --join-existing \ + --directory ../web --files-from POTFILES-php -o aurweb.pot; \ + xgettext --default-domain=aurweb -L python --join-existing \ --keyword=translate \ --add-location=file --add-comments=TRANSLATORS: \ --package-name="$$pkgname" --package-version="$$pkgver" \ --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ - --directory ../aurweb --files-from POTFILES-py -o aur.pot + --directory ../aurweb --files-from POTFILES-py -o aurweb.pot update-po: ${MAKE} ${UPDATEPOFILES} @@ -77,7 +77,7 @@ clean: install: all for l in ${LOCALES}; do mkdir -p ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done - for l in ${LOCALES}; do cp $$l.mo ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/aur.mo; done + for l in ${LOCALES}; do cp $$l.mo ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/aurweb.mo; done uninstall: for l in ${LOCALES}; do rm -rf ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done diff --git a/po/aur.pot b/po/aurweb.pot similarity index 100% rename from po/aur.pot rename to po/aurweb.pot From 2aa78d75d37ac565d51bef1962dc3bc5fbbdbfbf Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 7 Jul 2018 16:08:33 +0200 Subject: [PATCH 0439/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 741 ++++++++++++++++++++++++++++++++++++----- po/ast.po | 701 +++++++++++++++++++++++++++++++++++---- po/ca.po | 709 +++++++++++++++++++++++++++++++++++---- po/cs.po | 746 ++++++++++++++++++++++++++++++++++++----- po/da.po | 660 ++++++++++++++++++++++++++++++++++-- po/de.po | 909 ++++++++++++++++++++++++++++++++++++++------------ po/el.po | 723 +++++++++++++++++++++++++++++++++++----- po/es.po | 888 ++++++++++++++++++++++++++++++++++++++----------- po/es_419.po | 879 +++++++++++++++++++++++++++++++++++++----------- po/fi.po | 885 +++++++++++++++++++++++++++++++++++++++---------- po/fr.po | 917 +++++++++++++++++++++++++++++++++++++++------------ po/he.po | 808 ++++++++++++++++++++++++++++++++++++++------- po/hr.po | 663 +++++++++++++++++++++++++++++++++++-- po/hu.po | 845 +++++++++++++++++++++++++++++++++++++---------- po/it.po | 857 +++++++++++++++++++++++++++++++++++++---------- po/ja.po | 849 +++++++++++++++++++++++++++++++++++++---------- po/nb.po | 840 +++++++++++++++++++++++++++++++++++++--------- po/nl.po | 802 ++++++++++++++++++++++++++++++++++++-------- po/pl.po | 804 ++++++++++++++++++++++++++++++++++++-------- po/pt_BR.po | 864 ++++++++++++++++++++++++++++++++++++++---------- po/pt_PT.po | 858 ++++++++++++++++++++++++++++++++++++++--------- po/ro.po | 731 +++++++++++++++++++++++++++++++++++----- po/ru.po | 836 +++++++++++++++++++++++++++++++++++++--------- po/sk.po | 832 +++++++++++++++++++++++++++++++++++++--------- po/sr.po | 806 ++++++++++++++++++++++++++++++++++++-------- po/tr.po | 816 +++++++++++++++++++++++++++++++++++++-------- po/uk.po | 842 +++++++++++++++++++++++++++++++++++++--------- po/zh_CN.po | 755 +++++++++++++++++++++++++++++++++++++----- po/zh_TW.po | 735 ++++++++++++++++++++++++++++++++++++----- 29 files changed, 19497 insertions(+), 3804 deletions(-) diff --git a/po/ar.po b/po/ar.po index 02de226f..64a1b870 100644 --- a/po/ar.po +++ b/po/ar.po @@ -1,1132 +1,1439 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # safa1996alfulaij , 2015 # صفا الفليج , 2015-2016 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Arabic (http://www.transifex.com/lfleischer/aur/language/" -"ar/)\n" -"Language: ar\n" +"Language-Team: Arabic (http://www.transifex.com/lfleischer/aurweb/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " -"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"Language: ar\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +#: html/404.php msgid "Page Not Found" msgstr "لم يُعثر على الصّفحة" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "آسفون، الصّفحة التي طلبتها غير موجودة." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "ملاحظة" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "الخدمة غير متوفّرة" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "لا تفزع! عُطّل الموقع لأعمال الصّيانة. سنعود قريبًا." +#: html/account.php msgid "Account" msgstr "حساب" +#: html/account.php template/header.php msgid "Accounts" msgstr "الحسابات" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "ليس مسموحًا لك بالنّفاذ إلى هنا." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "تعذّر جلب معلومات المستخدم المحدّد." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "لا صلاحيّات لديك لتحرير هذا الحساب." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "استخدم هذه الاستمارة للبحث عن حسابات موجودة." +#: html/account.php msgid "You must log in to view user information." msgstr "عليك الولوج لعرض معلومات المستخدمين." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "أضف رأيًا" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "اسم المستخدم غير موجود." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "" +#: html/addvote.php msgid "Invalid type." msgstr "النّوع غير صالح." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "لا يمكن أن يكون الرّأي فارغًا." +#: html/addvote.php msgid "New proposal submitted." msgstr "قُدّم رأي جديد." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "قدّم رأيًا للتّصويت عليه." +#: html/addvote.php msgid "Applicant/TU" msgstr "" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(فارغ إن لم ينطبق)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "النّوع" +#: html/addvote.php msgid "Addition of a TU" msgstr "إضافة م‌م" +#: html/addvote.php msgid "Removal of a TU" msgstr "إزالة م‌م" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "الرّأي" +#: html/addvote.php msgid "Submit" msgstr "قدّم" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "أدر المصينين المشاركين" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "حرّر التّعليق" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "الرّئيسيّة" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "حزمي" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ " -"الموثوقين (م‌م)%s لمعلومات أكثر." +msgstr "مرحبًا بك في م‌م‌آ! فضلًا اقرأ %sإرشادات مستخدمي م‌م‌آ%s و%sإرشادات مستخدمي م‌م‌آ الموثوقين (م‌م)%s لمعلومات أكثر." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"ملفّات PKGBUILD التي تساهم بها %sيجب%s أن تتّبع %sمعايير التّحزيم في آرتش%s " -"وإلا فستُحذف!" +msgstr "ملفّات PKGBUILD التي تساهم بها %sيجب%s أن تتّبع %sمعايير التّحزيم في آرتش%s وإلا فستُحذف!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "تذكّر أن تصوّت لحزمك المفضّلة!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "قد تكون بعض الحزم متوفّرة كثنائيّات في مستودع المجتمع [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "إخلاء مسؤوليّة" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"حزم م‌م‌آ هي حزم قدّمها المستخدمين. أيّ استخدام للملفّات يكون على مسؤوليّتك الخاصّة." +msgstr "حزم م‌م‌آ هي حزم قدّمها المستخدمين. أيّ استخدام للملفّات يكون على مسؤوليّتك الخاصّة." +#: html/home.php msgid "Learn more..." msgstr "اطّلع على المزيد..." +#: html/home.php msgid "Support" msgstr "الدّعم" +#: html/home.php msgid "Package Requests" msgstr "طلبات الحزم" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة " -"تفاصيل الحزمة:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "هناك ثلاث أنواع من الحزم التي يمكن ملؤها في مربّع %sإجراءات الحزم%s في صفحة تفاصيل الحزمة:" +#: html/home.php msgid "Orphan Request" msgstr "طلب \"يتيمة\"" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة " -"كقديمة لوقت طويل." +msgstr "اطلب أن يُتبرّأ من الحزمة، مثلًا عندما يكون مصينها غير نشط وقد عُلّمت الحزمة كقديمة لوقت طويل." +#: html/home.php msgid "Deletion Request" msgstr "طلب الحذف" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت " -"الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن " -"طلب \"يتيمة\" إن تطلّب الأمر." +msgstr "اطلب أن تُزال الحزمة من مستودع مستخدمي آرتش. فضلًا لا تستخدم هذه إن كانت الحزمة معطوبة ويمكن إصلاحها بسهولة. بدل ذلك تواصل مع مصين الحزمة وأبلغ عن طلب \"يتيمة\" إن تطلّب الأمر." +#: html/home.php msgid "Merge Request" msgstr "طلب الدّمج" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"اطلب دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو " -"استبدال بحزمة تقسيميّة." +msgstr "اطلب دمج حزمة مع أخرى. يمكن استخدامه عندما تحتاج حزمة ما إعادة تسمية أو استبدال بحزمة تقسيميّة." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. " -"لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." +msgstr "إن أردت النّقاش حول طلب ما، يمكنك استخدام قائمة %saur-requests%s البريديّة. لكن فضلًا لا تستخدمها للإبلاغ عن الطلبات." +#: html/home.php msgid "Submitting Packages" msgstr "تقديم الحزم" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع " -"قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." +msgstr "غِت Git عبر SSH يُستخدم الآن لتقديم الحزم إلى مستودع مستخدمي آرتش (م‌م‌آ). طالع قسم %sتقديم الحزم%s في صفحة مستودع مستخدمي آرتش في ويكي آرتش لتفاصيل أكثر." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "بصمات SSH الآتية مستخدمة في م‌م‌آ:" +#: html/home.php msgid "Discussion" msgstr "النّقاش" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين " -"تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِبّ م‌م‌آ، استخدم " -"قائمة %saur-dev%s البريديّة." +msgstr "النّقاشات العاّمة حول مستودع مستخدمي آرتش (م‌م‌آ) وبنية المستخدمين الموثوقين تكون في %saur-general%s. للنّقاشات المتعلّقة بتطوير واجهة وِبّ م‌م‌آ، استخدم قائمة %saur-dev%s البريديّة." +#: html/home.php msgid "Bug Reporting" msgstr "الإبلاغ عن العلل" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"إن وجدت علّة في واجهة وِبّ م‌م‌آ، فضلًا املأ تقريرًا بها في %sمتعقّب العلل%s. استخدم " -"المتعقّب للإبلاغ عن العلل في واجهة وِبّ م‌م‌آ %sفقط%s. للإبلاغ عن علل الحزم راسل " -"مديرها أو اترك تعليقًا في صفحة الحزمة المناسبة." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "إن وجدت علّة في واجهة وِبّ م‌م‌آ، فضلًا املأ تقريرًا بها في %sمتعقّب العلل%s. استخدم المتعقّب للإبلاغ عن العلل في واجهة وِبّ م‌م‌آ %sفقط%s. للإبلاغ عن علل الحزم راسل مديرها أو اترك تعليقًا في صفحة الحزمة المناسبة." +#: html/home.php msgid "Package Search" msgstr "ابحث عن حزمة" +#: html/index.php msgid "Adopt" msgstr "تبنّ" +#: html/index.php msgid "Vote" msgstr "صوّت" +#: html/index.php msgid "UnVote" msgstr "أزل التّصويت" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "الإخطار" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "أزل الإخطار" +#: html/index.php msgid "UnFlag" msgstr "أزل التّعليم" +#: html/login.php template/header.php msgid "Login" msgstr "لِج" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "والج كَـ: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "اخرج" +#: html/login.php msgid "Enter login credentials" msgstr "أدخل بيانات الولوج" +#: html/login.php msgid "User name or email address" msgstr "اسم المستخدم أو عنوان البريد الإلكترونيّ" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "كلمة المرور" +#: html/login.php msgid "Remember me" msgstr "تذكّرني" +#: html/login.php msgid "Forgot Password" msgstr "نسيت كلمة المرور" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "ولوج HTTP معطّل. فضلًا %sبدّل إلى HTTPs%s إن أردت الولوج." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "معايير البحث" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "الحزم" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "خطأ في محاولة جلب تفاصيل الحزمة." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "أحد الحقول المطلوبة ناقصة." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "حقلا كلمة المرور لا يتطابقان." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "يجب أن تكون كلمة مرورك بطول %s محارف على الأقل." +#: html/passreset.php msgid "Invalid e-mail." msgstr "بريد إلكترونيّ غير صالح." +#: html/passreset.php msgid "Password Reset" msgstr "صفّر كلمة المرور" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "افحص بريدك الإلكترونيّ لوصلة التّأكيد." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "صُفّرت كلمة مرورك بنجاح." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "أكّد عنوان بريدك الإلكترونيّ:" +#: html/passreset.php msgid "Enter your new password:" msgstr "أدخل كلمة مرورك الجديدة:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "أكّد كلمة مرورك الجديدة:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "تابع" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى " -"قائمة %saur-general%s البريديّة." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى قائمة %saur-general%s البريديّة." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "أدخل عنوان بريدك الإلكترونيّ:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "لم يُتنازل عن الحزم المحدّدة، افحص مربع تأشير التّأكيد." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "تعذّر العثور على الحزمة لدمج التّصويتات والتّعليقات معها." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "لا يمكن الدّمج بلا أساس الحزمة نفسه." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "لم تُحذف الحزم المحدّدة، افحص مربع تأشير التّأكيد." +#: html/pkgdel.php msgid "Package Deletion" msgstr "احذف حزمة" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "احذف الحزمة" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "استخدم هذه الاستمارة لحذف أساس الحزمة %s%s%s والحزم الآتية من م‌م‌آ:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "حذف الحزم نهائيّ." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "حدّد مربع تأشير لتأكيد الإجراء." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "أكّد حذف الحزمة" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "احذف" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين حذف الحزم." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "تنازل عن حزمة" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "استخدم هذه الاستمارة للتّنازل عن أساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة ونقل ملكيّتها إلى %s%s%s." +msgstr "بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة ونقل ملكيّتها إلى %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "بتأشير مربع التّأشير، أنت تؤكّد على تنازلك عن الحزمة." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "أكّد التّنازل عن الحزمة" +#: html/pkgdisown.php msgid "Disown" msgstr "تنازل" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين التّنازل عن الحزم." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "علّم الحزمة كقديمة" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "استخدم هذه الاستمارة لتعليم أساس الحزمة %s%s%s والحزم الآتية كقديمة:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"من فضلك %sلا%s تستخدم هذه الاستمارة للتّبليع عن العلل. علّق على الحزم بدل ذلك." +msgstr "من فضلك %sلا%s تستخدم هذه الاستمارة للتّبليع عن العلل. علّق على الحزم بدل ذلك." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "التّعليقات" +#: html/pkgflag.php msgid "Flag" msgstr "علّم" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "يمكن فقط للمستخدمين المسجّلين تعليم الحزم كقديمة." +#: html/pkgmerge.php msgid "Package Merging" msgstr "ادمج حزمة" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "ادمج الحزم" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "استخدم هذه الاستمارة لدمج أساس الحزمة %s%s%s مع حزمة أخرى." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "ستُحذف الحزم الآتية:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "بمجرّد دمج الحزمة لا يمكن عكس الإجراء." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "أدخل اسم الحزمة التي ترغب بدمج الحزمة معها." +#: html/pkgmerge.php msgid "Merge into:" msgstr "ادمج مع:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "أكّد دمج الحزم" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "دمج" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين دمج الحزم." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "أغلق الطّلب" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "الأولى" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "السّابقة" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "التّالية" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "الأخيرة" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "الطّلبات" +#: html/register.php template/header.php msgid "Register" msgstr "سجّل" +#: html/register.php msgid "Use this form to create an account." msgstr "استخدم هذه الاستمارة لإنشاء حساب." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "مستخدم موثوق" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "تعذّر استرجاع تفاصيل الرّأي." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "أُغلق التّصويت على هذا الرّأي." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "فقط المستخدمين الموثوقين مسموح لهم بالتّصويت." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "لا يمكنك التّصويت على رأي عنك." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "لقد صوّتّ على هذا الرّأي بالفعل." +#: html/tu.php msgid "Vote ID not valid." msgstr "معرّف التّصويت غير صالح." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "التّصويتات الحاليّة" +#: html/tu.php msgid "Past Votes" msgstr "التّصويتات الماضية" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "المصوّتون" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " -"المتكرّرة. آسفون لإزاعجك" +msgstr "تسجيل الحسابات معطّل حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "معرّف المستخدم ناقص" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "اسم المستخدم غير صالح." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "يجب أن يكون بطول بين %s و %s محرفًا" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "يجب أن يبدأ وينتهي بحرف أو رقم." +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "يمكنه احتواء نقطة واحدة، أو شرطة سفليّة واحدة أو شرطة واحدة." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "عنوان البريد الإلكترونيّ غير صالح." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "بصمة مفتاح PGP غير صالحة." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "مفتاح SSH العموميّ غير صالح." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "لا يمكن زيادة صلاحيّات الحساب." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "اللغة غير مدعومة حاليًّا." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "اسم المستخدم %s%s%s مستخدم بالفعل." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "العنوان %s%s%s مستخدم بالفعل." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "مفتاح SSH العموميّ %s%s%s مستخدم بالفعل." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "فشلت محاولة إنشاء الحساب %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "أُنشئ الحساب %s%s%s بنجاح." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "مفتاح تصفير كلمة المرور أُرسل إلى عنوان بريدك الإلكترونيّ." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "انقر وصلة الولوج أعلاه لاستخدام حسابك." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "لم تجري أيّ تغييرات على الحساب %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "عُدّل الحساب %s%s%s بنجاح." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة " -"المتكرّرة. آسفون لإزاعجك." +msgstr "استمارة الولوج معطّلة حاليًّا لعنوان IP خاصّتك، لربمّا بسبب هجماتك السّخاميّة المتكرّرة. آسفون لإزاعجك." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "عُلّق الحساب" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد " -"الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من " -"صفحة %sصفّر كلمة المرور%s." +msgstr "لقد صُفّرت كلمة مرورك. إن أنشئت حسابًا جديدًا للتّوّ، فضلًا استخدم الوصلة من الريد الإلكتروني التّأكيديّ لتعيين كلمة مرور أوّليّة. وإلّا، فضلًا اطلب مفتاح تصفير من صفحة %sصفّر كلمة المرور%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "اسم مستخدم أو كلمة مرور سيئّة." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "حدث خطأ أثناء توليد جلسة مستخدم." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "البريد الإلكترونيّ وتجميعة مفاتيح التّصفير غير صالحة." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "بلا" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "اعرض معلومات حساب %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "معرّف أساس الحزمة أو اسمه ناقص." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "ليس مسموحًا لك بتحرير هذا التّعليق." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "التّعليق غير موجود." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "لا يمكن أن يكون التّعليق فارغًا." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "أُضيف التّعليق" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "عليك الولوج قبل تحرير معلومات الحزم." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "معرّف التّعليق ناقص." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "لا يمكن تثبيت أكثر من 5 تعليقات." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "ليس مسموحًا لك بتثبيت هذا التّعليق." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "ليس مسموحًا لك بفكّ تثبيت هذا التّعليق." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "ثّبّت التّعليق." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "فُكّ تثبيت التعليق." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "خطأ في استرجاع تفاصيل الحزمة." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "تعذّر العثور على تفاصيل الحزمة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "عليك الولوج قبل تعليم الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "لم تحدّد أيّ حزم لتعليمها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "لم تعلّم الحزم المحدّدة، فضلًا أدخل تعليقًا." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "عُلّمت الحزم المحدّدة كقديمة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "عليك الولوج قبل إزالة تعليم الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "لم تحدّد أيّ حزم لإزالة تعليمها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "أزثيل تعليم الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "لا صلاحيّة لديك لحذف الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "لم تحدّد أيّ حزم لحذفها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "حُذفت الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "عليك الولوج قبل تبنّي الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "عليك الولوج قبل التّنازل عن الحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "لم تحدّد أيّ حزم لتبنّيها." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "لم تحدّد أيّ حزم للتّنازل عنها." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "تُبنّيت الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "تُنوزل عن الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "عليك الولوج قبل التّصويت للحزم." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "عليك الولوج قبل إزالة التصّويت للحزم." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "لم تحدّد أيّ حزم للتّصويت لها." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "أُزيلت تصويتاتك من الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "أُدليت تصويتاتك على الحزم المحدّدة." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "تعذّرت الإضافة إلى قائمة الإخطارات." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "أُضفت إلى قائمة إخطار التّعليقات لِـ %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "أُزلت من قائمة إخطار التّعليقات لِـ %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "ليس مسموحًا لك بحذف هذا التّعليق." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "حُذف التّعليق." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "حُرّر التّعليق." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "ليس مسموحًا لك بتحرير كلمات أساس الحزمة المفتاحيّة." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "حُدّثت كلمات أساس الحزمة المفتاحيّة." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "ليس مسموحًا لك بإدارة مصيني أساس الحزمة هذا المشاركين." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "اسم مستخدم غير صالح: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "حُدّث مصيني أساس الحزمة المشاركين." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "اعرض تفاصيل حزمة" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "تطلب %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "عليك الولوج لفتح طلبات حزم." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "اسم غير صالح: فقط الأحرف بالحالة الصغيرة مسموح بها." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "يجب ألّا يكون حقل التّعليق فارغًا." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "نوع الطّلب غير صالح." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "أُضيف الطّلب بنجاح." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "سبب غير صالح." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "يمكن فقط للمستخدمين الموثوقين والمطوّرين إغلاق الطّلبات." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "ُأُغلق الطّلب بنجاح." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "يمكنك استخدام هذه الاستمارة لحذف حساب م‌م‌آ هذا %s نهائيًّا." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sتحذير%s: هذا إجراء لا عودة فيه." +#: template/account_delete.php msgid "Confirm deletion" msgstr "أكّد الحذف" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "اسم المستخدم" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "نوع الحساب" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "مستخدم" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "مطوّر" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "مستخدم موثوق ومطوّر" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "البريد الإلكترونيّ" +#: template/account_details.php msgid "hidden" msgstr "مخفيّ" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "الاسم الحقيقيّ" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "الرّئيسيّة" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "اسم آي‌آر‌سي المستعار" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "بصمة مفتاح PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "الحالة" +#: template/account_details.php msgid "Inactive since" msgstr "غير نشط منذ" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "نشط" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "مجهول" +#: template/account_details.php msgid "Last Login" msgstr "آخر ولوج" +#: template/account_details.php msgid "Never" msgstr "أبدًا" +#: template/account_details.php msgid "View this user's packages" msgstr "اعرض ملفّ هذا المستخدم الشخصيّ" +#: template/account_details.php msgid "Edit this user's account" msgstr "حرّر حساب هذا المستخدم" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "انقر %sهنا%s إن أردت حذف هذا الحساب نهائيًّا." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "مطلوب" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "مستخدم عاديّ" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "مستخدم موثوق" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "حساب معلّق" +#: template/account_edit_form.php msgid "Inactive" msgstr "غير نشط" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "فضلًا تأكّد من إدخال البريد الإلكترونيّ الصّحيح، وإلّا فسيُقفل الحساب." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "أخفِ عنوان البريد الإلكترونيّ" +#: template/account_edit_form.php msgid "Re-type password" msgstr "أعد كتابة كلمة المرور" +#: template/account_edit_form.php msgid "Language" msgstr "اللغة" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "المعلومات الآتية مطلوبة فقط إن أردت تقديم حزم إلى مستودع مستخدمي آرتش." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "مفتاح SSH العموميّ" +#: template/account_edit_form.php msgid "Notification settings" msgstr "إعدادات الإخطارات" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "أخطرني بالتّعليقات الجديدة" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "أخطرني بتحديثات الحزم" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "أخطرني بتغيير المُلّاك" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "حدّث" +#: template/account_edit_form.php msgid "Create" msgstr "أنشئ" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "صفّر" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "لا نتائج طابقت معايير بحثك." +#: template/account_search_results.php msgid "Edit Account" msgstr "حرّر الحساب" +#: template/account_search_results.php msgid "Suspended" msgstr "معلّق" +#: template/account_search_results.php msgid "Edit" msgstr "حرّر" +#: template/account_search_results.php msgid "Less" msgstr "أقلّ" +#: template/account_search_results.php msgid "More" msgstr "أكثر" +#: template/account_search_results.php msgid "No more results to display." msgstr "لا نتائج أخرى لعرضها." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "استخدم هذه الاستمارة لإضافة مصينين مشاركين لِـ %s%s%s (اسم في كلّ سطر):" +#: template/comaintainers_form.php msgid "Users" msgstr "المستخدمون" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "احفظ" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "تعليق التّعليم كقديمة: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "علّم %s%s%s الحزمة %s%s%s بقديمة في %s%s%s وذلك للأسباب الآتية:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "لم تُعلّم الحزمة %s%s%s كقديمة." +#: template/flag_comment.php msgid "Return to Details" msgstr "عُد إلى التّفاصيل" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "الحقوق محفوظة %s 2004-%d فريق تطوير aurweb." +#: template/header.php msgid " My Account" msgstr "حسابي" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "إجراءات الحزمة" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "اعرض PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "اعرض التّغييرات" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "نزّل لقطة شاشة" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "ابحث في الويكي" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "معلّمة كقديمة (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "علّم الحزمة كقديمة" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "أزل تعليم الحزمة" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "أزل التّصويت" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "صوّت لهذه الحزمة" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "عطّل الإخطارات" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "فعّل الإخطارات" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "أدر المصينين المشاركين" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1137,180 +1444,238 @@ msgstr[3] "%d طلبات منتظرة" msgstr[4] "%d طلبًا منتظرًا" msgstr[5] "%d طلب منتظر" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "تبنّ الحزمة" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "تفاصيل أساس الحزمة" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "عنوان غِت للاستنساخ" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "للقراءة فقط" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "الكلمات المفتاحيّة" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "المقدّم" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "المصين" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "آخر محزّم" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "التّصويتات" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "الشّعبيّة" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "أول تقديم" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "آخر تحديث" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "حرّر تعليق: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "أضف تعليقًا" +#: template/pkg_comments.php msgid "View all comments" msgstr "اعرض كلّ التّعليقات" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "التّعليقات المثبّتة" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "آخر التّعليقات" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "علّق %s على %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "تعليق مجهول على %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "احذف التّعليق" +#: template/pkg_comments.php msgid "Pin comment" msgstr "ثبّت التّعليق" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "فكّ تثبيت التّعليق" +#: template/pkg_comments.php msgid "All comments" msgstr "كلّ التّعليقات" +#: template/pkg_details.php msgid "Package Details" msgstr "تفاصيل الحزمة" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "أساس الحزمة" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "الوصف" +#: template/pkg_details.php msgid "Upstream URL" msgstr "عنوان المنبع" +#: template/pkg_details.php msgid "Visit the website for" msgstr "زُر موقع وِبّ" +#: template/pkg_details.php msgid "Licenses" msgstr "الرّخص" +#: template/pkg_details.php msgid "Groups" msgstr "المجموعات" +#: template/pkg_details.php msgid "Conflicts" msgstr "تتعارض مع" +#: template/pkg_details.php msgid "Provides" msgstr "توفّر" +#: template/pkg_details.php msgid "Replaces" msgstr "تستبدل" +#: template/pkg_details.php msgid "Dependencies" msgstr "الاعتماديّات" +#: template/pkg_details.php msgid "Required by" msgstr "تطلبها" +#: template/pkg_details.php msgid "Sources" msgstr "المصادر" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "استخدم هذه الاستمارة لإغلاق طلب أساس الحزمة %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." +msgstr "يمكن ترك حقل التّعليقات فارغًا. مع ذلك، من المستحسن إضافة تعليق عند رفض طلب ما." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "السّبب" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "مقبول" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "مرفوض" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"استخدم هذه الاستمارة لفتح طلب لأساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +msgstr "استخدم هذه الاستمارة لفتح طلب لأساس الحزمة %s%s%s المتضمّنة الحزم الآتية:" +#: template/pkgreq_form.php msgid "Request type" msgstr "نوع الطّلب" +#: template/pkgreq_form.php msgid "Deletion" msgstr "حذف" +#: template/pkgreq_form.php msgid "Orphan" msgstr "يتيمة" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "ادمج مع" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1318,6 +1683,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1325,9 +1691,11 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1338,19 +1706,24 @@ msgstr[3] "عُثر على %d طلبات حزم." msgstr[4] "عُثر على %d طلب حزمة." msgstr[5] "عُثر على %d طلب حزمة." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "الصّفحة %d من %d." +#: template/pkgreq_results.php msgid "Package" msgstr "الحزم" +#: template/pkgreq_results.php msgid "Filed by" msgstr "فتحه:" +#: template/pkgreq_results.php msgid "Date" msgstr "التّاريخ" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" @@ -1361,6 +1734,7 @@ msgstr[3] "" msgstr[4] "" msgstr[5] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1371,96 +1745,128 @@ msgstr[3] "بقي حوالي %d ساعات" msgstr[4] "بقي حوالي %d ساعةً" msgstr[5] "بقي حوالي %d ساعة" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "بقيت أقلّ من ساعة" +#: template/pkgreq_results.php msgid "Accept" msgstr "اقبل" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "أغلق" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "مغلق" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "الاسم، الوصف" +#: template/pkg_search_form.php msgid "Name Only" msgstr "الاسم فقط" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "الاسم بالضّبط" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "أساس الحزمة بالضّبط" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "الكلّ" +#: template/pkg_search_form.php msgid "Flagged" msgstr "المعلّمة" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "غير المعلّمة" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "الاسم" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "مصوّت عليها" +#: template/pkg_search_form.php msgid "Last modified" msgstr "آخر تعديل" +#: template/pkg_search_form.php msgid "Ascending" msgstr "تصاعديًّا" +#: template/pkg_search_form.php msgid "Descending" msgstr "تنازليًّا" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "أدخل معايير البحث" +#: template/pkg_search_form.php msgid "Search by" msgstr "ابحث حسب" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "القديمة" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "افرز حسب" +#: template/pkg_search_form.php msgid "Sort order" msgstr "ترتيب الفرز" +#: template/pkg_search_form.php msgid "Per page" msgstr "لكلّ صفحة" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "انطلق" +#: template/pkg_search_form.php msgid "Orphans" msgstr "اليتيمة" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "خطأ في استرجاع قائمة الحزم." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "لا حزم طابقت معايير بحثك." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1471,117 +1877,278 @@ msgstr[3] "عُثر على %d حزم." msgstr[4] "عُثر على %d حزمةً." msgstr[5] "عُثر على %d حزمة." +#: template/pkg_search_results.php msgid "Version" msgstr "الإصدارة" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "نعم" +#: template/pkg_search_results.php msgid "orphan" msgstr "يتيمة" +#: template/pkg_search_results.php msgid "Actions" msgstr "الإجراءات" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "أزل التّعليم كقديمة" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "تبنّ الحزم" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "تنازل عن الحزم" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "احذف الحزم" +#: template/pkg_search_results.php msgid "Confirm" msgstr "أكّد" +#: template/search_accounts_form.php msgid "Any type" msgstr "أيّ نوع" +#: template/search_accounts_form.php msgid "Search" msgstr "ابحث" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "الإحصائيّات" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "الحزم اليتيمة" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "الحزم المضافة في السّبعة أيّام الماضية" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "الحزم المحدّثة في السّبعة أيّام الماضية" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "الحزم المضافة في السّنة الماضية" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "الحزم التي لم تحدّث مطلقًا" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "المستخدمون المسجّلون" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "المستخدمون الموثوقون" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "التّحديثات الأخيرة" +#: template/stats/updates_table.php msgid "more" msgstr "أخرى" +#: template/stats/user_table.php msgid "My Statistics" msgstr "إحصائيّاتي" +#: template/tu_details.php msgid "Proposal Details" msgstr "تفاصيل الرّأي" +#: template/tu_details.php msgid "This vote is still running." msgstr "ما زال هذا التّصويت قائمًا." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "قدّمه (في %s) ‏%s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "النّهاية" +#: template/tu_details.php msgid "Result" msgstr "النّتيجة" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "لا" +#: template/tu_details.php msgid "Abstain" msgstr "الامتناع" +#: template/tu_details.php msgid "Total" msgstr "المجموع" +#: template/tu_details.php msgid "Participation" msgstr "المشاركة" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "آخر التّصويتات لِـ م‌م" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "آخر تصويت" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "لم يُعثر على أيّ نتيجة." +#: template/tu_list.php msgid "Start" msgstr "البداية" +#: template/tu_list.php msgid "Back" msgstr "السّابق" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/ast.po b/po/ast.po index 0b1ca085..df9db049 100644 --- a/po/ast.po +++ b/po/ast.po @@ -1,1295 +1,1678 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # enolp , 2014-2015,2017 # Ḷḷumex03 , 2014 # Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2014-2015 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Asturian (http://www.transifex.com/lfleischer/aur/language/" -"ast/)\n" -"Language: ast\n" +"Language-Team: Asturian (http://www.transifex.com/lfleischer/aurweb/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: ast\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Nun s'alcontró la páxina" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Perdón, la páxina que pidisti nun esiste." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "Serviciu non disponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "¡Asela! Esti sitiu ta cayíu debío a caltenimientu. Volverémos ceo." +#: html/account.php msgid "Account" msgstr "Cuenta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentes" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nun tienes permisu p'acceder a esta area." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nun pudo recibise la información pal usuariu especificáu." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nun tienes permisu pa editar esta cuenta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa esti formulariu pa guetar cuentes esistentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Tienes d'aniciar sesión pa ver la información del usuariu." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Amestar propuesta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Token non válidu pa la aición del usuariu" +#: html/addvote.php msgid "Username does not exist." msgstr "El nome d'usuariu nun esiste." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s yá tien la propuesta que cuerre pa ellos." +#: html/addvote.php msgid "Invalid type." msgstr "Triba non válida." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta nun pue tar balera" +#: html/addvote.php msgid "New proposal submitted." msgstr "Unvióse la propuesta nueva." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "" +#: html/addvote.php msgid "Applicant/TU" msgstr "Aplicante/Usuariu d'Enfotu." +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(baletu si nun s'aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Triba" +#: html/addvote.php msgid "Addition of a TU" msgstr "Añedir un Usuariu d'Enfotu" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" +#: html/addvote.php msgid "Submit" msgstr "Unviar" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Aniciu" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Los mios paquetes" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"¡Bienllegáu al AUR! Llei la %sGuía d'usuariu del AUR%s y la %sGuía d'usuariu " -"TU del AUR%s pa más información." +msgstr "¡Bienllegáu al AUR! Llei la %sGuía d'usuariu del AUR%s y la %sGuía d'usuariu TU del AUR%s pa más información." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Los PKGBUILD contribuyíos %stienen%s de ser compatibles col %sEstándar de " -"empaquetado de Arch%s d'otra forma van ser esaniciaos." +msgstr "Los PKGBUILD contribuyíos %stienen%s de ser compatibles col %sEstándar de empaquetado de Arch%s d'otra forma van ser esaniciaos." +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerda votar los tos paquetes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Dellos paquetes puen apurrise como binarios en [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Los paquetes d'AUR son conteníu producíu polos usuarios. Cualesquier usu de " -"los ficheros forníos ta sol to propiu riesgu." +msgstr "Los paquetes d'AUR son conteníu producíu polos usuarios. Cualesquier usu de los ficheros forníos ta sol to propiu riesgu." +#: html/home.php msgid "Learn more..." msgstr "Llei más..." +#: html/home.php msgid "Support" msgstr "Sofitu" +#: html/home.php msgid "Package Requests" msgstr "Solicitúes de paquetes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "Solicitú güérfana" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "Solicitú de desaniciu" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "Solicitú de desanciu" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "Unviu de paquetes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Agora úsase GIT sobro SSH pa unviar paquetes a AUR. Mira la estaya %sUnviu " -"de paquetes%s de la páxina ArchWiki del AUR pa más detalles." +msgstr "Agora úsase GIT sobro SSH pa unviar paquetes a AUR. Mira la estaya %sUnviu de paquetes%s de la páxina ArchWiki del AUR pa más detalles." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Les buelgues SSH de darréu úsense pal AUR:" +#: html/home.php msgid "Discussion" msgstr "Discutiniu" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Informe de fallos" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Gueta de paquetes" +#: html/index.php msgid "Adopt" msgstr "Adoptar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Retirar votu" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Avisar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "" +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "Aniciar sesión" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "" +#: html/login.php template/header.php msgid "Logout" msgstr "Zarrar sesión" +#: html/login.php msgid "Enter login credentials" msgstr "Introduz les tos credenciales d'aniciu sesión" +#: html/login.php msgid "User name or email address" msgstr "Nome d'usuariu o direición de corréu" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" +#: html/login.php msgid "Remember me" msgstr "Recordáime" +#: html/login.php msgid "Forgot Password" msgstr "Escaecí la contraseña" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteriu de gueta" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Fallu intentando recibir los detalles del paquete." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campu riquíu." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Nun concasen los campos de contraseñes" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La to contraseña tien de tener polo menos %s carauteres." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Corréu electrónicu non válidu" +#: html/passreset.php msgid "Password Reset" msgstr "Reaniciu de contraseña" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Comprueba'l to corréu pal enllaz de confirmación." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La to contraseña reanicióse con ésitu." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirma'l to corréu:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Introduz la to contraseña nueva:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirma la to contraseña nueva:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Siguir" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si escaecisti la dirección de corréu electrónicu utilizasti pa rexistrar, " -"complacer unviar un mensaxe a la llista de orréu %saur-xeneral%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si escaecisti la dirección de corréu electrónicu utilizasti pa rexistrar, complacer unviar un mensaxe a la llista de orréu %saur-xeneral%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduz la to direción de corréu:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "Desaniciu de paquete" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Usa esti formulariu pa desaniciar el paquete base %s%s%s y los paquetes " -"siguientes d'AUR:" +msgstr "Usa esti formulariu pa desaniciar el paquete base %s%s%s y los paquetes siguientes d'AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El desaniciu d'un paquete ye permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmar desaniciu de paquete" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Desaniciar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"%sNun%s uses esti formulariu pa informar de fallos, por favor. Usa nel so " -"llugar los comentarios del paquete." +msgstr "%sNun%s uses esti formulariu pa informar de fallos, por favor. Usa nel so llugar los comentarios del paquete." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Comentarios" +#: html/pkgflag.php msgid "Flag" msgstr "" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Desaniciaránse los paquetes de darréu:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduz el nome del paquete al que deseyes amestar" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zarar solicitú" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Solicitúes" +#: html/register.php template/header.php msgid "Register" msgstr "Rexistrase" +#: html/register.php msgid "Use this form to create an account." msgstr "Usa esti formulariu pa crear una cuenta." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "" +#: html/tu.php msgid "Vote ID not valid." msgstr "Nun ye válida la ID del votu." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" +#: html/tu.php msgid "Past Votes" msgstr "Votos pasaos" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta la ID d'usuariu" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nome d'usuariu nun ye válidu" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Tien de tar ente %s y %s carauteres de llargor" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La direición de corréu nun ye válida." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La buelga de la clave PGP nun ye válida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave SSH pública nun ye válida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nun puen aumentase los permisos de la cuenta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "La llingua nun ta anguaño sofitada." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nome d'usuariu, %s%s%s, yá ta n'usu." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La direición, %s%s%s, yá ta n'usu." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La llave pública SSH, %s%s%s, ye yá n'usu." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Fallu intentando crear la cuenta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, creóse con ésitu." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Primi nel enllaz d'aniciu de sesión d'enriba pa usar la to cuenta" +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nun se fixeron camudancies na cuenta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, modificóse con ésitu." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Reanicióse la to contraseña. Si tas acabantes crear una cuenta nueva, usa " -"l'enllaz del corréu de confirmación p'afitar una contraseña inicial, por " -"favor. D'otramiente, solicita una clave de reaniciu na páxina %sReaniciu de " -"contraseña%s, por favor." +msgstr "Reanicióse la to contraseña. Si tas acabantes crear una cuenta nueva, usa l'enllaz del corréu de confirmación p'afitar una contraseña inicial, por favor. D'otramiente, solicita una clave de reaniciu na páxina %sReaniciu de contraseña%s, por favor." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nome d'usuariu o contraseña incorreutos" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Asocedió un fallu intentando xenerar una sesión d'usuariu." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nun tienes permisu pa editar esti comentariu." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Nun esiste'l comentariu." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Nun pue tar baleru'l comentariu." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Amestóse'l comentariu." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Falta la ID del comentariu." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Fallu recibiendo los detalles de paquete." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nun pudieron alcontrase los detalles del paquete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nun esbillesti dengún ficheru pa desaniciar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Desaniciáronse los paquetes esbillaos." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nun pudo amestase al llistáu d'avisos." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nun tienes permisu pa desaniciar esti comentariu." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "El comentariu amestóse." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Editóse'l comentariu." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nome d'usuariu non válidu: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles de paquetes pa" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campu del comentariu nun tien de tar baleru." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Triba de solicitú non válida." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Amestada con ésitu la solicitú." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón non válida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Solicitú zarrada con ésitu." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Pues usar esti formulariu pa desaniciar la cuenta del AUR %s dafechu." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sAVISU%s: Esta aición nun pue desfacese." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar desaniciu" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nome d'usuariu" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Triba de cuenta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuariu" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desendolcador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Direición de corréu" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alcuñu nel IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Buelga de clave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estáu" +#: template/account_details.php msgid "Inactive since" msgstr "Inactivu dende" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activu" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "Desconocíu" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Enxamás" +#: template/account_details.php msgid "View this user's packages" msgstr "" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Primi %sequí%s si quies desaniciar esta cuenta dafechu." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "riquíu" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuariu normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuariu d'Enfotu" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivu" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Teclexa de nueves la contraseña" +#: template/account_edit_form.php msgid "Language" msgstr "Llingua" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La información de darréu namái se rique si quies xubir paquetes al AUR." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La información de darréu namái se rique si quies xubir paquetes al AUR." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave SSH pública" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Anovar" +#: template/account_edit_form.php msgid "Create" msgstr "Crear" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reafitar" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "" +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar cuenta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendíu" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Más" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nun hai más resultaos p'amosar." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuarios" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Guardar" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "La mio cuenta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Aiciones de paquete" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver camudancies" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Baxar instantánea" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Guetar na wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcáu como non actualizáu" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Quitar marca de non actualizáu" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Quitar votu" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar pol paquete" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Alministra comantenedores" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL pa clonar con Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Pallabres clave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Caltenedor" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Amestar comentariu" +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver tolos comentarios" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Comentarios caberos" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Desaniciar comentariu" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Tolos comentarios" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "Llicencies" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "Apurre" +#: template/pkg_details.php msgid "Replaces" msgstr "Troca" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencies" +#: template/pkg_details.php msgid "Required by" msgstr "Riquíu por" +#: template/pkg_details.php msgid "Sources" msgstr "Fontes" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa esti formulariu pa zarrar la solicitú pal paquete base %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"El campu de comentarios pue dexase baleru, Por embargu, encamiéntase amestar " -"un comentariu al refugar una solicitú." +msgstr "El campu de comentarios pue dexase baleru, Por embargu, encamiéntase amestar un comentariu al refugar una solicitú." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceutáu" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Refugáu" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "Triba de solicitú" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Desaniciu" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Güérfanu" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1297,6 +1680,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1304,247 +1688,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Páxina %d de %d" +#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Falta ~%d hora" msgstr[1] "Falten ~%d hores" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "Falta menos d'una hora" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceutar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloquiáu" +#: template/pkgreq_results.php msgid "Close" msgstr "Zarrar" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zarráu" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descripción" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Namái nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exautu" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exautu" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Too" +#: template/pkg_search_form.php msgid "Flagged" msgstr "" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Guetar per" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Ensin anovar" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar per" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Mou d'ordenación" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per páxina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Dir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Güérfanos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nun hai paquetes que concasen col criteriu de gueta." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Alcontróse %d paquete." msgstr[1] "Alcontráronse %d paquetes" +#: template/pkg_search_results.php msgid "Version" msgstr "Versión" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "güérfanu" +#: template/pkg_search_results.php msgid "Actions" msgstr "Aiciones" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "" +#: template/pkg_search_results.php msgid "Confirm" msgstr "" +#: template/search_accounts_form.php msgid "Any type" msgstr "" +#: template/search_accounts_form.php msgid "Search" msgstr "" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadístiques" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes güérfanos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes amestaos nos pasaos 7 díes" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes anovaos nos pasaos 7 díes" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes anovaos nel añu caberu" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes qu'enxamás s'anovaron" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios rexistraos." +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios d'enfotu." +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Anovamientos recientes" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Les mios estadístiques" +#: template/tu_details.php msgid "Proposal Details" msgstr "" +#: template/tu_details.php msgid "This vote is still running." msgstr "" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Resultáu" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Non" +#: template/tu_details.php msgid "Abstain" msgstr "Astención" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participación" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nun s'alcontró dengún resultáu." +#: template/tu_list.php msgid "Start" msgstr "" +#: template/tu_list.php msgid "Back" msgstr "" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/ca.po b/po/ca.po index ef2de9b6..4ce79e69 100644 --- a/po/ca.po +++ b/po/ca.po @@ -1,1297 +1,1678 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: -# Adolfo Jayme Barrientos, 2014 +# Adolfo Jayme-Barrientos, 2014 # Hector Mtz-Seara , 2011,2013 # Lukas Fleischer , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Catalan (http://www.transifex.com/lfleischer/aur/language/" -"ca/)\n" -"Language: ca\n" +"Language-Team: Catalan (http://www.transifex.com/lfleischer/aurweb/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "No s’ha trobat la pàgina" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Ho sentim, la pàgina que ha sol·licitat no existeix." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "Compte" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No esteu autoritzat per a accedir a aquesta àrea." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No s'ha pogut obtenir la informació de l'usuari especificat." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "No teniu permís per a editar aquest compte." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilitzeu aquest formulari per a cercar comptes existents." +#: html/account.php msgid "You must log in to view user information." msgstr "Heu d'identificar-vos per a veure la inforació de l'usuari." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Afegeix proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Element invàlid per acció de l'usuari." +#: html/addvote.php msgid "Username does not exist." msgstr "El nom d’usuari no existeix." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ja te una proposta corrent per ells." +#: html/addvote.php msgid "Invalid type." msgstr "El tipus no és vàlid." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La proposta no pot estar buit." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta presentada." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Presentar una proposta per votar." +#: html/addvote.php msgid "Applicant/TU" msgstr "Sol.licitant / TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(Buit si no s'aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipus" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Envia" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Inici" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Els meus paquets" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Benvingut a l'AUR! Si us plau, llegiu les %sdirectrius d'usuari d'AUR%s i " -"les %sdirectrius de TU (usuari de confiança) d'AUR%s per més informació." +msgstr "Benvingut a l'AUR! Si us plau, llegiu les %sdirectrius d'usuari d'AUR%s i les %sdirectrius de TU (usuari de confiança) d'AUR%s per més informació." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"És %sobligatori%s que els PKGBUILDs amb que es contribueix s'ajustin als " -"%sEstandars d'empaquetament d'Arc%s, en cas contrari seran esborrats!" +msgstr "És %sobligatori%s que els PKGBUILDs amb que es contribueix s'ajustin als %sEstandars d'empaquetament d'Arc%s, en cas contrari seran esborrats!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Recordeu votar els vostres paquets preferits!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Alguns paquets poden ser oferts com binaris a [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "Avís legal" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Discussió" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Comunicar errada" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Cercar Paquets" +#: html/index.php msgid "Adopt" msgstr "" +#: html/index.php msgid "Vote" msgstr "Vota" +#: html/index.php msgid "UnVote" msgstr "Lleva el vot" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notifica" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Lleva notificació" +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Entra" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Identificat com: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Surt" +#: html/login.php msgid "Enter login credentials" msgstr "Introduïu les credencials d'inici de sessió" +#: html/login.php msgid "User name or email address" msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contrasenya" +#: html/login.php msgid "Remember me" msgstr "Recorda'm" +#: html/login.php msgid "Forgot Password" msgstr "Has oblidat la teva contrasenya" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"L'inici de sessió HTTP està deshabilitat. Si us plau %s canvia a HTTPs %s si " -"voleu iniciar la sessió." +msgstr "L'inici de sessió HTTP està deshabilitat. Si us plau %s canvia a HTTPs %s si voleu iniciar la sessió." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteri de cerca" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquets" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "S'ha produït un error en obtenir els detalls del paquet." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Manca un camp requerit." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Els camps de contrasenya no coincideixen." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La seva contrasenya ha de tenir almenys %s caràcters." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Direcció de correu electrònic no vàlida." +#: html/passreset.php msgid "Password Reset" msgstr "Restablir contrasenya" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Revisi el seu correu electrònic per a l'enllaç de confirmació." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La seva contrasenya s'ha restablert correctament." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Tots" +#: html/passreset.php msgid "Enter your new password:" msgstr "Marcat" +#: html/passreset.php msgid "Confirm your new password:" msgstr "No marcat" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si ha oblidat l'adreça de correu electrònic utilitzada al registrar-se, si " -"us plau envïi un missatge a la llista de correu %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si ha oblidat l'adreça de correu electrònic utilitzada al registrar-se, si us plau envïi un missatge a la llista de correu %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduiu la vostra adreça de correu." +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "No es pot trobar el paquet on combinar vots i comentaris." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Els paquets seleccionats no s'han esborrat, marqui la casella de confirmació." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Els paquets seleccionats no s'han esborrat, marqui la casella de confirmació." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Esborrament Paquet" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Esborrar el paquet" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "L'esborrament del paquet és permanent." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Marqueu el quadre de verificació per confirmar l'operació." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmeu l'eliminació del paquet" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Esborra" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Només els usuaris de confiança (TUs) i desenvolupadors poden eliminar " -"paquets." +msgstr "Només els usuaris de confiança (TUs) i desenvolupadors poden eliminar paquets." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Desposseir-se del paquet" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Comentaris" +#: html/pkgflag.php msgid "Flag" msgstr "Marcar" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusió de Paquets" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Fusionar el paquet" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vegada que el paquet s'ha fusionat que no es pot revertir." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introdueixi el nom del paquet amb que voleu fusionar aquest paquet." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionar amb:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmi la fusió del paquet" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusió" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Només el usuaris de confiança (TUs) i desenvolupadors poden fusionar paquets." +msgstr "Només el usuaris de confiança (TUs) i desenvolupadors poden fusionar paquets." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primer" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Següent" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Darrer" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "Registrar-se" +#: html/register.php msgid "Use this form to create an account." msgstr "Utilitzeu aquest formulari per a crear un compte." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuari de Confiança" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No es va poder recuperar detalls de la proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "La votació es va tancar per a aquesta proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No pots votar en una proposta sobre tu." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ja has votat en aquesta proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "L'identificador de vot no és vàlid." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Vots actuals" +#: html/tu.php msgid "Past Votes" msgstr "Últims vots" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votants" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El registre de comptes ha estat inhabilitat per la seva adreça IP, " -"probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +msgstr "El registre de comptes ha estat inhabilitat per la seva adreça IP, probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manca l'identificador de l'usuari" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nom d'usuari és icorrecte." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "En número de caràcters ha d'estar entre %s i %s" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comença i finalitza amb una lletra o número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Només pot contenir un punt, guió o guió baix." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adreça del correu-e no és vàlida." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "L'empremta de la clau PGP no és vàlida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No es possible augmentar els permisos del compte." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "L'idioma no està suportat actualment." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nom d'usuari, %s%s%s, ja s'està fent servir." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L'adressa, %s%s%s, ja s'està fent servir." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error al intentar crear el compte, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "El compte, %s%s%s, s'ha creat correctament." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "S'ha enviat una contrasenya nova al seu correu electrònic." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "" -"Feu clic a l'enllaç superior d'Inici de sessió per utilitzar el seu compte." +msgstr "Feu clic a l'enllaç superior d'Inici de sessió per utilitzar el seu compte." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No s'han fet canvis al compte, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "El compte, %s%s%s, s'ha modificat correctament." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El formulari de registre està deshabilitat per la seva adreça IP, " -"probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +msgstr "El formulari de registre està deshabilitat per la seva adreça IP, probablement a causa de continus atacs d'spam. Disculpeu les molèsties." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"La seva contrasenya s'ha restablert. Si acaba de crear un nou compte, si us " -"plau utilitzeu l'enllaç al correu electrònic de confirmació per configurar " -"una contrasenya inicial. En cas contrari, sol·liciti una clau de reinici a " -"la pàgina %s de restabliment de contanenya %s." +msgstr "La seva contrasenya s'ha restablert. Si acaba de crear un nou compte, si us plau utilitzeu l'enllaç al correu electrònic de confirmació per configurar una contrasenya inicial. En cas contrari, sol·liciti una clau de reinici a la pàgina %s de restabliment de contanenya %s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "nom d'usuari o contrasenya incorrectes." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." -msgstr "" -"Direcció de correu electrònic i combinació de tecles de restabliment no " -"vàlida." +msgstr "Direcció de correu electrònic i combinació de tecles de restabliment no vàlida." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Res" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Veure l'informació del compte per %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "S'ha afegit el comentari." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Heu d'identificar-vos abans d'editar qualsevol informació de paquet." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Manca l'identificador del comentari." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "No s'han pogut obtenir els detalls del paquet." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "No s'han pogut trobar els detalls del paquet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Heu d'identificar-vos abans de marcar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No heu seleccionat cap paquet per a marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Els paquets seleccionats s'han marcat com No-Actualitzats." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Heu d'identificar-vos abans de desmarcar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No heu seleccionat cap paquet per a desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Els paquets seleccionats s'han desmarcat." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No té permís per eliminar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No heu seleccionat cap paquet per a esborrar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Els paquets seleccionats s'han esborrat." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Heu d'identificar-vos abans d'apropiar-se paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Heu d'identificar-vos abans de desapropiàr-se paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No heu seleccionat cap paquet per apropiar-se'n." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No heu seleccionat cap paquet per desapropiar-se'n." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Els paquets seleccionats s'han apropiat." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Els paquets seleccionats han sigut desapropiats." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Heu d'identificar-vos abans de votar paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Heu d'identificar-vos abans de llevar el vot als paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No heu seleccionat cap paquet per votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Els vostres vots s'han suprimit dels paquets seleccionats." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Els vostres vots s'han enviat per als paquets seleccionats." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No s'ha pogut afegir a la llista de notificació." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Heu estat afegit a la llista de notificacions de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Heu sigut esborrat de la llista de notificacions de comentaris de %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No esteu autoritzat per esborrar aquest comentari." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "S'ha esborrat el comentari." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Veure els detalls del paquet per" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nom no vàlid: sols es permet lletres minúscules." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "El tipus de sol·licitud no és vàlid." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nom d'usuari" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipus de compte" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuari" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolupador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adreça de correu-e" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nom real" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nom d'usuari IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Emprempta clau PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estat" +#: template/account_details.php msgid "Inactive since" msgstr "" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actiu" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "desconegut" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Mai" +#: template/account_details.php msgid "View this user's packages" msgstr "Visualitza els paquets d'aquest usuari" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "requerit" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuari normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuari de Confiança" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "El compte s'ha suspès" +#: template/account_edit_form.php msgid "Inactive" msgstr "" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Escriu altre cop la contrasenya" +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notificar comentaris nous" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualitza" +#: template/account_edit_form.php msgid "Create" msgstr "Crea" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Restaura" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "No s'ha trobat cap coindidència amb els criteris de cerca." +#: template/account_search_results.php msgid "Edit Account" msgstr "Edita compte" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspès" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menys" +#: template/account_search_results.php msgid "More" msgstr "Més" +#: template/account_search_results.php msgid "No more results to display." msgstr "No hi ha més resultats per mostrar." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "El meu Compte" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Accions Paquet" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Veure PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar el paquet com a no-actualitzat" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar el paquet" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "eliminar vot" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Vota per aquest paquet" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Deshabilitar notificacions" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar Paquet" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Paraules Clau" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Remitent" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mantenidor" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Vots" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Primer enviament" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualització" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Afegir un comentari" +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Darrers Comentaris" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Esborra comentari" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Tots el comentaris" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalls del paquet" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripció" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Enllaç URL Upstream" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visiti la pàgina web per" +#: template/pkg_details.php msgid "Licenses" msgstr "" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "" +#: template/pkg_details.php msgid "Replaces" msgstr "" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependències" +#: template/pkg_details.php msgid "Required by" msgstr "Requerit per" +#: template/pkg_details.php msgid "Sources" msgstr "Fonts" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motiu" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Acceptat" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rebutjat" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Combinar amb" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1299,6 +1680,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1306,247 +1688,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pàgina %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nom, Descripció" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Només nom" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Tots" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcat" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No Marcat" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nom" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votat" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendent" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendent" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introdueixi in criteri de cerca" +#: template/pkg_search_form.php msgid "Search by" msgstr "Cerca per" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "No-Actualitzat" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordena per" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordena en sentit" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pàgina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Vés" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfes" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "S'ha produït un error en obtenir la llista de paquets." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "No s'ha trobat cap coincidència amb el teu criteri de cerca." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +#: template/pkg_search_results.php msgid "Version" msgstr "Versió" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "orfe" +#: template/pkg_search_results.php msgid "Actions" msgstr "Accions" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarca No-Actualitzat" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Apròpia paquets" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Desapròpia els paquets" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Esborra paquet" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualsevol tipus" +#: template/search_accounts_form.php msgid "Search" msgstr "Cerca" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadístiques" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquets orfes" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquets afegits en els darrers 7 dies" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquets actualitzats en els darrers 7 dies" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquets actualitzats en l'últim any" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquets mai actualitzats" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuaris registrats" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuaris de Confiança" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualitzacions recents" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Les meves estadístiques" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalls de la proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Aquesta votació encara es troba en funcionament." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Enviat: %s per %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fi" +#: template/tu_details.php msgid "Result" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Abstenir-se" +#: template/tu_details.php msgid "Total" msgstr "Nom exacte" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No s'han trobat resultats." +#: template/tu_list.php msgid "Start" msgstr "Inici" +#: template/tu_list.php msgid "Back" msgstr "Enrere" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/cs.po b/po/cs.po index a8749526..a69a21dc 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,1299 +1,1683 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Daniel Milde , 2017 # Jaroslav Lichtblau , 2015-2016 # Jaroslav Lichtblau , 2014 -# Jiří Vírava , 2017 +# Jiří Vírava , 2017-2018 # Lukas Fleischer , 2011 # Pavel Ševeček , 2014 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Czech (http://www.transifex.com/lfleischer/aur/language/cs/)\n" -"Language: cs\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-31 10:10+0000\n" +"Last-Translator: Jiří Vírava \n" +"Language-Team: Czech (http://www.transifex.com/lfleischer/aurweb/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Language: cs\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" +#: html/404.php msgid "Page Not Found" msgstr "Stránka nenalezena" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Omlouváme se, požadovaná stránka neexistuje." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Poznámka" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" -"URL adresy pro klonování Git repozitáře nejsou určeny k otevření v " -"prohlížeči." +msgstr "URL adresy pro klonování Git repozitáře nejsou určeny k otevření v prohlížeči." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Pro naklonování Git repozitáře %s, spusťte %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Klikněte %s zde %s pro návrat na %s stránku detailu." +#: html/503.php msgid "Service Unavailable" msgstr "Služba nedostupná" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "Nepanikařte! Na tomto webu dochází k údržbě. Brzy budeme zpět." +#: html/account.php msgid "Account" msgstr "Účet" +#: html/account.php template/header.php msgid "Accounts" msgstr "Účty" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Zde nemáte povolený přístup." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nelze obdržet informace pro vybraného uživatele." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemáte oprávnění pro úpravu tohoto účtu." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Pro vyhledání existujících účtů použíte tento formulář." +#: html/account.php msgid "You must log in to view user information." msgstr "Musíte se přihlásit, pro zobrazení informací o uživateli." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Přidat návrh" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Chybný token uživatelské akce." +#: html/addvote.php msgid "Username does not exist." msgstr "Uživatelské jméno neexistuje." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Pro %s se již hlasuje." +#: html/addvote.php msgid "Invalid type." msgstr "Chybný typ." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Návrh nemůže být prázdný." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nový návrh podán." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Předložit návrh na hlasování." +#: html/addvote.php msgid "Applicant/TU" msgstr "Uchazeč/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vynechat pokud neni vhodný)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Typ" +#: html/addvote.php msgid "Addition of a TU" msgstr "Přidání TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Odebrání TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Odebrání TU (nehlášená neaktivita)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Úprava směrnic" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Návrh" +#: html/addvote.php msgid "Submit" msgstr "Odeslat" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Správa spolu-správců" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Upravit komentář" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Dashboard" +#: html/home.php template/header.php msgid "Home" msgstr "Domů" +#: html/home.php msgid "My Flagged Packages" msgstr "Moje označené balíčky" +#: html/home.php msgid "My Requests" -msgstr "Moje požadavky" +msgstr "Moje žádosti" +#: html/home.php msgid "My Packages" msgstr "Moje balíčky" +#: html/home.php msgid "Search for packages I maintain" msgstr "Hledat balíčky, které spravuji" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Spolu-spravované balíčky" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Hledat balíčky, které spolu-spravuji" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nezapomeň hlasovat pro svoje oblíbené balíčky!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Některé balíčky mohou být poskytnuty v binární podobě v repozitáři " -"[community]." +msgstr "Některé balíčky mohou být poskytnuty v binární podobě v repozitáři [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Obsah balíčků AUR je vytvořen uživateli. Jakékoli použití poskytnutých " -"souborů je na vlastní nebezpečí." +msgstr "Obsah balíčků AUR je vytvořen uživateli. Jakékoli použití poskytnutých souborů je na vlastní nebezpečí." +#: html/home.php msgid "Learn more..." msgstr "Další informace ..." +#: html/home.php msgid "Support" msgstr "Podpora" +#: html/home.php msgid "Package Requests" -msgstr "" +msgstr "Žádosti o balíčky" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "Žádost o osiření" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "Žádost o smazání" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "Žádost o sloučení" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "Odeslání balíčků" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Pro AUR se používají následující otisky SSH" +#: html/home.php msgid "Discussion" msgstr "Diskuze" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Hlášení chyb" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Vyhledávání balíčků" +#: html/index.php msgid "Adopt" msgstr "Adoptovat" +#: html/index.php msgid "Vote" msgstr "Hlasovat" +#: html/index.php msgid "UnVote" msgstr "Odebrat hlas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Oznamovat" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Neoznamovat" +#: html/index.php msgid "UnFlag" msgstr "Odznačit" +#: html/login.php template/header.php msgid "Login" msgstr "Přihlásit" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Přihlášen jako: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Odhlásit" +#: html/login.php msgid "Enter login credentials" msgstr "Vložit přihlašovací údaje" +#: html/login.php msgid "User name or email address" msgstr "Uživatelské jméno nebo e-mailová adresa" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Heslo" +#: html/login.php msgid "Remember me" msgstr "Pamatuj si mě" +#: html/login.php msgid "Forgot Password" msgstr "Zapomenuté heslo" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Přihlášení přes HTTP je zakázáno. . Pokud se chcete přihlásit, prosíme " -"%spřejděte na HTTPs%s ." +msgstr "Přihlášení přes HTTP je zakázáno. . Pokud se chcete přihlásit, prosíme %spřejděte na HTTPs%s ." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Vyhledávací kritéria" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Balíčky" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Došlo k chybě při získávání detailů balíčku." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Chybí povinný údaj." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Hesla se neshodují" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Heslo musí mít nejméně %s znaků." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Neplatný e-mail." +#: html/passreset.php msgid "Password Reset" msgstr "Reset hesla" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Pro potvrzovací odkaz zkontrolujte e-mail." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Heslo bylo úspěšně resetováno." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrďte svou e-mailovou adresu:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Zadejte nové heslo:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrďte nové heslo:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Pokračovat" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Pokud jste zapomněli emailovou adresu použitou při registraci, pošlete " -"zprávu na %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Pokud jste zapomněli emailovou adresu použitou při registraci, pošlete zprávu na %saur-general%s mailing list." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Zadejte emailovou adresu:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Nelze najít balíček pro sloučení hlasů a komentářů." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "Smazání balíčku" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Smazat balíček" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Smazání balíčku je trvalé." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaškrtnout políčko pro potvrzení akce." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrdit smazání balíčku" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Smazat" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Komentáře" +#: html/pkgflag.php msgid "Flag" msgstr "Označit" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "Spojení balíčku" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Sloučit balíček" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Následující balíkčy budou smazány:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "Sloučit do:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrdit spojení balíčku" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Spojit" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" -msgstr "Odeslat požadavek" +msgstr "Odeslat žádost" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" -msgstr "Uzavřít požadavek" +msgstr "Uzavřít žádost" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "První" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Předchozí" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Další" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Poslední" +#: html/pkgreq.php template/header.php msgid "Requests" -msgstr "Požadavky" +msgstr "Žádosti" +#: html/register.php template/header.php msgid "Register" msgstr "Registrovat" +#: html/register.php msgid "Use this form to create an account." msgstr "Použíte tento formulář k založení účtu." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Důvěryhodný uživatel" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nelze obdržet navrhované detaily." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Toto hlasování již skončilo." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemůžete volit sami pro sebe." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Již jste hlasoval." +#: html/tu.php msgid "Vote ID not valid." msgstr "Nesprávné ID hlasování." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Současný počet hlasů" +#: html/tu.php msgid "Past Votes" msgstr "Předešlá hlasování" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Hlasující" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Registrace účtu byla pro vaši IP adresu zakázána, pravděpodobně kvůli " -"trvalým spamovým útokům. Omluvám se za nepříjemnost." +msgstr "Registrace účtu byla pro vaši IP adresu zakázána, pravděpodobně kvůli trvalým spamovým útokům. Omluvám se za nepříjemnost." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Chybějící Uživateské ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Chybně zadané uživatelské jméno" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Délka musí být %s až %s znaků" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Začíná a končí písmenem nebo číslicí" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Může obsahovat pouze jednu tečku, podtržítko nebo spojovník." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Vadná emailová adresa." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "Domovská stránka je neplatná, zadejte úplnou adresu URL HTTP(s)." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP otisk je neplatný." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Neplatný veřejný klíč SSH." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nelze zvýšit oprávnění účtu." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jazyk není momentálné podporován." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Časové pásmo momentálně není podporováno." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Uživatelské jméno, %s%s%s, je již používáno." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa, %s%s%s, je již použita." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Veřejný SSH klíč, %s%s%s, je již použit." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Chyba při vytváření účtu, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Účet, %s%s%s, byl úspěšně vytvořen." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Na vaši e-mailovou adresu byl odeslán klíč pro obnovení hesla." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Kliknutím na odkaz Přihlásit se výše použijte svůj účet." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Na účtu nebyly provedeny žádné změny,, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Účet, %s%s%s, byl úspěšně změněn." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Přihlašovací formulář je momentálně pro vaši IP adresu zakázán, " -"pravděpodobně kvůli trvalým spamovým útokům. Omluvám se za nepříjemnost." +msgstr "Přihlašovací formulář je momentálně pro vaši IP adresu zakázán, pravděpodobně kvůli trvalým spamovým útokům. Omluvám se za nepříjemnost." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Účet pozastaven" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Vaše heslo bylo resetováno. Pokud jste právě vytvořili nový účet, použijte " -"odkaz z potvrzovacího e-mailu a nastavte počáteční heslo. V opačném případě " -"požádejte o resetovací klíč na stránce %s Reset hesla %s ." +msgstr "Vaše heslo bylo resetováno. Pokud jste právě vytvořili nový účet, použijte odkaz z potvrzovacího e-mailu a nastavte počáteční heslo. V opačném případě požádejte o resetovací klíč na stránce %s Reset hesla %s ." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Chybné uživatelské jméno nebo heslo." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Došlo k chybě při pokusu generovat uživatelskou relaci." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Neplatná kombinace resetovacího klíče a e-mailu." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Zobrazení informací o účtu pro %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nemáte oprávnění upravit tento komentář." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Komentář neexistuje." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Komentář nemůže být prázdný." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentář byl přidán" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Musíte být přihlášeni, než budete moci upravovat informace o balíčcích." +msgstr "Musíte být přihlášeni, než budete moci upravovat informace o balíčcích." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Chybějící ID komentáře." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Nelze připnout více než 5 komentářů." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Nemáte oprávnění připnout tento komentář." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Nemáte oprávnění k odepnout tento komentář." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Komentář byl připnut." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Zrušeno připnutí komentáře." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Došlo k chybě při získávání detailů o balíčku." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Detailní informace o balíčku nejsou dostupné." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Před nastavením příznaku balíčků se musíte přihlásit." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nezvolili jste žádný balíček k označení." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Zvoleným balíčkům byl nastaven příznak zastaralé." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musíte být příhlášeni, abyste mohli odznačit balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nevybrali jste žádne balíčky k odebrání příznaku." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Zvoleným bálíčkům bylo odebráno označení." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nemáte oprávnění k odstranění balíčků." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nevybrali jste žádné balíčky ke smazání." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Zvolené balíčky byly smazány." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musíte být přihlášeni, než si budete moci osvojit balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musíte být přihlášeni, pro odebrání vlastnictví u svých balíčků." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nevybrali jste žádný balíček k osvojení." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nevybrali jste žádný balíček pro odebrání vlastnictví." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Zvolené balíčky byly osvojeny." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Vybraným balíčkům bylo odebráno vlastnictví." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Před hlasováním se musíte přihlásit." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musíte být přihlášeni, než budete moci odebrat hlasování pro balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nezvolili jste žádné balíčky k hlasování." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaše hlasování bylo odebráno vybraným balíčkům." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Vaše hlasování bylo započteno pro vybrané balíčky." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nelze přidat do seznamu upozornění." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Byly jste přidáni do seznamu oznámení ohledně %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Byli jste odebrání ze seznamu upozornění ohledně %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Nemáte oprávnění k obnovení tohoto komentáře." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Komentář byl obnoven." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nemáte oprávnění pro smazání tohoto komentáře." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentář byl smazán." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Komentář byl upraven." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nemáte oprávnění upravit klíčová slova tohoto balíčku." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Neplatné uživatelské jméno: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Zobrazit podrobnosti o balíčcích pro" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "vyžaduje %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Chybný název: jsou povolena pouze malá písmena." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Pole s komentáři nesmí být prázdné." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Neplatný typ požadavku." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." -msgstr "Požadavek byl úspěšně přidán." +msgstr "Žádost byla úspěšně přidána." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Neplatný důvod." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." -msgstr "Požadavek byla úspěšně uzavřen." +msgstr "Žádost byla úspěšně uzavřena." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Tento formulář můžete použít k trvalému odstranění účtu AUR %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sVAROVÁNÍ%s: Tuto akci nelze vrátit zpět." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Potvrdit smazání" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Uživatelské jméno" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Typ účtu" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Uživatel" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Vyvojář" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Důvěryhodný uživatel a vývojář" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Emailová adresa" +#: template/account_details.php msgid "hidden" msgstr "skrytý" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Skutečné jméno" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Domovská stránka" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC přezdívka" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Otisk klíče PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Neaktivní od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivní" +#: template/account_details.php msgid "Registration date:" msgstr "Datum registrace:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "neznámý" +#: template/account_details.php msgid "Last Login" msgstr "Poslední přihlášení" +#: template/account_details.php msgid "Never" msgstr "Nikdy" +#: template/account_details.php msgid "View this user's packages" msgstr "Zobrazit balíčky tohoto uživatele" +#: template/account_details.php msgid "Edit this user's account" msgstr "Upravit tento uživatelský účet" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "vyžadováno" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Obyčejný uživatel" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Důvěryhodný uživatel" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Účet pozastaven" +#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktivní" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Ujistěte se, že jste správně zadali svou e-mailovou adresu, jinak budete " -"zablokováni." +msgstr "Ujistěte se, že jste správně zadali svou e-mailovou adresu, jinak budete zablokováni." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Skrýt email" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Heslo znovu" +#: template/account_edit_form.php msgid "Language" msgstr "Jazyk" +#: template/account_edit_form.php msgid "Timezone" msgstr "Časové pásmo" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Následující informace jsou požadovány pouze v případě, že chcete odeslat " -"balíčky do Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Následující informace jsou požadovány pouze v případě, že chcete odeslat balíčky do Arch User Repository." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Veřejný SSH klíč" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Nastavení upozornění" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Oznamovat nové komentáře" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Oznámení o aktualizacích balíčku" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Oznámit změnu vlastnictví" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualizovat" +#: template/account_edit_form.php msgid "Create" msgstr "Vytvořit" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reset" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Pro Váš dotaz nebyl nalezen žádný odpovídající výsledek." +#: template/account_search_results.php msgid "Edit Account" msgstr "Upravit účet" +#: template/account_search_results.php msgid "Suspended" msgstr "Pozastavený" +#: template/account_search_results.php msgid "Edit" msgstr "Upravit" +#: template/account_search_results.php msgid "Less" msgstr "Méně" +#: template/account_search_results.php msgid "More" msgstr "Více" +#: template/account_search_results.php msgid "No more results to display." msgstr "Žádné další výsledky." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "Uživatelé" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Uložit" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Autorská práva %s 2004-%d vývojový tým aurweb." +#: template/header.php msgid " My Account" msgstr "Můj účet" +#: template/pkgbase_actions.php msgid "Package Actions" -msgstr "" +msgstr "Dostupné akce pro balíček" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Zobrazit PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Zobrazit změny" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Stáhnout snímek" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Prohledat wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Označit balíček jako zastaralý" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Zrušit označení balíčku" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Vzít zpět hlas" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Hlasovat pro tento balíček" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Vypnout oznámení" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Zapnout oznámení" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d čekající požadavek" msgstr[1] "%d čekající požadavky" -msgstr[2] "%d čekajících požadavků" +msgstr[2] "%d čekajících žádostí" +msgstr[3] "%d čekajících žádostí" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptovat balíček" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "jen pro čtení" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Klíčová slova" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Správce" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Hlasy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularita" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" -msgstr "" +msgstr "Poprvé vložen" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Naposledy aktualizováno" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Přidat komentář" +#: template/pkg_comments.php msgid "View all comments" msgstr "Zobrazit všechny komentáře" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Připnuté komentáře" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Nejnovější komentáře" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s přidal komentář %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "upraveno %s upravil %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "upraveno %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Smazat komentář" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Připnout komentář" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Odepnout komentář" +#: template/pkg_comments.php msgid "All comments" msgstr "Všechny komentáře" +#: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčku" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Popis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "Licence" +#: template/pkg_details.php msgid "Groups" msgstr "Skupiny" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikty" +#: template/pkg_details.php msgid "Provides" msgstr "Poskytuje" +#: template/pkg_details.php msgid "Replaces" msgstr "Nahrazuje" +#: template/pkg_details.php msgid "Dependencies" msgstr "Závislosti" +#: template/pkg_details.php msgid "Required by" msgstr "Vyžadováno" +#: template/pkg_details.php msgid "Sources" msgstr "Zdroje" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Důvod" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Přijato" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Zamítnuto" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" -msgstr "Typ požadavku" +msgstr "Typ žádosti" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Smazání" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Sirotek" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Sloučit do" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1301,6 +1685,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1308,253 +1693,456 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." -msgstr "Žádné požadavky neodpovídaly vašim kritériím vyhledávání." +msgstr "Žádné žádosti neodpovídaly vašim kritériím vyhledávání." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" msgstr[2] "" +msgstr[3] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." -msgstr "" +msgstr "Stránka %d z %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Balíček" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" msgstr[2] "" +msgstr[3] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" msgstr[2] "" +msgstr[3] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "Přijmout" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zamčeno" +#: template/pkgreq_results.php msgid "Close" msgstr "Uzavřít" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Uzavřeno" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Jméno, popis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Pouze jméno" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Přesné jméno" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Vše" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Označené" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Neoznačené" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Název" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Hlasováno" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Naposledy změněno" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Vzestupně" +#: template/pkg_search_form.php msgid "Descending" msgstr "Sestupně" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Zadat kritéria vyhledávání" +#: template/pkg_search_form.php msgid "Search by" msgstr "Vyhledat dle" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastaralé" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Seřadit dle" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Řadit" +#: template/pkg_search_form.php msgid "Per page" msgstr "Na jedné stránce" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Jdi" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Sirotci" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Chyba při získávání seznamu balíčků." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Žádný balíček neodpovídá zadaným kritériím." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Nalezen %d balíček." msgstr[1] "Nalezeny %d balíčky." msgstr[2] "Nalezeno %d balíčků." +msgstr[3] "Nalezeno %d balíčků." +#: template/pkg_search_results.php msgid "Version" msgstr "Verze" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Popularita je vypočtena jako součet všech hlasů, přičemž každý hlas je vážen " -"faktorem %.2f za den od jeho vytvoření.." +msgstr "Popularita je vypočtena jako součet všech hlasů, přičemž každý hlas je vážen faktorem %.2f za den od jeho vytvoření.." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ano" +#: template/pkg_search_results.php msgid "orphan" msgstr "sirotek" +#: template/pkg_search_results.php msgid "Actions" msgstr "Akce" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Odebrat příznak zastaralý" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Osvojit balíček" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odebrat vlastnictví" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Smazat balíčky" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrdit" +#: template/search_accounts_form.php msgid "Any type" msgstr "Jakýkoliv" +#: template/search_accounts_form.php msgid "Search" msgstr "Hledat" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiky" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Balíčků bez správce" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Přidaných balíčků za posledních 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Aktualizovaných balíčků za posledních 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Aktualizovaných balíčků v posledním roce" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Balíčků, které nebyly nikdy aktualizovány" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovaných uživatelů" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Důvěryhodných uživatelů" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedávné aktualizace" +#: template/stats/updates_table.php msgid "more" msgstr "více" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moje statistiky" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaily návrhu" +#: template/tu_details.php msgid "This vote is still running." msgstr "Hlasování stále probíhá." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Vloženo: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Konec" +#: template/tu_details.php msgid "Result" msgstr "Výsledek" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" +#: template/tu_details.php msgid "Abstain" msgstr "Zdržet se" +#: template/tu_details.php msgid "Total" msgstr "Celkem" +#: template/tu_details.php msgid "Participation" msgstr "Účast" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Naposledy hlasováno" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Žádné výsledky." +#: template/tu_list.php msgid "Start" msgstr "Začátek" +#: template/tu_list.php msgid "Back" msgstr "Zpět" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/da.po b/po/da.po index 181d8294..f4e2c2e2 100644 --- a/po/da.po +++ b/po/da.po @@ -1,655 +1,848 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Louis Tim Larsen , 2015 # Lukas Fleischer , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Danish (http://www.transifex.com/lfleischer/aur/language/" -"da/)\n" -"Language: da\n" +"Language-Team: Danish (http://www.transifex.com/lfleischer/aurweb/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: da\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Siden blev ikke fundet" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Beklager, den forspurgte side findes ikke." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "Service utilgængelig" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Konti" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Du har ikke tilladelse til dette område." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kunne ikke hente information om den specifikke bruger." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du har ikke tilladelse til at redigere denne konto." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Brug denne formular til at søge i eksisterende konti." +#: html/account.php msgid "You must log in to view user information." msgstr "Du skal være logget ind for at se brugerinformation." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "Brugernavnet findes ikke." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s har allerede et forslag kørende for dem." +#: html/addvote.php msgid "Invalid type." msgstr "" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Forslag må ikke være tomt." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nyt forslag tilføjet." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Fremsæt et forslag til afstemning." +#: html/addvote.php msgid "Applicant/TU" msgstr "" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tomt hvis ikke relevant)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Forslag" +#: html/addvote.php msgid "Submit" msgstr "Tilføj" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Hjem" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Mine pakker" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" +#: html/home.php msgid "DISCLAIMER" msgstr "" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Diskussion" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Pakkesøgning" +#: html/index.php msgid "Adopt" msgstr "Adopter" +#: html/index.php msgid "Vote" msgstr "Stem" +#: html/index.php msgid "UnVote" msgstr "Tilbagetræk stemme" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Påmindelse" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ingen påmindelse" +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "Log ind" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Logget ind som: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Log ud" +#: html/login.php msgid "Enter login credentials" msgstr "" +#: html/login.php msgid "User name or email address" msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Adgangskode" +#: html/login.php msgid "Remember me" msgstr "Husk mig" +#: html/login.php msgid "Forgot Password" msgstr "Glemt adgangskode" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Søgekriterier" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakker" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Fejl ved modtagning af pakkedetaljer." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Du mangler at udfylde et påkrævet felt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Adgangskoderne stemmer ikke overens." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Din adgangskode skal være mindst %s tegn." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ugyldig mail." +#: html/passreset.php msgid "Password Reset" msgstr "Nulstil adgangskode" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Tjek din mail for bekræftelses-link." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Din adgangskode blev nulstillet." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bekræft din nye mail-adresse:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Indtast din nye adgangskode:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bekræft din nye adgangskode:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Forsæt" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." msgstr "" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Indtast din mail-adresse:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Slet pakke" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Sletning af en pakke er permanent" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bekræft sletning af pakke" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Slet" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Kun betroede brugere og udviklere kan slette pakker." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentarer" +#: html/pkgflag.php msgid "Flag" msgstr "" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Følgende pakker vil blive slettet:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Luk forspørgsel" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Tidligere" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Næste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Sidste" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Forspørgelser" +#: html/register.php template/header.php msgid "Register" msgstr "Register" +#: html/register.php msgid "Use this form to create an account." msgstr "Brug denne formular til at oprette en konto." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Betroet bruger (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Kunne ikke hente detaljer om forslaget." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Afstemningen er lukket for dette forslag." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Du kan ikke stemme i et forslag om dig selv." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du har allerede stemt ved dette forslag." +#: html/tu.php msgid "Vote ID not valid." msgstr "Stemme ID er ikke gyldigt." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Aktuelle stemmer" +#: html/tu.php msgid "Past Votes" msgstr "" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manglende bruger-ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Brugernavnet er ugyldigt." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Skal være mellem %s og %s tegn." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Start og slut med et bogstav eller tal" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun indeholde ét punktum, én bundstreg eller én bindestreg." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mail adressen er ugyldig." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Sproget er ikke understøttet på nuværende tidspunkt." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto suspenderet" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -657,617 +850,828 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Forkert brugernavn eller adgangskode" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Ingen" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentaren blev tilføjet" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Du skal være logget ind for at redigere pakkeoplysninger." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Manglende kommentar ID." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Fejl ved modtagelse af pakkedetaljer." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Kunne ikke finde pakkedetaljerne.." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du skal være logget ind for at markere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Du har ikke valgt nogle pakker at markere." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "De valgte pakker er markeret forældet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Du skal være logget ind for at afmarkere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Du har ikke valgt nogle at afmarkere." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De valgte pakker er afmarkeret." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du har ikke tilladelse til, at slette pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du har ikke valgt nogle pakker at slette." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De valgte pakker er blevet slettet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du skal være logget ind for at adoptere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du skal være logget ind for at opgive ejerskabet for pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du har ikke valgt nogle pakker at adoptere." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du har ikke valgt nogle pakker at opgive ejerskabet for." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "De valgte pakker er adopteret." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De valgte pakker er blevet efterladt." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du skal være logget ind for at stemme på pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du skal være logget ind for at fjerne din stemme fra pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du har ikke valgt nogle pakker at stemme på." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Dine stemmer er fjernet fra de valgte pakker." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Din stemme er afgivet for de valgte pakker." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kunne ikke tilføje til listen over påmindelser." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du vil nu modtage besked, når der kommer nye kommentarer til %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du vil ikke længere modtage besked ved nye kommentarer for %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du har ikke rettigheder til at slette denne kommentar." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentaren er slettet." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ugyldigt brugernavn: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vis pakkedeltaljer for" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ugyldigt navn: kun små bogstaver er tilladt." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ugyldig årsag" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bekræft sletning" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Brugernavn" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Kontotype" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Bruger" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Udvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Betroet bruger og udvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail adresse" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Rigtigt navn" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC kaldenavn" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Inaktiv siden" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "ukendt" +#: template/account_details.php msgid "Last Login" msgstr "Sidste login" +#: template/account_details.php msgid "Never" msgstr "Aldrig" +#: template/account_details.php msgid "View this user's packages" msgstr "Vis pakker fra denne bruger" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "påkrævet" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normal bruger" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Betroet bruger (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto suspenderet" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Bekræft adgangskode" +#: template/account_edit_form.php msgid "Language" msgstr "Sprog" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Opdater" +#: template/account_edit_form.php msgid "Create" msgstr "Opret" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Nulstil" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Ingen resultater opfyldte dine søgekriterier." +#: template/account_search_results.php msgid "Edit Account" msgstr "Rediger konto" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspenderet" +#: template/account_search_results.php msgid "Edit" msgstr "" +#: template/account_search_results.php msgid "Less" msgstr "Færre" +#: template/account_search_results.php msgid "More" msgstr "Flere" +#: template/account_search_results.php msgid "No more results to display." msgstr "Ikke flere resultater at vise." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "Brugere" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Gem" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "Min konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Vis PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Vis ændringer" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Fjern stemme" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem på denne pakke" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Deaktiver notifikationer" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter pakke" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Nøgleord" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Indsender" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ejer" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Sidste pakker" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmer" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularitet" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Først tilføjet" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Sidst opdateret" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Tilføj kommentar" +#: template/pkg_comments.php msgid "View all comments" msgstr "Vis alle kommentarer" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Seneste kommentarer" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Slet kommentar" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Alle kommentarer" +#: template/pkg_details.php msgid "Package Details" msgstr "Detaljer om pakken" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beskrivelse" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Besøg hjemmesiden for" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenser" +#: template/pkg_details.php msgid "Groups" msgstr "Grupper" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikter" +#: template/pkg_details.php msgid "Provides" msgstr "Tilbyder" +#: template/pkg_details.php msgid "Replaces" msgstr "Erstatter" +#: template/pkg_details.php msgid "Dependencies" msgstr "Afhængigheder" +#: template/pkg_details.php msgid "Required by" msgstr "Påkrævet af" +#: template/pkg_details.php msgid "Sources" msgstr "Kilder" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Accepteret" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Afvist" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Sletning" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Forladt" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1275,6 +1679,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1282,247 +1687,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Side %d af %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakke" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Udfyldt af" +#: template/pkgreq_results.php msgid "Date" msgstr "Dato" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d time tilbage" msgstr[1] "~%d timer tilbage" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 time tilbage" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accepter" +#: template/pkgreq_results.php msgid "Locked" msgstr "Låst" +#: template/pkgreq_results.php msgid "Close" msgstr "Luk" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Lukket" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Navn, beskrivelse" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Kun navn" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Præcist navn" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Navn" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Stemt" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "" +#: template/pkg_search_form.php msgid "Descending" msgstr "" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Søg efter" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Forældet" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortér efter" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorter efter" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per side" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Søg" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Forladt" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fejl ved modtagelse af pakkeliste." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ingen pakker opfylder dine søgekriterier." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pakke fundet." msgstr[1] "%d pakker fundet." +#: template/pkg_search_results.php msgid "Version" msgstr "Version" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "forladt" +#: template/pkg_search_results.php msgid "Actions" msgstr "Handlinger" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Afmarker forældet" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter pakker" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Fjern ejerskab for pakker" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Slet pakker" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Forsæt" +#: template/search_accounts_form.php msgid "Any type" msgstr "Vilkårlig type" +#: template/search_accounts_form.php msgid "Search" msgstr "Søg" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistikker" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Forladte pakker" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakker tilføjet indenfor de seneste 7 dage" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakker opdateret indenfor de seneste 7 dage" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakker opdateret indenfor det seneste år" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pakker aldrig opdateret" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registerede brugere" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Betroede brugere" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Seneste opdateringer" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mine statistikker" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaljer om forslag" +#: template/tu_details.php msgid "This vote is still running." msgstr "Denne afstemning er stadig aktiv." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Tilføjet: %s af %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Slut" +#: template/tu_details.php msgid "Result" msgstr "Resultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nej" +#: template/tu_details.php msgid "Abstain" msgstr "Undlad at stemme" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Deltagelse" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Sidste stemme" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ingen resultater fundet." +#: template/tu_list.php msgid "Start" msgstr "Start" +#: template/tu_list.php msgid "Back" msgstr "Tilbage" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/de.po b/po/de.po index e46c5b3c..00ab95c2 100644 --- a/po/de.po +++ b/po/de.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Alexander Griesbaum , 2013 # Alexander Griesbaum , 2013-2014 @@ -17,1644 +17,2135 @@ # Matthias Gorissen , 2012 # Nuc1eoN , 2014 # Nuc1eoN , 2014 +# simon04 , 2018 # Simon Schneider , 2011 -# Stefan Auditor , 2017 +# Stefan Auditor , 2017-2018 # Thomas_Do , 2013-2014 # Thomas_Do , 2012-2013 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-30 12:23+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 15:47+0000\n" "Last-Translator: Stefan Auditor \n" -"Language-Team: German (http://www.transifex.com/lfleischer/aur/language/" -"de/)\n" -"Language: de\n" +"Language-Team: German (http://www.transifex.com/lfleischer/aurweb/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Seite nicht gefunden" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Die angeforderte Seite existiert leider nicht." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Anmerkung" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Git clone URLs sind nicht dafür gedacht im Browser geöffnet zu werden." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Um das Git-Repository von %s zu clonen, führe %s aus." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Klicke %shere%s um zur %s Detailseite zurückzukehren." +#: html/503.php msgid "Service Unavailable" -msgstr "Dienst nicht verfügbr" +msgstr "Dienst nicht verfügbar" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir " -"werden gleich zurück sein." +msgstr "Keine Panik! Diese Seite ist wegen Verwaltungs-Aufgaben geschlossen. Wir werden gleich zurück sein." +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Konten" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Es ist Dir nicht erlaubt, auf diesen Bereich zuzugreifen." +#: html/account.php msgid "Could not retrieve information for the specified user." -msgstr "" -"Es konnten keine Informationen für den angegebenen Benutzer geladen werden." +msgstr "Es konnten keine Informationen für den angegebenen Benutzer geladen werden." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du hast keine Berechtigung, dieses Konto zu ändern." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Benutze dieses Formular, um vorhandene Konten zu suchen." +#: html/account.php msgid "You must log in to view user information." -msgstr "Du musst Dich anmelden, um Benutzerinformationen anzusehen." +msgstr "Du musst Dich anmelden, um Benutzer-Informationen anzusehen." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Vorschlag hinzufügen" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Ungültiges Zeichen für eine Benutzer-Aktion." +#: html/addvote.php msgid "Username does not exist." msgstr "Der Benutzername existiert nicht." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Es läuft bereits ein Vorschlag für %s." +#: html/addvote.php msgid "Invalid type." msgstr "Ungültiger Typ." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Vorschlag darf nicht leer sein." +#: html/addvote.php msgid "New proposal submitted." msgstr "Neuer Vorschlag eingereicht." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Reiche einen Vorschlag zur Abstimmung ein." +#: html/addvote.php msgid "Applicant/TU" msgstr "Bewerber/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(leer, falls nicht zutreffend)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Typ" +#: html/addvote.php msgid "Addition of a TU" msgstr "TU hinzugefügt" +#: html/addvote.php msgid "Removal of a TU" msgstr "TU entfernt" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU entfernt (unerklärte Inaktivität)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Änderung der Bestimmungen" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Vorschlag" +#: html/addvote.php msgid "Submit" msgstr "Abschicken" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" -msgstr "Verwalte Mit-Betreuer" +msgstr "Verwalte Co-Maintainer" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Kommentar bearbeiten" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Dashboard" +#: html/home.php template/header.php msgid "Home" msgstr "Startseite" +#: html/home.php msgid "My Flagged Packages" msgstr "Meine markierten Pakete" +#: html/home.php msgid "My Requests" msgstr "Meine Anfragen" +#: html/home.php msgid "My Packages" msgstr "Meine Pakete" +#: html/home.php msgid "Search for packages I maintain" msgstr "Suche nach Paketen die ich betreue" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Mitbetreute Pakete" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Suche nach Paketen die ich mitbetreue" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Willkommen im AUR! Für weitere Informationen lies bitte die %sAUR User " -"Guidelines%s und die %sAUR TU Guidelines%s." +msgstr "Willkommen im AUR! Für weitere Informationen lies bitte die %sAUR User Guidelines%s und die %sAUR TU Guidelines%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Alle hier eingereichten PKGBUILDs %smüssen%s den %sArch Packaging Standards" -"%s entsprechen. Andernfalls werden sie entfernt!" +msgstr "Alle hier eingereichten PKGBUILDs %smüssen%s den %sArch Packaging Standards%s entsprechen. Andernfalls werden sie entfernt!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Denk daran, für Deine bevorzugten Pakete zu stimmen!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Manche Pakete könnten als Binär-Pakete in [community] bereitgestellt sein." +msgstr "Manche Pakete könnten als Binär-Pakete in [community] bereitgestellt sein." +#: html/home.php msgid "DISCLAIMER" -msgstr "" -"DISCLAIMER: Offiziell nicht unterstützte PKGBUILDS werden von den Benutzern " -"erstellt - durch den Download willigt man ein, diese auf eigene Gefahr zu " -"benutzen." +msgstr "DISCLAIMER: Offiziell nicht unterstützte PKGBUILDS werden von den Benutzern erstellt - durch den Download willigt man ein, diese auf eigene Gefahr zu benutzen." +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"AUR Pakete sind von Benutzern erstellter Inhalt. Die Benutzung der " -"angebotenen Dateien erfolgt auf eigenes Risiko." +msgstr "AUR Pakete sind von Benutzern erstellter Inhalt. Die Benutzung der angebotenen Dateien erfolgt auf eigenes Risiko." +#: html/home.php msgid "Learn more..." msgstr "Erfahre mehr ..." +#: html/home.php msgid "Support" msgstr "Untersttzung" +#: html/home.php msgid "Package Requests" msgstr "Paketanfragen" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Es gibt drei Arten von Anfragen, die in der %sPaketaktionen%s Box auf der " -"Paketdetailseite eingereicht werden können:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Es gibt drei Arten von Anfragen, die in der %sPaketaktionen%s Box auf der Paketdetailseite eingereicht werden können:" +#: html/home.php msgid "Orphan Request" msgstr "Verwaisanfrage" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Anfrage eine Pakte abzugeben, z.B. wenn der Betreuer nicht aktiv ist und das " -"Paket vor einer ganzen Weile als veraltet makiert wurde." +msgstr "Anfrage eine Paket abzugeben, z.B. wenn der Maintainer nicht aktiv ist und das Paket vor einer ganzen Weile als veraltet markiert wurde." +#: html/home.php msgid "Deletion Request" msgstr "Löschanfrage" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte " -"benutze diese nicht, wenn das Paket kaputt ist und leich repariert werden " -"kann. Sondern kontaktiere den Betreuer und reiche eine Verwaisungsanfrage " -"ein, wenn nötig." +msgstr "Anfrage zum Entfernen eines Pakets aus dem Arch User Repository. Bitte benutze diese nicht, wenn das Paket kaputt ist und leich repariert werden kann. Sondern kontaktiere den Maintainer und reiche eine Verwaisungsanfrage ein, wenn nötig." +#: html/home.php msgid "Merge Request" msgstr "Zusammenführungsanfrage" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Anfrage ein Paket mit einem anderen zusammenzuführen. Wird benutzt, wenn ein " -"Paket umbenannt werden muss oder durch ein geteiltes Paket ersetzt wird." +msgstr "Anfrage ein Paket mit einem anderen zusammenzuführen. Wird benutzt, wenn ein Paket umbenannt werden muss oder durch ein geteiltes Paket ersetzt wird." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Wenn Du eine Anfrage diskutieren willst, kannst Du die %saur-requests%s " -"Mailingliste benutzen. Benutze diese jedoch nicht um Anfragen einzureichen." +msgstr "Wenn Du eine Anfrage diskutieren willst, kannst Du die %saur-requests%s Mailingliste benutzen. Benutze diese jedoch nicht um Anfragen einzureichen." +#: html/home.php msgid "Submitting Packages" msgstr "Pakete einreichen" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git über SSH wird jetzt benutzt um Pakete in das AUR einzureichen. Siehe die " -"%sEinreichen von Paketen%s Sektion von der Arch User Repository ArchWiki " -"Seite für mehr Details." +msgstr "Git über SSH wird jetzt benutzt um Pakete in das AUR einzureichen. Siehe die %sEinreichen von Paketen%s Sektion von der Arch User Repository ArchWiki Seite für mehr Details." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Die folgenden SSH Fingerabdrücke werden für das AUR benutzt:" +#: html/home.php msgid "Discussion" msgstr "Diskussion" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und " -"vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für " -"Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface benutze die " -"%saur-dev%s Mailingliste." +msgstr "Grundsätzliche Diskussionen bezüglich des Arch User Repository (AUR) und vertrauenswürdigen Benutzern finden auf %saur-general%s statt. Für Diskussionen im Bezug auf die Entwicklung des AUR Web-Interface benutze die %saur-dev%s Mailingliste." +#: html/home.php msgid "Bug Reporting" msgstr "Fehler melden" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-" -"Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um " -"Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte direkt " -"an den zuständigen Betreuer, oder hinterlasse einen Kommentar auf der " -"entsprechenden Seite des Paketes." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Wenn du einen Fehler im AUR Web-Interface findest, fülle bitte eine Fehler-Meldung in unserem %sbug-tracker%s aus. Benutze den Tracker %snur%s, um Fehler im AUR zu melden. Für falsch gepackte Pakete, wende dich bitte direkt an den zuständigen Maintainer, oder hinterlasse einen Kommentar auf der entsprechenden Seite des Pakets." +#: html/home.php msgid "Package Search" msgstr "Paketsuche" +#: html/index.php msgid "Adopt" msgstr "Übernimm Paket" +#: html/index.php msgid "Vote" msgstr "Abstimmen" +#: html/index.php msgid "UnVote" msgstr "Stimme zurückziehen" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Benachrichtigen" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Nicht mehr benachrichtigen" +#: html/index.php msgid "UnFlag" msgstr "Markierung aufheben" +#: html/login.php template/header.php msgid "Login" msgstr "Anmelden" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Angemeldet als: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Abmelden" +#: html/login.php msgid "Enter login credentials" msgstr "Zugangsdaten eingeben" +#: html/login.php msgid "User name or email address" msgstr "Benutzername oder E-Mail-Adresse" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Passwort" +#: html/login.php msgid "Remember me" msgstr "Angemeldet bleiben" +#: html/login.php msgid "Forgot Password" msgstr "Passwort vergessen" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Die Anmeldung über HTTP wurde deaktiviert. Zum Anmelden %swechsle bitte zu " -"HTTPS%s." +msgstr "Die Anmeldung über HTTP wurde deaktiviert. Zum Anmelden %swechsle bitte zu HTTPS%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Suchkriterien" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakete" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Während des Empfangs der Paket-Details ist ein Fehler aufgetreten." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Ein benötigtes Feld ist nicht ausgefüllt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Passwort-Felder sind unterschiedlich." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Dein Passwort muss mindestens %s Zeichen lang sein." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ungültige E-Mail-Adresse." +#: html/passreset.php msgid "Password Reset" msgstr "Passwort zurücksetzen" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Überprüfe Dein E-Mail-Postfach hinsichtlich des Bestätigungslinks." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Dein Passwort wurde erfolgreich zurückgesetzt." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bestätige Deine E-Mail-Adresse:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Gib Dein neues Passwort ein:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bestätige Dein neues Passwort:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Weiter" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Wenn Du die E-Mail-Adresse vergessen hast, die Du für Deine Registrierung " -"benutzt hast, sende bitte eine Nachricht an die %saur-general%s Mailing-" -"Liste." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Wenn Du die E-Mail-Adresse vergessen hast, die Du für Deine Registrierung benutzt hast, sende bitte eine Nachricht an die %saur-general%s Mailing-Liste." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Gib Deine E-Mail-Adresse ein:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Paketbasis" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Die Betreuung der ausgewählten Pakete wurde nicht abgegeben, überprüfe die " -"Bestätigungs-Checkbox." +msgstr "Die Betreuung der ausgewählten Pakete wurde nicht abgegeben, überprüfe die Bestätigungs-Checkbox." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Das Paket, in das die Stimmen und Kommentare übernommen werden sollen, kann " -"nicht gefunden werden." +msgstr "Das Paket, in das die Stimmen und Kommentare übernommen werden sollen, kann nicht gefunden werden." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Eine Paketbasis kann nicht mit sich selbst verschmolzen werden." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Die ausgewählten Pakete wurden nicht gelöscht, bitte aktiviere die " -"Bestätigungs-Checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Die ausgewählten Pakete wurden nicht gelöscht, bitte aktiviere die Bestätigungs-Checkbox." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Pakete entfernen" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Paket löschen" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Benutze dieses Formular um die Paketbasis %s%s%s und die folgenden Pakete " -"vom AUR zu löschen:" +msgstr "Benutze dieses Formular um die Paketbasis %s%s%s und die folgenden Pakete vom AUR zu löschen:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Die Löschung eines Pakets ist endgültig." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Wähle ein Kästchen aus, um die Aktion zu bestätigen." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bestätige das Löschen des Pakets" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Löschen" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Nur vertrauenswürdige Benutzer und Entwickler können Pakete löschen." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Paket abgeben" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Benutze dieses Formular um die Paketbasis %s%s%s, welche die folgenden " -"Pakete enhält, abzugeben:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Benutze dieses Formular um die Paketbasis %s%s%s, welche die folgenden Pakete enhält, abzugeben:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "Durch Auswahl dieser Checkbox bestätigst Du, dass Du nicht mehr Co-Maintainer dieses Pakets sein willst." + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Durch das markieren des Kontrollkästchen bestätigtst Du, dass Du das Paket " -"abegen und den Besitz an %s%s%s übergeben willst." +msgstr "Durch das markieren des Kontrollkästchen bestätigtst Du, dass Du das Paket abegen und den Besitz an %s%s%s übergeben willst." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Durch Auswahl dieser Checkbox bestätigst du, dass du die Betreuung dieses " -"Paketes abgeben willst." +msgstr "Durch Auswahl dieser Checkbox bestätigst du, dass du die Betreuung dieses Pakets abgeben willst." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Bestätige die Abgabe der Paket-Betreuung" +#: html/pkgdisown.php msgid "Disown" msgstr "Gebe Paket ab" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Nur Tus und Developer können die Paket-Betreuung abgeben." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Kommentar markieren" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" -msgstr "Paket als \"veraltet\" makieren" +msgstr "Paket als \"veraltet\" markieren" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Benutze dieses Formular, um die Paketbasis %s%s%s und die folgenden Pakete " -"als \"veraltet\" zu markieren." +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Benutze dieses Formular, um die Paketbasis %s%s%s und die folgenden Pakete als \"veraltet\" zu markieren." +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Bitte benutze dieses Formular %snicht%s, um Fehler zu melden. Benutze " -"stattdessen die Paketkommentare." +msgstr "Bitte benutze dieses Formular %snicht%s, um Fehler zu melden. Benutze stattdessen die Paketkommentare." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Beschreibe genauer, warum das Paket \"veraltet\" ist, vorzugsweise mit Links " -"zu der Veröffentlichungsankündigung oder dem Release-Tar-Archive." +msgstr "Beschreibe genauer, warum das Paket \"veraltet\" ist, vorzugsweise mit Links zu der Veröffentlichungsankündigung oder dem Release-Tar-Archive." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentare" +#: html/pkgflag.php msgid "Flag" msgstr "Markieren" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Nur registrierte Benutzer können Pakete als \"veraltet\" markieren." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakete verschmelzen" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Paket verschmelzen" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Benutze dieses Formular um die Paketbasis %s%s%s in ein anderes Paket zu " -"verschmelzen." +msgstr "Benutze dieses Formular um die Paketbasis %s%s%s in ein anderes Paket zu verschmelzen." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Die folgenden Pakete werden gelöscht:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Wenn das Paket einmal verschmolzen ist, kann diese Aktion nicht mehr " -"revidiert werden." +msgstr "Wenn das Paket einmal verschmolzen ist, kann diese Aktion nicht mehr revidiert werden." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Trag den Namen des Pakets ein, in welches Du das vorliegende Paket " -"verschmelzen willst." +msgstr "Trag den Namen des Pakets ein, in welches Du das vorliegende Paket verschmelzen willst." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Verschmelze in:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Bestätige Verschmelzung der Pakete" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Verschmelzen" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." +msgstr "Nur vertrauenswürdige Benutzer und Entwickler können Pakete verschmelzen." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Anfrage absenden" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Anfrage schließen" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Erste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Zurück" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Weiter" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Letzte" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Anfragen" +#: html/register.php template/header.php msgid "Register" msgstr "Registrieren" +#: html/register.php msgid "Use this form to create an account." msgstr "Benutze dieses Formular, um ein Konto zu erstellen." +#: html/tos.php msgid "Terms of Service" msgstr "Nutzungsbedingungen" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" -"Die folgenden Dokumente wurden aktualisiert, bitte aufmerksam überprüfen:" +msgstr "Die folgenden Dokumente wurden aktualisiert, bitte aufmerksam überprüfen:" +#: html/tos.php #, php-format msgid "revision %d" msgstr "Revision %d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "Ich akzeptiere die obigen Nutzungsbedingungen." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Vertrauenswürdiger Benutzer (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Es konnten keine Vorschlag-Details ermittelt werden." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Die Abstimmungsphase für diesen Vorschlag ist beendet." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Nur Trusted User dürfen wählen." +#: html/tu.php msgid "You cannot vote in an proposal about you." -msgstr "" -"Du kannst über einen Vorschlag, der dich selbst betrifft, nicht abstimmen." +msgstr "Du kannst über einen Vorschlag, der dich selbst betrifft, nicht abstimmen." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du hast über diesen Vorschlag bereits abgestimmt." +#: html/tu.php msgid "Vote ID not valid." msgstr "Ungültige Abstimmungs-ID." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Laufende Abstimmungen" +#: html/tu.php msgid "Past Votes" msgstr "Abgeschlossene Abstimmungen" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Abstimmende" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Die Registrierung ist aktuell für deine IP-Adresse deaktiviert. Ein " -"möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die " -"Unannehmlichkeiten." +msgstr "Die Registrierung ist aktuell für deine IP-Adresse deaktiviert. Ein möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die Unannehmlichkeiten." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Benutzer-ID fehlt" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Der Benutzername ist ungültig." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Er muss zwischen %s und %s Zeichen lang sein." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Muss mit einem Buchstaben oder einer Zahl beginnen und enden" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kann nur einen Punkt, Unter- oder Bindestrich enthalten." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Die E-Mail-Adresse ist ungültig." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" -"Diese Adresse ist ungültig, bitte eine vollständige HTTP(S) URL angeben." +msgstr "Diese Adresse ist ungültig, bitte eine vollständige HTTP(S) URL angeben." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Der PGP-Schlüssel-Fingerabdruck ist ungültig." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Der öffentliche SSH Schlüssel ist ungültig." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Die Zugriffsrechte des Kontos können nicht erweitert werden." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Diese Sprache wird momentan noch nicht unterstützt." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Diese Zeitzone wird momentan noch nicht unterstützt." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Der Benutzername %s%s%s ist bereits vergeben." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Die Adresse %s%s%s wird bereits verwendet." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Der öffentliche SSH Schlüssel, %s%s%s, ist bereits in Benutzung." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Beim Erstellen des Kontos %s%s%s ist ein Fehler aufgetreten." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Das Konto %s%s%s wurde erfolgreich erstellt." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ein Rücksetzungscode wurde an deine E-Mail-Adresse gesendet." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klicke zur Anmeldung bitte oben auf den Login-Link." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Es wurden keine Änderungen am Konto %s%s%s vorgenommen." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Das Konto %s%s%s wurde erfolgreich bearbeitet." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Das Loginformular ist aktuell für deine IP-Adresse deaktiviert. Ein " -"möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die " -"Unannehmlichkeiten." +msgstr "Das Loginformular ist aktuell für deine IP-Adresse deaktiviert. Ein möglicher Grund können anhaltende Spam-Attacken sein. Bitte entschuldige die Unannehmlichkeiten." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto aufgehoben" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Dein Passwort wurde zurückgesetzt. Solltest du ein neues Konto erstellt " -"haben, verwende bitte den Bestätigungslink aus der E-Mail, um dein Passwort " -"festzulegen. Fordere andernfalls bitte einen Rücksetzungscode über die " -"%sPasswort zurücksetzen%s Seite an." +msgstr "Dein Passwort wurde zurückgesetzt. Solltest du ein neues Konto erstellt haben, verwende bitte den Bestätigungslink aus der E-Mail, um dein Passwort festzulegen. Fordere andernfalls bitte einen Rücksetzungscode über die %sPasswort zurücksetzen%s Seite an." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Falscher Benutzername oder falsches Passwort." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Es geschah ein Fehler beim Versuch eine Nutzersitzung zu erstellen." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ungültige Kombination aus E-Mail und Reset-Schlüssel." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Keine" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Konto-Informationen aufrufen für %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Paketbasis ID oder Paketbasis Name fehlen." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Du bist nicht berechtigt diesen Kommentar zu ändern." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Kommentar existiert nicht" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Kommentar darf nicht leer sein." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentar wurde hinzugefügt." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Du musst angemeldet sein, um Paket-Informationen zu bearbeiten." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Kommentar-ID fehlt." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Mehr als 5 Kommentare können nicht angeheftet werden." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Du bist nicht berechtigt diesen Kommentar anzuheften." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Du bist nicht berechtigt diesen Kommentar loszuheften." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Kommentar wurde angeheftet." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Kommentar wurde losgeheftet." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Fehler beim Aufrufen der Paket-Details." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paket-Details konnten nicht gefunden werden." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du musst Dich anmelden, um Pakete markieren zu können." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Du hast kein Paket zum Markieren ausgewählt." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"Die gewählten Pakete wurden nicht makiert, bitte einen Kommentar eingeben." +msgstr "Die gewählten Pakete wurden nicht markiert, bitte einen Kommentar eingeben." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Die gewählten Pakete wurden als \"veraltet\" markiert." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Du musst Dich anmelden, um die Markierung von Paketen entfernen zu können." +msgstr "Du musst Dich anmelden, um die Markierung von Paketen entfernen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Du hast kein Paket für das Entfernen der Markierung ausgewählt." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Die Markierungen der gewählten Pakete wurden entfernt." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du hast keine Berechtigung zum Löschen von Paketen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du hast keine Pakete zum Löschen ausgewählt." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Die gewählten Pakete wurden gelöscht." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du musst angemeldet sein, um Pakete übernehmen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." -msgstr "Du musst anmeldet sein, um die Betreuung eines Paketes abzugeben." +msgstr "Du musst anmeldet sein, um die Betreuung eines Pakets abzugeben." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du hast keine Pakete zum Übernehmen gewählt." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du hast keine Pakete gewählt, deren Betreuung Du abgeben willst." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Die gewählten Pakete wurde übernommen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Die Betreuung der gewählten Pakete wurde abgegeben." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du musst angemeldet sein, um für Pakete stimmen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du musst angemeldet sein, um Pakete abwählen zu können." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du hast keine Pakete zum Wählen markiert." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Deine Stimmen wurden von den markierten Paketen entfernt." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Deine Stimmen wurden für die markierten Pakete gezählt." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Es konnte nichts zur Benachrichtigungsliste hinzugefügt werden." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du wurdest zur Benachrichtigungliste für %s hinzugefügt." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du wurdest von der Benachrichtigungsliste für %s entfernt." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Du bist nicht berechtigt diesen Kommentar wiederherzustellen." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Kommentar wurde wiederhergestellt." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du darfst diesen Kommentar nicht löschen." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentar wurde gelöscht." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Kommentar wurde geändert." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Du bist nicht berechtigt die Schlagworte dieser Paketbasis zu ändern." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Die Schlagwörter der Paketbasis wurden aktualisiert." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "Du darfst die Mit-Betreuer für diese Paketbasis nicht verwalten." +msgstr "Du darfst die Co-Maintainer für diese Paketbasis nicht verwalten." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ungültiger Benutzername: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." -msgstr "Die Mit-Betreuer der Paketbasis wurden aktualisiert." +msgstr "Die Co-Maintainer der Paketbasis wurden aktualisiert." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Paket-Informationen aufrufen für" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "Benötigt %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Du musst angemeldet sein, um Paketanfragen einreichen zu können." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ungültiger Name: Es dürfen nur Kleinbuchstaben verwendet werden." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Das Kommentarfeld darf nicht leer sein." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ungültiger Anfragetyp." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Anfrage erfolgreich hinzugefügt." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ungültiger Grund." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Nur Entwicker und TUs können Anfragen schließen." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Anfrage erfolgreich geschlossen." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Du kannst dieses Formular verwenden, um den AUR Account unwiderruflich zu " -"entfernen %s." +msgstr "Du kannst dieses Formular verwenden, um den AUR Account unwiderruflich zu entfernen %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWARNUNG%s: Diese Aktion kann nicht rückgängig gemacht werden." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bestätige das Entfernen" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Benutzername" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Konto-Typ" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Benutzer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Entwickler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Vertrauenswürdiger Benutzer & Entwickler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-Mail-Adresse" +#: template/account_details.php msgid "hidden" msgstr "versteckt" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Echter Name" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Homepage" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC-Name" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP-Schlüssel-Fingerabdruck" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Nicht aktiv seit" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" +#: template/account_details.php msgid "Registration date:" msgstr "Registrierungsdatum:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "unbekannt" +#: template/account_details.php msgid "Last Login" msgstr "Letzter Login" +#: template/account_details.php msgid "Never" msgstr "Niemals" +#: template/account_details.php msgid "View this user's packages" msgstr "Alle Pakete dieses Benutzers anzeigen" +#: template/account_details.php msgid "Edit this user's account" msgstr "Konto dieses Benutzers bearbeiten" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "" -"Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchtest." +msgstr "Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchtest." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Klicke %shere%s für Benutzerdetails." +#: template/account_edit_form.php msgid "required" msgstr "Notwendig" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" -"Der Benutzername ist der Name, der für die Anmeldung benutzt wird. Er ist " -"öffentlich sichtbar, auch wenn das Konto inaktiv ist." +msgstr "Der Benutzername ist der Name, der für die Anmeldung benutzt wird. Er ist öffentlich sichtbar, auch wenn das Konto inaktiv ist." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normaler Benutzer" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Vertrauenswürdiger Benutzer (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto gesperrt" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Bitte stell sicher, dass du deine E-Mail korrekt eingegeben hast, sonst " -"wirst du dich aussperren." +msgstr "Bitte stell sicher, dass du deine E-Mail korrekt eingegeben hast, sonst wirst du dich aussperren." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Verstecke E-Mail-Adresse" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Bestätige das Passwort" +#: template/account_edit_form.php msgid "Language" msgstr "Sprache" +#: template/account_edit_form.php msgid "Timezone" msgstr "Zeitzone" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Die folgende Information wird nur benötigt, wenn du Pakete beim Arch User " -"Repository einreichen willst." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Die folgende Information wird nur benötigt, wenn du Pakete beim Arch User Repository einreichen willst." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Öffentlicher SSH Schlüssel" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Benachrichtigungseinstellungen" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Über neue Kommentare benachrichtigen" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Benachrichtige Paketaktualisierungen" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Benachrichtige Besitzeränderungen" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualisieren" +#: template/account_edit_form.php msgid "Create" msgstr "Erstellen" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Zurücksetzen" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Die Suchkriterien erzielten keine Treffer." +#: template/account_search_results.php msgid "Edit Account" msgstr "Konto bearbeiten" +#: template/account_search_results.php msgid "Suspended" msgstr "Gesperrt" +#: template/account_search_results.php msgid "Edit" msgstr "Ändern" +#: template/account_search_results.php msgid "Less" msgstr "Weniger" +#: template/account_search_results.php msgid "More" msgstr "Mehr" +#: template/account_search_results.php msgid "No more results to display." msgstr "Keine weiteren Ergebnisse." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Benutze dieses Formular um Mit-Betreuer für %s%s%s hinzuzufügen (ein " -"Benutzername pro Zeile):" +msgstr "Benutze dieses Formular um Co-Maintainer für %s%s%s hinzuzufügen (ein Benutzername pro Zeile):" +#: template/comaintainers_form.php msgid "Users" msgstr "Benutzer" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Speichern" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "Markiert als \"veraltet\" Kommentar: %s" +msgstr "Kommentar der \"veraltet\"-Markierung: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "%s%s%s markiert %s%s%s als veraltet am %s%s%s aufgrund von:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s wurde nicht als \"veraltet\" markiert." +#: template/flag_comment.php msgid "Return to Details" msgstr "Zu den Details zurückkehren" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." +#: template/header.php msgid " My Account" msgstr "Mein Konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Paketaktionen" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD ansehen" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Änderungen betrachten" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Schnappschuss herunterladen" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Durchsuche Wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Als \"veraltet\" markiert (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Paket als \"veraltet\" markieren" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Paketmarkierung entfernen" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Stimme entfernen" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Für dieses Paket stimmen" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Benachrichtigungen deaktivieren" +#: template/pkgbase_actions.php msgid "Enable notifications" -msgstr "Benachritigungen aktivieren" +msgstr "Benachrichtigungen aktivieren" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" -msgstr "Verwalte Mit-Betreuer" +msgstr "Verwalte Co-Maintainer" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d ausstehende Anfrage" msgstr[1] "%d ausstehende Anfragen" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Paket übernehmen" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Paketbasis Details" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "nur lesen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Schlüsselwörter" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Eingereicht von" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" -msgstr "Betreuer" +msgstr "Maintainer" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Letzter Paketierer" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stimmen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Beliebtheit" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Zuerst eingereicht am" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Letzte Aktualisierung" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Bearbeite Kommentar für: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Kommentar hinzufügen" +#: template/pkg_comments.php msgid "View all comments" msgstr "Zeige alle Kommentare" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Angeheftete Kommentare" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Neueste Kommentare" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s kommentierte %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anonym kommentierte %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "gelöscht am %s von %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "gelöscht am %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "geändert am %s von %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "geändert am %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Kommentar wiederherstellen" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Kommentar löschen" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Kommentar anheften" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Kommentar losheften" +#: template/pkg_comments.php msgid "All comments" msgstr "Alle Kommentare" +#: template/pkg_details.php msgid "Package Details" msgstr "Paket-Details" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paketbasis" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beschreibung" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Besuche die Web-Seite für" +#: template/pkg_details.php msgid "Licenses" msgstr "Lizenzen" +#: template/pkg_details.php msgid "Groups" msgstr "Gruppen" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikte" +#: template/pkg_details.php msgid "Provides" msgstr "Liefert" +#: template/pkg_details.php msgid "Replaces" msgstr "Ersetzt" +#: template/pkg_details.php msgid "Dependencies" msgstr "Abhängigkeiten" +#: template/pkg_details.php msgid "Required by" msgstr "Benötigt von" +#: template/pkg_details.php msgid "Sources" msgstr "Quellen" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Benutze dieses Formular, um die Anfrage für die Paketbasis %s%s%s zu " -"schließen." +msgstr "Benutze dieses Formular, um die Anfrage für die Paketbasis %s%s%s zu schließen." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Das Kommentarfeld kann leer gelassen werden, es wird jedoch strengstens " -"empfohlen, beim Ablehnen einer Anfrage einen Kommentar hinzuzufügen." +msgstr "Das Kommentarfeld kann leer gelassen werden, es wird jedoch strengstens empfohlen, beim Ablehnen einer Anfrage einen Kommentar hinzuzufügen." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Grund" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Akzeptiert" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Zurückgewiesen" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Benutze dieses Formular um eine Anfrage für die Paketbasis %s%s%s " -"einzureichen, welche die folgenden Pakete enthält:" +msgstr "Benutze dieses Formular um eine Anfrage für die Paketbasis %s%s%s einzureichen, welche die folgenden Pakete enthält:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Anfragetyp" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Löschung" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Verwaist" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Verschmelzen mit" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Durch das Absenden einer Löschanfrage wird ein vertrauenswürdiger Benutzer " -"gefragt die Paketbasis zu löschen. Dieser Typ von Anfragen soll für doppelte " -"Pakete, vom Upstream aufgegebene Software sowie illegale und unreparierbar " -"kaputte Pakete verwendet werden." +msgstr "Durch das Absenden einer Löschanfrage wird ein vertrauenswürdiger Benutzer gefragt die Paketbasis zu löschen. Dieser Typ von Anfragen soll für doppelte Pakete, vom Upstream aufgegebene Software sowie illegale und unreparierbar kaputte Pakete verwendet werden." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Durch das Absenden einer Zusammenfüranfrage wird ein vertrauenswürdiger " -"Benutzer gefragt die Paketbasis zu löschen und die Stimmen und Kommentare zu " -"einer anderen Paketbasis zu transferieren. Das Zusammenführen eines Paketes " -"betrifft nicht die zugehörigen Git Repositories. Stelle sicher, dass die Git " -"Historie des Zielpakets von dir aktualisiert wird." +msgstr "Durch das Absenden einer Zusammenfüranfrage wird ein vertrauenswürdiger Benutzer gefragt die Paketbasis zu löschen und die Stimmen und Kommentare zu einer anderen Paketbasis zu transferieren. Das Zusammenführen eines Pakets betrifft nicht die zugehörigen Git-Repositories. Stelle sicher, dass die Git-Historie des Zielpakets von dir aktualisiert wird." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Durch das absenden einer Verwaisanfrage wird ein vertrauenswürdiger Benutzer " -"gebeten die Paketbasis zu enteignen. Bitte tue das nur, wenn das Paket " -"Aufmerksamkeit des Betreuers benötigt, der Betreuer nicht reagiert und Du " -"vorher bereits versucht hast ihn zu kontaktieren." +msgstr "Durch das absenden einer Verwaisanfrage wird ein vertrauenswürdiger Benutzer gebeten die Paketbasis zu enteignen. Bitte tue das nur, wenn das Paket Aufmerksamkeit des Maintainers benötigt, der Maintainer nicht reagiert und Du vorher bereits versucht hast ihn zu kontaktieren." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Die Suchkriterien erzielten keine Treffer in Anfragen." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d Paket gefunden." msgstr[1] "%d Paketanfragen gefunden." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Seite %d von %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Eingereicht von" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "noch ~%d Tag" msgstr[1] "noch ~%d Tage" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d Stunde verbleibend" msgstr[1] "~%d Stunden verbleibend" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 Stunde verbleibend" +#: template/pkgreq_results.php msgid "Accept" msgstr "Akzeptieren" +#: template/pkgreq_results.php msgid "Locked" msgstr "Gesperrt" +#: template/pkgreq_results.php msgid "Close" msgstr "Schließen" +#: template/pkgreq_results.php msgid "Pending" msgstr "Ausstehend" +#: template/pkgreq_results.php msgid "Closed" msgstr "Geschlossen" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Name, Beschreibung" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Nur Name" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Exakter Name" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Exakte Paketbasis" +#: template/pkg_search_form.php msgid "Co-maintainer" -msgstr "Mit-Betreuer" +msgstr "Co-Maintainer" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" -msgstr "Betreuer, Mit-Betreuer" +msgstr "Maintainer, Co-Maintainer" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Markiert" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nicht markiert" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Name" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Abgestimmt" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Zuletzt geändert" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Aufsteigend" +#: template/pkg_search_form.php msgid "Descending" msgstr "Absteigend" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Suchkriterien eingeben" +#: template/pkg_search_form.php msgid "Search by" msgstr "Suche nach" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Veraltet" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortieren nach" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Neu ordnen" +#: template/pkg_search_form.php msgid "Per page" msgstr "Pro Seite" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Los" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Verwaiste Pakete" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fehler beim Aufrufen der Paket-Liste." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Die Suchkriterien erzielten keine Treffer in Pakete." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d Paket gefunden." msgstr[1] "%d Pakete gefunden." +#: template/pkg_search_results.php msgid "Version" msgstr "Version" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Die Beliebtheit wird als die Summe aller Stimmen berechnet, wobei jede " -"Stimme mit dem Faktor %.2f pro Tag seit der Erstellung gewichtet wird." +msgstr "Die Beliebtheit wird als die Summe aller Stimmen berechnet, wobei jede Stimme mit dem Faktor %.2f pro Tag seit der Erstellung gewichtet wird." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "Verwaist" +#: template/pkg_search_results.php msgid "Actions" msgstr "Aktionen" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "\"veraltet\"-Markierung entfernen" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Pakete übernehmen" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Betreuung der Pakete abgeben" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Pakete löschen" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Bestätige" +#: template/search_accounts_form.php msgid "Any type" msgstr "Beliebiger Typ" +#: template/search_accounts_form.php msgid "Search" msgstr "Suche" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiken" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Verwaiste Pakete" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakete, die in den letzten 7 Tagen hinzugefügt wurden" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakete, die in den letzten 7 Tagen aktualisiert wurden" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakete, die im letzten Jahr aktualisiert wurden" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pakete, die nie aktualisiert wurden" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrierte Benutzer" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Vertrauenswürdige Benutzer (TU)" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Letzte Aktualisierungen" +#: template/stats/updates_table.php msgid "more" msgstr "mehr" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Meine Statistiken" +#: template/tu_details.php msgid "Proposal Details" msgstr "Vorschlag-Details" +#: template/tu_details.php msgid "This vote is still running." msgstr "Diese Abstimmung läuft noch." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Eingereicht: %s von %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Ende" +#: template/tu_details.php msgid "Result" msgstr "Ergebnis" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nein" +#: template/tu_details.php msgid "Abstain" msgstr "Enthalten" +#: template/tu_details.php msgid "Total" msgstr "Insgesamt" +#: template/tu_details.php msgid "Participation" msgstr "Teilnahme" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Letzte Stimme vom TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Letzte Stimme" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Keine Ergebnisse gefunden" +#: template/tu_list.php msgid "Start" msgstr "Beginn" +#: template/tu_list.php msgid "Back" msgstr "Zurück" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "AUR Passwort-Reset" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "Eine Passwort-Reset wurde für den Account {user}, der mit dieser E-Mail-Adresse verknüpft ist, angefordert. Wenn Du Dein Passwort zurücksetzen möchtest, folge dem untenstehenden Link [1], ansonsten kannst Du diese Nachricht ignorieren und nichts wird geschehen." + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "Willkommen im Arch User Repository" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "Willkommen im Arch User Repository! Um ein Passwort für dein neues Konto festzulegen, klicke bitte auf den unten stehenden Link [1]. Sollte das nicht funktionieren, versuche den Link zu kopieren und in deinem Browser einzufügen." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "AUR Kommentar für {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "{user} [1] hat einen Kommentar zu {pkgbase} [2] erstellt:" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "Wenn Du keine weiteren Benachrichtigungen für dieses Paket erhalten willst, wähle \"{label}\" auf der Seite des Pakets [2]." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "AUR Paket-Update: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "{user} [1] hat einen neuen Commit in {pkgbase} [2] gepushed." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "AUR Out-of-date Benachrichtigung für {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "Dein Paket {pkgbase} [1] wurde von {user} [2] als veraltet markiert:" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "AUR Besitzer Benachrichtigung für {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "Das Paket {pkgbase} [1] wurde von {user} [2] adoptiert." + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "Das Paket {pkgbase} [1] wurde von {user} [2] verstoßen." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "AUR Co-Maintainer Benachrichtigung für {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "Du wurdest in die Liste der Co-Maintainer für {pkgbase} [1] aufgenommen." + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "Du wurdest von der liste der Co-Maintainer für {pkgbase} [1] entfernt." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "AUR Paket gelöscht: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "{user} [1] hat {old} [2] in {new} [3] gemerged.\n\nWenn Du keine weiteren Benachrichtigungen über das neue Paket erhalten möchtest, gehe bitte zu [3] und klicke \"{label}\"." + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "{user} [1] hat {pkgbase} [2] gelöscht.\n\nDu wirst keine weiteren Benachrichtigungen über dieses Paket erhalten." + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "TU Abstimmungs-Erinnerung: Vorschlag {id}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "Bitte denke daran für Vorschlag {id} [1] deine Stimme anzugeben. Die Abstimmungspriode endet in weniger als 48 Stunden." diff --git a/po/el.po b/po/el.po index aac17bb2..8eaa5f0f 100644 --- a/po/el.po +++ b/po/el.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Achilleas Pipinellis, 2014 # Achilleas Pipinellis, 2013 @@ -12,1298 +12,1671 @@ # flamelab , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Greek (http://www.transifex.com/lfleischer/aur/language/el/)\n" -"Language: el\n" +"Language-Team: Greek (http://www.transifex.com/lfleischer/aurweb/language/el/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: el\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Η σελίδα δε βρέθηκε" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Μας συγχωρείτε, η σελίδα που ζητήσατε δεν υπάρχει." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "Λογαριασμοί" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Δεν σας επιτρέπεται η πρόσβαση σε αυτήν την περιοχή." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Δεν ήταν δυνατή η λήψη πληροφοριών για αυτόν τον χρήστη." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Δεν έχετε την άδεια να επεξεργαστείτε αυτόν τον λογαριασμό." +#: html/account.php msgid "Use this form to search existing accounts." -msgstr "" -"Χρησιμοποιήστε αυτή τη φόρμα για να αναζητήσετε υπάρχοντες λογαριασμούς." +msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να αναζητήσετε υπάρχοντες λογαριασμούς." +#: html/account.php msgid "You must log in to view user information." msgstr "Πρέπει να συνδεθείτε για να δείτε πληροφορίες χρήστη." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Προσθέστε Πρόταση" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Μη έγκυρο διακριτικό για την ενέργεια του χρήστη." +#: html/addvote.php msgid "Username does not exist." msgstr "Αυτό το όνομα χρήστη δεν υπάρχει." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s έχει ήδη πρόταση σε εξέλιξη για αυτό το θέμα." +#: html/addvote.php msgid "Invalid type." msgstr "Άκυρος τύπος." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Η πρόταση δεν μπορεί να είναι κενή." +#: html/addvote.php msgid "New proposal submitted." msgstr "Υποβλήθηκε νέα πρόταση." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Υποβάλετε μία πρόταση προς ψήφιση." +#: html/addvote.php msgid "Applicant/TU" msgstr "Αιτών / TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(κενό εάν δεν είναι εφαρμόσιμο)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Είδος" +#: html/addvote.php msgid "Addition of a TU" msgstr "Προσθήκη ενός TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Αφαίρεση ενός TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Αφαίρεση ενός TU (αδήλωτη αδράνεια)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Τροποποίηση των " +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Πρόταση" +#: html/addvote.php msgid "Submit" msgstr "Υποβολή" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Αρχική" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Τα πακέτα μου" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Καλωσήρθατε στο AUR! Διαβάστε παρακαλώ τον %sOδηγό Χρηστών του AUR%s και τον " -"%sΟδηγό των Trusted Users%s για περισσότερες πληροφορίες. " +msgstr "Καλωσήρθατε στο AUR! Διαβάστε παρακαλώ τον %sOδηγό Χρηστών του AUR%s και τον %sΟδηγό των Trusted Users%s για περισσότερες πληροφορίες. " +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Τα συνεισφέροντα PKGBUILDs %sπρέπει%s να ακολουθούν τα %sΠρότυπα δημιουργίας " -"πακέτων του Arch%s αλλιώς θα διαγράφονται! " +msgstr "Τα συνεισφέροντα PKGBUILDs %sπρέπει%s να ακολουθούν τα %sΠρότυπα δημιουργίας πακέτων του Arch%s αλλιώς θα διαγράφονται! " +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Θυμηθείτε να ψηφίσετε τα αγαπημένα σας πακέτα!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Ορισμένα πακέτα μπορεί να μεταφερθούν ως binaries στο [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ΑΠΟΠΟΙΗΣΗ ΕΥΘΥΝΗΣ" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Συζήτηση" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Αναφορά Σφαλμάτων" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Αναζήτηση Πακέτου" +#: html/index.php msgid "Adopt" msgstr "Υιοθέτηση" +#: html/index.php msgid "Vote" msgstr "Ψηφίστε" +#: html/index.php msgid "UnVote" msgstr "Αναίρεση ψήφου" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Ειδοποίηση" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Διακοπή Ειδοποίησης" +#: html/index.php msgid "UnFlag" msgstr "Αποχαρακτήριση" +#: html/login.php template/header.php msgid "Login" msgstr "Σύνδεση" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Έχετε συνδεθεί ως: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Αποσύνδεση" +#: html/login.php msgid "Enter login credentials" msgstr "Εισάγετε πιστοποιητικά εισόδου" +#: html/login.php msgid "User name or email address" msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Κωδικός" +#: html/login.php msgid "Remember me" msgstr "Θυμήσου με" +#: html/login.php msgid "Forgot Password" msgstr "Ξεχάσατε τον κωδικό σας" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Το HTTP είναι απενεργοποιημένο. Παρακαλώ %sγυρίστε σε HTTPs%s αν θέλετε να " -"εισέλθετε." +msgstr "Το HTTP είναι απενεργοποιημένο. Παρακαλώ %sγυρίστε σε HTTPs%s αν θέλετε να εισέλθετε." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Κριτήρια Αναζήτησης" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Πακέτα" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Σφάλμα στη διαδικασία λήψης των πληροφοριών του πακέτου." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Λείπει ένα απαραίτητο πεδίο." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." -msgstr "" -"Οι τιμές που εισαγάγατε στα πεδία “κωδικού” και “επιβεβαίωσης κωδικού” δεν " -"είναι ίδιες." +msgstr "Οι τιμές που εισαγάγατε στα πεδία “κωδικού” και “επιβεβαίωσης κωδικού” δεν είναι ίδιες." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Ο κωδικός πρέπει να αποτελείται τουλάχιστον %s χαρακτήρες." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Μη έγκυρο e-mail." +#: html/passreset.php msgid "Password Reset" msgstr "Επαναφορά Κωδικού" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Ελέγξτε το e-mail σας για το σύνδεσμο επιβεβαίωσης." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Το συνθηματικό σας έχει επαναφερθεί με επιτυχία." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Παρακαλώ επιβεβαιώστε την διεύθυνση e-mail σας:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Εισάγετε νέο κωδικό" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Επιβεβαιώστε το νέο σας συνθηματικό:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Συνεχίστε" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Εάν έχετε ξεχάσει την ηλεκτρονική διεύθυνση που χρησιμοποιήσατε για να " -"εγγραφείτε, παρακαλώ στείλτε ένα μήνυμα στη λίστα ταχυδρομείου %saur-general" -"%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Εάν έχετε ξεχάσει την ηλεκτρονική διεύθυνση που χρησιμοποιήσατε για να εγγραφείτε, παρακαλώ στείλτε ένα μήνυμα στη λίστα ταχυδρομείου %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Εισάγετε την διεύθυνση e-mail σας:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Δεν μπορεί να βρεθεί το πακέτο για τη συγχώνευση ψήφων και σχόλιων" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Τα επιλεγμένα πακέτα δεν έχουν διαγραφεί, παρακαλώ ελέγξτε το κουτάκι " -"επιβεβαίωσης." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Τα επιλεγμένα πακέτα δεν έχουν διαγραφεί, παρακαλώ ελέγξτε το κουτάκι επιβεβαίωσης." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Διαγραφή Πακέτου" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Διαγράψτε πακέτο" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Η διαγραφή ενός πακέτου είναι μόνιμη." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Επιλέξτε το κουτάκι για να επιβεβαιώσετε." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Επιβεβαιώστε τη διαγραφή του πακέτου" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Διαγράψτε" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Μόνο οι Trusted Users και οι Developers μπορούν να διαγράψουν πακέτα." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Aποδεσμεύστε το Πακέτο" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "Αποδέσμευση" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "" +#: html/pkgflag.php msgid "Flag" msgstr "Επισήμανση" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "Συγχώνευση Πακέτου" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Συγχώνευση πακέτου" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Μόλις το πακέτο συγχωνευτεί, η διαδικασία δεν μπορεί να αντιστραφεί." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Εισάγετε το όνομα του πακέτου με το οποίο επιθυμείτε να συγχωνεύσετε το " -"τρέχον πακέτο." +msgstr "Εισάγετε το όνομα του πακέτου με το οποίο επιθυμείτε να συγχωνεύσετε το τρέχον πακέτο." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Συγχωνεύστε σε:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Επιβεβαιώστε τη συγχώνευση του πακέτου" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Συγχώνευση" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Μόνο οι Trusted Users και οι Developers μπορούν να συγχωνεύσουν πακέτα." +msgstr "Μόνο οι Trusted Users και οι Developers μπορούν να συγχωνεύσουν πακέτα." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Πρώτο" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Προηγούμενο" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Επόμενο" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Τελευταίο" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "Εγγραφείτε" +#: html/register.php msgid "Use this form to create an account." msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να δημιουργήσετε λογαριασμό." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Δεν ήταν δυνατή η ανάκτηση των στοιχείων της πρότασης." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Η ψηφοφορία έχει κλείσει για αυτή την πρόταση." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Μόνο οι Trusted Users έχουν δικαίωμα ψήφου." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Δεν μπορείτε να ψηφίσετε σε μία πρόταση που αφορά σε εσάς." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Έχετε ήδη ψηφίσει για αυτή τη πρόταση." +#: html/tu.php msgid "Vote ID not valid." msgstr "Το ID της ψήφου δεν είναι έγκυρο." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Τρέχουσες ψήφοι" +#: html/tu.php msgid "Past Votes" msgstr "Παρελθόντες ψήφοι" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Ψηφίσαντες" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Η εγγραφή λογαριασμών έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω " -"επιθέσεων spam. Μας συγχωρείτε για την ενόχληση." +msgstr "Η εγγραφή λογαριασμών έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω επιθέσεων spam. Μας συγχωρείτε για την ενόχληση." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Λείπει το ID Χρήστη" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Το όνομα χρήστη δεν είναι έγκυρο." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Πρέπει να αποτελείται από %s έως %s χαρακτήρες" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Ξεκινήστε και τελειώστε με γράμμα ή αριθμό" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Μπορεί να περιλαμβάνει μόνο μία τελεία, κάτω παύλα ή παύλα." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Αυτή η διεύθυνση email δεν είναι έγκυρη." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Το fingerprint του PGP κλειδιού δεν είναι έγκυρο." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Δε γίνεται να αυξηθούν τα δικαιώματα του λογαριασμού" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Η γλώσσα αυτή δεν υποστηρίζεται ακόμη." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Το όνομα, %s%s%s, χρησιμοποιείται ήδη." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Η διεύθυνση, %s%s%s, χρησιμοποιείται ήδη." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Σφάλμα κατά τη δημιουργία του λογαριασμού, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Ο λογαριασμός, %s%s%s, δημιουργήθηκε επιτυχώς." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Ένα κλειδί επαναφοράς του κωδικού έχει σταλεί στην ηλεκτρονική σας διεύθυνση." +msgstr "Ένα κλειδί επαναφοράς του κωδικού έχει σταλεί στην ηλεκτρονική σας διεύθυνση." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "" -"Πατήστε στον παραπάνω σύνδεσμο Σύνδεση για να χρησιμοποιήσετε το λογαριασμό " -"σας." +msgstr "Πατήστε στον παραπάνω σύνδεσμο Σύνδεση για να χρησιμοποιήσετε το λογαριασμό σας." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Δεν έγιναν αλλαγές στο λογαριασμό, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Ο λογαριασμός, %s%s%s, τροποποποιήθηκε επιτυχώς." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Η σύνδεση στο λογαριασμό σας έχει απενεργοποιηθεί για την IP σας, πιθανόν " -"λόγω επιθέσεων spam. Μας συγχωρείτε για την ταλαιπωρία." +msgstr "Η σύνδεση στο λογαριασμό σας έχει απενεργοποιηθεί για την IP σας, πιθανόν λόγω επιθέσεων spam. Μας συγχωρείτε για την ταλαιπωρία." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Ο λογαριασμός έχει ανασταλεί" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Η επαναφορά του κωδικού σας έχει πραγματοποιηθεί. Αν μόλις δημιουργήσατε ένα " -"νέο λογαρισμό, παρακαλώ χρησιμοποιείστε τον σύνδεσμο από το email " -"ενεργοποίησης για να ορίσετε έναν αρχικό κωδικό. Διαφορετικά, παρακαλείσθε " -"να ζητήσετε ένα κλειδί επαναφοράς στη σελίδα %sPassword Reset%s." +msgstr "Η επαναφορά του κωδικού σας έχει πραγματοποιηθεί. Αν μόλις δημιουργήσατε ένα νέο λογαρισμό, παρακαλώ χρησιμοποιείστε τον σύνδεσμο από το email ενεργοποίησης για να ορίσετε έναν αρχικό κωδικό. Διαφορετικά, παρακαλείσθε να ζητήσετε ένα κλειδί επαναφοράς στη σελίδα %sPassword Reset%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Λάθος όνομα χρήστη ή συνθηματικό." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ένα σφάλμα προέκυψε προσπαθώντας να δημιουργήσετε μια συνεδρία χρήστη." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Μη έγκυρο e-mail και συνδυασμός κλειδιού επαναφοράς" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Κανένα" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Δείτε τις πληροφορίες λογαριασμού του %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Το σχόλιο έχει προστεθεί." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Πρέπει να έχετε συνδεθεί για να προσπαθήσετε να επεξεργαστείτε τις " -"πληροφορίες του πακέτου." +msgstr "Πρέπει να έχετε συνδεθεί για να προσπαθήσετε να επεξεργαστείτε τις πληροφορίες του πακέτου." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Λείπει το ID του σχολίου." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Σφάλμα κατά τη διάρκεια φόρτωσης των πληροφοριών του πακέτου." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Οι πληροφορίες του πακέτου δεν μπόρεσαν να βρεθούν." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Πρέπει να έχετε συνδεθεί για να επισημάνετε τα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Δεν επιλέξατε κάποιο πακέτο για επισήμανση." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Τα συγκεκριμένα πακέτα έχουν επισημανθεί ως παρωχημένα." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να αποχαρακτηρίσετε πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Δεν επιλέξατε κάποιο πακέτο για να αποχαρακτηρίσετε." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Τα συγκεκριμένα πακέτα έχουν αποεπισημανθεί." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Δεν έχετε τα απαραίτητα δικαιώματα για να διαγράψετε τα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Δεν επιλέξατε κάποιο πακέτο για να διαγράψετε." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Tα επιλεγμένα πακέτα έχουν διαγραφεί." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να υιοθετήσετε πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να αποδεσμεύσετε πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Δεν επιλέξατε κανένα πακέτο για να υιοθετήσετε." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Δεν επιλέξατε κάποιο πακέτο για απόρριψη." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Τα επιλεγμένα πακέτα έχουν υιοθετηθεί." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Τα επιλεγμένα πακέτα έχουν αποδεσμευθεί." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να ψηφίσετε για πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "" -"Πρέπει να έχετε συνδεθεί για να μπορέσετε να ακυρώσετε την ψήφο σας για " -"πακέτα." +msgstr "Πρέπει να έχετε συνδεθεί για να μπορέσετε να ακυρώσετε την ψήφο σας για πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Δεν επιλέξατε κάποιο πακέτο για να το ψηφίσετε." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Οι ψήφοι σας έχουν αφαιρεθεί από τα επιλεγμένα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Οι ψήφοι σας προστέθηκαν στα επιλεγμένα πακέτα." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Δεν ήταν δυνατή η προσθήκη του στη λίστα ειδοποίησης." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Έχετε προστεθεί στη λίστα ειδοποίησης σχολίων για το %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Έχετε αφαιρεθεί από τη λίστα ειδοποίησης σχολίων για το %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Δεν σας επιτρέπεται να διαγράψετε αυτό το σχόλιο." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Το σχόλιο έχει διαγραφεί." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Δείτε τις λεπτομέρειες πακέτου για το" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Μη έγκυρο όνομα: μόνο πεζοί χαρακτήρες επιτρέπονται." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Όνομα χρήστη" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Είδος λογαριασμού" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Χρήστης" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Developer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Διεύθυνση email" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Πραγματικό 'Ονομα" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Ψευδώνυμο IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP Key Fingerprint" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Κατάσταση" +#: template/account_details.php msgid "Inactive since" msgstr "Αδρανής από" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Ενεργός" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "άγνωστο" +#: template/account_details.php msgid "Last Login" msgstr "Τελευταία σύνδεση" +#: template/account_details.php msgid "Never" msgstr "Ποτέ" +#: template/account_details.php msgid "View this user's packages" msgstr "Δείτε τα πακέτα αυτού του χρήστη" +#: template/account_details.php msgid "Edit this user's account" msgstr "Τροποποιήστε το λογαριασμό αυτού του χρήστη" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "απαιτούμενο" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Απλός χρήστης" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Αξιόπιστος χρήστης" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Ο Λογαριασμός έχει Ανασταλεί." +#: template/account_edit_form.php msgid "Inactive" msgstr "Αδρανής" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Πληκτρολογήστε ξανά τον κωδικό σας." +#: template/account_edit_form.php msgid "Language" msgstr "Γλώσσα" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Ειδοποίησε για νέα σχόλια" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Eνημέρωση" +#: template/account_edit_form.php msgid "Create" msgstr "Δημιουργήστε" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Επαναφορά" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Δε βρέθηκε αποτέλεσμα που να ικανοποιεί τα κριτήρια αναζήτησης." +#: template/account_search_results.php msgid "Edit Account" msgstr "Τροποποίηση Λογαριασμού" +#: template/account_search_results.php msgid "Suspended" msgstr "Έχει ανασταλεί" +#: template/account_search_results.php msgid "Edit" msgstr "Επεξεργασία" +#: template/account_search_results.php msgid "Less" msgstr "Λιγότερο" +#: template/account_search_results.php msgid "More" msgstr "Περισσότερα" +#: template/account_search_results.php msgid "No more results to display." msgstr "Δεν υπάρχουν άλλα αποτελέσματα για να δείτε." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "Ο λογαριασμός μου" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ενέργειες Πακέτου" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Δείτε το PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Επισημάνετε ως παρωχημένο" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Αποχαρακτηρίστε ως παρωχημένο" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Αφαιρέστε ψήφο" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Ψηφίστε για αυτό το πακέτο" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Απενεργοποιήστε τις ειδοποιήσεις" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Υιοθετήστε το Πακέτο" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Λέξεις κλειδιά" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Υποβάλλων" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Συντηρητής" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Ψήφοι" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Πρώτη Υποβολή" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Τελευταία Ενημέρωση" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Προσθέστε σχόλιο" +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Τελευταία σχόλια" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Διαγράψτε το σχόλιο" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Όλα τα σχόλια" +#: template/pkg_details.php msgid "Package Details" msgstr "Πληροφορίες Πακέτου" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Περιγραφή" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Επισκεφτείτε την ιστοσελίδα για " +#: template/pkg_details.php msgid "Licenses" msgstr "" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "" +#: template/pkg_details.php msgid "Replaces" msgstr "" +#: template/pkg_details.php msgid "Dependencies" msgstr "Εξαρτήσεις" +#: template/pkg_details.php msgid "Required by" msgstr "Απαιτείται από" +#: template/pkg_details.php msgid "Sources" msgstr "Πηγές" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Δεκτός" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Απορριπτέος" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Συγχώνευση σε" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1311,6 +1684,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1318,247 +1692,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Όνομα, Περιγραφή" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Όνομα μόνο" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Όλα" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Σημειωμένα" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Μη Σημειωμένα" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Όνομα" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Ψηφισμένο" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Αύξουσα" +#: template/pkg_search_form.php msgid "Descending" msgstr "Φθίνουσα" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Εισάγετε κριτήρια αναζήτησης" +#: template/pkg_search_form.php msgid "Search by" msgstr "Αναζήτηση κατά" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Παρωχημένα" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ταξινόμηση κατά" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Σειρά ταξινόμησης" +#: template/pkg_search_form.php msgid "Per page" msgstr "Ανά σελίδα" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Πήγαινε" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Ορφανά" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Σφάλμα κατά τη λήψη της λίστας πακέτων." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Κανένα πακέτο δεν ικανοποιεί τα κριτήρια αναζήτησης σας." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +#: template/pkg_search_results.php msgid "Version" msgstr "Έκδοση" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ναι" +#: template/pkg_search_results.php msgid "orphan" msgstr "ορφανό" +#: template/pkg_search_results.php msgid "Actions" msgstr "Ενέργειες" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Αποχαρακτηρίστε το πακέτο ως Παρωχημένο" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Υιοθετήστε Πακέτα" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Aποδεσμεύστε Πακέτα" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Διαγράψτε Πακέτα" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Επιβεβαιώστε" +#: template/search_accounts_form.php msgid "Any type" msgstr "Κάθε είδος" +#: template/search_accounts_form.php msgid "Search" msgstr "Αναζήτηση" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Στατιστικά" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Ορφανά Πακέτα" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Πακέτα που προστέθηκαν τις τελευταίες 7 ημέρες" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Πακέτα που ενημερώθηκαν τις τελευταίες 7 ημέρες" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Πακέτα που ενημερώθηκαν κατά το παρελθόν έτος" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Πακέτα που δεν ενημερώθηκαν ποτέ" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Εγγεγραμμένοι Χρήστες" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Πρόσφατες Ανανεώσεις" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Τα στατιστικά μου" +#: template/tu_details.php msgid "Proposal Details" msgstr "Πληροφορίες Πρότασης" +#: template/tu_details.php msgid "This vote is still running." msgstr "Η ψηφοφορία αυτή βρίσκεται ακόμη σε εξέλιξη." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Υποβλήθηκε: %s από %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Τέλος" +#: template/tu_details.php msgid "Result" msgstr "Αποτέλεσμα" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Όχι" +#: template/tu_details.php msgid "Abstain" msgstr "Απέχουν" +#: template/tu_details.php msgid "Total" msgstr "Σύνολο" +#: template/tu_details.php msgid "Participation" msgstr "Συμμετοχή" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Κανένα αποτέλεσμα δεν βρέθηκε." +#: template/tu_list.php msgid "Start" msgstr "Ξεκινήστε" +#: template/tu_list.php msgid "Back" msgstr "Πίσω" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/es.po b/po/es.po index cabcc007..f32725c3 100644 --- a/po/es.po +++ b/po/es.po @@ -1,9 +1,9 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: -# Adolfo Jayme Barrientos, 2015 +# Adolfo Jayme-Barrientos, 2015 # Angel Velasquez , 2011 # juantascon , 2011 # Lukas Fleischer , 2011 @@ -16,1640 +16,2128 @@ # Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-29 14:11+0000\n" -"Last-Translator: Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] \n" -"Language-Team: Spanish (http://www.transifex.com/lfleischer/aur/language/" -"es/)\n" -"Language: es\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Spanish (http://www.transifex.com/lfleischer/aurweb/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página no encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "La página solicitada no existe." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" -"Las direcciones de clonado de Git no deberían ser habiertas en un navegador." +msgstr "Las direcciones de clonado de Git no deberían ser habiertas en un navegador." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Para clonar el repositorio Git de %s, ejecuta %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Haz clic %saquí%s para regresar a la página de detalles de %s." +#: html/503.php msgid "Service Unavailable" msgstr "Servicio no disponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"¡No te asustes! El sitio está desactivado por tareas de mantenimiento. " -"Volveremos pronto." +msgstr "¡No te asustes! El sitio está desactivado por tareas de mantenimiento. Volveremos pronto." +#: html/account.php msgid "Account" msgstr "Cuenta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No estás autorizado para acceder a esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No se pudo obtener la información del usuario especificado." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "No tienes los permisos para editar esta cuenta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa este formulario para buscar cuentas existentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Debes autentificarte para ver la información del usuario." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Añadir propuesta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "La ficha no es válida para la acción de usuario." +#: html/addvote.php msgid "Username does not exist." msgstr "El nombre de usuario no existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ya tiene una propuesta activa." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo no válido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta no puede estar vacía." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nueva propuesta enviada." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Envía una propuesta a la cual votar." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/Usuario de confianza (UC)" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Agregar a un nuevo usuario de confianza" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remover a un usuario de confianza" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remover a un usuario de confianza (no declarado inactivo)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Enmienda a los Estatutos" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" +#: html/addvote.php msgid "Submit" msgstr "Subir" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Administrar coencargados" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Editar comentario" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Tablero" +#: html/home.php template/header.php msgid "Home" msgstr "Inicio" +#: html/home.php msgid "My Flagged Packages" msgstr "Mis paquetes marcados" +#: html/home.php msgid "My Requests" msgstr "Mis solicitudes" +#: html/home.php msgid "My Packages" msgstr "Mis paquetes" +#: html/home.php msgid "Search for packages I maintain" msgstr "Buscar paquetes que mantengo" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Paquetes que soy coencargado" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Buscar paquetes que soy coencargado" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"¡Bienvenido al repositorio de usuarios de Arch! Léase las %sDirectrices del " -"usuario del AUR%s y las %sDirectrices del usuario de confianza del AUR%s " -"para mayor información." +msgstr "¡Bienvenido al repositorio de usuarios de Arch! Léase las %sDirectrices del usuario del AUR%s y las %sDirectrices del usuario de confianza del AUR%s para mayor información." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de " -"empaquetado de Arch%s de otra forma serán eliminados." +msgstr "Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de empaquetado de Arch%s de otra forma serán eliminados." +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerda votar tus paquetes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Algunos paquetes pueden estar provistos de forma binaria en [community]." +msgstr "Algunos paquetes pueden estar provistos de forma binaria en [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Los paquetes del AUR son producidos por los usuarios. Cualquier uso de los " -"archivos de estos es a tu propio riesgo." +msgstr "Los paquetes del AUR son producidos por los usuarios. Cualquier uso de los archivos de estos es a tu propio riesgo." +#: html/home.php msgid "Learn more..." msgstr "Más información…" +#: html/home.php msgid "Support" msgstr "Ayuda" +#: html/home.php msgid "Package Requests" msgstr "Solicitudes para los paquetes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Hay tres tipos de solicitudes que puedes presentar en el cuadro %sAcciones " -"del paquete%s en la página de detalles del paquete:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Hay tres tipos de solicitudes que puedes presentar en el cuadro %sAcciones del paquete%s en la página de detalles del paquete:" +#: html/home.php msgid "Orphan Request" msgstr "Solicitud de orfandad" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está " -"inactivo y el paquete se ha marcado como obsoleto por un largo tiempo." +msgstr "Solicitar la orfandad de un paquete, por ejemplo, cuando el encargado está inactivo y el paquete se ha marcado como obsoleto por un largo tiempo." +#: html/home.php msgid "Deletion Request" msgstr "Solicitud de eliminación" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Solicitar la eliminación de un paquete del repositorio de usuarios de Arch. " -"No utilices esta opción si un paquete está roto pero puede ser arreglado " -"fácilmente. En cambio, contacta al encargado del paquete y presenta una " -"solicitud de orfandad si es necesario." +msgstr "Solicitar la eliminación de un paquete del repositorio de usuarios de Arch. No utilices esta opción si un paquete está roto pero puede ser arreglado fácilmente. En cambio, contacta al encargado del paquete y presenta una solicitud de orfandad si es necesario." +#: html/home.php msgid "Merge Request" msgstr "Solicitud de unión" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Solicitar que un paquete sea unido con otro. Puede ser utilizado cuando un " -"paquete tiene que ser cambiado de nombre o sustituido por un paquete " -"dividido." +msgstr "Solicitar que un paquete sea unido con otro. Puede ser utilizado cuando un paquete tiene que ser cambiado de nombre o sustituido por un paquete dividido." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Si quieres discutir una solicitud, puedes utilizar la lista de correo %saur-" -"requests%s. Sin embargo, por favor no utilices esa lista para presentar " -"solicitudes." +msgstr "Si quieres discutir una solicitud, puedes utilizar la lista de correo %saur-requests%s. Sin embargo, por favor no utilices esa lista para presentar solicitudes." +#: html/home.php msgid "Submitting Packages" msgstr "Subir paquetes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Ahora se utiliza Git sobre SSH para subir paquetes al AUR. Véase la sección " -"%sSubir paquetes%s de la wiki del repositorio de usuarios de Arch para más " -"detalles." +msgstr "Ahora se utiliza Git sobre SSH para subir paquetes al AUR. Véase la sección %sSubir paquetes%s de la wiki del repositorio de usuarios de Arch para más detalles." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Las siguientes huellas SSH están en uso para el AUR." +#: html/home.php msgid "Discussion" msgstr "Debate" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"La discusión general sobre el repositorio de usuarios de Arch (AUR) y la " -"estructura de usuarios de confianza se realiza en la lista de correos %saur-" -"general%s. Para la discusión en relación con el desarrollo de la interfaz " -"web del AUR, utiliza la lista de correo %saur-dev%s." +msgstr "La discusión general sobre el repositorio de usuarios de Arch (AUR) y la estructura de usuarios de confianza se realiza en la lista de correos %saur-general%s. Para la discusión en relación con el desarrollo de la interfaz web del AUR, utiliza la lista de correo %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Informe de errores" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Si encuentras un error en la interfaz web del AUR, llena un informe de error " -"en nuestro %srastreador de errores o «bug tracker»%s. Usa este para reportar " -"%súnicamente%s errores de la interfaz web del AUR. Para reportar errores de " -"empaquetado debes contactar al encargado o dejar un comentario en la página " -"respectiva del paquete." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Si encuentras un error en la interfaz web del AUR, llena un informe de error en nuestro %srastreador de errores o «bug tracker»%s. Usa este para reportar %súnicamente%s errores de la interfaz web del AUR. Para reportar errores de empaquetado debes contactar al encargado o dejar un comentario en la página respectiva del paquete." +#: html/home.php msgid "Package Search" msgstr "Buscar paquetes" +#: html/index.php msgid "Adopt" msgstr "Adoptar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Retirar voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Quitar notificación" +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Autentificarte" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificado como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Salir" +#: html/login.php msgid "Enter login credentials" msgstr "Proporciona tus datos de acceso" +#: html/login.php msgid "User name or email address" msgstr "Nombre de usuario y dirección de correo" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" +#: html/login.php msgid "Remember me" msgstr "Recordarme" +#: html/login.php msgid "Forgot Password" msgstr "¿Olvidaste tu contraseña?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"La autentificación por HTTP está deshabilitada. %scambia a HTTPS%s si deseas " -"autentificarte" +msgstr "La autentificación por HTTP está deshabilitada. %scambia a HTTPS%s si deseas autentificarte" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criterio de búsqueda" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "No se pudieron recuperar correctamente los detalles del paquete." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campo obligatorio." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Los campos de la contraseña no coinciden." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Tu contraseña debe tener como mínimo %s letras." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Dirección de correo no válida." +#: html/passreset.php msgid "Password Reset" msgstr "Restablecer la contraseña" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Comprueba tu correo para ver el enlace de confirmación." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Se ha restablecido la contraseña correctamente." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirma tu dirección de correo:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Escribe tu contraseña nueva:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirma la contraseña nueva:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si olvidaste la dirección de correo que usaste para registrarte, envía un " -"mensaje a la %slista de correo general del AUR%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si olvidaste la dirección de correo que usaste para registrarte, envía un mensaje a la %slista de correo general del AUR%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduce tu dirección de correo:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Paquetes base" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Los paquetes seleccionados no se han abandonado, marca la casilla de " -"confirmación." +msgstr "Los paquetes seleccionados no se han abandonado, marca la casilla de confirmación." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"No se puede encontrar el paquete para unir los votos y comentarios en él." +msgstr "No se puede encontrar el paquete para unir los votos y comentarios en él." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "No se puede unir un paquete base consigo mismo." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Los paquetes seleccionados no han sido eliminados, comprueba la casilla de " -"confirmación." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Los paquetes seleccionados no han sido eliminados, comprueba la casilla de confirmación." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminación de paquetes" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Eliminar paquete" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Usa este formulario para eliminar el paquete base %s%s%s y los siguientes " -"paquetes en el AUR:" +msgstr "Usa este formulario para eliminar el paquete base %s%s%s y los siguientes paquetes en el AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El eliminado de un paquete es permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Selecciona la casilla para confirmar la acción." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirma la eliminación del paquete" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Eliminar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Solamente usuarios de confianza y desarrolladores pueden eliminar paquetes." +msgstr "Solamente usuarios de confianza y desarrolladores pueden eliminar paquetes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar paquete" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Utiliza este formulario para abandonar el paquete base %s %s %s que incluye " -"los siguientes paquetes:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Utiliza este formulario para abandonar el paquete base %s %s %s que incluye los siguientes paquetes:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Al seleccionar la casilla de verificación, confirmas que deseas abandonar el " -"paquete y transferir su propiedad a %s%s%s." +msgstr "Al seleccionar la casilla de verificación, confirmas que deseas abandonar el paquete y transferir su propiedad a %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Al seleccionar la casilla de verificación, confirmas que deseas abandonar el " -"paquete." +msgstr "Al seleccionar la casilla de verificación, confirmas que deseas abandonar el paquete." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirma para abandonar el paquete" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Solamente usuarios de confianza y desarrolladores puede forzar el abandono " -"de paquetes." +msgstr "Solamente usuarios de confianza y desarrolladores puede forzar el abandono de paquetes." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Marcar comentario" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Marcado como obsoleto" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Usa este formulario para marcar el paquete base %s%s%s y los siguientes " -"paquetes en el AUR como obsoletos:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Usa este formulario para marcar el paquete base %s%s%s y los siguientes paquetes en el AUR como obsoletos:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"%sNo%s uses el formulario para reportar fallos. Usa los comentarios del " -"paquete para ello." +msgstr "%sNo%s uses el formulario para reportar fallos. Usa los comentarios del paquete para ello." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Introduce el porqué del marcado del paquete como obsoleto, preferiblemente " -"incluye un enlace al anuncio de la nueva versión o al paquete comprimido." +msgstr "Introduce el porqué del marcado del paquete como obsoleto, preferiblemente incluye un enlace al anuncio de la nueva versión o al paquete comprimido." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Comentarios" +#: html/pkgflag.php msgid "Flag" msgstr "Marcar" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Solamente los usuario registrados pueden marcar como obsoleto." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Unión de paquetes" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Unir paquete" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Este formulario es para unir el paquete base %s%s%s en otro paquete." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Los siguientes paquetes serán eliminados:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vez unido el paquete este no puede ser separado." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduce el nombre del paquete que deseas unir." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Unir dentro:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirma la unión de paquetes" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Unión" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Solamente usuarios de confianza y desarrolladores pueden unir paquetes." +msgstr "Solamente usuarios de confianza y desarrolladores pueden unir paquetes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Enviar solicitud" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Cerrar solicitud" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Solicitud" +#: html/register.php template/header.php msgid "Register" msgstr "Registro" +#: html/register.php msgid "Use this form to create an account." msgstr "Usa este formulario para crear una cuenta." +#: html/tos.php msgid "Terms of Service" msgstr "Terminos y condiciones" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" -"Los siguientes documentos han sido actualizados. revísalos cuidadosamente:" +msgstr "Los siguientes documentos han sido actualizados. revísalos cuidadosamente:" +#: html/tos.php #, php-format msgid "revision %d" msgstr "Revisión %d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "Acepto los términos y condiciones anteriores." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuario de confianza" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No se han podido recuperar los detalles de la propuesta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Las votaciones para esta propuesta están cerradas." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solamente usuarios de confianza pueden votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No puedes votar en una propuesta sobre ti." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ya ha votado en esta propuesta." +#: html/tu.php msgid "Vote ID not valid." msgstr "El identificador del voto no es válido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" +#: html/tu.php msgid "Past Votes" msgstr "Últimos votos" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El registro de nuevas cuentas está desabilitado para tu dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdona los " -"inconvenientes" +msgstr "El registro de nuevas cuentas está desabilitado para tu dirección IP, probablemente debido a numerosos ataque de correo basura. Perdona los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta el identificador de usuario" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nombre de usuario no es válido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Debe tener entre %s y %s letras" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comenzar y acabar con una letra o número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Solamente puede contener un punto, guion bajo o guion." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" -"La página de inicio no es válida. Especifica la dirección HTTP(S) completa." +msgstr "La página de inicio no es válida. Especifica la dirección HTTP(S) completa." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave pública SSH no es válida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No se puede incrementar los permisos de la cuenta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "El huso horario no es admitido actualmente." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La dirección, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error tratando de crear la cuenta, %s%s%s" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, ha sido creada satisfactoriamente." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Se envió una clave de restablecimiento de contraseña a tu dirección de " -"correo electrónico." +msgstr "Se envió una clave de restablecimiento de contraseña a tu dirección de correo electrónico." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Pulsa en el enlace de acceso anterior para utilizar la cuenta." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No se realizaron cambios a la cuenta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, ha sido modificada satisfactoriamente" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El formulario de registro ha sido deshabilitado para tu dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdona los " -"inconvenientes" +msgstr "El formulario de registro ha sido deshabilitado para tu dirección IP, probablemente debido a numerosos ataque de correo basura. Perdona los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Tu contraseña ha sido reinicializada, si creaste una nueva cuenta, utiliza " -"el enlace inferior para confirmar el correo y así crear tu contraseña " -"inicial. En caso contrario, pide un reinicialización de contraseña en la " -"página para %sReinicializar las contraseñas%s." +msgstr "Tu contraseña ha sido reinicializada, si creaste una nueva cuenta, utiliza el enlace inferior para confirmar el correo y así crear tu contraseña inicial. En caso contrario, pide un reinicialización de contraseña en la página para %sReinicializar las contraseñas%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Contraseña o nombre de usuario erróneos." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Un error ocurrió intentando generar la sesión." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinación de dirección de correo y clave no válidos." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nada" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver información de la cuenta para %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Falta el identificador o el nombre del paquete base." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "No tienes permitido editar este comentario." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "El comentario no existe." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "El comentario no puede estar vacío." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Se ha añadido el comentario." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Debes autentificarte antes de editar la información del paquete." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Falta el identificador del comentario." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "No pueden fijarse más de 5 comentarios." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "No tienes permitido fijar este comentario." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "No tienes permitido desfijar este comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "El comentario ha sido fijado." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "El comentario ha sido desfijado." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Los detalles del paquete no se han podido encontrar." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Debes autentificarte antes de poder marcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No seleccionaste ningún paquete a marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"Los paquetes seleccionados no han sido marcados como desactualizados, " -"escribe un comentario." +msgstr "Los paquetes seleccionados no han sido marcados como desactualizados, escribe un comentario." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Los paquetes seleccionados han sido marcados como obsoletos." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Debes autentificarte antes de poder desmarcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No seleccionaste ningún paquete a desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Los paquetes seleccionados han sido desmarcados." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No posees los permisos para eliminar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No seleccionaste ningún paquete a eliminar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Los paquetes seleccionados se han eliminado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Debes autentificarte antes de poder adoptar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Debes autentificarte antes de poder abandonar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No haz seleccionado ningún paquete para ser adoptado." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No seleccionaste ningún paquete para ser abandonado." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Los paquetes seleccionados han sido adoptados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Los paquetes seleccionados han sido abandonados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Debes autentificarte antes de poder votar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Debes autentificarte antes de poder quitar votos a los paquetes" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No seleccionaste ningún paquete a votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Tus votos han sido eliminados de los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Tus votos han sido computados para los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No se pudo añadir a la lista de notificaciones." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Haz sido añadido a la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Haz sido eliminado de la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "No estás autorizado a restablecer este comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "El comentario se ha restablecido." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No estás autorizado para eliminar este comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "El comentario ha sido eliminado." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "El comentario ha sido editado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"No estás autorizado para editar las palabras clave de este paquete base." +msgstr "No estás autorizado para editar las palabras clave de este paquete base." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Las palabras clave del paquete base se han actualizado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "No se te permite administrar los coencargados de este paquete base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nombre de usuario no válido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Los coencargados del paquete base han sido actualizados." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles del paquete para" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "requiere %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Debes estar identificado para realizar solicitudes para el paquete." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nombre no válido: solamente se permiten letras minúsculas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campo de comentarios no debe estar vacío." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de solicitud no válida." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Solicitud agregada con éxito." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón no válida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Solamente los usuarios de confianza y desarrolladores pueden cerrar una " -"solicitud." +msgstr "Solamente los usuarios de confianza y desarrolladores pueden cerrar una solicitud." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Solicitud cerrada exitosamente" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Puedes usar este formulario para eliminar la cuenta de %s en AUR " -"permanentemente." +msgstr "Puedes usar este formulario para eliminar la cuenta de %s en AUR permanentemente." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVERTENCIA%s: Esta acción no puede deshacerse." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar borrado" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nombre de usuario" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de cuenta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuario" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desarrollador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Usuarios de confianza y desarrolladores" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Dirección de correo" +#: template/account_details.php msgid "hidden" msgstr "oculto" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nombre real" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Página principal" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alias de IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Huella digital PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estado" +#: template/account_details.php msgid "Inactive since" msgstr "Inactivo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" +#: template/account_details.php msgid "Registration date:" msgstr "Fecha de registración:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "desconocido" +#: template/account_details.php msgid "Last Login" msgstr "Última autentificación" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Ver los paquetes de este usuario" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Haz clic %saquí%s si deseas eliminar permanentemente esta cuenta." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Haz clic %saquí%s para ver los detalles del usuario." +#: template/account_edit_form.php msgid "required" msgstr "obligatorio" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" -"Tu nombre de usuario es el nombre que usarás para iniciar sesión. Es visible " -"para el público en general, incluso si tu cuenta no está activa." +msgstr "Tu nombre de usuario es el nombre que usarás para iniciar sesión. Es visible para el público en general, incluso si tu cuenta no está activa." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuario normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuario de confianza" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivo" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Asegúrate de escribir tu dirección de correo correctamente o terminarás " -"bloqueado." +msgstr "Asegúrate de escribir tu dirección de correo correctamente o terminarás bloqueado." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Ocultar dirreción de correo" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Reescribe la contraseña" +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "Timezone" msgstr "Huso horario" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La siguiente información únicamente es necesaria si deseas subir paquetes al " -"repositorio de usuarios de Arch." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La siguiente información únicamente es necesaria si deseas subir paquetes al repositorio de usuarios de Arch." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave pública SSH" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Gestión de notificaciones" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Notificar de actualizaciones de un paquete" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Notificar de cambios de propietario" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Crear" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Limpiar" +#: template/account_search_results.php msgid "No results matched your search criteria." -msgstr "" -"No se encontraron resultados que coincidan con tu criterio de búsqueda." +msgstr "No se encontraron resultados que coincidan con tu criterio de búsqueda." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar cuenta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendido" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Más" +#: template/account_search_results.php msgid "No more results to display." msgstr "No hay más resultados que mostrar." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Utiliza este formulario para agregar coencargados para %s%s%s (un nombre de " -"usuario por línea):" +msgstr "Utiliza este formulario para agregar coencargados para %s%s%s (un nombre de usuario por línea):" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuarios" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Guardar" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Marcar comentario como obsoleto: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s se ha marcado %s%s%s como obsoleto %s%s%s por la siguiente razón:" +msgstr "%s%s%s se ha marcado %s%s%s como obsoleto %s%s%s por la siguiente razón:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s no está marcado como obsoleto." +#: template/flag_comment.php msgid "Return to Details" msgstr "Regresar a detalles" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" -"Derechos de autor %s 2004 - %d, equipo desarrollador de la web del AUR." +msgstr "Derechos de autor %s 2004 - %d, equipo desarrollador de la web del AUR." +#: template/header.php msgid " My Account" msgstr "Mi cuenta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Acciones del paquete" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver cambios" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Descargar instantánea" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Buscar en la wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Marcado como obsoleto (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar paquete como obsoleto" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar paquete" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Eliminar voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar por este paquete" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Deshabilitar notificaciones" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Habilitar notificaciones" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "Hay %d solicitud pendiente" msgstr[1] "Hay %d solicitudes pendientes" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar paquete" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Dirección URL de clonado con Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "Solamente lectura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palabras claves" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Primer encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Encargado" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularidad" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Fecha de creación" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualización" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Editar comentario para: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Añadir un comentario" +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos los comentarios" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Comentarios fijados" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos comentarios" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s comentó en %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Comentario anónimo en %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "borrado el %s por %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "borrado el %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "editado el %s por %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "editado el %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Comentario restablecido" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Eliminar comentario" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Comentario fijado" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Comentario desfijado" +#: template/pkg_comments.php msgid "All comments" msgstr "Todos los comentarios" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Desarrollador principal" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita el sitio web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencias" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflictos" +#: template/pkg_details.php msgid "Provides" msgstr "Proveen" +#: template/pkg_details.php msgid "Replaces" msgstr "Remplazan" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencias" +#: template/pkg_details.php msgid "Required by" msgstr "Requerido por" +#: template/pkg_details.php msgid "Sources" msgstr "Fuentes" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Usa este formulario para cerrar la solicitud para el paquete base %s%s%s." +msgstr "Usa este formulario para cerrar la solicitud para el paquete base %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda " -"encarecidamente añadir un comentario al rechazar una solicitud." +msgstr "El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda encarecidamente añadir un comentario al rechazar una solicitud." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceptado" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rechazado" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Usa este formulario para presentar una solicitud para el paquete base %s%s%s " -"el cual incluye los siguientes paquetes:" +msgstr "Usa este formulario para presentar una solicitud para el paquete base %s%s%s el cual incluye los siguientes paquetes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de solicitud" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Borrado" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfandad" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Unir en" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Al enviar una solicitud de eliminación, le preguntas a un usuario de " -"confianza que elimine el paquete base. Este tipo de solicitud debe ser " -"utilizado para los duplicados, programas abandonados por el desarrollador " -"principal o encargado, así como programas ilegales e irreparablemente rotos." +msgstr "Al enviar una solicitud de eliminación, le preguntas a un usuario de confianza que elimine el paquete base. Este tipo de solicitud debe ser utilizado para los duplicados, programas abandonados por el desarrollador principal o encargado, así como programas ilegales e irreparablemente rotos." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Al enviar una solicitud de unión, le preguntas a un usuario de confianza que " -"elimine el paquete base y transfiera sus votos y comentarios a otro paquete " -"base. La unión de un paquete no afecta a los correspondientes repositorios " -"Git. Por tanto asegúrate de actualizar el historia Git del paquete de " -"destino tú mismo." +msgstr "Al enviar una solicitud de unión, le preguntas a un usuario de confianza que elimine el paquete base y transfiera sus votos y comentarios a otro paquete base. La unión de un paquete no afecta a los correspondientes repositorios Git. Por tanto asegúrate de actualizar el historia Git del paquete de destino tú mismo." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Al enviar una solicitud de orfandad, le preguntas a un usuario de confianza " -"que remueva la propiedad sobre el paquete base al encargado principal de " -"este. Por favor, haz esto solamente si el paquete necesita una acción de " -"mantenención, el encargado no presenta signos de actividad y ya intentaste " -"ponerte en contacto con él anteriormente." +msgstr "Al enviar una solicitud de orfandad, le preguntas a un usuario de confianza que remueva la propiedad sobre el paquete base al encargado principal de este. Por favor, haz esto solamente si el paquete necesita una acción de mantenención, el encargado no presenta signos de actividad y ya intentaste ponerte en contacto con él anteriormente." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Ninguna solicitud coincide con tu criterio de búsqueda." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Se encontró %d solicitud para el paquete." msgstr[1] "Se encontraron %d solicitudes para el paquete." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Solicitado por" +#: template/pkgreq_results.php msgid "Date" msgstr "Fecha" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d día restante" msgstr[1] "~%d días restantes" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Aprox. %d hora restante" msgstr[1] "Aprox. %d horas restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 hora restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceptar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloqueada" +#: template/pkgreq_results.php msgid "Close" msgstr "Cerrar" +#: template/pkgreq_results.php msgid "Pending" msgstr "Pendiente" +#: template/pkgreq_results.php msgid "Closed" msgstr "Cerrada" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nombre, descripción" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Solamente nombre" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nombre exacto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exacto" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Coencargado" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Encargado y coencargado" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No marcados" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nombre" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Última modificación" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" +#: template/pkg_search_form.php msgid "Search by" msgstr "Buscar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Orden" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Huérfanos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Error al recuperar la lista de paquetes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ningún paquete coincide con tu criterio de búsqueda." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquete fue encontrado." msgstr[1] "%d paquetes fueron encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versión" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"La popularidad se calcula como la suma de todos los votos y cada uno " -"ponderado con un factor de %.2f por día desde la creación del paquete." +msgstr "La popularidad se calcula como la suma de todos los votos y cada uno ponderado con un factor de %.2f por día desde la creación del paquete." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "huérfano" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acciones" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar como obsoleto" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar paquetes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar paquetes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Eliminar paquetes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Cualquier tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Buscar" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes huérfanos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes añadidos en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes actualizados en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes actualizados el último año" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes que no han sido nunca actualizados" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios registrados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios de confianza" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizaciones recientes" +#: template/stats/updates_table.php msgid "more" msgstr "más" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mis estadísticas" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalles de la propuesta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Aún se puede votar." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Subido: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Abstenerse" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participación" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Último voto del usuario de confianza" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No se han encontrado resultados." +#: template/tu_list.php msgid "Start" msgstr "Inicio" +#: template/tu_list.php msgid "Back" msgstr "Atrás" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/es_419.po b/po/es_419.po index 23953197..d6fa54ea 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Angel Velasquez , 2011 # juantascon , 2011 @@ -14,1637 +14,2128 @@ # Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2016 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-29 14:11+0000\n" -"Last-Translator: Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] \n" -"Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/" -"aur/language/es_419/)\n" -"Language: es_419\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/aurweb/language/es_419/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: es_419\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página no encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Disculpe, la página que solicitó no existe." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" -"Las direcciones de clonado de Git no deberían ser habiertas en un navegador." +msgstr "Las direcciones de clonado de Git no deberían ser habiertas en un navegador." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Para clonar el repositorio Git de %s, ejecute %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Haga clic %saquí%s para regresar a la página de detalles de %s." +#: html/503.php msgid "Service Unavailable" msgstr "Servicio no disponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"¡No se asustes! El sitio está desactivado por mantenimiento. Pronto " -"volveremos." +msgstr "¡No se asustes! El sitio está desactivado por mantenimiento. Pronto volveremos." +#: html/account.php msgid "Account" msgstr "Cuenta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Cuentas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "No está autorizado a acceder a esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "No se pudo obtener la información del usuario especificado." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "No tiene permisos para editar esta cuenta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Use este formulario para buscar cuentas existentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Debe autentificarse para ver la información del usuario." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Añadir propuesta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Elemento inválido para la acción del usuario." +#: html/addvote.php msgid "Username does not exist." msgstr "El nombre de usuario no existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ya tiene una propuesta activa." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo no válido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La propuesta no puede estar vacía." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nueva propuesta enviada." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Envíe una propuesta a la cual votar." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/Usuario de confianza (UC)" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vacío si no aplica)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Agregar a un nuevo Usuario de Confianza" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remover a un Usuario de Confianza" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remover a un Usuario de Confianza (no declarado inactivo)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Enmienda a las Bylaws (Reglas de los TU)" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propuesta" +#: html/addvote.php msgid "Submit" msgstr "Subir" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Administrar coencargados" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Editar comentario" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Tablero" +#: html/home.php template/header.php msgid "Home" msgstr "Inicio" +#: html/home.php msgid "My Flagged Packages" msgstr "Mis paquetes marcados" +#: html/home.php msgid "My Requests" msgstr "Mis peticiones" +#: html/home.php msgid "My Packages" msgstr "Mis paquetes" +#: html/home.php msgid "Search for packages I maintain" msgstr "Buscar paquetes que soy encargado" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Paquetes que soy coencargado" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Buscar paquetes que soy coencargado" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"¡Bienvenido al repositorio de usuarios de Arch! Lea la %sGuía del usuario " -"del AUR%s y la %sGuía del usuario de Confianza del AUR%s para mayor " -"información." +msgstr "¡Bienvenido al repositorio de usuarios de Arch! Lea la %sGuía del usuario del AUR%s y la %sGuía del usuario de Confianza del AUR%s para mayor información." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de " -"empaquetado de Arch%s de otra forma serán borrados." +msgstr "Los PKGBUILD contribuidos %sdeben%s ser compatibles con el %sEstándar de empaquetado de Arch%s de otra forma serán borrados." +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "¡Recuerde votar sus paquetes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Algunos paquetes pueden estar disponibles de forma binaria en [community]." +msgstr "Algunos paquetes pueden estar disponibles de forma binaria en [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ACLARATORIA" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Los paquetes en el AUR son producidos por los usuarios. Cualquier uso de " -"ellos o sus archivos es a su propio riesgo." +msgstr "Los paquetes en el AUR son producidos por los usuarios. Cualquier uso de ellos o sus archivos es a su propio riesgo." +#: html/home.php msgid "Learn more..." msgstr "Aprenda más..." +#: html/home.php msgid "Support" msgstr "Soporte" +#: html/home.php msgid "Package Requests" msgstr "Peticiones para los paquetes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Existen tres tipos de peticiones que pueden presentarse en el recuadro " -"%sAcciones del paquete%s en la página de detalles del paquete:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Existen tres tipos de peticiones que pueden presentarse en el recuadro %sAcciones del paquete%s en la página de detalles del paquete:" +#: html/home.php msgid "Orphan Request" msgstr "Petición de Orfandad" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Pedir la orfandad de un paquete, por ejemplo, cuando el encargado está " -"inactivo y el paquete fue marcado como desactualizado por un largo tiempo." +msgstr "Pedir la orfandad de un paquete, por ejemplo, cuando el encargado está inactivo y el paquete fue marcado como desactualizado por un largo tiempo." +#: html/home.php msgid "Deletion Request" msgstr "Petición de Borrado" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Pedir que un paquete sea borrado del Repositorio Usuarios de Arch. Por " -"favor, no use esta opción si un paquete está roto y se puede arreglar " -"fácilmente. En cambio, contacte con el encargado del paquete y presentar " -"solicitud orfandad si es necesario." +msgstr "Pedir que un paquete sea borrado del Repositorio Usuarios de Arch. Por favor, no use esta opción si un paquete está roto y se puede arreglar fácilmente. En cambio, contacte con el encargado del paquete y presentar solicitud orfandad si es necesario." +#: html/home.php msgid "Merge Request" msgstr "Petición de Fusión" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Pedir que se fusione un paquete en otro. Puede usarla cuando un paquete " -"tiene que ser cambiado de nombre o sustituido por un paquete dividido." +msgstr "Pedir que se fusione un paquete en otro. Puede usarla cuando un paquete tiene que ser cambiado de nombre o sustituido por un paquete dividido." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Si quiere discutir una petición, puede usar la lista de correo %saur-" -"peticiones%s. Sin embargo, por favor no utilice esa lista para presentar " -"solicitudes." +msgstr "Si quiere discutir una petición, puede usar la lista de correo %saur-peticiones%s. Sin embargo, por favor no utilice esa lista para presentar solicitudes." +#: html/home.php msgid "Submitting Packages" msgstr "Subir paquetes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Ahora se usa Git sobre SSH para subir paquetes al AUR. Véase la sección " -"%sSubir paquetes%s de la wiki del Repositorio de Usuarios de Arch para más " -"información." +msgstr "Ahora se usa Git sobre SSH para subir paquetes al AUR. Véase la sección %sSubir paquetes%s de la wiki del Repositorio de Usuarios de Arch para más información." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Las siguientes huellas SSH están en uso para el AUR." +#: html/home.php msgid "Discussion" msgstr "Debate" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"La discusión general acerca del Repositorio de Usuarios de Arch (AUR) y la " -"estructura de Usuarios de Confianza se realiza en la lista de correos %saur-" -"general%s. Para discusiones relacionadas con el desarrollo de la interfaz " -"web del AUR, utilice la lista de correo %saur-dev%s." +msgstr "La discusión general acerca del Repositorio de Usuarios de Arch (AUR) y la estructura de Usuarios de Confianza se realiza en la lista de correos %saur-general%s. Para discusiones relacionadas con el desarrollo de la interfaz web del AUR, utilice la lista de correo %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Informe de errores" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Si encuentra un error en la interfaz web del AUR, llene un informe de fallo " -"en nuestro %s«bug tracker»%s. Use este para reportar %súnicamente%s errores " -"de la interfaz web del AUR. Para reportar errores de empaquetado debe " -"contactar con el encargado o dejar un comentario en la página respectiva del " -"paquete." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Si encuentra un error en la interfaz web del AUR, llene un informe de fallo en nuestro %s«bug tracker»%s. Use este para reportar %súnicamente%s errores de la interfaz web del AUR. Para reportar errores de empaquetado debe contactar con el encargado o dejar un comentario en la página respectiva del paquete." +#: html/home.php msgid "Package Search" msgstr "Buscar paquetes" +#: html/index.php msgid "Adopt" msgstr "Adoptar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Retirar voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Quitar notificación" +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Autentificarse" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificado como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Salir" +#: html/login.php msgid "Enter login credentials" msgstr "Introduce las credenciales de autentificación" +#: html/login.php msgid "User name or email address" msgstr "Nombre de usuario y dirección de correo" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" +#: html/login.php msgid "Remember me" msgstr "Recordarme" +#: html/login.php msgid "Forgot Password" msgstr "Olvidó su cotraseña" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"La autentificación por HTTP está deshabilitada. %scambie a HTTPS%s si desea " -"autentificarse" +msgstr "La autentificación por HTTP está deshabilitada. %scambie a HTTPS%s si desea autentificarse" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criterio de búsqueda" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquetes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "No se pudieron recuperar los detalles del paquete." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Falta un campo obligatorio." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Los campos de la contraseña no coinciden." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Su contraseña debe tener como mínimo %s letras." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Dirección de correo no válida." +#: html/passreset.php msgid "Password Reset" msgstr "Reiniciar la contraseña" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Compruebe su correo para ver el enlace de confirmación." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Su contraseña fue reiniciada con éxito." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme su dirección de correo:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Ingrese su nueva contraseña:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme su nueva contraseña:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje " -"a la %slista de correo aur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje a la %slista de correo aur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduzca su dirección de correo:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Paquetes base" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Los paquetes seleccionados no fueron abandonados, marque la casilla de " -"confirmación." +msgstr "Los paquetes seleccionados no fueron abandonados, marque la casilla de confirmación." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"No se puede encontrar el paquete para fusionar sus votos y comentarios." +msgstr "No se puede encontrar el paquete para fusionar sus votos y comentarios." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "No se puede fusionar un paquete base consigo mismo." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Los paquetes seleccionados no se borraron, compruebe la casilla de " -"confirmación." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Los paquetes seleccionados no se borraron, compruebe la casilla de confirmación." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminación de paquetes" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Borrar paquete" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Use este formulario para borrar el paquete base %s%s%s y los siguientes " -"paquetes en el AUR:" +msgstr "Use este formulario para borrar el paquete base %s%s%s y los siguientes paquetes en el AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "El borrado de un paquete es permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Selecciona la casilla para confirmar la acción." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirme el borrado del paquete" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Borrar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Solo Usuarios de Confianza y Desarrolladores pueden borrar paquetes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar paquete" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Use este formulario para abandonar el paquete base %s %s %s que incluye los " -"siguientes paquetes:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Use este formulario para abandonar el paquete base %s %s %s que incluye los siguientes paquetes:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Al seleccionar la casilla de verificación, confirma que desea abandonar el " -"paquete y transferir su propiedad a %s %s %s." +msgstr "Al seleccionar la casilla de verificación, confirma que desea abandonar el paquete y transferir su propiedad a %s %s %s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Al seleccionar la casilla de verificación, confirma que desea abandonar el " -"paquete." +msgstr "Al seleccionar la casilla de verificación, confirma que desea abandonar el paquete." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirme para abandonar el paquete" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Solo Usuarios de Confianza y Desarrolladores pueden forzar el abandono de " -"paquetes." +msgstr "Solo Usuarios de Confianza y Desarrolladores pueden forzar el abandono de paquetes." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Marcar comentario" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Marcado como desactualizado" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Use este formulario para marcar el paquete base %s%s%s y los siguientes " -"paquetes en el AUR como desactualizados:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Use este formulario para marcar el paquete base %s%s%s y los siguientes paquetes en el AUR como desactualizados:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"%sNo%s use este formulario para reportar fallos. Use los comentarios del " -"paquete en su lugar." +msgstr "%sNo%s use este formulario para reportar fallos. Use los comentarios del paquete en su lugar." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Introduzca los detalles del porqué el paquete fue marcado como " -"desactualizado, peferentemente incluyendo un enlace al anuncio de la nueva " -"versión o al empaquetado." +msgstr "Introduzca los detalles del porqué el paquete fue marcado como desactualizado, peferentemente incluyendo un enlace al anuncio de la nueva versión o al empaquetado." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Comentarios" +#: html/pkgflag.php msgid "Flag" msgstr "Marcar" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Solo los usuario registrados pueden marcar como desactualizado." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusión de paquetes" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Fusionar paquete" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Este formulario es para fusionar el paquete base %s%s%s en otro paquete." +msgstr "Este formulario es para fusionar el paquete base %s%s%s en otro paquete." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Los siguientes paquetes serán borrados:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Una vez fusionado el paquete este no se puede separar." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduzca el nombre del paquete que desea fusionar." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionar dentro:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmar fusión de paquetes" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusión" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo Usuarios de Confianza y Desarrolladores pueden fusionar paquetes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Enviar petición" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Cerrar Petición" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Petición" +#: html/register.php template/header.php msgid "Register" msgstr "Registro" +#: html/register.php msgid "Use this form to create an account." msgstr "Use este formulario para crear una cuenta." +#: html/tos.php msgid "Terms of Service" msgstr "Terminos y condiciones" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" -"Los siguientes documentos han sido actualizados. Por favor revíselos " -"cuidadosamente:" +msgstr "Los siguientes documentos han sido actualizados. Por favor revíselos cuidadosamente:" +#: html/tos.php #, php-format msgid "revision %d" msgstr "Revisión %d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "Acepto las Terminos y condiciones anteriores." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuario de Confianza" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "No se han podido recuperar los detalles de la propuesta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Las votaciones para esta propuesta están cerradas." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solo Usuarios de Confianza pueden votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "No puede votar en una propuesta sobre usted." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ya ha votado en esta propuesta." +#: html/tu.php msgid "Vote ID not valid." msgstr "El identificador del voto no es válido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos actuales" +#: html/tu.php msgid "Past Votes" msgstr "Últimos votos" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El registro de nuevas cuentas está desabilitado para su dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdone los " -"inconvenientes" +msgstr "El registro de nuevas cuentas está desabilitado para su dirección IP, probablemente debido a numerosos ataque de correo basura. Perdone los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Falta el identificador de usuario" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "El nombre de usuario no es válido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Debe tener entre %s y %s letras" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Comenzar y acabar con una letra o número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Solo puede contener un punto, guion bajo o guion." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" -"La página de inicio no es válida. Especifique la URL en HTTP(S) completa." +msgstr "La página de inicio no es válida. Especifique la URL en HTTP(S) completa." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La huella digital PGP no es válida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clave pública SSH no es válida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "No se puede incrementar los permisos de la cuenta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "El idioma no está soportado actualmente." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "La zona horaria no se admite actualmente." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "El nombre de usuario, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "La dirección, %s%s%s, ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Error tratando de crear la cuenta, %s%s%s" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "La cuenta, %s%s%s, fue creada satisfactoriamente." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Una llave para reiniciar su contraseña fue enviada a su correo." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Haz clic en el enlace de autentificación para usar su cuenta." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "No se realizaron cambios a la cuenta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "La cuenta, %s%s%s, fue modificada satisfactoriamente" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"El formulario de registro ha sido deshabilitado para su dirección IP, " -"probablemente debido a numerosos ataque de correo basura. Perdone los " -"inconvenientes" +msgstr "El formulario de registro ha sido deshabilitado para su dirección IP, probablemente debido a numerosos ataque de correo basura. Perdone los inconvenientes" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cuenta suspendida" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Su contraseña fue reiniciada, si creó una nueva cuenta, use el enlace " -"inferior para confirmar el correo y así crear su contraseña inicial. En caso " -"contrario, pida un reinicio de contraseña en la página para %sreiniciar las " -"contraseñas%s." +msgstr "Su contraseña fue reiniciada, si creó una nueva cuenta, use el enlace inferior para confirmar el correo y así crear su contraseña inicial. En caso contrario, pida un reinicio de contraseña en la página para %sreiniciar las contraseñas%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Contraseña o nombre de usuario erróneos." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Un error ocurrió intentando generar la sesión." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinación de dirección de correo y clave no válida." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nada" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver información de la cuenta para %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Falta el identificador o nombre del paquete base." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "No tiene permitido editar este comentario." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "El comentario no existe." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "El comentario no puede estar vacío." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "El comentario fue añadido." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Debe autentificarse antes de editar la información del paquete." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Falta el identificador del comentario." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "No pueden ser anclar más de 5 comentarios." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "No tiene permitido anclar este comentario." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "No tiene permitido desanclar este comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "El comentario fue anclado." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "El comentario fue desanclado." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Error al recuperar los detalles del paquete." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Los detalles del paquete no se pudieron encontrar." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Debe autentificarse antes de poder marcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "No seleccionó ningún paquete para marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"Los paquetes seleccionados no han sido marcados como desactualizados, " -"escriba un comentario." +msgstr "Los paquetes seleccionados no han sido marcados como desactualizados, escriba un comentario." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Los paquetes seleccionados han sido marcados como desactualizados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Debe autentificarse antes de poder desmarcar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "No seleccionó ningún paquete para desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Los paquetes seleccionados han sido desmarcados." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "No posee los permisos para borrar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "No seleccionó ningún paquete para borrar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Los paquetes seleccionados se han borrado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Debe autentificarse antes de poder adoptar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Debe autentificarse antes de poder abandonar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "No seleccionó ningún paquete para adoptar." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "No seleccionó ningún paquete para ser abandonado." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Los paquetes seleccionados han sido adoptados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Los paquetes seleccionados han sido abandonados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Debe autentificarse antes de poder votar paquetes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Debe autentificarse antes de poder quitar votos a los paquetes" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "No seleccionó ningún paquete para votarlo." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Sus votos han sido eliminados de los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Sus votos se añadieron a los paquetes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "No se pudo añadir a la lista de notificaciones." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Ha sido añadido a la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Ha sido eliminado de la lista de notificaciones de comentarios de %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "No está autorizado a restablecer este comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "El comentario fue restablecido." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "No está autorizado a borrar este comentario." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "El comentario fue borrado." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "El comentario fue editado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"No está autorizado para editar las palabras clave de este paquete base." +msgstr "No está autorizado para editar las palabras clave de este paquete base." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Las palabras clave del paquete base actualizaron ." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "No tiene permitido administrar los coencargados de este paquete base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nombre de usuario no válido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Los coencargados del paquete base fueron actualizados." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalles del paquete para" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "requiere %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Debe estar identificado para realizar peticiones para el paquete." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nombre no válido: solo se permiten letras minúsculas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "El campo de comentarios no debe estar vacío." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de petición no válida." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Petición agregada con éxito." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razón no válida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Solo Usuarios de Confianza y Desarrolladores pueden cerrar una petición." +msgstr "Solo Usuarios de Confianza y Desarrolladores pueden cerrar una petición." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Petición cerrada exitosamente" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Puede usar este formulario para borrar la cuenta de %s en AUR " -"permanentemente." +msgstr "Puede usar este formulario para borrar la cuenta de %s en AUR permanentemente." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVERTENCIA%s: Esta acción no puede deshacerse." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar borrado" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nombre de usuario" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de cuenta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuario" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desarrollador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Usuarios de Confianza y desarrolladores" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Dirección de correo" +#: template/account_details.php msgid "hidden" msgstr "oculto" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nombre real" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Página principal" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Alias de IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Huella digital PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estado" +#: template/account_details.php msgid "Inactive since" msgstr "Inactivo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" +#: template/account_details.php msgid "Registration date:" msgstr "Fecha de registración:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "desconocido" +#: template/account_details.php msgid "Last Login" msgstr "Última autentificación" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Ver los paquetes de este usuario" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Haga clic %saquí%s si desea borrar permanentemente esa cuenta." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Haga clic %saquí%s para ver los detalles del usuario." +#: template/account_edit_form.php msgid "required" msgstr "obligatorio" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" -"Su nombre de usuario es el nombre que usará para iniciar sesión. Es visible " -"al público en general, incluso si su cuenta está inactiva." +msgstr "Su nombre de usuario es el nombre que usará para iniciar sesión. Es visible al público en general, incluso si su cuenta está inactiva." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuario normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Usuario de Confianza" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cuenta suspendida" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactivo" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Asegúrese de escribir su correo correctamente o de lo contrario quedará " -"bloqueado." +msgstr "Asegúrese de escribir su correo correctamente o de lo contrario quedará bloqueado." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Ocultar dirreción de correo" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Reescriba la contraseña" +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "Timezone" msgstr "Zona horaria" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La siguiente información es necesaria únicamente si quiere subir paquetes al " -"Repositorio de Usuarios de Arch." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La siguiente información es necesaria únicamente si quiere subir paquetes al Repositorio de Usuarios de Arch." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clave pública SSH" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Configuración de notificaciones" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notificación de nuevos comentarios" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Notificar sobre actualizaciones de un paquete" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Notificarme de cambios de propietario" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Crear" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Limpiar" +#: template/account_search_results.php msgid "No results matched your search criteria." -msgstr "" -"No se encontraron resultados que coincidan con su criterio de búsqueda." +msgstr "No se encontraron resultados que coincidan con su criterio de búsqueda." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar cuenta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendido" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Más" +#: template/account_search_results.php msgid "No more results to display." msgstr "No hay más resultados que mostrar." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Use este formulario para agregar coencargados para %s%s%s (un nombre de " -"usuario por línea):" +msgstr "Use este formulario para agregar coencargados para %s%s%s (un nombre de usuario por línea):" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuarios" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Guardar" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Marcar comentario como desactualizado: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s fue marcado %s%s%s como desactualizado %s%s%s por la siguiente razón:" +msgstr "%s%s%s fue marcado %s%s%s como desactualizado %s%s%s por la siguiente razón:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s no está marcado como desactualizado." +#: template/flag_comment.php msgid "Return to Details" msgstr "Regresar a detalles" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" -"Derechos de autor %s 2004 - %d, equipo de desarrollo de la web del AUR." +msgstr "Derechos de autor %s 2004 - %d, equipo de desarrollo de la web del AUR." +#: template/header.php msgid " My Account" msgstr "Mi cuenta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Acciones del paquete" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver cambios" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Descargar instantánea" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Buscar en la wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Marcado como desactualizado (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar paquete como desactualizado" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar paquete" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Eliminar voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar por este paquete" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Deshabilitar notificaciones" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Habilitar notificaciones" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Administrar coencargados" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "Hay %d petición pendiente" msgstr[1] "Hay %d peticiones pendientes" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptar paquete" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalles del paquete base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL de clonado con Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "Solo lectura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palabras claves" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Primer encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Encargado" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último encargado" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularidad" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Fecha de creación" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última actualización" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Editar commentario para: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Agregar un comentario" +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos los comentarios" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Comentarios anclados" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos comentarios" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s comentó en %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Comentario anónimo en %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "borrado el %s por %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "borrado el %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "editado el %s por %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "editado el %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Comentario restablecido" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Borrar comentario" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Comentario anclado" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Comentario desanclado" +#: template/pkg_comments.php msgid "All comments" msgstr "Todos los comentarios" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquete base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descripción" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Desarrollador principal" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita el sitio web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencias" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflictos" +#: template/pkg_details.php msgid "Provides" msgstr "Proveen" +#: template/pkg_details.php msgid "Replaces" msgstr "Remplazan" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependencias" +#: template/pkg_details.php msgid "Required by" msgstr "Requerido por" +#: template/pkg_details.php msgid "Sources" msgstr "Fuentes" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Use este formulario para cerrar la petición para el paquete base %s%s%s." +msgstr "Use este formulario para cerrar la petición para el paquete base %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda " -"encarecidamente añadir un comentario al rechazar una petición." +msgstr "El campo de comentarios se puede dejar vacío. Sin embargo, se recomienda encarecidamente añadir un comentario al rechazar una petición." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razón" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceptado" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rechazado" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Use este formulario para presentar una petición para el paquete base %s%s%s " -"el cual incluye los siguientes paquetes:" +msgstr "Use este formulario para presentar una petición para el paquete base %s%s%s el cual incluye los siguientes paquetes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de petición" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Borrado" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfandad" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fusionar en" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Al enviar una Petición de Borrado, le preguntará a un Usuario de Confianza " -"que elimine dicho paquete base. Este tipo de peticiones debe ser utilizada " -"para duplicados, programas abandonados por el desarrollador principal o " -"encargado, así como programas ilegales e irreparablemente rotos." +msgstr "Al enviar una Petición de Borrado, le preguntará a un Usuario de Confianza que elimine dicho paquete base. Este tipo de peticiones debe ser utilizada para duplicados, programas abandonados por el desarrollador principal o encargado, así como programas ilegales e irreparablemente rotos." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Al enviar una Petición de Fusión, le preguntará a un Usuario de Confianza " -"que borre el paquete base y transfiera sus votos y comentarios a otro " -"paquete base. La fusión de un paquete no afecta a los correspondientes " -"repositorios Git. Por lo tanto asegúrese de actualizar el historia Git del " -"paquete de destino uste mismo." +msgstr "Al enviar una Petición de Fusión, le preguntará a un Usuario de Confianza que borre el paquete base y transfiera sus votos y comentarios a otro paquete base. La fusión de un paquete no afecta a los correspondientes repositorios Git. Por lo tanto asegúrese de actualizar el historia Git del paquete de destino uste mismo." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Al enviar una Petición de Orfandad, le preguntarás a un Usuario de Confianza " -"que le quite la propiedad sobre el paquete base al encargado principal de " -"este. Por favor, haga esto solo si el paquete necesita acciones de " -"mantenención para funcionar, el encargado no presenta da de actividad y ya " -"intentó ponerse en contacto con él anteriormente." +msgstr "Al enviar una Petición de Orfandad, le preguntarás a un Usuario de Confianza que le quite la propiedad sobre el paquete base al encargado principal de este. Por favor, haga esto solo si el paquete necesita acciones de mantenención para funcionar, el encargado no presenta da de actividad y ya intentó ponerse en contacto con él anteriormente." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Ninguna peticiones coincide con su criterio de búsqueda." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Se encontró %d solicitud para el paquete." msgstr[1] "Se encontraron %d solicitudes para el paquete." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquete" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Solicitado por" +#: template/pkgreq_results.php msgid "Date" msgstr "Fecha" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d día restante" msgstr[1] "~%d días restantes" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Aprox. %d hora restante" msgstr[1] "Aprox. %d horas restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 hora restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceptar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloqueada" +#: template/pkgreq_results.php msgid "Close" msgstr "Cerrar" +#: template/pkgreq_results.php msgid "Pending" msgstr "Pendiente" +#: template/pkgreq_results.php msgid "Closed" msgstr "Cerrada" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nombre, descripción" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Solo nombre" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nombre exacto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquete base exacto" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Coencargado" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Encargado y coencargado" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "No marcados" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nombre" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Última modificación" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzca el criterio de búsqueda" +#: template/pkg_search_form.php msgid "Search by" msgstr "Buscar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Orden" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Huérfanos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Error al recuperar la lista de paquetes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ningún paquete coincide con su criterio de búsqueda." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquete fue encontrado." msgstr[1] "%d paquetes fueron encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versión" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"La Popularidad es calculada como la suma de todos los votos ponderados con " -"un factor de %.2f por día desde la creación del paquete." +msgstr "La Popularidad es calculada como la suma de todos los votos ponderados con un factor de %.2f por día desde la creación del paquete." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sí" +#: template/pkg_search_results.php msgid "orphan" msgstr "huérfano" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acciones" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar como actualizado" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar paquetes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar paquetes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Borrar paquetes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Cualquier tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Buscar" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estadísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquetes huérfanos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquetes nuevos en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquetes actualizados en los últimos 7 días" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquetes actualizados el último año" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquetes que nunca se han actualizado" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuarios registrados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuarios de Confianza" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizaciones recientes" +#: template/stats/updates_table.php msgid "more" msgstr "más" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mis estadísticas" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalles de la propuesta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Aún se puede votar." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Subido: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Abstenerse" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participación" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Último voto del Usuario de Confianza" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "No se han encontrado resultados." +#: template/tu_list.php msgid "Start" msgstr "Inicio" +#: template/tu_list.php msgid "Back" msgstr "Atrás" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/fi.po b/po/fi.po index bd77b538..fde1a974 100644 --- a/po/fi.po +++ b/po/fi.po @@ -1,1334 +1,1686 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Elias Autio, 2016 # Jesse Jaara , 2011-2012,2015 +# Sami Korkalainen, 2018 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Finnish (http://www.transifex.com/lfleischer/aur/language/" -"fi/)\n" -"Language: fi\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 13:04+0000\n" +"Last-Translator: Sami Korkalainen\n" +"Language-Team: Finnish (http://www.transifex.com/lfleischer/aurweb/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: fi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Sivua ei löydy." +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Valitettavasti hakemaasi sivua ei ole olemassa." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "Git-kloonausosoitteita ei ole tarkoitettu avattavaksi selaimella." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Kloonataksesi Git-varaston %s, suorita %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Klikkaa %stästä%s palataksesi %s tietosivulle." +#: html/503.php msgid "Service Unavailable" msgstr "Palvelu ei saatavilla." +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "Älä panikoi! Sivu on poissa käytöstä huollon vuoksi. Palaamme pian." +#: html/account.php msgid "Account" msgstr "Käyttäjätili" +#: html/account.php template/header.php msgid "Accounts" msgstr "Käyttäjätilit" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Sinulla ei ole oikeuksia tämän osion käyttämiseen." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Valitun käyttäjän tietoja ei voitu noutaa." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Sinulla ei ole oikeuksia tämän käyttäjätlin muokkaamiseen." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Etsi käyttäjätilejä." +#: html/account.php msgid "You must log in to view user information." msgstr "Sinun pitää kirjautua sisään tarkastellaksesi käyttäjien tietoja." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Lisää ehdotus" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "Käyttäjänimeä ei ole olemassa." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "" +#: html/addvote.php msgid "Invalid type." -msgstr "" +msgstr "Virheellinen tyyppi." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Ehdotus ei voi olla tyhjä." +#: html/addvote.php msgid "New proposal submitted." msgstr "Uusi ehdotus lisätty." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Lisää ehdotus äänestettäväksi." +#: html/addvote.php msgid "Applicant/TU" msgstr "Ehdokas/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tyhjä jos ei tiettyä henkilöä)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tyyppi" +#: html/addvote.php msgid "Addition of a TU" -msgstr "" +msgstr "Luotetun käyttäjän (TU) lisääminen" +#: html/addvote.php msgid "Removal of a TU" -msgstr "" +msgstr "Luotetun käyttäjän (TU) poisto" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Ehdotus" +#: html/addvote.php msgid "Submit" msgstr "Lisää" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Muokkaa kommenttia" +#: html/home.php template/header.php msgid "Dashboard" -msgstr "" +msgstr "Kojelauta" +#: html/home.php template/header.php msgid "Home" msgstr "Etusivu" +#: html/home.php msgid "My Flagged Packages" -msgstr "" +msgstr "Pakettini, jotka on merkitty" +#: html/home.php msgid "My Requests" -msgstr "" +msgstr "Pyyntöni" +#: html/home.php msgid "My Packages" msgstr "Omat paketit" +#: html/home.php msgid "Search for packages I maintain" -msgstr "" +msgstr "Hae ylläpitämiäni paketteja" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Tervetuloa AURiin! Luethan %sAURin käyttäjä ohjeen%s sekä %sTU-käyttäjän " -"oppaan%s, kun tarvitset lisätietoa." +msgstr "Tervetuloa AURiin! Luethan %sAURin käyttäjä ohjeen%s sekä %sTU-käyttäjän oppaan%s, kun tarvitset lisätietoa." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Lisättyjen PKGBUILD tiedostojen %stulee%s olla %sArchin pakettistandardien%s " -"mukaisia, muuten ne saatetaan poistaa!" +msgstr "Lisättyjen PKGBUILD tiedostojen %stulee%s olla %sArchin pakettistandardien%s mukaisia, muuten ne saatetaan poistaa!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Muista äänestää suosikki pakettejasi!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Jotkin paketit saattavat olla tarjolla valmiina paketteina [community] " -"varastossa. :)" +msgstr "Jotkin paketit saattavat olla tarjolla valmiina paketteina [community] varastossa. :)" +#: html/home.php msgid "DISCLAIMER" msgstr "Vastuuvapauslauseke" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"AUR-paketit ovat käyttäjien luomia eivätkä ole virallisesti tuettuja. Näiden " -"käyttäminen on omalla vastuullasi." +msgstr "AUR-paketit ovat käyttäjien luomia eivätkä ole virallisesti tuettuja. Näiden käyttäminen on omalla vastuullasi." +#: html/home.php msgid "Learn more..." msgstr "Selvitä lisää..." +#: html/home.php msgid "Support" msgstr "Tuki" +#: html/home.php msgid "Package Requests" msgstr "Pakettienhallintapyydöt" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Pakettien sivuilta löytyvän %spakettitoiminnot%s -laatikon kautta voi " -"lähettää TU-käyttäjille kolme erilaista pakettienhallintapyyntöä." +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Pakettien sivuilta löytyvän %spakettitoiminnot%s -laatikon kautta voi lähettää TU-käyttäjille kolme erilaista pakettienhallintapyyntöä." +#: html/home.php msgid "Orphan Request" msgstr "Hylkäämispyyntö" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Hallintapyyntö paketin poistamiseksi sen nykyiseltä ylläpitäjältä, esimerksi " -"jos ylläpitäjä ei vastaa kommentteihin eikä sähköpostiin ja paketti on " -"merkitty vanhentuneeksi jo kauan sitten." +msgstr "Hallintapyyntö paketin poistamiseksi sen nykyiseltä ylläpitäjältä, esimerksi jos ylläpitäjä ei vastaa kommentteihin eikä sähköpostiin ja paketti on merkitty vanhentuneeksi jo kauan sitten." +#: html/home.php msgid "Deletion Request" msgstr "Poistopyyntö" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Hallintapyyntö paketin poistamiseksi AUR:ista. Jos paketti on jollain tapaa " -"rikki tai huono, mutta helposti korjattavissa, tulisi ensisijaisesti olla " -"yhteydessä paketin ylläpitäjään ja viimekädessä pistää paketin " -"hylkäämispyyntö menemään." +msgstr "Hallintapyyntö paketin poistamiseksi AUR:ista. Jos paketti on jollain tapaa rikki tai huono, mutta helposti korjattavissa, tulisi ensisijaisesti olla yhteydessä paketin ylläpitäjään ja viimekädessä pistää paketin hylkäämispyyntö menemään." +#: html/home.php msgid "Merge Request" msgstr "Yhdistämispyyntö" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Hallintapyyntö kahden eri paketin yhdistämiseksi. Voidaan käyttää muun " -"muassa silloin kun jokin paketti on nimettyuudelleen tai korvattu " -"monipaketilla (split package)." +msgstr "Hallintapyyntö kahden eri paketin yhdistämiseksi. Voidaan käyttää muun muassa silloin kun jokin paketti on nimettyuudelleen tai korvattu monipaketilla (split package)." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Pakettienhallintapyynnöistä voi keskustella niin yleisellä- kuin myös " -"tiettyyn pyyntöön littyvällä tasolla %saur-requests%s -postituslistalla. Älä " -"kuitenkaan lähetä hallintapyyntöjä postituslistalle." +msgstr "Pakettienhallintapyynnöistä voi keskustella niin yleisellä- kuin myös tiettyyn pyyntöön littyvällä tasolla %saur-requests%s -postituslistalla. Älä kuitenkaan lähetä hallintapyyntöjä postituslistalle." +#: html/home.php msgid "Submitting Packages" msgstr "Paketien lisääminen ja päivittäminen" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Pakettien lisääminen ja päivittäminen uudessa AUR versiossa tapahtuu SSH-" -"yhteyden yli Git-versionhallinan avulla. Tarkemman ohjeet löytyvät Arch " -"Linuxin wiki-oppaan AUR-sivulta kohdasta %sPakettien lisääminen%s." +msgstr "Pakettien lisääminen ja päivittäminen uudessa AUR versiossa tapahtuu SSH-yhteyden yli Git-versionhallinan avulla. Tarkemman ohjeet löytyvät Arch Linuxin wiki-oppaan AUR-sivulta kohdasta %sPakettien lisääminen%s." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR käyttää seuraavia SSH-tunnisteita:" +#: html/home.php msgid "Discussion" msgstr "Keskustelu" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" +msgstr "Yleinen keskustelu AUR:iin ja Luotettuihin käyttäjiin liittyen käydään postitusluettelossa %saur-general%s. AUR-verkkokäyttöliittymän kehittämiseen liittyvä keskustelu käydään postitusluettelossa %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Virheiden raportointi" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Jos löydät AUR-verkkokäyttöliittymästa virheen, täytä virheenilmoituslomake %svirheenseurannassamme%s. Käytä sivustoa %sainoastaan%s verkkokäyttöliittymän virheiden ilmoittamiseen. Ilmoittaaksesi pakettien virheistä, ota yhteys paketin ylläpitäjään tai jätä kommentti paketin sivulla." +#: html/home.php msgid "Package Search" msgstr "Pakettihaku" +#: html/index.php msgid "Adopt" msgstr "Ota haltuun" +#: html/index.php msgid "Vote" msgstr "Äänestä" +#: html/index.php msgid "UnVote" msgstr "Peru ääni" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Lähetä ilmoituksia" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "En halua ilmoituksia" +#: html/index.php msgid "UnFlag" msgstr "Poista merkintä" +#: html/login.php template/header.php msgid "Login" msgstr "Kirjaudu" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Nykyinen käyttäjä: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Kirjaudu ulos" +#: html/login.php msgid "Enter login credentials" msgstr "Kirjautumistiedot" +#: html/login.php msgid "User name or email address" msgstr "Käyttäjänimi tai sähköpostiosoite" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Salasana" +#: html/login.php msgid "Remember me" msgstr "Muista minut" +#: html/login.php msgid "Forgot Password" msgstr "Unohditko salasanasi?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP:n kautta kirjoutuminen ei ole käytössä. Ole hyvä ja %svaihda HTTPS " -"yhteyteen%s kirjautuaksesi." +msgstr "HTTP:n kautta kirjoutuminen ei ole käytössä. Ole hyvä ja %svaihda HTTPS yhteyteen%s kirjautuaksesi." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Haku kriteerit" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketit" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Valitun paketin tietoja ei löytynyt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Jokin vaadituista kentistä on puutteellinen." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Salasanakentät eivät täsmää." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Salasanan pitää olla vähintään %s merkkiä pitkä." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Epäkelvollinen sähköpostiosoite." +#: html/passreset.php msgid "Password Reset" msgstr "Salasanan palautus" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "Sähköpostiisi on nyt lähetetty varmistus linkki." +msgstr "Sähköpostiisi on nyt lähetetty varmistuslinkki." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Salasanasi on palautettu onnistuneesti." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Vahvista sähköpostiositteesi:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Uuusi salasana:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Vahvista uusi salasana:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Jatka" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Jos olet unohtanut rekisteröityessäsi käyttämäsi sähköpostiosoitteen lähetä " -"viesti %saur-general%s postituslistalle." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Jos olet unohtanut rekisteröityessäsi käyttämäsi sähköpostiosoitteen lähetä viesti %saur-general%s postituslistalle." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Sähköpostiosoitteesi:" +#: html/pkgbase.php msgid "Package Bases" -msgstr "" +msgstr "Pakettikannat" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" +msgstr "Seuraavia paketteja ei ole hylätty. Tarkista varmistusruutu." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Pakettia, johon haluat siirtää äänet ja kommentit, ei löydy." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." -msgstr "" +msgstr "Pakettikantaa ei voi yhdistää itseensä." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Valittuja paketteja ei ole poistettu. Muistitko laittaa raksin varmistus " -"ruutuun?" +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Valittuja paketteja ei ole poistettu. Muistitko laittaa raksin varmistusruutuun?" +#: html/pkgdel.php msgid "Package Deletion" msgstr "Paketin poisto" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Poista paketti" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" +msgstr "Käytä tätä lomaketta poistaaksesi pakettikannan %s%s%s ja seuraavat paketit AUR:sta:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Pakettin poistaminen on lopullista, sitä ei voi peruuttaa." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Vahvista toiminto valitsemalla valintaruutu." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Vahvista paketin poisto" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Poista" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Vain Trusted- statuksen omaavat käyttäjät, sekä kehittäjät voivat poistaa " -"paketteja." +msgstr "Vain Luotetut käyttäjät, sekä kehittäjät voivat poistaa paketteja." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Hylkää paketti" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Käytä tätä lomaketta hylätäksesi pohjapaketin %s%s%s joka sisältää seuraavat " -"paketit:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Käytä tätä lomaketta hylätäksesi pakettikannan %s%s%s joka sisältää seuraavat paketit:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Valitsemalla valintaruudun, vahvista että haluat hylätä paketin ja siirtää " -"hallinnan käyttäjälle %s%s%s." +msgstr "Valitsemalla valintaruudun, vahvista että haluat hylätä paketin ja siirtää hallinnan käyttäjälle %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Valitsemalla valintaruudun, vahvistat että haluat hylätä paketin." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Vahvista paketin hylkäys" +#: html/pkgdisown.php msgid "Disown" msgstr "Hylkää" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Vain Trusted-statuksen omaavat käyttäjät, sekä kehittäjät voivat hylätä " -"paketteja." +msgstr "Vain Luotetut käyttäjät, sekä kehittäjät voivat hylätä paketteja." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Merkitse paketti vanhentuneeksi" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Käytä tätä lomaketta merkitäksesi pohjapaketin %s%s%s ja seuraavat paketit " -"vanhentuneiksi:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Käytä tätä lomaketta merkitäksesi pakettikannan %s%s%s ja seuraavat paketit vanhentuneiksi:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"%sÄlä%s käytä tätä lomaketta ilmoittaaksesi bugeista. Käytä kommentteja " -"siihen." +msgstr "%sÄlä%s käytä tätä lomaketta ilmoittaaksesi ohjelmointivirheistä. Käytä kommentteja siihen." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Anna lisätietoja miksi paketti on vanhentunut, mieluiten sisältäen linkin " -"ilmoitukseen tai uuteen tiedostoon." +msgstr "Anna lisätietoja miksi paketti on vanhentunut, mieluiten sisältäen linkin ilmoitukseen tai uuteen tiedostoon." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentit" +#: html/pkgflag.php msgid "Flag" msgstr "Merkitse" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"Vain rekisteröityneet käyttäjät voivat merkitä paketteja vanhentuneiksi." +msgstr "Vain rekisteröityneet käyttäjät voivat merkitä paketteja vanhentuneiksi." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakettien yhdistäminen" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Yhdistä toiseen pakettiin" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Käytä tätä lomaketta yhdistääksesi pohjapaketin %s%s%s toiseen pakettiin." +msgstr "Käytä tätä lomaketta yhdistääksesi pakettikannan %s%s%s toiseen pakettiin." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Seuraavat paketit poistetaan:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Paketin yhdistämistä ei voi peruuttaa." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Valitse kohdepaketti." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Yhdistä tähän pakettiin:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Vahvista pakettien yhdistäminen" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Liitä" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Vain Trusted-statuksen omaavat käyttäjät, sekä kehittäjät voivat yhdistää " -"paketteja." +msgstr "Vain Luotetut käyttäjät, sekä kehittäjät voivat yhdistää paketteja." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Lähetä pyyntö" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Sulje pyyntö" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Ensimmäinen" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Edellinen" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seuraava" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Viimeinen" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Pyynnöt" +#: html/register.php template/header.php msgid "Register" msgstr "Rekisteröidy" +#: html/register.php msgid "Use this form to create an account." msgstr "Käytä tätä lomaketta uuden käyttäjätilin luomiseen." +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "Palveluehdot" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "Seuraavat dokumentit on päivitetty. Kertaa ne huolellisesti:" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "versio %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "Hyväksyn ylläolevat ehdot." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Luotettu käyttäjä (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Ehdotuksen tietoja ei voitu noutaa." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Tämän ehdoksen äänestys on päättynyt." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." -msgstr "Vain Trusted- statuksen omaavat käyttäjät voivat äänestää." +msgstr "Vain Luotetut käyttäjät voivat äänestää." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Et voi äänestää itseäsi koskevassa äänestyksessä." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Olet jo antanut äänesi tälle ehdotukselle." +#: html/tu.php msgid "Vote ID not valid." msgstr "Äänestys ID ei ole kelvollinen." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Avoimet äänestykset." +#: html/tu.php msgid "Past Votes" msgstr "Sulkeutuneet äänestykset." +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Äänestäjät" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Tunnuksien rekisteröinti on estetty IP-osoitteestasi, luultavasti toistuvien " -"roskapostihyökkäysten takia. Pahoittelemme aiheutunutta haittaa." +msgstr "Tunnuksien rekisteröinti on estetty IP-osoitteestasi, luultavasti toistuvien roskapostihyökkäysten takia. Pahoittelemme aiheutunutta haittaa." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Käyttäjän tunnus puuttuu" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Käyttäjänimi ei ole kelvollinen." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Sen pitää olla %s-%s kirjaintapitkä" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Alkaa ja loppua kirjaimeen tai numeroon" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Voi sisältää vain yhden väliviivan, alaviivan tai pisteen." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Sähköpostiosoite ei ole kelvollinen." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "Kotisivun osoite on virheellinen, määrittele koko http(s) URL." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP-avaimen sormenjälki ei ole kelvollinen." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Julkinen SSH-avain ei ole kelvollinen." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Käyttäjätunnuksen oikeuksia ei voitu korottaa." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Kieli ei ole vielä tuettuna." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." -msgstr "" +msgstr "Aikavyöhykettä ei tällä hetkellä tueta." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Käyttäjänimi %s%s%s on jo käytössä." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Osoite %s%s%s on jo käytössä." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Julkinen SSH-avain %s%s%s on jo käytössä." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Virhe luotaessa tiliä %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Käyttäjätili %s%s%s on nyt luotu." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Salasanan palautuspyyntö on lähetetty sähköpostiosoitteeseesi." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klikkaa Kirjaudu-linkkiä kirjautuaksesi." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Käyttäjätunnukseen %s%s%s ei tehty muutoksia." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Käyttäjätilin %s%s%s tiedot on nyt tallennettu." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Kirjautumislomake on estetty IP-osoitteestasi, luultavasti toistuvien " -"roskapostihyökkäysten takia. Pahoittelemme aiheutunutta haittaa." +msgstr "Kirjautumislomake on estetty IP-osoitteestasi, luultavasti toistuvien roskapostihyökkäysten takia. Pahoittelemme aiheutunutta haittaa." +#: lib/acctfuncs.inc.php msgid "Account suspended" -msgstr "" +msgstr "Tili jäädytetty" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" +msgstr "Salasanasi on palautettu. Jos loit juuri uuden tilin, käytä sähköpostitse saamaasi varmistuslinkkiä asettaaksesi ensimmäisen salasanasi. Muussa tapauksessa pyydä salasanan palauttamista %sSalasanan palautus%s -sivulla." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Virheellinen käyttäjänimi tai salasana." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "" +msgstr "Virhe tapahtui käyttäjäistuntoa luodessa." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Epäkelvollinen sähköposti ja palautusavain yhdistelmä." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" -msgstr "" +msgstr "Näytä käyttäjän %s tiedot" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Sinulla ei ole oikeuksia tämän kommentin muokkaamiseen." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Kommenttia ei ole olemassa." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Kommentti ei voi olla tyhjä." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentti lisätty." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Sinun pitää kirjautua, ennen kuin voit muokata paketin tietoja." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Kommentin tunnus puuttuu." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Yli 5 kommenttia ei voi kiinnittää." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Sinulla ei ole oikeuksia tämän kommentin kiinnittämiseen." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Sinulla ei ole oikeuksia tämän kommentin kiinnityksen poistamiseen." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Kommentti on kiinnitetty." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Kommentin kiinnitys on poistettu." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Virhe haettaessa paketin tietoja." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paketin tietoja ei löydetty." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Sinun pitää kirjautua, ennen kuin voit muuttaa merkintöjä." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Et valinnut yhtään pakettia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" +msgstr "Seuraavia paketteja ei merkitty. Syötä kommentti." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Valitut paketit on merkitty vanhentuneiksi." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Sinun pitää kirjautua, ennen kuin voit muuttaa merkintöjä." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Et valinnut yhtään pakettia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Valittuilta paketeilta on poistettu merkintä." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." -msgstr "" +msgstr "Sinulla ei ole oikeutta poistaa paketteja." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Et valinnut yhtään pakettia poistettavaksi." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Valitut paketit on nyt poistettu." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Sinun pitää kirjautua, ennen kuin voit adoptoida paketteja." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Sinun pitää kirjautua, ennen kuin voit hylätä paketteja." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Et valinnut yhtään pakettia adoptoitavaksi." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Et valinnut yhtään pakettia hylättäväksi." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Valitut paketit on nyt adoptoitu." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Valitut paketiti on nyt hylätty." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Sinun pitää kirjautua, ennen kuin voit äänestää paketteja." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Sinun pitää kirjautua, ennen kuin voit perua äänesi." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Et valinnut yhtään pakettia äänestettäväksi." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Valittuille paketeille antamasi äänet on nyt peruttu." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Äänesi on nyt annettu valituille paketeille." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ei kyetty lisäämään ilmoituslistaan." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Saat nyt ilmoituksen paketin %s uusista kommenteista." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Et saa enää ilmoituksia paketin %s uusista kommenteista." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Sinun ei sallita palauttaa tätä kommenttia." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." -msgstr "" +msgstr "Kommentti on palautettu." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Sinulla ei ole oikeuksia tämän kommentin poistamiseen." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentti on poistettu." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." -msgstr "" +msgstr "Kommenttia on muokattu." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" +msgstr "Sinun ei sallita muokata tämän pakettikannan avainsanoja." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." -msgstr "" +msgstr "Tämän pakettikannan avainsanat päivitettiin." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" -msgstr "" +msgstr "Virheellinen käyttäjänimi: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." -msgstr "" +msgstr "Sinun täytyy kirjautua sisään lähettääksesi pyyntöjä paketista." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Virheellinen nimi: vain pienet kirjaimet ovat sallittuja." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." -msgstr "" +msgstr "Kommenttikenttä ei saa olla tyhjä." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." -msgstr "" +msgstr "Virheellinen pyyntötyyppi." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." -msgstr "" +msgstr "Pyyntö lisättiin onnistuneesti." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." -msgstr "" +msgstr "Virheellinen syy." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" +msgstr "Vain Luotetut käyttäjät (TU) ja kehittäjät voivat sulkea pyyntöjä." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Käyttäjänimi" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "TIlin tyyppi" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Käyttäjä" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Kehittäjä" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" -msgstr "" +msgstr "Luotettu käyttäjä & kehittäjä" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Sähköpostiosoite" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Oikea nimi" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC nikki" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Tila" +#: template/account_details.php msgid "Inactive since" msgstr "" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiivinen" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "tuntematon" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Ei koskaan" +#: template/account_details.php msgid "View this user's packages" msgstr "Näytä käyttäjän paketit" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "" +msgstr "Klikkaa %stästä%s, jos haluat peruuttamattomasti poistaa tämän tilin." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." -msgstr "" +msgstr "Klikkaa %stästä%s saadaksesi käyttäjän tiedot." +#: template/account_edit_form.php msgid "required" msgstr "vaaditaan" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Tavallinen käyttäjä" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Luotettu käyttäjä (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Käyttäjätili hyllytetty" +#: template/account_edit_form.php msgid "Inactive" msgstr "" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Salasana uudelleen:" +#: template/account_edit_form.php msgid "Language" msgstr "Kieli" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Julkinen SSH avain" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Lähetä ilmoitus uusista kommnteista" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Päivitä" +#: template/account_edit_form.php msgid "Create" msgstr "Luo" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Tyhjennä" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Hakuasi vastaavia paketteja ei löydy." +#: template/account_search_results.php msgid "Edit Account" msgstr "Muokkaa käyttäjätiliä" +#: template/account_search_results.php msgid "Suspended" msgstr "Hyllytä" +#: template/account_search_results.php msgid "Edit" msgstr "Muokkaa" +#: template/account_search_results.php msgid "Less" msgstr "Vähemmän" +#: template/account_search_results.php msgid "More" msgstr "Enemmän" +#: template/account_search_results.php msgid "No more results to display." msgstr "Ei enempää tuloksia" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "" +msgstr "Vanhentuneeksi merkitsemisen kommentti: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" +msgstr "%s%s%s merkitsi %s%s%s vanhentuneeksi %s %s%s seuraavasta syystä:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "" +msgstr "%s%s%s ei ole merkitty vanhentuneeksi." +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." -msgstr "" +msgstr "Tekijänoikeudet %s 2004-%d aurweb kehittäjätiimi." +#: template/header.php msgid " My Account" msgstr "Omat tiedot" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakettitoiminnot" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Näytö PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Näytä muutoshistoria" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Lataa tuorein versio" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Etsi wikistä" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" -msgstr "" +msgstr "Merkitty vanhentuneeksi (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Merkitse paketti vanhentuneeksi" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Poista merkintä" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Poista ääneni" +#: template/pkgbase_actions.php msgid "Vote for this package" -msgstr "Äännestä pakettia" +msgstr "Äänestä pakettia" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "En halua enää ilmoituksia" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Hallitse ylläpitäjäkumppaneita" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d käsittelemätön hallintapyyntö" msgstr[1] "%d käsittelemätöntä hallintapyyntöä" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Ryhdy ylläpitäjäksi" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" -msgstr "Git kopionti osoite" +msgstr "Git-kloonausosoite" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "vain luku" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Avainsanat" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Lisääjä" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ylläpitäjä" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" -msgstr "Uusimman versionn luoja" +msgstr "Viimeisin paketoija" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Äänet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" -msgstr "" +msgstr "Suosio" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Lisättiin" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Päivitettiin" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Lisää kommentti" +#: template/pkg_comments.php msgid "View all comments" msgstr "Näytä kaikki kommentit" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Uusimmat kommentit" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Poista kommentti" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Kaikki kommentit" +#: template/pkg_details.php msgid "Package Details" msgstr "Paketin tiedot" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Ylipaketti" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Kuvaus" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Kotisivu" +#: template/pkg_details.php msgid "Visit the website for" -msgstr "" +msgstr "Vieraile tämän paketin verkkosivulla: " +#: template/pkg_details.php msgid "Licenses" msgstr "Lisenssit" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "Ristiriidat" +#: template/pkg_details.php msgid "Provides" msgstr "Tarjoaa paketit" +#: template/pkg_details.php msgid "Replaces" msgstr "Korvaa paketit" +#: template/pkg_details.php msgid "Dependencies" msgstr "Riippuvuudet" +#: template/pkg_details.php msgid "Required by" msgstr "Riippuvuutena paketeille" +#: template/pkg_details.php msgid "Sources" msgstr "Lähdetiedostot" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" -msgstr "" +msgstr "Pyynnön tyyppi" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Yhdistä pakettiin" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" +msgstr "Lähettämällä poistopyynnön pyydät Luotettua käyttäjää poistamaan pakettikannan. Tämän tyyppisiä pyyntöjä tulisi käyttää ainoastaan kaksoiskappaleisiin, laittomiin tai korjaamattoman rikkonaisiin paketteihin sekä ohjelmistoihin, jotka kehittäjä on hylännyt." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" +msgstr "Ennen yhdistämispyynnön lähettämistä, pyydä Luotettua käyttäjää poistamaan pakettikanta ja siirtämään sen äänet ja kommentit toiseen pakettikantaan. Paketin yhdistäminen ei vaikuta Git-varastoihin. Varmista, että päivität kohdepaketin Git-historian itse." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1336,247 +1688,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nimi, kuvaus" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Pelkkä nimi" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Kaikki" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Merkitty" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Ei merkitty" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nimi" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Äänestin" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Nouseva" +#: template/pkg_search_form.php msgid "Descending" msgstr "Laskeva" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Etsintäperuste" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Vanhentunut" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Järjestelyperuste" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Järjestelyperuste" +#: template/pkg_search_form.php msgid "Per page" msgstr "Sivua kohden" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Etsi" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orvot" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Virhe pakettilistaa noudettaessa." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Hakuasi vastaavia paketteja ei löydy." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +#: template/pkg_search_results.php msgid "Version" msgstr "Versio" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" +msgstr "Suosio lasketaan ottamalla äänien summa ja painottamalla jokaista ääntä kertoimella %.2f joka päivä sen luomisesta lähtien." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Kyllä" +#: template/pkg_search_results.php msgid "orphan" msgstr "orpo" +#: template/pkg_search_results.php msgid "Actions" msgstr "Toiminnot" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Ei vanhentunut" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptoi paketit" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Hylkää paketit" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Poista paketit" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Vahvista" +#: template/search_accounts_form.php msgid "Any type" msgstr "Mikä tahansa" +#: template/search_accounts_form.php msgid "Search" msgstr "Etsi" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Tilastoja" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Hylättyjä paketteja" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Uudet paketit 7 päivän sisällä" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paketteja päivitetty 7 päivän sisällä" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Vuoden aikana päivitettyjä paketteja" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paketteja ei ole koskaan päivitetty" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Rekisteröityjä käyttäjiä" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Luotettuja käyttäjiä" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Viimeisimmät päivitykset" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Tilastoni" +#: template/tu_details.php msgid "Proposal Details" msgstr "Ehdotuksen tiedot" +#: template/tu_details.php msgid "This vote is still running." msgstr "Tätä ehdotusta voi vielä äänestää." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Lisätty: %s Lisääjä: %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Loppu" +#: template/tu_details.php msgid "Result" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ei" +#: template/tu_details.php msgid "Abstain" msgstr "" +#: template/tu_details.php msgid "Total" msgstr "Yhteensä" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ei tuloksia." +#: template/tu_list.php msgid "Start" msgstr "Alku" +#: template/tu_list.php msgid "Back" msgstr "Takaisin" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "Tervetuloa AUR:iin! Asettaaksesi ensimmäisen salasanan uudelle tilillesi, klikkaa alla olevaa linkkiä [1]. Jos linkki ei toimi, kokeile kopioida ja liittää se selaimeesi." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "AUR: Ilmoitus paketin {pkgbase} vanhentumisesta" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "Pakettisi {pkgbase} [1] on merkitty vanhentuneeksi. Merkinnän teki käyttäjä {user} [2]:" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "{user} [1] yhdisti paketin {old} [2] pakettiin {new} [3].\n\nJos et enää halua saada ilmoituksia uudesta paketista, mene osoitteeseen [3] ja klikkaa \"{label}\"." + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/fr.po b/po/fr.po index eb22f19c..3eef4efe 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,8 +1,9 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: +# Alexandre Macabies , 2018 # Antoine Lubineau , 2012 # Antoine Lubineau , 2012-2016 # Cedric Girard , 2011,2014,2016 @@ -10,1651 +11,2131 @@ # lordheavy , 2013-2014 # lordheavy , 2011-2012 # Lukas Fleischer , 2011 -# Xorg , 2015,2017 +# Xorg, 2015,2017 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: French (http://www.transifex.com/lfleischer/aur/language/" -"fr/)\n" -"Language: fr\n" +"Language-Team: French (http://www.transifex.com/lfleischer/aurweb/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Page non trouvée" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Désolé, la page que vous avez demandée n’existe pas." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Note" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" -"Les URL de clone Git ne sont pas censées être ouvertes depuis un navigateur." +msgstr "Les URL de clone Git ne sont pas censées être ouvertes depuis un navigateur." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Pour cloner le dépôt Git de %s, exécutez %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Cliquez %sici%s pour retourner à la page des détails de %s." +#: html/503.php msgid "Service Unavailable" msgstr "Service indisponible" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Ne paniquez pas ! Le site est fermé pour maintenance. Nous serons bientôt de " -"retour." +msgstr "Ne paniquez pas ! Le site est fermé pour maintenance. Nous serons bientôt de retour." +#: html/account.php msgid "Account" msgstr "Compte" +#: html/account.php template/header.php msgid "Accounts" msgstr "Comptes" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Vous n’avez pas la permission d’accéder à cet espace." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Impossible de trouver l’information pour l’utilisateur spécifié." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Vous n’avez pas la permission d’éditer ce compte." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilisez ce formulaire pour rechercher des comptes existants." +#: html/account.php msgid "You must log in to view user information." -msgstr "" -"Vous devez vous authentifier pour voir les informations de l’utilisateur." +msgstr "Vous devez vous authentifier pour voir les informations de l’utilisateur." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Ajoutez une proposition" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Action invalide." +#: html/addvote.php msgid "Username does not exist." msgstr "Le nom d'utilisateur n’existe pas." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s a déjà une proposition en cours à son sujet." +#: html/addvote.php msgid "Invalid type." msgstr "Type invalide." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Une proposition ne peut être vide." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nouvelle proposition enregistrée." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Soumettre une proposition à laquelle voter." +#: html/addvote.php msgid "Applicant/TU" msgstr "Requérant/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vide si non applicable)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "Ajout d’un utilisateur de confiance." +#: html/addvote.php msgid "Removal of a TU" msgstr "Suppression d’un utilisateur de confiance" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Suppression d’un utilisateur de confiance (inactivité non prévenue)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendement du règlement" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposition" +#: html/addvote.php msgid "Submit" msgstr "Soumettre" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Gérer les co-mainteneurs" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Éditer le commentaire" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Tableau de bord" +#: html/home.php template/header.php msgid "Home" msgstr "Accueil" +#: html/home.php msgid "My Flagged Packages" msgstr "Mes paquets périmés" +#: html/home.php msgid "My Requests" msgstr "Mes requêtes" +#: html/home.php msgid "My Packages" msgstr "Mes paquets" +#: html/home.php msgid "Search for packages I maintain" msgstr "Rechercher les paquets que je maintiens" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Paquets co-maintenus" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Rechercher les paquets que je co-maintiens" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bienvenue sur AUR ! Veuillez lire les %sconsignes pour les utilisateurs d’AUR" -"%s et les %sconsignes pour les utilisateurs de confiance%s pour plus " -"d’information." +msgstr "Bienvenue sur AUR ! Veuillez lire les %sconsignes pour les utilisateurs d’AUR%s et les %sconsignes pour les utilisateurs de confiance%s pour plus d’information." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Les PKGBUILD proposés %sdoivent%s respecter les %sstandards d’empaquetage " -"d’Arch%s, sinon ils seront supprimés !" +msgstr "Les PKGBUILD proposés %sdoivent%s respecter les %sstandards d’empaquetage d’Arch%s, sinon ils seront supprimés !" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Pensez à voter pour vos paquets favoris !" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Certains paquets peuvent être disponibles sous forme binaire dans le dépôt " -"[community]." +msgstr "Certains paquets peuvent être disponibles sous forme binaire dans le dépôt [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVERTISSEMENT" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Les paquets AUR sont produits par des utilisateurs. Toute utilisation des " -"fichiers fournis se fait à vos propres risques." +msgstr "Les paquets AUR sont produits par des utilisateurs. Toute utilisation des fichiers fournis se fait à vos propres risques." +#: html/home.php msgid "Learn more..." msgstr "En apprendre plus..." +#: html/home.php msgid "Support" msgstr "Soutien" +#: html/home.php msgid "Package Requests" msgstr "Requêtes de paquet" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Il existe trois types de requêtes qui peuvent être soumises dans la boîte " -"%sActions du paquet%s sur la page des détails d'un paquet :" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Il existe trois types de requêtes qui peuvent être soumises dans la boîte %sActions du paquet%s sur la page des détails d'un paquet :" +#: html/home.php msgid "Orphan Request" msgstr "Requête de destitution" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Demande qu'un paquet soit destitué, c'est-à-dire quand le mainteneur est " -"inactif et que le paquet a été marqué comme périmé depuis un long moment." +msgstr "Demande qu'un paquet soit destitué, c'est-à-dire quand le mainteneur est inactif et que le paquet a été marqué comme périmé depuis un long moment." +#: html/home.php msgid "Deletion Request" msgstr "Requête de suppression" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Demande qu'un paquet soit supprimé d'AUR. Prière de ne pas l'utiliser si un " -"paquet est cassé et que le problème peut être réglé facilement. À la place, " -"contactez le mainteneur du paquet, et soumettez une requête de destitution " -"si nécessaire." +msgstr "Demande qu'un paquet soit supprimé d'AUR. Prière de ne pas l'utiliser si un paquet est cassé et que le problème peut être réglé facilement. À la place, contactez le mainteneur du paquet, et soumettez une requête de destitution si nécessaire." +#: html/home.php msgid "Merge Request" msgstr "Requête de fusion" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Demande que le paquet soit fusionné dans un autre. Peut être utilisé quand " -"un paquet a besoin d'être renommé ou bien remplacé par un paquet splitté." +msgstr "Demande que le paquet soit fusionné dans un autre. Peut être utilisé quand un paquet a besoin d'être renommé ou bien remplacé par un paquet splitté." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Si vous voulez débattre d'une requête, vous pouvez utiliser la mailing-list " -"%saur-requests%s. Cependant, merci de ne pas utiliser cette liste pour " -"soumettre des requêtes." +msgstr "Si vous voulez débattre d'une requête, vous pouvez utiliser la mailing-list %saur-requests%s. Cependant, merci de ne pas utiliser cette liste pour soumettre des requêtes." +#: html/home.php msgid "Submitting Packages" msgstr "Soumission de paquets" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git par-dessus SSH est maintenant utilisé pour soumettre des paquets sur " -"AUR. Voir la section %sSoumettre des paquets%s sur la page Arch User " -"Repository du wiki pour plus de détails." +msgstr "Git par-dessus SSH est maintenant utilisé pour soumettre des paquets sur AUR. Voir la section %sSoumettre des paquets%s sur la page Arch User Repository du wiki pour plus de détails." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Les empreintes SSH suivantes sont utilisées pour AUR :" +#: html/home.php msgid "Discussion" msgstr "Discussion" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Les discussions générales en rapport avec AUR (Arch User Repository, dépôt " -"des utilisateurs d’Arch Linux) et les TU (Trusted User, utilisateurs de " -"confiance) ont lieu sur %saur-general%s. Pour les discussions en rapport " -"avec le développement de l'interface web d'AUR, utilisez la mailing-list " -"%saur-dev.%s" +msgstr "Les discussions générales en rapport avec AUR (Arch User Repository, dépôt des utilisateurs d’Arch Linux) et les TU (Trusted User, utilisateurs de confiance) ont lieu sur %saur-general%s. Pour les discussions en rapport avec le développement de l'interface web d'AUR, utilisez la mailing-list %saur-dev.%s" +#: html/home.php msgid "Bug Reporting" msgstr "Rapports de bug" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Si vous trouvez un bug dans l'interface web d'AUR, merci de remplir un " -"rapport de bug sur le %sbug tracker%s. N’utilisez le tracker %sque%s pour " -"les bugs de l'interface web d'AUR. Pour signaler un bug dans un paquet, " -"contactez directement le mainteneur du paquet, ou laissez un commentaire sur " -"la page du paquet." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Si vous trouvez un bug dans l'interface web d'AUR, merci de remplir un rapport de bug sur le %sbug tracker%s. N’utilisez le tracker %sque%s pour les bugs de l'interface web d'AUR. Pour signaler un bug dans un paquet, contactez directement le mainteneur du paquet, ou laissez un commentaire sur la page du paquet." +#: html/home.php msgid "Package Search" msgstr "Recherche d'un paquet" +#: html/index.php msgid "Adopt" msgstr "Adopter" +#: html/index.php msgid "Vote" msgstr "Voter" +#: html/index.php msgid "UnVote" msgstr "Retirer le vote" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notifier" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne plus notifier" +#: html/index.php msgid "UnFlag" msgstr "Ne plus marquer comme périmé" +#: html/login.php template/header.php msgid "Login" msgstr "Se connecter" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Connecté en tant que : %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Déconnexion" +#: html/login.php msgid "Enter login credentials" msgstr "Entrez vos identifiants" +#: html/login.php msgid "User name or email address" msgstr "Nom d'utilisateur ou adresse e-mail :" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Mot de passe" +#: html/login.php msgid "Remember me" msgstr "Se souvenir de moi" +#: html/login.php msgid "Forgot Password" msgstr "Mot de passe oublié" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"La connexion HTTP est désactivée. Veuillez %sbasculer en HTTPS%s pour " -"pouvoir vous connecter." +msgstr "La connexion HTTP est désactivée. Veuillez %sbasculer en HTTPS%s pour pouvoir vous connecter." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critères de recherche" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paquets" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erreur en essayant de retrouver les détails du paquets." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Il manque un champ requis." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Les champs du mot de passe ne correspondent pas." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Votre mot de passe doit comprendre au moins %s caractères." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail invalide" +#: html/passreset.php msgid "Password Reset" msgstr "Réinitialisation de mot de passe" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Vérifiez votre e-mail pour le lien de confirmation." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Votre mot de passe a été réinitialisé avec succès." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirmez votre adresse e-mail :" +#: html/passreset.php msgid "Enter your new password:" msgstr "Entrez votre nouveau mot de passe :" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirmez votre nouveau mot de passe :" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continuer" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Si vous avez oublié avec quelle adresse e-mail vous vous êtes inscrit, " -"veuillez envoyer un message sur la mailing-list %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Si vous avez oublié avec quelle adresse e-mail vous vous êtes inscrit, veuillez envoyer un message sur la mailing-list %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Entrez votre adresse e-mail :" +#: html/pkgbase.php msgid "Package Bases" msgstr "Bases du paquet" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Les paquets sélectionnés n'ont pas été destitués, vérifiez la boîte de " -"confirmation." +msgstr "Les paquets sélectionnés n'ont pas été destitués, vérifiez la boîte de confirmation." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Impossible de trouver le paquet dans lequel fusionner les votes et les " -"commentaires." +msgstr "Impossible de trouver le paquet dans lequel fusionner les votes et les commentaires." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Impossible de fusionner un paquet de base avec lui-même" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Les paquets sélectionnés n'ont pas été supprimés, cochez la case de " -"confirmation." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Les paquets sélectionnés n'ont pas été supprimés, cochez la case de confirmation." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Suppression de paquet" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Supprimer le paquet" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Utilisez ce formulaire pour supprimer le paquet de base %s%s%s et les " -"paquets suivants de AUR :" +msgstr "Utilisez ce formulaire pour supprimer le paquet de base %s%s%s et les paquets suivants de AUR :" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "La suppression d’un paquet est permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Cochez la case pour confirmer l’action." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmer la suppression du paquet" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Supprimer" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Seuls les Utilisateur de Confiance et les Développeurs peuvent effacer des " -"paquets." +msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent effacer des paquets." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Destituer le paquet" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Utilisez ce formulaire pour destituer le paquet de base %s%s%s qui inclut " -"les paquets suivants : " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Utilisez ce formulaire pour destituer le paquet de base %s%s%s qui inclut les paquets suivants : " +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"En cochant la case, vous confirmez que vous voulez destituer le paquet et " -"transférer sa propriété à %s%s%s." +msgstr "En cochant la case, vous confirmez que vous voulez destituer le paquet et transférer sa propriété à %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"En cochant la case, vous confirmez que vous voulez destituer le paquet." +msgstr "En cochant la case, vous confirmez que vous voulez destituer le paquet." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirmer la destitution du paquet" +#: html/pkgdisown.php msgid "Disown" msgstr "Destituer" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Seuls les Utilisateur de Confiance et les Développeurs peuvent destituer des " -"paquets." +msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent destituer des paquets." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Signaler le commentaire" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Marquer le paquet comme périmé" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Utilisez ce formulaire pour marquer le paquet de base %s%s%s et les paquets " -"suivants périmés :" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Utilisez ce formulaire pour marquer le paquet de base %s%s%s et les paquets suivants périmés :" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Merci de %sne pas%s utiliser ce formulaire pour rapporter des bugs. Utilisez " -"les commentaires du paquet à la place." +msgstr "Merci de %sne pas%s utiliser ce formulaire pour rapporter des bugs. Utilisez les commentaires du paquet à la place." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Entrez les détails de pourquoi le paquet est périmé, de préférence en " -"incluant un lien vers l'annonce de la version ou bien vers l'archive de la " -"nouvelle version." +msgstr "Entrez les détails de pourquoi le paquet est périmé, de préférence en incluant un lien vers l'annonce de la version ou bien vers l'archive de la nouvelle version." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Commentaires" +#: html/pkgflag.php msgid "Flag" msgstr "Marquer comme périmé" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"Seuls les utilisateurs enregistrés peuvent marquer les paquets périmés." +msgstr "Seuls les utilisateurs enregistrés peuvent marquer les paquets périmés." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusion de paquet" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Fusionner le paquet" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Utilisez ce formulaire pour fusionner ce paquet de base %s%s%s dans un autre " -"paquet." +msgstr "Utilisez ce formulaire pour fusionner ce paquet de base %s%s%s dans un autre paquet." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Les paquets suivants vont être supprimés :" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "La fusion du paquet est une opération irréversible." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Saisissez le nom du paquet dans lequel vous souhaitez fusionner ce paquet." +msgstr "Saisissez le nom du paquet dans lequel vous souhaitez fusionner ce paquet." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fusionner dans :" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmer la fusion du paquet" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fusionner" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Seuls les Utilisateur de Confiance et les Développeurs peuvent fusionner des " -"paquets." +msgstr "Seuls les Utilisateur de Confiance et les Développeurs peuvent fusionner des paquets." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Soumettre une demande" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fermer la requête" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Première" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Précédente" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Suivant" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Dernière" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Requêtes" +#: html/register.php template/header.php msgid "Register" msgstr "S’inscrire" +#: html/register.php msgid "Use this form to create an account." msgstr "Utilisez ce formulaire pour créer un compte." +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "Conditions de service" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "Les documents suivants ont été mis à jours. Merci de les consulter attentivement :" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "version %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "J'accepte les modalités ci-avant." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Utilisateur de confiance (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Impossible d’obtenir le détail de la proposition." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Le vote est clos pour cette proposition." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Seuls les Utilisateurs de Confiance sont autorisés à voter." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Vous ne pouvez pas voter dans une proposition à votre sujet." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Vous avez déjà voté pour cette proposition." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID de vote non valide." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votes en cours" +#: html/tu.php msgid "Past Votes" msgstr "Votes passés" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votants" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"La création de compte est désactivée pour votre adresse IP, probablement à " -"cause d’attaques de spammeurs. Désolé pour le désagrément." +msgstr "La création de compte est désactivée pour votre adresse IP, probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID d'utilisateur manquant" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Le nom d'utilisateur choisi n'est pas valide." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Il doit être compris entre %s et %s caractères," +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "doit débuter et se terminer par une lettre ou un chiffre." +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "ne peut contenir qu'un seul point, tiret bas ou virgule," +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adresse email n'est pas valide." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "La page d'accueil est invalide, spécifiez l'URL HTTP(s) complet." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "L’empreinte de clé PGP est invalide." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La clé SSH publique est invalide." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Ne peut pas augmenter les autorisations du compte." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Cette langue n'est pas supportée pour le moment." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Le fuseau horaire n'est actuellement pas pris en charge" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Le nom d’utilisateur %s%s%s, est déjà utilisé." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L’adresse %s%s%s est déjà utilisée." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clé SSH publique, %s%s%s, est déjà utilisée." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erreur en essayant de créer le compte %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Le compte %s%s%s a été créé avec succès." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Une clé de réinitialisation de mot de passe vous a été envoyée par e-mail." +msgstr "Une clé de réinitialisation de mot de passe vous a été envoyée par e-mail." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Cliquez sur le lien de connexion ci-dessus pour utiliser votre compte." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Aucun changement n'ont été fait au compte, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Le compte %s%s%s a été modifié avec succès." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Le formulaire de connexion est actuellement désactivé pour votre adresse IP, " -"probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +msgstr "Le formulaire de connexion est actuellement désactivé pour votre adresse IP, probablement à cause d’attaques de spammeurs. Désolé pour le désagrément." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Compte suspendu." +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Votre mot de passe a été réinitialisé. Si vous venez de créer un nouveau " -"compte, veuillez utiliser le lien présent dans l’e-mail de confirmation pour " -"modifier le mot de passe. Sinon, demandez une clé de réinitialisation depuis " -"la page « %sRéinitialisation de mot de passe%s »." +msgstr "Votre mot de passe a été réinitialisé. Si vous venez de créer un nouveau compte, veuillez utiliser le lien présent dans l’e-mail de confirmation pour modifier le mot de passe. Sinon, demandez une clé de réinitialisation depuis la page « %sRéinitialisation de mot de passe%s »." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Mauvais nom d'utilisateur ou mot de passe." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "" -"Une erreur est survenue en essayant de générer une session utilisateur." +msgstr "Une erreur est survenue en essayant de générer une session utilisateur." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinaison entre l'e-mail et la clef de réinitialisation invalides." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Aucun" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Voir les informations du compte pour %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "L'ID du paquet de base ou le nom du paquet de base est manquant." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Vous n'êtes pas autorisé(e) à éditer ce commentaire." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Le commentaire n'existe pas." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Le commentaire ne peut pas être vide." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Le commentaire a été ajouté." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Vous devez vous identifier avant de pouvoir éditer les informations du " -"paquet." +msgstr "Vous devez vous identifier avant de pouvoir éditer les informations du paquet." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "ID de commentaire manquant." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Au plus 5 commentaires peuvent être épinglés." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Vous n’avez pas le droit d’épingler ce commentaire." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Vous n’avez pas le droit de désépingler ce commentaire." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Le commentaire a été épinglé." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Le commentaire a été désépinglé." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Erreur en recherchant les détails du paquet." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Les détails du paquet ne peuvent pas être trouvés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Vous devez être authentifié avant de pouvoir étiqueter des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Vous n'avez sélectionné aucun paquet à étiqueter." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"Les paquets sélectionnés n'ont pas été étiquetés, merci d'entrer un " -"commentaire." +msgstr "Les paquets sélectionnés n'ont pas été étiquetés, merci d'entrer un commentaire." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Les paquets sélectionnés ont été étiquetés comme périmés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Vous devez être authentifié avant de pouvoir retirer l'étiquetage des " -"paquets." +msgstr "Vous devez être authentifié avant de pouvoir retirer l'étiquetage des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Vous n'avez sélectionné aucun paquet auquel retirer l'étiquetage." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Les paquets sélectionnés ne sont plus étiquetés." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Vous n’avez pas la permission de supprimer des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Vous n'avez sélectionné aucun paquet à supprimer." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Les paquets sélectionnés ont été supprimés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Vous devez être authentifié avant de pouvoir adopter des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Vous devez être authentifié avant de pouvoir abandonner des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Vous n'avez pas sélectionné de paquet à adopter." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Vous n'avez sélectionné aucun paquet à abandonner." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Les paquets sélectionnés ont été adoptés." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Les paquets sélectionnés ont été abandonnés." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Vous devez être authentifié avant de pouvoir voter pour des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "" -"Vous devez être authentifié avant de pouvoir retirer votre vote sur des " -"paquets." +msgstr "Vous devez être authentifié avant de pouvoir retirer votre vote sur des paquets." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Vous n'avez sélectionné aucun paquet pour lequel vous souhaitez voter." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vos votes ont été retirés des paquets sélectionnés." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Vos votes ont été distribués aux paquets sélectionnés." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ajout impossible à la liste de notification." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "" -"Vous avez été ajouté à la liste des notifications de commentaire pour %s." +msgstr "Vous avez été ajouté à la liste des notifications de commentaire pour %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "" -"Vous avez été retiré de la liste des notifications de commentaire pour %s." +msgstr "Vous avez été retiré de la liste des notifications de commentaire pour %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Vous n’avez pas l’autorisation de restaurer ce commentaire." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Le commentaire a été restauré." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Vous n'êtes pas autorisé(e) à supprimer ce commentaire." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Le commentaire a été supprimé." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Le commentaire a été édité." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Vous n'êtes pas autorisé à éditer les mots-clés de ce paquet de base." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Les mots-clés du paquet de base ont été mis à jour." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Vous n'êtes pas autorisé à gérer les co-mainteneurs de ce paquet de base." +msgstr "Vous n'êtes pas autorisé à gérer les co-mainteneurs de ce paquet de base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nom d'utilisateur invalide : %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Les co-mainteneurs du paquet de base ont été mis à jour." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Voir le paquet" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "a besoin de %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Vous devez être identifié pour soumette des requêtes sur des paquets." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nom invalide : seules les lettres minuscules sont autorisées." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "La zone de commentaire ne doit pas être vide." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Type de requête invalide." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Requête ajouté avec succès." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Raison incorrecte." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Seuls les utilisateurs de confiance et les développeurs peuvent fermer les " -"requêtes." +msgstr "Seuls les utilisateurs de confiance et les développeurs peuvent fermer les requêtes." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Requête fermée avec succès." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Vous ne pouvez pas utiliser ce formulaire pour effacer le compte AUR %s de " -"façon permanente." +msgstr "Vous ne pouvez pas utiliser ce formulaire pour effacer le compte AUR %s de façon permanente." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sATTENTION%s: cette action ne peut être annulée" +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmer la suppression" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nom d'utilisateur" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Type de compte" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilisateur" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Développeur" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Utilisateur de confiance (TU) et Développeur" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresse e-mail" +#: template/account_details.php msgid "hidden" msgstr "caché" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nom réel" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Accueil" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Pseudo IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Empreinte de clé PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "État" +#: template/account_details.php msgid "Inactive since" msgstr "Inactif depuis" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actif" +#: template/account_details.php msgid "Registration date:" msgstr "Date d'enregistrement :" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "inconnu" +#: template/account_details.php msgid "Last Login" msgstr "Dernière connexion." +#: template/account_details.php msgid "Never" msgstr "Jamais" +#: template/account_details.php msgid "View this user's packages" msgstr "Visualiser les paquets de cet utilisateur." +#: template/account_details.php msgid "Edit this user's account" msgstr "Éditer le compte de cet utilisateur." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Cliquez %sici%s si vous voulez effacer ce compte de façon définitive." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Cliquer %sici%s pour obtenir les détails de l'utilisateur." +#: template/account_edit_form.php msgid "required" msgstr "requis" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" +msgstr "Votre nom d'utilisateur est le nom que vous utilisez pour vous connecter. Il est publiquement visible, même si votre compte est inactif." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilisateur normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Utilisateur de confiance (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Compte suspendu" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactif" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Assurez-vous d'avoir correctement entré votre adresse e-mail, sinon vous " -"n'arriverez plus à vous connecter." +msgstr "Assurez-vous d'avoir correctement entré votre adresse e-mail, sinon vous n'arriverez plus à vous connecter." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Cacher l'adresse e-mail" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Retapez le mot de passe" +#: template/account_edit_form.php msgid "Language" msgstr "Langue" +#: template/account_edit_form.php msgid "Timezone" msgstr "Fuseau horaire" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"L'information suivante est requise uniquement si vous voulez soumettre des " -"paquets sur AUR" +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "L'information suivante est requise uniquement si vous voulez soumettre des paquets sur AUR" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Clé SSH publique" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Réglages des notifications" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Avertir des nouveaux commentaires" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Notifications de mises à jour de paquets" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Notifier des changements de propriétaire" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Mise à jour" +#: template/account_edit_form.php msgid "Create" msgstr "Créer" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Réinitialiser" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Aucun résultat ne correspond à vos critères de recherche." +#: template/account_search_results.php msgid "Edit Account" msgstr "Éditer le compte" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendu" +#: template/account_search_results.php msgid "Edit" msgstr "Éditer" +#: template/account_search_results.php msgid "Less" msgstr "Moins" +#: template/account_search_results.php msgid "More" msgstr "Plus" +#: template/account_search_results.php msgid "No more results to display." msgstr "Plus de résultats à afficher." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Utilisez ce formulaire pour ajouter des co-mainteneurs pour %s%s%s (un nom " -"d'utilisateur par ligne) :" +msgstr "Utilisez ce formulaire pour ajouter des co-mainteneurs pour %s%s%s (un nom d'utilisateur par ligne) :" +#: template/comaintainers_form.php msgid "Users" msgstr "Utilisateurs" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Sauvegarder" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Commentaire de paquet périmé : %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s a marqué %s%s%s comme périmé ls %s%s%s pour la raison suivante :" +msgstr "%s%s%s a marqué %s%s%s comme périmé ls %s%s%s pour la raison suivante :" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s n’est pas marqué comme périmé." +#: template/flag_comment.php msgid "Return to Details" msgstr "Retourner aux détails" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." +#: template/header.php msgid " My Account" msgstr "Mon compte" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Actions du paquet" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Voir le PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Voir les changements" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Télécharger un instantané" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Rechercher sur le wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Marqué comme périmé (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marquer le paquet comme périmé" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Ne plus marquer le paquet comme périmé" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Retirer le vote" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Voter pour ce paquet" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Désactiver les notifications" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Activer les notifications" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Gérer les co-mainteneurs" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requête en attente" msgstr[1] "%d requêtes en attente" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter ce paquet" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Détails du paquet de base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL de clone (Git)" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "lecture seule" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Mots-clés" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Contributeur" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mainteneur" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Dernier packageur" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votes" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularité" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Première soumission" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Dernière mise à jour" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Commentaire édité le : %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Ajouter un commentaire" +#: template/pkg_comments.php msgid "View all comments" msgstr "Voir tous les commentaires" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Commentaires épinglés" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Derniers commentaires" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s a commenté le %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Commentaire anonyme le %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "supprimé le %s par %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "supprimé le %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "édité le %s par %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "édité le %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Restaurer le commentaire" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Effacer le commentaire" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Épingler le commentaire" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Désépingler le commentaire" +#: template/pkg_comments.php msgid "All comments" msgstr "Tous les commentaires" +#: template/pkg_details.php msgid "Package Details" msgstr "Détails du paquet" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paquet de base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Description" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Lien" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Accéder au site web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licences" +#: template/pkg_details.php msgid "Groups" msgstr "Groupes" +#: template/pkg_details.php msgid "Conflicts" msgstr "En conflit avec" +#: template/pkg_details.php msgid "Provides" msgstr "Fournit" +#: template/pkg_details.php msgid "Replaces" msgstr "Remplace" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dépendances" +#: template/pkg_details.php msgid "Required by" msgstr "Requis par" +#: template/pkg_details.php msgid "Sources" msgstr "Sources" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Utiliser ce formulaire pour fermer la requête pour le paquet de base %s%s%s." +msgstr "Utiliser ce formulaire pour fermer la requête pour le paquet de base %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Le champ commentaires peut être laissé vide. Cependant, il est fortement " -"recommandé d'ajouter un commentaire lors du rejet d'une requête." +msgstr "Le champ commentaires peut être laissé vide. Cependant, il est fortement recommandé d'ajouter un commentaire lors du rejet d'une requête." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Raison" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Accepté" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rejeté" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Utilisez ce formulaire pour soumettre une requête concernant le paquet de " -"base %s%s%s contenant les paquets suivant:" +msgstr "Utilisez ce formulaire pour soumettre une requête concernant le paquet de base %s%s%s contenant les paquets suivant:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Type de requête" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Suppression" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Rendre orphelin" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fusionner dans" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"En soumettant une requète de suppression, vous demandez à un utilisateur de " -"confiance de supprimer le paquet de base. Ce type de requète doit être " -"utilisé pour les doublons, les logiciels abandonnés par l'upstream ainsi que " -"pour les paquets illégaux ou irréparables." +msgstr "En soumettant une requète de suppression, vous demandez à un utilisateur de confiance de supprimer le paquet de base. Ce type de requète doit être utilisé pour les doublons, les logiciels abandonnés par l'upstream ainsi que pour les paquets illégaux ou irréparables." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"En soumettant une requète de fusion, vous demandez à un utilisateur de " -"confiance de supprimer le paquet de base et de transférer les votes et les " -"commentaires vers un autre paquet de base. Fusionner un paquet n'impacte pas " -"le dépot Git correspondant. Assurez-vous de mettre à jour l'historique Git " -"du paquet cible vous-même." +msgstr "En soumettant une requète de fusion, vous demandez à un utilisateur de confiance de supprimer le paquet de base et de transférer les votes et les commentaires vers un autre paquet de base. Fusionner un paquet n'impacte pas le dépot Git correspondant. Assurez-vous de mettre à jour l'historique Git du paquet cible vous-même." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"En soumettant une requète pour rendre orphelin, vous demandez à un " -"utilisateur de confiance de retirer le mainteneur du paquet de base. Merci " -"de ne faire ceci que si le paquet nécessite l'action d'un mainteneur, que le " -"mainteneur ne répond pas et que vous avez préalablement essayé de contacter " -"le mainteneur." +msgstr "En soumettant une requète pour rendre orphelin, vous demandez à un utilisateur de confiance de retirer le mainteneur du paquet de base. Merci de ne faire ceci que si le paquet nécessite l'action d'un mainteneur, que le mainteneur ne répond pas et que vous avez préalablement essayé de contacter le mainteneur." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Aucune requête ne correspond à vos critères de recherche." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d paquet demandé trouvé." msgstr[1] "%d paquets demandés trouvés." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Page %d sur %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paquet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Soumise par" +#: template/pkgreq_results.php msgid "Date" msgstr "Date" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d jour restant" msgstr[1] "~%d jours restants" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d heure restante" msgstr[1] "%d heures restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "< 1 heure restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accepter" +#: template/pkgreq_results.php msgid "Locked" msgstr "Verrouillé" +#: template/pkgreq_results.php msgid "Close" msgstr "Fermer" +#: template/pkgreq_results.php msgid "Pending" msgstr "En attente" +#: template/pkgreq_results.php msgid "Closed" msgstr "Fermé" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nom, Description" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Noms seulement" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nom exact" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Paquet de base exact" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Co-mainteneurs" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Mainteneur, co-mainteneur" +#: template/pkg_search_form.php msgid "All" msgstr "Tout" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Étiqueté" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Non étiqueté" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nom" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Voté" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Dernière modification" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendant" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendant" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Saisissez les critères de recherche" +#: template/pkg_search_form.php msgid "Search by" msgstr "Rechercher par" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Périmé" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Trier par" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordre de tri" +#: template/pkg_search_form.php msgid "Per page" msgstr "Par page" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Aller" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orphelins" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erreur en récupérant la liste des paquets." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Aucun paquet ne correspond à vos critères de recherche." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquet trouvé." msgstr[1] "%d paquets trouvés." +#: template/pkg_search_results.php msgid "Version" msgstr "Version" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"La popularité est calculée à partir de la somme de tous les votes, chacun " -"étant pondéré par un facteur de %.2f par jour depuis sa création." +msgstr "La popularité est calculée à partir de la somme de tous les votes, chacun étant pondéré par un facteur de %.2f par jour depuis sa création." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Oui" +#: template/pkg_search_results.php msgid "orphan" msgstr "orphelin" +#: template/pkg_search_results.php msgid "Actions" msgstr "Actions" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Retirer l'étiquette « périmé »" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter des paquets" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonner les paquets" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Supprimer des paquets" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmer" +#: template/search_accounts_form.php msgid "Any type" msgstr "Tout type" +#: template/search_accounts_form.php msgid "Search" msgstr "Rechercher" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiques" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paquets orphelins" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paquets ajoutés au cours des 7 derniers jours" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paquets mis à jour au cours des 7 derniers jours" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paquets mis à jour dans l'année écoulée" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paquets jamais mis à jour" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilisateurs enregistrés" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Utilisateurs de confiance (TU)" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Mises à jour récentes" +#: template/stats/updates_table.php msgid "more" msgstr "plus" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mes statistiques" +#: template/tu_details.php msgid "Proposal Details" msgstr "Détails de la proposition" +#: template/tu_details.php msgid "This vote is still running." msgstr "Ce vote est toujours en cours." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Soumission: %s par %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fin" +#: template/tu_details.php msgid "Result" msgstr "Résultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Non" +#: template/tu_details.php msgid "Abstain" msgstr "Abstention" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participation" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Derniers votes de TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Dernier vote" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Aucun résultat trouvé." +#: template/tu_list.php msgid "Start" msgstr "Début" +#: template/tu_list.php msgid "Back" msgstr "Retour" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/he.po b/po/he.po index 8f6c2493..16d1196d 100644 --- a/po/he.po +++ b/po/he.po @@ -1,1589 +1,2145 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # GenghisKhan , 2016 # Lukas Fleischer , 2011 -# Yaron Shahrabani , 2016-2017 +# Yaron Shahrabani , 2016-2018 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Hebrew (http://www.transifex.com/lfleischer/aur/language/" -"he/)\n" -"Language: he\n" +"Language-Team: Hebrew (http://www.transifex.com/lfleischer/aurweb/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Language: he\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" +#: html/404.php msgid "Page Not Found" msgstr "העמוד לא נמצא" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "העמוד שביקשת אינו קיים, עמך הסליחה." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "הערה" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "כתובות שיבוט של Git לא אמורות להיפתח בדפדפן." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "כדי לשבט את מאגר ה־Git של %s, יש להפעיל את %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "יש ללחוץ %sכאן%s כדי לחזור אל הפרטים על %s." +#: html/503.php msgid "Service Unavailable" msgstr "השירות אינו זמין" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "אל בהלה! אתר זה הושבת לטובת עבודות תחזוקה. נשוב במהרה." +#: html/account.php msgid "Account" msgstr "חשבון" +#: html/account.php template/header.php msgid "Accounts" msgstr "חשבונות" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "אין לך גישה לאזור זה." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "לא ניתן לקבל נתונים עבור המשתמש שנבחר." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "אין לך הרשאה לערוך חשבון זה." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "נא להשתמש בטופס על מנת לחפש אחר חשבונות קיימים." +#: html/account.php msgid "You must log in to view user information." msgstr "עליך להיכנס על מנת לצפות בנתוני משתמש." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "הוספת הצעה" +#: html/addvote.php msgid "Invalid token for user action." msgstr "אסימון שגוי לפעולת משתמש." +#: html/addvote.php msgid "Username does not exist." msgstr "שם המשתמש לא קיים." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "ל־%s יש כבר הצעה קיימת." +#: html/addvote.php msgid "Invalid type." msgstr "סוג שגוי." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "הצעה לא יכולה להיות ריקה." +#: html/addvote.php msgid "New proposal submitted." msgstr "הצעה חדשה נשלחה." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "שליחת הצבעה עבור הפעלת הצבעה." +#: html/addvote.php msgid "Applicant/TU" msgstr "מועמד/משתמש מהימן" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(ריק אם אינה מתאימה)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "סוג" +#: html/addvote.php msgid "Addition of a TU" msgstr "הוספת משתמש מהימן" +#: html/addvote.php msgid "Removal of a TU" msgstr "הסרת משתמש מהימן" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "הסרת משתמש מהימן (חוסר פעילות בלתי מוצהרת)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "תיקון חוקי עזר" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "הצעה" +#: html/addvote.php msgid "Submit" msgstr "שליחה" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "ניהול שותפים לתחזוקה" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "עריכת תגובה" +#: html/home.php template/header.php msgid "Dashboard" msgstr "לוח בקרה" +#: html/home.php template/header.php msgid "Home" msgstr "בית" +#: html/home.php msgid "My Flagged Packages" msgstr "החבילות המסומנות שלי" +#: html/home.php msgid "My Requests" msgstr "הבקשות שלי" +#: html/home.php msgid "My Packages" msgstr "החבילות שלי" +#: html/home.php msgid "Search for packages I maintain" msgstr "חיפוש אחר חבילות בתחזוקה" +#: html/home.php msgid "Co-Maintained Packages" msgstr "חבילות בתחזוקת משנה" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "חיפוש אחר חבילה שאני מתחזק המשנה שלה" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"ברוך בואך ל־AUR, מאגר תרומות המשתמשים של ארץ׳! נא לקרוא את %sהכללים למשתמש ב־" -"AUR%s ואת %sהכללים למשתמשים מהימנים ב־AUR%s." +msgstr "ברוך בואך ל־AUR, מאגר תרומות המשתמשים של ארץ׳! נא לקרוא את %sהכללים למשתמש ב־AUR%s ואת %sהכללים למשתמשים מהימנים ב־AUR%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"הגדרות PKGBUILD שנתרמו %sחייבות%s לעמוד ב%sתקני האריזה של ארץ׳%s אחרת הן " -"תמחקנה!" +msgstr "הגדרות PKGBUILD שנתרמו %sחייבות%s לעמוד ב%sתקני האריזה של ארץ׳%s אחרת הן תמחקנה!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "לא לשכוח להצביע לחבילות המועדפות עליך!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "יתכן שחלק מהחבילות מסופקות בתור קבצים בינריים תחת [community] (קהילה)." +#: html/home.php msgid "DISCLAIMER" msgstr "הבהרה" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"חבילות AUR הן תוכן שנוצר על ידי המשתמשים. כל שימוש בקבצים שסופקו הוא על " -"אחריותך בלבד." +msgstr "חבילות AUR הן תוכן שנוצר על ידי המשתמשים. כל שימוש בקבצים שסופקו הוא על אחריותך בלבד." +#: html/home.php msgid "Learn more..." msgstr "מידע נוסף..." +#: html/home.php msgid "Support" msgstr "תמיכה" +#: html/home.php msgid "Package Requests" msgstr "בקשות חבילה" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"ישנם שלושה סוגים של בקשות שניתן להגיש בתיבה %sפעולות על חבילה%s בעמוד פרטי " -"החבילה:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "ישנם שלושה סוגים של בקשות שניתן להגיש בתיבה %sפעולות על חבילה%s בעמוד פרטי החבילה:" +#: html/home.php msgid "Orphan Request" msgstr "בקשת יתומה" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"הגשת בקשה לניתוק בעלות על חבילה, למשל כאשר המתחזק אינו פעיל והחבילה סומנה " -"כלא עדכנית במשך זמן מה." +msgstr "הגשת בקשה לניתוק בעלות על חבילה, למשל כאשר המתחזק אינו פעיל והחבילה סומנה כלא עדכנית במשך זמן מה." +#: html/home.php msgid "Deletion Request" msgstr "בקשת מחיקה" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"ניתן לבקש הסרת חבילה ממאגר המשתמשים של ארץ׳. אין להשתמש בזה אם יש תקלה " -"בחבילה וניתן לתקן אותה בקלות. במקום זאת, יש ליצור קשר עם מתחזק החבילה ולהגיש " -"בקשת יתומה אם יש צורך." +msgstr "ניתן לבקש הסרת חבילה ממאגר המשתמשים של ארץ׳. אין להשתמש בזה אם יש תקלה בחבילה וניתן לתקן אותה בקלות. במקום זאת, יש ליצור קשר עם מתחזק החבילה ולהגיש בקשת יתומה אם יש צורך." +#: html/home.php msgid "Merge Request" msgstr "בקשת מיזוג" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"הגשת בקשה למיזוג חבילה אחת לתוך חבילה אחרת. ניתן להשתמש כאשר צריך לשנות שם " -"של חבילה או להחליף אותה בחבילה מפוצלת." +msgstr "הגשת בקשה למיזוג חבילה אחת לתוך חבילה אחרת. ניתן להשתמש כאשר צריך לשנות שם של חבילה או להחליף אותה בחבילה מפוצלת." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"כדי לדון בבקשה, ניתן להשתמש בקבוצת הדיונים %saur-requests%s. עם זאת, נא לא " -"להשתמש ברשימה הזאת כדי להגיש בקשות." +msgstr "כדי לדון בבקשה, ניתן להשתמש בקבוצת הדיונים %saur-requests%s. עם זאת, נא לא להשתמש ברשימה הזאת כדי להגיש בקשות." +#: html/home.php msgid "Submitting Packages" msgstr "שליחת חבילות" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git על גבי SSH היא התשתית העדכנית להגשת חבילות ל־AUR. ניתן לעיין בסעיף " -"%sהגשת חבילות%s בעמוד Arch User Repository ב־ArchWiki לקבלת פרטים נוספים." +msgstr "Git על גבי SSH היא התשתית העדכנית להגשת חבילות ל־AUR. ניתן לעיין בסעיף %sהגשת חבילות%s בעמוד Arch User Repository ב־ArchWiki לקבלת פרטים נוספים." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "טביעות האצבע מסוג SSH הבאות נמצאות בשימוש עבור AUR:" +#: html/home.php msgid "Discussion" msgstr "דיון" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"הדיון הכללי על מאגר המשתמשים של ארץ׳ (AUR) ומבנה המשתמשים המהימנים מתנהל " -"ברשימה %saur-general%s. לדיון בנוגע לפיתוח של המנשק של AUR, יש להשתמש ברשימה " -"%saur-dev%s." +msgstr "הדיון הכללי על מאגר המשתמשים של ארץ׳ (AUR) ומבנה המשתמשים המהימנים מתנהל ברשימה %saur-general%s. לדיון בנוגע לפיתוח של המנשק של AUR, יש להשתמש ברשימה %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "דיווח על באגים" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"אם נתקלת בתקלה במנשק הדפדפן של AUR, נא להגיש דיווח על תקלה ב%sמערכת ניהול " -"התקלות%s שלנו. יש להשתמש במערכת ניהול התקלות כדי לדווח על תקלות במנשק הדפדפן " -"%sבלבד%s. כדי לדווח על תקלות עם אריזה יש ליצור קשר עם מתחזק החבילה או להשאיר " -"הערה בעמוד החבילה בהתאם." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "אם נתקלת בתקלה במנשק הדפדפן של AUR, נא להגיש דיווח על תקלה ב%sמערכת ניהול התקלות%s שלנו. יש להשתמש במערכת ניהול התקלות כדי לדווח על תקלות במנשק הדפדפן %sבלבד%s. כדי לדווח על תקלות עם אריזה יש ליצור קשר עם מתחזק החבילה או להשאיר הערה בעמוד החבילה בהתאם." +#: html/home.php msgid "Package Search" msgstr "חיפוש חבילות" +#: html/index.php msgid "Adopt" msgstr "אימוץ" +#: html/index.php msgid "Vote" msgstr "הצבעה" +#: html/index.php msgid "UnVote" msgstr "ביטול הצבעה" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "התרעה" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "ביטול התרעה" +#: html/index.php msgid "UnFlag" msgstr "ביטול סימון" +#: html/login.php template/header.php msgid "Login" msgstr "כניסה" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "נכנסת בשם: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "ניתוק" +#: html/login.php msgid "Enter login credentials" msgstr "נא להזין פרטי גישה" +#: html/login.php msgid "User name or email address" msgstr "שם משתמש או כתובת דוא״ל" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "ססמה" +#: html/login.php msgid "Remember me" msgstr "שמירת הפרטים" +#: html/login.php msgid "Forgot Password" msgstr "שכחתי את הססמה" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "כניסה באמצעות HTTP מנוטרלת. נא %sלעבור ל־HTTPs%s אם ברצונך להיכנס." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "קריטריונים לחיפוש" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "חבילות" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "ארעה שגיאה בזמן קבלת נתוני חבילה." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "שדה הכרחי חסר." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "שדות הססמה לא תואמים." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "הססמה חייבת להיות באורך של %s אותיות לפחות." +#: html/passreset.php msgid "Invalid e-mail." msgstr "כתובת דוא״ל שגויה." +#: html/passreset.php msgid "Password Reset" msgstr "איפוס ססמה" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "נא לבדוק בתיבת הדוא״ל שלך אם התקבל קישור לאישור." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "הססמה שלך התאפסה בהצלחה." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "אישור כתובת הדוא״ל שלך" +#: html/passreset.php msgid "Enter your new password:" msgstr "הזנת ססמה חדשה:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "אישור הססמה החדשה:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "המשך" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"אם שכחת את כתובת הדוא״ל בה השתמש כדי להירשם, נא לשלוח הודעה לקבוצת הדיוור " -"%saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "אם שכחת את כתובת הדוא״ל בה השתמש כדי להירשם, נא לשלוח הודעה לקבוצת הדיוור %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "נא להזין את כתובת הדוא״ל שלך:" +#: html/pkgbase.php msgid "Package Bases" msgstr "בסיסי חבילות" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "החבילות הבאות לא נותקו מבעליהן, נא לסמן את התיבה לאישור." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "לא ניתן למצוא חבילה למיזוג הצבעות ותגובות אליה." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "אי אפשר למזג בסיס חבילה עם עצמו." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "החבילות שנבחרו לא נמחקו, נא לבחור בתיבת האישור." +#: html/pkgdel.php msgid "Package Deletion" msgstr "מחיקת חבילות" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "מחיקת חבילה" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"ניתן להשתמש בטופס זה כדי למחוק את בסיס החבילה %s%s%s ואת החבילות הבאות מ־AUR:" +msgstr "ניתן להשתמש בטופס זה כדי למחוק את בסיס החבילה %s%s%s ואת החבילות הבאות מ־AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "מחיקת חבילה היא לצמיתות." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "נא לבחור את תיבת הסימון כדי לאשר את הפעולה." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "אישור מחיקת חבילה" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "מחיקה" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "רק משתמשים מהימנים ומפתחים יכולים למחוק חבילות." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "ניתוק בעלות על חבילה" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"ניתן להשתמש בטופס זה כדי לשלול את הבעלות על בסיס החבילה %s%s%s שכוללת את " -"החבילות הבאות:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "ניתן להשתמש בטופס זה כדי לשלול את הבעלות על בסיס החבילה %s%s%s שכוללת את החבילות הבאות:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"על ידי סימון תיבת הבחירה, ניתן אישורך לניתוק הבעלות על חבילה והעברת הבעלות " -"אל %s%s%s." +msgstr "על ידי סימון תיבת הבחירה, ניתן אישורך לניתוק הבעלות על חבילה והעברת הבעלות אל %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "על ידי סימון תיבת הבחירה, נתת את אישורך לניתוק הבעלות על חבילה." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "אישור ניתוק בעלות החבילה" +#: html/pkgdisown.php msgid "Disown" msgstr "ניתוק בעלות" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "רק משתמשים מהימנים ומפתחים יכולים לנתק בעלות של חבילות." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "סימון התגובה" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "סימון תגובה כבלתי עדכנית" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"יש להשתמש בטופס זה כדי לסמן את בסיס החבילה %s%s%s ואת החבילות הבאות לבלתי " -"עדכניות:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "יש להשתמש בטופס זה כדי לסמן את בסיס החבילה %s%s%s ואת החבילות הבאות לבלתי עדכניות:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"נא %sלא%s להשתמש בטופס הזה כדי לדווח על תקלות. יש להשתמש בהערות החבילה במקום." +msgstr "נא %sלא%s להשתמש בטופס הזה כדי לדווח על תקלות. יש להשתמש בהערות החבילה במקום." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"נא להזין את הפרטים על מדוע החבילה אינה בתוקף, מומלץ להוסיף קישורים להכרזות " -"המתאימות או לקובצי הגרסה העדכנית." +msgstr "נא להזין את הפרטים על מדוע החבילה אינה בתוקף, מומלץ להוסיף קישורים להכרזות המתאימות או לקובצי הגרסה העדכנית." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "תגובות" +#: html/pkgflag.php msgid "Flag" msgstr "סימון" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "רק משתמשים רשומים יכולים לסמן חבילות כפגות תוקף." +#: html/pkgmerge.php msgid "Package Merging" msgstr "מיזוג חבילות" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "מיזוג חבילה" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "ניתן להשתמש בטופס זה כדי למזג את בסיס החבילה %s%s%s לתוך חבילה אחרת." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "החבילות הבאות תימחקנה:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "לאחר מיזוג החבילות לא ניתן לחזור אחורה בתהליך." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "נא להזין את שם החבילה שאליה ברצונך למזג את החבילה." +#: html/pkgmerge.php msgid "Merge into:" msgstr "מיזוג לתוך:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "אימות מיזוג חבילה" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "מיזוג" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "רק משתמשים מהימנים ומפתחים יכולים למזג חבילות." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "שליחת בקשה" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "סגירת בקשה" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "ראשון" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "הקודם" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "הבא" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "אחרון" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "בקשות" +#: html/register.php template/header.php msgid "Register" msgstr "הרשמה" +#: html/register.php msgid "Use this form to create an account." msgstr "ניתן להשתמש בטופס זה על מנת ליצור חשבון." +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "תנאי השירות" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "המסמכים הבאים עודכנו. נא לסקור אותם בקפידה:" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "מהדורה %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "התנאים שלעיל מקובלים עלי." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "משתמש מהימן" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "לא ניתן לקבל נתוני הצעה." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "ההצבעה סגורה עבור הצעה זו." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "רק משתמשים מהימנים מורשים להצביע." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "אין באפשרותך להצביע עבור הצעה הקשורה בך." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "כבר הצבעת עבור הצעה זו." +#: html/tu.php msgid "Vote ID not valid." msgstr "מס׳ הזיהוי של ההצבעה אינו תקין." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "קולות נוכחיים" +#: html/tu.php msgid "Past Votes" msgstr "קולות עבר" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "מצביעים" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"הרשמה לחשבון הושבתה לכתובת ה־IP שלך עקב מתקפות זבל מתמשכות. אנו מתנצלים על " -"אי הנוחות." +msgstr "הרשמה לחשבון הושבתה לכתובת ה־IP שלך עקב מתקפות זבל מתמשכות. אנו מתנצלים על אי הנוחות." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "מס׳ הזיהוי של המשתמש חסר" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "שם המשתמש אינו חוקי." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "חייב להיות בין %s ל־%s אותיות" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "יש להתחיל ולסיים עם תו או מספר" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "יכול הכיל רק נקודה אחת, קו תחתון או מקף." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "כתובת הדוא״ל שהוזנה אינה תקינה." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "דף הבית שגוי, נא לציין את כתובת ה־HTTP(s) המלאה." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "טביעת האצבע מסוג PGP שגויה." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "מפתח ה־SSH הציבורי שגוי." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "לא ניתן להגדיל את הרשאות החשבון." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "השפה אינה נתמכת כרגע." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "אין תמיכה באזור זמן נכון לעכשיו." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "שם המשתמש, %s%s%s, כבר נמצא בשימוש." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "הכתובת, %s%s%s, כבר נמצאת בשימוש." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "מפתח ה־SSH הציבורי, %s%s%s, כבר נמצא בשימוש." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "אירעה שגיאה בניסיון ליצירת חשבון, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "החשבון, %s%s%s, נוצר בהצלחה." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "מפתח איפוס ססמה נשלח לכתובת הדוא״ל שלך." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "נא ללחוץ על קישור הכניסה להלן כדי להשתמש בחשבון שלך." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "לא בוצעו שינויים בחשבון, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "החשבון, %s%s%s, השתנה בהצלחה." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"כתובת הכניסה מנוטרלת לכתובת ה־ IP שלך, כנראה עקב מתקפות ספאם מתמשכות. אנו " -"מתנצלים על אי הנוחות." +msgstr "כתובת הכניסה מנוטרלת לכתובת ה־ IP שלך, כנראה עקב מתקפות ספאם מתמשכות. אנו מתנצלים על אי הנוחות." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "חשבון מושעה" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"הססמה שלך עברה איפוס. אם הרגע יצרת חשבון חדש, נא להשתמש בקישור מהודעת האימות " -"כדי להגדיר ססמה ראשונית. בכל מצב אחר, נא לבקר מפתח איפוס בעמוד %sאיפוס ססמה" -"%s." +msgstr "הססמה שלך עברה איפוס. אם הרגע יצרת חשבון חדש, נא להשתמש בקישור מהודעת האימות כדי להגדיר ססמה ראשונית. בכל מצב אחר, נא לבקר מפתח איפוס בעמוד %sאיפוס ססמה%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "שם המשתמש או הססמה שגויים." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "אירעה שגיאה בעת הניסיון ליצירת הפעלת משתמש." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "השילוב בין כתובת דוא״ל למפתח איפוס שגוי." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "ללא" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "הצגת פרטי החשבון %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "מזהה בסיס החבילה או שם בסיס החבילה חסר." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "אין לך הרשאה לערוך את התגובה הזו." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "התגובה אינה קיימת." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "התגובה לא יכולה להישאר ריקה." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "נוספה תגובה." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "עליך להיכנס לפני שיהיה באפשרותך לערוך נתוני חבילה." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "חסר מס׳ זיהוי להערה." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "אי אפשר להצמיד למעלה מ־5 תגובות." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "אין לך הרשאה להצמיד תגובה זו." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "אין לך הרשה לבטל את ההצמדה של תגובה זו." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "התגובה הוצמדה." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "הצמדת התגובה בוטלה." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "שגיאה בקבלת נתוני חבילה." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "נתוני חבילה לא נמצאו." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לסמן חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "לא בחרת שום חבילות לסימון." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "החבילות הנבחרות לא סומנו, נא לכתוב תגובה." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "החבילות שנבחרו מסומנות כלא עדכניות." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "עליך להתחבר לפני שיהיה באפשרותך לבטל סימוני חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "לא בחרת שום חבילות לביטול סימון." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "החבילות שנבחרו בוטלו מהסימון." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "אין לך הרשאה למחוק חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "לא בחרת שום חבילות למחיקה." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "החבילות המסומנות נמחקו." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לאמץ חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "עליך להיכנס לפני שיהיה באפשרותך לנתק בעלות על חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "לא בחרת שום חבילות לאימוץ." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "לא בחרת שום חבילות לניתוק בעלותך מהן." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "החבילות שנבחרו אומצו." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "החבילות המסומנות ננטשו על ידי בעליהן." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "עליך להיכנס לפני שתהיה באפשרותך להצביע לחבילות." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "עליך להתחבר לפני ביטול הצבעה עבור חבילות." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "לא בחרת שום חבילות להצביע עבורן." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "ההצבעות שלך הוסרו מהחבילות המסומנות." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "ההצבעות שלך נקלטו עבור החבילות המסומנות." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "לא ניתן לצרף את רשימת ההתרעות." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "צורפת אל רשימת ההתרעות עבור %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "הוסרת מרשימה ההתרעות עבור ההערות של %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "אין לך הרשאה לשחזר את התגובה הזו." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "התגובה שוחזרה." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "אין לך הרשאה למחוק הערה זו." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "הערה נמחקה." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "התגובה נערכה." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "אין לך הרשאה לערוך את מילות המפתח של בסיס חבילה זו." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "מילות המפתח של בסיס החבילה עודכנו." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "אין לך הרשאה לנהל את מתחזקי המשנה לבסיס חבילה זה." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "שם משתמש שגוי: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "מתחזקי המשנה של בסיס החבילה עודכנו." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "הצגת פרטי החבילה עבור" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "דורשת את %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "עליך להיכנס כדי להגיש בקשות חבילה." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "שם לא חוקי: רק אותיות קטנות מותרות." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "שדה התגובה לא יכול להישאר ריק." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "סוג הבקשה שגוי." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "התגובה נוספה בהצלחה." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "הסיבה שגויה." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "רק משתמשים מהימנים ומפתחים יכולים לסגור בקשות." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "הבקשה נסגרה בהצלחה." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "ניתן להשתמש בטופס זה כדי למחוק את חשבון ה־AUR בשם %s לצמיתות." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sאזהרה%s: לא ניתן לחזור בך מפעולה זו." +#: template/account_delete.php msgid "Confirm deletion" msgstr "אימות מחיקה" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "שם משתמש" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "סוג חשבון" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "משתמש" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "מפתח" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "משתמש מהימן ומפתח" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "כתובת דוא״ל" +#: template/account_details.php msgid "hidden" msgstr "מוסתר" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "שם אמתי" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "עמוד הבית" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "כינוי IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "טביעת אצבע מסוג PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "מצב" +#: template/account_details.php msgid "Inactive since" msgstr "אין פעילות מאז" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "פעיל" +#: template/account_details.php msgid "Registration date:" msgstr "תאריך ההרשמה:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "לא מוכר" +#: template/account_details.php msgid "Last Login" msgstr "כניסה אחרונה" +#: template/account_details.php msgid "Never" msgstr "לעולם" +#: template/account_details.php msgid "View this user's packages" msgstr "צפייה בחבילות המשתמש" +#: template/account_details.php msgid "Edit this user's account" msgstr "עריכת החשבון של משתמש זה" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "נא ללחוץ %sכאן%s אם רצונך הוא למחוק את החשבון הזה לצמיתות." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "יש ללחוץ %sכאן%s לפרטים על המשתמש." +#: template/account_edit_form.php msgid "required" msgstr "נדרש" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" +msgstr "שם המשתמש שלך הוא השם שישמש אותך לכניסה למערכת. הוא גלוי לכלל, אפילו לאחר השבתת חשבונך." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "משתמש רגיל" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "משתמשים אמינים" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "חשבון מושעה" +#: template/account_edit_form.php msgid "Inactive" msgstr "בלתי פעיל" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "נא לוודא שהזנת את כתובת הדוא״ל שלך כראוי, אחרת חשבונך יינעל." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "הסתרת כתובת דוא״ל" +#: template/account_edit_form.php msgid "Re-type password" msgstr "הקלדת הססמה מחדש" +#: template/account_edit_form.php msgid "Language" msgstr "שפה" +#: template/account_edit_form.php msgid "Timezone" msgstr "אזור זמן" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "המידע הבא נחוץ רק אם ברצונך להגיש חבילות למאגר החבילות של ארץ׳." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "מפתח SSH ציבורי" +#: template/account_edit_form.php msgid "Notification settings" msgstr "הגדרות התרעה" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "להודיע לי על תגובות חדשות" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "להודיע לי ל עדכונים בחבילה" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "להודיע לי על שינויים בבעלות" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "עדכון" +#: template/account_edit_form.php msgid "Create" msgstr "יצירה" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "איפוס" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "אין תוצאות עבור נתוני החיפוש שלך." +#: template/account_search_results.php msgid "Edit Account" msgstr "עריכת חשבון" +#: template/account_search_results.php msgid "Suspended" msgstr "השעייה" +#: template/account_search_results.php msgid "Edit" msgstr "עריכה" +#: template/account_search_results.php msgid "Less" msgstr "פחות" +#: template/account_search_results.php msgid "More" msgstr "עוד" +#: template/account_search_results.php msgid "No more results to display." msgstr "אין יותר תוצאות להצגה." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"ניתן להשתמש בטופס זה כדי להוסיף מתחזקי משנה %s%s%s (שם משתמש אחד בשורה):" +msgstr "ניתן להשתמש בטופס זה כדי להוסיף מתחזקי משנה %s%s%s (שם משתמש אחד בשורה):" +#: template/comaintainers_form.php msgid "Users" msgstr "משתמשים" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "שמירה" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "הערת סימון כלא עדכנית: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" +msgstr "%s%s%s סומנה בדגל %s%s%s כבלתי עדכנית %s%s%s מהסיבה הבאה:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s אינה מסומנת כפגת תוקף." +#: template/flag_comment.php msgid "Return to Details" msgstr "חזרה לפרטים" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "כל הזכויות שמורות %s 2004-%d לצוות הפיתוח של aurweb." +#: template/header.php msgid " My Account" msgstr "החשבון שלי" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "פעולות חבילה" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "הצגת ה־PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "הצגת השינויים" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "הורדת לכידה עדכנית" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "חיפוש בוויקי" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "סימון כלא עדכנית (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "סימון החבילה כבלתי עדכנית" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "ביטול סימון חבילה" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "הסרת הצבעה" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "להצביע לחבילה זו" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "נטרול התרעות" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "הפעלת התרעות" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "ניהול מתחזקי משנה" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "בקשה %d ממתינה" msgstr[1] "%d בקשות ממתינות" +msgstr[2] "%d בקשות ממתינות" +msgstr[3] "%d בקשות ממתינות" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "אימוץ חבילה" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "פרטי בסיס החבילה" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "כתובת השכפול מ־Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "לקריאה בלבד" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "מילות מפתח" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "מגיש" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "מתחזק" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "נארז לאחרונה ע״י" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "הצבעות" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "פופולריות" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "נשלחה לראשונה" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "עדכון אחרון" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "עריכת תגובה עבור: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "הוספת תגובה" +#: template/pkg_comments.php msgid "View all comments" msgstr "הצגת כל התגובות" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "תגובות נעוצות" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "התגובות האחרונות" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "נכתבה תגובה ע״י %s על %s" +msgstr "נכתבה תגובה ע״י %s ב־%s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" -msgstr "תגובה אלמונית על %s" +msgstr "תגובה אלמונית ב־%s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "נמחקה ב־%s ע״י %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "נמחקה ב־%s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "נערכה בתאריך %s ע״י %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "נערכה ב־%s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "ביטול מחיקת התגובה" +#: template/pkg_comments.php msgid "Delete comment" msgstr "מחיקת הערה" +#: template/pkg_comments.php msgid "Pin comment" msgstr "הצמדת התגובה" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "ביטול הצמדת התגובה" +#: template/pkg_comments.php msgid "All comments" msgstr "כל התגובות" +#: template/pkg_details.php msgid "Package Details" msgstr "נתוני חבילה" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "בסיס החבילה" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "תיאור" +#: template/pkg_details.php msgid "Upstream URL" msgstr "כתובת מאגר המקור" +#: template/pkg_details.php msgid "Visit the website for" msgstr "ביקור באתר של" +#: template/pkg_details.php msgid "Licenses" msgstr "רישיונות" +#: template/pkg_details.php msgid "Groups" msgstr "קבוצות" +#: template/pkg_details.php msgid "Conflicts" msgstr "התנגשויות" +#: template/pkg_details.php msgid "Provides" msgstr "מספקת" +#: template/pkg_details.php msgid "Replaces" msgstr "מחליפה" +#: template/pkg_details.php msgid "Dependencies" msgstr "תלויות" +#: template/pkg_details.php msgid "Required by" msgstr "נדרשת על ידי" +#: template/pkg_details.php msgid "Sources" msgstr "מקורות" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "ניתן להשתמש בטופס זה כדי לסגור את הבקשה לבסיס החבילה %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"שדה ההערות יכול להישאר ריק. עם זאת, מומלץ מאוד להוסיף הערה כשדוחים בקשה." +msgstr "שדה ההערות יכול להישאר ריק. עם זאת, מומלץ מאוד להוסיף הערה כשדוחים בקשה." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "סיבה" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "התקבל" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "נדחה" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"ניתן להשתמש בטופס זה כדי להגיש את הבקשה לבסיס החבילה %s%s%s שכולל את החבילות " -"הבאות:" +msgstr "ניתן להשתמש בטופס זה כדי להגיש את הבקשה לבסיס החבילה %s%s%s שכולל את החבילות הבאות:" +#: template/pkgreq_form.php msgid "Request type" msgstr "סוג הבקשה" +#: template/pkgreq_form.php msgid "Deletion" msgstr "מחיקה" +#: template/pkgreq_form.php msgid "Orphan" msgstr "יתומה" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "מיזוג לתוך" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"בהגשת בקשה למחיקה, משתמש מהימן ישקול אם למחוק בסיס חבילה. סוג כזה של בקשה " -"יכול לשמש במקרים של כפילויות, תכנית שנזנחה במקור לצד חבילה בלתי חוקית או " -"שבורה באופן שלא ניתן לשקם." +msgstr "בהגשת בקשה למחיקה, משתמש מהימן ישקול אם למחוק בסיס חבילה. סוג כזה של בקשה יכול לשמש במקרים של כפילויות, תכנית שנזנחה במקור לצד חבילה בלתי חוקית או שבורה באופן שלא ניתן לשקם." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"הגשת בקשת מיזוג מופנית למשתמש מהימן לטובת מחיקת בסיס חבילה והעברת ההצבעות " -"וההערות שלו לבסיס חבילה אחר. מיזוג חבילה לא משפיע על מאגרי ה־Git הקשורים " -"אליו. יש לוודא שעדכנת את היסטוריית ה־Git של חבילת היעד בעצמך." +msgstr "הגשת בקשת מיזוג מופנית למשתמש מהימן לטובת מחיקת בסיס חבילה והעברת ההצבעות וההערות שלו לבסיס חבילה אחר. מיזוג חבילה לא משפיע על מאגרי ה־Git הקשורים אליו. יש לוודא שעדכנת את היסטוריית ה־Git של חבילת היעד בעצמך." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"הגשת בקשת יתומה מופנית למשתמש מהימן לטובת ביטול שייכות בסיס חבילה. נא להגיש " -"בקשה זו רק אם החבילה דורשת פעולת תחזוקה, המתחזק אינו זמין וכבר ניסית ליצור " -"קשר עם המתחזק בעבר." +msgstr "הגשת בקשת יתומה מופנית למשתמש מהימן לטובת ביטול שייכות בסיס חבילה. נא להגיש בקשה זו רק אם החבילה דורשת פעולת תחזוקה, המתחזק אינו זמין וכבר ניסית ליצור קשר עם המתחזק בעבר." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "אין בקשות שתואמות את תנאי החיפוש שלך." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "נמצאה בקשה אחת (%d) לחבילה." msgstr[1] "נמצאו %d בקשות לחבילות." +msgstr[2] "נמצאו %d בקשות לחבילות." +msgstr[3] "נמצאו %d בקשות לחבילות." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "עמוד %d מתוך %d." +#: template/pkgreq_results.php msgid "Package" msgstr "חבילה" +#: template/pkgreq_results.php msgid "Filed by" msgstr "הוגש ע״י" +#: template/pkgreq_results.php msgid "Date" msgstr "תאריך" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "נותר ~%d אחד" msgstr[1] "נותרו ~%d ימים" +msgstr[2] "נותרו ~%d ימים" +msgstr[3] "נותרו ~%d ימים" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "נותרה שעה ~%d" msgstr[1] "~%d שעות נותרו" +msgstr[2] "~%d שעות נותרו" +msgstr[3] "~%d שעות נותרו" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "נותרה פחות משעה" +#: template/pkgreq_results.php msgid "Accept" msgstr "קבלה" +#: template/pkgreq_results.php msgid "Locked" msgstr "ננעל" +#: template/pkgreq_results.php msgid "Close" msgstr "סגירה" +#: template/pkgreq_results.php msgid "Pending" msgstr "בהמתנה" +#: template/pkgreq_results.php msgid "Closed" msgstr "סגור" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "שם, תיאור" +#: template/pkg_search_form.php msgid "Name Only" msgstr "שם בלבד" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "שם מדויק" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "בסיס החבילה המדויק" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "מתחזק משנה" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "מתחזק, מתחזק משנה" +#: template/pkg_search_form.php msgid "All" msgstr "הכול" +#: template/pkg_search_form.php msgid "Flagged" msgstr "מסומנת" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "לא מסומנת" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "שם" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "הצביעו" +#: template/pkg_search_form.php msgid "Last modified" msgstr "מועד שינוי אחרון" +#: template/pkg_search_form.php msgid "Ascending" msgstr "עולה" +#: template/pkg_search_form.php msgid "Descending" msgstr "יורד" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "נא להזין תנאי חיפוש" +#: template/pkg_search_form.php msgid "Search by" msgstr "חיפוש לפי" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "לא עדכני" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "סידור לפי" +#: template/pkg_search_form.php msgid "Sort order" msgstr "סדר המיון" +#: template/pkg_search_form.php msgid "Per page" msgstr "לפי דף" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "מעבר" +#: template/pkg_search_form.php msgid "Orphans" msgstr "יתומות" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "שגיאה בעת קבלת רשימת החבילות." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "אין חבילות התואמות לנתוני החיפוש שלך." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "נמצאה חבילה %d." msgstr[1] "נמצאו %d חבילות." +msgstr[2] "נמצאו %d חבילות." +msgstr[3] "נמצאו %d חבילות." +#: template/pkg_search_results.php msgid "Version" msgstr "גרסה" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"הפופולריות מחושבת כסכום של כל ההצבעות כאשר כל הצבעה נשקלת עם מקדם של %.2f " -"ליום מאז שנוצרה." +msgstr "הפופולריות מחושבת כסכום של כל ההצבעות כאשר כל הצבעה נשקלת עם מקדם של %.2f ליום מאז שנוצרה." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "כן" +#: template/pkg_search_results.php msgid "orphan" msgstr "יתומה" +#: template/pkg_search_results.php msgid "Actions" msgstr "פעולות" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "ביטול סימון כלא מעודכן" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "אימוץ חבילות" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "ניתוק בעלות על חבילות" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "מחיקת חבילות" +#: template/pkg_search_results.php msgid "Confirm" msgstr "אישור" +#: template/search_accounts_form.php msgid "Any type" msgstr "כל סוג" +#: template/search_accounts_form.php msgid "Search" msgstr "חיפוש" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "סטטיסטיקות" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "חבילות יתומות" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "חבילות שנוספו בשבוע החולף" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "חבילות שעודכנו בשבוע החולף" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "חבילות שעודכנו בשנה החולפת" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "חבילות שלא עודכנו מעולם" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "משתמשים רשומים" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "משתמשים מהימנים" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "עדכונים אחרונים" +#: template/stats/updates_table.php msgid "more" msgstr "עוד" +#: template/stats/user_table.php msgid "My Statistics" msgstr "הסטטיסטיקות שלי" +#: template/tu_details.php msgid "Proposal Details" msgstr "פרטי הצעה" +#: template/tu_details.php msgid "This vote is still running." msgstr "ההצבעה עדיין קיימת." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "נשלח: %s על ידי %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "סוף" +#: template/tu_details.php msgid "Result" msgstr "תוצאה" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "לא" +#: template/tu_details.php msgid "Abstain" msgstr "הימנעות" +#: template/tu_details.php msgid "Total" msgstr "סך הכול" +#: template/tu_details.php msgid "Participation" msgstr "השתתפות" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "הצבעות אחרונות של משתמשים מהימנים" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "הצבעה אחרונה" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "לא נמצאו תוצאות." +#: template/tu_list.php msgid "Start" msgstr "התחלה" +#: template/tu_list.php msgid "Back" msgstr "חזרה" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/hr.po b/po/hr.po index 586507bc..56a101d6 100644 --- a/po/hr.po +++ b/po/hr.po @@ -1,655 +1,847 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Lukas Fleischer , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Croatian (http://www.transifex.com/lfleischer/aur/language/" -"hr/)\n" -"Language: hr\n" +"Language-Team: Croatian (http://www.transifex.com/lfleischer/aurweb/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"Language: hr\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +#: html/404.php msgid "Page Not Found" msgstr "" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "" +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "" +#: html/account.php template/header.php msgid "Accounts" msgstr "Računi" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nije vam dozvoljen pristup ovom području." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nije moguće naći informacije o zadanom korisniku." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemate ovlasti da bi mjenjali ovaj račun." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Koristite ovaj formular za pretraživanj postoječih računa." +#: html/account.php msgid "You must log in to view user information." msgstr "Morate se logirati kako bi pregledali informacije o korisniku." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "" +#: html/addvote.php msgid "Invalid token for user action." msgstr "" +#: html/addvote.php msgid "Username does not exist." msgstr "Korisničko ime ne postoji." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s već ima prijedlog." +#: html/addvote.php msgid "Invalid type." msgstr "" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Prijedlog nemože biti prazan." +#: html/addvote.php msgid "New proposal submitted." msgstr "Novi prijedlog je poslan." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Pošalji prijedlog za glasanje." +#: html/addvote.php msgid "Applicant/TU" msgstr "" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prazno ako nije prikladno)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tip" +#: html/addvote.php msgid "Addition of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU" msgstr "" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Prijedlog" +#: html/addvote.php msgid "Submit" msgstr "Pošalji" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Početna" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Moji paketi" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." msgstr "" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "" +#: html/home.php msgid "DISCLAIMER" msgstr "" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Rasprava" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "" +#: html/index.php msgid "Adopt" msgstr "" +#: html/index.php msgid "Vote" msgstr "Glasaj" +#: html/index.php msgid "UnVote" msgstr "Makni glas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Obavijesti" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne obavještavaj" +#: html/index.php msgid "UnFlag" msgstr "" +#: html/login.php template/header.php msgid "Login" msgstr "Login" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Logirani ste kao: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Logout" +#: html/login.php msgid "Enter login credentials" msgstr "" +#: html/login.php msgid "User name or email address" msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" +#: html/login.php msgid "Remember me" msgstr "Zapamti me" +#: html/login.php msgid "Forgot Password" msgstr "" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kriteriji traženja" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketi" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Došlo je do greške prilikom dobivanja detalja o paketu." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Nedostaje Vam obvezno polje." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Lozinke nisu jednake." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Lozinka mora sadržavati najmanje %s znakova." +#: html/passreset.php msgid "Invalid e-mail." msgstr "" +#: html/passreset.php msgid "Password Reset" msgstr "" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "" +#: html/passreset.php msgid "Enter your new password:" msgstr "" +#: html/passreset.php msgid "Confirm your new password:" msgstr "" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." msgstr "" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "" +#: html/pkgdel.php msgid "Package Deletion" msgstr "" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "" +#: html/pkgflag.php msgid "Flag" msgstr "" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "" +#: html/pkgmerge.php msgid "Merge into:" msgstr "" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sljedeći" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "" +#: html/register.php template/header.php msgid "Register" msgstr "" +#: html/register.php msgid "Use this form to create an account." msgstr "Koristite ovaj formular za kreiranje računa." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Pouzdan korisnik" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nemogu pronaći detalje o prijedlogu." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Glasanje je zaključeno za ovaj prijedlog" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemožete glasati o prijedlogu koji se tiće Vas." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Već ste glasali za ovaj prijedlog." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID glasa je neispravan." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Trenutno glasova" +#: html/tu.php msgid "Past Votes" msgstr "" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Nedostaje ID korisnika" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Korisničko ime je neispravno." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Mora biti najmanje %s a najviše %s znakova" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Zapični i završi sa slovom ili brojkom" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržavati samo jednu točku, donju crticu ili povlaku." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Email adresa je neispravna." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "" +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "" +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." msgstr "" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " @@ -657,439 +849,590 @@ msgid "" "please request a reset key on the %sPassword Reset%s page." msgstr "" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentar je dodan." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Morate biti logirani da biste mogli mijenjati informacije o paketu." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Nedostaje ID komentara." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Došlo je do greške prilikom preuzimanja detalja o paketu." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nije moguće naći detalje o paketu." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Morate se logirati da bi obilježavali pakete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Niste odabrali pakete koje želite obilježiti." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Odabrani paketi su obilježeni kao zastarijeli." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Morate se logirati da bi mogli obilježiti pakete kao ažurirane." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Niste odabrali pakete koje želite obilježiti kao ažurirane." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Odabrani paketu su postavljeni kao ažurirani." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Niste odabrali pakete koje želite izbrisati." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Odabrani paketi su izbrisani." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Morate se logirati da bi posvojili pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Morate se logirati da bi se mogli odreknuti paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Niste odabrali pakete koje želite posvojiti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Niste odabrali pakete kojih se želite odreči." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Posvojili ste odabrane pakete." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Odrekli ste se odabranih paketa." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Morate se logirati da bi glasali za pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Morate se logirati da bi mogli maknuti svoje glasove s paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Niste odabrali pakete za koje želite glasati." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaši su glasovi maknuti s odabranih paketa." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Glasovi su dodijeljeni odabranim paketima." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nemogu dodati u listu za obavještavanje." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Dodani ste u listu za obavještavanje o novim komentarima za %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Niste više na listi za obavježtavanje o novim komentarima za %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Brisanje ovog komentara Vam nije dozvoljeno." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentar je izbrisan." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neispravno ime: Dozvoljena su samo mala slova (kurenti)." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Korisničko ime" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip računa" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Korisnik" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Developer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Email adresa" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Vaše stvarno ime" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nadimak na IRC-u" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stanje" +#: template/account_details.php msgid "Inactive since" msgstr "" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivan" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "nepoznato" +#: template/account_details.php msgid "Last Login" msgstr "" +#: template/account_details.php msgid "Never" msgstr "Nikad" +#: template/account_details.php msgid "View this user's packages" msgstr "Pregledaj pakete ovog korisnika" +#: template/account_details.php msgid "Edit this user's account" msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "obvezno" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Običan korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Pouzdan korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Račun je suspendiran" +#: template/account_edit_form.php msgid "Inactive" msgstr "" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Ponovno upišite lozinku" +#: template/account_edit_form.php msgid "Language" msgstr "Jezik" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Ažuriraj" +#: template/account_edit_form.php msgid "Create" msgstr "Kreiraj" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetiraj" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nema rezultata pretrage." +#: template/account_search_results.php msgid "Edit Account" msgstr "Podesi račun" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendiran" +#: template/account_search_results.php msgid "Edit" msgstr "" +#: template/account_search_results.php msgid "Less" msgstr "Manje" +#: template/account_search_results.php msgid "More" msgstr "Više" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nema više rezultata za prikaz." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1097,178 +1440,238 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Održavatelj" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Glasovi" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvi put poslan" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Posljednji put ažuriran" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "" +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Briši komentar" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalji o paketu" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "" +#: template/pkg_details.php msgid "Visit the website for" msgstr "" +#: template/pkg_details.php msgid "Licenses" msgstr "" +#: template/pkg_details.php msgid "Groups" msgstr "" +#: template/pkg_details.php msgid "Conflicts" msgstr "" +#: template/pkg_details.php msgid "Provides" msgstr "" +#: template/pkg_details.php msgid "Replaces" msgstr "" +#: template/pkg_details.php msgid "Dependencies" msgstr "Ovisi o" +#: template/pkg_details.php msgid "Required by" msgstr "Potreban za" +#: template/pkg_details.php msgid "Sources" msgstr "Izvor" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "" +#: template/pkgreq_form.php msgid "Request type" msgstr "" +#: template/pkgreq_form.php msgid "Deletion" msgstr "" +#: template/pkgreq_form.php msgid "Orphan" msgstr "" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1276,6 +1679,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1283,9 +1687,11 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1293,19 +1699,24 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "" +#: template/pkgreq_results.php msgid "Package" msgstr "" +#: template/pkgreq_results.php msgid "Filed by" msgstr "" +#: template/pkgreq_results.php msgid "Date" msgstr "" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" @@ -1313,6 +1724,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1320,96 +1732,128 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "" +#: template/pkgreq_results.php msgid "Accept" msgstr "" +#: template/pkgreq_results.php msgid "Locked" msgstr "" +#: template/pkgreq_results.php msgid "Close" msgstr "" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "" +#: template/pkg_search_form.php msgid "Name Only" msgstr "" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "" +#: template/pkg_search_form.php msgid "Flagged" msgstr "" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Ime" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Glasao" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "" +#: template/pkg_search_form.php msgid "Descending" msgstr "" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "" +#: template/pkg_search_form.php msgid "Search by" msgstr "Traži po" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastario" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortiraj po" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Način sortiranja" +#: template/pkg_search_form.php msgid "Per page" msgstr "Po stranici" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Traži" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Napušteni" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Došlo je do greške prilikom stvaranja liste paketa." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nijedan paket ne odgovara kriterijima traženja." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1417,117 +1861,278 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkg_search_results.php msgid "Version" msgstr "" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Da" +#: template/pkg_search_results.php msgid "orphan" msgstr "napušten" +#: template/pkg_search_results.php msgid "Actions" msgstr "Radnje" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Obilježi kao ažuriran" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Posvoji paket" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odrekni se paketa" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Izbriši pakete" +#: template/pkg_search_results.php msgid "Confirm" msgstr "" +#: template/search_accounts_form.php msgid "Any type" msgstr "Bilo koji tip" +#: template/search_accounts_form.php msgid "Search" msgstr "Traži" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalji prijedloga" +#: template/tu_details.php msgid "This vote is still running." msgstr "Ovaj glas još vrijedi." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Poslan: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Kraj" +#: template/tu_details.php msgid "Result" msgstr "" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" +#: template/tu_details.php msgid "Abstain" msgstr "Suzdržan" +#: template/tu_details.php msgid "Total" msgstr "Ukupno" +#: template/tu_details.php msgid "Participation" msgstr "" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nema rezultata." +#: template/tu_list.php msgid "Start" msgstr "Početak" +#: template/tu_list.php msgid "Back" msgstr "Natrag" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/hu.po b/po/hu.po index 409f0805..8dd39982 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Balló György , 2013 # Balló György , 2011,2013-2016 @@ -9,1621 +9,2128 @@ # Lukas Fleischer , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Hungarian (http://www.transifex.com/lfleischer/aur/language/" -"hu/)\n" -"Language: hu\n" +"Language-Team: Hungarian (http://www.transifex.com/lfleischer/aurweb/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Az oldal nem található" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Sajnálom, a megtekinteni kívánt oldal nem létezik." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Megjegyzés" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "Szolgáltatás nem elérhető" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Nyugalom! Ez a webhely karbantartás miatt nem üzemel. Hamarosan visszajövünk." +msgstr "Nyugalom! Ez a webhely karbantartás miatt nem üzemel. Hamarosan visszajövünk." +#: html/account.php msgid "Account" msgstr "Fiók" +#: html/account.php template/header.php msgid "Accounts" msgstr "Fiókok" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nincs engedélyed hozzáférni ehhez a területhez." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nem sikerült letölteni a megadott felhasználó információit." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nincs engedélyed ennek a fióknak a szerkesztéséhez." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Már meglévő felhasználói fiókok kereséséhez használd ezt az űrlapot." +#: html/account.php msgid "You must log in to view user information." msgstr "A felhasználói információ megtekintéshez be kell jelentkezned." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Indítvány hozzáadása" +#: html/addvote.php msgid "Invalid token for user action." msgstr "A token érvénytelen a felhasználói művelethez." +#: html/addvote.php msgid "Username does not exist." msgstr "Ez a felhasználói név nem létezik." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s már megpályázta őket." +#: html/addvote.php msgid "Invalid type." msgstr "Érvénytelen típus." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Az indítvány nem lehet üres." +#: html/addvote.php msgid "New proposal submitted." msgstr "Új indítvány benyújtva." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Indítvány szavazásra bocsátása." +#: html/addvote.php msgid "Applicant/TU" msgstr "Jelölt/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(üres, ha nem alkalmazható)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Típus" +#: html/addvote.php msgid "Addition of a TU" msgstr "TU hozzáadása" +#: html/addvote.php msgid "Removal of a TU" msgstr "TU eltávolítása" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU eltávolítása (be nem jelentett inaktivitás)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Szabályzat módosítása" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Indítvány" +#: html/addvote.php msgid "Submit" msgstr "Feltöltés" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Társkarbantartók kezelése" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Hozzászólás szerkesztése" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Honlap" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Csomagjaim" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Üdvözlünk az AUR-ban! További információért olvasd el az %sAUR felhasználói " -"irányelveket%s és az %sAUR TU irányelveket%s." +msgstr "Üdvözlünk az AUR-ban! További információért olvasd el az %sAUR felhasználói irányelveket%s és az %sAUR TU irányelveket%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"A beküldött PKGBUILD-eknek meg %skell%s felelniük az %sArch csomagolási " -"szabályoknak%s, különben törlésre kerülnek!" +msgstr "A beküldött PKGBUILD-eknek meg %skell%s felelniük az %sArch csomagolási szabályoknak%s, különben törlésre kerülnek!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ne felejts el szavazni kedvenc csomagjaidra!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Néhány csomagot lehet, hogy a [community] binárisként szolgáltat." +#: html/home.php msgid "DISCLAIMER" msgstr "NYILATKOZAT" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Az AUR csomagok felhasználók által készített tartalmak. A szolgáltatott " -"fájlok használata csak saját felelősségre." +msgstr "Az AUR csomagok felhasználók által készített tartalmak. A szolgáltatott fájlok használata csak saját felelősségre." +#: html/home.php msgid "Learn more..." msgstr "Tudj meg többet..." +#: html/home.php msgid "Support" msgstr "Támogatás" +#: html/home.php msgid "Package Requests" msgstr "Csomagkérelmek" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Háromfajta kérelem tölthető ki a %sCsomagműveletek%s dobozban a csomag " -"részletei oldalon:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Háromfajta kérelem tölthető ki a %sCsomagműveletek%s dobozban a csomag részletei oldalon:" +#: html/home.php msgid "Orphan Request" msgstr "Megtagadási kérelem" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Egy csomag megtagadásának kérése, pl. amikor a karbantartó inaktív, és a " -"csomag régóta elavultnak lett jelölve." +msgstr "Egy csomag megtagadásának kérése, pl. amikor a karbantartó inaktív, és a csomag régóta elavultnak lett jelölve." +#: html/home.php msgid "Deletion Request" msgstr "Törlési kérelem" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Egy csomag Arch User Repositoriból való törlésének kérése. Kérünk, ne " -"használd ezt, ha a csomag törött, és könnyen javítható. Ehelyett vedd fel a " -"kapcsolatot a csomag karbantartójával, és tölts ki megtagadási kérelmet, ha " -"szükséges." +msgstr "Egy csomag Arch User Repositoriból való törlésének kérése. Kérünk, ne használd ezt, ha a csomag törött, és könnyen javítható. Ehelyett vedd fel a kapcsolatot a csomag karbantartójával, és tölts ki megtagadási kérelmet, ha szükséges." +#: html/home.php msgid "Merge Request" msgstr "Beolvasztási kérelem" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Egy csomag másik csomagba történő beolvasztásának kérése. Akkor használható, " -"amikor egy csomagot át kell nevezni, vagy lecserélésre kerül egy osztott " -"csomagra." +msgstr "Egy csomag másik csomagba történő beolvasztásának kérése. Akkor használható, amikor egy csomagot át kell nevezni, vagy lecserélésre kerül egy osztott csomagra." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Ha meg szeretnél tárgyalni egy kérelmet, használd az %saur-requests%s " -"levelezőlistát. Azonban ne használd ezt a listát kérvények beadására." +msgstr "Ha meg szeretnél tárgyalni egy kérelmet, használd az %saur-requests%s levelezőlistát. Azonban ne használd ezt a listát kérvények beadására." +#: html/home.php msgid "Submitting Packages" msgstr "Csomagok beküldése" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Jelenleg SSH-n keresztüli Git használandó a csomagok beküldéséhez az AUR-ba. " -"További részletekért lásd a %sCsomagok beküldése%s szakaszt az Arch User " -"Repository ArchWiki oldalon." +msgstr "Jelenleg SSH-n keresztüli Git használandó a csomagok beküldéséhez az AUR-ba. További részletekért lásd a %sCsomagok beküldése%s szakaszt az Arch User Repository ArchWiki oldalon." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Az alábbi SSH ujjlenyomatokat használjuk az AUR-hoz:" +#: html/home.php msgid "Discussion" msgstr "Megbeszélés" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Az Arch User Repositoryval (AUR) és a Trusted User struktúrával kapcsolatos " -"általános tanácskozás helye az %saur-general%s. Az AUR webes felületének " -"fejlesztésével kapcsolatos tanácskozáshoz az %saur-dev%s levelezőlista " -"használandó." +msgstr "Az Arch User Repositoryval (AUR) és a Trusted User struktúrával kapcsolatos általános tanácskozás helye az %saur-general%s. Az AUR webes felületének fejlesztésével kapcsolatos tanácskozáshoz az %saur-dev%s levelezőlista használandó." +#: html/home.php msgid "Bug Reporting" msgstr "Hibajelentés" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Ha találsz egy hibát az AUR webes felületén, kérünk, tölts ki egy " -"hibajelentést a %shibakövetőnkben%s. A hibakövetőt %scsak%s az AUR webes " -"felületén található hibák jelentésére használd. Csomagolási hibák " -"jelentéséhez lépj kapcsolatba a csomag fenntartójával, vagy hagyj egy " -"hozzászólást a megfelelő csomag oldalán." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Ha találsz egy hibát az AUR webes felületén, kérünk, tölts ki egy hibajelentést a %shibakövetőnkben%s. A hibakövetőt %scsak%s az AUR webes felületén található hibák jelentésére használd. Csomagolási hibák jelentéséhez lépj kapcsolatba a csomag fenntartójával, vagy hagyj egy hozzászólást a megfelelő csomag oldalán." +#: html/home.php msgid "Package Search" msgstr "Csomag keresése" +#: html/index.php msgid "Adopt" msgstr "Örökbe fogadás" +#: html/index.php msgid "Vote" msgstr "Szavazás" +#: html/index.php msgid "UnVote" msgstr "Szavazat visszavonása" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Értesítés" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Értesítés kikapcsolása" +#: html/index.php msgid "UnFlag" msgstr "Megjelölés visszavonása" +#: html/login.php template/header.php msgid "Login" msgstr "Bejelentkezés" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Bejelentkezve mint: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Kijelentkezés" +#: html/login.php msgid "Enter login credentials" msgstr "Bejelentkezési adatok megadása" +#: html/login.php msgid "User name or email address" msgstr "Felhasználónév vagy e-mail cím" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Jelszó" +#: html/login.php msgid "Remember me" msgstr "Maradjak bejelentkezve" +#: html/login.php msgid "Forgot Password" msgstr "Elfelejtett jelszó" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"A HTTP bejelentkezés letiltásra került. Ha be szeretnél jelentkezni, akkor " -"kérünk, hogy %sválts át HTTPs-re%s." +msgstr "A HTTP bejelentkezés letiltásra került. Ha be szeretnél jelentkezni, akkor kérünk, hogy %sválts át HTTPs-re%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Keresési feltételek" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Csomagok" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Egy kötelező mező megadása hiányzik." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "A jelszó mezők nem egyeznek." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "A jelszónak legalább %s karakter hosszúságúnak kell lennie." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Érvénytelen e-mail." +#: html/passreset.php msgid "Password Reset" msgstr "Jelszó visszaállítása" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Ellenőrizd az e-mailjeidet a megerősítő hivatkozáshoz." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Jelszavad sikeresen visszaállításra került." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Erősíts meg az e-mail címedet:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Add meg az új jelszavad:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Erősítsd meg az új jelszavad:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Folytatás" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Ha elfelejtetted az e-mail címet, amit a regisztrációhoz használtál, akkor " -"küldj egy üzenetet az %saur-general%s levelezőlistára." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Ha elfelejtetted az e-mail címet, amit a regisztrációhoz használtál, akkor küldj egy üzenetet az %saur-general%s levelezőlistára." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Add meg az e-mail címedet:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"A kiválasztott csomagok nem kerültek megtagadásra, ellenőrizd a megerősítő " -"jelölőnégyzetet." +msgstr "A kiválasztott csomagok nem kerültek megtagadásra, ellenőrizd a megerősítő jelölőnégyzetet." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Nem található csomag, amelybe a szavazatok és hozzászólások beolvaszthatók " -"lennének." +msgstr "Nem található csomag, amelybe a szavazatok és hozzászólások beolvaszthatók lennének." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Egy alapcsomag nem olvasztható önmagába." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"A kiválasztott csomagok nem kerültek törlésre, ellenőrizd a megerősítő " -"jelölőnégyzetet." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "A kiválasztott csomagok nem kerültek törlésre, ellenőrizd a megerősítő jelölőnégyzetet." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Csomag törlése" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Csomag törlése" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomag és az alábbi csomagok " -"törléséhez az AUR-ból:" +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag és az alábbi csomagok törléséhez az AUR-ból:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Egy csomag törlése végleges. " +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "A művelet megerősítéséhez jelöld be a jelölőnégyzetet." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Csomag törlésének megerősítése" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Törlés" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Csak megbízható felhasználók és fejlesztők tudnak csomagokat törölni." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Csomag megtagadása" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomag megtagadásához, amely a " -"következő csomagokat tartalmazza:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag megtagadásához, amely a következő csomagokat tartalmazza:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " -"csomagot, és átadni a tulajdonjogot neki: %s%s%s." +msgstr "A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a csomagot, és átadni a tulajdonjogot neki: %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a " -"csomagot." +msgstr "A jelölőnégyzet kiválasztásával megerősíted, hogy szeretnéd megtagadni a csomagot." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Csomag megtagadásának megerősítése." +#: html/pkgdisown.php msgid "Disown" msgstr "Megtagadás" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." +msgstr "Csak megbízható felhasználók és fejlesztők tudnak megtagadni csomagokat." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Hozzászólás jelölése" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Csomag elvaultnak jelölése" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Használd ezt az űrlapot annak jelzésére, hogy a(z) %s%s%s alapcsomag és a " -"következő csomagok elavultak:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Használd ezt az űrlapot annak jelzésére, hogy a(z) %s%s%s alapcsomag és a következő csomagok elavultak:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Kérünk, %sne%s használd ezt az űrlapot hibák jelentéséhez. Használd a " -"csomaghozzászólásokat helyette." +msgstr "Kérünk, %sne%s használd ezt az űrlapot hibák jelentéséhez. Használd a csomaghozzászólásokat helyette." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Add meg alább a részleteit, hogy miért avult el a csomag, lehetőleg " -"hivatkozásokkal a kiadási közleményre vagy az új kiadás tarballjára." +msgstr "Add meg alább a részleteit, hogy miért avult el a csomag, lehetőleg hivatkozásokkal a kiadási közleményre vagy az új kiadás tarballjára." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Hozzászólások" +#: html/pkgflag.php msgid "Flag" msgstr "Megjelölés" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Csak regisztrált felhasználók jelölhetnek csomagokat elavultnak." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Csomag beolvasztása" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Csomag beolvasztása" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomag másik csomagba történő " -"beolvasztásához." +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomag másik csomagba történő beolvasztásához." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "A következő csomagok törlésre kerülnek:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Ha egyszer egy csomag beolvasztásra került, többé nem lehet visszaállítani. " +msgstr "Ha egyszer egy csomag beolvasztásra került, többé nem lehet visszaállítani. " +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Add meg a csomag nevét, amibe szeretnéd beolvasztani a csomagot." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Beolvasztás ebbe:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Csomag beolvasztásának megerősítése" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Beolvasztás" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." -msgstr "" -"Csak megbízható felhasználók és fejlesztők tudnak csomagokat beolvasztani." +msgstr "Csak megbízható felhasználók és fejlesztők tudnak csomagokat beolvasztani." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Kérelem beküldése" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Kérelem lezárása" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Első" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Előző" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Következő" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Utolsó" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Kérelmek" +#: html/register.php template/header.php msgid "Register" msgstr "Regisztráció" +#: html/register.php msgid "Use this form to create an account." msgstr "Használd ezt a űrlapot felhasználói fiók létrehozására." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Megbízható felhasználó" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nem sikerült az indítvány részletes információinak letöltése." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A szavazás lezárult erre az indítványra." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "A szavazás csak megbízható felhasználóknak engedélyezett." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nem szavazhatsz egy rólad szóló indítványra." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Már szavaztál erre az indítványra." +#: html/tu.php msgid "Vote ID not valid." msgstr "Érvénytelen szavazatazonosító." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Jelenlegi szavazatok" +#: html/tu.php msgid "Past Votes" msgstr "Korábbi szavazatok" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Szavazók" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"A felhasználói regisztráció jelenleg letiltásra került az IP címedre, " -"valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +msgstr "A felhasználói regisztráció jelenleg letiltásra került az IP címedre, valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Hiányzó felhasználóazonosító" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "A felhasználónév érvénytelen." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "%s és %s közötti karakterhosszúságúnak kell lennie" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Betűvel vagy számjeggyel kezdődjön és végződjön" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Csak egyetlen pontot, aláhúzást vagy kötőjelet tartalmazhat." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Érvénytelen e-mail cím." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A PGP kulcs ujjlenyomata érvénytelen." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "A nyilvános SSH kulcs érvénytelen." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nem lehet megnövelni a fiók jogosultságait." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "A nyelv jelenleg nem támogatott." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "A(z) %s%s%s felhasználónév már használatban van." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "A(z) %s%s%s cím már használatban van." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "A(z) %s%s%s nyilvános SSH kulcs már használatban van." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Hiba történt a(z) %s%s%s fiók létrehozása során." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A(z) %s%s%s fiók sikeresen létrejött." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Egy jelszó-visszaállító kulcs kiküldésre került az e-mail címedre." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "A fiókod használatához kattints a Bejelentkezés hivatkozásra feljebb." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "A(z) %s%s%s fiók nem módosult." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A(z) %s%s%s fiók sikeresen módosítva." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"A bejelentkező űrlap jelenleg letiltásra került az IP címedre, valószínűleg " -"rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +msgstr "A bejelentkező űrlap jelenleg letiltásra került az IP címedre, valószínűleg rendszeres spam támadások miatt. Elnézést a kellemetlenségért." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Fiók felfüggesztve" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"A jelszavad visszaállításra került. Ha most regisztráltál, akkor a " -"megerősítő e-mailben található hivatkozással beállíthatsz egy kezdeti " -"jelszót. Egyéb esetben kérj egy visszaállító kulcsot a %sJelszó " -"visszaállítása%s oldalon." +msgstr "A jelszavad visszaállításra került. Ha most regisztráltál, akkor a megerősítő e-mailben található hivatkozással beállíthatsz egy kezdeti jelszót. Egyéb esetben kérj egy visszaállító kulcsot a %sJelszó visszaállítása%s oldalon." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Hibás felhasználónév vagy jelszó." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Hiba történt a felhasználói munkamenet létrehozásának megkísérlésekor." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Érvénytelen e-mail és visszaállító kulcs kombináció." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nincs" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Fiók információinak megtekintése – %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Alapcsomag-azonosító vagy alapcsomagnév hiányzik." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nem szerkesztheted ezt a hozzászólást." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "A hozzászólás nem létezik." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "A hozzászólás nem lehet üres." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "A hozzászólás hozzáadva." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "A csomag információinak szerkesztéséhez be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Hiányzó hozzászólásazonosító." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "5-nél több hozzászólás nem rögzíthető." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Nem rögzítheted ezt a hozzászólást." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Nem oldhatod fel ezt a hozzászólást." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "A hozzászólás rögzítésre került." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "A hozzászólás feloldásra került." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Hiba történt a csomag részletes információinak letöltése közben." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "A csomag részletes információi nem találhatók." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Csomagok megjelöléséhez be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nem választottál ki egyetlen csomagot sem megjelölésre." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "A kiválasztott csomagok nem lettek jelölve, adj meg egy megjegyzést." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "A kiválasztott csomagok elavultnak lettek jelölve." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Csomagok megjelölésének visszavonásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nem választottál ki egyetlen csomagot sem megjelölés visszavonására." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "A kiválasztott csomagok bejelölése visszavonva." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Csomagok törléséhez nincs jogosultságod." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nem választottál ki egyetlen törlendő csomagot sem." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "A kiválasztott csomagok törlése megtörtént." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Csomagok örökbefogadásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Csomagok megtagadásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nem választottál ki egyetlen örökbe fogadandó csomagot sem." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nem választottál ki egyetlen csomagot sem megtagadásra." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Sikeresen örökbe fogadtad a kiválasztott csomagokat." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "A kiválasztott csomagok megtagadva." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Csomagokra történő szavazáshoz be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Csomagokra adott szavazatok visszavonásához be kell jelentkezned." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nem választottál ki egyetlen csomagot sem, amire szavaznál." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Szavazatod eltávolításra került a kiválasztott csomagokról." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Leadtad a szavazatod a kiválasztott csomagokra." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nem sikerült hozzáadni az értesítési listához." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "" -"Sikeresen fel lettél véve a(z) %s csomag hozzászólásértesítési listájára." +msgstr "Sikeresen fel lettél véve a(z) %s csomag hozzászólásértesítési listájára." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "El lettél távolítva a(z) %s csomag hozzászólásértesítési listájáról." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Ennek a hozzászólásnak nem vonhatod vissza a törlését." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "A hozzászólás törlése visszavonásra került." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nem törölheted ezt a hozzászólást." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Hozzászólás törölve." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "A hozzászólás szerkesztve lett." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nem szerkesztheted ennek az alapcsomagnak a kulcsszavait." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Az alapcsomag kulcsszavai frissítve lettek." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nem szerkesztheted ennek az alapcsomagnak a társkarbantartóit." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Érvénytelen felhasználónév: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Az alapcsomag társkarbantartói frissítve lettek." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Csomag részleteinek megtekintése –" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "igényli ezt: %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Csomagkérelmek beküldéséhez be kell jelentkezned." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Érvénytelen név: csak kisbetűk használata engedélyezett." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "A hozászólás mező nem lehet üres." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Érvénytelen kérelemtípus." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Kérelem sikeresen hozzáadva." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Érvénytelen ok." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Csak megbízható felhasználók és fejlesztők tudnak kérelmeket lezárni." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Kérelem sikeresen lezárva." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ez az űrlap %s AUR fiókjának végleges törléséhez használható." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sFIGYELMEZTETÉS%s: ez a művelet nem visszavonható." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Törlés megerősítése" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Felhasználónév" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Fióktípus" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Felhasználó" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Fejlesztő" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Megbízható felhasználó és fejlesztő" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail cím" +#: template/account_details.php msgid "hidden" msgstr "rejtett" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Valós név" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Honlap" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC becenév" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP kulcs ujjlenyomata" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Állapot" +#: template/account_details.php msgid "Inactive since" msgstr "Ezóta inaktív:" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktív" +#: template/account_details.php msgid "Registration date:" msgstr "Regisztráció dátuma:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "ismeretlen" +#: template/account_details.php msgid "Last Login" msgstr "Legutóbbi bejelentkezés" +#: template/account_details.php msgid "Never" msgstr "Soha" +#: template/account_details.php msgid "View this user's packages" msgstr "A felhasználó csomagjainak megtekintése" +#: template/account_details.php msgid "Edit this user's account" msgstr "Ezen felhasználó fiókjának szerkesztése" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kattints %side%s, ha véglegesen törölni szeretnéd ezt a fiókot." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Kattints %side%s a felhasználó részleteihez." +#: template/account_edit_form.php msgid "required" msgstr "kötelező" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normál felhasználó" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Megbízható felhasználó" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Felhasználói fiók felfüggesztve" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktív" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Kérünk, győződj meg arról, hogy helyesen adtad meg az e-mail címedet, " -"különben ki leszel zárva." +msgstr "Kérünk, győződj meg arról, hogy helyesen adtad meg az e-mail címedet, különben ki leszel zárva." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "E-mail cím elrejtése" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Megismételt jelszó" +#: template/account_edit_form.php msgid "Language" msgstr "Nyelv" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Az alábbi információ csak akkor szükséges, ha csomagokat szeretnél beküldeni " -"az Arch User Repositoryba." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Az alábbi információ csak akkor szükséges, ha csomagokat szeretnél beküldeni az Arch User Repositoryba." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Nyilvános SSH kulcs" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Értesítési beállítások" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Értesítés új hozzászólásról" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Értesítés csomagfrissítésekről." +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Értesítés tulajdonváltozásokról" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Frissítés" +#: template/account_edit_form.php msgid "Create" msgstr "Létrehozás" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Visszaállítás" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nincs a keresési feltételeknek megfelelő találat." +#: template/account_search_results.php msgid "Edit Account" msgstr "Felhasználói fiók szerkesztése" +#: template/account_search_results.php msgid "Suspended" msgstr "Felfüggesztve" +#: template/account_search_results.php msgid "Edit" msgstr "Szerkesztés" +#: template/account_search_results.php msgid "Less" msgstr "Kevesebb" +#: template/account_search_results.php msgid "More" msgstr "Több" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nincs több kijelezhető eredmény." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Használd ezt az űrlapot társszerkesztők hozzáadásához a(z) %s%s%s csomaghoz " -"(soronként egy felhasználónév):" +msgstr "Használd ezt az űrlapot társszerkesztők hozzáadásához a(z) %s%s%s csomaghoz (soronként egy felhasználónév):" +#: template/comaintainers_form.php msgid "Users" msgstr "Felhasználók" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Mentés" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Elavultnak jelölő hozzászólás: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s elavultnak jelölte a(z) %s%s%s csomagot ekkor: %s%s%s a következő " -"okból:" +msgstr "%s%s%s elavultnak jelölte a(z) %s%s%s csomagot ekkor: %s%s%s a következő okból:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s nincs elavultnak jelölve." +#: template/flag_comment.php msgid "Return to Details" msgstr "Vissza a részletekhez" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb fejlesztői csapat." +#: template/header.php msgid " My Account" msgstr " Fiókom" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Csomagműveletek" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD megtekintése" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Módosítások megtekintése" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Pillanatkép letöltése" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Keresés wikiben" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Elavultnak jelölve (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Csomag elavultnak jelölése" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Csomag jelölésének visszavonása" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Szavazat eltávolítása" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Szavazás erre a csomagra" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Értesítések kikapcsolása" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Értesítések engedélyezése" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Társszerkesztők kezelése" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d függő kérelem" msgstr[1] "%d függő kérelem" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Csomag örökbe fogadása" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Alapcsomag részletei" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git klónozási URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "csak olvasható" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Kulcsszavak" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Beküldő" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Karbantartó" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Legutóbbi csomagoló" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Szavazatok" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Népszerűség" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Először beküldve" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Legutóbb frissítve" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Hozzászólás szerkesztése ehhez: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Hosszászólás" +#: template/pkg_comments.php msgid "View all comments" msgstr "Összes megjegyzés megjelenítése" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Rögzített hozzászólások" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Legújabb hozzászólások" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s hozzászólt ekkor: %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Névtelen hozzászólás ekkor: %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "törölve ekkor: %s %s által" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "törölve ekkor: %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "szerkesztve ekkor: %s %s által" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "szerkesztve ekkor: %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Hozzászólás törlésének visszavonása" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Hozzászólás törlése" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Hozzászólás rögzítése" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Hozzászólás feloldása" +#: template/pkg_comments.php msgid "All comments" msgstr "Összes hozzászólás" +#: template/pkg_details.php msgid "Package Details" msgstr "Részletes csomaginformáció" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Alapcsomag" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Leírás" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "A webhely meglátogatása –" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencek" +#: template/pkg_details.php msgid "Groups" msgstr "Csoportok" +#: template/pkg_details.php msgid "Conflicts" msgstr "Ütközik" +#: template/pkg_details.php msgid "Provides" msgstr "Szolgáltatja" +#: template/pkg_details.php msgid "Replaces" msgstr "Lecseréli" +#: template/pkg_details.php msgid "Dependencies" msgstr "Függőségek" +#: template/pkg_details.php msgid "Required by" msgstr "Igényli" +#: template/pkg_details.php msgid "Sources" msgstr "Források" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem " -"lezárásához." +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem lezárásához." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"A megjegyzések mező üresen hagyható. Viszont kérelem elutasításakor erősen " -"javasolt megjegyzés hozzáadása." +msgstr "A megjegyzések mező üresen hagyható. Viszont kérelem elutasításakor erősen javasolt megjegyzés hozzáadása." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Ok" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Elfogadva" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Elutasítva" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem " -"benyújtásához, amely a következő csomagokat tartalmazza:" +msgstr "Használd ezt az űrlapot a(z) %s%s%s alapcsomaggal kapcsolatos kérelem benyújtásához, amely a következő csomagokat tartalmazza:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Kérelem típusa" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Törlés" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Megtagadás" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Beolvasztás ebbe:" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Törlési kérelem beküldésével megkérsz egy megbízható felhasználót, hogy " -"törölje az alapcsomagot. Ez a típusú kérelem duplikátumok, főági fejlesztők " -"által felhagyott szoftverek, valamint illegális és helyrehozhatatlanul " -"elromlott csomagokhoz használható." +msgstr "Törlési kérelem beküldésével megkérsz egy megbízható felhasználót, hogy törölje az alapcsomagot. Ez a típusú kérelem duplikátumok, főági fejlesztők által felhagyott szoftverek, valamint illegális és helyrehozhatatlanul elromlott csomagokhoz használható." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Beolvasztási kérelem beküldésével megkérsz egy megbízható felhasználót, hogy " -"törölje az alapcsomagot, és vigye át a szavazatait és hozzászólásait egy " -"másik alapcsomaghoz. Egy csomag egyesítése nem érinti a kapcsolódó Git " -"tárolókat. Győződj meg róla, hogy frissítetted magadnak a célcsomag Git " -"történetét." +msgstr "Beolvasztási kérelem beküldésével megkérsz egy megbízható felhasználót, hogy törölje az alapcsomagot, és vigye át a szavazatait és hozzászólásait egy másik alapcsomaghoz. Egy csomag egyesítése nem érinti a kapcsolódó Git tárolókat. Győződj meg róla, hogy frissítetted magadnak a célcsomag Git történetét." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Megtagadási kérelem beküldésével megkérsz egy megbízható felhasználót, hogy " -"tegye árvává az alapcsomagot. Kérünk, hogy ezt csak akkor tedd, ha a csomag " -"igényel fenntartói műveletet, a fenntartó eltűnt, és előzőleg már " -"megpróbáltad felvenni a kapcsolatot a fenntartóval." +msgstr "Megtagadási kérelem beküldésével megkérsz egy megbízható felhasználót, hogy tegye árvává az alapcsomagot. Kérünk, hogy ezt csak akkor tedd, ha a csomag igényel fenntartói műveletet, a fenntartó eltűnt, és előzőleg már megpróbáltad felvenni a kapcsolatot a fenntartóval." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d csomagokkal kapcsolatos kérelem található." msgstr[1] "%d csomagokkal kapcsolatos kérelem található." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "%d. oldal, összesen: %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Csomag" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Kitöltő" +#: template/pkgreq_results.php msgid "Date" msgstr "Dátum" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d nap van hátra" msgstr[1] "~%d nap van hátra" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d óra van hátra" msgstr[1] "~%d óra van hátra" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 óra van hátra" +#: template/pkgreq_results.php msgid "Accept" msgstr "Elfogadás" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zárolva" +#: template/pkgreq_results.php msgid "Close" msgstr "Lezárás" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Lezárva" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Név, leírás" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Csak név" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Pontos név" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pontos alapcsomag" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Összes" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Jelölt" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nem jelölt" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Név" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Szavazva" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Legutóbb módosítva" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Növekvő" +#: template/pkg_search_form.php msgid "Descending" msgstr "Csökkenő" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Keresési feltételek megadása" +#: template/pkg_search_form.php msgid "Search by" msgstr "Keresés eszerint" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Elavult" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Rendezés" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Rendezési sorrend" +#: template/pkg_search_form.php msgid "Per page" msgstr "Laponként" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Mehet" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Árvák" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Hiba történt a csomaglista letöltése közben." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nincs a keresési feltételeknek megfelelő csomag." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d csomag található." msgstr[1] "%d csomag található." +#: template/pkg_search_results.php msgid "Version" msgstr "Verzió" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat " -"súlyozásra kerül naponta %.2f-as faktorral a létrehozása óta." +msgstr "A népszerűség az összes szavazatból kerül számításra. Minden egyes szavazat súlyozásra kerül naponta %.2f-as faktorral a létrehozása óta." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Igen" +#: template/pkg_search_results.php msgid "orphan" msgstr "árva" +#: template/pkg_search_results.php msgid "Actions" msgstr "Tevékenységek" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Elavultság visszavonása" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Csomagok örökbefogadása" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Csomagok megtagadása" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Csomagok törlése" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Megerősítés" +#: template/search_accounts_form.php msgid "Any type" msgstr "Bármilyen típus" +#: template/search_accounts_form.php msgid "Search" msgstr "Keresés" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statisztika" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Árva csomagok" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "A legutóbbi 7 napban hozzáadott csomagok" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "A legutóbbi 7 napban frissített csomagok" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Az utóbbi évben frissített csomagok" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Soha nem frissített csomagok" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Regisztrált felhasználók" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Megbízható felhasználók" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Legutóbbi frissítések" +#: template/stats/updates_table.php msgid "more" msgstr "több" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Statisztikám" +#: template/tu_details.php msgid "Proposal Details" msgstr "Indítvány részletes információi" +#: template/tu_details.php msgid "This vote is still running." msgstr "A szavazás még zajlik." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Benyújtva: %s (%s által)" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Vége" +#: template/tu_details.php msgid "Result" msgstr "Eredmény" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nem" +#: template/tu_details.php msgid "Abstain" msgstr "Tartózkodik" +#: template/tu_details.php msgid "Total" msgstr "Összesen" +#: template/tu_details.php msgid "Participation" msgstr "Részvétel" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Legutóbbi szavazatok TU szerint" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Legutóbbi szavazat" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nincs találat." +#: template/tu_list.php msgid "Start" msgstr "Kezdés" +#: template/tu_list.php msgid "Back" msgstr "Vissza" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/it.po b/po/it.po index bb311284..cf1af376 100644 --- a/po/it.po +++ b/po/it.po @@ -1,1370 +1,1678 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Giovanni Scafora , 2011-2015 # Lorenzo Porta , 2014 # Lukas Fleischer , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Italian (http://www.transifex.com/lfleischer/aur/language/" -"it/)\n" -"Language: it\n" +"Language-Team: Italian (http://www.transifex.com/lfleischer/aurweb/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Impossibile trovare la pagina" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Spiacenti, la pagina richiesta non esiste." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "Servizio non disponibile" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Niente panico! Il sito è fuori servizio per lavori di manutenzione. " -"Torneremo presto." +msgstr "Niente panico! Il sito è fuori servizio per lavori di manutenzione. Torneremo presto." +#: html/account.php msgid "Account" msgstr "Account" +#: html/account.php template/header.php msgid "Accounts" msgstr "Account" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Non sei autorizzato ad accedere a quest'area." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Impossibile recuperare le informazioni dell'utente specificato." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Non hai i permessi necessari per modificare questo account." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa questo modulo per cercare gli account esistenti." +#: html/account.php msgid "You must log in to view user information." msgstr "Devi autenticarti per visualizzare le informazioni dell'utente." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Aggiungi una proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Il token non è valido per l'intervento da parte dell'utente." +#: html/addvote.php msgid "Username does not exist." msgstr "Il nome utente non esiste." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ha già avviato una proposta per loro." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo non valido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "La proposta non può essere vuota." +#: html/addvote.php msgid "New proposal submitted." msgstr "La nuova proposta è stata inviata." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Invia una proposta da votare." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vuoto se non applicabile)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Aggiunta di un TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Rimozione di un TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Rimozione di un TU (inattività non dichiarata)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Modifica dello statuto" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Invia" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Gestisci i co-manutentori" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Edita il commento" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Home" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "I miei pacchetti" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Benvenuto in AUR! Per maggiori informazioni, leggi le %sAUR User Guidelines" -"%s e le %sAUR TU Guidelines%s." +msgstr "Benvenuto in AUR! Per maggiori informazioni, leggi le %sAUR User Guidelines%s e le %sAUR TU Guidelines%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"I PKGBUILD inviati %sdevono%s essere conformi agli %sArch Packaging Standards" -"%s altrimenti saranno eliminati!" +msgstr "I PKGBUILD inviati %sdevono%s essere conformi agli %sArch Packaging Standards%s altrimenti saranno eliminati!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ricorda di votare i tuoi pacchetti preferiti!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Alcuni pacchetti potrebbero essere disponibili come precompilati in " -"[community]." +msgstr "Alcuni pacchetti potrebbero essere disponibili come precompilati in [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVVISO" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"i pacchetti presenti in AUR sono stati inviati dagli utenti. Usali a tuo " -"rischio e pericolo." +msgstr "i pacchetti presenti in AUR sono stati inviati dagli utenti. Usali a tuo rischio e pericolo." +#: html/home.php msgid "Learn more..." msgstr "Ulteriori informazioni..." +#: html/home.php msgid "Support" msgstr "Supporto" +#: html/home.php msgid "Package Requests" msgstr "Richieste dei pacchetti" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Ci sono tre tipi di richieste che si possono effettuare dal riquadro " -"%sAzioni del pacchetto%s presente nella pagina dei dettagli del pacchetto:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Ci sono tre tipi di richieste che si possono effettuare dal riquadro %sAzioni del pacchetto%s presente nella pagina dei dettagli del pacchetto:" +#: html/home.php msgid "Orphan Request" msgstr "Richiesta di un pacchetto orfano" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"richiesta di un pacchetto che si vuole abbandonare, ad esempio, quando il " -"manutentore è inattivo ed il pacchetto è stato contrassegnato come non " -"aggiornato da molto tempo." +msgstr "richiesta di un pacchetto che si vuole abbandonare, ad esempio, quando il manutentore è inattivo ed il pacchetto è stato contrassegnato come non aggiornato da molto tempo." +#: html/home.php msgid "Deletion Request" msgstr "Richiesta di rimozione di un pacchetto" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usare " -"questo tipo di richiesta se un pacchetto non funziona e se può essere " -"sistemato facilmente. Contatta il manutentore del pacchetto e, se " -"necessario, invia una richiesta per renderlo orfano." +msgstr "richiesta per rimuovere un pacchetto dall'Arch User Repository. Non usare questo tipo di richiesta se un pacchetto non funziona e se può essere sistemato facilmente. Contatta il manutentore del pacchetto e, se necessario, invia una richiesta per renderlo orfano." +#: html/home.php msgid "Merge Request" msgstr "Richiesta di unione di un pacchetto" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"richiesta di un pacchetto da unire con un altro. Può essere usata quando un " -"pacchetto necessita di essere rinominato o rimpiazzato da un pacchetto " -"suddiviso" +msgstr "richiesta di un pacchetto da unire con un altro. Può essere usata quando un pacchetto necessita di essere rinominato o rimpiazzato da un pacchetto suddiviso" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Se vuoi discutere una richiesta, puoi usare la lista di discussione %saur-" -"requests%s. Non usare questa lista per inoltrare richieste." +msgstr "Se vuoi discutere una richiesta, puoi usare la lista di discussione %saur-requests%s. Non usare questa lista per inoltrare richieste." +#: html/home.php msgid "Submitting Packages" msgstr "Invio dei pacchetti" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Per inviare i pacchetti in AUR, adesso, si utilizza Git via SSH. Per " -"maggiori informazioni, vedi la sezione %sInviare i pacchetti%s della pagina " -"Arch User Repository dell'ArchWiki." +msgstr "Per inviare i pacchetti in AUR, adesso, si utilizza Git via SSH. Per maggiori informazioni, vedi la sezione %sInviare i pacchetti%s della pagina Arch User Repository dell'ArchWiki." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Per AUR si usano le seguenti fingerprint SSH:" +#: html/home.php msgid "Discussion" msgstr "Discussione" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"La discussione generale sull'Arch User Repository (AUR) e sulla struttura " -"dei TU avviene in %saur-general%s. Per la discussione relativa allo sviluppo " -"dell'interfaccia web di AUR, utilizza la lista di discussione %saur-dev%s." +msgstr "La discussione generale sull'Arch User Repository (AUR) e sulla struttura dei TU avviene in %saur-general%s. Per la discussione relativa allo sviluppo dell'interfaccia web di AUR, utilizza la lista di discussione %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Segnalazione di un bug" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Se trovi un bug nell'interfaccia web di AUR, invia un report al nostro %sbug " -"tracker%s. Usa il tracker %ssolo%s per inviare i bug di AUR. Per segnalare " -"bug inerenti alla pacchettizzazione, contatta il manutentore oppure lascia " -"un commento nella pagina del pacchetto." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Se trovi un bug nell'interfaccia web di AUR, invia un report al nostro %sbug tracker%s. Usa il tracker %ssolo%s per inviare i bug di AUR. Per segnalare bug inerenti alla pacchettizzazione, contatta il manutentore oppure lascia un commento nella pagina del pacchetto." +#: html/home.php msgid "Package Search" msgstr "Ricerca dei pacchetti" +#: html/index.php msgid "Adopt" msgstr "Adotta" +#: html/index.php msgid "Vote" msgstr "Vota" +#: html/index.php msgid "UnVote" msgstr "Rimuovi il voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Abilita le notifiche" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Disabilita le notifiche" +#: html/index.php msgid "UnFlag" msgstr "Deseleziona" +#: html/login.php template/header.php msgid "Login" msgstr "Accedi" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Connesso con il nome utente: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Esci" +#: html/login.php msgid "Enter login credentials" msgstr "Inserisci le credenziali di accesso" +#: html/login.php msgid "User name or email address" msgstr "Il nome utente o l'indirizzo email" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Password" +#: html/login.php msgid "Remember me" msgstr "Ricordami" +#: html/login.php msgid "Forgot Password" msgstr "Password dimenticata" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"L'accesso tramite HTTP è stato disabilitato. Se vuoi accedere, %spassa ad " -"HTTPs%s." +msgstr "L'accesso tramite HTTP è stato disabilitato. Se vuoi accedere, %spassa ad HTTPs%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteri di ricerca" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacchetti" +#: html/packages.php msgid "Error trying to retrieve package details." -msgstr "" -"Si è verificato un errore durante il recupero dei dettagli del pacchetto." +msgstr "Si è verificato un errore durante il recupero dei dettagli del pacchetto." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Manca un campo obbligatorio." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "I campi password non corrispondono." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "La password deve contenere almeno %s caratteri." +#: html/passreset.php msgid "Invalid e-mail." msgstr "L'e-mail inserita non è valida." +#: html/passreset.php msgid "Password Reset" msgstr "Ripristina la password" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Controlla la tua e-mail per il link di conferma." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "La tua password è stata ripristinata con successo." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Conferma il tuo indirizzo e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Inserisci la tua nuova password:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Conferma la tua nuova password:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continua" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un " -"messaggio nella mailing list %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un messaggio nella mailing list %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Inserisci il tuo indirizzo email:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"I pacchetti selezionati non sono stati abbandonati, conferma la tua scelta " -"inserendo un segno di spunta nell'apposita casella di controllo." +msgstr "I pacchetti selezionati non sono stati abbandonati, conferma la tua scelta inserendo un segno di spunta nell'apposita casella di controllo." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Impossibile trovare il pacchetto da unire al suo interno i voti ed i " -"commenti." +msgstr "Impossibile trovare il pacchetto da unire al suo interno i voti ed i commenti." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Impossibile unire un pacchetto base con se stesso." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"I pacchetti selezionati non sono stati eliminati, conferma la tua scelta " -"inserendo un segno di spunta nell'apposita casella di controllo." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "I pacchetti selezionati non sono stati eliminati, conferma la tua scelta inserendo un segno di spunta nell'apposita casella di controllo." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminazione del pacchetto" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Elimina il pacchetto" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Usa questo modulo per eliminare il pacchetto base %s%s%s e i seguenti " -"pacchetti da AUR:" +msgstr "Usa questo modulo per eliminare il pacchetto base %s%s%s e i seguenti pacchetti da AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "La rimozione di un pacchetto è permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Seleziona la casella di controllo per confermare l'azione richiesta." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Conferma di voler rimuovere il pacchetto" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Elimina" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Solo i TU e gli sviluppatori possono eliminare i pacchetti." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abbandona il pacchetto" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Usa questo modulo per abbandonare il pacchetto base %s%s%s che contiene i " -"seguenti pacchetti:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Usa questo modulo per abbandonare il pacchetto base %s%s%s che contiene i seguenti pacchetti:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Selezionando la casella di controllo, confermi che vuoi abbandonare il " -"pacchetto e trasferirlo a %s%s%s." +msgstr "Selezionando la casella di controllo, confermi che vuoi abbandonare il pacchetto e trasferirlo a %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Selezionando la casella di controllo, confermi che vuoi abbandonare il " -"pacchetto." +msgstr "Selezionando la casella di controllo, confermi che vuoi abbandonare il pacchetto." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Conferma di voler abbandonare il pacchetto" +#: html/pkgdisown.php msgid "Disown" msgstr "Abbandona" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Solo i TU e gli sviluppatori possono abbandonare i pacchetti." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Segnala che il pacchetto non è aggiornato" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Usa questo modulo per segnalare che il pacchetto base %s%s%s e i seguenti " -"pacchetti non sono aggiornati:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Usa questo modulo per segnalare che il pacchetto base %s%s%s e i seguenti pacchetti non sono aggiornati:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"%sNon%s utilizzare questo modulo per inviare bug report. Utilizza i commenti " -"nella pagina del pacchetto." +msgstr "%sNon%s utilizzare questo modulo per inviare bug report. Utilizza i commenti nella pagina del pacchetto." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Immetti qui sotto i dettagli sul perché il pacchetto non è aggiornato, " -"preferibilmente compresi il collegamento dell'annuncio del rilascio o del " -"nuovo sorgente." +msgstr "Immetti qui sotto i dettagli sul perché il pacchetto non è aggiornato, preferibilmente compresi il collegamento dell'annuncio del rilascio o del nuovo sorgente." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Commenti" +#: html/pkgflag.php msgid "Flag" msgstr "Seleziona" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"Solo gli utenti registrati possono segnalare i pacchetti non aggiornati." +msgstr "Solo gli utenti registrati possono segnalare i pacchetti non aggiornati." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Unione dei pacchetti" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Unisci il pacchetto" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Usa questo modulo per unire il pacchetto base %s%s%s con un altro pacchetto." +msgstr "Usa questo modulo per unire il pacchetto base %s%s%s con un altro pacchetto." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "I seguenti pacchetti saranno eliminati:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Una volta che il pacchetto è stato unito, non può essere più recuperato." +msgstr "Una volta che il pacchetto è stato unito, non può essere più recuperato." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Digita il nome del pacchetto che desideri unire all'interno del pacchetto." +msgstr "Digita il nome del pacchetto che desideri unire all'interno del pacchetto." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Unisci con:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Conferma di voler unire il pacchetto" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Unisci" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Solo i TU e gli sviluppatori possono unire i pacchetti." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Invia la richiesta" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Chiudi la richiesta" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primo" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedente" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Successivo" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Richieste" +#: html/register.php template/header.php msgid "Register" msgstr "Registrati" +#: html/register.php msgid "Use this form to create an account." msgstr "Usa questo modulo per creare un account." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "TU" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Impossibile recuperare i dettagli della proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Non puoi più votare per questa proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Solo i TU possono votare." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Non puoi votare per una proposta che ti riguarda in prima persona." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Hai già votato per questa proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "L'ID del voto non è valido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Voti attuali" +#: html/tu.php msgid "Past Votes" msgstr "Vecchi voti" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votanti" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"La registrazione dell'account è stata disabilitata per il tuo indirizzo IP, " -"probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per " -"l'inconveniente." +msgstr "La registrazione dell'account è stata disabilitata per il tuo indirizzo IP, probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per l'inconveniente." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manca l'ID dell'utente" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Il nome utente non è valido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Deve contenere un minino di %s ed un massimo di %s caratteri" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Inizia e termina con una lettera o un numero" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Può contenere solo un punto, un trattino basso o un trattino." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'indirizzo email non risulta valido." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "La fingerprint della chiave PGP non è valida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "La chiave pubblica SSH non è valida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Non è possibile incrementare i permessi dell'account." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Lingua attualmente non supportata." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Il nome utente %s%s%s è già in uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "L'indirizzo %s%s%s è già in uso." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "La chiave pubblica SSH %s%s%s, è già in uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Si è verificato un errore durante la creazione dell'account %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "L'account %s%s%s è stato creato con successo." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"È stata inviata una chiave di ripristino della password al tuo indirizzo e-" -"mail." +msgstr "È stata inviata una chiave di ripristino della password al tuo indirizzo e-mail." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Per utilizzare il tuo account, clicca sul link Accedi." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Non sono state apportate modifiche all'account %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "L'account %s%s%s è stato modificato con successo." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Il modulo d'accesso è attualmente disabilitato per il tuo indirizzo IP, " -"probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per " -"l'inconveniente." +msgstr "Il modulo d'accesso è attualmente disabilitato per il tuo indirizzo IP, probabilmente a causa di prolungati attacchi di spam. Ci scusiamo per l'inconveniente." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Account sospeso" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"La tua password è stata ripristinata. Se hai creato da poco un nuovo " -"account, usa il link presente nell'email di conferma, per impostare una " -"password iniziale. Altrimenti, richiedi il ripristino della password dalla " -"pagina %sRipristina la password%s." +msgstr "La tua password è stata ripristinata. Se hai creato da poco un nuovo account, usa il link presente nell'email di conferma, per impostare una password iniziale. Altrimenti, richiedi il ripristino della password dalla pagina %sRipristina la password%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nome utente o password errati." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "" -"Si è verificato un errore provando a generare una sessione dell'utente." +msgstr "Si è verificato un errore provando a generare una sessione dell'utente." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "La combinazione e-mail e chiave di ripristino non è valida." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nessuno" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Mostra le informazioni dell'account %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Manca l'ID o il nome del pacchetto." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Non sei autorizzato a modificare questo commento." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Il commento è stato rimosso." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Il commento non può essere vuoto." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Il commento è stato inserito." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Devi autenticarti prima di poter modificare le informazioni del pacchetto." +msgstr "Devi autenticarti prima di poter modificare le informazioni del pacchetto." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Manca l'ID del commento." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Non possono essere inseriti più di 5 commenti." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Non sei autorizzato ad inserire questo commento." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Non sei autorizzato a rimuovere questo commento." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Il commento è stato rimosso." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "I commenti sono stati rimossi." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." -msgstr "" -"Si è verificato un errore durante il recupero dei dettagli del pacchetto." +msgstr "Si è verificato un errore durante il recupero dei dettagli del pacchetto." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Impossibile trovare i dettagli del pacchetto." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Devi autenticarti prima di poter contrassegnare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." -msgstr "" -"Non hai selezionato nessun pacchetto da contrassegnare come non aggiornato." +msgstr "Non hai selezionato nessun pacchetto da contrassegnare come non aggiornato." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"I pacchetti selezionati non sono stati contrassegnati, immetti un commento." +msgstr "I pacchetti selezionati non sono stati contrassegnati, immetti un commento." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "I pacchetti selezionati sono stati contrassegnati come non aggiornati." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Devi autenticarti prima di poter rimuovere il contrassegno ai pacchetti." +msgstr "Devi autenticarti prima di poter rimuovere il contrassegno ai pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." -msgstr "" -"Non hai selezionato nessun pacchetto da contrassegnare come aggiornato." +msgstr "Non hai selezionato nessun pacchetto da contrassegnare come aggiornato." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "I pacchetti selezionati non sono più contrassegnati." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Non hai il permesso per eliminare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Non hai selezionato nessun pacchetto da eliminare." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "I pacchetti selezionati sono stati eliminati." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Devi autenticarti prima di poter adottare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Devi autenticarti prima di poter abbandonare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Non hai selezionato nessun pacchetto da adottare." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Non hai selezionato nessun pacchetto da abbandonare." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "I pacchetti selezionati sono stati adottati." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "I pacchetti selezionati sono stati abbandonati." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Devi autenticarti prima di poter votare i pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Devi autenticarti prima di poter rimuovere il voto dai pacchetti." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Non hai selezionato nessun pacchetto a cui assegnare il voto." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "I voti sono stati rimossi dai pacchetti selezionati." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "I voti sono stati assegnati ai pacchetti selezionati." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Impossibile aggiungere alla lista delle notifiche." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Sei stato aggiunto alla lista delle notifiche dei commenti di %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Sei stato rimosso dalla lista delle notifiche dei commenti di %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Non sei autorizzato a rimuovere questo commento." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Il commento è stato rimosso." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "I commenti sono stati modificati." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"Non sei autorizzato a modificare le parole chiave di questo pacchetto base." +msgstr "Non sei autorizzato a modificare le parole chiave di questo pacchetto base." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Le parole chiave del pacchetto base sono state aggiornate." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Non sei autorizzato a gestire i co-manutentori di questo pacchetto base." +msgstr "Non sei autorizzato a gestire i co-manutentori di questo pacchetto base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Il nome utente non è valido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "I co-menutentori del pacchetto base sono stati aggiornati." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Mostra i dettagli dei pacchetti di" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "richiede %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Devi autenticarti per richiedere i pacchetti." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Il nome non è valido: sono consentite solo le lettere minuscole." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Il campo dei commenti non deve essere vuoto." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Il tipo di richiesta non è valido." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "La richiesta è stata aggiunta con successo." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Il motivo non è valido." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Solo i TU e gli sviluppatori possono chiudere le richieste." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "La richiesta è stata chiusa con successo." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Puoi usare questo modulo per eliminare definitivamente da AUR l'account %s." +msgstr "Puoi usare questo modulo per eliminare definitivamente da AUR l'account %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sATTENZIONE%s: questa azione non può essere incompiuta." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Conferma la rimozione" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nome utente" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo di account" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utente" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Sviluppatore" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "TU e sviluppatore" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Indirizzo email" +#: template/account_details.php msgid "hidden" msgstr "nascosto" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome reale" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Fingerprint della chiave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stato" +#: template/account_details.php msgid "Inactive since" msgstr "Inattivo da" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Attivo" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "sconosciuta" +#: template/account_details.php msgid "Last Login" msgstr "Ultimo accesso" +#: template/account_details.php msgid "Never" msgstr "Mai" +#: template/account_details.php msgid "View this user's packages" msgstr "Mostra i pacchetti di quest'utente" +#: template/account_details.php msgid "Edit this user's account" msgstr "Modifica l'account di quest'utente" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clicca %squi%s se vuoi eliminare definitivamente questo account." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "obbligatorio" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utente normale" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "TU" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Account sospeso" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inattivo" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Assicurati di immettere correttamente il tuo indirizzo email, altrimenti " -"sarai bloccato." +msgstr "Assicurati di immettere correttamente il tuo indirizzo email, altrimenti sarai bloccato." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Nascondi l'indirizzo email" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Riscrivi la password" +#: template/account_edit_form.php msgid "Language" msgstr "Lingua" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"La seguente informazione è richiesta solo se vuoi inviare i pacchetti " -"nell'Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "La seguente informazione è richiesta solo se vuoi inviare i pacchetti nell'Arch User Repository." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Chiave pubblica SSH" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notifica dei nuovi commenti" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aggiorna" +#: template/account_edit_form.php msgid "Create" msgstr "Crea" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Cancella" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nessun risultato corrisponde ai tuoi criteri di ricerca." +#: template/account_search_results.php msgid "Edit Account" msgstr "Modifica l'account" +#: template/account_search_results.php msgid "Suspended" msgstr "Sospeso" +#: template/account_search_results.php msgid "Edit" msgstr "Modifica" +#: template/account_search_results.php msgid "Less" msgstr "Precedente" +#: template/account_search_results.php msgid "More" msgstr "Successivo" +#: template/account_search_results.php msgid "No more results to display." msgstr "Non vi sono ulteriori risultati da mostrare." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Usa questo modulo per aggiungere i co-manutentori di %s%s%s (un nome utente " -"per linea):" +msgstr "Usa questo modulo per aggiungere i co-manutentori di %s%s%s (un nome utente per linea):" +#: template/comaintainers_form.php msgid "Users" msgstr "Utenti" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Salva" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." +#: template/header.php msgid " My Account" msgstr "Il mio account" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Azioni del pacchetto" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Mostra il PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Mostra le modifiche" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Scarica lo snapshot" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Cerca nel wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Segnala che il pacchetto non è aggiornato" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Rimuovi la segnalazione del pacchetto" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Rimuovi il voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Vota per questo pacchetto" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Disabilita le notifiche" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Gestisci i co-manutentori" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d richiesta in attesa" msgstr[1] "%d richieste in attesa" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotta il pacchetto" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Dettagli del pacchetto base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "sola lettura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Parole chiave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Contributore" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Manutentore" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ultimo pacchettizzatore" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Voti" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popolarità" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Data del primo invio" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ultimo aggiornamento" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Modifica il commento di: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Aggiungi un commento" +#: template/pkg_comments.php msgid "View all comments" msgstr "Mostra tutti i commenti" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Elimina i commenti" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Ultimi commenti" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s ha commentato su %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Commento anonimo su %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "Eliminato su %s da %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Rimuovi il commento" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Inserisci il commento" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Elimina il commento" +#: template/pkg_comments.php msgid "All comments" msgstr "Tutti i commenti" +#: template/pkg_details.php msgid "Package Details" msgstr "Dettagli del pacchetto" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacchetto base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrizione" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL dell'upstream" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visita il sito web di" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenze" +#: template/pkg_details.php msgid "Groups" msgstr "Gruppi" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitti" +#: template/pkg_details.php msgid "Provides" msgstr "Fornisce" +#: template/pkg_details.php msgid "Replaces" msgstr "Rimpiazza" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dipendenze" +#: template/pkg_details.php msgid "Required by" msgstr "Richiesto da" +#: template/pkg_details.php msgid "Sources" msgstr "Sorgenti" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Usa questo modulo per chiudere la richiesta del pacchetto base %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Il campo dei commenti può essere lasciato vuoto. Tuttavia, è consigliabile " -"aggiungere un commento quando non si accetta una richiesta." +msgstr "Il campo dei commenti può essere lasciato vuoto. Tuttavia, è consigliabile aggiungere un commento quando non si accetta una richiesta." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motivo" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Accettato" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rifiutato" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Usa questo modulo per inviare una richiesta per il pacchetto base %s%s%s che " -"include i seguenti pacchetti:" +msgstr "Usa questo modulo per inviare una richiesta per il pacchetto base %s%s%s che include i seguenti pacchetti:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo di richiesta" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Elimina" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Abbandona" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Unisci con" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1372,6 +1680,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1379,248 +1688,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d di %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pacchetto" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Inviato da" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d ora rimanente" msgstr[1] "~%d ore rimanenti" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 ora rimanente" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accetta" +#: template/pkgreq_results.php msgid "Locked" msgstr "Bloccato" +#: template/pkgreq_results.php msgid "Close" msgstr "Chiudi" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Chiuso" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descrizione" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Solo il nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome esatto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacchetto base esatto" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Tutti" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Non aggiornati" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Aggiornati" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votato" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Ultima modifica" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Discendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Seleziona i criteri di ricerca" +#: template/pkg_search_form.php msgid "Search by" msgstr "Cerca per" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Non aggiornati" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordina per" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordina in modo" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Cerca" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfani" +#: template/pkg_search_results.php msgid "Error retrieving package list." -msgstr "" -"Si è verificato un errore durante il recupero della lista dei pacchetti." +msgstr "Si è verificato un errore durante il recupero della lista dei pacchetti." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nessun pacchetto corrisponde ai tuoi criteri di ricerca." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." +#: template/pkg_search_results.php msgid "Version" msgstr "Versione" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sì" +#: template/pkg_search_results.php msgid "orphan" msgstr "orfano" +#: template/pkg_search_results.php msgid "Actions" msgstr "Azioni" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Il pacchetto è aggiornato" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adotta il pacchetto" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abbandona il pacchetto" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Elimina il pacchetto" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Conferma" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualsiasi tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Cerca" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistiche" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacchetti orfani" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacchetti aggiunti negli ultimi 7 giorni" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacchetti aggiornati negli ultimi 7 giorni" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacchetti aggiornati nell'ultimo anno" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacchetti mai aggiornati" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utenti registrati" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "TU" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Aggiornamenti recenti" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Le mie statistiche" +#: template/tu_details.php msgid "Proposal Details" msgstr "Dettagli della proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Questa votazione è ancora in corso." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Inviato: %s da %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fine" +#: template/tu_details.php msgid "Result" msgstr "Risultato" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "No" +#: template/tu_details.php msgid "Abstain" msgstr "Astenuto" +#: template/tu_details.php msgid "Total" msgstr "Totale" +#: template/tu_details.php msgid "Participation" msgstr "Partecipazione" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ultimi voti dei TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ultimo voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "La ricerca non ha prodotto nessun risultato." +#: template/tu_list.php msgid "Start" msgstr "Home" +#: template/tu_list.php msgid "Back" msgstr "Precedente" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/ja.po b/po/ja.po index ea1a021d..4c8034b9 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # kusakata, 2013 # kusakata, 2013 @@ -9,1610 +9,2123 @@ # 尾ノ上卓朗 , 2017 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Japanese (http://www.transifex.com/lfleischer/aur/language/" -"ja/)\n" -"Language: ja\n" +"Language-Team: Japanese (http://www.transifex.com/lfleischer/aurweb/language/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: ja\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: html/404.php msgid "Page Not Found" msgstr "ページが見つかりませんでした" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "あなたがリクエストしたページは存在しませんでした。" +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "ノート" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Git のクローン URL はブラウザで開いてはいけません。" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "%s の Git リポジトリを複製するには、%s を実行してください。" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "%sこちら%sをクリックすると %s の詳細ページに戻ります。" +#: html/503.php msgid "Service Unavailable" msgstr "サービスは利用できません。" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"落ち着いて下さい!このサイトはメンテナンスのためにダウンしています。すぐに復" -"帰する予定です。" +msgstr "落ち着いて下さい!このサイトはメンテナンスのためにダウンしています。すぐに復帰する予定です。" +#: html/account.php msgid "Account" msgstr "アカウント" +#: html/account.php template/header.php msgid "Accounts" msgstr "アカウント" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "このページへのアクセスは許可されていません。" +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "指定のユーザーの情報が取得できませんでした。" +#: html/account.php msgid "You do not have permission to edit this account." msgstr "あなたはこのアカウントを編集する権利を持っていません。" +#: html/account.php msgid "Use this form to search existing accounts." msgstr "アカウントの検索はこのフォームを使って下さい。" +#: html/account.php msgid "You must log in to view user information." msgstr "ユーザー情報を見るにはログインする必要があります。" +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "提案を追加する" +#: html/addvote.php msgid "Invalid token for user action." msgstr "アクションの不正なトークン。" +#: html/addvote.php msgid "Username does not exist." msgstr "ユーザー名が存在しません。" +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s はすでにその提案を持っています。" +#: html/addvote.php msgid "Invalid type." msgstr "不正なタイプ。" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "提案が空です。" +#: html/addvote.php msgid "New proposal submitted." msgstr "新しい提案が投稿されました。" +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "採決する提案を提出してください。" +#: html/addvote.php msgid "Applicant/TU" msgstr "候補者/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(適当なものがない場合は空に)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "タイプ" +#: html/addvote.php msgid "Addition of a TU" msgstr "TU の追加" +#: html/addvote.php msgid "Removal of a TU" msgstr "TU の削除" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "TU の削除 (undeclared inactivity)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "規約の修正" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "提案" +#: html/addvote.php msgid "Submit" msgstr "投稿" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "共同メンテナの管理" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "コメントを編集" +#: html/home.php template/header.php msgid "Dashboard" msgstr "ダッシュボード" +#: html/home.php template/header.php msgid "Home" msgstr "ホーム" +#: html/home.php msgid "My Flagged Packages" msgstr "自分のフラグが立っているパッケージ" +#: html/home.php msgid "My Requests" msgstr "自分のリクエスト" +#: html/home.php msgid "My Packages" msgstr "自分のパッケージ" +#: html/home.php msgid "Search for packages I maintain" msgstr "メンテしているパッケージを検索" +#: html/home.php msgid "Co-Maintained Packages" msgstr "共同メンテしているパッケージ" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "共同メンテしているパッケージを検索" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"AUR にようこそ!AUR についての詳しい情報は %sAUR User Guidelines%s や %sAUR " -"TU Guidelines%s を読んで下さい。" +msgstr "AUR にようこそ!AUR についての詳しい情報は %sAUR User Guidelines%s や %sAUR TU Guidelines%s を読んで下さい。" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"PKGBUILD を投稿するつもりならば%s必ず%s %sArch Packaging Standards%s に従って" -"下さい。従っていないパッケージは削除されます!" +msgstr "PKGBUILD を投稿するつもりならば%s必ず%s %sArch Packaging Standards%s に従って下さい。従っていないパッケージは削除されます!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "お気に入りのパッケージに投票しましょう!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"パッケージがバイナリとして [community] で提供されることになるかもしれません。" +msgstr "パッケージがバイナリとして [community] で提供されることになるかもしれません。" +#: html/home.php msgid "DISCLAIMER" msgstr "免責事項" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"AUR のパッケージはユーザーによって作成されたものです。自己責任で使用して下さ" -"い。" +msgstr "AUR のパッケージはユーザーによって作成されたものです。自己責任で使用して下さい。" +#: html/home.php msgid "Learn more..." msgstr "詳細..." +#: html/home.php msgid "Support" msgstr "サポート" +#: html/home.php msgid "Package Requests" msgstr "パッケージリクエスト" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"各パッケージの詳細ページにある%sパッケージアクション%sボックスから送信するこ" -"とができるリクエストは3種類あります:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "各パッケージの詳細ページにある%sパッケージアクション%sボックスから送信することができるリクエストは3種類あります:" +#: html/home.php msgid "Orphan Request" msgstr "孤児リクエスト" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"パッケージを孤児にするようにリクエストします。メンテナが活動を停止していて" -"パッケージが長い間 out-of-date のまま放置されている場合などに使います。" +msgstr "パッケージを孤児にするようにリクエストします。メンテナが活動を停止していてパッケージが長い間 out-of-date のまま放置されている場合などに使います。" +#: html/home.php msgid "Deletion Request" msgstr "削除リクエスト" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Arch User Repository からパッケージを削除するようにリクエストします。パッケー" -"ジが壊れていて、その不具合を簡単に修正できるような場合、このリクエストは使わ" -"ないで下さい。代わりに、パッケージのメンテナに連絡したり、必要に応じて孤児リ" -"クエストを送りましょう。" +msgstr "Arch User Repository からパッケージを削除するようにリクエストします。パッケージが壊れていて、その不具合を簡単に修正できるような場合、このリクエストは使わないで下さい。代わりに、パッケージのメンテナに連絡したり、必要に応じて孤児リクエストを送りましょう。" +#: html/home.php msgid "Merge Request" msgstr "マージリクエスト" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"あるパッケージを他のパッケージとマージするようにリクエストします。パッケージ" -"の名前を変更する必要があるときや分割パッケージによって置き換えるときに使用し" -"ます。" +msgstr "あるパッケージを他のパッケージとマージするようにリクエストします。パッケージの名前を変更する必要があるときや分割パッケージによって置き換えるときに使用します。" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"リクエストについて議論したい場合、%saur-requests%s メーリングリストを使いま" -"す。ただし、このメーリングリスト宛にリクエストを送るのは止めて下さい。" +msgstr "リクエストについて議論したい場合、%saur-requests%s メーリングリストを使います。ただし、このメーリングリスト宛にリクエストを送るのは止めて下さい。" +#: html/home.php msgid "Submitting Packages" msgstr "パッケージの投稿" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"現在 AUR にパッケージを送信するときは SSH を介して Git を使うことになっていま" -"す。詳しくは ArchWiki の Arch User Repository のページの%sパッケージの投稿%s" -"セクションを見て下さい。" +msgstr "現在 AUR にパッケージを送信するときは SSH を介して Git を使うことになっています。詳しくは ArchWiki の Arch User Repository のページの%sパッケージの投稿%sセクションを見て下さい。" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR では以下の SSH フィンガープリントが使われます:" +#: html/home.php msgid "Discussion" msgstr "議論" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Arch User Repository (AUR) や Trusted User に関する一般的な議論は %saur-" -"general%s で行って下さい。AUR ウェブインターフェイスの開発に関しては、%saur-" -"dev%s メーリングリストを使用します。" +msgstr "Arch User Repository (AUR) や Trusted User に関する一般的な議論は %saur-general%s で行って下さい。AUR ウェブインターフェイスの開発に関しては、%saur-dev%s メーリングリストを使用します。" +#: html/home.php msgid "Bug Reporting" msgstr "バグレポート" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"AUR のウェブインターフェイスにバグを発見した時は%sバグトラッカー%sにバグを報" -"告してください。トラッカーを使って報告できるバグは AUR ウェブインターフェイス" -"のバグ%sだけ%sです。パッケージのバグを報告するときはパッケージのメンテナに連" -"絡するか該当するパッケージのページにコメントを投稿してください。" +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "AUR のウェブインターフェイスにバグを発見した時は%sバグトラッカー%sにバグを報告してください。トラッカーを使って報告できるバグは AUR ウェブインターフェイスのバグ%sだけ%sです。パッケージのバグを報告するときはパッケージのメンテナに連絡するか該当するパッケージのページにコメントを投稿してください。" +#: html/home.php msgid "Package Search" msgstr "パッケージ検索" +#: html/index.php msgid "Adopt" msgstr "承継" +#: html/index.php msgid "Vote" msgstr "投票" +#: html/index.php msgid "UnVote" msgstr "投票を削除" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "通知を削除" +#: html/index.php msgid "UnFlag" msgstr "フラグを降ろす" +#: html/login.php template/header.php msgid "Login" msgstr "ログイン" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "ログイン中: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "ログアウト" +#: html/login.php msgid "Enter login credentials" msgstr "ログイン情報を入力してください" +#: html/login.php msgid "User name or email address" msgstr "ユーザー名またはメールアドレス" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "パスワード" +#: html/login.php msgid "Remember me" msgstr "ログインしたままにする" +#: html/login.php msgid "Forgot Password" msgstr "パスワードを忘れた" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP ログインはできません。ログインするには %sHTTPs%s に切り替えてください。" +msgstr "HTTP ログインはできません。ログインするには %sHTTPs%s に切り替えてください。" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "検索条件" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "パッケージ" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "パッケージの詳細の取得エラー。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "必須項目が埋められていません。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "パスワードが一致しません。" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "パスワードは最低でも %s 文字以上必要です。" +#: html/passreset.php msgid "Invalid e-mail." msgstr "不正なメールアドレス。" +#: html/passreset.php msgid "Password Reset" msgstr "パスワードのリセット" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "メールをチェックして確認リンクを開いて下さい。" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "パスワードのリセットが成功しました。" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "メールアドレスの確認:" +#: html/passreset.php msgid "Enter your new password:" msgstr "新しいパスワードを入力:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "新しいパスワードを再入力:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "続行" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"登録したメールアドレスを忘れてしまった場合は、%saur-general%s メーリングリス" -"トにメッセージを送って下さい。" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "登録したメールアドレスを忘れてしまった場合は、%saur-general%s メーリングリストにメッセージを送って下さい。" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "メールアドレスを入力:" +#: html/pkgbase.php msgid "Package Bases" msgstr "パッケージベース" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"選択されたパッケージは孤児になっていません。確認チェックボックスにチェックを" -"入れて下さい。" +msgstr "選択されたパッケージは孤児になっていません。確認チェックボックスにチェックを入れて下さい。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "投票やコメントのマージをするパッケージが見つかりません。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "パッケージベースをそれ自体とマージすることはできません。" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"選択されたパッケージは削除されませんでした、確認チェックボックスにチェックを" -"入れてください。" +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "選択されたパッケージは削除されませんでした、確認チェックボックスにチェックを入れてください。" +#: html/pkgdel.php msgid "Package Deletion" msgstr "パッケージの削除" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "パッケージを削除" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"AUR からパッケージベース %s%s%s と以下のパッケージを削除するにはこのフォーム" -"を使って下さい:" +msgstr "AUR からパッケージベース %s%s%s と以下のパッケージを削除するにはこのフォームを使って下さい:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "パッケージの削除は戻すことができません。" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "アクションを確認するためにチェックボックスを選択してください。" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "パッケージ削除の確認" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "削除" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Trusted User と開発者だけがパッケージを削除できます。" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "パッケージの放棄" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"このフォームを使って以下のパッケージを含むパッケージベース %s%s%s を孤児にす" -"ることができます:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "このフォームを使って以下のパッケージを含むパッケージベース %s%s%s を孤児にすることができます:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"チェックボックスを選択して、パッケージを孤児にして所有権を %s%s%s に移すこと" -"を確定して下さい。" +msgstr "チェックボックスを選択して、パッケージを孤児にして所有権を %s%s%s に移すことを確定して下さい。" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"チェックボックスを選択して、パッケージを孤児にすることを確定してください。" +msgstr "チェックボックスを選択して、パッケージを孤児にすることを確定してください。" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "パッケージを孤児にすることの確認" +#: html/pkgdisown.php msgid "Disown" msgstr "放棄" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Trusted User と開発者だけがパッケージを孤児にできます。" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "コメントのフラグを立てる" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "パッケージの Out-Of-Date フラグを立てる" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"このフォームを使ってパッケージベース %s%s%s と以下のパッケージの out-of-date " -"フラグを立てます:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "このフォームを使ってパッケージベース %s%s%s と以下のパッケージの out-of-date フラグを立てます:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"このフォームはバグを報告するためのものでは%sありません%s。バグを報告するとき" -"はパッケージのコメント欄を使って下さい。" +msgstr "このフォームはバグを報告するためのものでは%sありません%s。バグを報告するときはパッケージのコメント欄を使って下さい。" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"以下にパッケージが out-of-date となっている理由を記述してください。なるべくリ" -"リースアナウンスや最新の tarball へのリンクも書きましょう。" +msgstr "以下にパッケージが out-of-date となっている理由を記述してください。なるべくリリースアナウンスや最新の tarball へのリンクも書きましょう。" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "コメント" +#: html/pkgflag.php msgid "Flag" msgstr "フラグ" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"パッケージの out-of-date フラグを立てることができるのは登録済みのユーザーだけ" -"です。" +msgstr "パッケージの out-of-date フラグを立てることができるのは登録済みのユーザーだけです。" +#: html/pkgmerge.php msgid "Package Merging" msgstr "パッケージのマージ" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "パッケージのマージ" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"他のパッケージにパッケージベース %s%s%s をマージするにはこのフォームを使って" -"下さい。" +msgstr "他のパッケージにパッケージベース %s%s%s をマージするにはこのフォームを使って下さい。" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "次のパッケージが削除されます:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "一度パッケージがマージされると戻すことはできません。" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "このパッケージをマージしたいパッケージ名を入力してください。" +#: html/pkgmerge.php msgid "Merge into:" msgstr "マージ先:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "パッケージマージの確認" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "マージ" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Trusted User と開発者だけがパッケージをマージできます。" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "リクエストを送信" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "リクエストをクローズ" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "最初" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "前へ" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "次へ" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "リクエスト" +#: html/register.php template/header.php msgid "Register" msgstr "登録" +#: html/register.php msgid "Use this form to create an account." msgstr "このフォームを使ってアカウントを作成してください。" +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "利用規約" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "以下の文章は更新されています。注意して読んでください:" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "改訂 %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "私は上記の利用規約を承認します。" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "提案内容が取得できませんでした。" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "この提案への投票は締め切られています。" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Trusted User だけが投票できます。" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "あなたについての提案に投票することはできません。" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "既にこの提案に投票しています。" +#: html/tu.php msgid "Vote ID not valid." msgstr "投票 ID が不正です。" +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "現在の投票" +#: html/tu.php msgid "Past Votes" msgstr "過去の投票" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票者" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"スパムのために、あなたのIPアドレスからアカウント登録はできません。ご迷惑をお" -"かけして申し訳ございません。" +msgstr "スパムのために、あなたのIPアドレスからアカウント登録はできません。ご迷惑をおかけして申し訳ございません。" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ユーザー ID の消失" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "ユーザー名が不正です。" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "文字の長さは %s から %s の間である必要があります" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "最初と最後の文字は英数字にしてください" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "ピリオド、アンダーライン、ハイフンはひとつだけ含めることができます。" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "メールアドレスが不正です。" +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "ホームページが不正です。完全な HTTP(s) URL を入力してください。" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 鍵のフィンガープリントが不正です。" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH 公開鍵が不正です。" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "アカウント権限を増やすことはできません。" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "言語は現在サポートされていません。" +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "タイムゾーンは現在サポートされていません。" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "%s%s%s というユーザー名は既に使われています。" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "%s%s%s というメールアドレスは既に使われています。" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開鍵、%s%s%s は既に使われています。" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "アカウントの作成エラー、%s%s%s。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "アカウント %s%s%s の作成が完了しました。" +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "パスワードのリセットキーがあなたのメールアドレスに送られました。" +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "あなたのアカウントを使うには上のログインリンクをクリックして下さい。" +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "アカウントに変更は加えられませんでした、%s%s%s。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "アカウント %s%s%s の修正が完了しました。" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"スパムのために、現在あなたのIPアドレスからはログインフォームが無効になってい" -"ます。ご迷惑をおかけして申し訳ございません。" +msgstr "スパムのために、現在あなたのIPアドレスからはログインフォームが無効になっています。ご迷惑をおかけして申し訳ございません。" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "休眠アカウント" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"あなたのパスワードはリセットされました。新しいアカウントを作成したときは、確" -"認メールにあるリンクからパスワードを設定してください。もしくは、%sPassword " -"Reset%s ページでリセットキーを申請してください。" +msgstr "あなたのパスワードはリセットされました。新しいアカウントを作成したときは、確認メールにあるリンクからパスワードを設定してください。もしくは、%sPassword Reset%s ページでリセットキーを申請してください。" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "不正なユーザー名またはパスワードです。" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "ユーザーセッションの生成時にエラーが発生しました。" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "メールアドレスとリセットキーの不正な組み合わせ。" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "なし" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "%s のアカウント情報を見る" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "パッケージベース ID やパッケージベース名が見つかりません。" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "このコメントを編集する権限がありません。" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "コメントが存在しません。" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "コメントには何か文字列を記入してください。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "コメントが追加されました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "パッケージの情報を編集するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "コメント ID が見つかりません。" +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "5個までコメントをピン留めできます。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "このコメントをピン留めする権限がありません。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "このコメントのピン留めを解除する権限がありません。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "コメントはピン留めされました。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "コメントのピン留めは解除されました。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "パッケージの詳細の取得エラー。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "パッケージの詳細が見つかりませんでした。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "パッケージのフラグを立てるにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "フラグを立てるパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"選択されたパッケージはまだフラグが立てられていません、コメントを入力してくだ" -"さい。" +msgstr "選択されたパッケージはまだフラグが立てられていません、コメントを入力してください。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "選択されたパッケージの out-of-date フラグが立てられました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "パッケージのフラグを降ろすにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "フラグを降ろすパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "選択されたパッケージのフラグが降ろされました。" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "あなたはパッケージを削除する許可を持っていません。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "削除するパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "選択されたパッケージが削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "パッケージを承継するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "パッケージを放棄するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "承継するパッケージが選択されていません。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "放棄するパッケージが選択されていません。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "選択されたパッケージを承継しました。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "選択されたパッケージを放棄しました。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "パッケージに投票するにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "パッケージへの投票を取り消すにはログインする必要があります。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "投票するパッケージが選ばれていません。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "選択されたパッケージからあなたの投票が削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "選択されたパッケージに投票しました。" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "通知リストに追加できませんでした。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "%s がコメントの通知リストに追加されました。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "%s がコメントの通知リストから削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "このコメントを復元する権限がありません。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "コメントは復元されました。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "このコメントを削除することはできません。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "コメントが削除されました。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "コメントは編集されました。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "このパッケージベースのキーワードを編集することはできません。" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "パッケージベースのキーワードは更新されました。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "このパッケージベースの共同メンテナを管理することはできません。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "不正なユーザー名: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "パッケージベースの共同メンテナが更新されました。" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "パッケージの詳細を見る" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "%s が必要" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "パッケージリクエストを送るにはログインする必要があります。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "不正な名前です: 小文字だけが使用できます。" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "コメント欄には何か記入して下さい。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "不正なリクエストの種類。" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "リクエストの追加が完了しました。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "不正な理由。" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "TU と開発者だけがリクエストをクローズできます。" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "リクエストのクローズが完了しました。" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"このフォームを使って AUR アカウント %s を恒久的に削除することができます。" +msgstr "このフォームを使って AUR アカウント %s を恒久的に削除することができます。" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s: この操作は元に戻すことができません。" +#: template/account_delete.php msgid "Confirm deletion" msgstr "削除の確認" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "ユーザー名" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "アカウントタイプ" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "ユーザー" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "開発者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & 開発者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "メールアドレス" +#: template/account_details.php msgid "hidden" msgstr "非公開" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "本名" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "ホームページ" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC ニックネーム" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 鍵のフィンガープリント" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "状態" +#: template/account_details.php msgid "Inactive since" msgstr "休止開始" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "活動中" +#: template/account_details.php msgid "Registration date:" msgstr "登録日:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "不明" +#: template/account_details.php msgid "Last Login" msgstr "最後のログイン" +#: template/account_details.php msgid "Never" msgstr "Never" +#: template/account_details.php msgid "View this user's packages" msgstr "ユーザーのパッケージを見る" +#: template/account_details.php msgid "Edit this user's account" msgstr "このユーザーのアカウントを編集" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "このアカウントを恒久的に削除したい場合は%sこちら%sをクリック。" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "ユーザーの詳細は%sこちら%sをクリック。" +#: template/account_edit_form.php msgid "required" msgstr "必須" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" +msgstr "ユーザー名はログインするときに使用する名前です。活動休止中でも一般に公開されます。" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "ノーマルユーザー" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "休眠アカウント" +#: template/account_edit_form.php msgid "Inactive" msgstr "活動休止" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"入力したメールアドレスが正しいか確認してください。間違っていた場合、アカウン" -"トが使えなくなります。" +msgstr "入力したメールアドレスが正しいか確認してください。間違っていた場合、アカウントが使えなくなります。" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "メールアドレスを非公開にする" +#: template/account_edit_form.php msgid "Re-type password" msgstr "パスワードの再入力" +#: template/account_edit_form.php msgid "Language" msgstr "言語" +#: template/account_edit_form.php msgid "Timezone" msgstr "タイムゾーン" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"以下の情報は Arch User Repository にパッケージを送信したい場合にのみ必要にな" -"ります。" +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "以下の情報は Arch User Repository にパッケージを送信したい場合にのみ必要になります。" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH 公開鍵" +#: template/account_edit_form.php msgid "Notification settings" msgstr "通知設定" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "新しいコメントを通知" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "パッケージアップデートの通知" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "所有者の変更の通知" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "更新" +#: template/account_edit_form.php msgid "Create" msgstr "作成" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "リセット" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "検索条件に一致する結果が見つかりませんでした。" +#: template/account_search_results.php msgid "Edit Account" msgstr "アカウントを編集" +#: template/account_search_results.php msgid "Suspended" msgstr "休止" +#: template/account_search_results.php msgid "Edit" msgstr "編集" +#: template/account_search_results.php msgid "Less" msgstr "Less" +#: template/account_search_results.php msgid "More" msgstr "More" +#: template/account_search_results.php msgid "No more results to display." msgstr "表示する結果はもうありません。" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"このフォームを使って %s%s%s の共同メンテナを追加することができます (一行につ" -"き一人のユーザー名を入力):" +msgstr "このフォームを使って %s%s%s の共同メンテナを追加することができます (一行につき一人のユーザー名を入力):" +#: template/comaintainers_form.php msgid "Users" msgstr "ユーザー" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "保存" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Out-of-Date フラグが立てられたコメント: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s は %s%s%s を %s%s%s に以下の理由で out-of-date フラグを立てました:" +msgstr "%s%s%s は %s%s%s を %s%s%s に以下の理由で out-of-date フラグを立てました:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s は out-of-date フラグが立てられていません。" +#: template/flag_comment.php msgid "Return to Details" msgstr "詳細に戻る" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." +#: template/header.php msgid " My Account" msgstr "アカウント" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "パッケージアクション" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD を見る" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "変更履歴" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "スナップショットのダウンロード" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "wiki を検索" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "out-of-date フラグが立てられています (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "パッケージの out-of-date フラグを立てる" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "パッケージのフラグを降ろす" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "投票を削除する" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "このパッケージに投票する" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "通知を止める" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "通知を有効にする" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "共同メンテナの管理" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 件の保留リクエスト。" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "パッケージを承継する" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "パッケージベースの詳細" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git クローン URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "リードオンリー" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "キーワード" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "投稿者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "メンテナ" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最後のパッケージ作成者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "投票数" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "人気度" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "最初の投稿" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最終更新" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "コメントを編集: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "コメントを投稿する" +#: template/pkg_comments.php msgid "View all comments" msgstr "全てのコメントを表示" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "ピン留めされたコメント" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "最新のコメント" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s が %s にコメントを投稿しました" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "匿名ユーザーが %s にコメントを投稿しました" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "%s によって %s に削除" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "%s に削除" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "%s に %s によって編集" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "%s に編集" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "コメントを復元" +#: template/pkg_comments.php msgid "Delete comment" msgstr "コメントを削除" +#: template/pkg_comments.php msgid "Pin comment" msgstr "コメントをピン留めする" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "コメントのピン留めを解除" +#: template/pkg_comments.php msgid "All comments" msgstr "全てのコメント" +#: template/pkg_details.php msgid "Package Details" msgstr "パッケージの詳細" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "パッケージベース" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "説明" +#: template/pkg_details.php msgid "Upstream URL" msgstr "上流 URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "ウェブサイトを見る" +#: template/pkg_details.php msgid "Licenses" msgstr "ライセンス" +#: template/pkg_details.php msgid "Groups" msgstr "グループ" +#: template/pkg_details.php msgid "Conflicts" msgstr "衝突" +#: template/pkg_details.php msgid "Provides" msgstr "提供" +#: template/pkg_details.php msgid "Replaces" msgstr "置換" +#: template/pkg_details.php msgid "Dependencies" msgstr "依存パッケージ" +#: template/pkg_details.php msgid "Required by" msgstr "必要としているパッケージ" +#: template/pkg_details.php msgid "Sources" msgstr "ソース" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"このフォームを使ってパッケージベース %s%s%s のリクエストをクローズすることが" -"できます。" +msgstr "このフォームを使ってパッケージベース %s%s%s のリクエストをクローズすることができます。" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"コメント欄は空でもかまいません。ただし、リクエストを却下されたときはコメント" -"を追加することを強く推奨します。" +msgstr "コメント欄は空でもかまいません。ただし、リクエストを却下されたときはコメントを追加することを強く推奨します。" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "理由" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "承認されました" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "却下されました" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"このフォームを使って以下のパッケージを含むパッケージベース %s%s%s にリクエス" -"トを送ることができます:" +msgstr "このフォームを使って以下のパッケージを含むパッケージベース %s%s%s にリクエストを送ることができます:" +#: template/pkgreq_form.php msgid "Request type" msgstr "リクエストの種類" +#: template/pkgreq_form.php msgid "Deletion" msgstr "削除" +#: template/pkgreq_form.php msgid "Orphan" msgstr "孤児" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "マージ" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"削除リクエストを送信することで、Trusted User にパッケージベースの削除を要求で" -"きます。削除リクエストを使用するケース: パッケージの重複や、上流によってソフ" -"トウェアの開発が放棄された場合、違法なパッケージ、あるいはパッケージがどうし" -"ようもなく壊れてしまっている場合など。" +msgstr "削除リクエストを送信することで、Trusted User にパッケージベースの削除を要求できます。削除リクエストを使用するケース: パッケージの重複や、上流によってソフトウェアの開発が放棄された場合、違法なパッケージ、あるいはパッケージがどうしようもなく壊れてしまっている場合など。" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"マージリクエストを送信することで、パッケージベースを削除して\n" -"投票数とコメントを他のパッケージベースに移動することを Trusted User に要求で" -"きます。パッケージのマージは Git リポジトリに影響を与えません。マージ先のパッ" -"ケージの Git 履歴は自分で更新してください。" +msgstr "マージリクエストを送信することで、パッケージベースを削除して\n投票数とコメントを他のパッケージベースに移動することを Trusted User に要求できます。パッケージのマージは Git リポジトリに影響を与えません。マージ先のパッケージの Git 履歴は自分で更新してください。" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"孤児リクエストを送信することで、パッケージベースの所有権が放棄されるように " -"Trusted User に要求できます。パッケージにメンテナが何らかの手を加える必要があ" -"り、現在のメンテナが行方不明で、メンテナに連絡を取ろうとしても返答がない場合" -"にのみ、リクエストを送信してください。" +msgstr "孤児リクエストを送信することで、パッケージベースの所有権が放棄されるように Trusted User に要求できます。パッケージにメンテナが何らかの手を加える必要があり、現在のメンテナが行方不明で、メンテナに連絡を取ろうとしても返答がない場合にのみ、リクエストを送信してください。" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "検索条件に一致するリクエストがありません。" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "パッケージリクエストが %d 個見つかりました。" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "ページ %d / %d。" +#: template/pkgreq_results.php msgid "Package" msgstr "パッケージ" +#: template/pkgreq_results.php msgid "Filed by" msgstr "送信者" +#: template/pkgreq_results.php msgid "Date" msgstr "日付" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "残り ~%d 日" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "残り ~%d 時間" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "残り <1 時間" +#: template/pkgreq_results.php msgid "Accept" msgstr "承認" +#: template/pkgreq_results.php msgid "Locked" msgstr "ロックされています" +#: template/pkgreq_results.php msgid "Close" msgstr "クローズ" +#: template/pkgreq_results.php msgid "Pending" msgstr "保留中" +#: template/pkgreq_results.php msgid "Closed" msgstr "クローズされました" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "名前、説明" +#: template/pkg_search_form.php msgid "Name Only" msgstr "名前のみ" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "名前完全一致" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "パッケージベース完全一致" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "共同メンテナ" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "メンテナ, 共同メンテナ" +#: template/pkg_search_form.php msgid "All" msgstr "全て" +#: template/pkg_search_form.php msgid "Flagged" msgstr "フラグ付き" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "フラグなし" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名前" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "投票済" +#: template/pkg_search_form.php msgid "Last modified" msgstr "最終更新日" +#: template/pkg_search_form.php msgid "Ascending" msgstr "昇順" +#: template/pkg_search_form.php msgid "Descending" msgstr "降順" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "検索条件を入力" +#: template/pkg_search_form.php msgid "Search by" msgstr "検索対象" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Out of Date" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "ソート" +#: template/pkg_search_form.php msgid "Sort order" msgstr "ソート順" +#: template/pkg_search_form.php msgid "Per page" msgstr "表示件数" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "検索" +#: template/pkg_search_form.php msgid "Orphans" msgstr "孤児のパッケージ" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "パッケージリスト取得エラー。" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "検索条件に一致するパッケージがありません。" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "パッケージが %d 個見つかりました。" +#: template/pkg_search_results.php msgid "Version" msgstr "バージョン" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"人気度は各投票にパッケージ作成日からの日数を %.2f 倍した全投票の合計で計算さ" -"れます。" +msgstr "人気度は各投票にパッケージ作成日からの日数を %.2f 倍した全投票の合計で計算されます。" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "はい" +#: template/pkg_search_results.php msgid "orphan" msgstr "孤児" +#: template/pkg_search_results.php msgid "Actions" msgstr "アクション" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Out-of-date フラグを降ろす" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "パッケージの承継" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "パッケージの放棄" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "パッケージの削除" +#: template/pkg_search_results.php msgid "Confirm" msgstr "確認" +#: template/search_accounts_form.php msgid "Any type" msgstr "全てのタイプ" +#: template/search_accounts_form.php msgid "Search" msgstr "検索" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "統計" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "孤児のパッケージ" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "過去7日間で追加されたパッケージ" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "過去7日間で更新されたパッケージ" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "過去1年間で更新されたパッケージ" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "更新されたことがないパッケージ" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "登録ユーザー" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted User" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最近のアップデート" +#: template/stats/updates_table.php msgid "more" msgstr "詳細" +#: template/stats/user_table.php msgid "My Statistics" msgstr "自分の統計" +#: template/tu_details.php msgid "Proposal Details" msgstr "提案の詳細" +#: template/tu_details.php msgid "This vote is still running." msgstr "投票が実行されています。" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "投稿: %s by %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "終了" +#: template/tu_details.php msgid "Result" msgstr "結果" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "いいえ" +#: template/tu_details.php msgid "Abstain" msgstr "棄権" +#: template/tu_details.php msgid "Total" msgstr "合計" +#: template/tu_details.php msgid "Participation" msgstr "参加" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "TU による最後の投票" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最後の投票" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "結果が見つかりませんでした。" +#: template/tu_list.php msgid "Start" msgstr "開始" +#: template/tu_list.php msgid "Back" msgstr "前へ" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/nb.po b/po/nb.po index 58c9501f..438a6600 100644 --- a/po/nb.po +++ b/po/nb.po @@ -1,9 +1,9 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: -# Alexander F Rødseth , 2015,2017 +# Alexander F Rødseth , 2015,2017-2018 # Alexander F Rødseth , 2011,2013-2014 # Harald H. , 2015 # Kim Nordmo , 2016 @@ -11,1606 +11,2128 @@ # Thor K. H. , 2016 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aur/" -"language/nb/)\n" -"Language: nb\n" +"Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aurweb/language/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: nb\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Finner ikke siden" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Den ønskede siden finnes ikke." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "OBS" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Nettleseren kan ikke åpne Git URL-er." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "For å klone et Git arkiv fra %s, kjør %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "Klikk %sher%s for å returnere til detalj-siden for %s." +msgstr "Klikk %sher%s for å gå tilbake til detalj-siden for %s." +#: html/503.php msgid "Service Unavailable" msgstr "Tjenesten er utilgjengelig" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "Slapp av! Siden er nede på grunn av vedlikehold. Vi er snart tilbake." +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Kontoer" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Du har ikke adgang til dette området." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kunne ikke hente informasjon om den valgte brukeren." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Du har ikke tilgang til å endre denne kontoen." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Bruk skjemaet for å søke etter eksisterende kontoer." +#: html/account.php msgid "You must log in to view user information." msgstr "Du må logge inn for å kunne se brukerinformasjon." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Legg til forslag" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Ugyldig billett for brukerhandling." +#: html/addvote.php msgid "Username does not exist." msgstr "Brukernavnet finnes ikke." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s har allerede et forslag på gang." +#: html/addvote.php msgid "Invalid type." msgstr "Ugyldig type." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Forslag kan ikke være tomme." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nytt forslag innsendt." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Send inn et forslag for å stemme over." +#: html/addvote.php msgid "Applicant/TU" msgstr "Søker/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(tomt hvis det ikke gjelder her)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "Utnevnelse av TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Fjerning av TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Fjerning av TU (inaktiv uten å si i fra)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Endring av vedtekter" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Forslag" +#: html/addvote.php msgid "Submit" msgstr "Send inn" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Administrer med-vedlikeholdere" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Rediger kommentar" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Instrumentpanel" +#: html/home.php template/header.php msgid "Home" msgstr "Hjem" +#: html/home.php msgid "My Flagged Packages" msgstr "Mine flaggede pakker" +#: html/home.php msgid "My Requests" msgstr "Mine forespørsler" +#: html/home.php msgid "My Packages" msgstr "Mine pakker" +#: html/home.php msgid "Search for packages I maintain" msgstr "Søk etter pakker jeg vedlikeholder" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Med-vedlikeholdte pakker" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Søk etter pakker jeg er med på å vedlikeholde" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Velkommen til AUR! Vennligst les %sAUR Brukerveiledning%s og %sAUR TU " -"Veiledning%s for mer informasjon." +msgstr "Velkommen til AUR! Vennligst les %sAUR Brukerveiledning%s og %sAUR TU Veiledning%s for mer informasjon." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Innsendte PKGBUILD-filer %små%s følge %sStandarden for Arch Pakker%s ellers " -"vil de bli slettet!" +msgstr "Innsendte PKGBUILD-filer %små%s følge %sStandarden for Arch Pakker%s ellers vil de bli slettet!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Husk å stemme på dine favorittpakker!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Noen pakker finnes som binærfiler i [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ANSVARSFRASKRIVELSE" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Pakker i AUR kan lages av hvem som helst. All bruk av filer herfra skjer på " -"eget ansvar." +msgstr "Pakker i AUR kan lages av hvem som helst. All bruk av filer herfra skjer på eget ansvar." +#: html/home.php msgid "Learn more..." msgstr "Lær mer..." +#: html/home.php msgid "Support" msgstr "Brukerstøtte" +#: html/home.php msgid "Package Requests" msgstr "Pakkeforespørsler" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Det er tre forskjellige forespørsler som kan velges i %sPakkenhandling%s-" -"boksen på siden til en pakke:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Det er tre forskjellige forespørsler som kan velges i %sPakkenhandling%s-boksen på siden til en pakke:" +#: html/home.php msgid "Orphan Request" -msgstr "Forespør at pakken gjøres eierløs" +msgstr "Frigjøringsforespørsel" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Forespør at pakken gjøres eierløs, f.eks. når vedlikeholderen er inaktiv og " -"pakken har vært flagget som utdatert i en lengre periode." +msgstr "Forespør at pakken gjøres eierløs, f.eks. når vedlikeholderen er inaktiv og pakken har vært flagget som utdatert i en lengre periode." +#: html/home.php msgid "Deletion Request" msgstr "Forespør sletting" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Forespør at pakken fjernes fra Arch User Repository. Ikke gjør dette hvis " -"pakken er ødelagt og lett kan fikses. Ta kontakt med vedlikeholderen i " -"stedet, eller forespør at pakken gjøres eierløs." +msgstr "Forespør at pakken fjernes fra Arch User Repository. Ikke gjør dette hvis pakken er ødelagt og lett kan fikses. Ta kontakt med vedlikeholderen i stedet, eller forespør at pakken gjøres eierløs." +#: html/home.php msgid "Merge Request" msgstr "Fletteforespørsel" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Forespør at pakken flettes inn i en annen. Kan brukes når en pakke trenger å " -"bytte navn eller å bli erstattet av en oppsplittet pakke." +msgstr "Forespør at pakken flettes inn i en annen. Kan brukes når en pakke trenger å bytte navn eller å bli erstattet av en oppsplittet pakke." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Hvis du vil diskutere en forespørsel kan du bruke %saur-request%s e-post " -"listen. Vennligst ikke send nye forespørsler dit." +msgstr "Hvis du vil diskutere en gitt forespørsel kan du kontakte e-postlisten %saur-request%s. Vennligst ikke send selve forespørselen dit." +#: html/home.php msgid "Submitting Packages" msgstr "Innsending av pakker" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git over SSH brukes nå for å sende inn pakker til AUR. Ta en titt på " -"%sSubmitting packages%s-seksjonen til Arch User Repository sin wikiside for " -"nærmere detaljer." +msgstr "Git over SSH brukes nå for å sende inn pakker til AUR. Ta en titt på %sSubmitting packages%s-seksjonen til Arch User Repository sin wikiside for nærmere detaljer." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Følgende SSH-fingeravtrykk brukes for AUR:" +#: html/home.php msgid "Discussion" msgstr "Diskusjon" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Generell diskusjon rundt Arch sitt brukerstyrte pakkebibliotek (AUR) og " -"strukturen rundt betrodde brukere, foregår på %saur-general%s. For " -"diskusjoner relatert til utviklingen av AUR web-grensesnittet, bruk %saur-dev" -"%s e-postlisten." +msgstr "Generell diskusjon rundt Arch sitt brukerstyrte pakkebibliotek (AUR) og strukturen rundt betrodde brukere, foregår på %saur-general%s. For diskusjoner relatert til utviklingen av AUR web-grensesnittet, bruk %saur-dev%s e-postlisten." +#: html/home.php msgid "Bug Reporting" msgstr "Feilrapportering" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Vennligst fyll ut en feilrapport i %sfeilrapporteringssystemet%s dersom du " -"finner en feil i AUR sitt web-grensesnitt. Bruk denne %skun%s til å " -"rapportere feil som gjelder AUR sitt web-grensesnitt. For å rapportere feil " -"med pakker, kontakt personen som vedlikeholder pakken eller legg igjen en " -"kommentar på siden til den aktuelle pakken." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Vennligst fyll ut en feilrapport i %sfeilrapporteringssystemet%s dersom du finner en feil i AUR sitt web-grensesnitt. Bruk denne %skun%s til å rapportere feil som gjelder AUR sitt web-grensesnitt. For å rapportere feil med pakker, kontakt personen som vedlikeholder pakken eller legg igjen en kommentar på siden til den aktuelle pakken." +#: html/home.php msgid "Package Search" msgstr "Pakkesøk" +#: html/index.php msgid "Adopt" msgstr "Adopter" +#: html/index.php msgid "Vote" msgstr "Stem" +#: html/index.php msgid "UnVote" msgstr "Fjern stemme" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Påminnelse" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Fjern påminnelse" +#: html/index.php msgid "UnFlag" msgstr "Ta bort flagg" +#: html/login.php template/header.php msgid "Login" msgstr "Logg inn" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Logget inn som: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Logg ut" +#: html/login.php msgid "Enter login credentials" msgstr "Fyll ut innloggingsinformasjon" +#: html/login.php msgid "User name or email address" msgstr "Brukernavn eller e-postadresse" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Passord" +#: html/login.php msgid "Remember me" msgstr "Husk meg" +#: html/login.php msgid "Forgot Password" msgstr "Glemt passord" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP-innlogging er deaktivert. %sBytt til HTTPs%s for å logge inn." +msgstr "HTTP-innlogging er slått av. %sBytt til HTTPs%s for å logge inn." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Søkekriterier" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakker" +#: html/packages.php msgid "Error trying to retrieve package details." -msgstr "Feil oppstod ved henting av pakkedetaljer." +msgstr "Feil ved henting av pakkedetaljer." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Mangler et nødvendig felt." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Passord-feltene stemmer ikke overens." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Passordet må være på minst %s tegn." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ugyldig e-post." +#: html/passreset.php msgid "Password Reset" msgstr "Tilbakestill passord" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "" -"Sjekk e-posten og bruk den tilsendte lenken for å bekrefte registreringen." +msgstr "Sjekk e-posten og bruk den tilsendte lenken for å bekrefte registreringen." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Passordet ditt er nullstilt." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bekreft e-postadressen din:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Angi et nytt passord:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bekreft ditt nye passord:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Fortsett" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Hvis du har glemt e-postadressen du brukte for å registrere deg, så kan du " -"sende en e-post til listen %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Hvis du har glemt e-postadressen du brukte for å registrere deg, så kan du sende en e-post til listen %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Angi din e-postadresse:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Pakkebaser" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"De valgte pakkene har ikke blitt gjort eierløse, kryss av i boksen for å " -"bekrefte." +msgstr "De valgte pakkene har ikke blitt gjort eierløse, kryss av i boksen for å bekrefte." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Kunne ikke finne pakke for å flette stemmer og kommentarer inn i." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Kan ikke slå sammen en basispakke med seg selv." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"De valgte pakkene har ikke blitt slettet, kryss av i boksen for å bekrefte." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "De valgte pakkene har ikke blitt slettet, kryss av i boksen for å bekrefte." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Sletting av pakke" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Slett pakke" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Bruk dette skjemaet for å slette basispakken %s%s%s og følgende pakker fra " -"AUR:" +msgstr "Bruk dette skjemaet for å slette basispakken %s%s%s og følgende pakker fra AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Slettingen av en pakke er endelig. " +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Kryss av i boksen for å bekrefte." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bekreft sletting av pakke" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Slett" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Bare betrodde brukere og utviklere kan slette pakker." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Gjør eierløs" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Bruk dette skjemaet for å gjøre pakkebasen %s%s%s eierløs. Den inkluderer " -"følgende pakker:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Bruk dette skjemaet for å gjøre pakkebasen %s%s%s eierløs. Den inkluderer følgende pakker:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Ved å krysse av i boksen bekrefter du at du ønsker å si fra deg pakken samt " -"overføre eierskapet til %s%s%s." +msgstr "Ved å krysse av i boksen bekrefter du at du ønsker å si fra deg pakken samt overføre eierskapet til %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Ved å krysse av i boksen bekrefter du at du ønsker å gjøre pakken eierløs." +msgstr "Ved å krysse av i boksen bekrefter du at du ønsker å gjøre pakken eierløs." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Bekreft at du ønsker å gjøre pakken eierløs." +#: html/pkgdisown.php msgid "Disown" msgstr "Gjør eierløs" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Bare betrodde brukere og Arch utviklere kan gjøre pakker eierløse." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Flagg kommentar" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Rapporter utdatert pakke" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Bruk skjemaet for å flagge pakkebasen %s%s%s og følgende pakker som " -"utdaterte:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Bruk skjemaet for å flagge pakkebasen %s%s%s og følgende pakker som utdaterte:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Vennligst %sikke%s bruk dette skjemaet for å rapportere feil. Bruk " -"kommentarfeltet for pakken istedenfor." +msgstr "Vennligst %sikke%s bruk dette skjemaet for å rapportere feil. Bruk kommentarfeltet for pakken istedenfor." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Skriv inn hvorfor pakken er utdatert nedenfor, helst med lenker til teksten " -"som annonserer slippet av den nye versjonen, eller den nye kildekodepakken." +msgstr "Skriv inn hvorfor pakken er utdatert nedenfor, helst med lenker til teksten som annonserer slippet av den nye versjonen, eller den nye kildekodepakken." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentar" +#: html/pkgflag.php msgid "Flag" msgstr "Flagg" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Bare registrerte brukere kan flagge pakker som utdaterte." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakkesammenslåing" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Slå sammen med en annen" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Bruk dette skjemaet for å slå sammen basispakken %s%s%s med en annen pakke." +msgstr "Bruk dette skjemaet for å slå sammen basispakken %s%s%s med en annen pakke." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Følgende pakker vil slettes:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Når pakken har blitt slått sammen med en annen, kan det ikke angres." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Angi navnet på pakken du ønsker å slå denne pakken sammen med." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Slå sammen til:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Bekreft sammenslåing" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Slå sammen" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Bare betrodde brukere og utviklere kan slå sammen pakker." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Send inn forespørsel" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Lukk forespørsel" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Forrige" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Neste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Siste" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Forespørsler" +#: html/register.php template/header.php msgid "Register" msgstr "Registrer" +#: html/register.php msgid "Use this form to create an account." msgstr "Bruk dette feltet for å opprette en konto." +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "Betingelser" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "Disse dokumentene har blitt oppdatert. Vennligst les nøye gjennom:" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "revisjon %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "Jeg godtar betingelsene ovenfor." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Betrodd bruker" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Kan ikke finne detaljer om forslaget." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Avstemningen er ferdig for dette forslaget." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Bare betrodde brukere har stemmerett." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Du kan ikke stemme på et forslag som gjelder deg." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Du har allerede stemt på dette forslaget." +#: html/tu.php msgid "Vote ID not valid." msgstr "Stemme-ID ikke gyldig." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Pågående avstemninger" +#: html/tu.php msgid "Past Votes" msgstr "Tidligere avstemninger" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Velgere" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Funksjonen for registrering av nye kontoer har blitt slått av for din IP " -"adresse, sannsynligvis på grunn av vedvarende spam-angrep. Vi beklager " -"ulempen dette medfører." +msgstr "Funksjonen for registrering av nye kontoer har blitt slått av for din IP adresse, sannsynligvis på grunn av vedvarende spam-angrep. Vi beklager ulempen dette medfører." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Manglende bruker-ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Brukernavnet er ugyldig." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Det må være mellom %s og %s tegn langt" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Start og slutt med en bokstav eller et siffer" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun innehold ett punktum, en understrek, eller en bindestrek." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-postadressen er ugyldig." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "Ugyldig hjemmeside, vennligst spesifiser hele HTTP(s) adressen." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP fingeravtrykket er ikke gyldig." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Den offentlige SSH-nøkkelen er ugyldig." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Kan ikke gi flere tillatelser til kontoen." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Språket støttes ikke på dette tidspunktet." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Den tidssonen støttes ikke akkurat nå" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Brukernavnet, %s%s%s, er allerede i bruk." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adressen, %s%s%s, er allerede i bruk." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Den offentlige SSH-nøkkelen, %s%s%s, er allerede i bruk." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Feil ved oppretting av konto, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Kontoen, %s%s%s, har nå blitt laget." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Nullstillingskode har blitt sendt til e-post adressen din." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klikk på Logg inn lenken over for å bruke kontoen." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Ingen endringer ble utført på kontoen, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Kontoen, %s%s%s, har nå blitt endret." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Inlogging er slått av for din IP adresse, sannsynligvis på grunn av " -"vedvarende spam-angrep. Beklager ulempen dette medfører." +msgstr "Inlogging er slått av for din IP adresse, sannsynligvis på grunn av vedvarende spam-angrep. Beklager ulempen dette medfører." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Kontoen er stengt" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Passordet har blitt nullstilt. Dersom du akkurat laget en ny konto, " -"vennligst følg lenken som ble sendt på e-post og sett så et nytt passord. " -"Ellers kan du bruke %sNullstill Passord% siden til å få tilsendt en " -"nullstillingskode." +msgstr "Passordet har blitt nullstilt. Dersom du akkurat laget en ny konto, vennligst følg lenken som ble sendt på e-post og sett så et nytt passord. Ellers kan du bruke %sNullstill Passord% siden til å få tilsendt en nullstillingskode." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Ugyldig brukernavn eller passord." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Feil oppstod ved generering av sesjon for bruker." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ugyldig kombinasjon av e-post og nullstillingsnøkkel." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Ingen" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Vis kontoinformasjon for %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "ID eller navn for pakkebasen mangler." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Du får ikke lov til å redigere denne kommentaren." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Kommentaren finnes ikke." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Kommentaren kan ikke være tom." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Kommentar har blitt lagt til." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Du må være logget inn for å kunne redigere pakkeinformasjon." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Mangler kommentar-ID." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Maks 5 kommentarer kan festes." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Du får ikke lov til å feste denne kommentaren." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Du får ikke lov til å løsrive denne kommentaren." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Kommentar har blitt festet." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Kommentar har blitt løsrevet." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Kunne ikke finne frem pakkedetaljer." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Kunne ikke finne pakkedetaljer." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Du må være logget inn for å kunne markere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Ingen pakker ble valgt for å bli markert." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"De valgte pakkene har ikke blitt flagget. Vennligst skriv inn en kommentar." +msgstr "De valgte pakkene har ikke blitt flagget. Vennligst skriv inn en kommentar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "De valgte pakkene har nå blitt flagget som utdaterte." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Du må være logget inn for å kunne fjerne flagg fra pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Ingen pakker ble valgt for å fjerne flagg fra." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De valgte pakkene har nå fått fjernet flaggene." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Du har ikke rettighetene som skal til for å kunne slette pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Du valgte ingen pakker for sletting." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De valgte pakkene har blitt slettet." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Du må være logget inn for å kunne adoptere pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Du må være logget inn for å kunne gjøre pakker eierløse." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Du valgte ingen pakker for adopsjon." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Du valgte ingen pakker som skal gjøres eierløse." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Den valgte pakken har blitt adoptert." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De valgte pakkene er nå eierløse." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Du må være logget inn for å kunne stemme på pakker." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Du må være logget inn for å kunne trekke tilbake stemmer på pakker." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Du valgte ingen pakker å stemme på." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Stemmene dine har blitt trukket tilbake fra de valgte pakkene." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Du har nå stemt på de valgte pakkene." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kunne ikke legge til i påminnelseslisten." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Du har blitt lagt til påminnelselisten for kommentarer for %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Du har blitt fjernet fra kommentarpåminnelselisten for %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Du får ikke lov til å angre på å slette denne kommentaren." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Kommentaren har ikke blitt slettet allikevel." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Du har ikke tilgang til å slette denne kommentaren." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Kommentaren har blitt slettet." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Kommentaren har blitt redigert." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Du får ikke lov til å redigere nøkkelordene til denne pakkebasen." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Pakkebasenøkkelordene har blitt oppdatert." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Du får ikke lov til å håndtere med-vedlikeholdere for denne pakkebasen." +msgstr "Du får ikke lov til å håndtere med-vedlikeholdere for denne pakkebasen." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ugyldig brukernavn: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Med-vedlikeholdere for denne pakkebasen har blitt oppdatert." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vis pakkedetaljer for" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "trenger %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Du må være logget inn for å kunne sende inn forespørsler om pakker." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ugyldig navn: kun små bokstaver er lov." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Kommentarfeltet kan ikke være tomt." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ugyldig type forspørsel." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Forespørsel er registrert." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ugyldig grunn." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Bare betrodde brukere og utviklere kan lukke forespørsler." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Forespørselen ble lukket." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Dette skjemaet kan brukes for å permanent slette AUR kontoen %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sADVARSEL%s: Denne handlingen kan ikke angres." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bekreft sletting" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Brukernavn" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Konto-type" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Bruker" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Utvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Betrodd bruker & Utvikler" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-postadresse" +#: template/account_details.php msgid "hidden" msgstr "gjemt" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Ekte navn" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Hjemmeside" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC-kallenavn" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP-nøkkel/fingeravtrykk" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Inaktiv siden" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktiv" +#: template/account_details.php msgid "Registration date:" msgstr "Registreringsdato:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "ukjent" +#: template/account_details.php msgid "Last Login" msgstr "Sist logget inn" +#: template/account_details.php msgid "Never" msgstr "Aldri" +#: template/account_details.php msgid "View this user's packages" msgstr "Vis pakkene til denne brukereren" +#: template/account_details.php msgid "Edit this user's account" msgstr "Endre brukerkonto" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klikk %sher%s hvis du vil slette denne kontoen for alltid." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Klikk %sher%s for brukerdetaljer." +#: template/account_edit_form.php msgid "required" msgstr "trengs" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" +msgstr "Brukernavnet er navnet du vil bruke for å logge inn med. Det er synlig for allmenheten, selv hvis kontoen din er inaktiv." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Vanlig bruker" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Betrodd bruker" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto suspendert" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inaktiv" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Kontroller at du har skrevet e-postadressen din korrekt, ellers vil du bli " -"utestengt." +msgstr "Kontroller at du har skrevet e-postadressen din korrekt, ellers vil du bli utestengt." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Gjem e-postadresse" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Skriv inn passordet på nytt" +#: template/account_edit_form.php msgid "Language" msgstr "Språk" +#: template/account_edit_form.php msgid "Timezone" msgstr "Tidssone" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Følgende informasjon behøves bare hvis du har tenkt til å sende inn pakker " -"til Arch sitt brukerstyrte pakkebibliotek." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Følgende informasjon behøves bare hvis du har tenkt til å sende inn pakker til Arch sitt brukerstyrte pakkebibliotek." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Offentlig SSH-nøkkel" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Varslingsinstillinger" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Gi beskjed om nye kommentarer" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Gi beskjed om pakkeoppdateringer" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Gi beskjed om endring av eierskap" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Oppdater" +#: template/account_edit_form.php msgid "Create" msgstr "Opprett" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Nullstill" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Ingen treff for de oppgitte søkekriteriene." +#: template/account_search_results.php msgid "Edit Account" msgstr "Endre brukerkonto" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendert" +#: template/account_search_results.php msgid "Edit" msgstr "Rediger" +#: template/account_search_results.php msgid "Less" msgstr "Færre" +#: template/account_search_results.php msgid "More" msgstr "Flere" +#: template/account_search_results.php msgid "No more results to display." msgstr "Ingen flere resultater å vise." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Bruk dette skjemaet for å legge til med-vedlikeholdere for %s%s%s (ett " -"brukernavn per linje):" +msgstr "Bruk dette skjemaet for å legge til med-vedlikeholdere for %s%s%s (ett brukernavn per linje):" +#: template/comaintainers_form.php msgid "Users" msgstr "Brukere" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Lagre" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Flagget kommentar som utdatert: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "%s%s%s flagget %s%s%s som utdatert den %s%s%s av følgende årsak:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s er ikke flagget som utdatert." +#: template/flag_comment.php msgid "Return to Details" msgstr "Returner til detaljer" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Kopibeskyttet %s 2004-%d aurweb utviklingsgruppe." +#: template/header.php msgid " My Account" msgstr " Min konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakkehandlinger" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Vis PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Vis endringer" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Last ned kildekode" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Søk på wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Flagget som utdatert (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marker som utdatert" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Fjern flagg" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Angre stemme" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem på denne pakken" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Slå av beskjeder" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Gi beskjed" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Med-vedlikeholdere" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d ventende forespørsel" msgstr[1] "%d ventende forespørsler" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopter pakke" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Basispakkedetaljer" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git-arkiv" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "skrivebeskyttet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Nøkkelord" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Innsender" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Eier" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Forrige innpakker" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmer" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularitet" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Opprettet" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Sist oppdatert" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Rediger kommentar for: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Legg til kommentar" +#: template/pkg_comments.php msgid "View all comments" msgstr "Vis alle kommentarer" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "La stå" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Siste kommentarer" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s kommenterte %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anonym kommenterte %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "slettet %s av %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "slettet %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "redigert %s av %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "redigert %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Angre sletting av kommentar" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Slett kommentar" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Fest kommentar" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Løsne kommentar" +#: template/pkg_comments.php msgid "All comments" msgstr "Alle kommentarer" +#: template/pkg_details.php msgid "Package Details" msgstr "Om pakken" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Basispakke" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Beskrivelse" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Prosjektside" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Besøk nettsiden til" +#: template/pkg_details.php msgid "Licenses" msgstr "Lisenser" +#: template/pkg_details.php msgid "Groups" msgstr "Grupper" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikter" +#: template/pkg_details.php msgid "Provides" msgstr "Tilbyr" +#: template/pkg_details.php msgid "Replaces" msgstr "Erstatter" +#: template/pkg_details.php msgid "Dependencies" msgstr "Avhengigheter" +#: template/pkg_details.php msgid "Required by" msgstr "Trengs av" +#: template/pkg_details.php msgid "Sources" msgstr "Kilder" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Bruk dette skjemaet for å lukke forespørselen for basispakken %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Kommentarfeltet kan stå tomt, men det anbefales å legge igjen en melding når " -"en forespørsel avvises." +msgstr "Kommentarfeltet kan stå tomt, men det anbefales å legge igjen en melding når en forespørsel avvises." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Begrunnelse" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Akseptert" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Avvist" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Bruk dette skjemaet for å registrere en forespørsel for basispakken %s%s%s " -"som inkluderer følgende pakker:" +msgstr "Bruk dette skjemaet for å registrere en forespørsel for basispakken %s%s%s som inkluderer følgende pakker:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Type forespørsel" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Sletting" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Eierløs" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Flett med" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Ved å sende inn en forespørsel om sletting spør du en betrodd bruker om å " -"slette pakken. Slike forespørsler bør brukes om duplikater, forlatt " -"programvare samt ulovlige eller pakker som er så ødelagte at de ikke lenger " -"kan fikses." +msgstr "Ved å sende inn en forespørsel om sletting spør du en betrodd bruker om å slette pakken. Slike forespørsler bør brukes om duplikater, forlatt programvare samt ulovlige eller pakker som er så ødelagte at de ikke lenger kan fikses." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Ved å sende inn en forespørsel om sammenslåing spør du en betrodd bruker om " -"å slette pakken. Stemmer og kommentarer vil bli overført til en annen pakke. " -"Å slå sammen en pakke har ingen effekt på korresponderende Git repo. Pass på " -"å oppdatere Git historikken til målpakken selv." +msgstr "Ved å sende inn en forespørsel om sammenslåing spør du en betrodd bruker om å slette pakken. Stemmer og kommentarer vil bli overført til en annen pakke. Å slå sammen en pakke har ingen effekt på korresponderende Git repo. Pass på å oppdatere Git historikken til målpakken selv." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Ved å sende inn en forespørsel om å gjøre en pakke eierløs spør du en " -"betrodd bruker om å utføre dette. Vennligst bare send inn forespørselen " -"dersom pakken trenger vedlikehold, nåværende vedlikeholder er fraværende og " -"du allerede har prøvd å kontakte den som vedlikeholder pakken." +msgstr "Ved å sende inn en forespørsel om å gjøre en pakke eierløs spør du en betrodd bruker om å utføre dette. Vennligst bare send inn forespørselen dersom pakken trenger vedlikehold, nåværende vedlikeholder er fraværende og du allerede har prøvd å kontakte den som vedlikeholder pakken." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Ingen treff på forespørsler." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Fant %d pakkeforespørsel." msgstr[1] "Fant %d pakkeforespørsler." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Side %d av %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakke" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Registrert av" +#: template/pkgreq_results.php msgid "Date" msgstr "Dato" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d dag igjen" msgstr[1] "~%d dager igjen" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d time igjen" msgstr[1] "~%d timer igjen" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 time igjen" +#: template/pkgreq_results.php msgid "Accept" msgstr "Godta" +#: template/pkgreq_results.php msgid "Locked" msgstr "Låst" +#: template/pkgreq_results.php msgid "Close" msgstr "Lukk" +#: template/pkgreq_results.php msgid "Pending" msgstr "I kø" +#: template/pkgreq_results.php msgid "Closed" msgstr "Lukket" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Navn, beskrivelse" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Bare navn" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Eksakt navn" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Eksakt basispakke" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Med-vedlikeholder" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Vedlikeholder, med-vedlikeholder" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Markert" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Umarkert" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Navn" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Din stemme" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Sist endret" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Stigende" +#: template/pkg_search_form.php msgid "Descending" msgstr "Synkende" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Angi søkekriterier" +#: template/pkg_search_form.php msgid "Search by" msgstr "Søk etter" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Ut på dato" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sorter etter" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sortering" +#: template/pkg_search_form.php msgid "Per page" msgstr "Treff per side" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Søk nå" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Eierløse" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Feil ved mottagelse av pakkeliste." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Ingen pakker her." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Fant %d pakke." msgstr[1] "Fant %d pakker." +#: template/pkg_search_results.php msgid "Version" msgstr "Versjon" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Populariteten beregnes som summen av alle stemmer der hver stemme vekktes " -"med en faktor på %.2f per dag siden den ble avlagt." +msgstr "Populariteten beregnes som summen av alle stemmer der hver stemme vekktes med en faktor på %.2f per dag siden den ble avlagt." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "eierløs" +#: template/pkg_search_results.php msgid "Actions" msgstr "Handlinger" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Fjern flagg" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopter pakker" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Gjør pakker eierløse" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Slett pakker" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Bekreft" +#: template/search_accounts_form.php msgid "Any type" msgstr "Hvilken som helst type" +#: template/search_accounts_form.php msgid "Search" msgstr "Søk" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistikk" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Eierløse pakker" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Lagt til de siste 7 dagene" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Oppdaterte pakker de siste 7 dagene" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Oppdaterte pakker det siste året" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Aldri oppdaterte pakker" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrerte brukere" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Betrodde brukere" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nylig oppdatert" +#: template/stats/updates_table.php msgid "more" msgstr "mer" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Min statistikk" +#: template/tu_details.php msgid "Proposal Details" msgstr "Forslagsdetaljer" +#: template/tu_details.php msgid "This vote is still running." msgstr "Avstemningen pågår fortsatt." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Innsendt: %s av %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Slutt" +#: template/tu_details.php msgid "Result" msgstr "Resultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nei" +#: template/tu_details.php msgid "Abstain" msgstr "Blank stemme" +#: template/tu_details.php msgid "Total" msgstr "Totalt" +#: template/tu_details.php msgid "Participation" msgstr "Deltagelse" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Betrodde brukeres avgitte stemmer" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Forrige avstemning" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Ingen resultater." +#: template/tu_list.php msgid "Start" msgstr "Start" +#: template/tu_list.php msgid "Back" msgstr "Tilbake" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/nl.po b/po/nl.po index 607efea8..e062fe53 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,1346 +1,1680 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Heimen Stoffels , 2015 # jelly , 2011 # Sietse , 2013 # Sietse , 2013 -# Wijnand Modderman-Lenstra , 2015 +# Wijnand Modderman-Lenstra , 2015 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Dutch (http://www.transifex.com/lfleischer/aur/language/nl/)\n" -"Language: nl\n" +"Language-Team: Dutch (http://www.transifex.com/lfleischer/aurweb/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "De pagina kon niet worden gevonden" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Sorry, de pagina die u heeft aangevraagd bestaat niet." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Notitie" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "De dienst is niet beschikbaar" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Raak niet in paniek! De website is uit de lucht wegens werkzaamheden. We " -"zullen snel weer terug in de lucht zijn." +msgstr "Raak niet in paniek! De website is uit de lucht wegens werkzaamheden. We zullen snel weer terug in de lucht zijn." +#: html/account.php msgid "Account" msgstr "Account" +#: html/account.php template/header.php msgid "Accounts" msgstr "Accounts" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "U heeft geen toegang tot dit gebied." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Kon geen informatie ophalen voor de opgegeven gebruiker." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "U heeft geen toestemming om dit account te bewerken." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Gebruik dit formulier om bestaande accounts te zoeken." +#: html/account.php msgid "You must log in to view user information." msgstr "U moet inloggen om de gebruikersinformatie te bekijken." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Voorstel toevoegen" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Ongeldige token voor gebruikersactie." +#: html/addvote.php msgid "Username does not exist." msgstr "De gebruikersnaam bestaat niet." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s heeft al een voorstel ervoor lopen." +#: html/addvote.php msgid "Invalid type." msgstr "Ongeldig type." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Het voorstel mag niet leeg worden gelaten." +#: html/addvote.php msgid "New proposal submitted." msgstr "Het nieuwe voorstel is ingediend." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Een voorstel indienen om op te stemmen." +#: html/addvote.php msgid "Applicant/TU" msgstr "Aanvrager/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(laat leeg indien niet van toepassing)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Type" +#: html/addvote.php msgid "Addition of a TU" msgstr "Toevoeging van een TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Verwijdering van een TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Verwijdering van een TU (onverklaarbare inactiviteit)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Wijziging van de statuten" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Voorstel" +#: html/addvote.php msgid "Submit" msgstr "Versturen" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Mede-onderhouders beheren" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Startgedeelte" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Mijn pakketten" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Welkom bij de AUR! Lees de %sAUR-gebruikersrichtlijnen%s en de %sAUR-" -"ontwikkelaarsrichtlijnen%s voor meer informatie." +msgstr "Welkom bij de AUR! Lees de %sAUR-gebruikersrichtlijnen%s en de %sAUR-ontwikkelaarsrichtlijnen%s voor meer informatie." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Bijgedragen PKGBUILDs %smoeten%s voldoen aan de %sArch-pakketstandaarden%s, " -"anders zullen ze worden verwijderd!" +msgstr "Bijgedragen PKGBUILDs %smoeten%s voldoen aan de %sArch-pakketstandaarden%s, anders zullen ze worden verwijderd!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Vergeet niet te stemmen op uw favoriete pakketten!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Sommige pakketten kunnen worden geleverd als uitvoerbare bestanden in " -"[community]." +msgstr "Sommige pakketten kunnen worden geleverd als uitvoerbare bestanden in [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "DISCLAIMER" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "Meer leren..." +#: html/home.php msgid "Support" msgstr "Ondersteuning" +#: html/home.php msgid "Package Requests" msgstr "Pakketaanvragen" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Er zijn drie typen aanvragen die kunnen worden ingedeeld in het " -"%sPakketacties%s-veld op de pakketdetails-pagina:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Er zijn drie typen aanvragen die kunnen worden ingedeeld in het %sPakketacties%s-veld op de pakketdetails-pagina:" +#: html/home.php msgid "Orphan Request" msgstr "Weesaanvraag" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Vragen om het pakket te markeren als wees, bijv. wanneer de onderhouder " -"inactief is en het pakket langere tijd als verouderd gemarkeerd is." +msgstr "Vragen om het pakket te markeren als wees, bijv. wanneer de onderhouder inactief is en het pakket langere tijd als verouderd gemarkeerd is." +#: html/home.php msgid "Deletion Request" msgstr "Verwijderaanvraag" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Verzoek om een pakket uit de Arch User Repository te laten verwijderen. " -"Gebruik dit niet als een pakket niet naar behoren functioneert en eenvoudig " -"gerepareerd kan worden. Neem in zo'n geval contact op met de " -"pakketontwikkelaar en open zo nodig een weesverzoek." +msgstr "Verzoek om een pakket uit de Arch User Repository te laten verwijderen. Gebruik dit niet als een pakket niet naar behoren functioneert en eenvoudig gerepareerd kan worden. Neem in zo'n geval contact op met de pakketontwikkelaar en open zo nodig een weesverzoek." +#: html/home.php msgid "Merge Request" msgstr "Aanvraag samenvoegen" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Verzoek om een pakket samen te laten voegen met een ander pakket. Dit kan " -"gebruikt worden als een pakket hernoemd moet worden of vervangen wordt door " -"een opgesplitst pakket." +msgstr "Verzoek om een pakket samen te laten voegen met een ander pakket. Dit kan gebruikt worden als een pakket hernoemd moet worden of vervangen wordt door een opgesplitst pakket." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Indien je het verzoek wilt bediscussiëren, dan kun je de %saur-requests%s " -"maillijst gebruiken. Gebruik deze lijst niet om verzoeken in te dienen." +msgstr "Indien je het verzoek wilt bediscussiëren, dan kun je de %saur-requests%s maillijst gebruiken. Gebruik deze lijst niet om verzoeken in te dienen." +#: html/home.php msgid "Submitting Packages" msgstr "Het bijdragen van pakketten" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git via SSA is nu in gebruik om pakketten bij te dragen aan de AUR. Zie de " -"%sHet bijdragen van pakketten%s-gedeelte van de Arch User Repository " -"ArchWiki-pagina voor meer details." +msgstr "Git via SSA is nu in gebruik om pakketten bij te dragen aan de AUR. Zie de %sHet bijdragen van pakketten%s-gedeelte van de Arch User Repository ArchWiki-pagina voor meer details." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "De volgende SSH-vingerafdrukken worden gebruikt voor de AUR:" +#: html/home.php msgid "Discussion" msgstr "Discussie" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Algemene discussies met betrekking tot de Arch User Repository (AUR) en de " -"opzet van Trusted Users vinden plaats op %saur-general%s. Voor discussies " -"gerelateerd aan de ontwikkeling van de AUR web interface, gebruik de %saur-" -"dev%s mailinglijst." +msgstr "Algemene discussies met betrekking tot de Arch User Repository (AUR) en de opzet van Trusted Users vinden plaats op %saur-general%s. Voor discussies gerelateerd aan de ontwikkeling van de AUR web interface, gebruik de %saur-dev%s mailinglijst." +#: html/home.php msgid "Bug Reporting" msgstr "Bug-rapportage" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Pakketten zoeken" +#: html/index.php msgid "Adopt" msgstr "Adopteren" +#: html/index.php msgid "Vote" msgstr "Stemmen" +#: html/index.php msgid "UnVote" msgstr "Stem verwijderen" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Informeren" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Niet informeren" +#: html/index.php msgid "UnFlag" msgstr "De-markeren" +#: html/login.php template/header.php msgid "Login" msgstr "Inloggen" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Ingelogd als: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Uitloggen" +#: html/login.php msgid "Enter login credentials" msgstr "Vul uw inloggegevens in" +#: html/login.php msgid "User name or email address" msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Wachtwoord" +#: html/login.php msgid "Remember me" msgstr "Onthoud mij" +#: html/login.php msgid "Forgot Password" msgstr "Wachtwoord vergeten" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP-inloggen is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." +msgstr "HTTP-inloggen is uitgeschakeld. %sVerander naar HTTPs%s om in te loggen." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Zoekcriteria" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakketten" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Fout bij het ophalen van pakket details." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Er ontbreekt een verplicht veld." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Wachtwoordvelden komen niet overeen." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Uw wachtwoord moet minimaal %s karakters lang zijn." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Ongeldig e-mailadres." +#: html/passreset.php msgid "Password Reset" msgstr "Wachtwoordherstel" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Controleer uw e-mail voor de bevestigingslink." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Uw wachtwoord is met succes teruggezet." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Bevestig uw e-mailadres:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Voer uw nieuwe wachtwoord in:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Bevestig uw nieuwe wachtwoord:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Doorgaan" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Als je het e-mail adres waarmee je geregistreerd hebt vergeten bent, stuur " -"dan een bericht naar de %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Als je het e-mail adres waarmee je geregistreerd hebt vergeten bent, stuur dan een bericht naar de %saur-general%s mailing list." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Vul uw e-mail adres in:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"De geselecteerde pakketten zijn niet onteigend, vink het bevestigingsvakje " -"aan." +msgstr "De geselecteerde pakketten zijn niet onteigend, vink het bevestigingsvakje aan." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Kan geen pakket vinden om stemmen en comments mee samen te voegen" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Het basispakket kan niet met zichzelf worden samengevoegd." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"De geselecteerde pakketten zijn niet gewist, vink het bevestigingsvakje aan." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "De geselecteerde pakketten zijn niet gewist, vink het bevestigingsvakje aan." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Pakketverwijdering" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Verwijder Pakket" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Gebruik dit formulier om basispakket %s%s%s te verwijderen van AUR met " -"inbegrip van de volgende pakketten:" +msgstr "Gebruik dit formulier om basispakket %s%s%s te verwijderen van AUR met inbegrip van de volgende pakketten:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Verwijdering van een pakket is permanent." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Vink het veld aan om de actie te bevestigen." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Bevestig pakketverwijdering" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Verwijderen" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten verwijderen." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Pakket onteigenen" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Gebruik dit formulier om basispakket %s%s%s te onteigenen met inbegrip van " -"de volgende pakketten:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Gebruik dit formulier om basispakket %s%s%s te onteigenen met inbegrip van de volgende pakketten:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen het " -"pakket en het eigendom over te dragen aan %s%s%s." +msgstr "Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen het pakket en het eigendom over te dragen aan %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen van " -"het pakket." +msgstr "Door het bevestigingsvakje aan te vinken, stem je in met het onteigenen van het pakket." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Bevestig de onteigening van het pakket" +#: html/pkgdisown.php msgid "Disown" msgstr "Onteigenen" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Alleen Vertouwde Gebruikers en ontwikkelaars kunnen pakketten onteigenen." +msgstr "Alleen Vertouwde Gebruikers en ontwikkelaars kunnen pakketten onteigenen." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Commentaar" +#: html/pkgflag.php msgid "Flag" msgstr "Markeren" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "Pakketsamenvoeging" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Voeg Pakket Samen" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Gebruik dit formulier om basispakkete %s%s%s samen te voegen met een ander " -"pakket." +msgstr "Gebruik dit formulier om basispakkete %s%s%s samen te voegen met een ander pakket." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "De volgende pakketten zullen worden verwijderd:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Als dit pakket samengevoegd is kan dit niet teruggedraaid worden." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "" -"Geef de naam van het pakket waarmee dit pakket samengevoegd moet worden." +msgstr "Geef de naam van het pakket waarmee dit pakket samengevoegd moet worden." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Samenvoegen naar:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Samenvoeging bevestigen" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Samenvoegen" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Alleen Trusted Users en Ontwikkelaars kunnen pakketten samen voegen." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Aanvraag sluiten" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Eerste" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Vorige" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Volgende" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Laatste" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Aanvragen" +#: html/register.php template/header.php msgid "Register" msgstr "Registreren" +#: html/register.php msgid "Use this form to create an account." msgstr "Gebruik dit formulier om een ​​account aan te maken." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Voorsteldetails kunnen niet opgehaald worden." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Stemmen is gesloten voor dit voorstel." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Alleen Trusted Users kunnen stemmen." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "U kunt niet stemmen op een voorstel over u." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "U heeft al gestemd op dit voorstel." +#: html/tu.php msgid "Vote ID not valid." msgstr "Uw stem-ID is ongeldig." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Huidig aantal stemmen" +#: html/tu.php msgid "Past Votes" msgstr "Eerdere stemmen" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Stemmers" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Registratie is uitgeschakeld voor jouw IP adres, waarschijnlijk vanwege " -"langdurige spam aanvallen. Excuses voor het ongemak." +msgstr "Registratie is uitgeschakeld voor jouw IP adres, waarschijnlijk vanwege langdurige spam aanvallen. Excuses voor het ongemak." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Gebruikers-ID ontbreekt" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "De gebruikersnaam is ongeldig." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Het moet tussen de %s en %s karakters lang zijn" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Beginnen en eindigen met een letter of nummer" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Kan maar één punt, komma of koppelteken bevatten." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Het e-mailadres is ongeldig." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "De vingerafdruk van de PGP sleutel is ongeldig." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "De publieke SSH-sleutel is ongeldig." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Kan de account permissies niet verhogen." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Taal wordt momenteel niet ondersteund." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "De gebruikersnaam %s%s%s is al in gebruik." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Het adres %s%s%s is al in gebruik." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "De SSH publieke sleutel, %s%s%s, is al ingebruik." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Fout bij het aanmaken van account %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Het account %s%s%s is met succes aangemaakt." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Een sleutel voor het resetten van je wachtwoord is verstuurd naar je e-mail " -"adres." +msgstr "Een sleutel voor het resetten van je wachtwoord is verstuurd naar je e-mail adres." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Klik op de Login link hierboven om je account te gebruiken" +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Geen veranderingen zijn gemaakt aan het account, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Het account %s%s%s is met succes aangepast." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Het log-in formulier is uitgeschakeld voor je IP adres, waarschijnlijk " -"vanwege langdurige spam-aanvallen. Excuses voor het ongemak." +msgstr "Het log-in formulier is uitgeschakeld voor je IP adres, waarschijnlijk vanwege langdurige spam-aanvallen. Excuses voor het ongemak." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Account is geschorst" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Je wachtwoord is gereset. Als je net een nieuwe account hebt aangemaakt, " -"gebruik dan de link uit de bevestigingsmail om een wachtwoord te genereren. " -"In andere gevallen, vraag een herstelsleutel aan op de %sPassword Reset%s " -"pagina." +msgstr "Je wachtwoord is gereset. Als je net een nieuwe account hebt aangemaakt, gebruik dan de link uit de bevestigingsmail om een wachtwoord te genereren. In andere gevallen, vraag een herstelsleutel aan op de %sPassword Reset%s pagina." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Verkeerd gebruiker of wachtwoord" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Er is een fout opgetreden bij het aanmaken van een gebruikerssessie." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Ongeldige e-mail en reset-toets combinatie." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Geen" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Toon accountinformatie voor %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Opmerking is toegevoegd." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Je moet ingelogd zijn voordat je pakketinformatie kunt bewerken." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Missende comment ID." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Fout bij het ophalen van pakketdetails." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Pakketdetails kunnen niet gevonden worden." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt markeren." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Je hebt geen pakketten geselecteerd om te markeren." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "De geselecteerde pakketten zijn gemarkeerd als verouderd." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Je moet ingelogd zijn voordat je een markering voor een pakket kunt " -"verwijderen." +msgstr "Je moet ingelogd zijn voordat je een markering voor een pakket kunt verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." -msgstr "" -"Je hebt geen pakketten geselecteerd om de markering van te verwijderen." +msgstr "Je hebt geen pakketten geselecteerd om de markering van te verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "De markering voor de geselecteerde pakketten is verwijderd." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Je hebt geen toestemming om pakketten te verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Je hebt geen pakketten geselecteerd om te verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "De geselecteerde pakketten zijn verwijderd." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt adopteren." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Je moet ingelogd zijn voordat je pakketten kunt onteigenen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Je hebt geen pakketten geselecteerd om te adopteren." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Je hebt geen pakketten geselecteerd om te onteigenen." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "De geselecteerde pakketten zijn geadopteerd." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "De geselecteerde pakketten zijn onteigend." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Je moet ingelogd zijn voordat je kunt stemmen op pakketten." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Je moet ingelogd zijn voordat je je stem kunt verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Je hebt geen pakketten geselecteerd om op te stemmen." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Je stem is verwijderd voor de geselecteerde pakketten." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Je hebt gestemd voor de geselecteerde pakketten." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Kon niet toevoegen aan notificatielijst." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Je bent toegevoegd aan de comment notificatielijst voor %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Je bent verwijderd van de comment notificatielijst voor %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Je hebt geen toestemming deze comment te verwijderen." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Comment is verwijderd." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"Je hebt geen toestemming de sleutelwoorden van dit basispakket aan te passen." +msgstr "Je hebt geen toestemming de sleutelwoorden van dit basispakket aan te passen." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "De sleutelwoorden van het basispakket zijn bijgewerkt." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Je hebt geen toestemming om de mede-eigenaren van dit basispakket aan te " -"passen." +msgstr "Je hebt geen toestemming om de mede-eigenaren van dit basispakket aan te passen." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Ongeldige gebruikersnaam: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "De mede-onderhouders van het basispakket zijn bijgewerkt." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Toon pakketdetails voor" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Je moet ingelogd zijn voordat je pekketverzoeken kunt indienen." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Ongeldige naam: alleen kleine letters zijn toegestaan." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Het commentaarveld mag niet leeg zijn." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Ongeldig verzoektype." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Verzoek succesvol toegevoegd." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Ongeldige reden." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Alleen TUs en ontwikkelaars mogen verzoeken sluiten." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Verzoek succesvol gesloten." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Gebruik dit formulier om permanent AUR account %s te verwijderen." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWAARSCHUWING%s: Deze actie kan niet ongedaan worden gemaakt." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Bevestig verwijdering" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Gebruikersnaam" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Account Type" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Gebruiker" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Ontwikkelaar" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Trusted User & Ontwikkelaar" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mail adres" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Echte naam" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Nick" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP sleutel vingerafdruk" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Geen activiteit sinds" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Actief" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "onbekend" +#: template/account_details.php msgid "Last Login" msgstr "Laatste Login" +#: template/account_details.php msgid "Never" msgstr "Nooit" +#: template/account_details.php msgid "View this user's packages" msgstr "Bekijk gebruiker zijn pakketten" +#: template/account_details.php msgid "Edit this user's account" msgstr "Bewerk account van deze gebruiker" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Klik %shier%s als u dit account permanent wilt verwijderen." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "verplicht" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normale gebruiker" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Account Geschorst" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactief" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Voer wachtwoord opnieuw in" +#: template/account_edit_form.php msgid "Language" msgstr "Taal" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"De volgende informatie is alleen verplicht als u pakketten aan de Arch User " -"Repository wilt toevoegen." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "De volgende informatie is alleen verplicht als u pakketten aan de Arch User Repository wilt toevoegen." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH Publieke Sleutel" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notificatie bij nieuwe comment" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Update" +#: template/account_edit_form.php msgid "Create" msgstr "Aanmaken" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reset" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Geen resultaten die voldoen aan je zoekcriteria." +#: template/account_search_results.php msgid "Edit Account" msgstr "Bewerk account" +#: template/account_search_results.php msgid "Suspended" msgstr "Geschorst" +#: template/account_search_results.php msgid "Edit" msgstr "Bewerken" +#: template/account_search_results.php msgid "Less" msgstr "Minder" +#: template/account_search_results.php msgid "More" msgstr "Meer" +#: template/account_search_results.php msgid "No more results to display." msgstr "Geen andere resultaten gevonden " +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Gebruik dit formulier om mede-onderhouders voor %s%s%s toe te voegen (een " -"gebruikersnaam per regel):" +msgstr "Gebruik dit formulier om mede-onderhouders voor %s%s%s toe te voegen (een gebruikersnaam per regel):" +#: template/comaintainers_form.php msgid "Users" msgstr "Gebruikers" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Bewaren" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "Mijn Account" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Pakket Acties" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Toon PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Bekijk Wijzigingen" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Download momentopname" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Doorzoek wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Markeer pakket als verouderd" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Verwijder markering" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Verwijder stem" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Stem voor dit pakket" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Schakel notificaties uit" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Beheer mede-onderhouders" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d verzoek in wachtrij" msgstr[1] "%d verzoeken in wachtrij" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adopteer Pakket" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Details van Basispakket" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Sleutelwoorden" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Inzender" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Beheerder" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Laatste Packager" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Stemmen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Populariteit" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Toegevoegd" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Laatste Update" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Voeg Comment Toe" +#: template/pkg_comments.php msgid "View all comments" msgstr "Bekijk alle commentaar" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Nieuwste Comments" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Verwijder opmerking" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Alle comments" +#: template/pkg_details.php msgid "Package Details" msgstr "Pakketdetails" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Basispakket" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Omschrijving" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Bezoek de website voor" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenties" +#: template/pkg_details.php msgid "Groups" msgstr "Groepen" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflicten" +#: template/pkg_details.php msgid "Provides" msgstr "Voorziet in" +#: template/pkg_details.php msgid "Replaces" msgstr "Vervangt" +#: template/pkg_details.php msgid "Dependencies" msgstr "Afhankelijkheden" +#: template/pkg_details.php msgid "Required by" msgstr "Vereist door" +#: template/pkg_details.php msgid "Sources" msgstr "Bronnen" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." +msgstr "Gebruik dit formulier om het verzoek voor basispakket %s%s%s te sluiten." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Het commentaarveld mag leeg blijven. Echter, het wordt sterk aanbevolen om " -"een afwijzing van commentaar te voorzien." +msgstr "Het commentaarveld mag leeg blijven. Echter, het wordt sterk aanbevolen om een afwijzing van commentaar te voorzien." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Reden" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Geaccepteerd" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Afgewezen" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Gebruik dit formulier om een verzoek in te dienen voor basispakket %s%s%s " -"welke de volgende pakketten omvat:" +msgstr "Gebruik dit formulier om een verzoek in te dienen voor basispakket %s%s%s welke de volgende pakketten omvat:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Verzoektype" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Verwijdering" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Wees" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Voeg samen met" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1348,6 +1682,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1355,247 +1690,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d pakketverzoek gevonden" msgstr[1] "%d pakketverzoeken gevonden" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d van %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Ingediend door" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d uur resterend" msgstr[1] "~%d uur resterend" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 uur resterend" +#: template/pkgreq_results.php msgid "Accept" msgstr "Accepteer" +#: template/pkgreq_results.php msgid "Locked" msgstr "Vergrendeld" +#: template/pkgreq_results.php msgid "Close" msgstr "Sluit" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Gesloten" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Naam, omschrijving" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Alleen de naam" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Exacte Naam" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Exact Basispakket" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Alle" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Gemarkeerd" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Ongemarkeerd" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Naam" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Gestemd" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Oplopend" +#: template/pkg_search_form.php msgid "Descending" msgstr "Aflopend" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Voer zoekcriteria in" +#: template/pkg_search_form.php msgid "Search by" msgstr "Zoek op" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Verouderd" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sorteer Op" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sorteervolgorde" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagina" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ga" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Wezen" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Fout bij het ophalen van pakkettenlijst" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Geen pakketen gevonden die aan uw zoekcriteria voldoen" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pakket gevonden" msgstr[1] "%d pakketten gevonden" +#: template/pkg_search_results.php msgid "Version" msgstr "Versie" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Ja" +#: template/pkg_search_results.php msgid "orphan" msgstr "wees" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acties" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Hef Out-of-Date markering op" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adopteer Pakketten" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Onteigen Pakketten" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Verwijder pakketten" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Bevestig" +#: template/search_accounts_form.php msgid "Any type" msgstr "Elk type" +#: template/search_accounts_form.php msgid "Search" msgstr "Zoek" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistieken" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Weespakketten" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakketten toegevoegd in de laatste 7 dagen" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakketten geüpdatet in de laatste 7 dagen" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakketen geüpdatet in het laatste jaar" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nooit geüpdate pakketten" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Geregistreerde Gebruikers" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted Users" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Recente updates" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Mijn statistieken" +#: template/tu_details.php msgid "Proposal Details" msgstr "Voorsteldetails" +#: template/tu_details.php msgid "This vote is still running." msgstr "Dit voorstel is nog bezig" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Opgestuurd: %s door %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Einde" +#: template/tu_details.php msgid "Result" msgstr "Resultaat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nee" +#: template/tu_details.php msgid "Abstain" msgstr "Onthouden" +#: template/tu_details.php msgid "Total" msgstr "Totaal" +#: template/tu_details.php msgid "Participation" msgstr "Participatie" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Laatste stemmen door TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Laatste stem" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Geen resultaten gevonden." +#: template/tu_list.php msgid "Start" msgstr "Start " +#: template/tu_list.php msgid "Back" msgstr "Terug" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/pl.po b/po/pl.po index b6ca8ed2..909d2ccb 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,1164 +1,1448 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Bartłomiej Piotrowski , 2011 # Bartłomiej Piotrowski , 2014 -# Chris Warrick , 2013 -# Chris Warrick , 2012 +# Chris Warrick, 2013 +# Chris Warrick, 2012 # Kwpolska , 2011 # Lukas Fleischer , 2011 -# m4sk1n , 2017 +# Marcin Mikołajczak , 2017 # Michal T , 2016 # Nuc1eoN , 2014 -# Piotr Strębski , 2017 +# Piotr Strębski , 2017-2018 # Piotr Strębski , 2013-2016 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Polish (http://www.transifex.com/lfleischer/aur/language/" -"pl/)\n" -"Language: pl\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-06-11 15:26+0000\n" +"Last-Translator: Piotr Strębski \n" +"Language-Team: Polish (http://www.transifex.com/lfleischer/aurweb/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n" -"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" -"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" +"Language: pl\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" +#: html/404.php msgid "Page Not Found" msgstr "Nie znaleziono strony" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Przepraszamy, strona o którą prosiłeś nie istnieje." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Uwaga" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Adresy URL GIT clone nie są przeznaczone do otwierania w przeglądarce." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Aby sklonować repozytorium GIT-a %s, uruchom %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Kliknij %stutaj%s by powrócić do strony szczegółów %s." +#: html/503.php msgid "Service Unavailable" msgstr "Usługa niedostępna" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Nie panikuj! W związku z przeprowadzanymi pracami technicznymi strona jest " -"chwilowo niedostępna. Już wkrótce wrócimy." +msgstr "Nie panikuj! W związku z przeprowadzanymi pracami technicznymi strona jest chwilowo niedostępna. Już wkrótce wrócimy." +#: html/account.php msgid "Account" msgstr "Konto" +#: html/account.php template/header.php msgid "Accounts" msgstr "Konta" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nie masz uprawnień do oglądania tej strony." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Uzyskanie informacji o podanym użytkowniku nie powiodło się." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nie masz uprawnień do edycji tego konta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Przy użyciu tego formularza możesz przeszukać istniejące konta." +#: html/account.php msgid "You must log in to view user information." msgstr "Musisz być zalogowany, aby móc przeglądać informacje o użytkownikach." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Dodaj propozycję" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Nieprawidłowy token dla czynności użytkownika." +#: html/addvote.php msgid "Username does not exist." msgstr "Nazwa użytkownika nie istnieje." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s ma już propozycję dla nich." +#: html/addvote.php msgid "Invalid type." msgstr "Nieprawidłowy rodzaj." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Propozycja nie może być pusta." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nowa propozycja wysłana." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Wyślij propozycję do głosowania." +#: html/addvote.php msgid "Applicant/TU" msgstr "Wnioskodawca/ZU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(puste, jeśli nie dotyczy)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Rodzaj" +#: html/addvote.php msgid "Addition of a TU" msgstr "Dodanie ZU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Usunięcie ZU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Usunięcie ZU (niezadeklarowana nieaktywność)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Zmiana Regulaminu" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propozycja" +#: html/addvote.php msgid "Submit" msgstr "Wyślij" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Zarządzanie współutrzymującymi" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Edytuj komentarz" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Tablica rozdzielcza" +#: html/home.php template/header.php msgid "Home" msgstr "Start" +#: html/home.php msgid "My Flagged Packages" msgstr "Moje oflagowane pakiety" +#: html/home.php msgid "My Requests" msgstr "Moje prośby" +#: html/home.php msgid "My Packages" msgstr "Moje pakiety" +#: html/home.php msgid "Search for packages I maintain" msgstr "Wyszukaj pakiety, którymi się opiekuję" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Witamy w AUR! Aby uzyskać więcej informacji, przeczytaj %sInstrukcję " -"Użytkownika AUR%s oraz %sInstrukcję Zaufanego Użytkownika%s." +msgstr "Witamy w AUR! Aby uzyskać więcej informacji, przeczytaj %sInstrukcję Użytkownika AUR%s oraz %sInstrukcję Zaufanego Użytkownika%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Pliki PKGBUILD %smuszą%s być zgodne ze %sStandardami Pakietów Archa%s, " -"inaczej będą usuwane!" +msgstr "Pliki PKGBUILD %smuszą%s być zgodne ze %sStandardami Pakietów Archa%s, inaczej będą usuwane!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nie zapomnij zagłosować na swoje ulubione pakiety!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Część pakietów może być dostępna w formie binarnej w [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ZRZECZENIE" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Pakiety w AUR są tworzone przez użytkowników. Używasz ich na własne ryzyko." +msgstr "Pakiety w AUR są tworzone przez użytkowników. Używasz ich na własne ryzyko." +#: html/home.php msgid "Learn more..." msgstr "Dowiedz się więcej..." +#: html/home.php msgid "Support" msgstr "Wsparcie" +#: html/home.php msgid "Package Requests" msgstr "Prośby o pakiet" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "Zgłoszenie osieroconego pakietu" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Wnioskuj o wyrzeczenie własności pakietu - np. gdy zarządzający jest " -"nieaktywny i pakiet został oznaczony jako przestarzały dawno temu." +msgstr "Wnioskuj o wyrzeczenie własności pakietu - np. gdy zarządzający jest nieaktywny i pakiet został oznaczony jako przestarzały dawno temu." +#: html/home.php msgid "Deletion Request" msgstr "Prośba o usunięcie" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "Prośba o połączenie" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "Przesyłanie pakietów" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Następujące odciski SSH są używane przez AUR:" +#: html/home.php msgid "Discussion" msgstr "Dyskusja" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Ogólna dyskusja dotycząca Repozytorium Użytkowników Arch (AUR) i struktury " -"Zaufanych Użytkowników odbywa się na %saur-general%s. Dyskusja dotycząca " -"rozwoju interfejsu webowego AUR odbywa się zaś na liście dyskusyjnej %saur-" -"dev%s." +msgstr "Ogólna dyskusja dotycząca Repozytorium Użytkowników Arch (AUR) i struktury Zaufanych Użytkowników odbywa się na %saur-general%s. Dyskusja dotycząca rozwoju interfejsu webowego AUR odbywa się zaś na liście dyskusyjnej %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Zgłaszanie błędów" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Jeśli znalazłeś błąd w interfejsie webowym AUR, zgłoś go w naszym %ssystemie " -"śledzenia błędów%s. Używaj go %swyłącznie%s do zgłaszania błędów związanych " -"z interfejsem webowym AUR. Błędy powiązane z pakietami zgłaszaj ich " -"opiekunom lub zostaw komentarz pod odpowiednim pakietem." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Jeśli znalazłeś błąd w interfejsie webowym AUR, zgłoś go w naszym %ssystemie śledzenia błędów%s. Używaj go %swyłącznie%s do zgłaszania błędów związanych z interfejsem webowym AUR. Błędy powiązane z pakietami zgłaszaj ich opiekunom lub zostaw komentarz pod odpowiednim pakietem." +#: html/home.php msgid "Package Search" msgstr "Wyszukiwanie pakietów" +#: html/index.php msgid "Adopt" msgstr "Przejmij" +#: html/index.php msgid "Vote" msgstr "Głosuj" +#: html/index.php msgid "UnVote" msgstr "Cofnij głos" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Włącz powiadamianie" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Rezygnuj z powiadamiania" +#: html/index.php msgid "UnFlag" msgstr "Odznacz" +#: html/login.php template/header.php msgid "Login" msgstr "Zaloguj się" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Zalogowany jako: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Wyloguj się" +#: html/login.php msgid "Enter login credentials" msgstr "Podaj poświadczenia logowania" +#: html/login.php msgid "User name or email address" msgstr "Nazwa użytkownika lub adres e-mail" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Hasło" +#: html/login.php msgid "Remember me" msgstr "Zapamiętaj mnie" +#: html/login.php msgid "Forgot Password" msgstr "Zapomniałem hasła" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Logowanie w HTTP jest wyłączone. %sPrzełącz się na HTTPs%s aby się " -"zalogować." +msgstr "Logowanie w HTTP jest wyłączone. %sPrzełącz się na HTTPs%s aby się zalogować." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kryteria wyszukiwania" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pakiety" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Błąd podczas pobierania informacji o pakiecie." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Brakuje wymaganego pola." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Hasła nie zgadzają się." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Twoje hasło musi mieć składać się z conajmniej %s znaków." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Nieprawidłowy e-mail." +#: html/passreset.php msgid "Password Reset" msgstr "Resetowanie hasła" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "" -"Na Twój adres został wysłany e-mail z instrukcją dotyczącą resetowania hasła." +msgstr "Na Twój adres został wysłany e-mail z instrukcją dotyczącą resetowania hasła." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Twoje hasło zostało pomyślnie zresetowane." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potwierdź swój adres e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Wpisz nowe hasło:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Wpisz ponownie hasło:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Kontynuuj" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Jeśli zapomniałeś adresu e-mail, którego użyłeś do rejestracji, prosimy o " -"wysłanie wiadomości na naszą listę dyskusyjną %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Jeśli zapomniałeś adresu e-mail, którego użyłeś do rejestracji, prosimy o wysłanie wiadomości na naszą listę dyskusyjną %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Wpisz swój adres e-mail:" +#: html/pkgbase.php msgid "Package Bases" -msgstr "" +msgstr "Bazy pakietów" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Wybrane pakiety nie zostały porzucone, sprawdź pole wyboru potwierdzenia." +msgstr "Wybrane pakiety nie zostały porzucone, sprawdź pole wyboru potwierdzenia." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Nie można znaleźć pakietu do scalenia głosów i komentarzy." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nie można połączyć bazy pakietu z nią samą." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Wybrane pakiety nie zostały usunięte, sprawdź pole wyboru potwierdzenia." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Wybrane pakiety nie zostały usunięte, sprawdź pole wyboru potwierdzenia." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Usuwanie pakietów" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Usuń pakiet" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Użyj tego formularza, aby usunąć bazę pakietu %s%s%s i następujące pakiety z " -"AUR:" +msgstr "Użyj tego formularza, aby usunąć bazę pakietu %s%s%s i następujące pakiety z AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Usunięcie pakietu jest nieodwracalne." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaznacz pole aby potwierdzić akcję." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potwierdź usunięcie pakietu" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Usuń" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą usuwać pakiety." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Porzuć pakiet" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Użyj tego formularza, aby złożyć prośbę wyrzeczenie własności bazie pakietu " -"%s%s%s, która zawiera następujące pakiety:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Użyj tego formularza, aby złożyć prośbę wyrzeczenie własności bazie pakietu %s%s%s, która zawiera następujące pakiety:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Zaznaczając pole wyboru potwierdzasz, że chcesz porzucić pakiet i przenieść " -"własność na %s%s%s." +msgstr "Zaznaczając pole wyboru potwierdzasz, że chcesz porzucić pakiet i przenieść własność na %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Zaznaczając pole wyboru potwierdzasz, że chcesz porzucić pakiet." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Potwierdź porzucenie pakietu" +#: html/pkgdisown.php msgid "Disown" msgstr "Porzuć" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Tylko Zaufani Użytkownicy i Programiści mogą porzucać pakiety." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Oznacz komentarz" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Oznacz pakiet jako nieaktualny" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Użyj tego formularza, aby oznaczyć bazę pakietu %s%s%s i następujące pakiety " -"jako nieaktualne:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Użyj tego formularza, aby oznaczyć bazę pakietu %s%s%s i następujące pakiety jako nieaktualne:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Prosimy %snie%s używać tego formularza do zgłaszania błędów. Użyj do tego " -"systemu komentowania pakietu." +msgstr "Prosimy %snie%s używać tego formularza do zgłaszania błędów. Użyj do tego systemu komentowania pakietu." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Wprowadź poniżej szczegóły, dlaczego pakiet został oznaczony jako " -"nieaktualny, najlepiej łącznie z odnośnikiem do ogłoszenia o nowym wydaniu " -"lub do archiwum tarball nowego wydania." +msgstr "Wprowadź poniżej szczegóły, dlaczego pakiet został oznaczony jako nieaktualny, najlepiej łącznie z odnośnikiem do ogłoszenia o nowym wydaniu lub do archiwum tarball nowego wydania." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Kommentarze" +#: html/pkgflag.php msgid "Flag" msgstr "Oznacz" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"Tylko zarejestrowani użytkownicy mogą oznaczać pakiety jako nieaktualne." +msgstr "Tylko zarejestrowani użytkownicy mogą oznaczać pakiety jako nieaktualne." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Scalanie pakietów" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Scal pakiet" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Użyj tego formularza, aby scalić bazę pakietu %s%s%s w inny pakiet." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Następujące pakiety zostaną usunięte:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Gdy pakiet zostanie scalony to nie będzie możliwości odwrócenia tej " -"czynności." +msgstr "Gdy pakiet zostanie scalony to nie będzie możliwości odwrócenia tej czynności." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Podaj nazwę pakietu, pod którą chcesz dokonać scalenia pakietu." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Scal z:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potwierdź scalenie pakietu" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Scal" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Tylko Zaufani Użytkownicy i Deweloperzy mogą scalać pakiety." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Prześlij prośbę" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zamknij prośbę" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Pierwsza" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Poprzednia" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Następna" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ostatnia" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Prośby" +#: html/register.php template/header.php msgid "Register" msgstr "Zarejestruj się" +#: html/register.php msgid "Use this form to create an account." msgstr "Przy użyciu tego formularza możesz utworzyć konto." +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "Zasady korzystania" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "wydanie %d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Zaufany Użytkownik" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nie można odczytać szczegółów propozycji." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Głosowanie na tą propozycję jest zamknięte." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Tylko Zaufani Użytkownicy mogą głosować." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nie możesz głosować w propozycji o tobie." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Już zagłosowałeś na tą propozycję" +#: html/tu.php msgid "Vote ID not valid." msgstr "Nieprawidłowy identyfikator głosowania." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Obecne głosy" +#: html/tu.php msgid "Past Votes" msgstr "Poprzednie głosy" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Głosujących" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Rejestracja konta została wyłączona dla Twojego adresu IP, " -"najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. " -"Przepraszamy za niedogodności." +msgstr "Rejestracja konta została wyłączona dla Twojego adresu IP, najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. Przepraszamy za niedogodności." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Brakujące ID użytkownika." +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Nazwa użytkownika jest nieprawidłowa." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Długość musi być pomiędzy %s a %s" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Zacznij i zakończ literą lub cyfrą" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Może zawierać tylko jedną kropkę, podkreślnik lub myślnik." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adres e-mail jest nieprawidłowy." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Odcisk palca klucza PGP jest nieprawidłowy." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Klucz publiczny SSH jest nieprawidłowy." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nie można zwiększyć uprawnień konta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Język nie jest obecnie obsługiwany." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Nazwa użytkownika, %s%s%s, jest już używana." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adres, %s%s%s, jest już używany." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Publiczny klucz SSH, %s%s%s, jest już używany." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Wystąpił błąd podczas tworzenia konta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Konto %s%s%s zostało pomyślnie utworzone." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Klucz resetujący hasło został przesłany na Twój adres e-mail." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Kliknij na link Zaloguj się powyżej aby się zalogować." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nie zostały dokonane żadne zmiany na koncie, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Konto %s%s%s zostało pomyślnie zaktualizowane." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Formularz logowania jest obecnie wyłączony dla Twojego adresu IP, " -"najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. " -"Przepraszamy za niedogodności." +msgstr "Formularz logowania jest obecnie wyłączony dla Twojego adresu IP, najprawdopodobniej z powodu przeprowadzanych ataków spamerskich. Przepraszamy za niedogodności." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Konto zawieszone" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Twoje hasło zostało zresetowane. Jeśli dopiero co utworzyłeś nowe konto, " -"prosimy o użycie odnośnika z e-maila potwierdzającego rejestrację, aby " -"ustawić hasło początkowe. W innym przypadku, prosimy o wnioskowanie o klucz " -"resetujący na stronie %sresetowania hasła%s." +msgstr "Twoje hasło zostało zresetowane. Jeśli dopiero co utworzyłeś nowe konto, prosimy o użycie odnośnika z e-maila potwierdzającego rejestrację, aby ustawić hasło początkowe. W innym przypadku, prosimy o wnioskowanie o klucz resetujący na stronie %sresetowania hasła%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nieprawidłowa nazwa użytkownika lub hasło." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Wystąpił błąd przy próbie utworzenia sesji użytkownika." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Nieprawidłowy e-mail i klucz do resetowania." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Żaden" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Wyświetl informacje o koncie %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Brakuje identyfikatora lub nazwy bazy pakietów." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nie masz uprawnień do edycji tego komentarza." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Komentarz nie istnieje." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Komentarz nie może być pusty." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentarz został dodany." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Musisz być zalogowany aby móc edytować informacje o pakiecie." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Brakuje identyfikatora komentarza." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Można przypiąć nie więcej niż 5 komentarzy." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Nie masz uprawnień do przypięcia tego komentarza." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Nie masz uprawnień do odpięcia tego komentarza." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Komentarz został przypięty." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Komentarz został odpięty." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Błąd podczas pobierania informacji o pakiecie." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Nie odnaleziono informacji o pakiecie." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Musisz być zalogowany aby móc oznaczyć pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nie wybrałeś żadnych pakietów do oznaczenia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"Zaznaczone pakiety nie zostały oznaczone, prosimy o wpisanie komentarza." +msgstr "Zaznaczone pakiety nie zostały oznaczone, prosimy o wpisanie komentarza." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Wybrane pakiety zostały oznaczone jako nieaktualne." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musisz być zalogowany aby móc odznaczyć pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nie wybrałeś żadnych pakietów do odznaczenia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Wybrane pakiety zostały odznaczone." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nie masz uprawnień do usuwania pakietów." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nie wybrałeś żadnych pakietów do usunięcia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Wybrane pakiety zostały usunięte." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musisz być zalogowany aby móc przejmować pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musisz być zalogowany, aby móc porzucać pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nie wybrałeś żadnych pakietów do przejęcia." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nie wybrałeś żadnych pakietów do porzucenia." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Wybrane pakiety zostały przejęte." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Wybrane pakiety zostały porzucone." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Musisz być zalogowany aby móc głosować na pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musisz być zalogowany aby móc anulować głosy na pakiety." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nie wybrałeś żadnych pakietów do zagłosowania." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Twoje głosy zostały odebrane wybranym pakietom." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Twoje głosy zostały przyznane wybranym pakietom." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Dodanie do listy powiadamiania nie powiodło się." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Zostałeś dodany do listy powiadamiania o nowych komentarzach dla %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Zostałeś usunięty z listy powiadamiania o komentarzach dla %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Nie masz uprawnień do cofnięcia usunięcia tego komentarza." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Zostało cofnięte usunięcie komentarza." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nie masz uprawnień do usunięcia tego komentarza." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentarz został usunięty." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Komentarz został zmodyfikowany." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nie masz uprawnień, by modyfikować słowa kluczowe tej bazy pakietów." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Słowa kluczowe bazy pakietu zostały zaktualizowane." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nie masz uprawnień, by zarządzać współutrzymującymi tej bazy pakietu." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Niepoprawna nazwa użytkownika: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Współutrzymujący bazy pakietu zostali zaktualizowani." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Wyświetl informacje o pakiecie" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "wymaga %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Musisz być zalogowanym, aby złożyć prośbę o pakiet." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nieprawidłowa nazwa: tylko małe litery są dozwolone." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Pole komentarzy nie może pozostać pustę." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Nieprawidłowy rodzaj prośby." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Pomyślnie dodano prośbę." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Nieprawidłowy powód." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Tylko Zaufani Użytkownicy i programiści mogą zamykać prośby." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Pomyślnie zamknięto prośbę." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Możesz użyć tego formularza, aby nieodwracalnie usunąć konto %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUWAGA%s: Ta czynność nie może zostać cofnięta." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Potwierdź usunięcie" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Użytkownik" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Rodzaj konta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Użytkownik" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Deweloper" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Zaufany Użytkownik i Developer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adres e-mail" +#: template/account_details.php msgid "hidden" msgstr "ukryte" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Imię i nazwisko" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Strona główna" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick na IRC-u" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Odcisk palca klucza PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stan" +#: template/account_details.php msgid "Inactive since" msgstr "Nieaktywny od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktywne" +#: template/account_details.php msgid "Registration date:" msgstr "Data rejestracji:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "nieznana" +#: template/account_details.php msgid "Last Login" msgstr "Ostatnie logowanie" +#: template/account_details.php msgid "Never" msgstr "Nigdy" +#: template/account_details.php msgid "View this user's packages" msgstr "Wyświetl pakiety tego użytkownika" +#: template/account_details.php msgid "Edit this user's account" msgstr "Edycja tego konta użytkownika" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknij %stutaj%s, jeśli chcesz nieodwracalnie usunąć to konto." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Kliknij %stutaj%s by wyświetlić szczegóły użytkownika." +#: template/account_edit_form.php msgid "required" msgstr "wymagane" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Zwykły użytkownik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Zaufany Użytkownik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Konto zablokowane" +#: template/account_edit_form.php msgid "Inactive" msgstr "Nieaktywny" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Upewnij się, czy poprawnie wpisano adres e-mail, w przeciwnym razie " -"zostaniesz zablokowany." +msgstr "Upewnij się, czy poprawnie wpisano adres e-mail, w przeciwnym razie zostaniesz zablokowany." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Ukryj adres e-mail" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Hasło (ponownie)" +#: template/account_edit_form.php msgid "Language" msgstr "Język" +#: template/account_edit_form.php msgid "Timezone" msgstr "Strefa czasowa" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Następująca informacja jest wymagana jedynie w sytuacji, gdy chcesz przesłać " -"pakiety do Repozytorium Użytkowników Arch." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Następująca informacja jest wymagana jedynie w sytuacji, gdy chcesz przesłać pakiety do Repozytorium Użytkowników Arch." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Klucz publiczny SSH" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Ustawienia powiadomień" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Powiadom o nowych komentarzach" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Powiadom o aktualizacjach pakietu" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Powiadom o zmianie właściciela" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualizuj" +#: template/account_edit_form.php msgid "Create" msgstr "Utwórz" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Wyczyść" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Wyszukiwanie nie przyniosło rezultatu." +#: template/account_search_results.php msgid "Edit Account" msgstr "Edytuj konto" +#: template/account_search_results.php msgid "Suspended" msgstr "Zablokowane" +#: template/account_search_results.php msgid "Edit" msgstr "Edytuj" +#: template/account_search_results.php msgid "Less" msgstr "Poprzednie" +#: template/account_search_results.php msgid "More" msgstr "Następne" +#: template/account_search_results.php msgid "No more results to display." msgstr "Brak wyników do wyświetlenia." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Użyj tego formularza, aby dodać współutrzymujących %s%s%s (jedna nazwa " -"użytkownika na wiersz):" +msgstr "Użyj tego formularza, aby dodać współutrzymujących %s%s%s (jedna nazwa użytkownika na wiersz):" +#: template/comaintainers_form.php msgid "Users" msgstr "Użytkownicy" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Zapisz" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Komentarz do oznaczenia jako nieaktualny: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s oznaczył %s%s%s jako nieaktualny dnia %s%s%s z następującego powodu:" +msgstr "%s%s%s oznaczył %s%s%s jako nieaktualny dnia %s%s%s z następującego powodu:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s nie jest oznaczone jako nieaktualne." +#: template/flag_comment.php msgid "Return to Details" msgstr "Powrót do szczegółów" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Prawa autorskie %s 2004-%d Zespół Programistów aurweb." +#: template/header.php msgid " My Account" msgstr "Moje konto" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Działania na pakietach" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Pokaż PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Zobacz zmiany" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Pobierz migawkę" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Przeszukaj wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Oznaczono jako nieaktualny (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Oznacz pakiet jako nieaktualny" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Odznacz pakiet" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Usuń głos" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Zagłosuj na ten pakiet" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Wyłącz powiadomienia" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Włącz powiadomienia" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Zarządzanie współutrzymującymi" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1167,182 +1451,238 @@ msgstr[1] "%d prośby w toku" msgstr[2] "%d próśb w toku" msgstr[3] "%d próśb w toku" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Przejmij pakiet" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Szczegóły bazy pakietu" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL klonu Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "tylko do odczytu" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Słowa kluczowe" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Nadesłał" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Opiekun" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ostatni pakujący" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Głosy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularność" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Umieszczony" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ostatnia aktualizacja" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Edycja komentarza do: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Dodaj komentarz" +#: template/pkg_comments.php msgid "View all comments" msgstr "Pokaż wszystkie komentarze" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Przypięte komentarze" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Ostatnie komentarze" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s skomentował dnia %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anonimowy komentarz do %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "usunięte %s przez %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "usunięte %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "edytowane %s przez %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "edytowane %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Cofnij usunięcie komentarza" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Usuń komentarz" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Przypnij komentarz" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Odepnij komentarz" +#: template/pkg_comments.php msgid "All comments" msgstr "Wszystkie komentarze" +#: template/pkg_details.php msgid "Package Details" msgstr "Informacje o pakiecie" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Baza pakietu" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL źródła" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Odwiedź stronę pakietu" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencje" +#: template/pkg_details.php msgid "Groups" msgstr "Grupy" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konfliktuje z" +#: template/pkg_details.php msgid "Provides" msgstr "Zapewnia" +#: template/pkg_details.php msgid "Replaces" msgstr "Zastępuje" +#: template/pkg_details.php msgid "Dependencies" msgstr "Zależności" +#: template/pkg_details.php msgid "Required by" msgstr "Wymagane przez" +#: template/pkg_details.php msgid "Sources" msgstr "Źródła" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Użyj tego formularza, aby zamknąć prośbę o bazę pakietów %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Pole komentarza może zostać pozostawione pustym. Jednakże w przypadku " -"odrzucenia prośby dodanie komentarza jest wysoce polecane." +msgstr "Pole komentarza może zostać pozostawione pustym. Jednakże w przypadku odrzucenia prośby dodanie komentarza jest wysoce polecane." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Powód" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Zaakceptowany" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Odrzucony" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Użyj tego formularza, aby złożyć prośbę przeciwko bazie pakietu %s%s%s, " -"która zawiera następujące pakiety:" +msgstr "Użyj tego formularza, aby złożyć prośbę przeciwko bazie pakietu %s%s%s, która zawiera następujące pakiety:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Rodzaj prośby" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Usunięcie" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Bez opiekuna" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Scal z" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1350,6 +1690,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1357,9 +1698,11 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1368,19 +1711,24 @@ msgstr[1] "%d prośby odnalezione." msgstr[2] "%d próśb odnaleziono." msgstr[3] "%d próśb odnaleziono." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Strona %d z %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pakiet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Złożone przez" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" @@ -1389,6 +1737,7 @@ msgstr[1] "pozostało ~%d dni" msgstr[2] "pozostało ~%d dni" msgstr[3] "pozostało ~%d dni" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1397,96 +1746,128 @@ msgstr[1] "pozostały ~%d godziny" msgstr[2] "pozostało ~%d godzin" msgstr[3] "pozostało ~%d godzin" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "pozostała <1 godzina" +#: template/pkgreq_results.php msgid "Accept" msgstr "Akceptuj" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zablokowane" +#: template/pkgreq_results.php msgid "Close" msgstr "Zamknij" +#: template/pkgreq_results.php msgid "Pending" -msgstr "" +msgstr "Oczekujące" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zamknięte" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nazwa, Opis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Tylko nazwy" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Dokładnej nazwy" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Dokładnej bazy pakietu" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Współopiekuna" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Opiekuna, współopiekuna" +#: template/pkg_search_form.php msgid "All" msgstr "Wszystko" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Oznaczone" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nieoznaczone" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nazwy" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Liczby głosów" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Ostatniej modyfikacji" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Rosnąco" +#: template/pkg_search_form.php msgid "Descending" msgstr "Malejąco" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Wprowadź kryteria wyszukiwania" +#: template/pkg_search_form.php msgid "Search by" msgstr "Szukaj według" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Nieaktualne" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortuj według" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Porządek sortowania" +#: template/pkg_search_form.php msgid "Per page" msgstr "Elementów na stronę" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Szukaj" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Osierocone pakiety" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Wystąpił błąd podczas otrzymywania listy pakietów." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nie znaleziono pakietów spełniających kryteria wyszukiwania." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1495,117 +1876,278 @@ msgstr[1] "%d pakiety znaleziono" msgstr[2] "%d pakietów znaleziono" msgstr[3] "%d pakietów znaleziono" +#: template/pkg_search_results.php msgid "Version" msgstr "Wersja" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Tak" +#: template/pkg_search_results.php msgid "orphan" msgstr "pakiet osierocony" +#: template/pkg_search_results.php msgid "Actions" msgstr "Działania" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Odznacz jako nieaktualny" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Przejmij pakiety" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Porzuć pakiety" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Usuń pakiety" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potwierdź" +#: template/search_accounts_form.php msgid "Any type" msgstr "Dowolnego typu" +#: template/search_accounts_form.php msgid "Search" msgstr "Szukaj" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statystyki" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Osierocone pakiety" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pakiety dodane w ciągu ostatniego tygodnia" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pakiety zaktualizowane w ciągu ostatniego tygodnia" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pakiety zaktualizowane w ostatnim roku" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pakiety nigdy nie aktualizowane" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Zarejestrowani użytkownicy" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Zaufani użytkownicy" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Ostatnio aktualizowane" +#: template/stats/updates_table.php msgid "more" msgstr "więcej" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moje statystyki" +#: template/tu_details.php msgid "Proposal Details" msgstr "Szczegóły propozycji" +#: template/tu_details.php msgid "This vote is still running." msgstr "Głosowanie ciągle trwa." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Wysłane: %s przez %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Koniec" +#: template/tu_details.php msgid "Result" msgstr "Wynik" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nie" +#: template/tu_details.php msgid "Abstain" msgstr "Wstrzymaj się od głosu" +#: template/tu_details.php msgid "Total" msgstr "Suma" +#: template/tu_details.php msgid "Participation" msgstr "Uczestnictwo" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ostatnie głosy ZU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ostatni głos" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Brak wyników." +#: template/tu_list.php msgid "Start" msgstr "Początek" +#: template/tu_list.php msgid "Back" msgstr "Wstecz" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "Reset hasła AUR" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "Witamy w AUR: Repozytorium Użytkowników Arch" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "Komentarze AUR do {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "Aktualizacja pakietu AUR: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "Usunięty pakiet AUR: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/pt_BR.po b/po/pt_BR.po index 0f862a08..8c05a312 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1,1637 +1,2139 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Albino Biasutti Neto Bino , 2011 # Fábio Nogueira , 2016 # Rafael Fontenelle , 2012-2015 -# Rafael Fontenelle , 2011,2015-2017 +# Rafael Fontenelle , 2011,2015-2018 # Rafael Fontenelle , 2011 # Sandro , 2011 # Sandro , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 22:00+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-21 18:28+0000\n" "Last-Translator: Rafael Fontenelle \n" -"Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aur/" -"language/pt_BR/)\n" -"Language: pt_BR\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aurweb/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página não encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Desculpe, a página que você solicitou não existe." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Nota" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "URLs de git-clone não servem para ser abertas em um navegador." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Para clonar o repositório Git de %s, execute %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Clique %saqui%s para retornar para a página de detalhes de %s." +#: html/503.php msgid "Service Unavailable" msgstr "Serviço indisponível" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Sem pânico! Este site está fechado para manutenção. Voltaremos às atividades " -"em breve." +msgstr "Sem pânico! Este site está fechado para manutenção. Voltaremos às atividades em breve." +#: html/account.php msgid "Account" msgstr "Conta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Contas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Você não tem permissão para acessar esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Não foi possível obter informações para o usuário especificado." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Você não tem permissão para editar esta conta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Você precisa fazer login para ver as informações do usuário." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adicionar proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Token inválido para a ação de usuário." +#: html/addvote.php msgid "Username does not exist." msgstr "Usuário não existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s já tem uma proposta aberta para eles." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo inválido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Proposta não pode ser vazia." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta foi enviada." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Enviar uma proposta para ser votada." +#: html/addvote.php msgid "Applicant/TU" msgstr "Requerente/UC" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vazio se não aplicável)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Adição de um UC" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remoção de um UC" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remoção de um UC (inatividade não declarada)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Emenda ao Estatuto" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Enviar" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Gerenciar co-mantenedores" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Editar comentário" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Dashboard" +#: html/home.php template/header.php msgid "Home" msgstr "Início" +#: html/home.php msgid "My Flagged Packages" msgstr "Meus pacotes sinalizados" +#: html/home.php msgid "My Requests" msgstr "Minhas requisições" +#: html/home.php msgid "My Packages" msgstr "Meus pacotes" +#: html/home.php msgid "Search for packages I maintain" msgstr "Pesquisar por pacotes que eu mantenho" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Pacote comantidos" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Pesquisar por pacotes que eu comantenho" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bem-vindo ao AUR! Por favor, leia as %sDiretrizes de Usuário do AUR%s e " -"%sDiretrizes de UC do AUR%s para mais informações." +msgstr "Bem-vindo ao AUR! Por favor, leia as %sDiretrizes de Usuário do AUR%s e %sDiretrizes de UC do AUR%s para mais informações." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"PKGBUILDs contribuídos %sdevem%s estar em conformidade com os %sPadrões de " -"Empacotamento do Arch%s, do contrário eles serão excluídos!" +msgstr "PKGBUILDs contribuídos %sdevem%s estar em conformidade com os %sPadrões de Empacotamento do Arch%s, do contrário eles serão excluídos!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Lembre-se de votar nos seus pacotes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Alguns pacotes podem ser fornecidos como binários no repositório [community]." +msgstr "Alguns pacotes podem ser fornecidos como binários no repositório [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVISO LEGAL" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Os pacotes do AUR são conteúdos produzidos por usuários. Qualquer uso dos " -"arquivos fornecidos é de sua própria conta e risco." +msgstr "Os pacotes do AUR são conteúdos produzidos por usuários. Qualquer uso dos arquivos fornecidos é de sua própria conta e risco." +#: html/home.php msgid "Learn more..." msgstr "Aprenda mais..." +#: html/home.php msgid "Support" msgstr "Suporte" +#: html/home.php msgid "Package Requests" msgstr "Requisições de pacote" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Há três tipos de requisições que podem ser realizadas na caixa %sAções do " -"pacote%s na página de detalhes do pacote:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Há três tipos de requisições que podem ser realizadas na caixa %sAções do pacote%s na página de detalhes do pacote:" +#: html/home.php msgid "Orphan Request" msgstr "Requisição para tornar o pacote órfão" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Requisite que seja desvinculado um pacote de seu mantenedor, de forma que o " -"pacote fique órfão, quando, por exemplo, o mantenedor está inativo e o " -"pacote foi marcado como desatualizado há muito tempo." +msgstr "Requisite que seja desvinculado um pacote de seu mantenedor, de forma que o pacote fique órfão, quando, por exemplo, o mantenedor está inativo e o pacote foi marcado como desatualizado há muito tempo." +#: html/home.php msgid "Deletion Request" msgstr "Requisição de exclusão" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Requisite que um pacote seja removido do Arch User Repository. Por favor, " -"não use esta opção se um pacote está quebrado, mas que pode ser corrigido " -"facilmente. Ao invés disso, contate o mantenedor do pacote e, se necessário, " -"preencha uma requisição para tornar esse pacote órfão." +msgstr "Requisite que um pacote seja removido do Arch User Repository. Por favor, não use esta opção se um pacote está quebrado, mas que pode ser corrigido facilmente. Ao invés disso, contate o mantenedor do pacote e, se necessário, preencha uma requisição para tornar esse pacote órfão." +#: html/home.php msgid "Merge Request" msgstr "Requisição de mesclagem" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Requisite que um pacote seja mesclado com outro. Pode ser usado quando um " -"pacote precisa ser renomeado ou substituído por um pacote dividido." +msgstr "Requisite que um pacote seja mesclado com outro. Pode ser usado quando um pacote precisa ser renomeado ou substituído por um pacote dividido." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Se você quiser discutir uma requisição, você pode user a lista de discussão " -"%saur-request%s. Porém, por favor não use essa lista para fazer requisições." +msgstr "Se você quiser discutir uma requisição, você pode user a lista de discussão %saur-request%s. Porém, por favor não use essa lista para fazer requisições." +#: html/home.php msgid "Submitting Packages" msgstr "Enviando pacotes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git sobre SSH agora é usado para enviar pacotes para o AUR. Veja a seção " -"%sEnviando pacotes%s da página wiki do Arch User Repository para mais " -"detalhes." +msgstr "Git sobre SSH agora é usado para enviar pacotes para o AUR. Veja a seção %sEnviando pacotes%s da página wiki do Arch User Repository para mais detalhes." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "As seguintes impressões digitais SSH são usadas para o AUR:" +#: html/home.php msgid "Discussion" msgstr "Discussão" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) " -"e do Usuário Confiável acontecem no %saur-general%s. Para discussão " -"relacionada ao desenvolvimento do AUR web, use a lista de discussão do %saur-" -"dev%s" +msgstr "Discussões gerais no que se refere à estrutura do Arch User Repository (AUR) e do Usuário Confiável acontecem no %saur-general%s. Para discussão relacionada ao desenvolvimento do AUR web, use a lista de discussão do %saur-dev%s" +#: html/home.php msgid "Bug Reporting" msgstr "Relatório de erros" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Se você encontrar um erro na interface web do AUR, por favor preencha um " -"relatório de erro no nosso %sbug tracker%s. Use o tracker para relatar erros " -"encontrados no AUR web, %ssomente%s. Para relatar erros de empacotamento, " -"contate o mantenedor do pacote ou deixe um comentário na página de pacote " -"apropriada." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Se você encontrar um erro na interface web do AUR, por favor preencha um relatório de erro no nosso %sbug tracker%s. Use o tracker para relatar erros encontrados no AUR web, %ssomente%s. Para relatar erros de empacotamento, contate o mantenedor do pacote ou deixe um comentário na página de pacote apropriada." +#: html/home.php msgid "Package Search" msgstr "Pesquisar pacote" +#: html/index.php msgid "Adopt" msgstr "Adotar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Desfazer voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Não notificar" +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Login" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Conectado como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Sair" +#: html/login.php msgid "Enter login credentials" msgstr "Digite as credenciais de login" +#: html/login.php msgid "User name or email address" msgstr "Nome de usuário ou endereço de e-mail" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Senha" +#: html/login.php msgid "Remember me" msgstr "Lembrar de mim" +#: html/login.php msgid "Forgot Password" msgstr "Esqueci minha senha" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Login via HTTP está desabilitado. Favor %sacesse via HTTPs%s caso queira " -"fazer login." +msgstr "Login via HTTP está desabilitado. Favor %sacesse via HTTPs%s caso queira fazer login." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critérios de pesquisa" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacotes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erro ao tentar obter detalhes do pacote." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Preencha todos os campos obrigatórios." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Campos de senha não correspondem." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Sua senha deve conter pelo menos %s caracteres." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail inválido." +#: html/passreset.php msgid "Password Reset" msgstr "Redefinição de senha" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifique no seu e-mail pelo link de confirmação." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Sua senha foi redefinida com sucesso." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme seu endereço de e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Informe com sua senha:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme sua nova senha:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continuar" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Se você esqueceu o endereço de e-mail que você usou para registrar, por " -"favor envie uma mensagem para a lista de e-mail do %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Se você esqueceu o endereço de e-mail que você usou para registrar, por favor envie uma mensagem para a lista de e-mail do %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Digite o seu endereço de e-mail:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Pacotes base" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Os pacotes selecionados não foram abandonados, marque a caixa de confirmação." +msgstr "Os pacotes selecionados não foram abandonados, marque a caixa de confirmação." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Não foi possível encontrar pacote para nele fundir votos e comentários." +msgstr "Não foi possível encontrar pacote para nele fundir votos e comentários." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Não é possível mesclar um pacote base com ele mesmo" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Exclusão de pacotes" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Excluir pacote" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Use este formulário para excluir o pacote base %s%s%s e os seguintes pacotes " -"do AUR: " +msgstr "Use este formulário para excluir o pacote base %s%s%s e os seguintes pacotes do AUR: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "A exclusão de pacote um pacote é permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Marque a caixa de seleção para confirmar a ação." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmar exclusão de pacote" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Excluir" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Somente Usuários Confiáveis e Desenvolvedores podem excluir pacotes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonar pacote" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Use esse formulário para abandonar o pacote base %s%s%s que incluem os " -"seguintes pacotes:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Use esse formulário para abandonar o pacote base %s%s%s que incluem os seguintes pacotes:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "Ao marcar a caixa de seleção, você confirma que deseja deixar de ser um comantenedor de pacote." + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote e " -"transferir a responsabilidade para %s%s%s." +msgstr "Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote e transferir a responsabilidade para %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote." +msgstr "Ao marcar a caixa de seleção, você confirma que deseja abandonar o pacote." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Confirme para abandonar o pacote" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Apenas Usuários Confiáveis e Desenvolvedores podem abandonar pacotes." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Comentário da marcação" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Marcar pacote desatualizado" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Use este formulário para marcar o pacote base %s%s%s e os seguintes pacotes " -"como desatualizados: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Use este formulário para marcar o pacote base %s%s%s e os seguintes pacotes como desatualizados: " +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Por favor, %snão%s use esse formulário para relatar erros. Para isto, use os " -"comentários do pacote." +msgstr "Por favor, %snão%s use esse formulário para relatar erros. Para isto, use os comentários do pacote." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Insira detalhes sobre o motivo do pacote estar desatualizado abaixo, " -"preferivelmente incluindo links para o anúncio de lançamento ou um novo " -"tarball de lançamento." +msgstr "Insira detalhes sobre o motivo do pacote estar desatualizado abaixo, preferivelmente incluindo links para o anúncio de lançamento ou um novo tarball de lançamento." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Comentários" +#: html/pkgflag.php msgid "Flag" msgstr "Marcar" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Apenas usuários registrados podem marcar pacotes como desatualizados." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Mesclagem de pacotes" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Mesclar pacote" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Use este formulário para mesclar o pacote base %s%s%s em outro pacote. " +msgstr "Use este formulário para mesclar o pacote base %s%s%s em outro pacote. " +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Os seguintes pacotes serão excluídos: " +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " -msgstr "" -"Assim que o pacote tiver sido mesclado, não é possível reverter a ação." +msgstr "Assim que o pacote tiver sido mesclado, não é possível reverter a ação." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Digite o nome do pacote para o qual você deseja mesclar o pacote." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Mesclar em:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmar a mesclagem de pacotes" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Mesclar" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Somente Usuários Confiáveis e Desenvolvedores podem mesclar pacotes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Enviar requisição" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fechar requisição" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Próxima" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Última" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Requisições" +#: html/register.php template/header.php msgid "Register" msgstr "Registrar" +#: html/register.php msgid "Use this form to create an account." msgstr "Utilize este formulário para criar uma conta." +#: html/tos.php msgid "Terms of Service" msgstr "Termos de Serviço" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" -"Os seguintes documentos foram atualizados. Por favor, revise-os " -"cuidadosamente:" +msgstr "Os seguintes documentos foram atualizados. Por favor, revise-os cuidadosamente:" +#: html/tos.php #, php-format msgid "revision %d" msgstr "revisão %d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "Eu aceito os termos e condições acima." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Usuário confiável" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Não foi possível adquirir detalhes da proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A votação está encerrada para esta proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Apenas Usuários Confiáveis têm permissão para votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Você não pode votar em uma proposta sobre você." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Você já votou nessa proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID de voto inválido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos atuais" +#: html/tu.php msgid "Past Votes" msgstr "Votos anteriores" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Eleitores" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O registro de conta foi desabilitado para seu endereço IP, provavelmente por " -"causa de ataques continuados de spam. Desculpe a inconveniência." +msgstr "O registro de conta foi desabilitado para seu endereço IP, provavelmente por causa de ataques continuados de spam. Desculpe a inconveniência." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Faltando ID de usuário" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "O usuário é inválido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Deve conter entre %s e %s caracteres" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Começo e fim com uma letra ou um número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Pode conter somente um ponto, traço inferior ou hífen." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" -"A página inicial é inválida. Por favor especificar a URL HTTP(s) completa." +msgstr "A página inicial é inválida. Por favor especificar a URL HTTP(s) completa." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "A chave pública de SSH é inválida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Não foi possível aumentar as permissões da conta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Idioma sem suporte no momento." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Fuso horário sem suporte no momento." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de usuário, %s%s%s, já está sendo usado." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "O endereço, %s%s%s, já está sendo usado." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "A chave pública de SSH, %s%s%s, já está em uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erro ao tentar criar uma conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A conta %s%s%s foi criada com sucesso." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Uma chave de redefinição de senha foi enviada para seu endereço de e-mail." +msgstr "Uma chave de redefinição de senha foi enviada para seu endereço de e-mail." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clique no link de Login acima para usar a sua conta." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nenhuma alteração foi feita na conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A conta %s%s%s foi modificada com sucesso." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O formulário de login está desabilitado momento para seu endereço IP, " -"provavelmente por causa de ataques continuados de spam. Desculpe a " -"inconveniência." +msgstr "O formulário de login está desabilitado momento para seu endereço IP, provavelmente por causa de ataques continuados de spam. Desculpe a inconveniência." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Conta suspensa" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Sua senha foi redefinida. Se você acabou de criar uma conta, por favor use o " -"link do e-mail de confirmação para definir uma senha inicial. Do contrário, " -"por favor requisite uma chave de senha na página de %sRedefinição de senha%s." +msgstr "Sua senha foi redefinida. Se você acabou de criar uma conta, por favor use o link do e-mail de confirmação para definir uma senha inicial. Do contrário, por favor requisite uma chave de senha na página de %sRedefinição de senha%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Usuário ou senha inválida." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ocorreu um erro ao tentar gerar uma sessão de usuário." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinação entre email e chave de redefinição é inválida" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nenhum" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver informações da conta para %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Faltando ID ou nome do pacote base." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Você não tem permissão para editar este comentário." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "O comentário não existe." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "O comentário não pode estar vazio." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "O comentário foi adicionado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Você tem que estar conectado para poder editar informações do pacote." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Faltando ID de comentário." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Não mais que 5 comentários podem ser afixados." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Você não tem permissão para afixar este comentário." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Você não tem permissão para desafixar este comentário." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "O comentário foi afixado." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "O comentário foi desafixado." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Erro ao obter detalhes do pacote." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Não foi possível encontrar os detalhes do pacote." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Você deve estar conectado para marcar os pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Você não selecionou nenhum pacote para marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" -"Os pacotes selecionados não foram marcados como desatualizados, por favor " -"insira um comentário." +msgstr "Os pacotes selecionados não foram marcados como desatualizados, por favor insira um comentário." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "O pacote selecionado foi marcado como desatualizado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Você deve estar conectado para desmarcar os pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Você não selecionou nenhum pacote para desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "O pacote selecionado foi desmarcado." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Você não tem permissão para excluir pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Você selecionou nenhum pacote para excluir." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Os pacotes selecionados foram excluídos." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Você deve estar conectado para adotar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Você deve estar conectado para abandonar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Você não selecionou pacote para adotar." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Você não selecionou pacote para abandonar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Os pacotes selecionados foram adotados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Os pacotes selecionados foram abandonados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Você deve estar conectado para votar nos pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Você deve estar conectado para desfazer o voto dos pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Você não selecionou nenhum pacote para votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Seus votos foram removidos dos pacotes selecionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Seus votos foram enviados para os pacotes selecionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Não foi possível adicionar à lista de notificação." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Você foi adicionado à lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Você foi removido da lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Você não tem permissão para desfazer a exclusão deste comentário." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "O comentário teve sua exclusão desfeita." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Você não tem permissão para excluir esse comentário." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "O comentário foi excluído." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "O comentário foi editado." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"Você não tem permissão para editar as palavras-chaves deste pacote base." +msgstr "Você não tem permissão para editar as palavras-chaves deste pacote base." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "As palavras-chave do pacote base foram atualizadas." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Você não tem permissão para gerenciar comantenedores deste pacote base." +msgstr "Você não tem permissão para gerenciar comantenedores deste pacote base." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Nome de usuário inválido: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Os comantenedores do pacote base foram atualizados." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalhes de pacotes para" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "requer %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Você deve estar conectado para preencher requisições de pacotes." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nome inválido: apenas letras minúsculas são permitidas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "O campo de comentário não pode estar vazio" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de requisição inválida" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Requisição adicionada com sucesso" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Motivo inválido" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Apenas UCs e desenvolvedores podem fechar requisições." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Requisição fechada com sucesso" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Você pode usar esse formulário para excluir permanentemente a conta %s do " -"AUR." +msgstr "Você pode usar esse formulário para excluir permanentemente a conta %s do AUR." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sAVISO%s: Essa ação não pode ser desfeita." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmar exclusão" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Usuário" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de conta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Usuário" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolvedor" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Usuário Confiável & Desenvolvedor" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Endereço de e-mail" +#: template/account_details.php msgid "hidden" msgstr "oculto" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Página inicial" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Apelido no IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Impressão digital de chave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Inativo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Ativa" +#: template/account_details.php msgid "Registration date:" msgstr "Data de registro:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "desconhecido" +#: template/account_details.php msgid "Last Login" msgstr "Último login" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Visualizar pacotes deste usuário" +#: template/account_details.php msgid "Edit this user's account" msgstr "Edite a conta desse usuário" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clique %saqui%s se você deseja excluir permanentemente esta conta." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Clique %saqui%s para os detalhes do usuário." +#: template/account_edit_form.php msgid "required" msgstr "obrigatório" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" -"Seu nome de usuário é o nome que você vai usar para se autenticar. É visível " -"para o público geral, mesmo se sua contas estiver inativa." +msgstr "Seu nome de usuário é o nome que você vai usar para se autenticar. É visível para o público geral, mesmo se sua contas estiver inativa." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Usuário normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Conta suspensa" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inativo" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Por favor, certifique-se de que você informou seu endereço de e-mail, do " -"contrário você perderá acesso." +msgstr "Por favor, certifique-se de que você informou seu endereço de e-mail, do contrário você perderá acesso." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Ocultar endereço de e-mail" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Re-digite a senha" +#: template/account_edit_form.php msgid "Language" msgstr "Idioma" +#: template/account_edit_form.php msgid "Timezone" msgstr "Fuso horário" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"A informação a seguir é necessária apenas se você deseja enviar pacotes para " -"o Repositório de Usuário do Arch." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "A informação a seguir é necessária apenas se você deseja enviar pacotes para o Repositório de Usuário do Arch." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Chave pública de SSH" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Configurações de notificação" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notificar sobre novos comentários" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Notificar sobre atualizações de pacotes" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Notificar sobre mudanças de mantenedor" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Atualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Criar" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Limpar" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nenhum resultado correspondeu aos seus critérios de pesquisa." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar conta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspensa" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Mais" +#: template/account_search_results.php msgid "No more results to display." msgstr "Não há mais resultados para serem exibidos." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Use este formulário para adicionar comantenedores para %s%s%s (um nome de " -"usuário por linha):" +msgstr "Use este formulário para adicionar comantenedores para %s%s%s (um nome de usuário por linha):" +#: template/comaintainers_form.php msgid "Users" msgstr "Usuários" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Salvar" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Comentário sobre marcação como desatualizado: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s marcou %s%s%s como desatualizado em %s%s%s pelo seguinte motivo:" +msgstr "%s%s%s marcou %s%s%s como desatualizado em %s%s%s pelo seguinte motivo:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s não está marcado como desatualizado." +#: template/flag_comment.php msgid "Return to Details" msgstr "Retornar para Detalhes" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d Equipe de Desenvolvimento do aurweb." +#: template/header.php msgid " My Account" msgstr " Minha conta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ações do pacote" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Visualizar PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Ver alterações" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Baixar snapshot" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Pesquisar no wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Marcado como desatualizado (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar como desatualizado" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar desatualização" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Remover voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar neste pacote" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Desabilitar notificações" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Habilitar notificações" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Gerenciar comantenedores" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requisição pentende" msgstr[1] "%d requisições pentendes" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotar pacote" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalhes do pacote base" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "somente leitura" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palavras-chave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Criado por" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Mantenedor" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último empacotador" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularidade" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Criado em" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última atualização" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Editar comentário para: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adicionar comentário" +#: template/pkg_comments.php msgid "View all comments" msgstr "Ver todos os comentários" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Comentários afixados" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos comentários" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s comentou em %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Comentário anônimo em %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "excluído em %s por %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "excluído em %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "editado em %s por %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "editado em %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Desfazer exclusão de comentário" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Excluir comentário" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Afixar comentário" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Desafixar comentário" +#: template/pkg_comments.php msgid "All comments" msgstr "Todos os comentários" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do pacote" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacote base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrição" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visitar o site para" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenças" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitos" +#: template/pkg_details.php msgid "Provides" msgstr "Provê" +#: template/pkg_details.php msgid "Replaces" msgstr "Substitui" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependências" +#: template/pkg_details.php msgid "Required by" msgstr "Necessário para" +#: template/pkg_details.php msgid "Sources" msgstr "Fontes" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Use esse formulário para fechar a requisição para o pacote base %s%s%s." +msgstr "Use esse formulário para fechar a requisição para o pacote base %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"O campo de comentários pode ser deixado vazio. Porém, é fortemente " -"recomendado adicionar um comentário ao rejeitar uma requisição." +msgstr "O campo de comentários pode ser deixado vazio. Porém, é fortemente recomendado adicionar um comentário ao rejeitar uma requisição." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motivo" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceito" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rejeitado" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Use esse formulário para fazer uma requisição sobre o pacote base %s%s%s que " -"inclui os seguintes pacotes:" +msgstr "Use esse formulário para fazer uma requisição sobre o pacote base %s%s%s que inclui os seguintes pacotes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de requisição" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Excluir" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Tornar órfão" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Mesclar em" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Ao enviar uma requisição de exclusão, você solicita que um Trusted User " -"exclua o pacote base. Esse tipo de requisição deveria ser usada em caso de " -"duplicidade, softwares abandonados pelo upstream, assim como pacotes ilegais " -"ou irreparavelmente quebrados." +msgstr "Ao enviar uma requisição de exclusão, você solicita que um Trusted User exclua o pacote base. Esse tipo de requisição deveria ser usada em caso de duplicidade, softwares abandonados pelo upstream, assim como pacotes ilegais ou irreparavelmente quebrados." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Ao enviar uma requisição de mesclagem, você solicita que um Trusted User " -"exclua o pacote base e transfira seus votos e comentários para um outro " -"pacote base. Mesclar um pacote não afeta os repositórios Git " -"correspondentes. Certifique-se de você mesmo atualizar o histórico Git do " -"pacote alvo." +msgstr "Ao enviar uma requisição de mesclagem, você solicita que um Trusted User exclua o pacote base e transfira seus votos e comentários para um outro pacote base. Mesclar um pacote não afeta os repositórios Git correspondentes. Certifique-se de você mesmo atualizar o histórico Git do pacote alvo." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Ao enviar uma requisição de tornar órfão, você pede que um Trusted User " -"abandona o pacote base. Por favor, apenas faça isto se o pacote precise de " -"ação do mantenedor, estando este ausente por muito tempo, e você já tentou - " -"e não conseguiu - contatá-lo anteriormente." +msgstr "Ao enviar uma requisição de tornar órfão, você pede que um Trusted User abandona o pacote base. Por favor, apenas faça isto se o pacote precise de ação do mantenedor, estando este ausente por muito tempo, e você já tentou - e não conseguiu - contatá-lo anteriormente." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Nenhuma requisição correspondeu aos seus critérios de pesquisa." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d requisição de pacote encontrada." msgstr[1] "%d requisições de pacotes encontradas." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pacote" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Criada por" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d dia restante" msgstr[1] "~%d dias restantes" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d hora restante" msgstr[1] "~%d horas restantes" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 hora restante" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceitar" +#: template/pkgreq_results.php msgid "Locked" msgstr "Travado" +#: template/pkgreq_results.php msgid "Close" msgstr "Fechar" +#: template/pkgreq_results.php msgid "Pending" msgstr "Pendente" +#: template/pkgreq_results.php msgid "Closed" msgstr "Fechada" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, descrição" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Somente nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exato" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacote base exato" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Comantenedor" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Mantenedor, comantenedor" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcado" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Não marcado" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votado" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Última modificação" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Crescente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Decrescente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Digite os critérios de pesquisa" +#: template/pkg_search_form.php msgid "Search by" msgstr "Pesquisar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desatualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordem de classificação" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Pesquisar" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Órfãos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erro ao obter a lista de pacotes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nenhum pacote correspondeu aos seus critérios de pesquisa." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versão" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Popularidade é calculada como a soma de todos os votos, sendo cada voto " -"pesado com um fator de %.2f por dia desde sua criação." +msgstr "Popularidade é calculada como a soma de todos os votos, sendo cada voto pesado com um fator de %.2f por dia desde sua criação." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sim" +#: template/pkg_search_results.php msgid "orphan" msgstr "órfão" +#: template/pkg_search_results.php msgid "Actions" msgstr "Ações" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar desatualizado" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adotar pacotes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonar pacotes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Excluir pacotes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualquer tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Pesquisa" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estatísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacotes órfãos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacotes adicionados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacotes atualizados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacotes atualizados no último ano" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacotes nunca atualizados" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Usuários registrados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Usuários Confiáveis" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Atualizações recentes" +#: template/stats/updates_table.php msgid "more" msgstr "mais" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Minhas estatísticas" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalhes da proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Essa votação ainda está aberta." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Enviado: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fim" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Não" +#: template/tu_details.php msgid "Abstain" msgstr "Abster" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participação" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Últimos votos por UC" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nenhum resultado encontrado." +#: template/tu_list.php msgid "Start" msgstr "Iniciar" +#: template/tu_list.php msgid "Back" msgstr "Voltar" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "Redefinir senha do AUR" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "Uma requisição de redefinição de senha foi enviada para a conta {user} associada com seu endereço de e-mail. Se deseja redefinir sua senha acesse o link [1] abaixo, do contrário ignore essa mensagem e nada vai acontecer." + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "Bem-vindo ao Arch User Repository" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "Bem-vindo ao Arch User Repository! Para definir uma senha inicial para sua nova conta, por favor clique no link [1] abaixo. Se o link não funcionar, tente copiar e colá-lo no seu navegador." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "Comentário no AUR para {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "{user} [1] adicionou o seguinte comentário ao {pkgbase} [2]:" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "Se você não deseja mais receber notificações sobre esse pacote, por favor vá à página do pacote [2] e selecione \"{label}\"." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "Atualização de pacote do AUR: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "{user} [1] enviou um novo commit ao {pkgbase} [2]." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "Notificação de desatualização do AUR para {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "Seu pacote {pkgbase} [1] foi marcado como desatualizado por {user} [2]:" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "Notificação de propriedade do AUR para {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "O pacote {pkgbase} [1] foi adotado por {user} [2]." + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "O pacote {pkgbase} [1] foi abandonado por {user} [2]." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "Notificação de comantenedor do AUR para {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "Você foi adicionado à lista de comantenedor de {pkgbase} [1]." + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "Você foi removido da lista de comantenedor de {pkgbase} [1]." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "Pacote do AUR excluído: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "{user} [1] mesclou {old} [2] ao {new} [3].\n\nSe você não deseja mais receber notificações sobre o novo pacote, por favor acesse a [3] e clique em \"{label}\"." + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "{user} [1] excluiu {pkgbase} [2].\n\nVocê não mais receberá notificações sobre esse pacote." + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "Lembrete de votação de TU: Proposta {id}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "Por favor, lembre-se de votar na proposta {id} [1]. O período de votação termina em menos de 48 horas." diff --git a/po/pt_PT.po b/po/pt_PT.po index 3002f5a7..30a75434 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -1,8 +1,9 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: +# Christophe Silva , 2018 # Gaspar Santos , 2011 # R00KIE , 2013,2016 # R00KIE , 2011 @@ -10,1314 +11,1671 @@ # DarkVenger, 2012 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/" -"aur/language/pt_PT/)\n" -"Language: pt_PT\n" +"Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/aurweb/language/pt_PT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: pt_PT\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Página Não Encontrada" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "As nossas desculpas, a página que pediu não existe." +#: html/404.php template/pkgreq_close_form.php msgid "Note" -msgstr "" +msgstr "Nota" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "URLs Git clone não sao destinados a serem abertos em browser." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "Para clonar o repositório Git do %s, executa %s" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Clica %s aqui %s para retornares à %s página de detalhes" +#: html/503.php msgid "Service Unavailable" msgstr "Serviço não disponível" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Não entre em pânico! Esta página encontra-se em baixo devido a manutenção. " -"Voltaremos brevemente." +msgstr "Não entre em pânico! Esta página encontra-se em baixo devido a manutenção. Voltaremos brevemente." +#: html/account.php msgid "Account" msgstr "Conta" +#: html/account.php template/header.php msgid "Accounts" msgstr "Contas" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Não tem autorização para aceder a esta área." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Não foi possível obter informações para o utilizador especificado." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Não tem autorização para editar esta conta." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." +#: html/account.php msgid "You must log in to view user information." msgstr "Necessita iniciar sessão para visualizar a informação do utilizador." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adicionar Proposta" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Token inválido para acção de utilizador." +#: html/addvote.php msgid "Username does not exist." msgstr "O utilizador não existe." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s já tem uma proposta a decorrer." +#: html/addvote.php msgid "Invalid type." msgstr "Tipo inválido." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "A proposta não pode estar vazia." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nova proposta submetida." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Submeta uma proposta para votação." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidato/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(vazio se não aplicável)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tipo" +#: html/addvote.php msgid "Addition of a TU" msgstr "Adição de um TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Remoção de um TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Remoção de um TU (inatividade não declarada)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Alterações ao Estatutos" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Proposta" +#: html/addvote.php msgid "Submit" msgstr "Enviar" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Gerir responsáveis" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Editar comentário" +#: html/home.php template/header.php msgid "Dashboard" -msgstr "" +msgstr "Painel de Controle" +#: html/home.php template/header.php msgid "Home" msgstr "Início" +#: html/home.php msgid "My Flagged Packages" -msgstr "" +msgstr "Os meus pacotes marcados" +#: html/home.php msgid "My Requests" -msgstr "" +msgstr "Os meus Pedidos" +#: html/home.php msgid "My Packages" msgstr "Os meus pacotes" +#: html/home.php msgid "Search for packages I maintain" -msgstr "" +msgstr "Procurar por pacotes que eu mantenho" +#: html/home.php msgid "Co-Maintained Packages" -msgstr "" +msgstr "Pacotes Co-Mantidos" +#: html/home.php msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Procurar por pacotes que eu co-mantenho" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bem-vindo ao AUR! Por favor leia as %sOrientações de Utilizador do AUR%s e " -"%sOrientações de TU do AUR%s para mais informações." +msgstr "Bem-vindo ao AUR! Por favor leia as %sOrientações de Utilizador do AUR%s e %sOrientações de TU do AUR%s para mais informações." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"As contribuições de PKGBUILDs %sdevem%s obedecer aos %sPadrões de " -"Empacotamento Arch%s ou serão eliminadas!" +msgstr "As contribuições de PKGBUILDs %sdevem%s obedecer aos %sPadrões de Empacotamento Arch%s ou serão eliminadas!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Lembre-se de votar nos seus pacotes favoritos!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Alguns dos pacotes podem ser fornecidos como binários no repositório " -"[community]." +msgstr "Alguns dos pacotes podem ser fornecidos como binários no repositório [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "AVISO LEGAL" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Os pacotes AUR são produzidos por utilizadores. O seu uso é por sua conta e " -"risco." +msgstr "Os pacotes AUR são produzidos por utilizadores. O seu uso é por sua conta e risco." +#: html/home.php msgid "Learn more..." msgstr "Saber mais..." +#: html/home.php msgid "Support" msgstr "Suporte" +#: html/home.php msgid "Package Requests" msgstr "Pedidos de Pacotes" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Existem três tipos de pedidos que podem ser preenchidos na caixa " -"%sPackageActions%s na página de detalhes de um pacote." +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Existem três tipos de pedidos que podem ser preenchidos na caixa %sPackageActions%s na página de detalhes de um pacote." +#: html/home.php msgid "Orphan Request" msgstr "Pedido para Tornar Orfão" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Pedido para que um pacote dique sem dono, por exemplo, quando o atual " -"responsável se encontra inativo e o pacote foi marcado como desatualizado há " -"muito tempo." +msgstr "Pedido para que um pacote dique sem dono, por exemplo, quando o atual responsável se encontra inativo e o pacote foi marcado como desatualizado há muito tempo." +#: html/home.php msgid "Deletion Request" msgstr "Pedido para Apagar" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Pedido para que um pacote seja removido do Arch User Repository. Por favor " -"não use este pedido se um pacote está danificado e pode ser resolvido " -"facilmente. Contacte o responsável pelo mesmo e faça um Pedido para Tornar " -"Orfão se necessário." +msgstr "Pedido para que um pacote seja removido do Arch User Repository. Por favor não use este pedido se um pacote está danificado e pode ser resolvido facilmente. Contacte o responsável pelo mesmo e faça um Pedido para Tornar Orfão se necessário." +#: html/home.php msgid "Merge Request" msgstr "Pedido de junção" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Requerer que um pacote seja junto a outro. Pode ser utilizado quando é " -"necessário mudar o nome ao pacote ou substituir o mesmo por um pacote " -"separado." +msgstr "Requerer que um pacote seja junto a outro. Pode ser utilizado quando é necessário mudar o nome ao pacote ou substituir o mesmo por um pacote separado." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Se quiser discutir um pedido, pode faze-lo utilizando a lista de email %saur-" -"requests%s. Por favor não use a lista para submeter pedidos." +msgstr "Se quiser discutir um pedido, pode faze-lo utilizando a lista de email %saur-requests%s. Por favor não use a lista para submeter pedidos." +#: html/home.php msgid "Submitting Packages" msgstr "Submeter Pacotes" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" +msgstr "O \"Git por SSH\" é usado agora para enviar pacotes para o AUR. Veja a seção %s Submitir pacotes %s secção da página ArchWiki do Repositório de Arquivos do Arch para mais detalhes." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" -msgstr "" +msgstr "As seguintes impressões digitais SSH são usadas para o AUR:" +#: html/home.php msgid "Discussion" msgstr "Discussão" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" +msgstr "A discussão geral sobre o Repositório do Usuário do Arco (AUR) e a estrutura do Usuário Confiável ocorre em %s aur-general %s. Para discussão relacionada ao desenvolvimento da interface da web AUR, use a lista de emails %s aur-dev %s" +#: html/home.php msgid "Bug Reporting" msgstr "Reportar um Bug" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Pesquisa de Pacotes" +#: html/index.php msgid "Adopt" msgstr "Adoptar" +#: html/index.php msgid "Vote" msgstr "Votar" +#: html/index.php msgid "UnVote" msgstr "Retirar voto" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificar" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Não Notificar" +#: html/index.php msgid "UnFlag" msgstr "Desmarcar" +#: html/login.php template/header.php msgid "Login" msgstr "Iniciar sessão" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Sessão iniciada como: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Terminar sessão" +#: html/login.php msgid "Enter login credentials" msgstr "Introduza as credenciais para login" +#: html/login.php msgid "User name or email address" -msgstr "" +msgstr "Usuário ou endereço de email" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Palavra-passe" +#: html/login.php msgid "Remember me" msgstr "Lembrar-se de mim" +#: html/login.php msgid "Forgot Password" msgstr "Esqueceu-se da palavra-passe" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Início de sessão em HTTP está desactivado. Por favor %smude para HTTPs%s se " -"pretende iniciar sessão." +msgstr "Início de sessão em HTTP está desactivado. Por favor %smude para HTTPs%s se pretende iniciar sessão." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Critérios de Pesquisa" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pacotes" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Erro ao tentar obter os detalhes do pacote." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Em falta um campo obrigatório." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Campos de palavra-passe não correspondem." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "A sua palavra-passe tem de ter pelo menos %s caracteres." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail inválido." +#: html/passreset.php msgid "Password Reset" msgstr "Reiniciar a Palavra-passe" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifique o seu e-mail para o link de confirmação." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "A palavra-passe foi reiniciada com êxito." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirme o endereço de e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Introduza a nova palavra-passe:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirme a nova palavra-passe:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continue" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Se se esqueceu do endereço de e-mail que utilizou para efectuar o registo, " -"por favor envie uma mensagem para a lista de discussão %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Se se esqueceu do endereço de e-mail que utilizou para efectuar o registo, por favor envie uma mensagem para a lista de discussão %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introduza o endereço de e-mail:" +#: html/pkgbase.php msgid "Package Bases" -msgstr "" +msgstr "Base de pacotes" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" +msgstr "Os pacotes selecionados não foram desaprovados, verifique a caixa de confirmação." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Não é possível encontrar o pacote onde juntar os votos e os comentários." +msgstr "Não é possível encontrar o pacote onde juntar os votos e os comentários." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." -msgstr "" +msgstr "Não é possível combinar uma base de pacotes com ela própria." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Os pacotes selecionados não foram apagados, marque a caixa de confirmação." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Eliminar Pacote" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Eliminar Pacote" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Use este formulário para eliminar o pacote base %s%s%s e os seguintes " -"pacotes do AUR:" +msgstr "Use este formulário para eliminar o pacote base %s%s%s e os seguintes pacotes do AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "A eliminação de um pacote é permanente." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Seleccione a caixa para confirmar a acção." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmar eliminação do pacote" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Eliminar" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." -msgstr "" -"Apenas Utilizadores de Confiança e Programadores podem eliminar pacotes." +msgstr "Apenas Utilizadores de Confiança e Programadores podem eliminar pacotes." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Renunciar Pacote" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Use este formulário para desaprovar os pacotes base %s %s %s que incluem os seguintes pacotes:" + +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." msgstr "" +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" +msgstr "Ao escolher na caixa de seleção, confirma que pretende desaprovar o pacote e transferir a propriedade para %s %s %s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" +msgstr "Ao escolher na caixa de seleção, confirma que pretende desaprovar o pacote." +#: html/pkgdisown.php msgid "Confirm to disown the package" -msgstr "" +msgstr "Confirmar desaprovação do pacote." +#: html/pkgdisown.php msgid "Disown" msgstr "Renunciar" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" +msgstr "Somente Usuários Verificados e Desenvolvedores podem desaprovar pacotes." +#: html/pkgflagcomment.php msgid "Flag Comment" -msgstr "" +msgstr "Marcar comentário." +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" -msgstr "" +msgstr "Marcar pacote desatualizado." +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Use este formulário para marcar o pacote base %s %s %s e os seguintes pacotes desatualizados:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" +msgstr "Porfavor faça %s e não %s para usar o formulário de reporte de bugs. Use os comentários do pacote em vez disso." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" +msgstr "Digite detalhes sobre o porquê do pacote em baixo estar desactualizado, de preferência, incluindo links para o anúncio de lançamento ou o novo lançamento de tarball." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Comentários" +#: html/pkgflag.php msgid "Flag" msgstr "Marcar" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" +msgstr "Somente usuários registados podem marcar pacotes desatualizados." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fusão de Pacotes" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Fundir Pacote" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Use este formulário para fundir o pacote base %s%s%s num outro pacote." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Os pacotes listados serão eliminados:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Uma vez feita a fusão do pacote não há como reverter o processo." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introduza o nome do pacote com o qual deseja realizar a fusão." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fundir com:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confimar fusão de pacote" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fundir" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Apenas Utilizadores de Confiança e Programadores podem fundir pacotes." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" -msgstr "" +msgstr "Submeter Pedido" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Fechar Pedido" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seguinte" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo." +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Pedidos" +#: html/register.php template/header.php msgid "Register" msgstr "Registar" +#: html/register.php msgid "Use this form to create an account." msgstr "Para criar uma conta utilize este formulário." +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "Termos do Serviço" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "Os seguintes documentos foram atualizados. Porfavor verifique-os com cuidado:" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "revisão %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "Eu aceito os termos e condições acima mencionados." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Utilizador de Confiança" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Não foi possível obter detalhes da proposta." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "A votação está fechada para esta proposta." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Apenas Utilizadores de Confiança podem votar." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Não pode votar numa proposta acerca de si." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Já votou nesta proposta." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID de voto não é válido." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Votos Actuais" +#: html/tu.php msgid "Past Votes" msgstr "Votos Passados" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votantes" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O registo de contas encontra-se inibido para pedidos do seu IP, " -"provavelmente devido a continuados ataques de spam. Lamentamos o " -"inconveniente." +msgstr "O registo de contas encontra-se inibido para pedidos do seu IP, provavelmente devido a continuados ataques de spam. Lamentamos o inconveniente." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID de utilizador em falta" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "O nome de utilizador é inválido." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Tem de ter entre %s e %s caracteres de comprimento" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Começar e acabar com uma letra ou um número" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Apenas pode conter um ponto, underscore ou hífen." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "A página inicial é inválida, especifique o URL de HTTP (s) completo (s)." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "A impressão digital da chave PGP é inválida." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." -msgstr "" +msgstr "A chave pública SSH é inválida." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Incapaz de aumentar as permissões da conta." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Língua não suportada actualmente." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." -msgstr "" +msgstr "O fuso horário não é suportado no momento." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "O nome de utilizador, %s%s%s, já se encontra a ser utilizado." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "O endereço, %s%s%s, já está a ser utilizado." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "" +msgstr "A chave pública SSH, %s %s %s, já está em uso." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Erro ao tentar criar a conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "A conta, %s%s%s, foi criada com sucesso." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." -msgstr "" -"Uma chave de reinicialização da sua palavra-passe foi enviada para o seu " -"endereço de e-mail." +msgstr "Uma chave de reinicialização da sua palavra-passe foi enviada para o seu endereço de e-mail." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clique no link Login acima para iniciar sessão." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nenhuma alterações foi realizada à conta, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "A conta, %s%s%s, foi modificada com sucesso." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"O formulário de início de sessão encontra-se inibido para pedidos do seu IP, " -"provavelmente devido a continuados ataques de spam. Lamentamos o " -"inconveniente." +msgstr "O formulário de início de sessão encontra-se inibido para pedidos do seu IP, provavelmente devido a continuados ataques de spam. Lamentamos o inconveniente." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Conta Suspensa" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"A sua palavra passe foi reiniciada. Se criou uma nova conta agora, por favor " -"siga a ligação do email de confirmação para definir uma palavra passe. Caso " -"contrário, por favor peça um reinicio à chave na pagina %sReiniciar Password" -"%s." +msgstr "A sua palavra passe foi reiniciada. Se criou uma nova conta agora, por favor siga a ligação do email de confirmação para definir uma palavra passe. Caso contrário, por favor peça um reinicio à chave na pagina %sReiniciar Password%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Mau nome de utilizador ou palavra-passe." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Ocorreu um erro ao tentar gerar uma sessão de utilizador." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinação de e-mail e chave de recuperação inválidos." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nenhum" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Ver informação de conta de %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." -msgstr "" +msgstr "O ID do pacote base ou o nome do pacote base está em falta." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "" +msgstr "Não está autorizado a editar este comentário." +#: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "" +msgstr "O comentário não existe." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "" +msgstr "O comentário não pode estar vazio." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "O comentário foi adicionado." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Tem de ter sessão iniciada antes de poder as informações de um pacote." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "ID de comentário em falta." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." -msgstr "" +msgstr "Não podem ser marcados mais de 5 comentários." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." -msgstr "" +msgstr "Você não pode definir este comentário." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." -msgstr "" +msgstr "Você não tem permissão para desativar esse comentário." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." -msgstr "" +msgstr "O comentário foi marcado." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." -msgstr "" +msgstr "O comentário foi desmarcado." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Erro ao obter os detalhes do pacote." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Não foi possivel encontrar detalhes acerca do pacote." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Tem de iniciar sessão antes de poder marcar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Não seleccionou nenhum pacote a marcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." -msgstr "" +msgstr "Os pacotes selecionados não foram sinalizados, insira um comentário." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Os pacotes seleccionados foram marcados como desactualizados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Tem de iniciar sessão antes de poder desmarcar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Não seleccionou nenhum pacote a desmarcar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Os pacotes seleccionados foram desmarcados." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Não tem permissão para eliminar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Não seleccionou nenhum pacote a apagar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Os pacotes seleccionados foram apagados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Tem de iniciar se sessão antes de poder adoptar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Tem de iniciar se sessão antes de poder renunciar pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Não seleccionou nenhum pacote a adoptar." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Não seleccionou nenhum pacote a renunciar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Os pacotes seleccionados foram adoptados." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Os pacotes seleccionados foram renunciados." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Tem de iniciar sessão antes de poder votar em pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Tem de ter sessão iniciada antes de poder retirar votos dos pacotes." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Não seleccionou nenhuns pacotes nos quais votar." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Os seus votos foram retirados dos pacotes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Os seus votos foram lançados para os pacotes seleccionados." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Não foi possível adicionar à lista de notificações." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Foi adicionado à lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Foi removido da lista de notificação de comentários de %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." -msgstr "" +msgstr "Você não pode recuperar esse comentário." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Não tem permissão para apagar este comentário." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "O comentário foi apagado." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Ver detalhes do pacote de" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Nome inválido: apenas são permitidas letras minúsculas." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "O campo \"comentários\" não pode ficar vazio." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tipo de pedido inválido." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Pedido adicionado com sucesso." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Razão inválida." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Apenas programadores e TUs podem fechar pedidos." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Pedido fechado com sucesso." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "" +#: template/account_delete.php msgid "Confirm deletion" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nome de utilizador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tipo de conta" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilizador" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Desenvolvedor" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Endereço de E-mail" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nome real" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Nick IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Impressão digital da chave PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Estado" +#: template/account_details.php msgid "Inactive since" msgstr "Inativo desde" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activo" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "desconhecido" +#: template/account_details.php msgid "Last Login" msgstr "Última sessão" +#: template/account_details.php msgid "Never" msgstr "Nunca" +#: template/account_details.php msgid "View this user's packages" msgstr "Ver os pacotes deste utilizador" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editar a conta deste utilizador" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "necessário" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilizador normal" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Utilizador de confiança" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Conta Suspensa" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inativo" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Reintroduza a palavra-passe" +#: template/account_edit_form.php msgid "Language" msgstr "Língua" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notificar-me sobre novos comentários" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizar" +#: template/account_edit_form.php msgid "Create" msgstr "Criar" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reiniciar" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Não existem resultados que correspondam aos seus critérios de procura." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editar Conta" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspenso" +#: template/account_search_results.php msgid "Edit" msgstr "Editar" +#: template/account_search_results.php msgid "Less" msgstr "Menos" +#: template/account_search_results.php msgid "More" msgstr "Mais" +#: template/account_search_results.php msgid "No more results to display." msgstr "Não existem mais resultados para mostrar." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "A minha Conta" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Ações sobre Pacotes" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Ver PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Pesquisar na Wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marcar como desatualizado" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Desmarcar pacote" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Remover voto" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votar neste pacote" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Desativar notificações" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d pedido por atender" msgstr[1] "%d pedidos por atender" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adotar Pacote" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Pacote Base Detalhes" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Palavras-chave" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Submissor" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Responsável pela manutenção" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Último Responsável" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Votos" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Primeira Submissão" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Última Actualização" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adicionar comentário" +#: template/pkg_comments.php msgid "View all comments" msgstr "" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Últimos Comentários" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Pagar comentário" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Todos os comentários" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do Pacote" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pacote Base" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descrição" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL a montante" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Visitar a página web de" +#: template/pkg_details.php msgid "Licenses" msgstr "Licenças" +#: template/pkg_details.php msgid "Groups" msgstr "Grupos" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflitos" +#: template/pkg_details.php msgid "Provides" msgstr "Fornece" +#: template/pkg_details.php msgid "Replaces" msgstr "Substitui" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependências" +#: template/pkg_details.php msgid "Required by" msgstr "Exigido por" +#: template/pkg_details.php msgid "Sources" msgstr "Fontes" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Aceite" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Rejeitado" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Use este formulário para enviar um pedido sobre o pacote base %s%s%s que " -"inclui os seguintes pacotes:" +msgstr "Use este formulário para enviar um pedido sobre o pacote base %s%s%s que inclui os seguintes pacotes:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipo de pedido" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Apagar" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfão" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Juntar em" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1325,6 +1683,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1332,247 +1691,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d pedido de pacote encontrado." msgstr[1] "%d pedidos de pacotes encontrados." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Página %d de %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pacote" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Enviado por" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +#: template/pkgreq_results.php msgid "<1 hour left" -msgstr "" +msgstr "Falta <1 hora" +#: template/pkgreq_results.php msgid "Accept" msgstr "Aceitar" +#: template/pkgreq_results.php msgid "Locked" -msgstr "" +msgstr "Bloqueado" +#: template/pkgreq_results.php msgid "Close" msgstr "Fechar" +#: template/pkgreq_results.php msgid "Pending" -msgstr "" +msgstr "Pendente" +#: template/pkgreq_results.php msgid "Closed" msgstr "Fechado" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nome, Descrição" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Só Nome" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nome exacto" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pacote Base Exacto" +#: template/pkg_search_form.php msgid "Co-maintainer" -msgstr "" +msgstr "Co-maintainer" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" -msgstr "" +msgstr "Maintainer, Co-maintainer" +#: template/pkg_search_form.php msgid "All" msgstr "Todos" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcados" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Não marcados" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nome" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votou" +#: template/pkg_search_form.php msgid "Last modified" -msgstr "" +msgstr "Última modificação" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Ascendente" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descendente" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introduzir critério de pesquisa" +#: template/pkg_search_form.php msgid "Search by" msgstr "Procurar por" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Desactualizado" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Ordenar por" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordem de ordenação" +#: template/pkg_search_form.php msgid "Per page" msgstr "Por página" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Ir" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Órfãos" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Erro ao obter lista de pacotes." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nenhum pacote corresponde aos critérios de procura." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." +#: template/pkg_search_results.php msgid "Version" msgstr "Versão" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Sim" +#: template/pkg_search_results.php msgid "orphan" msgstr "Órfão" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acções" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Desmarcar como Desactualizado" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptar Pacotes" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Renunciar Pacotes" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Apagar Pacotes" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmar" +#: template/search_accounts_form.php msgid "Any type" msgstr "Qualquer tipo" +#: template/search_accounts_form.php msgid "Search" msgstr "Procurar" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Estatísticas" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pacotes Órfãos" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pacotes adicionados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pacotes actualizados nos últimos 7 dias" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pacotes actualizados no último ano" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pacotes nunca actualizados" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilizadores Registados" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Utilizadores de Confiança" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizações recentes" +#: template/stats/updates_table.php msgid "more" -msgstr "" +msgstr "mais" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Minhas Estatísticas" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalhes da Proposta" +#: template/tu_details.php msgid "This vote is still running." msgstr "Este votação ainda está a decorrer." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Submetido: %s por %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Fim" +#: template/tu_details.php msgid "Result" msgstr "Resultado" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Não" +#: template/tu_details.php msgid "Abstain" msgstr "Abster-se" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participação" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Últimos votos de TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Último voto" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Não foram encontrados resultados." +#: template/tu_list.php msgid "Start" msgstr "Inicio" +#: template/tu_list.php msgid "Back" msgstr "Anterior" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/ro.po b/po/ro.po index f3ee1ced..0859fa42 100644 --- a/po/ro.po +++ b/po/ro.po @@ -1,1125 +1,1440 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Arthur Țițeică , 2013-2015 # Lukas Fleischer , 2011 # Mihai Coman , 2011-2014 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Romanian (http://www.transifex.com/lfleischer/aur/language/" -"ro/)\n" -"Language: ro\n" +"Language-Team: Romanian (http://www.transifex.com/lfleischer/aurweb/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?" -"2:1));\n" +"Language: ro\n" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" +#: html/404.php msgid "Page Not Found" msgstr "Pagina nu a fost găsită" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Din păcate, pagina solicitată nu există." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Notă" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "" +#: html/503.php msgid "Service Unavailable" msgstr "" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "" +#: html/account.php msgid "Account" msgstr "Cont" +#: html/account.php template/header.php msgid "Accounts" msgstr "Conturi" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nu îți este permis accesul la această secțiune." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nu s-au putut prelua informații despre utilizatorul specificat." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nu ai permisiune pentru a modifica acest cont." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Folosește acest formular pentru a căuta conturi existente." +#: html/account.php msgid "You must log in to view user information." -msgstr "" -"Trebuie să fi autentificat pentru a putea vedea informații despre " -"utilizatori." +msgstr "Trebuie să fi autentificat pentru a putea vedea informații despre utilizatori." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Adaugă o propunere" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Jeton nevalid pentru acțiunea utilizatorului." +#: html/addvote.php msgid "Username does not exist." msgstr "Nume de utilizator inexistent." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Pentru %s exista o propunere în desfășurare." +#: html/addvote.php msgid "Invalid type." msgstr "Tip nevalid." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Propunerea nu poate fi goală." +#: html/addvote.php msgid "New proposal submitted." msgstr "Propunerea nouă a fost trimisă." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Trimite o propunere pentru a putea fi votată." +#: html/addvote.php msgid "Applicant/TU" msgstr "Candidat/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(gol dacă nu este cazul)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tip" +#: html/addvote.php msgid "Addition of a TU" msgstr "Adăugarea unui TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Înlăturarea unui TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Înlăturarea unui TU (inactivitate nedeclarată)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendamentul Statutului" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Propunere" +#: html/addvote.php msgid "Submit" msgstr "Trimite" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Acasă" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Pachetele mele" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Bine ai venit la AUR! Te rog citește %sGhidul utilizatorului AUR%s și " -"%sGhidul AUR TU%s pentru mai multe informații." +msgstr "Bine ai venit la AUR! Te rog citește %sGhidul utilizatorului AUR%s și %sGhidul AUR TU%s pentru mai multe informații." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"PKGBUILDurile contribuite %strebuie%s să fie conforme cu %sStandardele de " -"Împachetare Arch%s, altfel vor fi șterse!" +msgstr "PKGBUILDurile contribuite %strebuie%s să fie conforme cu %sStandardele de Împachetare Arch%s, altfel vor fi șterse!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nu uita să votezi pentru pachetele tale favorite!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Unele pachete pot fi furnizate ca binare în [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "DECLARAȚIE DE NEASUMARE A RESPONSABILITĂȚII" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "" +#: html/home.php msgid "Learn more..." msgstr "" +#: html/home.php msgid "Support" msgstr "" +#: html/home.php msgid "Package Requests" msgstr "" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "" +#: html/home.php msgid "Orphan Request" msgstr "" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." msgstr "" +#: html/home.php msgid "Deletion Request" msgstr "" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." msgstr "" +#: html/home.php msgid "Merge Request" msgstr "" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." msgstr "" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." msgstr "" +#: html/home.php msgid "Submitting Packages" msgstr "" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." msgstr "" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "" +#: html/home.php msgid "Discussion" msgstr "Discuție" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." msgstr "" +#: html/home.php msgid "Bug Reporting" msgstr "Semnalare buguri" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Căutare pachete" +#: html/index.php msgid "Adopt" msgstr "Adoptă" +#: html/index.php msgid "Vote" msgstr "Vot" +#: html/index.php msgid "UnVote" msgstr "EliminăVot" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Notificare" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "DeNotificare" +#: html/index.php msgid "UnFlag" msgstr "Elimină marcaj" +#: html/login.php template/header.php msgid "Login" msgstr "Autentificare" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Autentificat ca: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "De-autentificare" +#: html/login.php msgid "Enter login credentials" msgstr "Introdu datele de autentificare" +#: html/login.php msgid "User name or email address" msgstr "" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Parolă" +#: html/login.php msgid "Remember me" msgstr "Ține-mă minte" +#: html/login.php msgid "Forgot Password" msgstr "Parolă uitată" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Autentificarea prin HTTP este dezactivată. %sSchimbă pe HTTPS%s dacă vrei să " -"te autentifici." +msgstr "Autentificarea prin HTTP este dezactivată. %sSchimbă pe HTTPS%s dacă vrei să te autentifici." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Criteriul de căutare" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Pachete" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Eroare la încercarea de a prelua detaliile pachetului." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Lipsește un câmp necesar." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Câmpurile parolei nu sunt potrivesc." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Parola trebuie să fie de cel puțin %s caractere." +#: html/passreset.php msgid "Invalid e-mail." msgstr "E-mail nevalid" +#: html/passreset.php msgid "Password Reset" msgstr "Resetare parolă" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Verifică e-mailul pentru legătura de confirmare." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Parola ta a fost restabilită cu succes." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Confirmă adresa de e-mail:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Introdu noua parolă:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Confirmă noua parolă." +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Continuă" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Dacă ai uitat adresa de email folosită la înregistrare, trimite un mesaj la " -"lista de discuții %saur-general%s" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Dacă ai uitat adresa de email folosită la înregistrare, trimite un mesaj la lista de discuții %saur-general%s" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Introdu adresa ta de e-mail:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Nu s-a putut găsi pachet pentru fuzionare voturi și comentarii." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nu se poate fuziona un pachet cu el însuși." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Pachetele selectate nu au fost șterse; verifică căsuța de bifare." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Ștergere pachet" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Șterge pachet" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Folosește acest formular pentru a șterge pachetul de bază %s%s%s și " -"următoarele pachete din AUR: " +msgstr "Folosește acest formular pentru a șterge pachetul de bază %s%s%s și următoarele pachete din AUR: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Ștergerea unui pachet este permanentă." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Bifează căsuța pentru a confirma acțiunea." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Confirmă ștergerea pachetului" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Șterge" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Numai Dezvoltatorii și Trusted Users pot șterge pachete." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Abandonează pachet" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "" +#: html/pkgdisown.php msgid "Disown" msgstr "Abandonează" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." msgstr "" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Comentarii" +#: html/pkgflag.php msgid "Flag" msgstr "Marchează" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "" +#: html/pkgmerge.php msgid "Package Merging" msgstr "Fuzionare pachet" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Fuzionează pachet" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Folosește acest formular pentru a îmbina pachetul de bază %s%s%s cu alt " -"pachet." +msgstr "Folosește acest formular pentru a îmbina pachetul de bază %s%s%s cu alt pachet." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Următoarele pachete vor fi șterse:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Odată ce pachetul a fuzionat, acțiunea nu este reversibilă." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Introdu numele pachetului cu care vrei să fie fuzionat acest pachet." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Fuzionează cu:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Confirmă fuzionarea pachetului" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Fuzionare" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Numai Dezvoltatorii și Trusted Users pot fuziona pachete." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Închide cererea" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prim" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedent" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Înainte" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultim" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Cereri" +#: html/register.php template/header.php msgid "Register" msgstr "Înregistrare" +#: html/register.php msgid "Use this form to create an account." msgstr "Folosește acest formular pentru a crea un cont." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Trusted User" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nu am putut prelua detaliile propunerii." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Votarea este închisă pentru această propunere." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Doar Trusted Users au permisiunea să voteze." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nu poți vota într-o propunere despre tine." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ai votat deja pentru această propunere." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID-ul votului nu este valid." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Voturi curente" +#: html/tu.php msgid "Past Votes" msgstr "Voturi precedente" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Votanți" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Înregistrarea de conturi noi a fost dezactivată pentru adresa ta IP, " -"probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru " -"inconveniență." +msgstr "Înregistrarea de conturi noi a fost dezactivată pentru adresa ta IP, probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "ID-ul utilizatorului lipsește" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Numele de utilizator nu este valid." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Trebuie să fie între %s și %s caractere lungime" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Începe și sfârșește cu o literă sau un număr." +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Poate conține doar o virgulă, linie joasă sau cratimă." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adresa de email nu este validă." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Amprenta cheii PGP este nevalidă." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Permisiunile contului nu pot fi ridicate." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Limba nu este încă suportată." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Numele de utilizator %s%s%s este deja folosit." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s este deja folosită." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Eroare la încercarea de a crea contul, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Contul %s%s%s a fost creat cu succes." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "O cheie de resetare a parolei a fost trimisă la adresa ta de e-mail." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Clic pe legătura către Autentificare pentru a-ți folosi contul." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nu a fost efectuată nicio modificare asupra contului, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Contul %s%s%s a fost modificat cu succes." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Formularul de autentificare a fost dezactivat pentru adresa ta IP, probabil " -"datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +msgstr "Formularul de autentificare a fost dezactivat pentru adresa ta IP, probabil datorită unor atacuri spam repetate. Ne cerem scuze pentru inconveniență." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Cont suspendat" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Parola ta a fost resetată. Dacă tocmai ai creat un cont nou, folosește " -"legătura din e-mailul de confirmare pentru a seta o parolă inițială. Altfel, " -"cere o resetare a parolei din pagina %sResetare parolă%s." +msgstr "Parola ta a fost resetată. Dacă tocmai ai creat un cont nou, folosește legătura din e-mailul de confirmare pentru a seta o parolă inițială. Altfel, cere o resetare a parolei din pagina %sResetare parolă%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nume de utilizator sau parolă greșite." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "A apărut o eroare în timp ce se genera sesiunea de utilizator." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Combinație e-mail și cheie pentru resetare nevalidă." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nimic" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Vezi informații despre contul lui %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Comentariul a fost adăugat." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Trebuie să fi autentificat înainte de a putea modifica informațiile " -"pachetului." +msgstr "Trebuie să fi autentificat înainte de a putea modifica informațiile pachetului." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "ID-ul comentariului lipsește" +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Eroare la preluarea detaliilor pachetului." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Detaliile pachetului nu pot fi găsite." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Trebuie să fi autentificat înainte de a putea marca pachetele." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nu ai selectat niciun pachet pentru a fi marcat" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Pachetele selectate au fost marcate ca fiind Neactualizate." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." -msgstr "" -"Trebuie să fi autentificat înainte de a putea elimina marcajul de " -"Neactualizat al pachetelor." +msgstr "Trebuie să fi autentificat înainte de a putea elimina marcajul de Neactualizat al pachetelor." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nu ai selectat niciun pachet pentru a-i fi eliminat marcajul." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "La pachetele selectate a fost eliminat marcajul de Neactualizat." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nu ai permisiune pentru a șterge pachete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nu ai selectat niciun pachet pentru a fi șters." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Pachetele selectate au fost șterse." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Trebuie să fi autentificat înainte de a putea adopta pachete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Trebuie să te autentifici înainte de a abandona pachete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nu ai selectat niciun pachet pentru a-l adopta." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Nu ai selectat niciun pachet pentru a-l abandona." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Pachetele selectate au fost adoptate." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Pachetele selectate au fost abandonate." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Trebuie să fi autentificat înainte de a putea vota pentru pachete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." -msgstr "" -"Trebuie să fi autentificat înainte de a putea șterge voturile pachetelor." +msgstr "Trebuie să fi autentificat înainte de a putea șterge voturile pachetelor." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nu ai selectat niciun pachet pentru a vota." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Voturile tale au fost șterse de la pachetele selectate." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Voturile au fost exprimate pentru pachetele selectate." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Nu am putut adăuga la lista de notificări." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Ai fost adăugat în lista de notificare a comentariilor pentru %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "" -"Ai fost șters din lista de notificare pentru comentarii pentru pachetul %s." +msgstr "Ai fost șters din lista de notificare pentru comentarii pentru pachetul %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nu ai voie să ștergi acest comentariu." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Comentariul a fost șters." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Vezi detaliile pachetelor pentru" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Trebuie să fi autentificat pentru a înregistra cereri pentru pachet." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Numele nu este valid: doar litere mici sunt permise." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Câmpul pentru comentariu nu trebuie lăsat necompletat." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Tip de cerere nevalidă." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Cererea a fost adăugată cu succes." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Motiv nevalid." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Doar TU și dezvoltatorii pot închide cererile." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Cerere închisă cu succes." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Poți folosi acest formular pentru a șterge permanent contul AUR %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sWARNING%s: Acestă acțiune nu poate fi anulată." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Confirmă ștergerea" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Nume utilizator" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip cont" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Utilizator" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Dezvoltator" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Utilizator de încredere (TU) & Dezvoltator" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresă email" +#: template/account_details.php msgid "hidden" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Nume real" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Pseudonim IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Amprentă cheie PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Stare" +#: template/account_details.php msgid "Inactive since" msgstr "Inactiv din" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Activ" +#: template/account_details.php msgid "Registration date:" msgstr "" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "necunoscut" +#: template/account_details.php msgid "Last Login" msgstr "Ultima autentificare" +#: template/account_details.php msgid "Never" msgstr "Niciodată" +#: template/account_details.php msgid "View this user's packages" msgstr "Vezi pachetele acestui utilizator" +#: template/account_details.php msgid "Edit this user's account" msgstr "Modifică contul acestui utilizator" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Clic %saici%s dacă dorești să ștergi definitiv acest cont." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php msgid "required" msgstr "cerut" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Utilizator obișnuit" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Trusted user" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Cont suspendat" +#: template/account_edit_form.php msgid "Inactive" msgstr "Inactiv" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Rescrie parola" +#: template/account_edit_form.php msgid "Language" msgstr "Limbă" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "" +#: template/account_edit_form.php msgid "Notification settings" msgstr "" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Notifică pentru comentarii noi" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Actualizare" +#: template/account_edit_form.php msgid "Create" msgstr "Creează" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetează" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nici un rezultat nu s-a încadrat în criteriile de căutare." +#: template/account_search_results.php msgid "Edit Account" msgstr "Modificare cont" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendat" +#: template/account_search_results.php msgid "Edit" msgstr "Modifică" +#: template/account_search_results.php msgid "Less" msgstr "Mai puțin" +#: template/account_search_results.php msgid "More" msgstr "Mai mult" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nu mai sunt rezultate de afișat." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "" +#: template/comaintainers_form.php msgid "Users" msgstr "" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "" +#: template/flag_comment.php msgid "Return to Details" msgstr "" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "Contul meu" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Operațiuni" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Examinează PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Caută în wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Marchează pachetul ca Neactualizat" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Elimină marcaj pachet" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Elimină vot" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Votează acest pachet" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Dezactivează notificări" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1127,184 +1442,238 @@ msgstr[0] "%d cerere în așteptare" msgstr[1] "%d cereri în așteptare" msgstr[2] "%d de cereri în așteptare" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptă pachet" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detalii pachet de bază" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Cuvinte cheie" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Autor" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Responsabil" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Ultimul autor de pachet" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Voturi" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prima trimitere" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Ultima actualizare" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Adaugă comentariu" +#: template/pkg_comments.php msgid "View all comments" msgstr "Vizualizează toate comentariile" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Ultimele comentarii" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Șterge comentariu" +#: template/pkg_comments.php msgid "Pin comment" msgstr "" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Toate comentariile" +#: template/pkg_details.php msgid "Package Details" msgstr "Detalii pachet" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Pachet de bază" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Descriere" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL upstream" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Vizitează pagina web pentru" +#: template/pkg_details.php msgid "Licenses" msgstr "Licențe" +#: template/pkg_details.php msgid "Groups" msgstr "Grupuri" +#: template/pkg_details.php msgid "Conflicts" msgstr "Conflicte" +#: template/pkg_details.php msgid "Provides" msgstr "Furnizează" +#: template/pkg_details.php msgid "Replaces" msgstr "Înlocuiește" +#: template/pkg_details.php msgid "Dependencies" msgstr "Dependențe" +#: template/pkg_details.php msgid "Required by" msgstr "Cerut de" +#: template/pkg_details.php msgid "Sources" msgstr "Surse" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Folosește acest formular pentru a închide cererea pentru pachetul de bază %s" -"%s%s." +msgstr "Folosește acest formular pentru a închide cererea pentru pachetul de bază %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Câmpul pentru comentarii poate fi lăsat necompletat. Este totuși foarte " -"recomandat să adaugi un comentariu când respingi o cerere." +msgstr "Câmpul pentru comentarii poate fi lăsat necompletat. Este totuși foarte recomandat să adaugi un comentariu când respingi o cerere." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Motiv" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Acceptat" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Respins" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Folosește acest formular pentru a înregistra o cerere pentru pachetul de " -"bază %s%s%s care cuprinde următoarele pachete:" +msgstr "Folosește acest formular pentru a înregistra o cerere pentru pachetul de bază %s%s%s care cuprinde următoarele pachete:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tipul de cerere" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Ștergere" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Orfan" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Fuzionează" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " @@ -1312,6 +1681,7 @@ msgid "" "update the Git history of the target package yourself." msgstr "" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1319,9 +1689,11 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1329,19 +1701,24 @@ msgstr[0] "%d cerere pentru pachet găsită" msgstr[1] "%d cereri pentru pachet găsite" msgstr[2] "%d de cereri pentru pachet găsite" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Pagina %d din %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Pachet" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Depusă de" +#: template/pkgreq_results.php msgid "Date" msgstr "Data" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" @@ -1349,6 +1726,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1356,96 +1734,128 @@ msgstr[0] "~%d oră rămasă" msgstr[1] "~%d ore rămase" msgstr[2] "~%d de ore rămase" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 oră a rămas" +#: template/pkgreq_results.php msgid "Accept" msgstr "Acceptă" +#: template/pkgreq_results.php msgid "Locked" msgstr "Blocat" +#: template/pkgreq_results.php msgid "Close" msgstr "Închide" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Închis" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Nume, Descriere" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Doar nume" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Nume exact" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Pachet de bază exact" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Toate" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Marcate" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Nemarcate" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Nume" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Votat" +#: template/pkg_search_form.php msgid "Last modified" msgstr "" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Crescător" +#: template/pkg_search_form.php msgid "Descending" msgstr "Descrescător" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Introdu criteriul de căutare" +#: template/pkg_search_form.php msgid "Search by" msgstr "Caută după" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Neactualizate" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sortează după" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Ordinea sortării" +#: template/pkg_search_form.php msgid "Per page" msgstr "Per pagină" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Înainte" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Orfane" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Eroare la preluarea listei de pachete." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Niciun pachet nu s-a potrivit criteriului de căutare." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1453,117 +1863,278 @@ msgstr[0] "%d pachet găsit" msgstr[1] "%d pachete găsite" msgstr[2] "%d de pachete găsite" +#: template/pkg_search_results.php msgid "Version" msgstr "Versiune" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Da" +#: template/pkg_search_results.php msgid "orphan" msgstr "orfan" +#: template/pkg_search_results.php msgid "Actions" msgstr "Acțiuni" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Elimină marcajul de Neactualizat" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptă pachete" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Abandonează pachete" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Șterge pachete" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Confirmare" +#: template/search_accounts_form.php msgid "Any type" msgstr "Orice tip" +#: template/search_accounts_form.php msgid "Search" msgstr "Caută" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistici" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Pachete orfane" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Pachete adăugate în ultimele 7 zile" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Pachete actualizate în ultimele 7 zile" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Pachete actualizate în ultimul an" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Pachete niciodată actualizate" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Utilizatori înregistrați" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Trusted users" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Actualizări recente" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Statisticile mele" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaliile propunerii." +#: template/tu_details.php msgid "This vote is still running." msgstr "Această votare este încă în desfășurare." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Trimis: %s de %s " +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Sfârșit" +#: template/tu_details.php msgid "Result" msgstr "Rezultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nu" +#: template/tu_details.php msgid "Abstain" msgstr "Abținere" +#: template/tu_details.php msgid "Total" msgstr "Total" +#: template/tu_details.php msgid "Participation" msgstr "Participare" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Ultimele voturi de la un TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Ultimul vot" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Niciun rezultat găsit" +#: template/tu_list.php msgid "Start" msgstr "Start" +#: template/tu_list.php msgid "Back" msgstr "Înapoi" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/ru.po b/po/ru.po index da152833..abe4a5c9 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Evgeniy Alekseev , 2014-2015 # Evgeniy Alekseev , 2014-2015, 2016 @@ -11,1161 +11,1437 @@ # Lukas Fleischer , 2011 # Rustam Tsurik , 2013 # Sergey Shepelev , 2014,2016 -# Александр Яворский , 2017 +# Alex , 2017 # Аскольд , 2016 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Russian (http://www.transifex.com/lfleischer/aur/language/" -"ru/)\n" -"Language: ru\n" +"Language-Team: Russian (http://www.transifex.com/lfleischer/aurweb/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" -"%100>=11 && n%100<=14)? 2 : 3);\n" +"Language: ru\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" +#: html/404.php msgid "Page Not Found" msgstr "Страница не найдена" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Извините, запрошенная страница не существует." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Примечание" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Клонирование репозитория Git не подразумевает открытие в браузере." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Для клонирования репозитория Git «%s» выполните «%s»." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" -"Нажмите %sздесь%s, для возврата на страницу с подробной информацией о «%s»." +msgstr "Нажмите %sздесь%s, для возврата на страницу с подробной информацией о «%s»." +#: html/503.php msgid "Service Unavailable" msgstr "Сервис недоступен" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "Не паниковать! Сайт недоступен из-за работ. Скоро мы вернемся назад." +#: html/account.php msgid "Account" msgstr "Аккаунт" +#: html/account.php template/header.php msgid "Accounts" msgstr "Учетные записи" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "У вас нет доступа сюда." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Не удалось получить информацию об указанном пользователе." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Вы не имеете права редактировать эту учетную запись." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Используйте эту форму для поиска существующих учетных записей." +#: html/account.php msgid "You must log in to view user information." -msgstr "" -"Вы должны представиться для того, чтобы посмотреть информацию о пользователе." +msgstr "Вы должны представиться для того, чтобы посмотреть информацию о пользователе." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Добавить предложение" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Неверная метка для действия пользователя." +#: html/addvote.php msgid "Username does not exist." msgstr "Имя пользователя не существует." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "За %s уже идет голосование." +#: html/addvote.php msgid "Invalid type." msgstr "Неправильный тип" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Предложение не может быть пустым." +#: html/addvote.php msgid "New proposal submitted." msgstr "Новое предложение принято." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Отправить предложение." +#: html/addvote.php msgid "Applicant/TU" msgstr "Кандидат/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(пусто если не нужно)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Тип" +#: html/addvote.php msgid "Addition of a TU" msgstr "Добавление TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Удаление TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Удаление TU (неактивность без уведомлений)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Внесение изменений в Устав" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Предложение" +#: html/addvote.php msgid "Submit" msgstr "Прислать" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Управление сопровождающими" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Редактировать комментарий" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Панель настроек" +#: html/home.php template/header.php msgid "Home" msgstr "Главная" +#: html/home.php msgid "My Flagged Packages" msgstr "Мои отмеченные пакеты" +#: html/home.php msgid "My Requests" msgstr "Мои заявки" +#: html/home.php msgid "My Packages" msgstr "Мои пакеты" +#: html/home.php msgid "Search for packages I maintain" msgstr "Искать пакеты, которые я сопровождаю" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Пакеты, в сопровождении которых я участвую" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Поиск пакетов, в которых я сопровождающий" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Добро пожаловать в AUR! Пожалуйста, ознакомьтесь с %sРуководством " -"пользователя AUR%s и с %sРуководством доверенного пользователя AUR%s, чтобы " -"узнать больше." +msgstr "Добро пожаловать в AUR! Пожалуйста, ознакомьтесь с %sРуководством пользователя AUR%s и с %sРуководством доверенного пользователя AUR%s, чтобы узнать больше." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Присланные пэкиджбилды (англ. PKGBUILD) %sдолжны%s соответствовать " -"%sстандартам создания пакетов для Арча%s, иначе они будут удалены!" +msgstr "Присланные пэкиджбилды (англ. PKGBUILD) %sдолжны%s соответствовать %sстандартам создания пакетов для Арча%s, иначе они будут удалены!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Не забывайте голосовать за понравившиеся вам пакеты!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"В хранилище [community] некоторые пакеты могут быть представлены в бинарном " -"виде." +msgstr "В хранилище [community] некоторые пакеты могут быть представлены в бинарном виде." +#: html/home.php msgid "DISCLAIMER" msgstr "Отказ от ответственности" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Пакеты в AUR содержат предоставленный пользователями контент. Любое " -"использование предоставляемых файлов выполняйте на свой риск." +msgstr "Пакеты в AUR содержат предоставленный пользователями контент. Любое использование предоставляемых файлов выполняйте на свой риск." +#: html/home.php msgid "Learn more..." msgstr "Больше..." +#: html/home.php msgid "Support" msgstr "Поддержка" +#: html/home.php msgid "Package Requests" msgstr "Запросы по пакету" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Три типа запросов могут быть посланы с использованием %sДействия над пакетом" -"%s на странице пакета:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Три типа запросов могут быть посланы с использованием %sДействия над пакетом%s на странице пакета:" +#: html/home.php msgid "Orphan Request" msgstr "Запрос на сброс сопровождающего" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Запросить, чтобы пакет быть лишен сопровождающего, например, если текущий " -"сопровождающий неактивен и пакет давно помечен, как устаревший." +msgstr "Запросить, чтобы пакет быть лишен сопровождающего, например, если текущий сопровождающий неактивен и пакет давно помечен, как устаревший." +#: html/home.php msgid "Deletion Request" msgstr "Запрос на удаление" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Запросить удаление пакета из AUR. Пожалуйста, не используйте это действие, " -"если пакет не собирается и это может быть легко исправлено. Вместо этого, " -"свяжитесь с сопровождающим и отправьте запрос на смену сопровождающего, если " -"необходимо." +msgstr "Запросить удаление пакета из AUR. Пожалуйста, не используйте это действие, если пакет не собирается и это может быть легко исправлено. Вместо этого, свяжитесь с сопровождающим и отправьте запрос на смену сопровождающего, если необходимо." +#: html/home.php msgid "Merge Request" msgstr "Запрос объединения" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Запросить объединение пакета с другим. Может быть использовано, когда пакет " -"необходимо переименовать или заменить другим." +msgstr "Запросить объединение пакета с другим. Может быть использовано, когда пакет необходимо переименовать или заменить другим." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Если вы хотите обсудить запрос, вы можете использовать список рассылки %saur-" -"requests%s. Однако, пожалуйста, не используйте список рассылки для отправки " -"запросов." +msgstr "Если вы хотите обсудить запрос, вы можете использовать список рассылки %saur-requests%s. Однако, пожалуйста, не используйте список рассылки для отправки запросов." +#: html/home.php msgid "Submitting Packages" msgstr "Загрузка пакетов" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"На текущий момент для загрузки пакетов в AUR используется Git через SSH. " -"Смотри %sЗагрузка пакетов%s в ArchWiki для более подробной информации." +msgstr "На текущий момент для загрузки пакетов в AUR используется Git через SSH. Смотри %sЗагрузка пакетов%s в ArchWiki для более подробной информации." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Следующие отпечатки ключей используются AUR:" +#: html/home.php msgid "Discussion" msgstr "Обсуждение" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Общее обсуждение Пользовательского Репозитория ArchLinux (AUR) и структуры " -"Доверенных Пользователей ведется в %saur-general%s. Для обсуждение " -"разработки веб-интерфейса AUR используйте %saur-dev%s." +msgstr "Общее обсуждение Пользовательского Репозитория ArchLinux (AUR) и структуры Доверенных Пользователей ведется в %saur-general%s. Для обсуждение разработки веб-интерфейса AUR используйте %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Отчет об ошибке" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Если вы нашли баг в интерфейсе AUR, пожалуйста, отправьте сообщение на %sбаг " -"трекер%s. Используйте данный баг трекер %sтолько%s для сообщениях о багах в " -"AUR. Если вы хотите сообщить о баге в пакете, свяжитесь с сопровождающим, " -"или оставьте комментарий на соответствующей странице." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Если вы нашли баг в интерфейсе AUR, пожалуйста, отправьте сообщение на %sбаг трекер%s. Используйте данный баг трекер %sтолько%s для сообщениях о багах в AUR. Если вы хотите сообщить о баге в пакете, свяжитесь с сопровождающим, или оставьте комментарий на соответствующей странице." +#: html/home.php msgid "Package Search" msgstr "Поиск пакетов" +#: html/index.php msgid "Adopt" msgstr "Усыновить" +#: html/index.php msgid "Vote" msgstr "Голосовать" +#: html/index.php msgid "UnVote" msgstr "Убрать голос" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Извещать" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Не извещать" +#: html/index.php msgid "UnFlag" msgstr "Снять метку" +#: html/login.php template/header.php msgid "Login" msgstr "Войти" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Вы вошли как: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Выход" +#: html/login.php msgid "Enter login credentials" msgstr "Введите учётные данные" +#: html/login.php msgid "User name or email address" msgstr "Имя пользователя или email" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Пароль" +#: html/login.php msgid "Remember me" msgstr "Запомнить меня" +#: html/login.php msgid "Forgot Password" msgstr "Забыли пароль?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Вход через HTTP отключен. Пожалуйста, %sпереключитесь на HTTPs%s, чтобы " -"войти." +msgstr "Вход через HTTP отключен. Пожалуйста, %sпереключитесь на HTTPs%s, чтобы войти." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Критерии поиска" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Пакеты" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Ошибка получения информации о пакете." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Отсутствует обязательное значение." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Пароли не совпадают." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Пароль должен быть не менее %s символов." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Неверная электронная почта." +#: html/passreset.php msgid "Password Reset" msgstr "Сброс пароля" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Проверьте свою электронную почту на наличие ссылки подтверждения." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Ваш пароль успешно сброшен." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Подтвердите адрес своей электронной почты:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Введите ваш новый пароль:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Подтвердите ваш новый пароль:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Продолжить" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Если вы забыли электронный адрес, который вы использовали для регистрации, " -"пожалуйста, отошлите сообщение в список рассылки %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Если вы забыли электронный адрес, который вы использовали для регистрации, пожалуйста, отошлите сообщение в список рассылки %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Введите свой адрес электронной почты:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Группы пакетов" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Выбранные пакеты будут брошены." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Не могу найти пакет для объединения голосов и комментариев." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Невозможно объединить группу пакетов с самой собой." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Выбранные пакеты не были удалены. Поставьте галочку для подтверждения." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Удаление пакета" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Удалить пакет" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "Используйте эту форму, чтобы удалить группу пакетов %s%s%s из AUR:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Удаление пакета необратимо." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Активируйте чекбокс для подтверждения действия." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Подтвердите удаление пакета" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Удалить" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Только Доверенные Пользователи и Разработчики могут удалять пакеты." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Бросить пакет" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Используйте данную форму, чтобы бросить группу пакетов %s%s%s, которая " -"включает в себя следующие пакеты:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Используйте данную форму, чтобы бросить группу пакетов %s%s%s, которая включает в себя следующие пакеты:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Ставя галочку, вы подтверждаете, что хотите бросить пакеты и сделать " -"сопровождающим %s%s%s." +msgstr "Ставя галочку, вы подтверждаете, что хотите бросить пакеты и сделать сопровождающим %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Ставя галочку, вы подтверждаете, что хотите бросить пакет." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Подтвердите отказ от пакета" +#: html/pkgdisown.php msgid "Disown" msgstr "Бросить" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Только Доверенные Пользователи или разработчики могут бросить пакеты." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Отметить комментарий" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Отметить пакет устаревшим" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Используйте данную форму, чтобы отметить устаревшими группу пакетов %s%s%s, " -"которая включает в себя следующие пакеты:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Используйте данную форму, чтобы отметить устаревшими группу пакетов %s%s%s, которая включает в себя следующие пакеты:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Пожалуйста %sне%s используйте данную форму для сообщения об ошибке. " -"Используйте для этого комментарии." +msgstr "Пожалуйста %sне%s используйте данную форму для сообщения об ошибке. Используйте для этого комментарии." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Введите описание, почему данные пакет устарел; добавление ссылок на новость " -"о релизе или архив с новой версией предпочтительно." +msgstr "Введите описание, почему данные пакет устарел; добавление ссылок на новость о релизе или архив с новой версией предпочтительно." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Комментарии" +#: html/pkgflag.php msgid "Flag" msgstr "Пометить" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"Только зарегистрированные пользователи могут отметить пакет устаревшим." +msgstr "Только зарегистрированные пользователи могут отметить пакет устаревшим." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Объединение пакетов" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Объединить пакеты" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Используйте эту форму, чтобы объединить группу пакетов %s%s%s с другим " -"пакетом." +msgstr "Используйте эту форму, чтобы объединить группу пакетов %s%s%s с другим пакетом." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Следующие пакеты будут удалены:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Объединение пакетов — необратимое действие." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Введите имя пакета, с которым вы хотите объединить этот пакет." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Объединить с:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Подтвердить объединение пакетов" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Объединить" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Только Доверенные Пользователи и Разработчики могут объединять пакеты." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Отправить запрос" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Закрыть запрос" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Первый" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Назад" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далее" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Последний" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Запросы" +#: html/register.php template/header.php msgid "Register" msgstr "Регистрация" +#: html/register.php msgid "Use this form to create an account." msgstr "Используйте эту форму для создания учетной записи." +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "Условия обслуживания" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "Этот документ был обновлён, ознакомьтесь с ним внимательно:" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "редакция %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "Я принимаю приведённые выше положения и условия." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Доверенный пользователь" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Не получилось показать предложение." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Голосование закрыто." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Только Доверенные Пользователи имеют право голоса." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Нельзя голосовать за себя." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Вы уже проголосовали." +#: html/tu.php msgid "Vote ID not valid." msgstr "Идентификатор голосование неверный." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Сейчас голосов" +#: html/tu.php msgid "Past Votes" msgstr "Прошлые голоса" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Голосовавшие" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Регистрация аккаунтов с вашего IP адреса запрещена, возможная причина " -"проблемы — спам-атаки. Извините за неудобства." +msgstr "Регистрация аккаунтов с вашего IP адреса запрещена, возможная причина проблемы — спам-атаки. Извините за неудобства." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Отсутствует идентификатор пользователя" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Неверное имя пользователя." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Длина должна быть от %s до %s символов" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Начинаются и заканчиваются цифрой или буквой" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Может содержать только одну точку, подчёркивание или тире." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Неправильный адрес электронной почты." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "Неверная домашняя страница, укажите полный адрес с указанием протокола HTTP(s)." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Неверный отпечаток ключа PGP." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Публичный SSH ключ неправильный." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Невозможно повысить привилегии." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Язык пока не поддерживается." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Часовые пояса пока не поддерживаются." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Имя %s%s%s уже занято." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Адрес %s%s%s уже используется." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Публичный SSH ключ %s%s%s уже используется." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Ошибка при создании аккаунта %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Учетная запись %s%s%s была успешно создана." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ключ для смены пароля был отправлен на ваш электронный адрес." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Нажмите на ссылку Войти выше." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "С аккаунтом %s%s%s не произведено никаких действий." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Учетная запись %s%s%s успешно изменена." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Доступ к форме входа с вашего IP адреса запрещен, возможная причина проблемы " -"— спам-атаки. Извините за неудобства." +msgstr "Доступ к форме входа с вашего IP адреса запрещен, возможная причина проблемы — спам-атаки. Извините за неудобства." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Действие аккаунта приостановлено." +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Ваш пароль был сброшен. Если вы только что создали аккаунт, пожалуйста " -"используйте ссылку из письма подтверждения чтобы установить начальный " -"пароль. В противном случае, запросите ключ для сброса на странице %sСброс " -"пароля%s." +msgstr "Ваш пароль был сброшен. Если вы только что создали аккаунт, пожалуйста используйте ссылку из письма подтверждения чтобы установить начальный пароль. В противном случае, запросите ключ для сброса на странице %sСброс пароля%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Неверно указаны имя пользователя или пароль." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Произошла ошибка при создании пользовательской сессии." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Неверная электронная почта и комбинация сброса ключа." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Нет" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Просмотр информации об аккаунте %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "ID или имя группы пакетов отсутствует." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Вы не можете редактировать данный комментарий." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Комментарий не существует." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Комментарий не может быть пустым." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Комментарий добавлен." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Вы должны представиться прежде чем редактировать информацию о пакете." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Идентификатор комментария отсутствует." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Не более 5 комментариев могут быть прикреплены." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Вы не можете прикрепить данный комментарий." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Вы не можете открепить данный комментарий." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Комментарий был прикреплен." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Комментарий был откреплен." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Ошибка получения информации о пакете." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Не найдена информация о пакете." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Вы должны войти чтобы ставить флажки на пакеты." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Вы не выбрали ни одного пакета для пометки." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "Выбранные пакеты не были отмечены, пожалуйста, введите комментарий." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Выбранные пакеты помечены как устаревшие." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Вы должны войти чтобы снимать флажки." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Вы не выбрали ни одного пакета для снятия пометки." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "С выбранных пакетов пометка снята." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "У вас нет права на удаление пакетов." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Вы не выбрали ни одного пакета для удаления." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Выбранные пакеты удалены." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Вы должны войти чтобы усыновлять пакеты." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Вы должны войти чтобы бросать пакеты." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Вы не выбрали ни одного пакета для усыновления." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Вы не выбрали ни одного пакета чтобы бросить." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Выбранные пакеты усыновлены." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Выбранные пакеты брошены." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Вы должны войти чтобы голосовать." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Вы должны войти чтобы снимать голос с пакета." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Вы не выбрали ни одного пакета для голосования." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Ваш голос убран с выбранного пакета." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Вы проголосовали за выбранные пакеты." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Невозможно добавить в список получателей извещений." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Вы добавлены в список извещений для %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Вам больше не будут приходить извещения от %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Вы не можете отменить удаление данного комментария." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Комментарий был восстановлен." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "У вас нет прав для удаления этого комментария." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Комментарий удален." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Комментарий был отредактирован." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Вы не можете редактировать ключевые слова данной группы пакетов." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ключевые слова были обновлены." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Вы не можете управлять сопровождающими данной группы пакетов." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Неправильное имя пользователя: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Сопровождающие пакета были обновлены." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Просмотреть информацию о пакете" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "требует %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Вы должны войти, чтобы отправить запрос по пакету." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Неверное имя: допустим только нижний регистр." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Поле комментариев должно быть заполнено." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Неправильный тип запроса." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Запрос добавлен успешно." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Неправильная причина." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." -msgstr "" -"Только Доверенные пользователи или разработчики могут закрывать запросы." +msgstr "Только Доверенные пользователи или разработчики могут закрывать запросы." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Запрос закрыт успешно." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "" -"Вы можете использовать данную форму, чтобы удалить следующий аккаунт AUR: %s." +msgstr "Вы можете использовать данную форму, чтобы удалить следующий аккаунт AUR: %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sПРЕДУПРЕЖДЕНИЕ%s: Данное действие не может быть отменено." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Подтвердите удаление" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Имя пользователя" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Тип учетной записи" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Пользователь" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Разработчик" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Доверенные пользователи и Разработчики" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Адрес электронной почты" +#: template/account_details.php msgid "hidden" msgstr "скрыто" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Настоящее имя" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Домашняя страница" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Ник" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Отпечаток ключа PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Статус" +#: template/account_details.php msgid "Inactive since" msgstr "Неактивен с" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Активный" +#: template/account_details.php msgid "Registration date:" msgstr "Дата регистрации:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "неизвестно" +#: template/account_details.php msgid "Last Login" msgstr "Последний вход" +#: template/account_details.php msgid "Never" msgstr "Никогда" +#: template/account_details.php msgid "View this user's packages" msgstr "Посмотреть пакеты этого пользователя" +#: template/account_details.php msgid "Edit this user's account" msgstr "Отредактировать этот аккаунт" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Нажмите %sздесь%s, если Вы хотите удалить данный аккаунт насовсем." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Нажмите %sздесь%s, чтобы просмотреть данные о пользователе." +#: template/account_edit_form.php msgid "required" msgstr "необходимо" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" +msgstr "Имя пользователя имя, которое будет использоваться для входа. Это имя видимо всех, даже когда учётная запись не активна." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Обычный пользователь" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Доверенный пользователь" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Действие учетной записи приостановлено" +#: template/account_edit_form.php msgid "Inactive" msgstr "Неактивен" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Пожалуйста убедитесь, что Вы корректно ввели Ваш email; в противном случае " -"вы будете заблокированы." +msgstr "Пожалуйста убедитесь, что Вы корректно ввели Ваш email; в противном случае вы будете заблокированы." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Скрыть email." +#: template/account_edit_form.php msgid "Re-type password" msgstr "Введите пароль еще раз" +#: template/account_edit_form.php msgid "Language" msgstr "Язык" +#: template/account_edit_form.php msgid "Timezone" msgstr "Часовой пояс" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Следующая информация необходима, только если вы хотите загружать пакеты в " -"AUR." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Следующая информация необходима, только если вы хотите загружать пакеты в AUR." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Публичный SSH ключ" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Настройки уведомлений" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Уведомлять о новых комментариях" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Уведомлять об обновлении пакета" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Уведомлять об измененях собственности" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Обновить" +#: template/account_edit_form.php msgid "Create" msgstr "Создать" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Очистить" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "По вашему запросу ничего не найдено." +#: template/account_search_results.php msgid "Edit Account" msgstr "Изменить учетную запись" +#: template/account_search_results.php msgid "Suspended" msgstr "Приостановлена" +#: template/account_search_results.php msgid "Edit" msgstr "Редактировать" +#: template/account_search_results.php msgid "Less" msgstr "Меньше" +#: template/account_search_results.php msgid "More" msgstr "Больше" +#: template/account_search_results.php msgid "No more results to display." msgstr "Больше нет результатов." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Используйте данную форму, чтобы добавить сопровождающих для %s%s%s (одно имя " -"на строку):" +msgstr "Используйте данную форму, чтобы добавить сопровождающих для %s%s%s (одно имя на строку):" +#: template/comaintainers_form.php msgid "Users" msgstr "Пользователи" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Сохранить" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Комментарий: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "%s%s%s отметил %s%s%s устаревшим %s%s%s по следующей причине:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s не отмечен устаревшим." +#: template/flag_comment.php msgid "Return to Details" msgstr "Вернуться к деталям" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." +#: template/header.php msgid " My Account" msgstr "Моя учётная запись" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Действия над пакетом" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Просмотреть PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Посмотреть изменения" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Загрузить снимок" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Искать в Wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Отмечен устаревшим (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Пометить пакет как устаревший" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Снять пометку" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Удалить голос" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Проголосовать за пакет" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Выключить уведомления" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Включить уведомления" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Управление сопровождающими" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1174,210 +1450,258 @@ msgstr[1] "%d запроса в обработке" msgstr[2] "%d запросов в обработке" msgstr[3] "%d запросов в обработке" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Усыновить пакет" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Информация по группе пакетов" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL для git clone" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "только чтение" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Ключевые слова" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Автор" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Ответственный" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Последний приславший" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Голосов" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Популярность" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Впервые послан" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Последнее обновление" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Редактировать комментарий для: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Добавить комментарий" +#: template/pkg_comments.php msgid "View all comments" msgstr "Посмотреть все комментарии" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Закрепленные комментарии" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Последние комментарии" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s прокомментировал %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Анонимный комментарий для %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "удалён %s %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "удалён %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "отредактирован %s %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "отредактирован %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Восстановить комментарий" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Удалить комментарий" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Закрепить комментарий" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Открепить комментарий" +#: template/pkg_comments.php msgid "All comments" msgstr "Все комментарии" +#: template/pkg_details.php msgid "Package Details" msgstr "Информация о пакете" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Группа пакетов" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Описание" +#: template/pkg_details.php msgid "Upstream URL" msgstr "URL апстрима" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Посетить сайт" +#: template/pkg_details.php msgid "Licenses" msgstr "Лицензия" +#: template/pkg_details.php msgid "Groups" msgstr "Группы" +#: template/pkg_details.php msgid "Conflicts" msgstr "Конфликтует" +#: template/pkg_details.php msgid "Provides" msgstr "Предоставляет" +#: template/pkg_details.php msgid "Replaces" msgstr "Заменяет" +#: template/pkg_details.php msgid "Dependencies" msgstr "Зависимости" +#: template/pkg_details.php msgid "Required by" msgstr "Требуется пакетами" +#: template/pkg_details.php msgid "Sources" msgstr "Исходники" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Используйте эту форму, чтобы закрыть запрос о группе пакетов %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"При отклонении запроса рекомендуется заполнить поле комментарий (не " -"обязательно)." +msgstr "При отклонении запроса рекомендуется заполнить поле комментарий (не обязательно)." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Причина" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Принято" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Отклонено" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Используйте данную форму, чтобы послать запрос по поводу группы пакетов %s%s" -"%s, которая включает следующие пакеты:" +msgstr "Используйте данную форму, чтобы послать запрос по поводу группы пакетов %s%s%s, которая включает следующие пакеты:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Тип запроса" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Удаление" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Сделать сиротой" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Объединить с" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Отправляя запрос удаления, Вы просите Доверенного Пользователя удалить " -"основной пакет. Этот тип запроса должен использоваться для дубликатов, " -"заброшенных, а также незаконных и безнадёжно сломанных пакетов." +msgstr "Отправляя запрос удаления, Вы просите Доверенного Пользователя удалить основной пакет. Этот тип запроса должен использоваться для дубликатов, заброшенных, а также незаконных и безнадёжно сломанных пакетов." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Отправляя запрос на слияние, Вы просите Доверенного Пользователя удалить " -"основной пакет, переместить голоса и комментарии к другому основному пакету. " -"Слияние пакета не влияет на соответствующие Git репозитории. Обновите Git " -"историю целевого пакета самостоятельно." +msgstr "Отправляя запрос на слияние, Вы просите Доверенного Пользователя удалить основной пакет, переместить голоса и комментарии к другому основному пакету. Слияние пакета не влияет на соответствующие Git репозитории. Обновите Git историю целевого пакета самостоятельно." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Отправляя сиротский запрос, Вы просите Доверенного Пользователя бросить " -"основной пакет. Пожалуйста, делайте это, только если пакет нуждается в " -"действиях обслуживающего, который недоступен и вы уже пытались связаться с " -"ним ранее." +msgstr "Отправляя сиротский запрос, Вы просите Доверенного Пользователя бросить основной пакет. Пожалуйста, делайте это, только если пакет нуждается в действиях обслуживающего, который недоступен и вы уже пытались связаться с ним ранее." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Нет запросов по выбранному критерию поиска." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1386,19 +1710,24 @@ msgstr[1] "Найдены запросы для %d пакетов." msgstr[2] "Найдены запросы для %d пакетов." msgstr[3] "Найдены запросы для %d пакетов." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Страница %d из %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Пакет" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Послан" +#: template/pkgreq_results.php msgid "Date" msgstr "Дата" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" @@ -1407,6 +1736,7 @@ msgstr[1] "осталось ~%d дня" msgstr[2] "осталось ~%d дней" msgstr[3] "осталось ~%d дней" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1415,96 +1745,128 @@ msgstr[1] "осталось ~%d часа" msgstr[2] "осталось ~%d часов" msgstr[3] "осталось ~%d часов" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "осталось меньше часа" +#: template/pkgreq_results.php msgid "Accept" msgstr "Принять" +#: template/pkgreq_results.php msgid "Locked" msgstr "Заблокировано" +#: template/pkgreq_results.php msgid "Close" msgstr "Закрыть" +#: template/pkgreq_results.php msgid "Pending" msgstr "Ожидает" +#: template/pkgreq_results.php msgid "Closed" msgstr "Закрыт" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Название, описание" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Только название" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Точное имя" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Точное имя группы" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Сопровождающий" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Ответственный, сопровождающий" +#: template/pkg_search_form.php msgid "All" msgstr "Все" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Отмеченные" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Неотмеченные" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Имя" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Мой голос" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Последнее обновление" +#: template/pkg_search_form.php msgid "Ascending" msgstr "По возрастанию" +#: template/pkg_search_form.php msgid "Descending" msgstr "По убыванию" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Введите критерии поиска" +#: template/pkg_search_form.php msgid "Search by" msgstr "Искать по" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Устарел" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Сортировать по" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Порядок сортировки" +#: template/pkg_search_form.php msgid "Per page" msgstr "Постранично" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Поехали" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Сироты" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Ошибка получения списка пакетов." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Нет пакетов по выбранному критерию поиска." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1513,120 +1875,278 @@ msgstr[1] "Найдено %d пакета." msgstr[2] "Найдено %d пакетов." msgstr[3] "Найдено %d пакетов." +#: template/pkg_search_results.php msgid "Version" msgstr "Версия" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Популярность считается, как сумма всех голосов, где каждый голос взвешен с " -"коэффициентом %.2f за каждый день разницы между днём голосования и днём " -"загрузки пакета." +msgstr "Популярность считается, как сумма всех голосов, где каждый голос взвешен с коэффициентом %.2f за каждый день разницы между днём голосования и днём загрузки пакета." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Да" +#: template/pkg_search_results.php msgid "orphan" msgstr "брошеный" +#: template/pkg_search_results.php msgid "Actions" msgstr "Действия" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Убрать флаг Устаревший" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Усыновить пакеты" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Бросить пакеты" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Удалить пакеты" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Подтвердить" +#: template/search_accounts_form.php msgid "Any type" msgstr "Любой тип" +#: template/search_accounts_form.php msgid "Search" msgstr "Поиск" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Статистика" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Брошеные пакеты" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Пакеты, добавленные за прошедшие 7 дней" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Пакеты, обновленные за прошедшие 7 дней" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Пакеты, обновленные за прошедший год" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Пакеты, которые никогда не обновлялись" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Зарегистрированных пользователей" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Доверенных пользователей" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Последние обновления" +#: template/stats/updates_table.php msgid "more" msgstr "больше" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Моя статистика" +#: template/tu_details.php msgid "Proposal Details" msgstr "Подробности предложения" +#: template/tu_details.php msgid "This vote is still running." msgstr "Голосование продолжается." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Получено: %s %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Конец" +#: template/tu_details.php msgid "Result" msgstr "Результат" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Нет" +#: template/tu_details.php msgid "Abstain" msgstr "Воздерживаюсь" +#: template/tu_details.php msgid "Total" msgstr "Всего" +#: template/tu_details.php msgid "Participation" msgstr "Участие" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Последний голос TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Последний голос" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Нет результатов." +#: template/tu_list.php msgid "Start" msgstr "Начало" +#: template/tu_list.php msgid "Back" msgstr "Назад" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/sk.po b/po/sk.po index ccd1edd9..ffbd86c7 100644 --- a/po/sk.po +++ b/po/sk.po @@ -1,1620 +1,2144 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # archetyp , 2013-2016 # Matej Ľach , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Slovak (http://www.transifex.com/lfleischer/aur/language/" -"sk/)\n" -"Language: sk\n" +"Language-Team: Slovak (http://www.transifex.com/lfleischer/aurweb/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"Language: sk\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" +#: html/404.php msgid "Page Not Found" msgstr "Stránka nebola nájdená" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Mrzí nás to, ale stránka, ktorú ste zadali, neexistuje." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Poznámka" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" -"URL adresy na klonovanie Git repozitárov nie sú určené pre otváranie v " -"prehliadači." +msgstr "URL adresy na klonovanie Git repozitárov nie sú určené pre otváranie v prehliadači." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Na klonovanie Git repozitáre pre %s spustite %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Kliknite %ssem%s pre návrat na stránku s detailami o %s." +#: html/503.php msgid "Service Unavailable" msgstr "Služba nie je dostupná" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Zachovajte pokoj. Na stránke momentálne prebieha údržba. Vrátime sa čoskoro." +msgstr "Zachovajte pokoj. Na stránke momentálne prebieha údržba. Vrátime sa čoskoro." +#: html/account.php msgid "Account" msgstr "Účet" +#: html/account.php template/header.php msgid "Accounts" msgstr "Účty" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nemáte potrebné práva pre prístup do tejto oblasti." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Nemožno získať informácie pre špecifikovaného užívateľa. " +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemáte potrebné oprávnenia, pre úpravu tohoto účtu. " +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Použite tento formulár pre vyhľadávanie v existujúcich účtoch." +#: html/account.php msgid "You must log in to view user information." msgstr "Musíte sa prihlásiť, pre zobrazenie užívateľských informácií. " +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Pridať návrh" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Neplatný znak pre užívateľskú akciu." +#: html/addvote.php msgid "Username does not exist." msgstr "Užívateľské meno neexistuje." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "O %s už návrh beží." +#: html/addvote.php msgid "Invalid type." msgstr "Neplatný typ." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Návrch nemôže byť prázdny." +#: html/addvote.php msgid "New proposal submitted." msgstr "Nový návrh bol odoslaný." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Odošli návrh na hlasovanie." +#: html/addvote.php msgid "Applicant/TU" msgstr "Adept/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prázdne ak nemožno uplatniť)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Typ" +#: html/addvote.php msgid "Addition of a TU" msgstr "Pridanie TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Odobranie TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Odobranie TU (neohlásená neaktivita)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Zmena stanov" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Návrh" +#: html/addvote.php msgid "Submit" msgstr "Odoslať" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Manažovať spolupracovníkov" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Editovať komentár" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Domov" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Moje balíčky" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Vitajte v AUR! Prečítajte si prosím %sAUR smernicu pre užívateľov%s a %sAUR " -"smernicu pre TU%s pre ďalšie informácie." +msgstr "Vitajte v AUR! Prečítajte si prosím %sAUR smernicu pre užívateľov%s a %sAUR smernicu pre TU%s pre ďalšie informácie." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Prispené PKGBUILDy sa %smusia%s riadiť %sArch podmienkami pre balíčky%s, " -"inak budú vymazané!" +msgstr "Prispené PKGBUILDy sa %smusia%s riadiť %sArch podmienkami pre balíčky%s, inak budú vymazané!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Nezabudnite hlasovať za svoje obľúbené balíčky!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Niektoré balíčky môžu byť poskytnuté ako binárky v [community]. " +#: html/home.php msgid "DISCLAIMER" msgstr "UPOZORNENIE" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Balíčky v AUR sú výsledkom práce užívateľov. Akékoľvek použitie týchto " -"súborov je na vlastnú zodpovednosť." +msgstr "Balíčky v AUR sú výsledkom práce užívateľov. Akékoľvek použitie týchto súborov je na vlastnú zodpovednosť." +#: html/home.php msgid "Learn more..." msgstr "Dozvedieť sa viac..." +#: html/home.php msgid "Support" msgstr "Podpora" +#: html/home.php msgid "Package Requests" msgstr "Žiadosti ohľadom balíčkov" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"V súčasnosti existujú tri typy žiadostí, ktoré možno vyplniť v časti %sAkcie " -"balíčka%s na stránke s detailami balíčka, a to:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "V súčasnosti existujú tri typy žiadostí, ktoré možno vyplniť v časti %sAkcie balíčka%s na stránke s detailami balíčka, a to:" +#: html/home.php msgid "Orphan Request" msgstr "Žiadosť o osirenie" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Žiadosť o odobratie vlastníctva balíčka, napr. ak správca balíčka nie je " -"aktívny a balíček bol dlhšiu dobu označený ako neaktuálny." +msgstr "Žiadosť o odobratie vlastníctva balíčka, napr. ak správca balíčka nie je aktívny a balíček bol dlhšiu dobu označený ako neaktuálny." +#: html/home.php msgid "Deletion Request" msgstr "Žiadosť o vymazanie" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Žiadosť o odstránenie balíčka z AUR. Nepoužívajte prosím túto možnosť v " -"prípade, že balíček je pokazený a možno ho ľahko opraviť. Namiesto toho " -"radšej kontaktujte jeho správcu alebo v prípade nutnosti požiadajte o jeho " -"osirenie." +msgstr "Žiadosť o odstránenie balíčka z AUR. Nepoužívajte prosím túto možnosť v prípade, že balíček je pokazený a možno ho ľahko opraviť. Namiesto toho radšej kontaktujte jeho správcu alebo v prípade nutnosti požiadajte o jeho osirenie." +#: html/home.php msgid "Merge Request" msgstr "Žiadosť o zlúčenie" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Žiadosť o zlúčenie balíčka do iného. Možno použiť tiež v prípade, že balíček " -"potrebuje byť premenovaný alebo nahradený rozdeleným balíčkom." +msgstr "Žiadosť o zlúčenie balíčka do iného. Možno použiť tiež v prípade, že balíček potrebuje byť premenovaný alebo nahradený rozdeleným balíčkom." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Ak potrebujete prediskutovať nejakú požiadavku, kedykoľvek môžete napísať na " -"mailing list %saur-requests%s. Nepoužívajte však tento mailing list na " -"posielanie požiadaviek." +msgstr "Ak potrebujete prediskutovať nejakú požiadavku, kedykoľvek môžete napísať na mailing list %saur-requests%s. Nepoužívajte však tento mailing list na posielanie požiadaviek." +#: html/home.php msgid "Submitting Packages" msgstr "Podanie balíčkov" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git cez SSH sa teraz používa na podanie balíčkov do AUR. Pre ďalšie " -"informácie pozri tiež sekciu %sPodanie balíčkov%s na AUR stránke v ArchWiki." +msgstr "Git cez SSH sa teraz používa na podanie balíčkov do AUR. Pre ďalšie informácie pozri tiež sekciu %sPodanie balíčkov%s na AUR stránke v ArchWiki." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Uvedené SSH fingerprints sa používajú pre AUR:" +#: html/home.php msgid "Discussion" msgstr "Diskusia" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Všeobecná diskusia týkajúca sa Arch Užívateľského Repozitára (AUR) a " -"štruktúry dôverovaných užívateľov (TU) je na %saur-general%s. Na diskusiu " -"týkajúcu sa vývoja AUR webu použite %saur-dev%s mailing list." +msgstr "Všeobecná diskusia týkajúca sa Arch Užívateľského Repozitára (AUR) a štruktúry dôverovaných užívateľov (TU) je na %saur-general%s. Na diskusiu týkajúcu sa vývoja AUR webu použite %saur-dev%s mailing list." +#: html/home.php msgid "Bug Reporting" msgstr "Ohlasovanie chýb" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Ak nájdete chybu vo webovom rozhradní AUR, pošlite prosím správu o chybe na " -"náš %sbug tracker%s. Posielajte sem %slen%s chyby webového rozhrania AUR. " -"Pre nahlásenie chýb balíčkov kontaktujte správcu balíčka alebo zanechate " -"komentár na príslušnej stránke balíčka." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Ak nájdete chybu vo webovom rozhradní AUR, pošlite prosím správu o chybe na náš %sbug tracker%s. Posielajte sem %slen%s chyby webového rozhrania AUR. Pre nahlásenie chýb balíčkov kontaktujte správcu balíčka alebo zanechate komentár na príslušnej stránke balíčka." +#: html/home.php msgid "Package Search" msgstr "Hľadanie balíčka" +#: html/index.php msgid "Adopt" msgstr "Adoptovať" +#: html/index.php msgid "Vote" msgstr "Hlasuj" +#: html/index.php msgid "UnVote" msgstr "Odober hlas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Upozorni" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Zruš upozornenie" +#: html/index.php msgid "UnFlag" msgstr "Odznač" +#: html/login.php template/header.php msgid "Login" msgstr "Prihlásiť" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Prihlásený ako: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Odhlásiť" +#: html/login.php msgid "Enter login credentials" msgstr "Zadajte prihlasovacie údaje" +#: html/login.php msgid "User name or email address" msgstr "Užívateľské meno alebo emailová adresa" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Heslo" +#: html/login.php msgid "Remember me" msgstr "Zapamätaj si ma" +#: html/login.php msgid "Forgot Password" msgstr "Zabudnuté heslo" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP prihlasovanie je zablokované. Pre prihlásenie prosím %sprepnite na HTTPs" -"%s." +msgstr "HTTP prihlasovanie je zablokované. Pre prihlásenie prosím %sprepnite na HTTPs%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Vyhľadávacie kritériá" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Balíčky" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Pri pokuse o získanie podrobností o balíčku nastala chyba." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Povinné pole nie je vyplnené." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Heslá sa nezhodujú. " +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Heslo musí mať aspoň %s znakov." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Neplatný e-mail." +#: html/passreset.php msgid "Password Reset" msgstr "Obnova hesla" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Skontrolujte si svoj e-mail pre potvrdzujúci odkaz." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Heslo bolo úspešne obnovené." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrďte svoju e-mailovú adresu:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Zadajte nové heslo:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrďte nové heslo:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Pokračuj" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Ak ste zabudli e-mailovú adresu, ktorú ste použili pri registrácii, pošlite " -"prosím správu na %saur-general%s mailing list." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Ak ste zabudli e-mailovú adresu, ktorú ste použili pri registrácii, pošlite prosím správu na %saur-general%s mailing list." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Zadajte svoju e-mailovú adresu:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Vybrané balíčky neboli vyvlastnené, pozrite potvrdzovacie zaškrtávacie " -"políčko." +msgstr "Vybrané balíčky neboli vyvlastnené, pozrite potvrdzovacie zaškrtávacie políčko." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Nepodarilo sa nájsť balíček, do ktorého sa mali zlúčiť hlasy a komentáre." +msgstr "Nepodarilo sa nájsť balíček, do ktorého sa mali zlúčiť hlasy a komentáre." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Nemožno zlúčiť základňu balíčka so sebou samou." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Vybrané balíčky neboli odstránené, začiarknite potvrdzujúce políčko." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Vymazanie balíčka" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Vymaž balíček" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Použite tento formulár pre vymazanie základne balíčka %s%s%s a nasledovných " -"balíčkov z AUR: " +msgstr "Použite tento formulár pre vymazanie základne balíčka %s%s%s a nasledovných balíčkov z AUR: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Vymazanie balíčka je nevratné." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Zaškrtnite políčko pre potvrdenie akcie." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrďte vymazanie balíčka" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Vymazať" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Len dôverovaní užívatelia a vývojári môžu vymazať balíčky." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Vyvlastni balíček" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Použite tento formulár na vyvlastnenie základne balíčka %s%s%s, ktorá " -"zahrňuje nasledujúce balíčky:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Použite tento formulár na vyvlastnenie základne balíčka %s%s%s, ktorá zahrňuje nasledujúce balíčky:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček " -"a presunúť vlastníctvo na %s%s%s." +msgstr "Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček a presunúť vlastníctvo na %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček." +msgstr "Označením zaškrtávacieho políčka potvrdzujete, že chcete vyvlastniť balíček." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Potvrďte na vyvlastnenie balíčka" +#: html/pkgdisown.php msgid "Disown" msgstr "Vyvlastniť" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Len dôverovaní užívatelia a vývojári môžu vyvlastňovať balíčky." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Označ komentár" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Označ balíček ako zastaranú verziu" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Použite tento formulár na označenie základne balíčka %s%s%s a nasledujúcich " -"balíčkov ako zastarané verzie:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Použite tento formulár na označenie základne balíčka %s%s%s a nasledujúcich balíčkov ako zastarané verzie:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Tento formulár %sneslúži%s na nahlasovanie chýb. Na to použite komentár k " -"balíčku." +msgstr "Tento formulár %sneslúži%s na nahlasovanie chýb. Na to použite komentár k balíčku." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Uveďte nižšie podrobnosti o tom prečo je balíček zastaraný, podľa možnosti " -"pridajte tiež link na oznam k novej verzii alebo nový tarball." +msgstr "Uveďte nižšie podrobnosti o tom prečo je balíček zastaraný, podľa možnosti pridajte tiež link na oznam k novej verzii alebo nový tarball." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Komentáre" +#: html/pkgflag.php msgid "Flag" msgstr "Označ" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Označiť zastaranú verziu balíčka môžu iba registrovaní užívatelia." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Zlúčenie balíčkov" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Zlúč balíček" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Použite tento formulár pre zlúčenie základne balíčka %s%s%s do iného " -"balíčka. " +msgstr "Použite tento formulár pre zlúčenie základne balíčka %s%s%s do iného balíčka. " +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Nasledujúce balíčky budú vymazané:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Operácia zlúčenia balíčkov je nevratná." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Zadajte meno balíčka, do ktorého chcete zlúčiť uvedený balíček." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Zlúčiť do:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrďte zlúčenie balíčka" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Zlúčiť" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Len dôverovaní užívatelia a vývojári môžu zlúčiť balíčky." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Odoslať žiadosť" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zatvoriť žiadosť" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prvý" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Predchádzajúci" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Ďaľej " +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Posledný" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Žiadosti" +#: html/register.php template/header.php msgid "Register" msgstr "Registrovať" +#: html/register.php msgid "Use this form to create an account." msgstr "Použite tento formulár pre vytvorenie účtu. " +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Dôverovaný užívateľ (TU)" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Nepodarilo sa načítať údaje o návrhu." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Hlasovanie o tomto návrhu bolo ukončené." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Práve hlasovať majú len dôverovaní užívatelia" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Nemôžete hlasovať v návrhu o Vás." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "O tomto návrhu ste už hlasovali." +#: html/tu.php msgid "Vote ID not valid." msgstr "ID hlasu nie je platné." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Súčasné hlasy" +#: html/tu.php msgid "Past Votes" msgstr "Minulé hlasy" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Hlasujúci" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Registrácia účtu bolo zablokovaná pre vašu IP adresu, pravdepodobne z dôvodu " -"stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +msgstr "Registrácia účtu bolo zablokovaná pre vašu IP adresu, pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Chýba ID užívateľa" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Užívateľké meno je neplatné." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Musí mať dĺžku medzi %s a %s znakmi" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Začínať a končiť s písmenom alebo číslom" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Môže obsahovať len jednu bodku, podčiarkovník alebo pomlčku." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mailová adresa nie je platná." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP otlačok kľúča je neplatný." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Verejný SSH kľúč nie je platný." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Nepodarilo sa rozšíriť práva účtu." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jazyk nie je momentálne podporovaný." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Užívateľské meno %s%s%s sa už používa." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s sa už používa." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Verejný SSH kľúč %s%s%s sa už používa." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Chyba pri vytváraní účtu, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Účer %s%s%s bol úspešne vytvorený." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Obnovovacie heslo vám bolo zaslané na vašu e-mailovú adresu." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Kliknite na Prihlásenie pre použitie svojho účtu." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Žiadne zmeny neboli vykonané na účte %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Účet %s%s%s bol úspešne zmenený." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Prihlasovací formulár je v súčasnosti zablokovaný pre vašu IP adresu, " -"pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa " -"ospravedlňujeme." +msgstr "Prihlasovací formulár je v súčasnosti zablokovaný pre vašu IP adresu, pravdepodobne z dôvodu stálych spamových útokov. Za nepríjemnosť sa ospravedlňujeme." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Účet bol pozastavený" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Vaše heslo bolo obnovené. Ak ste si práve vytvorili nový účet, použite " -"prosím link z potvrdzovacieho emailu na nastavenie prvotného hesla. Inak " -"prosím zašlite požiadavku na obnovenie hesla na stránku %sObnova hesla%s." +msgstr "Vaše heslo bolo obnovené. Ak ste si práve vytvorili nový účet, použite prosím link z potvrdzovacieho emailu na nastavenie prvotného hesla. Inak prosím zašlite požiadavku na obnovenie hesla na stránku %sObnova hesla%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Nesprávne užívateľské meno alebo heslo." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Pri vytváraní užívateľského sedenia sa vyskytla chyba." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Neplatný email a kombinácia obnovovacích znakov." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Žiadny" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Pozri informácie o účte pre %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Chyba ID alebo meno základne balíčka." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nemáte oprávnenie na editovanie tohoto komentára." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Komentár neexistuje." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Komentár nemôže byť prázdny." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentár bol pridaný." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Musíte byť prihlásený ak chcete editovať informácie o balíčku." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Chýba ID komentára." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Nemôže byť pripnutých viac ako 5 komentárov." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Nemáte oprávnenie na pripnutie tohoto komentára." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Nemáte oprávnenie na odopnutie tohoto komentára." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Komentár bol pripnutý." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Komentár bol odopnutý." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Chyba pri získavaní informácií o balíčku." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Informácie o balíčku sa nepodarilo nájsť." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Musíte byť prihlásený ak chcete označovať balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Nebol vybraný žiadny balíček na označenie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "Vybrané balíčky neboli označené, zanechajte prosím komentár." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Vybrané balíčky boli označené ako zastarané." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Musíte byť prihlásený ak chcete odznačiť balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Nebol vybraný žiadny balíček na odznačenie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Vybrané balíčky boli odznačené." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nemáte práve vymazať balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Nebol vybraný žiadny balíček na vymazanie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Vybrané balíčky boli vymazané." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Musíte byť prihlásený ak chcete adoptovať balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Musíte byť prihlásený ak chcete vyvlastniť balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Nebol vybraný žiadny balíček na adopciu." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Neoznačili ste žiadne balíčky na vyvlastnenie." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Vybrané balíčky boli adoptované." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Vybrané balíčky boli vyvlastnené." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Musíte byť prihlásený ak chcete hlasovať za balíčky." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Musíte byť prihlásený ak chcete odobrať hlas balíčkom." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Nebol vybraný žiadny balíček pre hlasovanie." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Váš hlas bol odobratý z vyznačených balíčkov." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Váš hlas bol pridaný vyznačeným balíčkom." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Pridanie do zoznamu upozornení bolo neúspešné." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Boli ste pridaný na notifikačný zoznam komentárov pre %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Boli ste odobraný z notifikačného zoznamu komentárov pre %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Nemáte práva na obnovenie tohto komentára." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Komentár bol obnovený." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nemáte práva na vymazanie tohto komentára." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentár bol vymazaný." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Komentár bol editovaný." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nemáte oprávnenie na editovanie kľúčových slov tejto základne balíčka." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Kľúčové slová základne balíčka boli aktualizované." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nie ste oprávnený manažovať spolupracovníkov tejto základne balíčka." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Neplatné užívateľské meno: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Spolupracovníci základne balíčka boli aktualizovaní." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Pozri detaily balíčky pre" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "vyžaduje %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Musíte byť prihlásený ak chcete posielať žiadosti o balíčkoch." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neplatné meno: povolené sú iba malé písmená." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Pole s komentárom nemôže byť prázdne." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Neplatný typ žiadosti." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Požiadavka bola úspešne pridaná." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Neplatný dôvod." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Len Dôverovaní Užívatelia (TU) a vývojári môžu zatvárať žiadosti." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Žiadosť bola úspešne uzavretá." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Tento formulár môžete použiť na trvalé vymazanie AUR účtu %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUPOZORNENIE%s: Túto akciu nemožno vrátiť." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Potvrdiť vymazanie" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Užívateľské meno" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Typ účtu" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Užívateľ" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Vývojár" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Dôverovaný užívateľ & Vývojár" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-mailová adresa" +#: template/account_details.php msgid "hidden" msgstr "skrytý" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Skutočné meno" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Domovská stránka" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC prezývka" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP otlačok kľúča" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Neaktívny od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktívny" +#: template/account_details.php msgid "Registration date:" msgstr "Dátum registrácie" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "neznámy" +#: template/account_details.php msgid "Last Login" msgstr "Posledné prihlásenie" +#: template/account_details.php msgid "Never" msgstr "Nikdy" +#: template/account_details.php msgid "View this user's packages" msgstr "Pozrieť balíčky tohto užívateľa" +#: template/account_details.php msgid "Edit this user's account" msgstr "Editovať účet tohto užívateľa" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %ssem%s ak chcete natrvalo vymazať tento účet." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Kliknite %ssem%s pre informácie o užívateľovi." +#: template/account_edit_form.php msgid "required" msgstr "povinný" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normálny užívateľ" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Dôverovaný užívateľ (TU)" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Účet bol pozastavený" +#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktívny" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Overte prosím, že ste emailovú adresu zadali správne, inak budete vymknutý." +msgstr "Overte prosím, že ste emailovú adresu zadali správne, inak budete vymknutý." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Skryť emailovú adresu" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Potvrďte heslo" +#: template/account_edit_form.php msgid "Language" msgstr "Jazyk" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Nasledujúca informácia je dôležitá iba v prípade, že chcete podať balíčky do " -"AUR." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Nasledujúca informácia je dôležitá iba v prípade, že chcete podať balíčky do AUR." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Verejný SSH kľúč" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Nastavenia upozornení" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Upozorni na nové komentáre" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Upozorni na aktualizácie balíčkov" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Upozorni na zmeny vo vlastníctve balíčka" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Aktualizácia" +#: template/account_edit_form.php msgid "Create" msgstr "Vytvoriť" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Reset" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Pre vaše vyhľadávacie kritériá neboli nájdené žiadne výsledky." +#: template/account_search_results.php msgid "Edit Account" msgstr "Editovať účet" +#: template/account_search_results.php msgid "Suspended" msgstr "Pozastavený" +#: template/account_search_results.php msgid "Edit" msgstr "Editovať" +#: template/account_search_results.php msgid "Less" msgstr "Menej" +#: template/account_search_results.php msgid "More" msgstr "Viac" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nie sú ďalšie výsledky na zobrazenie." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno " -"užívateľké meno na riadok):" +msgstr "Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno užívateľké meno na riadok):" +#: template/comaintainers_form.php msgid "Users" msgstr "Užívatelia" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Uložiť" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Komentár k označeniu balíčka ako zastaranej verzie: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "" -"%s%s%s bol označený %s%s%s ako zastaraný %s%s%s z nasledujúceho dôvodu:" +msgstr "%s%s%s bol označený %s%s%s ako zastaraný %s%s%s z nasledujúceho dôvodu:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s nie je označený ako zastarný." +#: template/flag_comment.php msgid "Return to Details" msgstr "Návrat na detaily" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." +#: template/header.php msgid " My Account" msgstr "Môj účet" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Akcie balíčka" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Pozrieť PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Prezrieť zmeny" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Stiahnuť snapshot" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Prehľadať wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Označený ako zastaraný (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Označ balíček ako neaktuálny" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Odznač balíček" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Odober hlas" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Hlasuj za tento balíček" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Vypni upozornenia" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Povoliť upozornenia" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Manažovať spolupracovníkov" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d ostávajúcich žiadostí" msgstr[1] "%d ostávajúce žiadosti" msgstr[2] "%d ostávajúcich žiadostí" +msgstr[3] "%d ostávajúcich žiadostí" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Adoptuj balíček" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Detaily základne balíčka" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "len na čítanie" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Kľúčové slová" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Prispievateľ" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Spravovateľ" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Naposledy zabalil" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Hlasy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularita" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvý príspevok" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Posledná aktualizácia" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Editovať komentár k: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Pridať komentár" +#: template/pkg_comments.php msgid "View all comments" msgstr "Pozrieť všetky komentáre" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Pripnuté komentáre" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Posledné komentáre" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s dal komentár k %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anonymný komentár k %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "vymazal %s %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "vymazaný %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "editovaný %s %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "editovaný %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Obnoviť komentár" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Vymaž komentár" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Pripnúť komentár" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Odopnúť komentár" +#: template/pkg_comments.php msgid "All comments" msgstr "Všetky komentáre" +#: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčka" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Základňa balíčka" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Popis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Upstream URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Navštív web stránku pre" +#: template/pkg_details.php msgid "Licenses" msgstr "Licencie" +#: template/pkg_details.php msgid "Groups" msgstr "Skupiny" +#: template/pkg_details.php msgid "Conflicts" msgstr "Konflikt s" +#: template/pkg_details.php msgid "Provides" msgstr "Poskytuje" +#: template/pkg_details.php msgid "Replaces" msgstr "Nahrádza" +#: template/pkg_details.php msgid "Dependencies" msgstr "Závislosti" +#: template/pkg_details.php msgid "Required by" msgstr "Vyžadovaný" +#: template/pkg_details.php msgid "Sources" msgstr "Zdroje" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Použite tento formulár pre zatvorenie požiadavky na základňu balíčka %s%s%s." +msgstr "Použite tento formulár pre zatvorenie požiadavky na základňu balíčka %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Políčko pre komentár možno nechať prázdne. Napriek tomu sa odporúča zanechať " -"komentár pri zamietnutí požiadavky." +msgstr "Políčko pre komentár možno nechať prázdne. Napriek tomu sa odporúča zanechať komentár pri zamietnutí požiadavky." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Dôvod" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Prijatý" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Zamietnutý" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Použite tento formulár na vyplnenie požiadavky ohľadom základne balíčka %s%s" -"%s ktorá zahrňuje nasledovné balíčky:" +msgstr "Použite tento formulár na vyplnenie požiadavky ohľadom základne balíčka %s%s%s ktorá zahrňuje nasledovné balíčky:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Typ žiadosti" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Vymazanie" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Vyvlastniť" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Zlúčiť do" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Odoslaním žiadosti na vymazanie balíčka žiadate dôverovaného užívateľa t.j. " -"Trusted User, aby vymazal balíček aj s jeho základňou. Tento typ požiadavky " -"by mal použitý pre duplikáty, softvér ku ktorému už nie sú zdroje ako aj " -"nelegálne a neopraviteľné balíčky." +msgstr "Odoslaním žiadosti na vymazanie balíčka žiadate dôverovaného užívateľa t.j. Trusted User, aby vymazal balíček aj s jeho základňou. Tento typ požiadavky by mal použitý pre duplikáty, softvér ku ktorému už nie sú zdroje ako aj nelegálne a neopraviteľné balíčky." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Odoslaním žiadosti na zlúčenie balíčka žiadate dôverovaného užívateľa t.j. " -"Trusted User, aby vymazal balíček aj s jeho základňou a preniesol hlasy a " -"komentáre na inú základňu balíčka. Zlúčenie balíčka nezasiahne prináležiace " -"Git repozitáre, preto sa uistite, že Git história cieľového balíčka je " -"aktuálna." +msgstr "Odoslaním žiadosti na zlúčenie balíčka žiadate dôverovaného užívateľa t.j. Trusted User, aby vymazal balíček aj s jeho základňou a preniesol hlasy a komentáre na inú základňu balíčka. Zlúčenie balíčka nezasiahne prináležiace Git repozitáre, preto sa uistite, že Git história cieľového balíčka je aktuálna." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Odoslaním žiadosti na osirotenie balíčka žiadate dôverovaného užívateľa t.j. " -"Trusted User, aby vyvlastnil balíček aj s jeho základňou. Toto urobte len " -"vtedy, ak balíček vyžaduje zásah od vlastníka, vlastník nie je zastihnuteľný " -"a už ste sa niekoľkokrát pokúšali vlastníka kontaktovať." +msgstr "Odoslaním žiadosti na osirotenie balíčka žiadate dôverovaného užívateľa t.j. Trusted User, aby vyvlastnil balíček aj s jeho základňou. Toto urobte len vtedy, ak balíček vyžaduje zásah od vlastníka, vlastník nie je zastihnuteľný a už ste sa niekoľkokrát pokúšali vlastníka kontaktovať." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Bola nájdená %d požiadavka ohľadom balíčkov." msgstr[1] "Boli nájdené %d požiadavky ohľadom balíčkov." msgstr[2] "Bolo nájdených %d požiadaviek ohľadom balíčkov." +msgstr[3] "Bolo nájdených %d požiadaviek ohľadom balíčkov." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Strana %d z %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Balíček" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Vyplnil" +#: template/pkgreq_results.php msgid "Date" msgstr "Dátum" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "ostáva ~%d deň" msgstr[1] "ostáva ~%d dni" msgstr[2] "ostáva ~%d dní" +msgstr[3] "ostáva ~%d dní" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "ostáva ~%d hodina" msgstr[1] "ostávajú ~%d hodiny" msgstr[2] "ostáva ~%d hodín" +msgstr[3] "ostáva ~%d hodín" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "ostáva < 1 hodina" +#: template/pkgreq_results.php msgid "Accept" msgstr "Prijať" +#: template/pkgreq_results.php msgid "Locked" msgstr "Uzamknuté" +#: template/pkgreq_results.php msgid "Close" msgstr "Zatvoriť" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zatvorené" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "meno, popis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "iba meno" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Presné meno" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Presná základňa balíčka" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Všetky" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Označené" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Neoznačené" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Meno" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Hlasoval" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Naposledy zmenený" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Vzostupne" +#: template/pkg_search_form.php msgid "Descending" msgstr "Zostupne" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Zadaj kritériá pre vyhľadávanie" +#: template/pkg_search_form.php msgid "Search by" msgstr "Vyhľadávať podľa" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Neaktuálny" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Zotriediť podľa" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Zotriediť" +#: template/pkg_search_form.php msgid "Per page" msgstr "Na stránku" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Choď" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Osirené" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Chyba pri získavaní zoznamu balíčkov." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Žiadne balíčky nezodpovedajú vaším vyhľadávacím kritériám." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d nájdených balíčkov." msgstr[1] "%d nájdené balíčky." msgstr[2] "%d nájdených balíčkov." +msgstr[3] "%d nájdených balíčkov." +#: template/pkg_search_results.php msgid "Version" msgstr "Verzia" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Popularita sa počíta ako súčet všetkých hlasov, pričom každý hlas je " -"prenásobený váhovým koeficientom %.2f každý deň od jeho pridania." +msgstr "Popularita sa počíta ako súčet všetkých hlasov, pričom každý hlas je prenásobený váhovým koeficientom %.2f každý deň od jeho pridania." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Áno" +#: template/pkg_search_results.php msgid "orphan" msgstr "osirelý" +#: template/pkg_search_results.php msgid "Actions" msgstr "Akcie" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Odznač ako neaktuálny" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Adoptuj balíčky" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Vyvlastni balíčky" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Vymaž balíčky" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrď" +#: template/search_accounts_form.php msgid "Any type" msgstr "Ľub. typ" +#: template/search_accounts_form.php msgid "Search" msgstr "Hľadaj" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Štatistika" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Osirelé balíčky" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Balíčky pridané za posledných 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Balíčky aktualiz. za uplynulých 7 dní" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Balíčky aktualiz. za posledný rok" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Nikdy neaktualizované balíčky" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovaní užívatelia" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Dôverovaní užívatelia (TU)" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedávne aktualizácie" +#: template/stats/updates_table.php msgid "more" msgstr "viac" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moja štatistika" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detaily o návrhu" +#: template/tu_details.php msgid "This vote is still running." msgstr "Hlasovanie stále prebieha." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Prispené: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Koniec" +#: template/tu_details.php msgid "Result" msgstr "Výsledok" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Nie" +#: template/tu_details.php msgid "Abstain" msgstr "Zdržalo sa" +#: template/tu_details.php msgid "Total" msgstr "Celkom" +#: template/tu_details.php msgid "Participation" msgstr "Účasť" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Posledné hlasy od TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Posledný hlas" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Žiadne výsledky neboli nájdené." +#: template/tu_list.php msgid "Start" msgstr "Začiatok" +#: template/tu_list.php msgid "Back" msgstr "Späť" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/sr.po b/po/sr.po index 722a5700..0a49ba72 100644 --- a/po/sr.po +++ b/po/sr.po @@ -1,1155 +1,1440 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Lukas Fleischer , 2011 # Slobodan Terzić , 2011-2012,2015-2017 # Slobodan Terzić , 2015 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-12-02 00:35+0000\n" -"Last-Translator: Slobodan Terzić \n" -"Language-Team: Serbian (http://www.transifex.com/lfleischer/aur/language/" -"sr/)\n" -"Language: sr\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Serbian (http://www.transifex.com/lfleischer/aurweb/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Language: sr\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +#: html/404.php msgid "Page Not Found" msgstr "Stranica nije nađena" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Stranica koju ste zahtevali ne postoji." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Beleška" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "URL-ovi za Git kloniranje nisu namenjeni za otvaranje u pregledaču." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Da bi klonirali git riznicu %s, pokrenite %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Kliknite %sovde%s da bi se vratili na stranicu o %s." +#: html/503.php msgid "Service Unavailable" msgstr "Servis nije dostupan" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Ne paničite! Sajt je van mreže usled održavanja. Povratak se očekuje uskoro." +msgstr "Ne paničite! Sajt je van mreže usled održavanja. Povratak se očekuje uskoro." +#: html/account.php msgid "Account" msgstr "Nalog" +#: html/account.php template/header.php msgid "Accounts" msgstr "Nalozi" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Nije vam dozvoljen pristup ovoj oblasti." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Ne mogu da dobavim podatke o izabranom korisniku." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Nemate dozvole za uređivanje ovog naloga." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Ovim obrascem pretražujete postojeće naloge." +#: html/account.php msgid "You must log in to view user information." msgstr "Morate se prijaviti da bi videli podatke o korisniku." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Dodavanje predloga" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Neispravan token korisničke radnje." +#: html/addvote.php msgid "Username does not exist." msgstr "Korisničko ime ne postoji." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "Predlog za %s već postoji." +#: html/addvote.php msgid "Invalid type." msgstr "Nedozvoljen tip." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Predlog ne može biti prazan." +#: html/addvote.php msgid "New proposal submitted." msgstr "Novi predlog je poslat." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Pošaljite predlog za glasanje." +#: html/addvote.php msgid "Applicant/TU" msgstr "Podnosioc/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(prazno ako je nevažeće)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Vrsta" +#: html/addvote.php msgid "Addition of a TU" msgstr "Dodavanje TU" +#: html/addvote.php msgid "Removal of a TU" msgstr "Uklanjanje TU" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Uklanjanje TU (nedeklarisana neaktivnost)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Dopuna o podzakonskim aktima" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Predlog" +#: html/addvote.php msgid "Submit" msgstr "Slanje" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Upravljanje koodržavaocima" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Uređivanje komentara" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Komandna tabla" +#: html/home.php template/header.php msgid "Home" msgstr "Početna" +#: html/home.php msgid "My Flagged Packages" msgstr "Moji označeni paketi" +#: html/home.php msgid "My Requests" msgstr "Moji zahtevi" +#: html/home.php msgid "My Packages" msgstr "Moji paketi" +#: html/home.php msgid "Search for packages I maintain" msgstr "Pretraži pakete koje održavam" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Koodržavani paketi" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Pretraži pakete koje koodržavam" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Dobrodošli u AUR! Molimo pročitajte %sSmernice za korisnike AUR-a%s i " -"%sSmernice za poverljive korinike%s za više informacija." +msgstr "Dobrodošli u AUR! Molimo pročitajte %sSmernice za korisnike AUR-a%s i %sSmernice za poverljive korinike%s za više informacija." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Priloženi PKGBUILD-ovi %smoraju%s biti u skladu sa %sArčovim standardima " -"pakiranja%s ili će biti obrisani!" +msgstr "Priloženi PKGBUILD-ovi %smoraju%s biti u skladu sa %sArčovim standardima pakiranja%s ili će biti obrisani!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Ne zaboravite da glasate za omiljene pakete!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Neki paketi se dostavljaju u binarnom obliku u riznici [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "UPOZORENJE" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Paketi u AUR-u su sadržaj koji stvaraju korisnici. Upotrebljavate ih na " -"sopstvenu odgovornost." +msgstr "Paketi u AUR-u su sadržaj koji stvaraju korisnici. Upotrebljavate ih na sopstvenu odgovornost." +#: html/home.php msgid "Learn more..." msgstr "Saznajte više..." +#: html/home.php msgid "Support" msgstr "Podrška" +#: html/home.php msgid "Package Requests" msgstr "Zahtevi za pakete" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Postoje tri vrste zahteva koji mogu biti podneti kroz kućicu %sRadnje nad " -"paketima%s na stranici sa detaljima o paketu:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Postoje tri vrste zahteva koji mogu biti podneti kroz kućicu %sRadnje nad paketima%s na stranici sa detaljima o paketu:" +#: html/home.php msgid "Orphan Request" msgstr "Zahtevi za odricanje" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"zahtev za odricanje od paketa, npr. kada je održavalac neaktivan a paket je " -"predugo označen kao zastareo." +msgstr "zahtev za odricanje od paketa, npr. kada je održavalac neaktivan a paket je predugo označen kao zastareo." +#: html/home.php msgid "Deletion Request" msgstr "Zahtevi za brisanje" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"zahtev za brisanje paketa iz Arčove Korisničke Riznice. Ne koristite ovo ako " -"je paket polomljen i može se lako ispraviti. Umesto toga, kontaktirajte " -"održavaoca paketa i podnesite zahtev za odricanje ukoliko je potreban." +msgstr "zahtev za brisanje paketa iz Arčove Korisničke Riznice. Ne koristite ovo ako je paket polomljen i može se lako ispraviti. Umesto toga, kontaktirajte održavaoca paketa i podnesite zahtev za odricanje ukoliko je potreban." +#: html/home.php msgid "Merge Request" msgstr "Zahtevi za spajanje" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"zahtev za spajanje paketa sa drugim paketom. Koristi se kada je paketu " -"potrebno novo ime ili ga je potrebno razdeliti ma manje pakete." +msgstr "zahtev za spajanje paketa sa drugim paketom. Koristi se kada je paketu potrebno novo ime ili ga je potrebno razdeliti ma manje pakete." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Ukoliko želite da diskutujete o zahtevu, možete koristiti dopisnu listu " -"%saur-requests%s. Međutim, molimo da ne koristite tu listu za podnošenje " -"zahteva." +msgstr "Ukoliko želite da diskutujete o zahtevu, možete koristiti dopisnu listu %saur-requests%s. Međutim, molimo da ne koristite tu listu za podnošenje zahteva." +#: html/home.php msgid "Submitting Packages" msgstr "Prilaganje paketa" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Za prilaganje paketa u AUR sada se koristi Git preko SSH. Pogledajte sekciju " -"%sPrilaganje paketa%s na stranici o AUR-u na Arčovom wikiju." +msgstr "Za prilaganje paketa u AUR sada se koristi Git preko SSH. Pogledajte sekciju %sPrilaganje paketa%s na stranici o AUR-u na Arčovom wikiju." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Sledeći SSH otisci se koriste za AUR:" +#: html/home.php msgid "Discussion" msgstr "Diskusija" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Opšta diskusija vezana za Arčovu Korisničku Riznicu (AUR) i strukturu " -"Poverljivih korisnika se vodi na dopisnoj listi %saur-general%s.Za diskusiju " -"o razvoju samog web sučelja AUR-a, pogedajte dopisnu listu %saur-dev%s." +msgstr "Opšta diskusija vezana za Arčovu Korisničku Riznicu (AUR) i strukturu Poverljivih korisnika se vodi na dopisnoj listi %saur-general%s.Za diskusiju o razvoju samog web sučelja AUR-a, pogedajte dopisnu listu %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Prijavljivanje grešaka" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Ukoliko nađete grešku u web sučelju AUR-a. molimo da je prijavite na našem " -"%sbubolovcu%s. Bubolovac koristite %sisključivo%s za prjavljivanje grešaka u " -"samom AUR-u. Za prijavu grešaka u samim paketima kontaktirajte održavaoce " -"paketa ili ostavite komentar na odgovarajućoj stranici paketa." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Ukoliko nađete grešku u web sučelju AUR-a. molimo da je prijavite na našem %sbubolovcu%s. Bubolovac koristite %sisključivo%s za prjavljivanje grešaka u samom AUR-u. Za prijavu grešaka u samim paketima kontaktirajte održavaoce paketa ili ostavite komentar na odgovarajućoj stranici paketa." +#: html/home.php msgid "Package Search" msgstr "Pretraga paketa" +#: html/index.php msgid "Adopt" msgstr "Usvoji" +#: html/index.php msgid "Vote" msgstr "Daj glas" +#: html/index.php msgid "UnVote" msgstr "Ukloni glas" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Obaveštenja" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Ne obaveštavaj" +#: html/index.php msgid "UnFlag" msgstr "Odznači" +#: html/login.php template/header.php msgid "Login" msgstr "Prijava" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Prijavljeni ste kao: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Odjava" +#: html/login.php msgid "Enter login credentials" msgstr "Unesite podatke za prijavu" +#: html/login.php msgid "User name or email address" msgstr "Korisničko ime ili adresa e-pošte" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" +#: html/login.php msgid "Remember me" msgstr "Pamti me" +#: html/login.php msgid "Forgot Password" msgstr "Zaboravljena lozinka" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Prijavljivanje preko HTTP je isključeno. Koristite %sHTTPs%s da bi se " -"prijavili." +msgstr "Prijavljivanje preko HTTP je isključeno. Koristite %sHTTPs%s da bi se prijavili." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Kriterijum pretrage" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketi" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Greška pri dobavljanju detalja paketa." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Nedostaje neophodno polje." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Polja lozinke se ne poklapaju." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Lozinka mora imati najmanje %s znaka." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Neispravna e-pošta." +#: html/passreset.php msgid "Password Reset" msgstr "Resetovanje lozinke" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Proverite e-poštu za vezu za potvrđivanje." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Vaša lozinka je uspešno resetovana." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Potvrdite adresu e-pošte:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Unesite novu lozinku:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Potvrdite novu lozinku:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Nastavi" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Ukoliko ste zaboravili registracionu adresu e-pošte, molimo pošaljite poruku " -"na dopisnu listu %saur-general%s." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Ukoliko ste zaboravili registracionu adresu e-pošte, molimo pošaljite poruku na dopisnu listu %saur-general%s." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Unesite adresu e-pošte:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Osnove paketa" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Izabrani paketi nisu odreknuti, pogledajte kućicu za potvrdu." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Ne mogu da nađem paket kako bih stopio glasove i komentare." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Ne mogu da spojim osnovu paketa sa samom sobom." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Izabrani paketi nisu obrisani; pogledajte kućicu za potvrđivanje." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Brisanje paketa" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Obriši paket" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Ovim formularom brišete osnovu paketa %s%s%s i sledeće pakete iz AUR-a:" +msgstr "Ovim formularom brišete osnovu paketa %s%s%s i sledeće pakete iz AUR-a:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Brisanje paketa je trajno." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Označite kućicu za potvrdu." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Potvrdite brisanje paketa" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Obriši" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Samo Poverljivi korisnici i Programeri mogu brisati pakete." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Odrekni se paketa" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Ovim formularom se odričete osnove paketa %s%s%s i sledećih pripadajučih " -"pakete:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Ovim formularom se odričete osnove paketa %s%s%s i sledećih pripadajučih pakete:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Označavanjem kućice potvrđujete odricanje prenos vlasništva paketa na %s%s%s." +msgstr "Označavanjem kućice potvrđujete odricanje prenos vlasništva paketa na %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Označavanjem kućice potvrđujete da želite da se odreknete od paketa." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Potvrdite odricanje od paketa" +#: html/pkgdisown.php msgid "Disown" msgstr "Odrekni se" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "Samo Poverljivi korisnici i Programeri mogu vršiti odricanje paketa." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Označi komentar" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Označi paket kao zastareo" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Ovim formularom označavate osnovu paketa %s%s%s i sledeće pakete kao " -"zastarele:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Ovim formularom označavate osnovu paketa %s%s%s i sledeće pakete kao zastarele:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Molimo da ovim formularom %sNE%s prijavljujete greške. Umesto toga koristite " -"komentare o paketu." +msgstr "Molimo da ovim formularom %sNE%s prijavljujete greške. Umesto toga koristite komentare o paketu." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Ispod unesite razloge zbog kojih je paket zastareo, poželjno i veze ka " -"objavi novog izdanja ili izvornom kodu nove verzije." +msgstr "Ispod unesite razloge zbog kojih je paket zastareo, poželjno i veze ka objavi novog izdanja ili izvornom kodu nove verzije." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Komentari" +#: html/pkgflag.php msgid "Flag" msgstr "Označi" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "Samo registrovani korisnici mogu označavati pakete zastarelim." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Spajanje paketa" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Spoji paket" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "Ovim formularom spajate osnovu paketa %s%s%s sa drugim paketom." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Sledeći paketi će biti obrisani:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Kada se jednom spoje, paketi ne mogu više biti razdvojeni." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Unesite ime paketa sa kojim želite da spojite ovaj paket." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Spoji sa:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Potvrdite spajanje" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Spoji" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Samo Poverljivi korisnici i Programeri mogu da spajaju pakete." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Podnesi zahtev" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Zatvori zahtev" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prva" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Prethodna" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sledeća" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Zadnja" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Zahtevi" +#: html/register.php template/header.php msgid "Register" msgstr "Registracija" +#: html/register.php msgid "Use this form to create an account." msgstr "Ovim formularom pravite nalog." +#: html/tos.php msgid "Terms of Service" msgstr "Uslovi korišćenja" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "Sledeći dokumenti su ažurirani. Molimo da ih pažljivo pročitate:" +#: html/tos.php #, php-format msgid "revision %d" msgstr "revizija %d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "Prihvatam gore navedene uslove." +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Poverljivi korisnik" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Ne mogu da dobavim detalje o predlogu." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Glasanje o ovom predlogu je završeno." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Samo poverljivi korisnici mogu da glasaju." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Ne možete glasati za predlog koji se odnosi na vas." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Već ste glasali za ovaj predlog." +#: html/tu.php msgid "Vote ID not valid." msgstr "Neispravan ID glasa." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Trenutno glasova" +#: html/tu.php msgid "Past Votes" msgstr "Prethodni glasovi" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Glasači" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Registrovanje naloga sa vaše IP adrese je onemogućeno, najverovatnije usled " -"napada spama. Oprostite na neprijatnosti." +msgstr "Registrovanje naloga sa vaše IP adrese je onemogućeno, najverovatnije usled napada spama. Oprostite na neprijatnosti." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Nedostaje ID korisnika" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Neispravno korisničko ime." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Mora imati između %s i %s znakova." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Počnje i završava slovom ili brojem" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržati samo jedan razmak, podvlaku ili crticu." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Neispravna adresa e-pošte." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Domaća stranica je neispravna, molimo navedite puni HTTP(s) URL." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Otisak PGP ključa nije ispravan." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Neispravan javni SSH ključ." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Ne mogu da uvećam dozvole naloga." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Jezik trenutno nije podržan." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Vremenska zona trenutno nije podržana." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Korisničko ime %s%s%s je već u upotrebi." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adresa %s%s%s je već u upotrebi." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Javni SSH ključ %s%s%s je već u upotrebi." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Greška pri pravljenju naloga %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Nalog %s%s%s je uspešno napravljen." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ključ za resetovanje lozinke je poslat na vašu adresu e-pošte." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Kliknite iznad na vezu Prijava da bi koristili svoj nalog." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Nisu izvršene nikakve izmene naloga %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Nalog %s%s%s je uspešno izmenjen." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Formular za prijavljivanje je trenutno onemogućen za vašu IP adresu, " -"najverovatnije usled napada spama. Oprostite na neprijatnosti." +msgstr "Formular za prijavljivanje je trenutno onemogućen za vašu IP adresu, najverovatnije usled napada spama. Oprostite na neprijatnosti." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Nalog je suspendovan" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Vaša lozinka je resetovana. Ukoliko ste tek napravili nov nalog, molimo " -"upotrebite vezu iz e-pisma za potvrdu kako bi postavili početnu lozinku. U " -"suprotnom, zatražite resetovajne ključa putem stranice %sResetovanje lozinke" -"%s." +msgstr "Vaša lozinka je resetovana. Ukoliko ste tek napravili nov nalog, molimo upotrebite vezu iz e-pisma za potvrdu kako bi postavili početnu lozinku. U suprotnom, zatražite resetovajne ključa putem stranice %sResetovanje lozinke%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Loše korisničko ime ili lozinka." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Došlo je do greške pri pravljenju korisničke sesije." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Neispravna kombinacija e-pošte i ključa za resetovanje." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Nema" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Prikaži podatke o nalogu za %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Nedostaje ID ili ime baze paketa." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Nemate dozvolu za uređivanje ovog komentara." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Komentar ne postoji." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Komentar ne sme biti prazan." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Komentar je dodat." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Morate se prijaviti da bi ste uređivali podatke o paketu." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Nedostaje ID komentara." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Ne može se izdvojiti više od 5 komentara." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Nemate dozvole za izdvajanje ovog komentara." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Nemate dozvole da odvajanje ovog komentara." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Komentar je izdvojen." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Komentar je odvojen." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Greška pri dobavaljanju podataka o paketu." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Ne mogu naći podatke o paketu." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Morate se prijaviti pre označavanja paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Niste izabrali pakete za označavanje." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "Izabrani paketi nisu označeni, molimo unesite komentar." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Izabrani paketi su označeni kao zastareli." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Morate se prijaviti da bi uklonili oznake." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Niste izabrali paket za uklanjanje oznake." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Označenim paketima je uklonjena oznaka." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Nemate dozvole za brisanje paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Niste izabrali pakete za brisanje." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Izbrani paketi su obrisani." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Morate se prijaviti da bi usvojili pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Morate se prijaviti da bi ste se odrekli paketa." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Niste izabrali paketa za usvajanje." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Niste izabrali pakete kojih bi da se odreknete." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Izabrani paketi su usvojeni." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Odrekli ste se izabranog paketa." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Morate se prijaviti da bi glasali za pakete." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Morate se prijaviti da bi uklonili glasove za pakete." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Niste izabrali pakete za koje glasate." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Vaši glasovi su uklonjeni za izabrane paketa." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Dali ste glas izabranim paketima." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Ne mogu da dodam na spisak za obaveštenja." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Dodati ste na spisak za obaveštenja o %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Uklonjeni ste sa spiska obaveštavanja o komentarima za %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Nemate dozvole za povraćaj ovog komentara." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Komentar je povraćen." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Nije vam dozvoljeno brisanje ovog komentara." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Komentar je obrisan." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Komentar je uređen." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Nije vam dozvoljeno da uređujete ključne reči za ovu osnovu paketa." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ključne reči baze paketa su ažurirane." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Nije vam dozvvoljeno da upravljate koodržavaocima ove osnove paketa." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Neispravno korisničko ime: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Koodržavaoci osnove baze paketa su ažurirani." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Prikaži detalje paketa za" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "zahteva %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Morate se prijaviti da bi slali zahteve za pakete." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Neispravno ime: dozvoljena su samo mala slova." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Polje komentara ne sme biti prazno." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Neispravan tip zahteva" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Zahtev je uspešno dodat." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Neispravan razlog." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Samo Poverljivi korisnici i programeri mogu zatvarati zahteve." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Zahtev je uspešno zatvoren." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ovim možete trajno obrisati nalog %s iz AUR-a." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUPOZORENJE%s: ova radnja se ne može opozvati" +#: template/account_delete.php msgid "Confirm deletion" msgstr "Potvrda brisanja" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Korisničko ime" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Tip naloga" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Korisnik" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Programer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Poverljivi korisnik i programer" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Adresa e-pošte" +#: template/account_details.php msgid "hidden" msgstr "skrivena" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Pravo ime" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Domaća stranica" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC nadimak" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Otisak PGP ključa" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Status" +#: template/account_details.php msgid "Inactive since" msgstr "Neaktivan od" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Aktivan" +#: template/account_details.php msgid "Registration date:" msgstr "Datum registracije:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "nepoznata" +#: template/account_details.php msgid "Last Login" msgstr "Poslednje prijavljivanje" +#: template/account_details.php msgid "Never" msgstr "Nikad" +#: template/account_details.php msgid "View this user's packages" msgstr "Pregledaj korisnikove pakete" +#: template/account_details.php msgid "Edit this user's account" msgstr "Uređivanje naloga ovog korisnika" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Kliknite %sovde%s ako želite trajno brisanje ovog naloga." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Kliknite %sovde%s za podatke o korisniku." +#: template/account_edit_form.php msgid "required" msgstr "neophodno" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" -"Vaše korisničko ime kojim se prijavljujete. Vidljivo je u javnosti, čak i " -"ako je vaš nalog neaktivan." +msgstr "Vaše korisničko ime kojim se prijavljujete. Vidljivo je u javnosti, čak i ako je vaš nalog neaktivan." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Običan korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Poverljivi korisnik" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Nalog je suspendovan" +#: template/account_edit_form.php msgid "Inactive" msgstr "Neaktivan" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Proverite da li ste ispravno uneli adresu e-pošte, inače će vam pristup biti " -"odbijen." +msgstr "Proverite da li ste ispravno uneli adresu e-pošte, inače će vam pristup biti odbijen." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Skrij adresu e-pošte" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Ponovo unesite lozinku" +#: template/account_edit_form.php msgid "Language" msgstr "Jezik" +#: template/account_edit_form.php msgid "Timezone" msgstr "Vremenska zona" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Sledeće informacije su neophodne ako želite da prilažete pakete u Arčovu " -"korisničku riznicu." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Sledeće informacije su neophodne ako želite da prilažete pakete u Arčovu korisničku riznicu." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Javni SSH ključ" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Postavke obaveštenja" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Obavesti o novim komentarima" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Obavesti o nadogradnjama paketa" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Obavesti o promenama vlasništva" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Ažuriraj" +#: template/account_edit_form.php msgid "Create" msgstr "Napravi" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Resetuj" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Nema rezultata koji se poklapaju sa kriterijumom pretrage." +#: template/account_search_results.php msgid "Edit Account" msgstr "Uredi nalog" +#: template/account_search_results.php msgid "Suspended" msgstr "Suspendovan" +#: template/account_search_results.php msgid "Edit" msgstr "Uredi" +#: template/account_search_results.php msgid "Less" msgstr "Manje" +#: template/account_search_results.php msgid "More" msgstr "Više" +#: template/account_search_results.php msgid "No more results to display." msgstr "Nema daljih rezultata." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Ovim formularom dodajete koodržavaoce za %s%s%s (jedno korisničko ime po " -"liniji):" +msgstr "Ovim formularom dodajete koodržavaoce za %s%s%s (jedno korisničko ime po liniji):" +#: template/comaintainers_form.php msgid "Users" msgstr "Korisnici" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Sačuvaj" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Komentar o oznaci zastarelosti: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "%s%s%s označi %s%s%s kao zastareo %s%s%s iz sledećeg razloga:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s nije označen kao zastareo." +#: template/flag_comment.php msgid "Return to Details" msgstr "Nazad na detalje" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb Development Team." +#: template/header.php msgid " My Account" msgstr "Moj nalog" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Radnje nad paketom" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Prikaži PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Prikaz izmena" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Preuzimanje snimka" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Pretraži wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Označen kao zastareo (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Označi kao zastareo" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Odznači paket" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Ukloni glas" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Glasajte za paket" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Ugasi obaveštenja" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Uključi obaveštenja" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Upravljanje koodržavaocima" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" @@ -1157,210 +1442,258 @@ msgstr[0] "%d zahtev na čekanju" msgstr[1] "%d zahteva na čekanju" msgstr[2] "%d zahteva na čekanju" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Usvoji paket" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Podaci o bazi paketa" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "URL za git kloniranje" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "samo za čitanje" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Ključne reči" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Pošiljalac" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Održavalac" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Poslednji paketar" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Glasovi" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Popularnost" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Prvi put priloženo" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Poslednje ažuriranje" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Uređivanje komentara za: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Dodaj komentar" +#: template/pkg_comments.php msgid "View all comments" msgstr "Prikaži sve komentare" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Izdvojeni komentari" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Poslednji komentari" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s postavi komentar %s u" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Anoniman komentar za %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "%s obrisa %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "obrisan %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "%s izmeni %s " +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "izmenjen %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Povraćeni komentar" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Obriši komentar" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Izdvoji komentar" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Odvoji komentar" +#: template/pkg_comments.php msgid "All comments" msgstr "Svi komentari" +#: template/pkg_details.php msgid "Package Details" msgstr "Podaci o paketu" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Osnova paketa" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Opis" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Uzvodni URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Poseti sajt za" +#: template/pkg_details.php msgid "Licenses" msgstr "Licence" +#: template/pkg_details.php msgid "Groups" msgstr "Grupe" +#: template/pkg_details.php msgid "Conflicts" msgstr "Sukobi" +#: template/pkg_details.php msgid "Provides" msgstr "Dostavlja" +#: template/pkg_details.php msgid "Replaces" msgstr "Smenjuje" +#: template/pkg_details.php msgid "Dependencies" msgstr "Zavisnosti" +#: template/pkg_details.php msgid "Required by" msgstr "Zahteva ga" +#: template/pkg_details.php msgid "Sources" msgstr "Izvori" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Ovim formularom zatvarate zahteve za osnovu paketa %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Polje komentara može ostati prazno. Međutim, preporučujemo da uvek dodate " -"komentar pri odbijanju zahteva." +msgstr "Polje komentara može ostati prazno. Međutim, preporučujemo da uvek dodate komentar pri odbijanju zahteva." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Razlog" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Prihvaćeno" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Odbijeno" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Ovim formularom pošaljite zahtev vezan za osnovu paketa %s%s%s koja sadrži " -"sledeće pakete:" +msgstr "Ovim formularom pošaljite zahtev vezan za osnovu paketa %s%s%s koja sadrži sledeće pakete:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Tip zahteva" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Brisanje" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Siročić" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Stopi sa" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Podnošenjem zahteva za brisanje tražili ste of poverljivog korisnika da " -"obriše bazu paketa. Ovaj tip zahteva treba koristiti za duplikate, uzvodno " -"napušten softver, kao i nelegalne ili nepopravljivo pokvarene pakete." +msgstr "Podnošenjem zahteva za brisanje tražili ste of poverljivog korisnika da obriše bazu paketa. Ovaj tip zahteva treba koristiti za duplikate, uzvodno napušten softver, kao i nelegalne ili nepopravljivo pokvarene pakete." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Podnošenjem zahteva za spajanje tražili ste of poverljivog korisnika da " -"obriše bazu paketa i spoji njene glasove sa drugom bazom paketa. Spajanje " -"paketa ne utiče na pripadajuće Git riznice. Postarajte se sami da ažurirate " -"Git istorijat ciljanog paketa." +msgstr "Podnošenjem zahteva za spajanje tražili ste of poverljivog korisnika da obriše bazu paketa i spoji njene glasove sa drugom bazom paketa. Spajanje paketa ne utiče na pripadajuće Git riznice. Postarajte se sami da ažurirate Git istorijat ciljanog paketa." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Podnošenjem zahteva za odricanje tražili ste od poverljivog korisnika da " -"izvrži odricanje od baze paketa. Molimo da ovo tražite samo ukoliko paket " -"zahteva održavanje, a održavalac je nedosupan i već ste pokušali da ga " -"kontaktirate." +msgstr "Podnošenjem zahteva za odricanje tražili ste od poverljivog korisnika da izvrži odricanje od baze paketa. Molimo da ovo tražite samo ukoliko paket zahteva održavanje, a održavalac je nedosupan i već ste pokušali da ga kontaktirate." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Nema zahteva koji odgovaraju kriterijumu pretrage." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." @@ -1368,19 +1701,24 @@ msgstr[0] "%d zahtev za paket." msgstr[1] "%d zahteva za paket." msgstr[2] "%d zahteva za paket." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Stranica %d od %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Paket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Posla" +#: template/pkgreq_results.php msgid "Date" msgstr "Datum" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" @@ -1388,6 +1726,7 @@ msgstr[0] "Preostaje još ~%d dan" msgstr[1] "Preostaje još ~%d dana" msgstr[2] "Preostaje još ~%d dana" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" @@ -1395,96 +1734,128 @@ msgstr[0] "Preostao ~%d čas" msgstr[1] "Preostala ~%d časa" msgstr[2] "Preostalo ~%d časova" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 sata preostalo" +#: template/pkgreq_results.php msgid "Accept" msgstr "Prihvati" +#: template/pkgreq_results.php msgid "Locked" msgstr "Zaključano" +#: template/pkgreq_results.php msgid "Close" msgstr "Zatvori" +#: template/pkgreq_results.php msgid "Pending" msgstr "Na čekanju" +#: template/pkgreq_results.php msgid "Closed" msgstr "Zatvoreno" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Ime, opis" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Samo ime" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Tačno ime" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Tačna osnova paketa" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Koodržavalac" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Održavalac, koodržavalac" +#: template/pkg_search_form.php msgid "All" msgstr "svi" +#: template/pkg_search_form.php msgid "Flagged" msgstr "označeni" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "neoznačeni" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Ime" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Dat glas" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Poslednja izmena" +#: template/pkg_search_form.php msgid "Ascending" msgstr "rastući" +#: template/pkg_search_form.php msgid "Descending" msgstr "opadajući" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Unesite kriterijum pretrage" +#: template/pkg_search_form.php msgid "Search by" msgstr "Traži se" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Zastareli paketi" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Složi prema" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Način ređanja" +#: template/pkg_search_form.php msgid "Per page" msgstr "Po stranici" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Idi" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Siročići" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Greška pri pruzimanju spiska paketa." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Nijedan paket ne odgovara kriterijumu pretrage." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." @@ -1492,119 +1863,278 @@ msgstr[0] "Nađen %d paket." msgstr[1] "Nađena %d paketa." msgstr[2] "Nađeno %d paketa." +#: template/pkg_search_results.php msgid "Version" msgstr "Verzija" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Popularnost se izračunava kao suma svih glasova, gde svaki glas ima teži " -"%.2f po danu od kada je dat." +msgstr "Popularnost se izračunava kao suma svih glasova, gde svaki glas ima teži %.2f po danu od kada je dat." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Da" +#: template/pkg_search_results.php msgid "orphan" msgstr "sirčoić" +#: template/pkg_search_results.php msgid "Actions" msgstr "Radnje" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Ukloni oznaku zastarelosti" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Usvoji paket" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Odrekni se paketa" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Obriši pakete" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Potvrdi" +#: template/search_accounts_form.php msgid "Any type" msgstr "Bilo koji tip" +#: template/search_accounts_form.php msgid "Search" msgstr "Pretraži" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Statistika" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Paketa siročića" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Paketa dodato u zadnjih 7 dana" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Paketa ažurirano u zadnjih 7 dana" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Paketa ažurirano prethodne godine" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Paketa koji nikad nisu ažurirani" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Registrovanih korisnika" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Poverljivih korisnika" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Nedavno ažurirano" +#: template/stats/updates_table.php msgid "more" msgstr "više" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Moja statistika" +#: template/tu_details.php msgid "Proposal Details" msgstr "Detalji predloga" +#: template/tu_details.php msgid "This vote is still running." msgstr "Glasanje u toku." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Priloženo: %s od %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Ističe" +#: template/tu_details.php msgid "Result" msgstr "Rezultat" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ne" +#: template/tu_details.php msgid "Abstain" msgstr "Uzdržan" +#: template/tu_details.php msgid "Total" msgstr "Ukupno" +#: template/tu_details.php msgid "Participation" msgstr "Učešće" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Poslednji glasovi od TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Poslednji glas" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Nema rezultata." +#: template/tu_list.php msgid "Start" msgstr "Pokrenut" +#: template/tu_list.php msgid "Back" msgstr "Nazad" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/tr.po b/po/tr.po index e87cb141..95cb4707 100644 --- a/po/tr.po +++ b/po/tr.po @@ -1,11 +1,11 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # tarakbumba , 2011,2013-2015 # tarakbumba , 2012,2014 -# Demiray Muhterem , 2015 +# Demiray “tulliana” Muhterem , 2015 # Lukas Fleischer , 2011 # Samed Beyribey , 2012 # Samed Beyribey , 2012 @@ -13,1350 +13,1679 @@ # tarakbumba , 2012 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" "Last-Translator: Lukas Fleischer \n" -"Language-Team: Turkish (http://www.transifex.com/lfleischer/aur/language/" -"tr/)\n" -"Language: tr\n" +"Language-Team: Turkish (http://www.transifex.com/lfleischer/aurweb/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: tr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +#: html/404.php msgid "Page Not Found" msgstr "Sayfa Bulunamadı" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "Üzgünüz, talep ettiğiniz sayfa bulunamadı." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Not" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Git clone linkleri bir tarayıcıda açılamazlar." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "%s'in Git deposunu kopyalamak için, %s komutunu çalıştırın." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Detaylar sayfasına %s geri dönmek için %sburaya%s tıklayınız." +#: html/503.php msgid "Service Unavailable" msgstr "Hizmete Erişilemiyor" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Paniklemeyin! Bu site bakım çalışmaları nedeniyle erişime kapatıldı. Kısa " -"süre sonra yeniden çalışmaya başlayacak" +msgstr "Paniklemeyin! Bu site bakım çalışmaları nedeniyle erişime kapatıldı. Kısa süre sonra yeniden çalışmaya başlayacak" +#: html/account.php msgid "Account" msgstr "Hesap" +#: html/account.php template/header.php msgid "Accounts" msgstr "Hesaplar" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "Bu alana erişim izniniz yok." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Belirtilen kullanıcı verileri alınamadı." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "Bu hesap üzerinde değişiklik yapma izniniz yok." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Mevcut hesaplar içinde arama yapmak için bu formu kullanın." +#: html/account.php msgid "You must log in to view user information." msgstr "Kullanıcı bilgilerini görmek için giriş yapmalısınız." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Öneri ekle" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Kullanıcı işlemi için geçersiz anahtar." +#: html/addvote.php msgid "Username does not exist." msgstr "Kullanıcı adı bulunamadı." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s için yürürlükte olan bir öneri var." +#: html/addvote.php msgid "Invalid type." msgstr "Geçersiz tür." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Öneri boş olamaz." +#: html/addvote.php msgid "New proposal submitted." msgstr "Yeni öneri gönderildi." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Oylanması için öneri gönder." +#: html/addvote.php msgid "Applicant/TU" msgstr "İstekli/TU" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(uygulanabilir değilse boş)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Tür" +#: html/addvote.php msgid "Addition of a TU" msgstr "Bir GK ekleme" +#: html/addvote.php msgid "Removal of a TU" msgstr "Bir GK çıkartma" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Bir GK çıkartma (bildirilmemiş hareketsizlik)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Amendment of Bylaws" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Öneri" +#: html/addvote.php msgid "Submit" msgstr "Gönder" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Yardımcı bakımcıları Yönet" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Yorumu düzenle" +#: html/home.php template/header.php msgid "Dashboard" msgstr "" +#: html/home.php template/header.php msgid "Home" msgstr "Anasayfa" +#: html/home.php msgid "My Flagged Packages" msgstr "" +#: html/home.php msgid "My Requests" msgstr "" +#: html/home.php msgid "My Packages" msgstr "Paketlerim" +#: html/home.php msgid "Search for packages I maintain" msgstr "" +#: html/home.php msgid "Co-Maintained Packages" msgstr "" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"AUR'a hoş geldiniz! Bilgi almak için lütfen %sAUR Kullanıcı Rehberi%s ve " -"%sGK Rehberini%s okuyun." +msgstr "AUR'a hoş geldiniz! Bilgi almak için lütfen %sAUR Kullanıcı Rehberi%s ve %sGK Rehberini%s okuyun." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Eklenen PKGBUILD dosyaları %smutlaka%s %sArch Paket Standartlarına%s " -"uymalıdır aksi takdirde silinecektir. " +msgstr "Eklenen PKGBUILD dosyaları %smutlaka%s %sArch Paket Standartlarına%s uymalıdır aksi takdirde silinecektir. " +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Beğendiğiniz paketleri oylamayı unutmayın!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" -"Burada listelenen paketlerin bazıları [community] deposunda yer almaktadır." +msgstr "Burada listelenen paketlerin bazıları [community] deposunda yer almaktadır." +#: html/home.php msgid "DISCLAIMER" msgstr "FERAGATNAME" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"AUR paketleri kullanıcılar tarafından üretilirler. Bu paketlerin herhangi " -"bir risk taşıyabileceğini unutmayın." +msgstr "AUR paketleri kullanıcılar tarafından üretilirler. Bu paketlerin herhangi bir risk taşıyabileceğini unutmayın." +#: html/home.php msgid "Learn more..." msgstr "Daha fazlasını öğrenin..." +#: html/home.php msgid "Support" msgstr "Destek" +#: html/home.php msgid "Package Requests" msgstr "Paket Talepleri" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Paket ayrıntıları sayfasındaki %sPaket Eylemleri%s kutusunda " -"doldurulabilecek üç tür talep vardır:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Paket ayrıntıları sayfasındaki %sPaket Eylemleri%s kutusunda doldurulabilecek üç tür talep vardır:" +#: html/home.php msgid "Orphan Request" msgstr "Sahipsiz Bırakma Talebi" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Bir paketin sahipliğinin bırakılması talebi, mesela bakımcısının etkin " -"olmaması ve paketin uzun zamandır güncel değil olarak işaretlenmiş olması." +msgstr "Bir paketin sahipliğinin bırakılması talebi, mesela bakımcısının etkin olmaması ve paketin uzun zamandır güncel değil olarak işaretlenmiş olması." +#: html/home.php msgid "Deletion Request" msgstr "Silme Talebi" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Bir paketin Arch Kullanıcı Deposundan kaldırılması talebidir. Lütfen bunu, " -"bir paket çalışmıyor fakat kolayca düzeltilebiliyorsa kullanmayın. Bunun " -"yerine, paket bakımcısı ile iletişim kurun ve mecbur kalınırsa paketin " -"sahipsiz bırakılması talebinde bulunun." +msgstr "Bir paketin Arch Kullanıcı Deposundan kaldırılması talebidir. Lütfen bunu, bir paket çalışmıyor fakat kolayca düzeltilebiliyorsa kullanmayın. Bunun yerine, paket bakımcısı ile iletişim kurun ve mecbur kalınırsa paketin sahipsiz bırakılması talebinde bulunun." +#: html/home.php msgid "Merge Request" msgstr "Birleştirme Talebi" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Bir paketin bir başkası ile birleştirilmesi talebidir. Bir paketin yeniden " -"adlandırılması veya bir ayrılmış paketle değiştirilmesi gerekiyorsa " -"kullanılabilir." +msgstr "Bir paketin bir başkası ile birleştirilmesi talebidir. Bir paketin yeniden adlandırılması veya bir ayrılmış paketle değiştirilmesi gerekiyorsa kullanılabilir." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Bir talep hakkında tartışmak istiyorsanız, %saur-requests%s e-posta " -"listesini kullanabilirsiniz. Bununla birlikte o e-posta listesini dosya " -"talepleri için kullanmamalısınız." +msgstr "Bir talep hakkında tartışmak istiyorsanız, %saur-requests%s e-posta listesini kullanabilirsiniz. Bununla birlikte o e-posta listesini dosya talepleri için kullanmamalısınız." +#: html/home.php msgid "Submitting Packages" msgstr "Paketleri göndermek" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Artık AUR' a paket göndermek için SSH üzerinden Git kullanılmaktadır. Daha " -"fazla bilgi için Arch Kullanıcı Deposu ArchWiki sayfasındaki %sPaketleri " -"Göndermek%s bölümüne bakın." +msgstr "Artık AUR' a paket göndermek için SSH üzerinden Git kullanılmaktadır. Daha fazla bilgi için Arch Kullanıcı Deposu ArchWiki sayfasındaki %sPaketleri Göndermek%s bölümüne bakın." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR için şu SSH parmak izleri kullanılmaktadır:" +#: html/home.php msgid "Discussion" msgstr "Tartışma" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Arch Kullanıcı Deposu (AUR) ve Güvenilir Kullanıcı yapısı ile ilgili genel " -"tartışmalar %saur-general%s üzerinde yapılır. AUR web arayüzü geliştirme " -"süreci ilgili tartışmalar %saur-dev%s listesinde yapılmaktadır." +msgstr "Arch Kullanıcı Deposu (AUR) ve Güvenilir Kullanıcı yapısı ile ilgili genel tartışmalar %saur-general%s üzerinde yapılır. AUR web arayüzü geliştirme süreci ilgili tartışmalar %saur-dev%s listesinde yapılmaktadır." +#: html/home.php msgid "Bug Reporting" msgstr "Hata Bildirimi" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." msgstr "" +#: html/home.php msgid "Package Search" msgstr "Paket Ara" +#: html/index.php msgid "Adopt" msgstr "Sorumluluğunu Al" +#: html/index.php msgid "Vote" msgstr "Oy ver" +#: html/index.php msgid "UnVote" msgstr "Oyu kaldır" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Bilgilendirme" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Bildirimi iptal et" +#: html/index.php msgid "UnFlag" msgstr "İşareti Kaldır" +#: html/login.php template/header.php msgid "Login" msgstr "Giriş" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "%s olarak giriş yapıldı" +#: html/login.php template/header.php msgid "Logout" msgstr "Çıkış" +#: html/login.php msgid "Enter login credentials" msgstr "Giriş bilgilerinizi doldurun" +#: html/login.php msgid "User name or email address" msgstr "Kullanıcı adı veya e-posta adresi" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Parola" +#: html/login.php msgid "Remember me" msgstr "Beni hatırla" +#: html/login.php msgid "Forgot Password" msgstr "Parolamı Unuttum" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"HTTP oturum açma devredışı. Lütfen oturum açmak için %sHTTPS kullanın%s." +msgstr "HTTP oturum açma devredışı. Lütfen oturum açmak için %sHTTPS kullanın%s." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Arama Ölçütü" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Paketler" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Paket ayrıntılarını almaya çalışırken hata oluştu." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Gerekli bir alan doldurulmamış." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Parolalar eşleşmiyor." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Şifreniz en az %s karakterden oluşmalıdır." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Geçersiz e-posta adresi" +#: html/passreset.php msgid "Password Reset" msgstr "Parola sıfırlama" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Onaylama bağlantısı için e-posta hesabınızı denetleyin." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Parolanız başarıyla sıfırlandı." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "E-posta adresinizi onaylayın:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Yeni parolanızı girin:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Yeni parolanızı onaylayın:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Devam" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Kayıt olurken kullandığınız e-posta adresini hatırlamıyorsanız lütfen %saur-" -"general%s posta listesine mesaj gönderin." +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Kayıt olurken kullandığınız e-posta adresini hatırlamıyorsanız lütfen %saur-general%s posta listesine mesaj gönderin." +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "E-posta adresinizi girin:" +#: html/pkgbase.php msgid "Package Bases" msgstr "" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." -msgstr "" -"Seçilen paketler için sahiplik bırakılamadı. Onaylama kutucuğunu işaretleyin." +msgstr "Seçilen paketler için sahiplik bırakılamadı. Onaylama kutucuğunu işaretleyin." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." -msgstr "" -"Oyların ve yorumların ilişkilendirilebileceği herhangi bir paket bulunamadı." +msgstr "Oyların ve yorumların ilişkilendirilebileceği herhangi bir paket bulunamadı." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Paket temeli kendisi ile birleştirilemiyor." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "Seçilen paketler silinmedi. Onaylama kutucuğunu işaretleyin." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Paket Silimi" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Paketi Sil" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Bu formu paket temeli %s%s%s ve şu paketleri AUR üzerinden silmek için " -"kullanın: " +msgstr "Bu formu paket temeli %s%s%s ve şu paketleri AUR üzerinden silmek için kullanın: " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Paket silme işlemi kalıcıdır." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "İşlemi onaylamak için kutucuğu işaretleyin." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Paket silmeyi onaylayın" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Sil" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paket silebilir." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Paket Sahipliğini Bırak" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Şu paketleri içeren %s%s%s paket temelinin sahipliğini bırakmak için bu " -"formu kullanın:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Şu paketleri içeren %s%s%s paket temelinin sahipliğini bırakmak için bu formu kullanın:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"İşaretleme kutucuğunu seçerek paketin sahipliğini bırakmayı ve sahipliği %s%s" -"%s üzerine geçirmeyi kabul ediyorsunuz." +msgstr "İşaretleme kutucuğunu seçerek paketin sahipliğini bırakmayı ve sahipliği %s%s%s üzerine geçirmeyi kabul ediyorsunuz." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." -msgstr "" -"Kutucuğu işaretleyerek paketin sahipliğini bırakmayı kabul ediyorsunuz." +msgstr "Kutucuğu işaretleyerek paketin sahipliğini bırakmayı kabul ediyorsunuz." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Paket sahipliğini bırakmayı onayla" +#: html/pkgdisown.php msgid "Disown" msgstr "Sorumluluğunu bırak" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Sadece geliştiriciler ve güvenilir kullanıcılar paketleri sahipsiz " -"bırakabilir." +msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paketleri sahipsiz bırakabilir." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Yorumu İşaretle" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Paketi güncel değil olarak işaretle" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Paketin neden güncel olmadığıyla ilgili detayları aşağıya girin, tercihen " -"sürüm bildirilerinin veya yeni tarball sürümünün linklerini dahil ederek." +msgstr "Paketin neden güncel olmadığıyla ilgili detayları aşağıya girin, tercihen sürüm bildirilerinin veya yeni tarball sürümünün linklerini dahil ederek." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Yorumlar" +#: html/pkgflag.php msgid "Flag" msgstr "İşaretle" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"Sadece kayıtlı kullanıcılar paketleri güncel değil olarak işaretleyebilir." +msgstr "Sadece kayıtlı kullanıcılar paketleri güncel değil olarak işaretleyebilir." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Paket birleştirme" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Paketi Birleştir" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Bu formu paket temeli %s%s%s ile bir başka paketi birleştirmek için " -"kullanın. " +msgstr "Bu formu paket temeli %s%s%s ile bir başka paketi birleştirmek için kullanın. " +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Şu paketler silinecek: " +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Paket birleştirme işlemi geri alınamaz." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Birleştirmek istediğiniz paketin ismini girin." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Şununla birleştir:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Paket birleştirme onayı" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Birleştir" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Sadece geliştiriciler ve güvenilir kullanıcılar paket birleştirebilir." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Kapama Talebi" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "İlk" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Önceki" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "İleri" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Son" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Talepler" +#: html/register.php template/header.php msgid "Register" msgstr "Kayıt ol" +#: html/register.php msgid "Use this form to create an account." msgstr "Yeni bir hesap oluşturmak için bu formu kullanın." +#: html/tos.php msgid "Terms of Service" msgstr "" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "" +#: html/tos.php #, php-format msgid "revision %d" msgstr "" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Güvenilen Kullanıcı" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Öneri detayları alınamadı." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Bu öneri için oylama kapanmıştır." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Sadece Güvenilir Kullanıcılar oy kullanabilir." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Sizin hakkınızdaki bir öneride oy kullanamazsınız." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Bu öneri için zaten oy vermişsiniz." +#: html/tu.php msgid "Vote ID not valid." msgstr "Oy kimliği geçersiz." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Mevcut Oylar" +#: html/tu.php msgid "Past Votes" msgstr "Geçmiş Oylar" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Oy verenler" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden hesap " -"oluşturma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +msgstr "Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden hesap oluşturma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Kullanıcı kimliği eksik" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Bu kullanıcı adı geçersizdir." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Uzunluğu %s ve %s karakter arasında olabilir." +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Bir rakam veya harf ile başlatıp bitirmelisiniz" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Sadece bir nokta, alt çizgi veya tire barındırabilir." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-posta adresi geçerli değil." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP anahtarı parmak izi hatalı." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH kamu anahtarı geçersiz." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Hesap izinleri yükseltilemiyor." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Dil henüz desteklenmiyor." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Kullanıcı adı, %s%s%s, zaten kullanılıyor." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Adres, %s%s%s, zaten kullanılıyor." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH kamu anahtarı, %s%s%s, zaten kullanımda." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Hesap oluşturulurken hata oluştu, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Hesap, %s%s%s, başarıyla oluşturuldu." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Bir parola sıfırlama anahtarı e-posta adresinize gönderildi." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "Hesabınızı kullanmak için Giriş bağlantısını kullanın." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Hesapta değişiklik yapılmadı, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Hesap, %s%s%s, başarıyla düzenlendi." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden giriş " -"yapma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +msgstr "Muhtemelen sürekli spam saldırıları olması nedeniyle IP adresinizden giriş yapma devre dışı bırakılmış. Bu durumdan dolayı üzgünüz." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Hesap donduruldu" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Parolanız sıfırlandı. Kısa süre önce yeni hesap oluşturduysanız lütfen, ilk " -"parolanızı ayarlamak için onaylama e-postasındaki bağlantıyı kullanın. Aksi " -"takdirde, %sParola Sıfırlama%s sayfasında bir sıfırlama anahtarı talep edin." +msgstr "Parolanız sıfırlandı. Kısa süre önce yeni hesap oluşturduysanız lütfen, ilk parolanızı ayarlamak için onaylama e-postasındaki bağlantıyı kullanın. Aksi takdirde, %sParola Sıfırlama%s sayfasında bir sıfırlama anahtarı talep edin." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Yanlış kullanıcı adı veya şifresi." +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Bir kullanıcı oturumu üretilmeye çalışılırken sorun oluştu." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Geçersiz e-posta adresi ve sıfırlama anahtarı bileşimi" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Yok" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "%s için hesap bilgilerini görüntüle" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "Paket ID'si veya paket ismi eksik." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "Bu yorumu düzenlemek için yetkiniz yok." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Yorum bulunamadı." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Yorum boş olamaz." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Yorum eklendi." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "Paket bilgilerini güncellemek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Yorum kimliği bulunamadı." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "5 taneden fazla yorum iğnelenemez." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Bu yorumu iğnelemek için yetkiniz yok." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Yorum iğnelendi." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Paket bilgileri alınırken hata oluştu." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Paket ayrıntıları bulunamadı." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Paketleri işaretleyebilmek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "İşaretlenecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "Seçilen paketler işaretlenmedi, lütfen bir yorum giriniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Seçilen paketler güncelliğini yitirmiş olarak işaretlendi." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Paketlerin işaretini kaldırabilmek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "İşareti kaldırılacak paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "Seçilen paketlerin işareti kaldırıldı." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "Paket silmek için gerekli izne sahip değilsiniz." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Silinecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Seçilen paketler silindi." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Paketleri sahiplenmek için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Paketlerin sahipliğini bırakmak için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Sahiplenilecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Sahipliği bırakılacak paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Seçilen paketler sahiplenildi." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Seçilen paketlerin sahipliği bırakıldı." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Paketlere oy vermeden önce giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Oy iptali için giriş yapmalısınız." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Oy verilecek paketleri seçmediniz." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Seçtiğiniz paketlerden oyunuz geri alındı." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Seçtiğiniz paketlere oyunuz eklendi." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Bildirim listesine ekleme işlemi başarısız oldu." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "%s bildirim listesine başarıyla eklendiniz." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "%s bildirim listesinden başarıyla çıktınız." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Bu silinmiş yorumu geri almak için yetkili değilsiniz." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Yorum silindi." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "Bu yorumu silme yetkiniz yok." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Yorum silindi." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Yorum düzenlendi." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." -msgstr "" -"Bu paket temelinin anahtar kelimelerini düzenleme yetkisine sahip değilsiniz." +msgstr "Bu paket temelinin anahtar kelimelerini düzenleme yetkisine sahip değilsiniz." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Paket temeli anahtar kelimeleri güncellendi." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." -msgstr "" -"Bu paket temelinin yardımcı bakımcılarını yönetme yetkisine sahip değilsiniz." +msgstr "Bu paket temelinin yardımcı bakımcılarını yönetme yetkisine sahip değilsiniz." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Geçersiz kullanıcı adı: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Paket temeli yardımcı bakımcıları güncellendi." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Paket detaylarını görüntüle" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "%s'ye ihtiyaç duyuyor." +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Paket gereksinimlerinin kaydını tutmalısın." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Geçersiz isim: yalnızca küçük harf kullanılabilir." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Yorum alanı boş olmamalı." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Geçersiz talep türü." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Talep başarıyla eklendi." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Geçersiz sebep." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Sadece GK'lar ve geliştiriciler talepleri kapatabilirler." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Talep başarıyla kapatıldı." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Bu formu kullanarak %s AUR hesabını temelli silebilirsiniz." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sUYARI%s: Bu eylem geri döndürülemez." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Silmeyi onayla" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Kullanıcı Adı" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Hesap Türü" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Kullanıcı" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Geliştirici" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Güvenilir Kullanıcı & Geliştirici" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "E-posta adresi" +#: template/account_details.php msgid "hidden" msgstr "gizli" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Gerçek İsim" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Anasayfa" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC Rumuzu" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP Anahtar Parmak İzi" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Durum" +#: template/account_details.php msgid "Inactive since" msgstr "Şu tarihten beri etkin değil:" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Etkin" +#: template/account_details.php msgid "Registration date:" msgstr "Kayıt tarihi:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "bilinmiyor" +#: template/account_details.php msgid "Last Login" msgstr "Son giriş" +#: template/account_details.php msgid "Never" msgstr "Hiç" +#: template/account_details.php msgid "View this user's packages" msgstr "Bu kullanıcı tarafından hazırlanan paketleri göster" +#: template/account_details.php msgid "Edit this user's account" msgstr "Bu kullanıcının hesabını düzenleyin" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Bu hesabı temelli olarak silmek istiyorsanız %sburaya%s tıklayın." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Kullanıcı detayları için %sburaya%s tıklayın." +#: template/account_edit_form.php msgid "required" msgstr "gerekli" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Normal kullanıcı" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Güvenilen kullanıcı" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Hesap Donduruldu" +#: template/account_edit_form.php msgid "Inactive" msgstr "Etkin değil" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Lütfen e-posta adresinizi doğru girdiğinizden emin olun, aksi halde " -"hesabınız kilitlenecektir." +msgstr "Lütfen e-posta adresinizi doğru girdiğinizden emin olun, aksi halde hesabınız kilitlenecektir." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "E-posta Adresini Gizle" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Parolayı tekrar girin" +#: template/account_edit_form.php msgid "Language" msgstr "Dil" +#: template/account_edit_form.php msgid "Timezone" msgstr "" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Aşağıdaki bilgi sadece Arch Kullanıcı Deposu' na paket göndermek " -"istiyorsanız gereklidir." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Aşağıdaki bilgi sadece Arch Kullanıcı Deposu' na paket göndermek istiyorsanız gereklidir." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH Kamu Anahtarı" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Bildirim ayarları" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Yeni yorumları bildir" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Paket güncellemelerini bildir" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Sahiplik değişikliklerini bildir." +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Güncelle" +#: template/account_edit_form.php msgid "Create" msgstr "Oluştur" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Sıfırla" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "Arama ölçütünzle eşleşen bir sonuç bulunamadı." +#: template/account_search_results.php msgid "Edit Account" msgstr "Hesap Bilgilerini Düzenle" +#: template/account_search_results.php msgid "Suspended" msgstr "Donduruldu" +#: template/account_search_results.php msgid "Edit" msgstr "Düzenle" +#: template/account_search_results.php msgid "Less" msgstr "Az" +#: template/account_search_results.php msgid "More" msgstr "Fazla" +#: template/account_search_results.php msgid "No more results to display." msgstr "Gösterilecek daha fazla sonuç yok." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"%s%s%s için yardımcı bakımcı eklemek istiyorsanız bu formu kullannı (her " -"satırda bir kullanıcı adı):" +msgstr "%s%s%s için yardımcı bakımcı eklemek istiyorsanız bu formu kullannı (her satırda bir kullanıcı adı):" +#: template/comaintainers_form.php msgid "Users" msgstr "Kullanıcılar" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Kaydet" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Güncel olmayan olarak işaretli yorum: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s güncel değil olarak işaretlenmedi." +#: template/flag_comment.php msgid "Return to Details" msgstr "Detaylara Geri Dön." +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "" +#: template/header.php msgid " My Account" msgstr "Hesabım" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Paket Eylemleri" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "PKGBUILD görüntüle" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Değişiklikleri Görüntüle" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Anlık görüntüsünü indir" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Wikide ara" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Güncel değil olarak işaretlendi (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Güncelliğini yitirmiş olarak işaretle" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "İşareti kaldır" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Oyu kaldır" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Pakete oy ver" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Bildirimleri kapat" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Bildirimleri etkinleştir" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Yardımcı Bakımcıları Yönet" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d adet bekleyen talep" msgstr[1] "%d adet bekleyen talep" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Paketi Sahiplen" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Paket Temeli Ayrıntıları" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "salt okunur" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Anahtar kelimeler" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Yükleyen" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Sorumlu" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Son Paketleyici" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Oy" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Beğenilme" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "İlk Yükleme" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Son Güncelleme" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Yorumu düzenle: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Yorum Ekle" +#: template/pkg_comments.php msgid "View all comments" msgstr "Tüm yorumları görünüle" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "İğnelenmiş Yorumlar" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Son Yorumlar" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s, %s'e yorum yaptı." +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "%s'e isimsiz yorum" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "%s'te, %s tarafından silindi." +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "%s'te silindi." +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "%s'te, %s tarafından düzenlendi" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "%s'te düzenlendi." +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Yorumu silmeyi geri al." +#: template/pkg_comments.php msgid "Delete comment" msgstr "Yorumu sil" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Yorumu iğnele" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "" +#: template/pkg_comments.php msgid "All comments" msgstr "Tüm yorumlar" +#: template/pkg_details.php msgid "Package Details" msgstr "Paket Ayrıntıları" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "Paket Temeli" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Açıklama" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Geliştiricinin Bağlantısı" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Web sayfasını görüntüle" +#: template/pkg_details.php msgid "Licenses" msgstr "Lisanslar" +#: template/pkg_details.php msgid "Groups" msgstr "Gruplar" +#: template/pkg_details.php msgid "Conflicts" msgstr "Çakışır" +#: template/pkg_details.php msgid "Provides" msgstr "Sunar" +#: template/pkg_details.php msgid "Replaces" msgstr "Yerini alır" +#: template/pkg_details.php msgid "Dependencies" msgstr "Bağımlılıklar" +#: template/pkg_details.php msgid "Required by" msgstr "İhtiyaç duyanlar" +#: template/pkg_details.php msgid "Sources" msgstr "Kaynak kodlar" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "" -"Bu formu %s%s%s paket temeli için yapılan talebi kapatmak için kullanın." +msgstr "Bu formu %s%s%s paket temeli için yapılan talebi kapatmak için kullanın." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Yorum alanı boş bırakılabilir. Ancak, bir talebi reddederken bir yorum " -"eklemeniz şiddetle önerilir." +msgstr "Yorum alanı boş bırakılabilir. Ancak, bir talebi reddederken bir yorum eklemeniz şiddetle önerilir." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Sebep" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Kabul edildi" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Reddedildi" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Bu formu kullanarak aşağıdaki paketleri içeren paket temeli %s%s%s için " -"talep doldurun:" +msgstr "Bu formu kullanarak aşağıdaki paketleri içeren paket temeli %s%s%s için talep doldurun:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Talep türü" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Silme" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Öksüz" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Şununla ilişkilendir:" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Silme talebi göndererek, Güvenilir Kullanıcıdan paketi silmesini " -"istiyorsunuz. Bu tür bir istek birden fazla olan paketlerde, geliştirilmesi " -"durdurulmuş yazılımlarda, ve aynı zamanda yasadışı ve onarılamaz bozuklukta " -"olan paketler için kullanılmalıdır." +msgstr "Silme talebi göndererek, Güvenilir Kullanıcıdan paketi silmesini istiyorsunuz. Bu tür bir istek birden fazla olan paketlerde, geliştirilmesi durdurulmuş yazılımlarda, ve aynı zamanda yasadışı ve onarılamaz bozuklukta olan paketler için kullanılmalıdır." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Birleştirme talebi göndererek, Güvenilir Kullanıcıdan paketi silmesini ve bu " -"paketin oylarını ve yorumlarını diğer pakete transfer etmesini istiyorsunuz. " -"Bir paketi birleştirmek ilgili Git deposunu etkilemeyecektir. Hedef paketin " -"Git geçmişini bizzat güncellediğinizden emin olun. " +msgstr "Birleştirme talebi göndererek, Güvenilir Kullanıcıdan paketi silmesini ve bu paketin oylarını ve yorumlarını diğer pakete transfer etmesini istiyorsunuz. Bir paketi birleştirmek ilgili Git deposunu etkilemeyecektir. Hedef paketin Git geçmişini bizzat güncellediğinizden emin olun. " +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " @@ -1364,249 +1693,448 @@ msgid "" "previously." msgstr "" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d adet paket talebi bulundu." msgstr[1] "%d adet paket talebi bulundu." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Sayfa %d / %d" +#: template/pkgreq_results.php msgid "Package" msgstr "Paket" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Dolduran" +#: template/pkgreq_results.php msgid "Date" msgstr "Tarih" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d gün kaldı" msgstr[1] "~%d gün kaldı" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d saat kaldı" msgstr[1] "~%d saat kaldı" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 saat kaldı" +#: template/pkgreq_results.php msgid "Accept" msgstr "Kabul" +#: template/pkgreq_results.php msgid "Locked" msgstr "Kilitli" +#: template/pkgreq_results.php msgid "Close" msgstr "Kapat" +#: template/pkgreq_results.php msgid "Pending" msgstr "" +#: template/pkgreq_results.php msgid "Closed" msgstr "Kapandı" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "İsim, Açıklama" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Sadece İsim" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Tam Ad" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Tam Paket Temeli" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "" +#: template/pkg_search_form.php msgid "All" msgstr "Tümü" +#: template/pkg_search_form.php msgid "Flagged" msgstr "İşaretlenmiş" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "İşaretlenmemiş" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "İsim" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Oylanmış" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Son düzenleme" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Eskiden yeniye" +#: template/pkg_search_form.php msgid "Descending" msgstr "Yeniden eskiye" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Arama kriteri girin" +#: template/pkg_search_form.php msgid "Search by" msgstr "Buna göre ara" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Güncelliğini Yitirmiş" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Sırala" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Sıralama düzeni" +#: template/pkg_search_form.php msgid "Per page" msgstr "Her sayfa" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Git" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Sahipsiz" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Paket listesi alınırken hata oluştu." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "Arama ölçütünüz ile eşleşen paket bulunamadı." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d adet paket bulundu." msgstr[1] "%d adet paket bulundu." +#: template/pkg_search_results.php msgid "Version" msgstr "Sürüm" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Popülarite, oluşturulmasından itibaren günlük %.2f oranı ile " -"ağırlaştırılarak bulunan her oyun toplamı ile ölçülür." +msgstr "Popülarite, oluşturulmasından itibaren günlük %.2f oranı ile ağırlaştırılarak bulunan her oyun toplamı ile ölçülür." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Evet" +#: template/pkg_search_results.php msgid "orphan" msgstr "sahipsiz" +#: template/pkg_search_results.php msgid "Actions" msgstr "Eylemler" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "\"Güncelliğini Yitirmiş\" İşaretini Kaldır" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Paketleri Sahiplen" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Paketleri sahiplenmeyi bırak" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Paketleri Sil" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Onayla" +#: template/search_accounts_form.php msgid "Any type" msgstr "Herhangi bir tür" +#: template/search_accounts_form.php msgid "Search" msgstr "Ara" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "İstatistikler" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Sahipsiz Paketler" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Son 7 günde eklenen paketler" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Son 7 günde güncellenen paketler" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Geçtiğimiz yıl güncellenen paketler" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Hiç güncellenmemiş paketler" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Kayıtlı Kullanıcılar" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Güvenilen Kullanıcılar" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Son Güncellemeler" +#: template/stats/updates_table.php msgid "more" msgstr "" +#: template/stats/user_table.php msgid "My Statistics" msgstr "İstatistiklerim" +#: template/tu_details.php msgid "Proposal Details" msgstr "Öneri Detayları" +#: template/tu_details.php msgid "This vote is still running." msgstr "Bu oylama hala yürürlükte." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Yüklendi: %s %s tarafından" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Son" +#: template/tu_details.php msgid "Result" msgstr "Sonuç" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Hayır" +#: template/tu_details.php msgid "Abstain" msgstr "Çekimser" +#: template/tu_details.php msgid "Total" msgstr "Toplam" +#: template/tu_details.php msgid "Participation" msgstr "Katkı" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "GK tarafından verilen son oylar" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Son Oy" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Sonuç bulunamadı." +#: template/tu_list.php msgid "Start" msgstr "Başlangıç" +#: template/tu_list.php msgid "Back" msgstr "Geri" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" diff --git a/po/uk.po b/po/uk.po index ab034a21..b4ec36d0 100644 --- a/po/uk.po +++ b/po/uk.po @@ -1,1629 +1,2147 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Lukas Fleischer , 2011 # Rax Garfield , 2012 # Rax Garfield , 2012 -# Yarema aka Knedlyk , 2011-2017 +# Yarema aka Knedlyk , 2011-2018 # Данило Коростіль , 2011 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-29 13:25+0000\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-25 20:15+0000\n" "Last-Translator: Yarema aka Knedlyk \n" -"Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aur/language/" -"uk/)\n" -"Language: uk\n" +"Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aurweb/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Language: uk\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" +#: html/404.php msgid "Page Not Found" msgstr "Сторінку не знайдено" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "На жаль, запитаної сторінки не існує." +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "Примітка" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" -"Посилання на клонування сховища Git не вдасться відкрити в переглядарці." +msgstr "Посилання на клонування сховища Git не вдасться відкрити в переглядарці." +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "Щоб клонувати сховище Git з %s, виконайте %s." +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "Клацніть %sтут%s для повернення на сторінку інформації %s." +#: html/503.php msgid "Service Unavailable" msgstr "Сервіс недоступний" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" -"Не панікуйте! Сторінка закрита на технічне обслуговування. Ми швидко " -"повернемося." +msgstr "Не панікуйте! Сторінка закрита на технічне обслуговування. Ми швидко повернемося." +#: html/account.php msgid "Account" msgstr "Обліковий запис" +#: html/account.php template/header.php msgid "Accounts" msgstr "Облікові записи" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "У вас недостатньо прав доступу." +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "Не вдалося отримати інформацію про вказаного користувача." +#: html/account.php msgid "You do not have permission to edit this account." msgstr "У вас недостатньо прав для редагування цього облікового запису." +#: html/account.php msgid "Use this form to search existing accounts." msgstr "Шукайте облікові записи за допомогою цієї форми." +#: html/account.php msgid "You must log in to view user information." msgstr "Ви повинні увійти в систему для перегляду даних користувача." +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "Додати пропозицію" +#: html/addvote.php msgid "Invalid token for user action." msgstr "Невірний маркер для дій користувача." +#: html/addvote.php msgid "Username does not exist." msgstr "Користувача не існує." +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s вже мають зареєстровану на себе пропозицію." +#: html/addvote.php msgid "Invalid type." msgstr "Неправильний тип." +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "Пропозиція не може бути порожньою." +#: html/addvote.php msgid "New proposal submitted." msgstr "Нову пропозицію надіслано." +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "Надіслати пропозицію для голосування." +#: html/addvote.php msgid "Applicant/TU" msgstr "Претендент/Довірений користувач" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(Порожньо, якщо не застосовується)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "Тип" +#: html/addvote.php msgid "Addition of a TU" msgstr "Додавання довіреного користувача" +#: html/addvote.php msgid "Removal of a TU" msgstr "Вилучення довіреного користувача" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "Вилучення довіреного користувача (неоголошена бездіяльність)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "Поправки до Статуту" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "Пропозиція" +#: html/addvote.php msgid "Submit" msgstr "Надіслати пакунок" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "Керування ко-супровідниками" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "Редагувати коментар" +#: html/home.php template/header.php msgid "Dashboard" msgstr "Панель знарядь" +#: html/home.php template/header.php msgid "Home" msgstr "Початкова сторінка" +#: html/home.php msgid "My Flagged Packages" msgstr "Мої відмічені пакунки" +#: html/home.php msgid "My Requests" msgstr "Мої запити" +#: html/home.php msgid "My Packages" msgstr "Мої пакунки" +#: html/home.php msgid "Search for packages I maintain" msgstr "Пошук пакунків які я підтримую" +#: html/home.php msgid "Co-Maintained Packages" msgstr "Пакунки з сумісним супроводом" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "Пошук пакунків з сумісним супроводом" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"Раді вітати вас в «AUR» — у сховищі користувацьких пакунків. Розширена " -"довідка надана в %sінструкції користувача AUR%s та %sінструкції довіреного " -"користувача (TU) AUR%s." +msgstr "Раді вітати вас в «AUR» — у сховищі користувацьких пакунків. Розширена довідка надана в %sінструкції користувача AUR%s та %sінструкції довіреного користувача (TU) AUR%s." +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"Надіслані PKGBUILD %sповинні%s задовольняти %sстандарти пакування%s, інакше " -"вони вилучаються." +msgstr "Надіслані PKGBUILD %sповинні%s задовольняти %sстандарти пакування%s, інакше вони вилучаються." +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "Не забудьте проголосувати за улюблені пакунки!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "Деякі пакунки можуть бути в бінарному вигляді у сховищі [community]." +#: html/home.php msgid "DISCLAIMER" msgstr "ВІДМОВА ВІД ВІДПОВІДАЛЬНОСТІ" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" -"Пакунки у сховищі AUR - це пакунки, створені користувачами. Ви можете " -"використовувати їх тільки на Ваш власний страх і ризик." +msgstr "Пакунки у сховищі AUR - це пакунки, створені користувачами. Ви можете використовувати їх тільки на Ваш власний страх і ризик." +#: html/home.php msgid "Learn more..." msgstr "Дізнатись більше..." +#: html/home.php msgid "Support" msgstr "Підтримка" +#: html/home.php msgid "Package Requests" msgstr "Запит щодо пакунку" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" -msgstr "" -"Існують три типи запитів, які можна створити в полі %sДія над пакунком%s на " -"сторінці подробиць пакунку:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" +msgstr "Існують три типи запитів, які можна створити в полі %sДія над пакунком%s на сторінці подробиць пакунку:" +#: html/home.php msgid "Orphan Request" msgstr "Запит щодо покинення пакунку" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"Запит щодо позбавлення пакунка власника, наприклад, коли супровідник пакунку " -"неактивний і пакунок позначений як застарілий вже довгий період часу." +msgstr "Запит щодо позбавлення пакунка власника, наприклад, коли супровідник пакунку неактивний і пакунок позначений як застарілий вже довгий період часу." +#: html/home.php msgid "Deletion Request" msgstr "Запит щодо вилучення" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"Запит щодо вилучення пакунку зі Сховища Користувацьких Пакунків AUR. Будь " -"ласка, не використовуйте його, якщо пакунок містить ваду, яку можна легко " -"виправити. Для цього зв’яжіться з супровідником пакунку і заповніть форму на " -"покинення пакунку в разі необхідності." +msgstr "Запит щодо вилучення пакунку зі Сховища Користувацьких Пакунків AUR. Будь ласка, не використовуйте його, якщо пакунок містить ваду, яку можна легко виправити. Для цього зв’яжіться з супровідником пакунку і заповніть форму на покинення пакунку в разі необхідності." +#: html/home.php msgid "Merge Request" msgstr "Запит щодо злиття" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"Запит щодо злиття пакунку з іншим пакунком. Цей запит можна використати, " -"коли потрібно перейменувати пакунок або замінити на розділений пакунок." +msgstr "Запит щодо злиття пакунку з іншим пакунком. Цей запит можна використати, коли потрібно перейменувати пакунок або замінити на розділений пакунок." +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"Якщо Ви бажаєте обговорити запит, використайте список розсилки %saur-requests" -"%s. Будь ласка, не використовуйте цю розсилку для подання запитів." +msgstr "Якщо Ви бажаєте обговорити запит, використайте список розсилки %saur-requests%s. Будь ласка, не використовуйте цю розсилку для подання запитів." +#: html/home.php msgid "Submitting Packages" msgstr "Надсилання пакунків" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"Git через SSH тепер використовується для надсилання пакунків до AUR. Для " -"деталей дивіться розділ %sНадсилання пакунків%s на сторінці ArchWiki про " -"Сховище Користувацьких Пакунків AUR." +msgstr "Git через SSH тепер використовується для надсилання пакунків до AUR. Для деталей дивіться розділ %sНадсилання пакунків%s на сторінці ArchWiki про Сховище Користувацьких Пакунків AUR." +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "Наступні відбитки ключів SSH використовуються в AUR:" +#: html/home.php msgid "Discussion" msgstr "Обговорення" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"Загальне обговорення сховища користувацьких пакунків (AUR) та структури " -"довірених користувачів відбувається в %saur-general%s. Для дискусій про " -"розробку AUR використовуйте список розсилання %saur-dev%s." +msgstr "Загальне обговорення сховища користувацьких пакунків (AUR) та структури довірених користувачів відбувається в %saur-general%s. Для дискусій про розробку AUR використовуйте список розсилання %saur-dev%s." +#: html/home.php msgid "Bug Reporting" msgstr "Повідомлення про вади" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"Якщо Ви знайдете ваду у веб-інтерфейсі AUR, повідомте про це нас на нашому " -"%sтрекері вад%s. Таким чином слід сповіщати %sлише%s про проблеми у веб-" -"інтерфейсі AUR. Про вади пакунка зв’яжіться з його супровідником або залиште " -"коментар на відповідній сторінці цього пакунка." +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "Якщо Ви знайдете ваду у веб-інтерфейсі AUR, повідомте про це нас на нашому %sтрекері вад%s. Таким чином слід сповіщати %sлише%s про проблеми у веб-інтерфейсі AUR. Про вади пакунка зв’яжіться з його супровідником або залиште коментар на відповідній сторінці цього пакунка." +#: html/home.php msgid "Package Search" msgstr "Пошук пакунків" +#: html/index.php msgid "Adopt" msgstr "Прийняти" +#: html/index.php msgid "Vote" msgstr "Проголосувати" +#: html/index.php msgid "UnVote" msgstr "Забрати голос" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "Сповіщати" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "Не сповіщати" +#: html/index.php msgid "UnFlag" msgstr "Зняти позначку" +#: html/login.php template/header.php msgid "Login" msgstr "Увійти" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "Ввійшов як: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "Вийти" +#: html/login.php msgid "Enter login credentials" msgstr "Увійдіть, ввівши облікові дані." +#: html/login.php msgid "User name or email address" msgstr "Назва користувача або адреса електронної пошти" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "Пароль" +#: html/login.php msgid "Remember me" msgstr "Запам'ятати мене" +#: html/login.php msgid "Forgot Password" msgstr "Забули пароль?" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "" -"Реєстрування через HTTP вимкнено. Будь-ласка, %sперейдіть на HTTPs%s для " -"входу." +msgstr "Реєстрування через HTTP вимкнено. Будь-ласка, %sперейдіть на HTTPs%s для входу." +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "Критерії пошуку" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "Пакунки" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "Стався збій під час пошуку інформації про пакунок." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "Бракує обов’язкового рядка." +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "Паролі не збігаються." +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "Ваш пароль має містити щонайменше %s символів." +#: html/passreset.php msgid "Invalid e-mail." msgstr "Неправильна електронна адреса." +#: html/passreset.php msgid "Password Reset" msgstr "Скидання паролю" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "Перевірте свою електронну пошту для підтвердження." +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "Ваш пароль успішно скинуто." +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "Підтвердьте адресу електронної пошти:" +#: html/passreset.php msgid "Enter your new password:" msgstr "Введіть новий пароль:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "Підтвердження нового паролю:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "Продовжити" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"Якщо Ви забули електронну адресу, використану при реєстрації, зверніться до " -"списку розсилання %saur-general%s" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "Якщо Ви забули електронну адресу, використану при реєстрації, зверніться до списку розсилання %saur-general%s" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "Введіть адресу електронної пошти:" +#: html/pkgbase.php msgid "Package Bases" msgstr "Бази пакунків" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "Вибрані пакунки все ще мають власника, підтвердіть дію." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "Не вдалося знайти пакунок для об’єднання голосів та коментарів." +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "Неможливо злити пакунок з самим собою." +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." -msgstr "" -"Обрані пакунки не вилучено, перевірте, чи поставлено галочку в полі " -"підтвердження." +"The selected packages have not been deleted, check the confirmation " +"checkbox." +msgstr "Обрані пакунки не вилучено, перевірте, чи поставлено галочку в полі підтвердження." +#: html/pkgdel.php msgid "Package Deletion" msgstr "Вилучення пакунку" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "Вилучити пакунок" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "" -"Використовуйте цю форму для вилучення бази пакунків %s%s%s і наступних " -"пакунків з AUR. " +msgstr "Використовуйте цю форму для вилучення бази пакунків %s%s%s і наступних пакунків з AUR. " +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "Вилучення пакунку є безповоротне." +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "Встановіть галочку, щоб підтвердити дію." +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "Підтвердити вилучення пакунку" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "Вилучити" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "Тільки Довірені Користувачі та Розробники можуть вилучати пакунки." +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "Зректися пакунку" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " -msgstr "" -"Використайте ці форму для позбавлення бази пакунків %s%s%s власника, яка " -"містить наступні пакунки:" +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " +msgstr "Використайте ці форму для позбавлення бази пакунків %s%s%s власника, яка містить наступні пакунки:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "Вибираючи це, Ви підтверджуєте, що не бажаєте бути співсупровідником." + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." -msgstr "" -"Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника і " -"перенести права власності до %s%s%s." +msgstr "Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника і перенести права власності до %s%s%s." +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "Вибираючи це, Ви підтверджуєте, що бажаєте позбавити пакунок власника." +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "Підтвердіть позбавлення пакунка власника" +#: html/pkgdisown.php msgid "Disown" msgstr "Відректися" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." -msgstr "" -"Тільки Довірені Користувачі та Розробники можуть забирати права власності на " -"пакунок." +msgstr "Тільки Довірені Користувачі та Розробники можуть забирати права власності на пакунок." +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "Позначити коментар" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "Позначити пакунок як застарілий" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " -msgstr "" -"Використовуйте цю форму для позначення бази пакунків %s%s%s і наступні " -"пакунки як застарілі:" +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " +msgstr "Використовуйте цю форму для позначення бази пакунків %s%s%s і наступні пакунки як застарілі:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"Будь ласка, %sне%s використовуйте цю форму для повідомлення про вади. " -"Використовуйте для цього коментарі до пакунку." +msgstr "Будь ласка, %sне%s використовуйте цю форму для повідомлення про вади. Використовуйте для цього коментарі до пакунку." +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"Введіть нижче деталі, чому пакунок є застарілим, по можливості подайте " -"посилання до оголошення про новий випуск або архів оновленого випуску." +msgstr "Введіть нижче деталі, чому пакунок є застарілим, по можливості подайте посилання до оголошення про новий випуск або архів оновленого випуску." +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "Коментарі" +#: html/pkgflag.php msgid "Flag" msgstr "Позначити" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "" -"Тільки зареєстровані користувачі можуть позначати пакунки як застарілі." +msgstr "Тільки зареєстровані користувачі можуть позначати пакунки як застарілі." +#: html/pkgmerge.php msgid "Package Merging" msgstr "Об’єднання пакунків" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "Об’єднати пакунок" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " -msgstr "" -"Використовуйте цю форму для злиття бази пакунків %s%s%s з іншим пакунком." +msgstr "Використовуйте цю форму для злиття бази пакунків %s%s%s з іншим пакунком." +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "Наступні пакунки будуть вилучені:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "Як тільки пакунок буде об’єднаний, його вже неможливо повернути." +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "Введіть назву пакунка, до якого потрібно приєднати цей." +#: html/pkgmerge.php msgid "Merge into:" msgstr "Об’єднати з:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "Підтвердити об’єднання пакунків" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "Об’єднати" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "Тільки Довірені Користувачі та Розробники можуть об’єднувати пакунки." +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "Надіслати запит" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "Закриття запиту" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "Перший" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Попередній" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далі" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Останній" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "Запити" +#: html/register.php template/header.php msgid "Register" msgstr "Зареєструватись" +#: html/register.php msgid "Use this form to create an account." msgstr "Створіть обліковий запис за допомогою цієї форми." +#: html/tos.php msgid "Terms of Service" msgstr "Умови обслуговування" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "Наступні документи оновлено. Перевірте їх уважно: " +#: html/tos.php #, php-format msgid "revision %d" msgstr "перегляд %d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "Я приймаю подані вище терміни і умови. " +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "Довірений користувач" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "Не вдалось отримати подробиць пропозиції." +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "Голосування на цю пропозицію закрито." +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "Тільки Довірені Користувачі мають право голосу." +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "Ви не можете голосувати за свою пропозицію." +#: html/tu.php msgid "You've already voted for this proposal." msgstr "Ви вже проголосували за цю пропозицію." +#: html/tu.php msgid "Vote ID not valid." msgstr "Ідентифікатор голосу неправильний." +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "Поточні голосування" +#: html/tu.php msgid "Past Votes" msgstr "Минулі голосування" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "Проголосували" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Реєстрація рахунку закрита для Вашої адреси IP, можливо із-за інтенсивної " -"спам-атаки. Вибачте за незручності." +msgstr "Реєстрація рахунку закрита для Вашої адреси IP, можливо із-за інтенсивної спам-атаки. Вибачте за незручності." +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "Бракує ідентифікатора користувача" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "Користувач неправильний." +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "Кількість символів повинна бути від %s до %s" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "Початок та кінець з літери або цифри" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "Може містити тільки один період, підкреслення або дефіс." +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Адреса електронної пошти неправильна." +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Неправильна домашня сторінка, вкажіть повну адресу HTTP(s)." +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "Відбиток ключа PGP недійсний." +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "Неправильний публічний ключ SSH." +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "Неможливо збільшити дозволи рахунку." +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "Наразі ця мова не підтримується." +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "Наразі часова зона не підтримується." +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "Назва користувача %s%s%s вже використовується." +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "Адрес %s%s%s вже використовується." +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "Публічний ключ SSH, %s%s%s, вже використовується." +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "Помилка при спробі створити рахунок %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "Рахунок %s%s%s успішно створено." +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "Ключ скидання пароля висланий на Вашу адресу електронної пошти." +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "" -"Використовуйте обліковий запис, увійшовши за допомогою посилання " -"«Увійти» (згори)." +msgstr "Використовуйте обліковий запис, увійшовши за допомогою посилання «Увійти» (згори)." +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "Ніяких змін не внесено до рахунку, %s%s%s." +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "Рахунок %s%s%s успішно змінено." +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"Форма логування зараз заборонена для Вашої адреси IP, можливо із-за " -"інтенсивної спам-атаки. Вибачте за незручності." +msgstr "Форма логування зараз заборонена для Вашої адреси IP, можливо із-за інтенсивної спам-атаки. Вибачте за незручності." +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "Рахунок вилучено" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"Ваш пароль скинуто. Якщо Ви щойно створили новий рахунок, тоді використайте " -"посилання електронного листа-підтвердження для встановлення початкового " -"пароля. В протилежному випадку використайте запит щодо скидання паролю на " -"сторінці %sPassword Reset%s." +msgstr "Ваш пароль скинуто. Якщо Ви щойно створили новий рахунок, тоді використайте посилання електронного листа-підтвердження для встановлення початкового пароля. В протилежному випадку використайте запит щодо скидання паролю на сторінці %sPassword Reset%s." +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "Неправильний користувач або пароль. " +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "Сталася помилка під час створення сесії користувача." +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "Неприпустима адреса електронної пошти й комбінація клавіш скидання." +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "Немає" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "Показати інформацію про рахунок для %s" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "ID бази пакунків або ж назва бази пакунків пропущена." +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "У вас немає прав, щоб редагувати цей коментар." +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "Коментаря не існує." +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "Коментар не може бути порожнім." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "Коментар додано." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." -msgstr "" -"Ви повинні увійти у систему, щоб мати можливість редагувати інформацію про " -"пакунок." +msgstr "Ви повинні увійти у систему, щоб мати можливість редагувати інформацію про пакунок." +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "Немає ідентифікатора коментаря." +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "Можна прикріпити не більше 5 коментарів." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "Вам заборонено прикріпляти цей коментар." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "Вам заборонено відкріпляти цей коментар." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "Коментар прикріплено." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "Коментар відкріплено." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "Помилка пошуку інформації про пакунок." +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "Інформації про пакунок не знайдено." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "Для встановлення мітки слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "Ви не вибрали жодного пакунку для мітки." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "Вибрані пакунки не мають міток, подайте коментар, будь ласка." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "Для вибраних пакунків призначено мітку «застарілий»." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "Для зняття мітки слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "Не вибрано жодного пакунку, щоб зняти мітку." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "З вибраних пакунків було знято мітку." +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "У Вас немає прав для вилучення пакунків." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "Не вибрано жодного пакунку для вилучення." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "Вибрані пакунки вилучено." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "Для перейняття пакунків слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "Для зречення пакунків слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "Ви не вибрали жодного пакунку для переймання." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "Не вибрано жодного пакунку, щоб зректись." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "Вибрані пакунки перейнято." +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "Ви зреклись вибраних пакунків." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "Для голосування слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "Для скасування голосу слід увійти." +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "Ви не вибрали жодного пакунка для голосування." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "Ваші голоси вилучено з вибраних пакунків." +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "Ви проголосували за вибрані пакунки." +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "Неможливо долучити до списку соповіщень." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "Вас долучено до списку сповіщень про коментарі для %s." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "Вас вилучено із списку сповіщень про коментарі для %s." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "Вам заборонено відновлювати цей коментар." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "Коментар відновлено." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "У вас немає прав, щоб вилучити цей коментар." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "Коментар вилучено." +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "Коментар редаговано." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "Ви не маєте прав для редагування ключових слів для цієї бази пакунків." +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "Ключові слова бази пакунків оновлено." +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "Ви не має прав для керування ко-супровідниками цієї бази пакунків." +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "Неправильна назва користувача: %s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "Оновлено ко-супровідників бази пакунків." +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "Показати деталі пакунку для " +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "вимагається %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "Ви повинні увійти, щоб створювати запити щодо пакунків." +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "Неправильна назва: дозволено тільки малі літери." +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "Поле коментаря не повинно пустувати." +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "Неправильний тип запиту." +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "Запит успішно додано." +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "Неправильна причина." +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "Тільки TU (довірені користувачі) і розробники можуть закривати запити." +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "Запит успішно закритий." +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "Ви можете використати цю форму для вилучення рахунку в AUR %s." +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%sУВАГА%s: Цю дію неможливо відмінити." +#: template/account_delete.php msgid "Confirm deletion" msgstr "Підтвердити вилучення" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "Користувач" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "Тип облікового запису" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "Користувач" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "Розробник" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "Довірений користувач & Розробник" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Адреса електронної пошти" +#: template/account_details.php msgid "hidden" msgstr "приховано" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "Справжнє ім'я" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "Домашня сторінка" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "Псевдонім IRC" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "Відбиток ключа PGP" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "Статус" +#: template/account_details.php msgid "Inactive since" msgstr "Неактивний з" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "Активний" +#: template/account_details.php msgid "Registration date:" msgstr "Дата реєстрації:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "невідомо" +#: template/account_details.php msgid "Last Login" msgstr "Останній вхід" +#: template/account_details.php msgid "Never" msgstr "Ніколи" +#: template/account_details.php msgid "View this user's packages" msgstr "Переглянути пакунки цього користувача" +#: template/account_details.php msgid "Edit this user's account" msgstr "Редагування рахунку цього користувача" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "Натисніть %sтут%s, якщо Ви бажаєте безповоротно вилучити цей рахунок." +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "Клацніть %sтут%s, щоб дізнатися більше про користувача." +#: template/account_edit_form.php msgid "required" msgstr "обов'язково" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" -"Ваша назва користувача є назвою, що буде використовуватися для входу. Вона " -"буде видимою для всіх, навіть якщо Ваш рахунок неактивний." +msgstr "Ваша назва користувача є назвою, що буде використовуватися для входу. Вона буде видимою для всіх, навіть якщо Ваш рахунок неактивний." +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "Звичайний користувач" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "Довіренний користувач" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "Обліковий запис призупинено" +#: template/account_edit_form.php msgid "Inactive" msgstr "Неактивний" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "" -"Будь ласка переконайтесь, що Ви правильно ввели Вашу адресу електронної " -"пошти, інакше Ви будете заблоковані." +msgstr "Будь ласка переконайтесь, що Ви правильно ввели Вашу адресу електронної пошти, інакше Ви будете заблоковані." +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "Приховати адресу електронної пошти" +#: template/account_edit_form.php msgid "Re-type password" msgstr "Введіть пароль ще раз" +#: template/account_edit_form.php msgid "Language" msgstr "Мова" +#: template/account_edit_form.php msgid "Timezone" msgstr "Часова зона" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." -msgstr "" -"Наступну інформацію потрібно, якщо Ви бажаєте надіслати пакунки до Сховища " -"Користувацьких Пакунків AUR." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." +msgstr "Наступну інформацію потрібно, якщо Ви бажаєте надіслати пакунки до Сховища Користувацьких Пакунків AUR." +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "Публічний ключ SSH" +#: template/account_edit_form.php msgid "Notification settings" msgstr "Налаштування повідомлень" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "Сповіщати про нові коментарі" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "Повідомлення про оновлення пакунків" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "Сповіщення про зміну власника" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "Оновити" +#: template/account_edit_form.php msgid "Create" msgstr "Створити" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "Очистити" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "За вашим запитом нічого не знайдено." +#: template/account_search_results.php msgid "Edit Account" msgstr "Редагувати обліковий запис" +#: template/account_search_results.php msgid "Suspended" msgstr "Призупинено" +#: template/account_search_results.php msgid "Edit" msgstr "Редагувати" +#: template/account_search_results.php msgid "Less" msgstr "Менше" +#: template/account_search_results.php msgid "More" msgstr "Більше" +#: template/account_search_results.php msgid "No more results to display." msgstr "Більше немає результатів." +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "" -"Використайте цю форму для додавання ко-супровідника для %s%s%s (одна назва " -"користувача в одній стрічці):" +msgstr "Використайте цю форму для додавання ко-супровідника для %s%s%s (одна назва користувача в одній стрічці):" +#: template/comaintainers_form.php msgid "Users" msgstr "Користувачі" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "Зберегти" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "Позначено як застарілий коментар: %s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "%s%s%s позначено %s%s%s як застарілий на %s%s%s з наступної причини:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s не позначений як застарілий." +#: template/flag_comment.php msgid "Return to Details" msgstr "Повернення до подробиць." +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Всі права застережено %s 2004-%d Команда Розробників aurweb." +#: template/header.php msgid " My Account" msgstr "Мій рахунок" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "Дії над пакунком" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "Переглянути PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "Переглянути зміни" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "Звантажити поточну версію" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "Шукати у Вікі" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "Позначено як застарілий (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "Позначити пакунок як застарілий" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "Відмінити позначення" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "Вилучити голос" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "Голосувати за цей пакунок" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "Відключити сповіщення" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "Включити сповіщення" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "Керування ко-супровідниками" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d запит в обробці" msgstr[1] "%d запитів в обробці" msgstr[2] "%d запитів в обробці" +msgstr[3] "%d запитів в обробці" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "Прийняти пакунок" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "Деталі бази пакунків" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Адреса URL для клонування Git" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "тільки для читання" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "Ключові слова" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "Подавач" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "Супровідник" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "Останній збирач пакунку" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "Голоси" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "Популярність" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "Вперше надіслано" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "Останній раз оновлено" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "Редагувати коментар для: %s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "Додати коментар" +#: template/pkg_comments.php msgid "View all comments" msgstr "Переглянути всі коментарі" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "Прикріплені коментарі" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "Останні коментарі" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s коментував про %s" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "Анонімний коментар про %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "вилучено на %s через %s" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "вилучено %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "редаговано %s через %s" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "редаговано %s" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "Відновити коментар" +#: template/pkg_comments.php msgid "Delete comment" msgstr "Вилучити коментар" +#: template/pkg_comments.php msgid "Pin comment" msgstr "Прикріпити коментар" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "Відкріпити коментар" +#: template/pkg_comments.php msgid "All comments" msgstr "Всі коментарі" +#: template/pkg_details.php msgid "Package Details" msgstr "Подробиці пакунку" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "База пакунків" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "Опис" +#: template/pkg_details.php msgid "Upstream URL" msgstr "Посилання" +#: template/pkg_details.php msgid "Visit the website for" msgstr "Відвідати веб-сторінку для" +#: template/pkg_details.php msgid "Licenses" msgstr "Ліцензії" +#: template/pkg_details.php msgid "Groups" msgstr "Групи" +#: template/pkg_details.php msgid "Conflicts" msgstr "Конфлікти" +#: template/pkg_details.php msgid "Provides" msgstr "Забезпечує" +#: template/pkg_details.php msgid "Replaces" msgstr "Замінює" +#: template/pkg_details.php msgid "Dependencies" msgstr "Залежності" +#: template/pkg_details.php msgid "Required by" msgstr "Потрібен для" +#: template/pkg_details.php msgid "Sources" msgstr "Сирці" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "Використайте цю форму для закриття запиту щодо бази пакунків %s%s%s." +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "" -"Поле коментарів може залишатися пустим. Тим не менше, рекомендовано залишити " -"коментар при відкиданні запиту." +msgstr "Поле коментарів може залишатися пустим. Тим не менше, рекомендовано залишити коментар при відкиданні запиту." +#: template/pkgreq_close_form.php msgid "Reason" msgstr "Причина" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "Прийнято" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "Відхилено" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" -msgstr "" -"Використайте цю форму для створення запиту щодо бази пакунків %s%s%s, яка " -"містить наступні пакунки:" +msgstr "Використайте цю форму для створення запиту щодо бази пакунків %s%s%s, яка містить наступні пакунки:" +#: template/pkgreq_form.php msgid "Request type" msgstr "Тип запиту" +#: template/pkgreq_form.php msgid "Deletion" msgstr "Вилучення" +#: template/pkgreq_form.php msgid "Orphan" msgstr "Позначити застарілим" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "Об'єднати в" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"Надсилаючи запит на вилучення, Ви просите Довіреного Користувача вилучити " -"пакунок з бази пакунків. Цей тип запиту повинен використовуватися для " -"дублікатів, неоновлюваних програм, а також нелегальних і невиправно " -"пошкоджених пакунків." +msgstr "Надсилаючи запит на вилучення, Ви просите Довіреного Користувача вилучити пакунок з бази пакунків. Цей тип запиту повинен використовуватися для дублікатів, неоновлюваних програм, а також нелегальних і невиправно пошкоджених пакунків." +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"Надсилаючи запит на об'єднання, Ви просите Довіреного Користувача вилучити " -"базу пакунків і перенести всі його голосування і коментарі до іншої бази " -"пакунків. Об'єднання пакунку не впливає на відповідні сховища Git. " -"Впевніться, що Ви самостійно оновили історію Git доцільового пакунку." +msgstr "Надсилаючи запит на об'єднання, Ви просите Довіреного Користувача вилучити базу пакунків і перенести всі його голосування і коментарі до іншої бази пакунків. Об'єднання пакунку не впливає на відповідні сховища Git. Впевніться, що Ви самостійно оновили історію Git доцільового пакунку." +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"Надсилаючи запит на зречення, Ви просите Довіреного Користувача позбавити " -"базу пакунків власника. Робіть це, якщо пакунок потребує якоїсь дії від " -"супровідника, супровідник не робить жодних дій і Ви вже попередньо " -"намагалися зв'язатися з ним." +msgstr "Надсилаючи запит на зречення, Ви просите Довіреного Користувача позбавити базу пакунків власника. Робіть це, якщо пакунок потребує якоїсь дії від супровідника, супровідник не робить жодних дій і Ви вже попередньо намагалися зв'язатися з ним." +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "Жоден запит не відповідає Вашим критеріям пошуку." +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Знайдено %d запит пакунку." msgstr[1] "Знайдено %d запитів пакунку." msgstr[2] "Знайдено %d запитів щодо пакунків." +msgstr[3] "Знайдено %d запитів щодо пакунків." +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "Сторінка %d з %d." +#: template/pkgreq_results.php msgid "Package" msgstr "Пакунок" +#: template/pkgreq_results.php msgid "Filed by" msgstr "Запаковано через" +#: template/pkgreq_results.php msgid "Date" msgstr "Дата" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d день залишився" msgstr[1] "~%d днів залишилося" msgstr[2] "~%d днів залишилося" +msgstr[3] "~%d днів залишилося" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d година залишилася" msgstr[1] "~%d годин залишилося" msgstr[2] "~%d годин залишилося" +msgstr[3] "~%d годин залишилося" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "<1 години залишилося" +#: template/pkgreq_results.php msgid "Accept" msgstr "Прийняти" +#: template/pkgreq_results.php msgid "Locked" msgstr "Замкнено" +#: template/pkgreq_results.php msgid "Close" msgstr "Закрити" +#: template/pkgreq_results.php msgid "Pending" msgstr "В очікуванні" +#: template/pkgreq_results.php msgid "Closed" msgstr "Замкнено" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "Назва, опис" +#: template/pkg_search_form.php msgid "Name Only" msgstr "Назва" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "Точна назва" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "Точна база пакунків" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "Ко-супровідник" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "Супровідник, ко-супровідник" +#: template/pkg_search_form.php msgid "All" msgstr "Всі" +#: template/pkg_search_form.php msgid "Flagged" msgstr "Позначені" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "Не позначені" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "Назва" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "Проголосовано" +#: template/pkg_search_form.php msgid "Last modified" msgstr "Востаннє змінювалося" +#: template/pkg_search_form.php msgid "Ascending" msgstr "Висхідний" +#: template/pkg_search_form.php msgid "Descending" msgstr "Спадний" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "Введіть критерії пошуку" +#: template/pkg_search_form.php msgid "Search by" msgstr "Де шукати" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "Застарілих" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "Упорядкувати за" +#: template/pkg_search_form.php msgid "Sort order" msgstr "Порядок упорядкування" +#: template/pkg_search_form.php msgid "Per page" msgstr "Результатів на сторінку" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Перейти" +#: template/pkg_search_form.php msgid "Orphans" msgstr "Покинуті" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "Помилка отримання списку пакунків." +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "За вашим запитом не знайдено пакунків." +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "Знайдено %d пакунок." msgstr[1] "Знайдено %d пакунків." msgstr[2] "Знайдено %d пакунків." +msgstr[3] "Знайдено %d пакунків." +#: template/pkg_search_results.php msgid "Version" msgstr "Версія" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" -"Популярність розраховується як сума всіх голосувань, де кожен голос береться " -"з ваговим коефіцієнтом %.2f за кожен день з часу створення." +msgstr "Популярність розраховується як сума всіх голосувань, де кожен голос береться з ваговим коефіцієнтом %.2f за кожен день з часу створення." +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "Так" +#: template/pkg_search_results.php msgid "orphan" msgstr "покинутий" +#: template/pkg_search_results.php msgid "Actions" msgstr "Дії" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "Зняти мітку «застарілий»" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "Прийняти пакунки" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "Зректися пакунків" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "Вилучити пакунки" +#: template/pkg_search_results.php msgid "Confirm" msgstr "Підтвердити" +#: template/search_accounts_form.php msgid "Any type" msgstr "Будь-який тип" +#: template/search_accounts_form.php msgid "Search" msgstr "Пошук" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "Статистика" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "Покинуті пакунки" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "Пакунки, додані за останні 7 днів" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "Пакунки, оновлені за останні 7 днів" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "Пакунки, оновлені за останній рік" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "Пакунки, що ніколи не оновлювалися" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "Зареєстровані користувачі" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "Довірені користувачі" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "Останні зміни" +#: template/stats/updates_table.php msgid "more" msgstr "більше" +#: template/stats/user_table.php msgid "My Statistics" msgstr "Моя статистика" +#: template/tu_details.php msgid "Proposal Details" msgstr "Подробиці пропозиції" +#: template/tu_details.php msgid "This vote is still running." msgstr "Це голосування все ще доречне." +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "Подано: %s з %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "Кінець" +#: template/tu_details.php msgid "Result" msgstr "Результат" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "Ні" +#: template/tu_details.php msgid "Abstain" msgstr "Утриматися" +#: template/tu_details.php msgid "Total" msgstr "Всього" +#: template/tu_details.php msgid "Participation" msgstr "Участь" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "Останні голосування через TU" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "Останнє голосування" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "Результатів не знайдено." +#: template/tu_list.php msgid "Start" msgstr "Початок" +#: template/tu_list.php msgid "Back" msgstr "Назад" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "Скидання паролю на AUR" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "Запит на скидання паролю для облікового запису {user} надісланий на пов’язану з ним адресу електронної пошти. Щоб скинути пароль, натисніть на посилання [1] нижче; щоб залишити все як є, проігноруйте це повідомлення." + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "Вітаємо Вас в Arch User Repository — сховищі користувацьких пакунків" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "Вітаємо в Сховищі Користувацьких Пакунків! Щоб встановити початковий пароль для Вашого рахунку натисніть на посилання [1] зверху. Якщо посилання не спрацьовує, скопіюйте його і вставте у Ваш переглядач інтернету." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "AUR коментар для {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "{user} [1] додав наступний коментар до {pkgbase} [2]:" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "Якщо Ви не бажаєте більше отримувати повідомлення про цей пакунок, тоді перейдіть на сторінку пакунка [2] і натисніть \"{label}\"." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "Оновлення пакунку AUR: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "{user} [1] додав наступний коментар до {pkgbase} [2]:" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "Повідомлення AUR про застарілі для {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "Цьому пакунку {pkgbase} [1] призначено мітку застарілий користувачем {user} [2]:" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "Повідомлення AUR про присвоєння для {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "Цей пакунок {pkgbase} [1] був прийнятий користувачем {user} [2]." + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "Пакунок {pkgbase} [1] був покинутий користувачем {user} [2]." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "Повідомлення про співсупровід AUR для {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "Вас додали до списку співсупровідників {pkgbase} [1]." + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "Вас видалили зі списку співсупровідників {pkgbase} [1]." + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "Пакунок з AUR вилучено: {pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "{user} [1] об'єднав {old} [2] в {new} [3].\n\nЯкщо Ви не бажаєте більше отримувати повідомлень про новий пакунок, перейдіть до [3] і клацніть \"{label}\"." + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "{user} [1] вилучив {pkgbase} [2].\n\nВи більше не будете отримувати повідомлень про цей пакунок." + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "Нагадування про голосування на довіреного користувача: Пропозиція {id}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "Будь ласка, не забудьте подати свій голос на пропозицію {id} [1]. Голосування закінчиться за менш ніж 48 годин." diff --git a/po/zh_CN.po b/po/zh_CN.po index ceacdea5..15b4c74d 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,1562 +1,2135 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: -# leonfeng , 2015-2016 +# leonfeng , 2015-2016 # dongfengweixiao , 2015 # Felix Yan , 2014 # Lukas Fleischer , 2011 -# pingplug , 2017 -# leonfeng , 2012 +# pingplug , 2017-2018 +# leonfeng , 2012 # Weiwen Zhao , 2013 # Xiaodong Qi , 2016 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 07:52+0000\n" -"Last-Translator: Lukas Fleischer \n" -"Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aur/" -"language/zh_CN/)\n" -"Language: zh_CN\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-23 12:28+0000\n" +"Last-Translator: pingplug \n" +"Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aurweb/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: html/404.php msgid "Page Not Found" msgstr "页面未找到" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "请求的页面不存在。" +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "提示" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Git 克隆地址并不意味着能被浏览器打开" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "要克隆 Git 项目 %s,运行 %s。" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "点击 %s这里%s 以回到 %s 的软件包详情页面" +#: html/503.php msgid "Service Unavailable" msgstr "服务不可用" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "别怕!本站正在维护中,我们会回来的。" +#: html/account.php msgid "Account" msgstr "帐户" +#: html/account.php template/header.php msgid "Accounts" msgstr "帐户" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "您无权访问此区域。" +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "无法获取指定用户的信息。" +#: html/account.php msgid "You do not have permission to edit this account." msgstr "您没有权限编辑此帐户。" +#: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表单查找存在的帐户。" +#: html/account.php msgid "You must log in to view user information." msgstr "您需要登录后才能察看用户信息。" +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "添加提议" +#: html/addvote.php msgid "Invalid token for user action." msgstr "用户操作使用了无效的令牌。" +#: html/addvote.php msgid "Username does not exist." msgstr "此用户不存在。" +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s 已经有了关于他们的提议。" +#: html/addvote.php msgid "Invalid type." msgstr "无效的类别。" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "提议不能为空。" +#: html/addvote.php msgid "New proposal submitted." msgstr "新提议已被提交。" +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "提交一个提议用于投票。" +#: html/addvote.php msgid "Applicant/TU" msgstr "申请人/信任用户(TU)" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(如果不符合可以留空)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "类别" +#: html/addvote.php msgid "Addition of a TU" msgstr "添加受信用户" +#: html/addvote.php msgid "Removal of a TU" msgstr "移除受信用户" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "移除受信用户(无故不活跃)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "修订章程" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "提议" +#: html/addvote.php msgid "Submit" msgstr "提交" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "管理共同维护者" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "编辑评论" +#: html/home.php template/header.php msgid "Dashboard" msgstr "仪表面板" +#: html/home.php template/header.php msgid "Home" msgstr "首页" +#: html/home.php msgid "My Flagged Packages" msgstr "被标记的软件包" +#: html/home.php msgid "My Requests" msgstr "我的请求" +#: html/home.php msgid "My Packages" msgstr "我的软件包" +#: html/home.php msgid "Search for packages I maintain" msgstr "搜索我维护的软件包" +#: html/home.php msgid "Co-Maintained Packages" msgstr "共同维护的软件包" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "搜索共同维护的软件包" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"欢迎来到 AUR!想了解更多信息,请阅读 %sAUR 用户指南%s和 %sAUR 受信用户指" -"南%s。" +msgstr "欢迎来到 AUR!想了解更多信息,请阅读 %sAUR 用户指南%s和 %sAUR 受信用户指南%s。" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" msgstr "提交的 PKGBUILD %s必须%s遵守 %sArch 软件包规范%s,否则它们将被删除!" +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "记得为您喜欢的软件包投票!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "部分软件包将在 [community] 仓库以二进制包的形式提供。" +#: html/home.php msgid "DISCLAIMER" msgstr "免责声明" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "AUR 包为用户产生的内容。使用它们造成的后果自负。" +#: html/home.php msgid "Learn more..." msgstr "了解更多..." +#: html/home.php msgid "Support" msgstr "支持" +#: html/home.php msgid "Package Requests" msgstr "软件包请求" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "在软件包详情页面上有三种可以在 %s软件包操作%s 框中提交的请求:" +#: html/home.php msgid "Orphan Request" msgstr "弃置请求" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"请求标记这个软件包为无主的,比如维护者不活跃而且这个软件包已经被标记为过时很" -"久了。" +msgstr "请求标记这个软件包为无主的,比如维护者不活跃而且这个软件包已经被标记为过时很久了。" +#: html/home.php msgid "Deletion Request" msgstr "删除请求" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"请求软件包从 AUR 中移除。如果这个包虽然损坏了但是可以被轻易地修好,请不要进行" -"此操作,您应该联系包的维护者或者有必要的情况下发送弃置请求。" +msgstr "请求软件包从 AUR 中移除。如果这个包虽然损坏了但是可以被轻易地修好,请不要进行此操作,您应该联系包的维护者或者有必要的情况下发送弃置请求。" +#: html/home.php msgid "Merge Request" msgstr "合并请求" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"请求一个软件包被合并到另一个中。在一个包需要被重命名或者被分离成多个包的情况" -"下使用。" +msgstr "请求一个软件包被合并到另一个中。在一个包需要被重命名或者被分离成多个包的情况下使用。" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"如果你想讨论一个请求,你可以在 %saur-requests%s 邮件列表上发送消息。然而,不" -"要在那里发送请求。" +msgstr "如果你想讨论一个请求,你可以在 %saur-requests%s 邮件列表上发送消息。然而,不要在那里发送请求。" +#: html/home.php msgid "Submitting Packages" msgstr "提交软件包" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"现在请使用 Git over SSH 来向 AUR 提交软件包。如果想知道更多,请查看 Arch " -"Wiki 上的 Arch User Repository (简体中文) 页面中 %s提交软件包%s 章节。" +msgstr "现在请使用 Git over SSH 来向 AUR 提交软件包。如果想知道更多,请查看 Arch Wiki 上的 Arch User Repository (简体中文) 页面中 %s提交软件包%s 章节。" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR 使用以下 SSH 指纹:" +#: html/home.php msgid "Discussion" msgstr "邮件列表" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"与 Arch 用户仓库(AUR)或者受信用户结构相关的一般讨论在 %saur-general%s 邮件" -"列表。若是与 AUR web 页面开发相关的讨论,请使用 %saur-dev%s 邮件列表。" +msgstr "与 Arch 用户仓库(AUR)或者受信用户结构相关的一般讨论在 %saur-general%s 邮件列表。若是与 AUR web 页面开发相关的讨论,请使用 %saur-dev%s 邮件列表。" +#: html/home.php msgid "Bug Reporting" msgstr "Bug 报告" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"如果你在 AUR web 页面中发现了一个 Bug,请提交到我们的 %sBug 追踪系统%s。请%s" -"仅仅%s使用追踪系统报告 AUR 自身的 Bug。如果想要报告打包方面的 Bug,请联系相应" -"的包维护者,或者在相应的软件包页面中留下一条评论。" +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "如果你在 AUR web 页面中发现了一个 Bug,请提交到我们的 %sBug 追踪系统%s。请%s仅仅%s使用追踪系统报告 AUR 自身的 Bug。如果想要报告打包方面的 Bug,请联系相应的包维护者,或者在相应的软件包页面中留下一条评论。" +#: html/home.php msgid "Package Search" msgstr "软件包搜索" +#: html/index.php msgid "Adopt" msgstr "接管" +#: html/index.php msgid "Vote" msgstr "投票" +#: html/index.php msgid "UnVote" msgstr "取消投票" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "取消通知" +#: html/index.php msgid "UnFlag" msgstr "取消标记" +#: html/login.php template/header.php msgid "Login" msgstr "登录" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "登录为: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "退出" +#: html/login.php msgid "Enter login credentials" msgstr "输入账户信息" +#: html/login.php msgid "User name or email address" msgstr "用户名或 E-mail" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "密码" +#: html/login.php msgid "Remember me" msgstr "记住我" +#: html/login.php msgid "Forgot Password" msgstr "找回密码" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." -msgstr "HTTP 登陆已被禁用,请使用%s切换到HTTPS%s。" +msgstr "HTTP 登录已被禁用,请使用%s切换到HTTPS%s。" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "搜索标准" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "软件包" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "尝试重新获取软件包详情时发生错误。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "缺少必填项。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "密码字段不匹配。" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "密码至少要 %s 个字符。" +#: html/passreset.php msgid "Invalid e-mail." msgstr "电子邮箱不正确。" +#: html/passreset.php msgid "Password Reset" msgstr "密码重置" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "请进入您的邮箱查看确认邮件。" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "密码已经成功重置。" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "确认邮箱地址:" +#: html/passreset.php msgid "Enter your new password:" msgstr "输入新密码:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "确认新密码:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "继续" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"如果您忘记了注册账号时使用的邮件地址,请向 %saur-general%s 邮件列表寻求帮助。" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "如果您忘记了注册账号时使用的邮件地址,请向 %saur-general%s 邮件列表寻求帮助。" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "输入您的邮箱地址:" +#: html/pkgbase.php msgid "Package Bases" msgstr "包基础" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "选中的软件包未被弃置,请检查确认复选框。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "找不到合并投票与评论的目标包。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "无法将一个包基础合并到它自己。" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "选中的软件包未被删除,请检查确认复选框。" +#: html/pkgdel.php msgid "Package Deletion" msgstr "软件包删除" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "删除软件包" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "使用这个表单将包基础 %s%s%s 和以下包从 AUR 中移除:" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "删除软件包是一个永久性的操作" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "选中复选框以确认操作。" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "确认删除包" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "删除" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "只有受信用户和开发人员能删除软件包。" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "弃置软件包" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "使用这个表格来弃置包基础 %s%s%s,其中包括下列软件包:" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "通过选中复选框,您将确认您不愿成为这个包的共同维护者。" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "通过选中复选框,您将确认您将弃置这个包并将其所有权转移给 %s%s%s。" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "通过选中复选框,您将确认您将弃置这个包。" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "继续以弃置包" +#: html/pkgdisown.php msgid "Disown" msgstr "弃置" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "只有受信用户和开发人员能弃置软件包。" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "标记评论" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "将软件包标记为过期" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "使用这个表单将包基础 %s%s%s 和以下包标记为已过期 :" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." msgstr "请 %s不%s 要用这个表单提交问题。请您使用包评论功能。" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"在下面输入为什么这个软件包过期了,最好写一下更新日志的链接或者新版软件压缩包" -"的地址。" +msgstr "在下面输入为什么这个软件包过期了,最好写一下更新日志的链接或者新版软件压缩包的地址。" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "评论" +#: html/pkgflag.php msgid "Flag" msgstr "标记" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "只有已注册的用户才能把软件标记为已过期。" +#: html/pkgmerge.php msgid "Package Merging" msgstr "软件包合并" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "合并软件包" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "使用这个表单将包基础 %s%s%s 合并到另一个包。" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "下面这些软件包将被删除:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "一旦包被合并,这个操作将是不可逆的。" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "请输入合并的目标包名。" +#: html/pkgmerge.php msgid "Merge into:" msgstr "合并到:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "确认合并包" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "合并" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "只有受信用户和开发人员才能删除软件包。" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "提交请求" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "关闭请求" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一页" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一页" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一页" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "末页" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "请求" +#: html/register.php template/header.php msgid "Register" msgstr "注册" +#: html/register.php msgid "Use this form to create an account." msgstr "使用此表单创建帐号。" +#: html/tos.php msgid "Terms of Service" -msgstr "" +msgstr "服务条款" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "以下文件已更新,请仔细审阅:" +#: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "版本 %d" +#: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "我接受以上条款与条件。" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "受信用户" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "无法获取提议详情。" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "该提议的投票已被关闭。" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "只有受信用户可以投票。" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "您不能在关于您的提议里投票。" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "您已经在这个提议上投票了。" +#: html/tu.php msgid "Vote ID not valid." msgstr "非法的投票标识" +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "当前的投票" +#: html/tu.php msgid "Past Votes" msgstr "历史投票" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"账户注册目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引" -"起的不便表示抱歉。" +msgstr "账户注册目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引起的不便表示抱歉。" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "缺少用户标识" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "用户名需要符合以下条件:" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "在 %s 到 %s 个字符之间" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "开头和结尾是数字/英文字母" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一个“.”,“_”,或“-”" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "错误的 Email 地址。" +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "" +msgstr "首页无效,请指定完整的 HTTP(s) URL。" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 密钥指纹无效。" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "此 SSH 公钥无效。" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "不能提高账户权限。" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "目前不支持此语言。" +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "目前不支持此时区。" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "用户名 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "该地址 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公钥 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "尝试创建帐户 %s%s%s 失败。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "帐户 %s%s%s 创建成功。" +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "一个密码重置密钥已经发送到你的电子邮箱。" +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "点击上方的登陆链接以使用你的帐号。" +msgstr "点击上方的登录链接以使用你的帐号。" +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "账户 %s%s%s 没有被修改。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "帐号 %s%s%s 已被成功修改。" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"登陆表单目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引" -"起的不便表示抱歉。" +msgstr "登录表单目前对您所使用的 IP 地址禁用,原因可能是持续的垃圾攻击。我们对因此引起的不便表示抱歉。" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "帐号被停用" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"你的密码已经成功被重置。如果你刚刚创建了一个新账户,请使用确认邮件中的链接来" -"设置一个初始密码。否则,请在 %s重置密码%s 页面申请一个重置密码密钥。" +msgstr "你的密码已经成功被重置。如果你刚刚创建了一个新账户,请使用确认邮件中的链接来设置一个初始密码。否则,请在 %s重置密码%s 页面申请一个重置密码密钥。" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "用户名或密码错误。" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "在创建用户会话的过程中出现了一个错误。" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "邮箱和重置 key 不匹配。" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "无" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "查看 %s 的账户信息" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "缺少软件包基础 ID 或软件包名。" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "你没有权限编辑评论。" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "评论不存在。" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "评论不能为空。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "已经添加评论。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "您需要登录后才能编辑软件包信息。" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "评论标识丢失。" +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "不能同时锁定 5 条以上的评论。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "你没有权限锁定这条评论。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "你没有权限解锁这条评论。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "评论已锁定。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "评论已解锁。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "获取软件包详情时发生错误。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "无法找到软件包的详细信息。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "您需要登录后才能标记软件包。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "您没有选择要标记的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "选中的软件包已被标记,请输入评论。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "选择的软件包已被标记为过期。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "您需要登录后才能移除软件包标记。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "您没有选择要取消标记的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "选中的软件包的标记已被移除。" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "您没有删除软件包的权限。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "您没有选择要删除的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "选中的软件包已经被删除。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." -msgstr "登陆后才能接管软件包" +msgstr "登录后才能接管软件包" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "您需要登录后才能弃置软件包。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "您没有选择要接管的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "您没有选择要弃置的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "选择的软件包已经被接管。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "选中的软件包已经被弃置。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "您需要登录后才能为软件包投票。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "您需要登录后才能为软件包取消投票。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "您没有选择要投票的软件包。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "您对所选软件包的投票已被取消。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "您对所选软件包的投票已被记录。" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "无法将您添加到通知列表。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "您已被成功添加到 %s 的评论通知列表。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "您将不再收到 %s 的评论通知。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "你没有权限恢复这条评论。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "评论已恢复。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "您没有权限删除此评论。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "评论已被删除。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "评论已编辑。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "你没有权限编辑这个软件包基础的关键词。" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "软件包基础的关键词已被更新。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "你没有权限管理这个软件包基础的共同管理者。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "非法用户名:%s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "软件包基础的共同维护者已更新。" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "查看软件包详细信息" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "需要 %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "登录之后才能提交软件包需求。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "无效的名称: 只允许小写字母。" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "评论内容不能为空。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "无效的请求类型。" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "请求提交成功。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "无效的理由。" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "只有受信用户和开发者可以关闭请求。" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "请求关闭成功。" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "你可以使用这个表单来彻底删除 AUR 帐号 %s。" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s:这个操作无法被撤销" +#: template/account_delete.php msgid "Confirm deletion" msgstr "确认删除" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "用户名" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "帐户类别" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "用户" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "开发人员" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "受信用户 & 开发者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "Email" +#: template/account_details.php msgid "hidden" msgstr "已隐藏" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "真实名字" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "首页" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC昵称" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 密钥指纹" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "状态" +#: template/account_details.php msgid "Inactive since" msgstr "不活跃自" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "激活" +#: template/account_details.php msgid "Registration date:" msgstr "注册日期:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "未知" +#: template/account_details.php msgid "Last Login" -msgstr "最后登陆" +msgstr "最后登录" +#: template/account_details.php msgid "Never" msgstr "从不" +#: template/account_details.php msgid "View this user's packages" msgstr "查看这个用户提交的软件包" +#: template/account_details.php msgid "Edit this user's account" msgstr "编辑此用户的帐号" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果你想要彻底删除这个帐号,请点击%s这里%s。" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "点击 %s这里%s 访问用户详情页面" +#: template/account_edit_form.php msgid "required" msgstr "必填" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." -msgstr "" +msgstr "您的用户名称将用于您的登录。这是公开的,即使您的账户不活跃。" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "普通用户" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "受信用户" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "帐户被暂停" +#: template/account_edit_form.php msgid "Inactive" msgstr "不活跃" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." -msgstr "请确认你正确地输入了你的 E-mail,或者你将会被锁定。" +msgstr "请确认你正确地输入了你的 E-mail,否则你将会被锁定。" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "隐藏 E-mail" +#: template/account_edit_form.php msgid "Re-type password" msgstr "确认密码" +#: template/account_edit_form.php msgid "Language" msgstr "语言" +#: template/account_edit_form.php msgid "Timezone" msgstr "时区" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "仅仅当你想要向 AUR 提交软件包时才需要填写以下信息。" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH 公钥" +#: template/account_edit_form.php msgid "Notification settings" msgstr "提醒设置" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "当有新评论的时候提醒我" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "软件包更新提醒" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "所有权更改提醒" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "更新" +#: template/account_edit_form.php msgid "Create" msgstr "创建" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "重填" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "没有结果符合您的搜索条件。" +#: template/account_search_results.php msgid "Edit Account" msgstr "编辑帐户" +#: template/account_search_results.php msgid "Suspended" msgstr "暂停" +#: template/account_search_results.php msgid "Edit" msgstr "编辑" +#: template/account_search_results.php msgid "Less" msgstr "更少" +#: template/account_search_results.php msgid "More" msgstr "更多" +#: template/account_search_results.php msgid "No more results to display." msgstr "没有更多的结果供显示。" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "使用这个表单来添加 %s%s%s 的共同维护者(一个用户名一行):" +#: template/comaintainers_form.php msgid "Users" msgstr "用户" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "保存" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "已标记为过期的评论:%s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "%s%s%s 标记了 %s%s%s 为过期,在 %s%s%s,因为以下原因:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s 未被标记为过期。" +#: template/flag_comment.php msgid "Return to Details" msgstr "返回详情" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "版权所有 %s 2004-%d aurweb 开发组" +#: template/header.php msgid " My Account" msgstr "我的帐户" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "软件包操作" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "查看 PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "查看更改" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "下载快照" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "搜索 Wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "已标记为过期 (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "将软件包标记为过期" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "取消标记软件包" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "移除投票" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "为这个软件包投票" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "禁用通知" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "启用通知" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "管理共同维护者" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 个未处理的请求" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "接管软件包" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "包基础详情" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git 克隆地址" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "只读" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "关键字" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "提交人" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "维护者" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最近一次打包者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "得票" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "受欢迎度" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "首次提交" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最后更新" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "编辑 %s 的评论" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "添加评论" +#: template/pkg_comments.php msgid "View all comments" msgstr "查看所有评论" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "已锁定评论" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "最新的评论" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s 在 %s 发表了评论" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "在 %s 发表的匿名评论" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "在 %s 被 %s 删除" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "在 %s 被删除" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "在 %s 被 %s 编辑" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "在 %s 被编辑" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "恢复评论" +#: template/pkg_comments.php msgid "Delete comment" msgstr "删除评论" +#: template/pkg_comments.php msgid "Pin comment" msgstr "锁定评论" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "解锁评论" +#: template/pkg_comments.php msgid "All comments" msgstr "全部评论" +#: template/pkg_details.php msgid "Package Details" msgstr "软件包详情" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "包基础" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "描述" +#: template/pkg_details.php msgid "Upstream URL" msgstr "上游 URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "访问网站" +#: template/pkg_details.php msgid "Licenses" msgstr "许可协议" +#: template/pkg_details.php msgid "Groups" msgstr "组" +#: template/pkg_details.php msgid "Conflicts" msgstr "冲突" +#: template/pkg_details.php msgid "Provides" msgstr "提供" +#: template/pkg_details.php msgid "Replaces" msgstr "取代" +#: template/pkg_details.php msgid "Dependencies" msgstr "依赖于:" +#: template/pkg_details.php msgid "Required by" msgstr "被需要:" +#: template/pkg_details.php msgid "Sources" msgstr "源代码:" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "使用这个表单来关闭对包基础 %s%s%s 的请求。" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "评论可以留空。不过,当拒绝一个请求的时候,强烈推荐提供一条评论。" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "原因" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "已接受" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "已拒绝" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "使用这个表格,提交一个针对包基础 %s%s%s 的请求,其中包括下列软件包:" +#: template/pkgreq_form.php msgid "Request type" msgstr "请求类型" +#: template/pkgreq_form.php msgid "Deletion" msgstr "删除" +#: template/pkgreq_form.php msgid "Orphan" msgstr "弃置" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "合并到" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"通过提交删除请求,您请求受信用户进行包基础的删除。这种请求应当被用于重复,软" -"件被上游放弃,非法或损坏且无法修复的软件包。" +msgstr "通过提交删除请求,您请求受信用户进行包基础的删除。这种请求应当被用于重复,软件被上游放弃,非法或损坏且无法修复的软件包。" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"通过提交合并请求,您请求受信用户进行包基础的删除,并转移其投票和评论到另一包" -"基础。合并一个软件包不会影响对应的 Git 项目,因此您需要自己更新目标软件包的 " -"Git 项目。" +msgstr "通过提交合并请求,您请求受信用户进行包基础的删除,并转移其投票和评论到另一包基础。合并一个软件包不会影响对应的 Git 项目,因此您需要自己更新目标软件包的 Git 项目。" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"通过提交弃置请求,您请求受信用户进行包基础的弃置。请仅在软件包需要维护者操" -"作,您之前已经尝试联系过维护者但没有回应时提交请求。" +msgstr "通过提交弃置请求,您请求受信用户进行包基础的弃置。请仅在软件包需要维护者操作,您之前已经尝试联系过维护者但没有回应时提交请求。" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "没有请求符合您的搜索条件。" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "找到了 %d 个软件包请求。" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "第 %d 页,共 %d 页。" +#: template/pkgreq_results.php msgid "Package" msgstr "软件包" +#: template/pkgreq_results.php msgid "Filed by" msgstr "提交者是" +#: template/pkgreq_results.php msgid "Date" msgstr "日期" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "剩余约 %d 天" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "剩余约 %d 小时" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "剩余不到 1 小时" +#: template/pkgreq_results.php msgid "Accept" msgstr "接受" +#: template/pkgreq_results.php msgid "Locked" msgstr "已锁定" +#: template/pkgreq_results.php msgid "Close" msgstr "关闭" +#: template/pkgreq_results.php msgid "Pending" msgstr "等待中" +#: template/pkgreq_results.php msgid "Closed" msgstr "已关闭" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "名称和描述" +#: template/pkg_search_form.php msgid "Name Only" msgstr "名称" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "确切的名字" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "准确包基础" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "共同维护者" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "维护者,共同维护者" +#: template/pkg_search_form.php msgid "All" msgstr "全部" +#: template/pkg_search_form.php msgid "Flagged" msgstr "已标记" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "未标记" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名称" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "已投票" +#: template/pkg_search_form.php msgid "Last modified" msgstr "上次修改" +#: template/pkg_search_form.php msgid "Ascending" msgstr "从小到大" +#: template/pkg_search_form.php msgid "Descending" msgstr "从大到小" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "输入搜索条件" +#: template/pkg_search_form.php msgid "Search by" msgstr "搜索" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "过期状态" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "排列依据" +#: template/pkg_search_form.php msgid "Sort order" msgstr "排列方式" +#: template/pkg_search_form.php msgid "Per page" msgstr "每页显示" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "Go" +#: template/pkg_search_form.php msgid "Orphans" msgstr "孤儿包" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "无法获取包列表。" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "没有相关的软件包符合您的搜索条件。" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "找到了 %d 个软件包。" +#: template/pkg_search_results.php msgid "Version" msgstr "版本" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "受欢迎度通过将每次投票以系数为每天 %.2f 的权重加权求和计算。" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "是" +#: template/pkg_search_results.php msgid "orphan" msgstr "孤儿包" +#: template/pkg_search_results.php msgid "Actions" msgstr "操作" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "移除过期标记" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "接管软件包" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "弃置软件包" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "删除软件包" +#: template/pkg_search_results.php msgid "Confirm" msgstr "确认" +#: template/search_accounts_form.php msgid "Any type" msgstr "所有类别" +#: template/search_accounts_form.php msgid "Search" msgstr "搜索" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "统计" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "无人维护的软件包" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "7天内新增的软件包" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "7天内更新的软件包" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "一年内更新的软件包" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "从未更新的软件包" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "注册用户" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "受信用户" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最新更新" +#: template/stats/updates_table.php msgid "more" msgstr "更多" +#: template/stats/user_table.php msgid "My Statistics" msgstr "我的统计" +#: template/tu_details.php msgid "Proposal Details" msgstr "提议详情" +#: template/tu_details.php msgid "This vote is still running." msgstr "投票仍在继续。" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "已提交 %s 由 %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "结束" +#: template/tu_details.php msgid "Result" msgstr "结果" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "否" +#: template/tu_details.php msgid "Abstain" msgstr "弃权" +#: template/tu_details.php msgid "Total" msgstr "总数" +#: template/tu_details.php msgid "Participation" msgstr "参与" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "受信用户的最后投票" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最后投票" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "没有找到结果。" +#: template/tu_list.php msgid "Start" msgstr "开始" +#: template/tu_list.php msgid "Back" msgstr "返回" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "重置 AUR 密码" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "关联此邮件地址的用户 {user} 的重置密码请求已经提交。如果您想要重置密码,请点击以下链接 [1],否则忽略此消息。" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "欢迎来到 Arch 用户软件仓库" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "欢迎来到 Arch 用户软件仓库!想要为你的新账户设置初始密码,请点击下面的链接 [1]。如果链接不工作,请尝试复制它到你的浏览器中打开。" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "AUR 软件包评论:{pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "用户 {user} [1] 在软件包 {pkgbase} [2] 下进行了如下评论:" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "若您不愿再收到关于此软件包的通知,请到此软件包页面 [2] 并选择 \"{label}\"。" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "AUR 软件包更新:{pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "用户 {user} [1] 在软件包 {pkgbase} [2] 上传了新的提交:" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "AUR 软件包过期通知:{pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "您的软件包 {pkgbase} [1] 已被用户 {user} [2] 标记为过期:" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "AUR 软件包所有权通知:{pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "软件包 {pkgbase} [1] 已被用户 {user} [2] 接管。" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "软件包 {pkgbase} [1] 已被用户 {user} [2] 弃置。" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "AUR 软件包共同维护者通知:{pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "您已被添加到软件包 {pkgbase} [1] 的共同维护者列表。" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "您已被移出软件包 {pkgbase} [1] 的共同维护者列表。" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "AUR 软件包删除:{pkgbase}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "用户 {user} [1] 将原软件包 {old} [2] 并入新软件包 {new} [3]。\n\n若您不愿再收到关于新软件包的通知,请到此软件包页面 [3] 并点击 \"{label}\"。" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "用户 {user} [1] 删除了软件包 {pkgbase} [2]。\n\n您将不再收到此软件包的评论通知。" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "受信用户投票提醒:提案 {id}" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "请记得为提案 {id} [1] 投票,投票时段将于48小时内结束。" diff --git a/po/zh_TW.po b/po/zh_TW.po index ad90859c..43292889 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1,1559 +1,2128 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AUR package. -# +# # Translators: # Jeff Huang , 2014-2017 msgid "" msgstr "" -"Project-Id-Version: Arch User Repository (AUR)\n" +"Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2017-11-27 16:23+0100\n" -"PO-Revision-Date: 2017-11-28 11:49+0000\n" -"Last-Translator: Jeff Huang \n" -"Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aur/" -"language/zh_TW/)\n" -"Language: zh_TW\n" +"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"PO-Revision-Date: 2018-05-18 04:38+0000\n" +"Last-Translator: Lukas Fleischer \n" +"Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aurweb/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: html/404.php msgid "Page Not Found" msgstr "頁面找不到" +#: html/404.php msgid "Sorry, the page you've requested does not exist." msgstr "抱歉,您所請求的頁面不存在。" +#: html/404.php template/pkgreq_close_form.php msgid "Note" msgstr "注意" +#: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." msgstr "Git clone 的網址並不代表可以在瀏覽器中開啟。" +#: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." msgstr "要 clone %s 的 Git 倉庫,執行 %s。" +#: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." msgstr "點選 %s此處%s 以回到 %s 的詳細資訊頁面。" +#: html/503.php msgid "Service Unavailable" msgstr "服務不可用" +#: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." msgstr "別緊張!這個頁面因維護而暫時下線。我們很快就會回來。" +#: html/account.php msgid "Account" msgstr "帳號" +#: html/account.php template/header.php msgid "Accounts" msgstr "帳號" +#: html/account.php html/addvote.php msgid "You are not allowed to access this area." msgstr "您不被允許存取此區域。" +#: html/account.php msgid "Could not retrieve information for the specified user." msgstr "無法擷取指定使用者的資訊。" +#: html/account.php msgid "You do not have permission to edit this account." msgstr "您沒有權限編輯此帳號。" +#: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表單來搜尋已有的帳號。" +#: html/account.php msgid "You must log in to view user information." msgstr "您必須登入才能檢視使用者資訊。" +#: html/addvote.php template/tu_list.php msgid "Add Proposal" msgstr "添加建議" +#: html/addvote.php msgid "Invalid token for user action." msgstr "無效的使用者動作標誌。" +#: html/addvote.php msgid "Username does not exist." msgstr "使用者名稱不存在。" +#: html/addvote.php #, php-format msgid "%s already has proposal running for them." msgstr "%s 已經有了關於他們的建議。" +#: html/addvote.php msgid "Invalid type." msgstr "無效的類型。" +#: html/addvote.php msgid "Proposal cannot be empty." msgstr "建議不能為空。" +#: html/addvote.php msgid "New proposal submitted." msgstr "已提交新的建議。" +#: html/addvote.php msgid "Submit a proposal to vote on." msgstr "提交一個建議用於投票。" +#: html/addvote.php msgid "Applicant/TU" msgstr "申請人/受信使用者" +#: html/addvote.php msgid "(empty if not applicable)" msgstr "(如果不符合可以留空)" +#: html/addvote.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Type" msgstr "類型" +#: html/addvote.php msgid "Addition of a TU" msgstr "添加受信使用者" +#: html/addvote.php msgid "Removal of a TU" msgstr "移除受信使用者" +#: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" msgstr "移除受信使用者(無故不活躍)" +#: html/addvote.php msgid "Amendment of Bylaws" msgstr "修定規則" +#: html/addvote.php template/tu_list.php msgid "Proposal" msgstr "建議" +#: html/addvote.php msgid "Submit" msgstr "提交" +#: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" msgstr "管理共同維護者" +#: html/commentedit.php template/pkg_comments.php msgid "Edit comment" msgstr "編輯評論" +#: html/home.php template/header.php msgid "Dashboard" msgstr "儀表板" +#: html/home.php template/header.php msgid "Home" msgstr "首頁" +#: html/home.php msgid "My Flagged Packages" msgstr "我標記的套件" +#: html/home.php msgid "My Requests" msgstr "我的請求" +#: html/home.php msgid "My Packages" msgstr "我的套件" +#: html/home.php msgid "Search for packages I maintain" msgstr "搜尋我維護的套件" +#: html/home.php msgid "Co-Maintained Packages" msgstr "共同維護的套件" +#: html/home.php msgid "Search for packages I co-maintain" msgstr "搜尋我共同維護的套件" +#: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" -"歡迎來到 AUR!請閱讀 %sAUR 使用者指導方針%s 和 %sAUR 受信使用者指導方針%s 以" -"獲取更多的詳細資訊。" +msgstr "歡迎來到 AUR!請閱讀 %sAUR 使用者指導方針%s 和 %sAUR 受信使用者指導方針%s 以獲取更多的詳細資訊。" +#: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" -"所貢獻的 PKGBUILDs 和 PKGINFOs %s必須%s 符合 %sArch 打包標準%s 否則將被被刪" -"除! " +msgstr "所貢獻的 PKGBUILDs 和 PKGINFOs %s必須%s 符合 %sArch 打包標準%s 否則將被被刪除! " +#: html/home.php msgid "Remember to vote for your favourite packages!" msgstr "記得投一票給您喜愛的套件!" +#: html/home.php msgid "Some packages may be provided as binaries in [community]." msgstr "某些套件可能會在 [community] 提供二進位檔案。" +#: html/home.php msgid "DISCLAIMER" msgstr "免責聲明" +#: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." msgstr "AUR 上的檔案是使用者產生的內容。任何使用檔案造成的風險由您自行承擔。" +#: html/home.php msgid "Learn more..." msgstr "了解更多..." +#: html/home.php msgid "Support" msgstr "支援" +#: html/home.php msgid "Package Requests" msgstr "套件請求" +#: html/home.php #, php-format msgid "" -"There are three types of requests that can be filed in the %sPackage Actions" -"%s box on the package details page:" +"There are three types of requests that can be filed in the %sPackage " +"Actions%s box on the package details page:" msgstr "有三種您可以在套件細節頁面中的 %s套件動作%s 中使用的請求:" +#: html/home.php msgid "Orphan Request" msgstr "棄置請求" +#: html/home.php msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" -"請求一個套件被解除擁有權,例如:當維護者不活躍且套件已經被標記為過期很長一段" -"時間。" +msgstr "請求一個套件被解除擁有權,例如:當維護者不活躍且套件已經被標記為過期很長一段時間。" +#: html/home.php msgid "Deletion Request" msgstr "刪除請求" +#: html/home.php msgid "" -"Request a package to be removed from the Arch User Repository. Please do not " -"use this if a package is broken and can be fixed easily. Instead, contact " +"Request a package to be removed from the Arch User Repository. Please do not" +" use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "" -"請求套件從 Arch 使用者套件庫中移除。如果套件損毀但可以很容易的被修復,請不要" -"使用這個請求。您應該聯絡套件維護者,並在必要時提出棄置請求。" +msgstr "請求套件從 Arch 使用者套件庫中移除。如果套件損毀但可以很容易的被修復,請不要使用這個請求。您應該聯絡套件維護者,並在必要時提出棄置請求。" +#: html/home.php msgid "Merge Request" msgstr "合併請求" +#: html/home.php msgid "" "Request a package to be merged into another one. Can be used when a package " "needs to be renamed or replaced by a split package." -msgstr "" -"請求將一個套件合併到另一個。可以使用在需要重新命名或是由分裂的套件所取代的套" -"件。" +msgstr "請求將一個套件合併到另一個。可以使用在需要重新命名或是由分裂的套件所取代的套件。" +#: html/home.php #, php-format msgid "" "If you want to discuss a request, you can use the %saur-requests%s mailing " "list. However, please do not use that list to file requests." -msgstr "" -"如果您想要討論某一個請求,您可以使用 %saur-requests%s 郵件列表。但請不要使用" -"這個列表來提出請求。" +msgstr "如果您想要討論某一個請求,您可以使用 %saur-requests%s 郵件列表。但請不要使用這個列表來提出請求。" +#: html/home.php msgid "Submitting Packages" msgstr "遞交套件" +#: html/home.php #, php-format msgid "" -"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting " -"packages%s section of the Arch User Repository ArchWiki page for more " +"Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" +" packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "" -"現在遞交套件到 AUR 上的方法是透過 SSH 的 Git。參見 ArchWiki 上的 Arch User " -"Repository 頁面之 %s遞交套件%s 章節以取得更多資訊。" +msgstr "現在遞交套件到 AUR 上的方法是透過 SSH 的 Git。參見 ArchWiki 上的 Arch User Repository 頁面之 %s遞交套件%s 章節以取得更多資訊。" +#: html/home.php msgid "The following SSH fingerprints are used for the AUR:" msgstr "AUR 使用下列 SSH 指紋:" +#: html/home.php msgid "Discussion" msgstr "討論" +#: html/home.php #, php-format msgid "" -"General discussion regarding the Arch User Repository (AUR) and Trusted User " -"structure takes place on %saur-general%s. For discussion relating to the " +"General discussion regarding the Arch User Repository (AUR) and Trusted User" +" structure takes place on %saur-general%s. For discussion relating to the " "development of the AUR web interface, use the %saur-dev%s mailing list." -msgstr "" -"與 Arch 使用者套件庫(AUR)及受信使用者結構相關的一般性討論請見 %saur-general" -"%s 。討論關於 AUR 網頁介面的開發,請使用 %saur-dev%s 郵件列表。" +msgstr "與 Arch 使用者套件庫(AUR)及受信使用者結構相關的一般性討論請見 %saur-general%s 。討論關於 AUR 網頁介面的開發,請使用 %saur-dev%s 郵件列表。" +#: html/home.php msgid "Bug Reporting" msgstr "臭蟲回報" +#: html/home.php #, php-format msgid "" "If you find a bug in the AUR web interface, please fill out a bug report on " -"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface " -"%sonly%s. To report packaging bugs contact the package maintainer or leave a " -"comment on the appropriate package page." -msgstr "" -"如果您在 AUR 網頁介面中發現了臭蟲,請在我們的 %s臭蟲追蹤系統%s 中回報。請%s" -"只%s回報 AUR 網頁介面本身的臭蟲。要回報打包臭蟲,請連絡套件的維護者或是在對應" -"的套件頁面中留下評論。" +"our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" +" %sonly%s. To report packaging bugs contact the package maintainer or leave " +"a comment on the appropriate package page." +msgstr "如果您在 AUR 網頁介面中發現了臭蟲,請在我們的 %s臭蟲追蹤系統%s 中回報。請%s只%s回報 AUR 網頁介面本身的臭蟲。要回報打包臭蟲,請連絡套件的維護者或是在對應的套件頁面中留下評論。" +#: html/home.php msgid "Package Search" msgstr "搜尋套件" +#: html/index.php msgid "Adopt" msgstr "接管" +#: html/index.php msgid "Vote" msgstr "投票" +#: html/index.php msgid "UnVote" msgstr "取消投票" +#: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" msgstr "通知" +#: html/index.php template/pkg_search_results.php msgid "UnNotify" msgstr "取消通知" +#: html/index.php msgid "UnFlag" msgstr "取消標記" +#: html/login.php template/header.php msgid "Login" msgstr "登入" +#: html/login.php html/tos.php #, php-format msgid "Logged-in as: %s" msgstr "已登入為: %s" +#: html/login.php template/header.php msgid "Logout" msgstr "登出" +#: html/login.php msgid "Enter login credentials" msgstr "輸入登入資訊" +#: html/login.php msgid "User name or email address" msgstr "使用者名稱或電子郵件地址" +#: html/login.php template/account_edit_form.php msgid "Password" msgstr "密碼" +#: html/login.php msgid "Remember me" msgstr "記住我" +#: html/login.php msgid "Forgot Password" msgstr "忘記密碼" +#: html/login.php #, php-format msgid "" "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." msgstr "HTTP 登入已被停用。如果您想要登入的話,請 %s切換至HTTPs%s 。" +#: html/packages.php template/pkg_search_form.php msgid "Search Criteria" msgstr "搜尋條件" +#: html/packages.php template/header.php template/pkgbase_details.php +#: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" msgstr "套件" +#: html/packages.php msgid "Error trying to retrieve package details." msgstr "嘗試擷取套件細節時發生錯誤。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." msgstr "缺少必填項目。" +#: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." msgstr "密碼不符合。" +#: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." msgstr "您的密碼必須至少 %s 個字節。" +#: html/passreset.php msgid "Invalid e-mail." msgstr "無效的電子郵件。" +#: html/passreset.php msgid "Password Reset" msgstr "密碼重置" +#: html/passreset.php msgid "Check your e-mail for the confirmation link." msgstr "請檢查您的電子郵件信箱裡是否有確認連結。" +#: html/passreset.php msgid "Your password has been reset successfully." msgstr "您的密碼已成功重置。" +#: html/passreset.php msgid "Confirm your e-mail address:" msgstr "確認您的電子郵件位置:" +#: html/passreset.php msgid "Enter your new password:" msgstr "輸入您的新密碼:" +#: html/passreset.php msgid "Confirm your new password:" msgstr "確認您的新密碼:" +#: html/passreset.php html/tos.php msgid "Continue" msgstr "繼續" +#: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." -msgstr "" -"如果您忘了您用來註冊的電子郵件地址,請寄一封訊息到 %saur-general%s 郵件列表" -"中。" +"If you have forgotten the e-mail address you used to register, please send a" +" message to the %saur-general%s mailing list." +msgstr "如果您忘了您用來註冊的電子郵件地址,請寄一封訊息到 %saur-general%s 郵件列表中。" +#: html/passreset.php msgid "Enter your e-mail address:" msgstr "輸入您的電子郵件地址:" +#: html/pkgbase.php msgid "Package Bases" msgstr "套件基礎" +#: html/pkgbase.php msgid "" "The selected packages have not been disowned, check the confirmation " "checkbox." msgstr "選取的套件未被棄置,請檢查確認的核取方塊。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." msgstr "找不到合併投票與評論的目標套件。" +#: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot merge a package base with itself." msgstr "無法將一個套件基礎與它自己合併。" +#: html/pkgbase.php msgid "" -"The selected packages have not been deleted, check the confirmation checkbox." +"The selected packages have not been deleted, check the confirmation " +"checkbox." msgstr "選取的套件未被刪除,請檢查確認的核取方塊。" +#: html/pkgdel.php msgid "Package Deletion" msgstr "套件刪除" +#: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" msgstr "刪除套件" +#: html/pkgdel.php #, php-format msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " msgstr "使用這個表單以從 AUR 刪除套件基礎 %s%s%s 以及以下的套件。" +#: html/pkgdel.php msgid "Deletion of a package is permanent. " msgstr "套件刪除是永久性的操作。" +#: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." msgstr "選取核取方塊以確認動作。" +#: html/pkgdel.php msgid "Confirm package deletion" msgstr "確認套件刪除" +#: html/pkgdel.php template/account_delete.php msgid "Delete" msgstr "刪除" +#: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." msgstr "只有受信使用者和開發者可以刪除套件。" +#: html/pkgdisown.php template/pkgbase_actions.php msgid "Disown Package" msgstr "棄置套件" +#: html/pkgdisown.php #, php-format msgid "" -"Use this form to disown the package base %s%s%s which includes the following " -"packages: " +"Use this form to disown the package base %s%s%s which includes the following" +" packages: " msgstr "使用這個表單以棄置一個包含以下套件的套件基礎 %s%s%s :" +#: html/pkgdisown.php +msgid "" +"By selecting the checkbox, you confirm that you want to no longer be a " +"package co-maintainer." +msgstr "" + +#: html/pkgdisown.php #, php-format msgid "" "By selecting the checkbox, you confirm that you want to disown the package " "and transfer ownership to %s%s%s." msgstr "透過選取核取方塊,您就會確認您想要棄置此套件並轉移所有權給 %s%s%s。" +#: html/pkgdisown.php msgid "" "By selecting the checkbox, you confirm that you want to disown the package." msgstr "透過選取核取方塊,您就會確認您想要棄置此套件。" +#: html/pkgdisown.php msgid "Confirm to disown the package" msgstr "確認棄置此套件" +#: html/pkgdisown.php msgid "Disown" msgstr "棄置" +#: html/pkgdisown.php msgid "Only Trusted Users and Developers can disown packages." msgstr "只有受信使用者和開發者可以棄置套件。" +#: html/pkgflagcomment.php msgid "Flag Comment" msgstr "標記評論" +#: html/pkgflag.php msgid "Flag Package Out-Of-Date" msgstr "將套件標記為過期" +#: html/pkgflag.php #, php-format msgid "" -"Use this form to flag the package base %s%s%s and the following packages out-" -"of-date: " +"Use this form to flag the package base %s%s%s and the following packages " +"out-of-date: " msgstr "使用這個表單來標記套件基礎 %s%s%s 以及以下的套件已過期:" +#: html/pkgflag.php #, php-format msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "" -"請 %s不要%s 使用此表單來回報臭蟲。打包臭蟲應使用套件頁面的評論功能回報。" +msgstr "請 %s不要%s 使用此表單來回報臭蟲。打包臭蟲應使用套件頁面的評論功能回報。" +#: html/pkgflag.php msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "" -"在下面輸入要將套件標記為過期的詳細原因,最好包括釋出公告或是新版 tarball 的連" -"結。" +msgstr "在下面輸入要將套件標記為過期的詳細原因,最好包括釋出公告或是新版 tarball 的連結。" +#: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php +#: template/pkgreq_results.php msgid "Comments" msgstr "評論" +#: html/pkgflag.php msgid "Flag" msgstr "標記" +#: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." msgstr "只有已註冊的使用者可以標記套件為過期。" +#: html/pkgmerge.php msgid "Package Merging" msgstr "套件合併" +#: html/pkgmerge.php template/pkgbase_actions.php msgid "Merge Package" msgstr "合併套件" +#: html/pkgmerge.php #, php-format msgid "Use this form to merge the package base %s%s%s into another package. " msgstr "使用這個表單以合併套件基礎 %s%s%s 以及其他套件。" +#: html/pkgmerge.php msgid "The following packages will be deleted: " msgstr "以下套件將會被刪除:" +#: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " msgstr "套件一經合併即無法回復。" +#: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " msgstr "請輸入您想要合併到該套件的套件名稱。" +#: html/pkgmerge.php msgid "Merge into:" msgstr "合併到:" +#: html/pkgmerge.php msgid "Confirm package merge" msgstr "確認套件合併" +#: html/pkgmerge.php template/pkgreq_form.php msgid "Merge" msgstr "合併" +#: html/pkgmerge.php msgid "Only Trusted Users and Developers can merge packages." msgstr "只有受信使用者和開發者可以合併套件。" +#: html/pkgreq.php template/pkgbase_actions.php template/pkgreq_form.php msgid "Submit Request" msgstr "遞交請求" +#: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" msgstr "關閉請求" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一頁" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一頁" +#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一頁" +#: html/pkgreq.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後一頁" +#: html/pkgreq.php template/header.php msgid "Requests" msgstr "請求" +#: html/register.php template/header.php msgid "Register" msgstr "註冊" +#: html/register.php msgid "Use this form to create an account." msgstr "使用此表單來新建一個帳號。" +#: html/tos.php msgid "Terms of Service" msgstr "服務條款" +#: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" msgstr "以下的文件已更新。請小心審閱它們:" +#: html/tos.php #, php-format msgid "revision %d" msgstr "修訂版本:%d" +#: html/tos.php msgid "I accept the terms and conditions above." msgstr "我接受上述條款與條件。" +#: html/tu.php template/account_details.php template/header.php msgid "Trusted User" msgstr "受信使用者" +#: html/tu.php msgid "Could not retrieve proposal details." msgstr "無法取得建議的細節。" +#: html/tu.php msgid "Voting is closed for this proposal." msgstr "這個建議的投票已被關閉。" +#: html/tu.php msgid "Only Trusted Users are allowed to vote." msgstr "只有受信使用者可以投票。" +#: html/tu.php msgid "You cannot vote in an proposal about you." msgstr "您不能在關於您的建議中投票。" +#: html/tu.php msgid "You've already voted for this proposal." msgstr "您已經在此建議上投過票了。" +#: html/tu.php msgid "Vote ID not valid." msgstr "投票的 ID 無效。" +#: html/tu.php template/tu_list.php msgid "Current Votes" msgstr "目前的投票" +#: html/tu.php msgid "Past Votes" msgstr "過去投票" +#: html/voters.php template/tu_details.php msgid "Voters" msgstr "投票者" +#: lib/acctfuncs.inc.php msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"帳號註冊在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們" -"為您的不便致歉。" +msgstr "帳號註冊在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們為您的不便致歉。" +#: lib/acctfuncs.inc.php msgid "Missing User ID" msgstr "遺失使用者 ID" +#: lib/acctfuncs.inc.php msgid "The username is invalid." msgstr "使用者名稱無效。" +#: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" msgstr "使用者名稱的長度必須在 %s 到 %s 個字節間。" +#: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" msgstr "以字母或數字當做開頭或結尾" +#: lib/acctfuncs.inc.php msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一個「.」、「_」或「-」。" +#: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "電子郵件地址無效。" +#: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "首頁無效,請指定完整的 HTTP(s) URL。" +#: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." msgstr "PGP 密鑰指紋無效。" +#: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." msgstr "SSH 公開金鑰無效。" +#: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." msgstr "無法提升帳號權限。" +#: lib/acctfuncs.inc.php msgid "Language is not currently supported." msgstr "目前不支援此語言。" +#: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." msgstr "目前不支援時區。" +#: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." msgstr "使用者名稱 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." msgstr "該位址 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開金鑰,%s%s%s,已在使用中。" +#: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." msgstr "嘗試建立帳號 %s%s%s 時發生錯誤。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." msgstr "帳號 %s%s%s 已成功建立。" +#: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." msgstr "一個密碼重置密鑰已寄到您的電子郵件信箱中。" +#: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." msgstr "點擊上面的登入連結以使用您的帳號。" +#: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." msgstr "帳號 %s%s%s 沒有被修改。" +#: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." msgstr "帳號 %s%s%s 已成功修改。" +#: lib/acctfuncs.inc.php msgid "" "The login form is currently disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "" -"登入表單在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們" -"為您的不便致歉。" +msgstr "登入表單在您目前所使用的 IP 位址被停用,可能是因為一些持續性的垃圾攻擊。我們為您的不便致歉。" +#: lib/acctfuncs.inc.php msgid "Account suspended" msgstr "帳號被暫停" +#: lib/acctfuncs.inc.php #, php-format msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "" -"您的密碼已成功重置。如果您剛建立了一個新帳號,請使用確認郵件中的連結來設定一" -"個初始密碼。否則,請在 %s密碼重置%s 頁面上請求一個重置密鑰。" +msgstr "您的密碼已成功重置。如果您剛建立了一個新帳號,請使用確認郵件中的連結來設定一個初始密碼。否則,請在 %s密碼重置%s 頁面上請求一個重置密鑰。" +#: lib/acctfuncs.inc.php msgid "Bad username or password." msgstr "使用者名稱或密碼錯誤。" +#: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." msgstr "嘗試生成使用者工作階段時發生錯誤。" +#: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." msgstr "無效的電子郵件與密鑰組合。" +#: lib/aur.inc.php template/pkg_details.php msgid "None" msgstr "無" +#: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" msgstr "檢視 %s 的帳號資訊" +#: lib/aurjson.class.php msgid "Package base ID or package base name missing." msgstr "套件基礎的 ID 或套件基礎的名稱遺失。" +#: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." msgstr "您不被允許編輯此評論。" +#: lib/aurjson.class.php msgid "Comment does not exist." msgstr "評論不存在。" +#: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." msgstr "評論不能為空。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been added." msgstr "評論已新增。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." msgstr "您必須先登入才能編輯套件資訊。" +#: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." msgstr "遺失評論 ID。" +#: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." msgstr "只能釘選不超過 5 個評論。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." msgstr "您不被允許釘選這個評論。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to unpin this comment." msgstr "您不被允許解除釘選這個評論。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." msgstr "評論已釘選。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." msgstr "評論已解除釘選。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." msgstr "擷取套件細節時發生錯誤。" +#: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." msgstr "找不到套件的詳細資訊。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "您必須先登入才能標記套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to flag." msgstr "您沒有選擇任何要標記的套件。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have not been flagged, please enter a comment." msgstr "選定的套件尚未被標記,請輸入評論。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been flagged out-of-date." msgstr "選定的套件已被標記為過期。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can unflag packages." msgstr "您必須先登入才能取消標記套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to unflag." msgstr "您沒有選擇任何要取消標記的套件。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been unflagged." msgstr "選定的套件已被取消標記。" +#: lib/pkgbasefuncs.inc.php msgid "You do not have permission to delete packages." msgstr "您沒有權限刪除套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." msgstr "您沒有選取任何要刪除的套件。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." msgstr "選取的套件已刪除。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." msgstr "您必須先登入才能接管套件。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." msgstr "您必須先登入才能棄置套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." msgstr "您沒有選擇任何要接管的套件。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to disown." msgstr "您沒有選擇任何要棄置的套件。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been adopted." msgstr "選定的套件已接管。" +#: lib/pkgbasefuncs.inc.php msgid "The selected packages have been disowned." msgstr "選定的套件已棄置。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can vote for packages." msgstr "您必須先登入才能對套件投票。" +#: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can un-vote for packages." msgstr "您必須先登入才能對套件取消投票。" +#: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to vote for." msgstr "您沒有選擇任何要投票的套件。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been removed from the selected packages." msgstr "您的投票已從選定的套件中被移除。" +#: lib/pkgbasefuncs.inc.php msgid "Your votes have been cast for the selected packages." msgstr "您的投票已加入選定的套件中。" +#: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." msgstr "無法加入到通知清單中。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." msgstr "您已經成功加入到 %s 的評論通知列表。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." msgstr "您已經成功從 %s 的評論通知列表移除。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." msgstr "您不被允許反刪除此則評論。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been undeleted." msgstr "評論已被反刪除。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." msgstr "您不被允許刪除此則評論。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." msgstr "評論已被刪除。" +#: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." msgstr "評論已被編輯。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." msgstr "您不被允許編輯此套件基礎的關鍵字。" +#: lib/pkgbasefuncs.inc.php msgid "The package base keywords have been updated." msgstr "套件基礎關鍵字已更新。" +#: lib/pkgbasefuncs.inc.php msgid "You are not allowed to manage co-maintainers of this package base." msgstr "您不被允許管理此套件基礎的共同維護者。" +#: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" msgstr "無效的使用者名稱:%s" +#: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." msgstr "套件基礎共同維護者已更新。" +#: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" msgstr "檢視套件的詳細資訊" +#: lib/pkgfuncs.inc.php #, php-format msgid "requires %s" msgstr "需要 %s" +#: lib/pkgreqfuncs.inc.php msgid "You must be logged in to file package requests." msgstr "您必須先登入才能匯報套件請求。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid name: only lowercase letters are allowed." msgstr "無效的名稱:只允許小寫字母。" +#: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." msgstr "評論區域不能為空。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid request type." msgstr "無效的請求類型。" +#: lib/pkgreqfuncs.inc.php msgid "Added request successfully." msgstr "成功加入請求。" +#: lib/pkgreqfuncs.inc.php msgid "Invalid reason." msgstr "無效的理由。" +#: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." msgstr "只有受信使用者和開發者可以關閉請求。" +#: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." msgstr "請求關閉成功。" +#: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." msgstr "您可以使用這個表單來永久刪除 AUR 帳號 %s 。" +#: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." msgstr "%s警告%s :此動作無法回復。" +#: template/account_delete.php msgid "Confirm deletion" msgstr "確認刪除" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Username" msgstr "使用者名稱" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Account Type" msgstr "帳號類型" +#: template/account_details.php template/tu_details.php +#: template/tu_last_votes_list.php template/tu_list.php msgid "User" msgstr "使用者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Developer" msgstr "開發者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Trusted User & Developer" msgstr "受信使用者 & 開發者" +#: template/account_details.php template/account_edit_form.php +#: template/search_accounts_form.php msgid "Email Address" msgstr "電子郵件地址" +#: template/account_details.php msgid "hidden" msgstr "已隱藏" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" msgstr "真實名稱" +#: template/account_details.php template/account_edit_form.php msgid "Homepage" msgstr "首頁" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" msgstr "IRC 暱稱" +#: template/account_details.php template/account_edit_form.php +#: template/account_search_results.php msgid "PGP Key Fingerprint" msgstr "PGP 密鑰指紋" +#: template/account_details.php template/account_search_results.php +#: template/pkgreq_results.php msgid "Status" msgstr "狀態" +#: template/account_details.php msgid "Inactive since" msgstr "不活躍自" +#: template/account_details.php template/account_search_results.php msgid "Active" msgstr "活躍" +#: template/account_details.php msgid "Registration date:" msgstr "註冊日期:" +#: template/account_details.php template/pkgbase_details.php +#: template/pkg_details.php template/pkgreq_results.php +#: template/tu_details.php msgid "unknown" msgstr "未知" +#: template/account_details.php msgid "Last Login" msgstr "最後登入" +#: template/account_details.php msgid "Never" msgstr "從未" +#: template/account_details.php msgid "View this user's packages" msgstr "檢視此使用者的套件" +#: template/account_details.php msgid "Edit this user's account" msgstr "編輯此使用者的帳號" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." msgstr "如果您想要永久刪除此帳號,請點擊 %s這裡%s 。" +#: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." msgstr "點選 %s此處%s 來取得使用者的詳細資訊。" +#: template/account_edit_form.php msgid "required" msgstr "必填" +#: template/account_edit_form.php msgid "" "Your user name is the name you will use to login. It is visible to the " "general public, even if your account is inactive." msgstr "您的使用者名稱是您要用於登入的名稱。它是公開的,即使您的帳號已停用。" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" msgstr "一般使用者" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" msgstr "受信使用者" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" msgstr "帳號被暫停" +#: template/account_edit_form.php msgid "Inactive" msgstr "不活躍" +#: template/account_edit_form.php msgid "" "Please ensure you correctly entered your email address, otherwise you will " "be locked out." msgstr "請確保您正確的輸入了您的電子郵件地址,否則您將會被鎖定。" +#: template/account_edit_form.php msgid "Hide Email Address" msgstr "隱藏電子郵件地址" +#: template/account_edit_form.php msgid "Re-type password" msgstr "重新輸入密碼" +#: template/account_edit_form.php msgid "Language" msgstr "語言" +#: template/account_edit_form.php msgid "Timezone" msgstr "時區" +#: template/account_edit_form.php msgid "" -"The following information is only required if you want to submit packages to " -"the Arch User Repository." +"The following information is only required if you want to submit packages to" +" the Arch User Repository." msgstr "以下的資訊僅在您想要遞交套件到 Arch 使用者套件庫時是必須的。" +#: template/account_edit_form.php msgid "SSH Public Key" msgstr "SSH 公開金鑰" +#: template/account_edit_form.php msgid "Notification settings" msgstr "通知設定" +#: template/account_edit_form.php msgid "Notify of new comments" msgstr "接收新評論通知" +#: template/account_edit_form.php msgid "Notify of package updates" msgstr "通知套件更新" +#: template/account_edit_form.php msgid "Notify of ownership changes" msgstr "擁有者變更通知" +#: template/account_edit_form.php template/pkgbase_details.php +#: template/pkg_details.php msgid "Update" msgstr "更新" +#: template/account_edit_form.php msgid "Create" msgstr "建立" +#: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" msgstr "重置" +#: template/account_search_results.php msgid "No results matched your search criteria." msgstr "沒有符合您搜尋條件的搜尋結果。" +#: template/account_search_results.php msgid "Edit Account" msgstr "編輯帳號" +#: template/account_search_results.php msgid "Suspended" msgstr "暫停" +#: template/account_search_results.php msgid "Edit" msgstr "編輯" +#: template/account_search_results.php msgid "Less" msgstr "更少" +#: template/account_search_results.php msgid "More" msgstr "更多" +#: template/account_search_results.php msgid "No more results to display." msgstr "無更多結果可顯示。" +#: template/comaintainers_form.php #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" msgstr "使用此表單來加入 %s%s%s 的共同維護者(每個使用者名稱一行):" +#: template/comaintainers_form.php msgid "Users" msgstr "使用者" +#: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" msgstr "儲存" +#: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" msgstr "標記過期評論:%s" +#: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" msgstr "%s%s%s 標記了 %s%s%s 過期在 %s%s%s 上並提供了下列理由:" +#: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." msgstr "%s%s%s 並未被標記為過期。" +#: template/flag_comment.php msgid "Return to Details" msgstr "回到詳情" +#: template/footer.php #, php-format msgid "Copyright %s 2004-%d aurweb Development Team." msgstr "Copyright %s 2004-%d aurweb 開發團隊。" +#: template/header.php msgid " My Account" msgstr "我的帳號" +#: template/pkgbase_actions.php msgid "Package Actions" msgstr "套件動作" +#: template/pkgbase_actions.php msgid "View PKGBUILD" msgstr "檢視 PKGBUILD" +#: template/pkgbase_actions.php msgid "View Changes" msgstr "檢視變更" +#: template/pkgbase_actions.php msgid "Download snapshot" msgstr "下載快照" +#: template/pkgbase_actions.php msgid "Search wiki" msgstr "搜尋 wiki" +#: template/pkgbase_actions.php #, php-format msgid "Flagged out-of-date (%s)" msgstr "標記為過期 (%s)" +#: template/pkgbase_actions.php msgid "Flag package out-of-date" msgstr "將套件標記為過期" +#: template/pkgbase_actions.php msgid "Unflag package" msgstr "取消標記套件" +#: template/pkgbase_actions.php msgid "Remove vote" msgstr "移除投票" +#: template/pkgbase_actions.php msgid "Vote for this package" msgstr "為此套件投票" +#: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" msgstr "停用通知" +#: template/pkgbase_actions.php msgid "Enable notifications" msgstr "啟用通知" +#: template/pkgbase_actions.php msgid "Manage Co-Maintainers" msgstr "管理共同維護者" +#: template/pkgbase_actions.php #, php-format msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d 個擱置的請求" +#: template/pkgbase_actions.php msgid "Adopt Package" msgstr "接管套件" +#: template/pkgbase_details.php msgid "Package Base Details" msgstr "套件基礎詳細資訊" +#: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" msgstr "Git Clone URL" +#: template/pkgbase_details.php template/pkg_details.php msgid "read-only" msgstr "唯讀" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Keywords" msgstr "關鍵字" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php msgid "Submitter" msgstr "提交人" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" msgstr "維護者" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" msgstr "最近一次打包者" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" msgstr "得票" +#: template/pkgbase_details.php template/pkg_details.php +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Popularity" msgstr "人氣" +#: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" msgstr "首次提交" +#: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" msgstr "最後更新" +#: template/pkg_comment_box.php #, php-format msgid "Edit comment for: %s" msgstr "編輯評論:%s" +#: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" msgstr "新增評論" +#: template/pkg_comments.php msgid "View all comments" msgstr "檢視所有評論" +#: template/pkg_comments.php msgid "Pinned Comments" msgstr "已釘選評論" +#: template/pkg_comments.php msgid "Latest Comments" msgstr "最新的評論" +#: template/pkg_comments.php #, php-format msgid "%s commented on %s" msgstr "%s 在 %s 上評論" +#: template/pkg_comments.php #, php-format msgid "Anonymous comment on %s" msgstr "在 %s 上的匿名評論" +#: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" msgstr "在 %s 由 %s 刪除" +#: template/pkg_comments.php #, php-format msgid "deleted on %s" msgstr "已在 %s 上刪除" +#: template/pkg_comments.php #, php-format msgid "edited on %s by %s" msgstr "在 %s 上由 %s 編輯" +#: template/pkg_comments.php #, php-format msgid "edited on %s" msgstr "在 %s 上編輯" +#: template/pkg_comments.php msgid "Undelete comment" msgstr "反刪除評論" +#: template/pkg_comments.php msgid "Delete comment" msgstr "刪除評論" +#: template/pkg_comments.php msgid "Pin comment" msgstr "釘選評論" +#: template/pkg_comments.php msgid "Unpin comment" msgstr "解除釘選評論" +#: template/pkg_comments.php msgid "All comments" msgstr "所有評論" +#: template/pkg_details.php msgid "Package Details" msgstr "套件詳細資訊" +#: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" msgstr "套件基礎" +#: template/pkg_details.php template/pkg_search_results.php msgid "Description" msgstr "描述" +#: template/pkg_details.php msgid "Upstream URL" msgstr "上游 URL" +#: template/pkg_details.php msgid "Visit the website for" msgstr "參觀網頁" +#: template/pkg_details.php msgid "Licenses" msgstr "授權條款" +#: template/pkg_details.php msgid "Groups" msgstr "軟體群組" +#: template/pkg_details.php msgid "Conflicts" msgstr "衝突" +#: template/pkg_details.php msgid "Provides" msgstr "它提供" +#: template/pkg_details.php msgid "Replaces" msgstr "它會取代" +#: template/pkg_details.php msgid "Dependencies" msgstr "它依賴" +#: template/pkg_details.php msgid "Required by" msgstr "需要它" +#: template/pkg_details.php msgid "Sources" msgstr "來源" +#: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." msgstr "使用這個表單以關閉請求套件基礎 %s%s%s 。" +#: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." msgstr "評論區域可以留空。但強烈建議在拒絕一個請求時加入一些評論。" +#: template/pkgreq_close_form.php msgid "Reason" msgstr "理由" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Accepted" msgstr "已接受" +#: template/pkgreq_close_form.php template/pkgreq_results.php +#: template/tu_details.php msgid "Rejected" msgstr "已拒絕" +#: template/pkgreq_form.php #, php-format msgid "" "Use this form to file a request against package base %s%s%s which includes " "the following packages:" msgstr "使用這個表單以提交針對套件基礎 %s%s%s 的請求。它包含以下套件:" +#: template/pkgreq_form.php msgid "Request type" msgstr "請求類型" +#: template/pkgreq_form.php msgid "Deletion" msgstr "刪除" +#: template/pkgreq_form.php msgid "Orphan" msgstr "棄置" +#: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" msgstr "合併到" +#: template/pkgreq_form.php msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" -"透過遞交刪除請求,您會請求受信使用者刪除套件基礎。這個類型的請求應該用於重" -"複、被上游放棄的軟體,以及違法與無法修復的損壞套件。" +msgstr "透過遞交刪除請求,您會請求受信使用者刪除套件基礎。這個類型的請求應該用於重複、被上游放棄的軟體,以及違法與無法修復的損壞套件。" +#: template/pkgreq_form.php msgid "" "By submitting a merge request, you ask a Trusted User to delete the package " "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" -"透過遞交合併請求,您會請求受信使用者刪除套件基礎並轉移其投票數到其他的套件基" -"礎。合併一個套件不會影響相對應的 Git 倉庫。確保您可以自己更新目標套件的 Git " -"歷史。" +msgstr "透過遞交合併請求,您會請求受信使用者刪除套件基礎並轉移其投票數到其他的套件基礎。合併一個套件不會影響相對應的 Git 倉庫。確保您可以自己更新目標套件的 Git 歷史。" +#: template/pkgreq_form.php msgid "" "By submitting an orphan request, you ask a Trusted User to disown the " "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" -"透過遞交棄置請求,您會請求受信使用者棄置套件基礎。請僅在該套件需要有維護者動" -"作、維護者突然消失且您先前已經連絡過維護者時做此動作。" +msgstr "透過遞交棄置請求,您會請求受信使用者棄置套件基礎。請僅在該套件需要有維護者動作、維護者突然消失且您先前已經連絡過維護者時做此動作。" +#: template/pkgreq_results.php msgid "No requests matched your search criteria." msgstr "沒有符合您搜尋條件的搜尋結果。" +#: template/pkgreq_results.php #, php-format msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "找到了 %d 個套件請求。" +#: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." msgstr "第 %d 頁,共 %d 頁。" +#: template/pkgreq_results.php msgid "Package" msgstr "套件" +#: template/pkgreq_results.php msgid "Filed by" msgstr "提交人為" +#: template/pkgreq_results.php msgid "Date" msgstr "日期" +#: template/pkgreq_results.php #, php-format msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "剩餘 ~%d 天" +#: template/pkgreq_results.php #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "剩餘 ~%d 小時" +#: template/pkgreq_results.php msgid "<1 hour left" msgstr "剩餘 <1 小時" +#: template/pkgreq_results.php msgid "Accept" msgstr "接受" +#: template/pkgreq_results.php msgid "Locked" msgstr "已鎖定" +#: template/pkgreq_results.php msgid "Close" msgstr "關閉" +#: template/pkgreq_results.php msgid "Pending" msgstr "擱置中" +#: template/pkgreq_results.php msgid "Closed" msgstr "已關閉" +#: template/pkg_search_form.php msgid "Name, Description" msgstr "名稱,描述" +#: template/pkg_search_form.php msgid "Name Only" msgstr "只有名稱" +#: template/pkg_search_form.php msgid "Exact Name" msgstr "確切的名稱" +#: template/pkg_search_form.php msgid "Exact Package Base" msgstr "確切的套件基礎" +#: template/pkg_search_form.php msgid "Co-maintainer" msgstr "共同維護者" +#: template/pkg_search_form.php msgid "Maintainer, Co-maintainer" msgstr "維護者、共同維護者" +#: template/pkg_search_form.php msgid "All" msgstr "全部" +#: template/pkg_search_form.php msgid "Flagged" msgstr "已標記" +#: template/pkg_search_form.php msgid "Not Flagged" msgstr "未標記" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" msgstr "名稱" +#: template/pkg_search_form.php template/pkg_search_results.php +#: template/tu_details.php template/tu_list.php msgid "Voted" msgstr "已投票" +#: template/pkg_search_form.php msgid "Last modified" msgstr "最後修改" +#: template/pkg_search_form.php msgid "Ascending" msgstr "遞增" +#: template/pkg_search_form.php msgid "Descending" msgstr "遞減" +#: template/pkg_search_form.php msgid "Enter search criteria" msgstr "輸入搜尋條件" +#: template/pkg_search_form.php msgid "Search by" msgstr "以何種方式搜尋" +#: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" msgstr "過期狀態" +#: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" msgstr "排列依據" +#: template/pkg_search_form.php msgid "Sort order" msgstr "排列方式" +#: template/pkg_search_form.php msgid "Per page" msgstr "每頁顯示" +#: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" msgstr "到" +#: template/pkg_search_form.php msgid "Orphans" msgstr "被棄置的套件" +#: template/pkg_search_results.php msgid "Error retrieving package list." msgstr "擷取套件列表時發生錯誤。" +#: template/pkg_search_results.php msgid "No packages matched your search criteria." msgstr "沒有套件符合您的搜尋條件。" +#: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "找到 %d 個套件。" +#: template/pkg_search_results.php msgid "Version" msgstr "版本" +#: template/pkg_search_results.php #, php-format msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." msgstr "人氣的計算方式為,將所有票數加總,且每一票自建立以來每天乘上 %.2f。" +#: template/pkg_search_results.php template/tu_details.php +#: template/tu_list.php msgid "Yes" msgstr "是" +#: template/pkg_search_results.php msgid "orphan" msgstr "被棄置的套件" +#: template/pkg_search_results.php msgid "Actions" msgstr "動作" +#: template/pkg_search_results.php msgid "Unflag Out-of-date" msgstr "取消過期標誌" +#: template/pkg_search_results.php msgid "Adopt Packages" msgstr "接管套件" +#: template/pkg_search_results.php msgid "Disown Packages" msgstr "棄置套件" +#: template/pkg_search_results.php msgid "Delete Packages" msgstr "刪除套件" +#: template/pkg_search_results.php msgid "Confirm" msgstr "確認" +#: template/search_accounts_form.php msgid "Any type" msgstr "任何類型" +#: template/search_accounts_form.php msgid "Search" msgstr "搜尋" +#: template/stats/general_stats_table.php msgid "Statistics" msgstr "統計" +#: template/stats/general_stats_table.php msgid "Orphan Packages" msgstr "棄置套件" +#: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" msgstr "過去 7 天內加入的套件" +#: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" msgstr "過去 7 天內更新的套件" +#: template/stats/general_stats_table.php msgid "Packages updated in the past year" msgstr "過去一年內更新的套件" +#: template/stats/general_stats_table.php msgid "Packages never updated" msgstr "從未更新過的套件" +#: template/stats/general_stats_table.php msgid "Registered Users" msgstr "已註冊的使用者" +#: template/stats/general_stats_table.php msgid "Trusted Users" msgstr "受信使用者" +#: template/stats/updates_table.php msgid "Recent Updates" msgstr "最近更新" +#: template/stats/updates_table.php msgid "more" msgstr "更多" +#: template/stats/user_table.php msgid "My Statistics" msgstr "我的統計" +#: template/tu_details.php msgid "Proposal Details" msgstr "建議詳情" +#: template/tu_details.php msgid "This vote is still running." msgstr "此投票仍在繼續。" +#: template/tu_details.php #, php-format msgid "Submitted: %s by %s" msgstr "已提交 %s 由 %s" +#: template/tu_details.php template/tu_list.php msgid "End" msgstr "結束" +#: template/tu_details.php msgid "Result" msgstr "結果" +#: template/tu_details.php template/tu_list.php msgid "No" msgstr "否" +#: template/tu_details.php msgid "Abstain" msgstr "棄權" +#: template/tu_details.php msgid "Total" msgstr "總數" +#: template/tu_details.php msgid "Participation" msgstr "參與" +#: template/tu_last_votes_list.php msgid "Last Votes by TU" msgstr "受信使用者的最後投票" +#: template/tu_last_votes_list.php msgid "Last vote" msgstr "最後投票" +#: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." msgstr "沒有找到結果。" +#: template/tu_list.php msgid "Start" msgstr "開始" +#: template/tu_list.php msgid "Back" msgstr "返回" + +#: scripts/notify.py +msgid "AUR Password Reset" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"A password reset request was submitted for the account {user} associated " +"with your email address. If you wish to reset your password follow the link " +"[1] below, otherwise ignore this message and nothing will happen." +msgstr "" + +#: scripts/notify.py +msgid "Welcome to the Arch User Repository" +msgstr "" + +#: scripts/notify.py +msgid "" +"Welcome to the Arch User Repository! In order to set an initial password for" +" your new account, please click the link [1] below. If the link does not " +"work, try copying and pasting it into your browser." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Comment for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] added the following comment to {pkgbase} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"If you no longer wish to receive notifications about this package, please go" +" to the package page [2] and select \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package Update: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "{user} [1] pushed a new commit to {pkgbase} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Out-of-date Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Ownership Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was adopted by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "The package {pkgbase} [1] was disowned by {user} [2]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Co-Maintainer Notification for {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were added to the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "You were removed from the co-maintainer list of {pkgbase} [1]." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "AUR Package deleted: {pkgbase}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] merged {old} [2] into {new} [3].\n" +"\n" +"If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"{user} [1] deleted {pkgbase} [2].\n" +"\n" +"You will no longer receive notifications about this package." +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "TU Vote Reminder: Proposal {id}" +msgstr "" + +#: scripts/notify.py +#, python-brace-format +msgid "" +"Please remember to cast your vote on proposal {id} [1]. The voting period " +"ends in less than 48 hours." +msgstr "" From 2c03766841d9fc103f538d664ec964bc5389f1a2 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 7 Jul 2018 17:23:29 +0200 Subject: [PATCH 0440/1891] Release 4.7.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index dc8e87f1..2a933ecc 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Sun, 8 Jul 2018 14:41:12 -0400 Subject: [PATCH 0441/1891] Fix regression in translating anything at all In commit 840ee20 (Rename translation resources from aur to aurweb, 2018-07-07) the translations file was renamed but we never actually switched to using the renamed translations. As a result, every single push to the AUR contains the following traceback: remote: Traceback (most recent call last): remote: File "/usr/bin/aurweb-notify", line 11, in remote: load_entry_point('aurweb==4.7.0', 'console_scripts', 'aurweb-notify')() remote: File "/usr/lib/python3.6/site-packages/aurweb-4.7.0-py3.6.egg/aurweb/scripts/notify.py", line 541, in main remote: File "/usr/lib/python3.6/site-packages/aurweb-4.7.0-py3.6.egg/aurweb/scripts/notify.py", line 69, in send remote: File "/usr/lib/python3.6/site-packages/aurweb-4.7.0-py3.6.egg/aurweb/scripts/notify.py", line 56, in get_body_fmt remote: File "/usr/lib/python3.6/site-packages/aurweb-4.7.0-py3.6.egg/aurweb/scripts/notify.py", line 192, in get_body remote: File "/usr/lib/python3.6/site-packages/aurweb-4.7.0-py3.6.egg/aurweb/l10n.py", line 14, in translate remote: File "/usr/lib/python3.6/gettext.py", line 514, in translation remote: raise OSError(ENOENT, 'No translation file found for domain', domain) remote: FileNotFoundError: [Errno 2] No translation file found for domain: 'aur' Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- aurweb/l10n.py | 2 +- web/lib/translator.inc.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/aurweb/l10n.py b/aurweb/l10n.py index e58e3fe2..66e0f1c0 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -9,7 +9,7 @@ class Translator: if lang == 'en': return s if lang not in self._translator: - self._translator[lang] = gettext.translation("aur", + self._translator[lang] = gettext.translation("aurweb", "../../web/locale", languages=[lang]) self._translator[lang].install() diff --git a/web/lib/translator.inc.php b/web/lib/translator.inc.php index d10f8e90..cd944c56 100644 --- a/web/lib/translator.inc.php +++ b/web/lib/translator.inc.php @@ -131,9 +131,8 @@ function set_lang() { } $streamer = new FileReader('../locale/' . $LANG . - '/LC_MESSAGES/aur.mo'); + '/LC_MESSAGES/aurweb.mo'); $l10n = new gettext_reader($streamer, true); return; } - From a7865ef5aa0309976b5dd2642210632babe106d9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 22 Jul 2018 10:41:57 +0200 Subject: [PATCH 0442/1891] Make the locale directory configurable Add a new configuration option to specify the locale directory to use. This allows the Python scripts to find the translations, even when not being run from the source code checkout. At the same time, multiple parallel aurweb setups can still use different sets of translations. Fixes FS#59278. Signed-off-by: Lukas Fleischer --- aurweb/l10n.py | 5 ++++- conf/config.defaults | 1 + web/lib/translator.inc.php | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/aurweb/l10n.py b/aurweb/l10n.py index 66e0f1c0..a7c0103e 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -1,8 +1,11 @@ import gettext +import aurweb.config + class Translator: def __init__(self): + self._localedir = aurweb.config.get('options', 'localedir') self._translator = {} def translate(self, s, lang): @@ -10,7 +13,7 @@ class Translator: return s if lang not in self._translator: self._translator[lang] = gettext.translation("aurweb", - "../../web/locale", + self._localedir, languages=[lang]) self._translator[lang].install() return _(s) diff --git a/conf/config.defaults b/conf/config.defaults index be37f430..c8bc3a7e 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -35,6 +35,7 @@ snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 render-comment-cmd = /usr/local/bin/aurweb-rendercomment +localedir = /srv/http/aurweb/aur.git/web/locale/ # memcache or apc cache = none memcache_servers = 127.0.0.1:11211 diff --git a/web/lib/translator.inc.php b/web/lib/translator.inc.php index cd944c56..334d0e76 100644 --- a/web/lib/translator.inc.php +++ b/web/lib/translator.inc.php @@ -130,7 +130,8 @@ function set_lang() { setcookie("AURLANG", $LANG, $cookie_time, "/"); } - $streamer = new FileReader('../locale/' . $LANG . + $localedir = config_get('options', 'localedir'); + $streamer = new FileReader($localedir . '/' . $LANG . '/LC_MESSAGES/aurweb.mo'); $l10n = new gettext_reader($streamer, true); From 3578e77ad4e9258495eed7e786b7dc3aebcf1b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Mon, 6 Aug 2018 02:02:57 +0200 Subject: [PATCH 0443/1891] Allow listing all comments from a user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johannes Löthberg Signed-off-by: Lukas Fleischer --- web/html/account.php | 20 +++++- web/html/css/aurweb.css | 42 +++++++++++++ web/html/index.php | 2 + web/html/pkgbase.php | 10 ++- web/lib/acctfuncs.inc.php | 42 +++++++++++++ web/lib/aur.inc.php | 53 ++++++++++++++++ web/lib/credentials.inc.php | 2 + web/lib/pkgbasefuncs.inc.php | 10 ++- web/lib/pkgfuncs.inc.php | 4 ++ web/template/account_details.php | 3 + web/template/account_edit_form.php | 1 + web/template/pkg_comments.php | 99 ++++++++++++++++++++++-------- 12 files changed, 258 insertions(+), 30 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index c30a89aa..9695c9b7 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -8,7 +8,7 @@ include_once('acctfuncs.inc.php'); # access Account specific functions $action = in_request("Action"); $need_userinfo = array( - "DisplayAccount", "DeleteAccount", "AccountInfo", "UpdateAccount" + "DisplayAccount", "DeleteAccount", "AccountInfo", "UpdateAccount", "ListComments" ); if (in_array($action, $need_userinfo)) { @@ -166,6 +166,24 @@ if (isset($_COOKIE["AURSID"])) { $row["Username"]); } + } elseif ($action == "ListComments") { + if (has_credential(CRED_ACCOUNT_LIST_COMMENTS)) { + # display the comment list if they're a TU/dev + + $total_comment_count = account_comments_count($row["ID"]); + list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); + + $username = $row["Username"]; + $uid = $row["ID"]; + $comments = account_comments($uid, $per_page, $offset); + + $comment_section = "account"; + include('pkg_comments.php'); + + } else { + print __("You are not allowed to access this area."); + } + } else { if (has_credential(CRED_ACCOUNT_SEARCH)) { # display the search page if they're a TU/dev diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index f5e10371..593c9ae8 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -148,3 +148,45 @@ label.confirmation, color: red; font-weight: bold; } + +.package-comments { + margin-top: 1.5em; +} + +.comments-header { + display: flex; + justify-content: space-between; + align-items: flex-start; +} + +/* arrowed headings */ +.comments-header h3 span.text { + display: block; + background: #1794D1; + font-size: 15px; + padding: 2px 10px; + color: white; +} + +.comments-header .comments-header-nav { + align-self: flex-end; +} + +.comment-header { + clear: both; + font-size: 1em; + margin-top: 1.5em; + border-bottom: 1px dotted #bbb; +} + +.comments div { + margin-bottom: 1em; +} + +.comments div p { + margin-bottom: 0.5em; +} + +.comments .more { + font-weight: normal; +} diff --git a/web/html/index.php b/web/html/index.php index 2c53cddd..b2cd840e 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -142,6 +142,8 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { $_REQUEST['Action'] = "UpdateAccount"; } elseif ($tokens[3] == 'delete') { $_REQUEST['Action'] = "DeleteAccount"; + } elseif ($tokens[3] == 'comments') { + $_REQUEST['Action'] = "ListComments"; } else { header("HTTP/1.0 404 Not Found"); include "./404.php"; diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index cf9a6c60..46ad77e6 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -43,6 +43,7 @@ if (isset($_POST['IDs'])) { /* Perform package base actions. */ $via = isset($_POST['via']) ? $_POST['via'] : NULL; +$return_to = isset($_POST['return_to']) ? $_POST['return_to'] : NULL; $ret = false; $output = ""; $fragment = ""; @@ -133,7 +134,14 @@ if (check_token()) { /* Redirect back to package request page on success. */ header('Location: ' . get_pkgreq_route()); exit(); - } if (isset($base_id)) { + } elseif ((current_action("do_DeleteComment") || + current_action("do_UndeleteComment")) && $return_to) { + header('Location: ' . $return_to); + exit(); + } elseif (current_action("do_PinComment") && $return_to) { + header('Location: ' . $return_to); + exit(); + } elseif (isset($base_id)) { /* Redirect back to package base page on success. */ header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); exit(); diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index df573755..dc444842 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -1403,3 +1403,45 @@ function accept_terms($uid, $termrev) { $dbh->exec($q); } } + +function account_comments($uid, $limit, $offset=0) { + $dbh = DB::connect(); + $q = "SELECT PackageComments.ID, Comments, UsersID, "; + $q.= "PackageBaseId, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; + $q.= "PinnedTS, "; + $q.= "C.UserName as DelUserName, RenderedComment, "; + $q.= "PB.ID as PackageBaseID, PB.Name as PackageBaseName "; + $q.= "FROM PackageComments "; + $q.= "LEFT JOIN PackageBases PB ON PackageComments.PackageBaseID = PB.ID "; + $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; + $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; + $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; + $q.= "WHERE A.ID = " . $dbh->quote($uid) . " "; + $q.= "ORDER BY CommentTS DESC"; + + if ($limit > 0) { + $q.=" LIMIT " . intval($limit); + } + + if ($offset > 0) { + $q.=" OFFSET " . intval($offset); + } + + $result = $dbh->query($q); + if (!$result) { + return null; + } + + return $result->fetchAll(); +} + +function account_comments_count($uid) { + $dbh = DB::connect(); + $q = "SELECT COUNT(*) "; + $q.= "FROM PackageComments "; + $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; + $q.= "WHERE A.ID = " . $dbh->quote($uid); + + $result = $dbh->query($q); + return $result->fetchColumn(); +} diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index feb4006b..e9530fc0 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -705,3 +705,56 @@ function aur_location() { } return $location; } + +/** + * Calculate pagination templates + * + * @return array The array of pagination templates, per page, and offset values + */ +function calculate_pagination($total_comment_count) { + /* Sanitize paging variables. */ + if (isset($_GET["O"])) { + $_GET["O"] = max(intval($_GET["O"]), 0); + } else { + $_GET["O"] = 0; + } + $offset = $_GET["O"]; + + if (isset($_GET["PP"])) { + $_GET["PP"] = bound(intval($_GET["PP"]), 1, 250); + } else { + $_GET["PP"] = 10; + } + $per_page = $_GET["PP"]; + + // Page offsets start at zero, so page 2 has offset 1, which means that we + // need to add 1 to the offset to get the current page. + $current_page = ceil($offset / $per_page) + 1; + $num_pages = ceil($total_comment_count / $per_page); + $pagination_templs = array(); + + if ($current_page > 1) { + $previous_page = $current_page - 1; + $previous_offset = ($previous_page - 1) * $per_page; + $pagination_templs['« ' . __('First')] = 0; + $pagination_templs['‹ ' . __('Previous')] = $previous_offset; + } + + if ($current_page - 5 > 1) { + $pagination_templs["..."] = false; + } + + for ($i = max($current_page - 5, 1); $i <= min($num_pages, $current_page + 5); $i++) { + $pagination_templs[$i] = ($i - 1) * $per_page; + } + + if ($current_page + 5 < $num_pages) + $pagination_templs["... "] = false; + + if ($current_page < $num_pages) { + $pagination_templs[__('Next') . ' ›'] = $current_page * $per_page; + $pagination_templs[__('Last') . ' »'] = ($num_pages - 1) * $per_page; + } + + return array($pagination_templs, $per_page, $offset); +} diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index d8698a87..c1251197 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -5,6 +5,7 @@ define("CRED_ACCOUNT_EDIT", 2); define("CRED_ACCOUNT_EDIT_DEV", 3); define("CRED_ACCOUNT_LAST_LOGIN", 4); define("CRED_ACCOUNT_SEARCH", 5); +define("CRED_ACCOUNT_LIST_COMMENTS", 28); define("CRED_COMMENT_DELETE", 6); define("CRED_COMMENT_UNDELETE", 27); define("CRED_COMMENT_VIEW_DELETED", 22); @@ -48,6 +49,7 @@ function has_credential($credential, $approved_users=array()) { $atype = account_from_sid($_COOKIE['AURSID']); switch ($credential) { + case CRED_ACCOUNT_LIST_COMMENTS: case CRED_PKGBASE_FLAG: case CRED_PKGBASE_NOTIFY: case CRED_PKGBASE_VOTE: diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 72c33b6d..953a5817 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -44,7 +44,7 @@ function pkgbase_comments_count($base_id, $include_deleted, $only_pinned=false) * * @return array All package comment information for a specific package base */ -function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false) { +function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false, $offset=0) { $base_id = intval($base_id); $limit = intval($limit); if (!$base_id) { @@ -71,6 +71,9 @@ function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false if ($limit > 0) { $q.=" LIMIT " . $limit; } + if ($offset > 0) { + $q.=" OFFSET " . $offset; + } $result = $dbh->query($q); if (!$result) { return null; @@ -273,6 +276,7 @@ function pkgbase_display_details($base_id, $row, $SID="") { include('pkgbase_details.php'); if ($SID) { + $comment_section = "package"; include('pkg_comment_box.php'); } @@ -281,13 +285,17 @@ function pkgbase_display_details($base_id, $row, $SID="") { $limit_pinned = isset($_GET['pinned']) ? 0 : 5; $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); if (!empty($pinned)) { + $comment_section = "package"; include('pkg_comments.php'); } unset($pinned); + $limit = isset($_GET['comments']) ? 0 : 10; $comments = pkgbase_comments($base_id, $limit, $include_deleted); + if (!empty($comments)) { + $comment_section = "package"; include('pkg_comments.php'); } } diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index ad254746..140b8fc2 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -624,13 +624,17 @@ function pkg_display_details($id=0, $row, $SID="") { $limit_pinned = isset($_GET['pinned']) ? 0 : 5; $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); if (!empty($pinned)) { + $comment_section = "package"; include('pkg_comments.php'); } unset($pinned); + $limit = isset($_GET['comments']) ? 0 : 10; $comments = pkgbase_comments($base_id, $limit, $include_deleted); + if (!empty($comments)) { + $comment_section = "package"; include('pkg_comments.php'); } } diff --git a/web/template/account_details.php b/web/template/account_details.php index 024bd9c3..fa6b528c 100644 --- a/web/template/account_details.php +++ b/web/template/account_details.php @@ -82,6 +82,9 @@
  • + +
  • + diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 6eff81bd..38d5274c 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -2,6 +2,7 @@

    ', '') ?> ', '') ?> + ', '') ?>

    diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 3e5e5cc5..3001a342 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -1,28 +1,69 @@ -
    -

    - - - - - - - + + + +
    + +
    + +
    +

    + + + + + + + + + + + + +

    + + 1): ?> +

    + $pagestart): ?> + + + + + + + + + + + + +

    -

    +
    $row): ?> ' . htmlspecialchars($row['PackageBaseName']) . ''; + $heading = __('Commented on package %s on %s', $pkg_uri, $date_fmtd); } $is_deleted = $row['DelTS']; @@ -50,8 +91,13 @@ if (!isset($count)) { } $heading .= ')'; } + + $comment_classes = "comment-header"; + if ($is_deleted) { + $comment_classes .= " comment-deleted"; + } ?> -

    " class="comment-deleted"> +

    " class=""> @@ -59,6 +105,7 @@ if (!isset($count)) { + " /> @@ -70,6 +117,7 @@ if (!isset($count)) { + " /> @@ -79,13 +127,14 @@ if (!isset($count)) { <?= __('Edit comment') ?> - = 5)): ?> + = 5)): ?>
    - + " /> + " />
    @@ -97,6 +146,7 @@ if (!isset($count)) { + " /> @@ -114,13 +164,8 @@ if (!isset($count)) { - - 10 && !isset($_GET['comments']) && !isset($pinned)): ?> -

    - -

    - + diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index b2ce8cbe..a6857c4e 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -49,9 +49,9 @@ $base_uri = get_pkgbase_uri($row['Name']); - () + (, ) -
    +
    () @@ -135,3 +135,16 @@ endif; + + From eeaa1c3a3220e3735445d094dc7d2cd9ac07b621 Mon Sep 17 00:00:00 2001 From: Stephan Springer Date: Sat, 4 Jan 2020 14:00:28 +0100 Subject: [PATCH 0484/1891] Separate text from footer in notification emails Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 591b5ca4..6c3be222 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -151,7 +151,7 @@ class CommentNotification(Notification): body = self._l10n.translate( '{user} [1] added the following comment to {pkgbase} [2]:', lang).format(user=self._user, pkgbase=self._pkgbase) - body += '\n\n' + self._text + '\n\n' + body += '\n\n' + self._text + '\n\n-- \n' dnlabel = self._l10n.translate('Disable notifications', lang) body += self._l10n.translate( 'If you no longer wish to receive notifications about this ' @@ -196,7 +196,7 @@ class UpdateNotification(Notification): '{pkgbase} [2].', lang).format( user=self._user, pkgbase=self._pkgbase) - body += '\n\n' + body += '\n\n-- \n' dnlabel = self._l10n.translate('Disable notifications', lang) body += self._l10n.translate( 'If you no longer wish to receive notifications about this ' @@ -362,6 +362,7 @@ class DeleteNotification(Notification): dnlabel = self._l10n.translate('Disable notifications', lang) return self._l10n.translate( '{user} [1] merged {old} [2] into {new} [3].\n\n' + '-- \n' 'If you no longer wish receive notifications about the ' 'new package, please go to [3] and click "{label}".', lang).format(user=self._user, old=self._old_pkgbase, From daee20c694000e1e85a98760773bcbbdc0709527 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 10:23:50 +0100 Subject: [PATCH 0485/1891] Require current password when setting a new one Prevent from easily taking over an account by changing the password with a stolen session ID. Fixes FS#65325. Signed-off-by: Lukas Fleischer --- web/html/account.php | 1 + web/html/register.php | 2 ++ web/lib/acctfuncs.inc.php | 15 ++++++++++++-- web/template/account_edit_form.php | 32 +++++++++++++++++++----------- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index 1d59e9c9..7c6c424a 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -34,6 +34,7 @@ if ($action == "UpdateAccount") { in_request("S"), in_request("E"), in_request("H"), + in_request("PO"), in_request("P"), in_request("C"), in_request("R"), diff --git a/web/html/register.php b/web/html/register.php index a4264829..8174e342 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -26,6 +26,7 @@ if (in_request("Action") == "NewAccount") { in_request("H"), '', '', + '', in_request("R"), in_request("L"), in_request("TZ"), @@ -54,6 +55,7 @@ if (in_request("Action") == "NewAccount") { in_request("H"), '', '', + '', in_request("R"), in_request("L"), in_request("TZ"), diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index e754989a..1de49b01 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -96,6 +96,7 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $S Whether or not the account is suspended * @param string $E The e-mail address for the user * @param string $H Whether or not the e-mail address should be hidden + * @param string $PO The old password of the user * @param string $P The password for the user * @param string $C The confirmed password for the user * @param string $R The real name of the user @@ -116,7 +117,7 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * * @return array Boolean indicating success and message to be printed */ -function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", +function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$PO="",$P="",$C="", $R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$captcha_salt="",$captcha="") { global $SUPPORTED_LANGS; @@ -134,6 +135,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" if(isset($_COOKIE['AURSID'])) { $editor_user = uid_from_sid($_COOKIE['AURSID']); + $row = account_details(in_request("ID"), in_request("U")); } else { $editor_user = null; @@ -159,9 +161,18 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" . "\n"; } - if (!$error && $P && $C && ($P != $C)) { + if (!$error && $P && !$C) { + $error = __("Please confirm your new password."); + } + if (!$error && $P && !$PO) { + $error = __("Please enter your old password in order to set a new one."); + } + if (!$error && $P && $P != $C) { $error = __("Password fields do not match."); } + if (!$error && $P && check_passwd($UID, $PO) != 1) { + $error = __("The old password is invalid."); + } if (!$error && $P != '' && !good_passwd($P)) { $length_min = config_get_int('options', 'passwd_min_len'); $error = __("Your password must be at least %s characters.", diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 5e84aa71..25e91853 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -86,18 +86,6 @@ />

    - -

    - - -

    - -

    - - -

    - -

    @@ -150,6 +138,26 @@

    + +
    + +

    + + +

    + +

    + + +

    + +

    + + +

    +
    + +

    From 4ececd6041133ea9745261b7a2ac0da1e8976e21 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 13:19:16 +0100 Subject: [PATCH 0486/1891] Keep signature delimiters intact in notifications Since commit eeaa1c3 (Separate text from footer in notification emails, 2020-01-04), information about unsubscribing from notifications is added in a signature block. However, the code to format the email body trimmed the RFC 3676 signature delimiter, replacing "-- " by "--". Fix this by adding a special case for signature delimiters. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 6c3be222..f2767fd8 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -54,6 +54,9 @@ class Notification: def get_body_fmt(self, lang): body = '' for line in self.get_body(lang).splitlines(): + if line == '-- ': + body += '-- \n' + continue body += textwrap.fill(line, break_long_words=False) + '\n' for i, ref in enumerate(self.get_refs()): body += '\n' + '[%d] %s' % (i + 1, ref) From d0e5c3db693296ed7e909c3a0a4457d1328d87de Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 13:23:51 +0100 Subject: [PATCH 0487/1891] t2500: fix test cases Since commit eeaa1c3 (Separate text from footer in notification emails, 2020-01-04), information about unsubscribing from notifications is added in a signature block. Fix the test cases accordingly. Signed-off-by: Lukas Fleischer --- test/t2500-notify.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/t2500-notify.sh b/test/t2500-notify.sh index 3080dc24..380e65b8 100755 --- a/test/t2500-notify.sh +++ b/test/t2500-notify.sh @@ -101,6 +101,7 @@ test_expect_success 'Test subject and body of comment notifications.' ' This is a test comment. + -- If you no longer wish to receive notifications about this package, please go to the package page [2] and select "Disable notifications". @@ -126,6 +127,7 @@ test_expect_success 'Test subject and body of update notifications.' ' cat <<-EOD >expected && user [1] pushed a new commit to foobar [2]. + -- If you no longer wish to receive notifications about this package, please go to the package page [2] and select "Disable notifications". @@ -264,6 +266,7 @@ test_expect_success 'Test subject and body of merge notifications.' ' cat <<-EOD >expected && user [1] merged foobar [2] into foobar2 [3]. + -- If you no longer wish receive notifications about the new package, please go to [3] and click "Disable notifications". From f090896fa1e9570715cfcdec7b23ecf95d25e936 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 11:58:16 +0100 Subject: [PATCH 0488/1891] Undo accidental code addition Rollback an accidental change that sneaked into commit daee20c (Require current password when setting a new one, 2020-01-30). Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 1 - 1 file changed, 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 1de49b01..601d4ce0 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -135,7 +135,6 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$PO="",$P=" if(isset($_COOKIE['AURSID'])) { $editor_user = uid_from_sid($_COOKIE['AURSID']); - $row = account_details(in_request("ID"), in_request("U")); } else { $editor_user = null; From 7aa420d24da7e8c2c214ab421d44b4684d42e73e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 12:39:52 +0100 Subject: [PATCH 0489/1891] Verify current password against logged in user When changing the password of an account, instead of asking for the old password of the account, ask for the password of the currently logged in user. This allows privileged users to edit other accounts without knowing their passwords. Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 9 ++++----- web/template/account_edit_form.php | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 601d4ce0..d2144c2a 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -134,10 +134,9 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$PO="",$P=" $dbh = DB::connect(); if(isset($_COOKIE['AURSID'])) { - $editor_user = uid_from_sid($_COOKIE['AURSID']); - } - else { - $editor_user = null; + $uid_session = uid_from_sid($_COOKIE['AURSID']); + } else { + $uid_session = null; } if (empty($E) || empty($U)) { @@ -169,7 +168,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$PO="",$P=" if (!$error && $P && $P != $C) { $error = __("Password fields do not match."); } - if (!$error && $P && check_passwd($UID, $PO) != 1) { + if (!$error && $P && check_passwd($uid_session, $PO) != 1) { $error = __("The old password is invalid."); } if (!$error && $P != '' && !good_passwd($P)) { diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 25e91853..7bd233a8 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -140,9 +140,9 @@

    - +

    - +

    From 8fc8898fef39af20a24c9928464fd8420481d819 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 11:52:32 +0100 Subject: [PATCH 0490/1891] Require password when deleting an account Further reduce the attack surface in case of a stolen session ID. Signed-off-by: Lukas Fleischer --- web/html/account.php | 17 +++++++++++++---- web/template/account_delete.php | 11 +++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index 7c6c424a..03af8d43 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -120,12 +120,21 @@ if (isset($_COOKIE["AURSID"])) { } elseif ($action == "DeleteAccount") { /* Details for account being deleted. */ if (can_edit_account($row)) { - $UID = $row['ID']; + $uid_removal = $row['ID']; + $uid_session = uid_from_sid($_COOKIE['AURSID']); + $username = $row['Username']; + if (in_request('confirm') && check_token()) { - user_delete($UID); - header('Location: /'); + if (check_passwd($uid_session, $_REQUEST['passwd']) == 1) { + user_delete($uid_removal); + header('Location: /'); + } else { + echo "
    • "; + echo __("Invalid password."); + echo "
    "; + include("account_delete.php"); + } } else { - $username = $row['Username']; include("account_delete.php"); } } else { diff --git a/web/template/account_delete.php b/web/template/account_delete.php index 718b172f..d0c6e74d 100644 --- a/web/template/account_delete.php +++ b/web/template/account_delete.php @@ -12,8 +12,15 @@
    -

    +

    + + +

    + +

    + +

    " /> From def2787b45275de2b8dfab0ece87f35ea280567b Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 14:00:07 +0100 Subject: [PATCH 0491/1891] Require password when changing account information Since commits daee20c (Require current password when setting a new one, 2020-01-30) and 8fc8898 (Require password when deleting an account, 2020-01-30), changing a password and deleting an account require the current password. Extend this to all other profile changes. Signed-off-by: Lukas Fleischer --- web/html/account.php | 5 +++-- web/html/register.php | 4 ++-- web/lib/acctfuncs.inc.php | 19 +++++++------------ web/template/account_edit_form.php | 17 +++++++++-------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index 03af8d43..ff9aba5b 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -34,7 +34,6 @@ if ($action == "UpdateAccount") { in_request("S"), in_request("E"), in_request("H"), - in_request("PO"), in_request("P"), in_request("C"), in_request("R"), @@ -49,7 +48,9 @@ if ($action == "UpdateAccount") { in_request("UN"), in_request("ON"), in_request("ID"), - $row["Username"]); + $row["Username"], + in_request("passwd") + ); } } diff --git a/web/html/register.php b/web/html/register.php index 8174e342..610befc4 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -26,7 +26,6 @@ if (in_request("Action") == "NewAccount") { in_request("H"), '', '', - '', in_request("R"), in_request("L"), in_request("TZ"), @@ -40,6 +39,7 @@ if (in_request("Action") == "NewAccount") { in_request("ON"), 0, "", + '', in_request("captcha_salt"), in_request("captcha"), ); @@ -55,7 +55,6 @@ if (in_request("Action") == "NewAccount") { in_request("H"), '', '', - '', in_request("R"), in_request("L"), in_request("TZ"), @@ -69,6 +68,7 @@ if (in_request("Action") == "NewAccount") { in_request("ON"), 0, "", + '', in_request("captcha_salt"), in_request("captcha") ); diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index d2144c2a..345d27af 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -96,7 +96,6 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $S Whether or not the account is suspended * @param string $E The e-mail address for the user * @param string $H Whether or not the e-mail address should be hidden - * @param string $PO The old password of the user * @param string $P The password for the user * @param string $C The confirmed password for the user * @param string $R The real name of the user @@ -112,13 +111,14 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $ON Whether to notify of ownership changes * @param string $UID The user ID of the modified account * @param string $N The username as present in the database + * @param string $passwd The password of the logged in user. * @param string $captcha_salt The salt used for the CAPTCHA. * @param string $captcha The CAPTCHA answer. * * @return array Boolean indicating success and message to be printed */ -function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$PO="",$P="",$C="", - $R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$captcha_salt="",$captcha="") { +function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", + $R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$passwd="",$captcha_salt="",$captcha="") { global $SUPPORTED_LANGS; $error = ''; @@ -133,10 +133,11 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$PO="",$P=" $dbh = DB::connect(); - if(isset($_COOKIE['AURSID'])) { + if (isset($_COOKIE['AURSID'])) { $uid_session = uid_from_sid($_COOKIE['AURSID']); - } else { - $uid_session = null; + if (!$error && check_passwd($uid_session, $passwd) != 1) { + $error = __("Invalid password."); + } } if (empty($E) || empty($U)) { @@ -162,15 +163,9 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$PO="",$P=" if (!$error && $P && !$C) { $error = __("Please confirm your new password."); } - if (!$error && $P && !$PO) { - $error = __("Please enter your old password in order to set a new one."); - } if (!$error && $P && $P != $C) { $error = __("Password fields do not match."); } - if (!$error && $P && check_passwd($uid_session, $PO) != 1) { - $error = __("The old password is invalid."); - } if (!$error && $P != '' && !good_passwd($P)) { $length_min = config_get_int('options', 'passwd_min_len'); $error = __("Your password must be at least %s characters.", diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 7bd233a8..09d65c0f 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -140,12 +140,7 @@

    - -

    - - -

    - +

    @@ -182,16 +177,22 @@

    -
    + + +

    + + +

    +

    ()

    -
    +

    From 23c0c9c372a7443e96115441571ea57bb24881c7 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 13:09:05 +0100 Subject: [PATCH 0492/1891] Update copyright range in the cgit footer --- web/template/cgit/footer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/template/cgit/footer.html b/web/template/cgit/footer.html index 1c0bf6f6..14c358f1 100644 --- a/web/template/cgit/footer.html +++ b/web/template/cgit/footer.html @@ -1,6 +1,6 @@

    From e5a839bf0b9884e2a015b3f0b3fdbf23d1a1654c Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 16:57:22 +0100 Subject: [PATCH 0493/1891] Add option to send reset key for a given user name In addition to supporting email addresses in the reset key form, also support user names. The reset key is then sent to the email address in the user's profile. Signed-off-by: Lukas Fleischer --- web/html/passreset.php | 25 ++++++++++++------------- web/lib/acctfuncs.inc.php | 13 +++++++------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/web/html/passreset.php b/web/html/passreset.php index 9e7cee88..b3c8bd29 100644 --- a/web/html/passreset.php +++ b/web/html/passreset.php @@ -11,14 +11,14 @@ if (isset($_COOKIE["AURSID"])) { $error = ''; -if (isset($_GET['resetkey'], $_POST['email'], $_POST['password'], $_POST['confirm'])) { +if (isset($_GET['resetkey'], $_POST['user'], $_POST['password'], $_POST['confirm'])) { $resetkey = $_GET['resetkey']; - $email = $_POST['email']; + $user = $_POST['user']; $password = $_POST['password']; $confirm = $_POST['confirm']; - $uid = uid_from_email($email); + $uid = uid_from_loginname($user); - if (empty($email) || empty($password)) { + if (empty($user) || empty($password)) { $error = __('Missing a required field.'); } elseif ($password != $confirm) { $error = __('Password fields do not match.'); @@ -31,16 +31,15 @@ if (isset($_GET['resetkey'], $_POST['email'], $_POST['password'], $_POST['confir } if (empty($error)) { - $error = password_reset($password, $resetkey, $email); + $error = password_reset($password, $resetkey, $user); } -} elseif (isset($_POST['email'])) { - $email = $_POST['email']; - $username = username_from_id(uid_from_email($email)); +} elseif (isset($_POST['user'])) { + $user = $_POST['user']; - if (empty($email)) { + if (empty($user)) { $error = __('Missing a required field.'); } else { - send_resetkey($email); + send_resetkey($user); header('Location: ' . get_uri('/passreset/') . '?step=confirm'); exit(); } @@ -67,7 +66,7 @@ html_header(__("Password Reset")); - + @@ -89,8 +88,8 @@ html_header(__("Password Reset"));
    -

    -

    +

    +

    diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 345d27af..f6cda69c 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -755,13 +755,13 @@ function create_resetkey($resetkey, $uid) { /** * Send a reset key to a specific e-mail address * - * @param string $email E-mail address of the user resetting their password + * @param string $user User name or email address of the user * @param bool $welcome Whether to use the welcome message * * @return void */ -function send_resetkey($email, $welcome=false) { - $uid = uid_from_email($email); +function send_resetkey($user, $welcome=false) { + $uid = uid_from_loginname($user); if ($uid == null) { return; } @@ -779,11 +779,11 @@ function send_resetkey($email, $welcome=false) { * * @param string $password The new password * @param string $resetkey Code e-mailed to a user to reset a password - * @param string $email E-mail address of the user resetting their password + * @param string $user User name or email address of the user * * @return string|void Redirect page if successful, otherwise return error message */ -function password_reset($password, $resetkey, $email) { +function password_reset($password, $resetkey, $user) { $hash = password_hash($password, PASSWORD_DEFAULT); $dbh = DB::connect(); @@ -792,7 +792,8 @@ function password_reset($password, $resetkey, $email) { $q.= "ResetKey = '' "; $q.= "WHERE ResetKey != '' "; $q.= "AND ResetKey = " . $dbh->quote($resetkey) . " "; - $q.= "AND Email = " . $dbh->quote($email); + $q.= "AND (Email = " . $dbh->quote($user) . " OR "; + $q.= "UserName = " . $dbh->quote($user) . ")"; $result = $dbh->exec($q); if (!$result) { From ee2aa9755fa3c94e8c8a697c3f7a9627027994d5 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 30 Jan 2020 17:15:33 +0100 Subject: [PATCH 0494/1891] Add support for backup email addresses Support secondary email addresses that can be used to recover an account in case access to the primary email address is lost. Reset keys for an account are always sent to both the primary and the backup email address. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 12 ++++++++---- schema/aur-schema.sql | 1 + upgrading/4.9.0.txt | 6 ++++++ web/html/account.php | 3 +++ web/html/login.php | 2 +- web/html/passreset.php | 6 +++--- web/html/register.php | 4 +++- web/lib/acctfuncs.inc.php | 15 +++++++++++---- web/template/account_edit_form.php | 12 +++++++++++- 9 files changed, 47 insertions(+), 14 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index f2767fd8..b0f218b5 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -90,13 +90,17 @@ class Notification: class ResetKeyNotification(Notification): def __init__(self, conn, uid): - cur = conn.execute('SELECT UserName, Email, LangPreference, ' + - 'ResetKey FROM Users WHERE ID = ?', [uid]) - self._username, self._to, self._lang, self._resetkey = cur.fetchone() + cur = conn.execute('SELECT UserName, Email, BackupEmail, ' + + 'LangPreference, ResetKey ' + + 'FROM Users WHERE ID = ?', [uid]) + self._username, self._to, self._backup, self._lang, self._resetkey = cur.fetchone() super().__init__() def get_recipients(self): - return [(self._to, self._lang)] + if self._backup: + return [(self._to, self._lang), (self._backup, self._lang)] + else: + return [(self._to, self._lang)] def get_subject(self, lang): return self._l10n.translate('AUR Password Reset', lang) diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql index fa991ba6..1f86df20 100644 --- a/schema/aur-schema.sql +++ b/schema/aur-schema.sql @@ -23,6 +23,7 @@ CREATE TABLE Users ( Suspended TINYINT UNSIGNED NOT NULL DEFAULT 0, Username VARCHAR(32) NOT NULL, Email VARCHAR(254) NOT NULL, + BackupEmail VARCHAR(254) NULL DEFAULT NULL, HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0, Passwd VARCHAR(255) NOT NULL, Salt CHAR(32) NOT NULL DEFAULT '', diff --git a/upgrading/4.9.0.txt b/upgrading/4.9.0.txt index 4c79283e..241f24af 100644 --- a/upgrading/4.9.0.txt +++ b/upgrading/4.9.0.txt @@ -4,3 +4,9 @@ ALTER TABLE PackageRequests ADD COLUMN ClosedTS BIGINT UNSIGNED NULL DEFAULT NULL; ALTER TABLE PackageRequests ADD COLUMN ClosedUID INTEGER UNSIGNED NULL DEFAULT NULL; ---- + +2. Add a new column to store backup email addresses: + +---- +ALTER TABLE Users ADD COLUMN BackupEmail VARCHAR(254) NULL DEFAULT NULL; +---- diff --git a/web/html/account.php b/web/html/account.php index ff9aba5b..c05d136d 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -33,6 +33,7 @@ if ($action == "UpdateAccount") { in_request("T"), in_request("S"), in_request("E"), + in_request("BE"), in_request("H"), in_request("P"), in_request("C"), @@ -97,6 +98,7 @@ if (isset($_COOKIE["AURSID"])) { $row["AccountTypeID"], $row["Suspended"], $row["Email"], + $row["BackupEmail"], $row["HideEmail"], "", "", @@ -159,6 +161,7 @@ if (isset($_COOKIE["AURSID"])) { in_request("T"), in_request("S"), in_request("E"), + in_request("BE"), in_request("H"), in_request("P"), in_request("C"), diff --git a/web/html/login.php b/web/html/login.php index df517055..01454414 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -26,7 +26,7 @@ html_header('AUR ' . __("Login"));

    - +

    diff --git a/web/html/passreset.php b/web/html/passreset.php index b3c8bd29..26b9bbbb 100644 --- a/web/html/passreset.php +++ b/web/html/passreset.php @@ -65,7 +65,7 @@ html_header(__("Password Reset"));

    - + @@ -81,14 +81,14 @@ html_header(__("Password Reset")); -

    ', ''); ?>

    -

    +

    diff --git a/web/html/register.php b/web/html/register.php index 610befc4..fee0a68f 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -23,6 +23,7 @@ if (in_request("Action") == "NewAccount") { 1, 0, in_request("E"), + in_request("BE"), in_request("H"), '', '', @@ -52,6 +53,7 @@ if (in_request("Action") == "NewAccount") { 1, 0, in_request("E"), + in_request("BE"), in_request("H"), '', '', @@ -75,7 +77,7 @@ if (in_request("Action") == "NewAccount") { } } else { print '

    ' . __("Use this form to create an account.") . '

    '; - display_account_form("NewAccount", "", "", "", "", "", "", "", "", $LANG); + display_account_form("NewAccount", "", "", "", "", "", "", "", "", "", $LANG); } echo ''; diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index f6cda69c..443fb4b1 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -46,6 +46,7 @@ function html_format_pgp_fingerprint($fingerprint) { * @param string $T The account type of the displayed user * @param string $S Whether the displayed user has a suspended account * @param string $E The e-mail address of the displayed user + * @param string $BE The backup e-mail address of the displayed user * @param string $H Whether the e-mail address of the displayed user is hidden * @param string $P The password value of the displayed user * @param string $C The confirmed password value of the displayed user @@ -67,7 +68,7 @@ function html_format_pgp_fingerprint($fingerprint) { * * @return void */ -function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="", +function display_account_form($A,$U="",$T="",$S="",$E="",$BE="",$H="",$P="",$C="",$R="", $L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$captcha_salt="",$captcha="") { global $SUPPORTED_LANGS; @@ -95,6 +96,7 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $T The account type for the user * @param string $S Whether or not the account is suspended * @param string $E The e-mail address for the user + * @param string $BE The backup e-mail address for the user * @param string $H Whether or not the e-mail address should be hidden * @param string $P The password for the user * @param string $C The confirmed password for the user @@ -117,7 +119,7 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * * @return array Boolean indicating success and message to be printed */ -function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", +function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$BE="",$H="",$P="",$C="", $R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$passwd="",$captcha_salt="",$captcha="") { global $SUPPORTED_LANGS; @@ -175,6 +177,9 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" if (!$error && !valid_email($E)) { $error = __("The email address is invalid."); } + if (!$error && $BE && !valid_email($BE)) { + $error = __("The backup email address is invalid."); + } if (!$error && !empty($HP) && !valid_homepage($HP)) { $error = __("The home page is invalid, please specify the full HTTP(s) URL."); @@ -311,6 +316,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" } $U = $dbh->quote($U); $E = $dbh->quote($E); + $BE = $dbh->quote($BE); $P = $dbh->quote($P); $R = $dbh->quote($R); $L = $dbh->quote($L); @@ -319,9 +325,9 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $I = $dbh->quote($I); $K = $dbh->quote(str_replace(" ", "", $K)); $q = "INSERT INTO Users (AccountTypeID, Suspended, "; - $q.= "InactivityTS, Username, Email, Passwd , "; + $q.= "InactivityTS, Username, Email, BackupEmail, Passwd , "; $q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) "; - $q.= "VALUES (1, 0, 0, $U, $E, $P, $R, $L, $TZ, "; + $q.= "VALUES (1, 0, 0, $U, $E, $BE, $P, $R, $L, $TZ, "; $q.= "$HP, $I, $K)"; $result = $dbh->exec($q); if (!$result) { @@ -374,6 +380,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" $q.= ", Suspended = 0"; } $q.= ", Email = " . $dbh->quote($E); + $q.= ", BackupEmail = " . $dbh->quote($BE); if ($H) { $q.= ", HideEmail = 1"; } else { diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 09d65c0f..edacbbf3 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -76,11 +76,21 @@ ()

    -

    +

    + + +

    +

    + + + + +

    +

    /> From e5f8fe5528960f5033df0e2a0bad14aea9154741 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 31 Jan 2020 09:16:23 +0100 Subject: [PATCH 0495/1891] Explain the hide email address setting Signed-off-by: Lukas Fleischer --- web/template/account_edit_form.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index edacbbf3..a4ea9949 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -80,6 +80,14 @@

    +

    + + /> +

    +

    + +

    +

    @@ -88,14 +96,10 @@ + " . __("Hide Email Address") . "") ?>

    -

    - - /> -

    -

    From aa555f9ae5a68f7567c862d017e27c78d1b6ec95 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 31 Jan 2020 09:25:57 +0100 Subject: [PATCH 0496/1891] Explain syntax/features in the comments section Addresses FS#64983. Signed-off-by: Lukas Fleischer --- web/template/pkg_comment_form.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/template/pkg_comment_form.php b/web/template/pkg_comment_form.php index 3feee8fb..e8a516e3 100644 --- a/web/template/pkg_comment_form.php +++ b/web/template/pkg_comment_form.php @@ -8,6 +8,10 @@ +

    + + ', "") ?> +

    From 8ff21fd39c537ef930e2bd32f76cd28d40fa3b67 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 31 Jan 2020 08:44:23 +0100 Subject: [PATCH 0497/1891] Update message catalog Signed-off-by: Lukas Fleischer --- po/aurweb.pot | 146 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 125 insertions(+), 21 deletions(-) diff --git a/po/aurweb.pot b/po/aurweb.pot index e49dc132..aeed9f02 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -1,14 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: AUR v4.6.0\n" +"Project-Id-Version: AURWEB v4.8.0\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -73,6 +73,10 @@ msgstr "" msgid "You do not have permission to edit this account." msgstr "" +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "" @@ -367,10 +371,10 @@ msgid "Enter login credentials" msgstr "" #: html/login.php -msgid "User name or email address" +msgid "User name or primary email address" msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "" @@ -431,7 +435,7 @@ msgid "Your password has been reset successfully." msgstr "" #: html/passreset.php -msgid "Confirm your e-mail address:" +msgid "Confirm your user name or primary e-mail address:" msgstr "" #: html/passreset.php @@ -449,12 +453,12 @@ msgstr "" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a " -"message to the %saur-general%s mailing list." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" +msgid "Enter your user name or your primary e-mail address:" msgstr "" #: html/pkgbase.php @@ -646,19 +650,19 @@ msgstr "" msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" @@ -759,10 +763,18 @@ msgstr "" msgid "Can contain only one period, underscore or hyphen." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -802,6 +814,18 @@ msgstr "" msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1210,6 +1234,10 @@ msgstr "" msgid "Edit this user's account" msgstr "" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1220,6 +1248,11 @@ msgstr "" msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "" @@ -1257,7 +1290,33 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." msgstr "" #: template/account_edit_form.php @@ -1268,6 +1327,16 @@ msgstr "" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new " +"password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to " @@ -1294,6 +1363,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1422,7 +1509,7 @@ msgstr "" msgid "Disable notifications" msgstr "" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1453,6 +1540,10 @@ msgstr "" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1499,8 +1590,15 @@ msgstr "" msgid "Add Comment" msgstr "" -#: template/pkg_comments.php -msgid "View all comments" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and " +"URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." msgstr "" #: template/pkg_comments.php @@ -1511,6 +1609,10 @@ msgstr "" msgid "Latest Comments" msgstr "" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1521,6 +1623,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1557,10 +1664,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "" - #: template/pkg_details.php msgid "Package Details" msgstr "" @@ -2106,6 +2209,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go " "to [3] and click \"{label}\"." msgstr "" From c277a3de8f3255be31a2c3f08cd49fe2f6c36aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Thu, 30 Jan 2020 03:35:12 +0100 Subject: [PATCH 0498/1891] rendercomment: respectful linkification of Git commits Turn the git-commits markdown processor into an inline processor, which is smart enough not to convert Git hashes contained in code blocks or links. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 36 ++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 5e18fd59..5c597481 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -40,19 +40,26 @@ class FlysprayLinksExtension(markdown.extensions.Extension): md.preprocessors.add('flyspray-links', preprocessor, '_end') -class GitCommitsPreprocessor(markdown.preprocessors.Preprocessor): - _oidre = re.compile(r'(\b)([0-9a-f]{7,40})(\b)') +class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): + """ + Turn Git hashes like f7f5152be5ab into links to AUR's cgit. + + Only commit references that do exist are linkified. Hashes are shortened to + shorter non-ambiguous prefixes. Only hashes with at least 7 digits are + considered. + """ + _repo = pygit2.Repository(repo_path) - _head = None def __init__(self, md, head): self._head = head - super(markdown.preprocessors.Preprocessor, self).__init__(md) + super().__init__(r'\b([0-9a-f]{7,40})\b', md) - def handleMatch(self, m): - oid = m.group(2) + def handleMatch(self, m, data): + oid = m.group(1) if oid not in self._repo: - return oid + # Unkwown OID; preserve the orginal text. + return None, None, None prefixlen = 12 while prefixlen < 40: @@ -60,13 +67,10 @@ class GitCommitsPreprocessor(markdown.preprocessors.Preprocessor): break prefixlen += 1 - html = '[`' + oid[:prefixlen] + '`]' - html += '(' + commit_uri % (self._head, oid[:prefixlen]) + ')' - - return html - - def run(self, lines): - return [self._oidre.sub(self.handleMatch, line) for line in lines] + el = markdown.util.etree.Element('a') + el.set('href', commit_uri % (self._head, oid[:prefixlen])) + el.text = markdown.util.AtomicString(oid[:prefixlen]) + return el, m.start(0), m.end(0) class GitCommitsExtension(markdown.extensions.Extension): @@ -77,8 +81,8 @@ class GitCommitsExtension(markdown.extensions.Extension): super(markdown.extensions.Extension, self).__init__() def extendMarkdown(self, md, md_globals): - preprocessor = GitCommitsPreprocessor(md, self._head) - md.preprocessors.add('git-commits', preprocessor, '_end') + processor = GitCommitsInlineProcessor(md, self._head) + md.inlinePatterns.add('git-commits', processor, '_end') class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor): From 0fc69e96bdd1197ca2b91bcd16a3064366954c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Fri, 31 Jan 2020 03:20:26 +0100 Subject: [PATCH 0499/1891] rendercomment: add a test for Git commit links Signed-off-by: Lukas Fleischer --- test/t2600-rendercomment.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index edf290cd..7b3a4a8d 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -63,4 +63,33 @@ test_expect_success 'Test link conversion.' ' test_cmp actual expected ' +test_expect_success 'Test Git commit linkification.' ' + local oid=`git -C aur.git rev-parse --verify HEAD` + cat <<-EOD | sqlite3 aur.db && + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (5, 1, " + $oid + ${oid:0:7} + x.$oid.x + ${oid}x + 0123456789abcdef + \`$oid\` + http://example.com/$oid + ", ""); + EOD + "$RENDERCOMMENT" 5 && + cat <<-EOD >expected && +

    ${oid:0:12} + ${oid:0:7} + x.${oid:0:12}.x + ${oid}x + 0123456789abcdef + $oid + http://example.com/$oid

    + EOD + cat <<-EOD | sqlite3 aur.db >actual && + SELECT RenderedComment FROM PackageComments WHERE ID = 5; + EOD + test_cmp actual expected +' + test_done From 199f34e42e78ca97f154a4880b77b3f1d01fa9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sat, 1 Feb 2020 19:07:41 +0100 Subject: [PATCH 0500/1891] rendercomment: safer auto-linkification of URLs Fixes a few edge cases: - URLs within code blocks used to get redundant <> added, breaking bash code snippets like `curl https://...` into `curl `. - Links written with markdown's syntax also used to get an extra pair of brackets. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 21 ++++++++++++--------- test/t2600-rendercomment.sh | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 5c597481..346ccff1 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -13,17 +13,20 @@ repo_path = aurweb.config.get('serve', 'repo-path') commit_uri = aurweb.config.get('options', 'commit_uri') -class LinkifyPreprocessor(markdown.preprocessors.Preprocessor): - _urlre = re.compile(r'(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' - r'(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))') - - def run(self, lines): - return [self._urlre.sub(r'<\1>', line) for line in lines] - - class LinkifyExtension(markdown.extensions.Extension): + """ + Turn URLs into links, even without explicit markdown. + Do not linkify URLs in code blocks. + """ + + # Captures http(s) and ftp URLs until the first non URL-ish character. + # Excludes trailing punctuation. + _urlre = (r'(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' + r'(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))') + def extendMarkdown(self, md, md_globals): - md.preprocessors.add('linkify', LinkifyPreprocessor(md), '_end') + processor = markdown.inlinepatterns.AutolinkInlineProcessor(self._urlre, md) + md.inlinePatterns.add('linkify', processor, '_end') class FlysprayLinksPreprocessor(markdown.preprocessors.Preprocessor): diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index 7b3a4a8d..b0209eb5 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -51,11 +51,22 @@ test_expect_success 'Test HTML sanitizing.' ' test_expect_success 'Test link conversion.' ' cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (4, 1, "Visit https://www.archlinux.org/.", ""); + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (4, 1, " + Visit https://www.archlinux.org/. + Visit . + Visit \`https://www.archlinux.org/\`. + Visit [Arch Linux](https://www.archlinux.org/). + Visit [Arch Linux][arch]. + [arch]: https://www.archlinux.org/ + ", ""); EOD "$RENDERCOMMENT" 4 && cat <<-EOD >expected && -

    Visit https://www.archlinux.org/.

    +

    Visit https://www.archlinux.org/. + Visit https://www.archlinux.org/. + Visit https://www.archlinux.org/. + Visit Arch Linux. + Visit Arch Linux.

    EOD cat <<-EOD | sqlite3 aur.db >actual && SELECT RenderedComment FROM PackageComments WHERE ID = 4; From 127bb4c84cf8584dd4ee9f544333782d386224ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 2 Feb 2020 20:25:08 +0100 Subject: [PATCH 0501/1891] rendercomment: safer Flyspray task linkification When an FS#123 is part of a code block, it must not be converted into a link. FS#123 may also appear inside an URL, in which case regular linkifaction of URLs must take precedence. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 21 ++++++++++++++------- test/t2600-rendercomment.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 346ccff1..22ed7b93 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -29,18 +29,25 @@ class LinkifyExtension(markdown.extensions.Extension): md.inlinePatterns.add('linkify', processor, '_end') -class FlysprayLinksPreprocessor(markdown.preprocessors.Preprocessor): - _fsre = re.compile(r'\b(FS#(\d+))\b') - _sub = r'[\1](https://bugs.archlinux.org/task/\2)' +class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): + """ + Turn Flyspray task references like FS#1234 into links to bugs.archlinux.org. - def run(self, lines): - return [self._fsre.sub(self._sub, line) for line in lines] + The pattern's capture group 0 is the text of the link and group 1 is the + Flyspray task ID. + """ + + def handleMatch(self, m, data): + el = markdown.util.etree.Element('a') + el.set('href', f'https://bugs.archlinux.org/task/{m.group(1)}') + el.text = markdown.util.AtomicString(m.group(0)) + return el, m.start(0), m.end(0) class FlysprayLinksExtension(markdown.extensions.Extension): def extendMarkdown(self, md, md_globals): - preprocessor = FlysprayLinksPreprocessor(md) - md.preprocessors.add('flyspray-links', preprocessor, '_end') + processor = FlysprayLinksInlineProcessor(r'\bFS#(\d+)\b',md) + md.inlinePatterns.add('flyspray-links', processor, '_end') class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index b0209eb5..1da422d3 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -103,4 +103,30 @@ test_expect_success 'Test Git commit linkification.' ' test_cmp actual expected ' +test_expect_success 'Test Flyspray issue linkification.' ' + sqlite3 aur.db <<-EOD && + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (6, 1, " + FS#1234567. + *FS#1234* + FS# + XFS#1 + \`FS#1234\` + https://archlinux.org/?test=FS#1234 + ", ""); + EOD + "$RENDERCOMMENT" 6 && + cat <<-EOD >expected && +

    FS#1234567. + FS#1234 + FS# + XFS#1 + FS#1234 + https://archlinux.org/?test=FS#1234

    + EOD + sqlite3 aur.db <<-EOD >actual && + SELECT RenderedComment FROM PackageComments WHERE ID = 6; + EOD + test_cmp actual expected +' + test_done From 81faab9978a80e1608b99b5d45456548eaf01a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 2 Feb 2020 20:25:33 +0100 Subject: [PATCH 0502/1891] rendercomment: test headings lowering Signed-off-by: Lukas Fleischer --- test/t2600-rendercomment.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index 1da422d3..1ba560af 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -129,4 +129,30 @@ test_expect_success 'Test Flyspray issue linkification.' ' test_cmp actual expected ' +test_expect_success 'Test headings lowering.' ' + sqlite3 aur.db <<-EOD && + INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (7, 1, " + # One + ## Two + ### Three + #### Four + ##### Five + ###### Six + ", ""); + EOD + "$RENDERCOMMENT" 7 && + cat <<-EOD >expected && +
    One
    +
    Two
    +
    Three
    +
    Four
    +
    Five
    +
    Six
    + EOD + sqlite3 aur.db <<-EOD >actual && + SELECT RenderedComment FROM PackageComments WHERE ID = 7; + EOD + test_cmp actual expected +' + test_done From e15d5c8180fab81d3e533cc521c1a98ff6f5b0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 2 Feb 2020 20:26:13 +0100 Subject: [PATCH 0503/1891] rendercomment: use python-markdown's new registration API First, this gets rid of the deprecation warnings Python displayed. Second, this fixes the case where a link contained a pair of underscores, which used to be interpreted as an emphasis because the linkify processor ran after the emphasis processor. Signed-off-by: Lukas Fleischer --- aurweb/scripts/rendercomment.py | 10 ++++++---- test/t2600-rendercomment.sh | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 22ed7b93..76865d27 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -26,7 +26,8 @@ class LinkifyExtension(markdown.extensions.Extension): def extendMarkdown(self, md, md_globals): processor = markdown.inlinepatterns.AutolinkInlineProcessor(self._urlre, md) - md.inlinePatterns.add('linkify', processor, '_end') + # Register it right after the default <>-link processor (priority 120). + md.inlinePatterns.register(processor, 'linkify', 119) class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): @@ -47,7 +48,7 @@ class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): class FlysprayLinksExtension(markdown.extensions.Extension): def extendMarkdown(self, md, md_globals): processor = FlysprayLinksInlineProcessor(r'\bFS#(\d+)\b',md) - md.inlinePatterns.add('flyspray-links', processor, '_end') + md.inlinePatterns.register(processor, 'flyspray-links', 118) class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): @@ -92,7 +93,7 @@ class GitCommitsExtension(markdown.extensions.Extension): def extendMarkdown(self, md, md_globals): processor = GitCommitsInlineProcessor(md, self._head) - md.inlinePatterns.add('git-commits', processor, '_end') + md.inlinePatterns.register(processor, 'git-commits', 117) class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor): @@ -106,7 +107,8 @@ class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor): class HeadingExtension(markdown.extensions.Extension): def extendMarkdown(self, md, md_globals): - md.treeprocessors.add('heading', HeadingTreeprocessor(md), '_end') + # Priority doesn't matter since we don't conflict with other processors. + md.treeprocessors.register(HeadingTreeprocessor(md), 'heading', 30) def get_comment(conn, commentid): diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh index 1ba560af..be408b80 100755 --- a/test/t2600-rendercomment.sh +++ b/test/t2600-rendercomment.sh @@ -52,7 +52,8 @@ test_expect_success 'Test HTML sanitizing.' ' test_expect_success 'Test link conversion.' ' cat <<-EOD | sqlite3 aur.db && INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (4, 1, " - Visit https://www.archlinux.org/. + Visit https://www.archlinux.org/#_test_. + Visit *https://www.archlinux.org/*. Visit . Visit \`https://www.archlinux.org/\`. Visit [Arch Linux](https://www.archlinux.org/). @@ -62,7 +63,8 @@ test_expect_success 'Test link conversion.' ' EOD "$RENDERCOMMENT" 4 && cat <<-EOD >expected && -

    Visit https://www.archlinux.org/. +

    Visit https://www.archlinux.org/#_test_. + Visit https://www.archlinux.org/. Visit https://www.archlinux.org/. Visit https://www.archlinux.org/. Visit Arch Linux. From d4632aaffa062de7cdc03c3e33e13fa0d9e77317 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 10 Feb 2020 11:05:27 +0100 Subject: [PATCH 0504/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ar.po | 160 ++++++++++++++++++++++++++------ po/ast.po | 162 ++++++++++++++++++++++++++------ po/ca.po | 156 +++++++++++++++++++++++++------ po/cs.po | 164 ++++++++++++++++++++++++++------ po/da.po | 225 ++++++++++++++++++++++++++++++++------------ po/de.po | 168 ++++++++++++++++++++++++++------- po/el.po | 156 +++++++++++++++++++++++++------ po/es.po | 160 ++++++++++++++++++++++++++------ po/es_419.po | 160 ++++++++++++++++++++++++++------ po/fi.po | 172 +++++++++++++++++++++++++++------- po/fr.po | 162 ++++++++++++++++++++++++++------ po/he.po | 258 ++++++++++++++++++++++++++++++++++++--------------- po/hr.po | 150 +++++++++++++++++++++++++----- po/hu.po | 160 ++++++++++++++++++++++++++------ po/it.po | 160 ++++++++++++++++++++++++++------ po/ja.po | 206 ++++++++++++++++++++++++++++++---------- po/nb.po | 162 ++++++++++++++++++++++++++------ po/nl.po | 158 +++++++++++++++++++++++++------ po/pl.po | 173 +++++++++++++++++++++++++++------- po/pt_BR.po | 162 ++++++++++++++++++++++++++------ po/pt_PT.po | 162 ++++++++++++++++++++++++++------ po/ro.po | 158 +++++++++++++++++++++++++------ po/ru.po | 160 ++++++++++++++++++++++++++------ po/sk.po | 167 ++++++++++++++++++++++++++------- po/sr.po | 160 ++++++++++++++++++++++++++------ po/tr.po | 162 ++++++++++++++++++++++++++------ po/uk.po | 207 +++++++++++++++++++++++++++++++---------- po/zh_CN.po | 162 ++++++++++++++++++++++++++------ po/zh_TW.po | 210 ++++++++++++++++++++++++++++++----------- 29 files changed, 4002 insertions(+), 980 deletions(-) diff --git a/po/ar.po b/po/ar.po index 64a1b870..7664c478 100644 --- a/po/ar.po +++ b/po/ar.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # safa1996alfulaij , 2015 @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Arabic (http://www.transifex.com/lfleischer/aurweb/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -74,6 +74,10 @@ msgstr "تعذّر جلب معلومات المستخدم المحدّد." msgid "You do not have permission to edit this account." msgstr "لا صلاحيّات لديك لتحرير هذا الحساب." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "استخدم هذه الاستمارة للبحث عن حسابات موجودة." @@ -368,10 +372,10 @@ msgid "Enter login credentials" msgstr "أدخل بيانات الولوج" #: html/login.php -msgid "User name or email address" -msgstr "اسم المستخدم أو عنوان البريد الإلكترونيّ" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "كلمة المرور" @@ -432,8 +436,8 @@ msgid "Your password has been reset successfully." msgstr "صُفّرت كلمة مرورك بنجاح." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "أكّد عنوان بريدك الإلكترونيّ:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -450,13 +454,13 @@ msgstr "تابع" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "إن نسيت عنوان البريد الإلكترونيّ الذي استخدمته للتّسجيل، فضلًا أرسل رسالة إلى قائمة %saur-general%s البريديّة." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "أدخل عنوان بريدك الإلكترونيّ:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -648,19 +652,19 @@ msgstr "" msgid "Close Request" msgstr "أغلق الطّلب" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "الأولى" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "السّابقة" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "التّالية" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "الأخيرة" @@ -761,10 +765,18 @@ msgstr "يجب أن يبدأ وينتهي بحرف أو رقم." msgid "Can contain only one period, underscore or hyphen." msgstr "يمكنه احتواء نقطة واحدة، أو شرطة سفليّة واحدة أو شرطة واحدة." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "عنوان البريد الإلكترونيّ غير صالح." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -804,6 +816,18 @@ msgstr "العنوان %s%s%s مستخدم بالفعل." msgid "The SSH public key, %s%s%s, is already in use." msgstr "مفتاح SSH العموميّ %s%s%s مستخدم بالفعل." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1213,6 +1237,10 @@ msgstr "اعرض ملفّ هذا المستخدم الشخصيّ" msgid "Edit this user's account" msgstr "حرّر حساب هذا المستخدم" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1223,6 +1251,11 @@ msgstr "انقر %sهنا%s إن أردت حذف هذا الحساب نهائي msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "مطلوب" @@ -1260,8 +1293,34 @@ msgid "Hide Email Address" msgstr "أخفِ عنوان البريد الإلكترونيّ" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "أعد كتابة كلمة المرور" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1271,6 +1330,16 @@ msgstr "اللغة" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "أعد كتابة كلمة المرور" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1297,6 +1366,24 @@ msgstr "أخطرني بتحديثات الحزم" msgid "Notify of ownership changes" msgstr "أخطرني بتغيير المُلّاك" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1425,7 +1512,7 @@ msgstr "صوّت لهذه الحزمة" msgid "Disable notifications" msgstr "عطّل الإخطارات" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "فعّل الإخطارات" @@ -1460,6 +1547,10 @@ msgstr "عنوان غِت للاستنساخ" msgid "read-only" msgstr "للقراءة فقط" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1506,9 +1597,16 @@ msgstr "حرّر تعليق: %s" msgid "Add Comment" msgstr "أضف تعليقًا" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "اعرض كلّ التّعليقات" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1518,6 +1616,10 @@ msgstr "التّعليقات المثبّتة" msgid "Latest Comments" msgstr "آخر التّعليقات" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1528,6 +1630,11 @@ msgstr "علّق %s على %s" msgid "Anonymous comment on %s" msgstr "تعليق مجهول على %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1564,10 +1671,6 @@ msgstr "ثبّت التّعليق" msgid "Unpin comment" msgstr "فكّ تثبيت التّعليق" -#: template/pkg_comments.php -msgid "All comments" -msgstr "كلّ التّعليقات" - #: template/pkg_details.php msgid "Package Details" msgstr "تفاصيل الحزمة" @@ -2130,6 +2233,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/ast.po b/po/ast.po index df9db049..5e08e86b 100644 --- a/po/ast.po +++ b/po/ast.po @@ -1,18 +1,18 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # enolp , 2014-2015,2017 # Ḷḷumex03 , 2014 -# Pablo Lezaeta Reyes [pˈaβ̞lo lˌe̞θaˈeta rˈejɛ] , 2014-2015 +# prflr88 , 2014-2015 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Asturian (http://www.transifex.com/lfleischer/aurweb/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -75,6 +75,10 @@ msgstr "Nun pudo recibise la información pal usuariu especificáu." msgid "You do not have permission to edit this account." msgstr "Nun tienes permisu pa editar esta cuenta." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa esti formulariu pa guetar cuentes esistentes." @@ -369,10 +373,10 @@ msgid "Enter login credentials" msgstr "Introduz les tos credenciales d'aniciu sesión" #: html/login.php -msgid "User name or email address" -msgstr "Nome d'usuariu o direición de corréu" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" @@ -433,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "La to contraseña reanicióse con ésitu." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Confirma'l to corréu:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -451,13 +455,13 @@ msgstr "Siguir" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si escaecisti la dirección de corréu electrónicu utilizasti pa rexistrar, complacer unviar un mensaxe a la llista de orréu %saur-xeneral%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Introduz la to direción de corréu:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -649,19 +653,19 @@ msgstr "" msgid "Close Request" msgstr "Zarar solicitú" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" @@ -762,10 +766,18 @@ msgstr "" msgid "Can contain only one period, underscore or hyphen." msgstr "" +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La direición de corréu nun ye válida." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -805,6 +817,18 @@ msgstr "La direición, %s%s%s, yá ta n'usu." msgid "The SSH public key, %s%s%s, is already in use." msgstr "La llave pública SSH, %s%s%s, ye yá n'usu." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1214,6 +1238,10 @@ msgstr "" msgid "Edit this user's account" msgstr "" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1224,6 +1252,11 @@ msgstr "Primi %sequí%s si quies desaniciar esta cuenta dafechu." msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "riquíu" @@ -1261,8 +1294,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Teclexa de nueves la contraseña" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1272,6 +1331,16 @@ msgstr "Llingua" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Teclexa de nueves la contraseña" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1298,6 +1367,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1426,7 +1513,7 @@ msgstr "Votar pol paquete" msgid "Disable notifications" msgstr "" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1457,6 +1544,10 @@ msgstr "URL pa clonar con Git" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1503,9 +1594,16 @@ msgstr "" msgid "Add Comment" msgstr "Amestar comentariu" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Ver tolos comentarios" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1515,6 +1613,10 @@ msgstr "" msgid "Latest Comments" msgstr "Comentarios caberos" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1525,6 +1627,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1561,10 +1668,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Tolos comentarios" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" @@ -2111,6 +2214,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/ca.po b/po/ca.po index 4ce79e69..c30fb1d8 100644 --- a/po/ca.po +++ b/po/ca.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Adolfo Jayme-Barrientos, 2014 @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Catalan (http://www.transifex.com/lfleischer/aurweb/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -75,6 +75,10 @@ msgstr "No s'ha pogut obtenir la informació de l'usuari especificat." msgid "You do not have permission to edit this account." msgstr "No teniu permís per a editar aquest compte." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilitzeu aquest formulari per a cercar comptes existents." @@ -369,10 +373,10 @@ msgid "Enter login credentials" msgstr "Introduïu les credencials d'inici de sessió" #: html/login.php -msgid "User name or email address" +msgid "User name or primary email address" msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Contrasenya" @@ -433,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "La seva contrasenya s'ha restablert correctament." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Tots" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -451,13 +455,13 @@ msgstr "Continuar" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si ha oblidat l'adreça de correu electrònic utilitzada al registrar-se, si us plau envïi un missatge a la llista de correu %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Introduiu la vostra adreça de correu." +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -649,19 +653,19 @@ msgstr "" msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primer" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Següent" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Darrer" @@ -762,10 +766,18 @@ msgstr "Comença i finalitza amb una lletra o número" msgid "Can contain only one period, underscore or hyphen." msgstr "Només pot contenir un punt, guió o guió baix." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adreça del correu-e no és vàlida." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -805,6 +817,18 @@ msgstr "L'adressa, %s%s%s, ja s'està fent servir." msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1214,6 +1238,10 @@ msgstr "Visualitza els paquets d'aquest usuari" msgid "Edit this user's account" msgstr "" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1224,6 +1252,11 @@ msgstr "" msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "requerit" @@ -1261,8 +1294,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Escriu altre cop la contrasenya" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1272,6 +1331,16 @@ msgstr "Idioma" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Escriu altre cop la contrasenya" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1298,6 +1367,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1426,7 +1513,7 @@ msgstr "Vota per aquest paquet" msgid "Disable notifications" msgstr "Deshabilitar notificacions" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1457,6 +1544,10 @@ msgstr "" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1503,8 +1594,15 @@ msgstr "" msgid "Add Comment" msgstr "Afegir un comentari" -#: template/pkg_comments.php -msgid "View all comments" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." msgstr "" #: template/pkg_comments.php @@ -1515,6 +1613,10 @@ msgstr "" msgid "Latest Comments" msgstr "Darrers Comentaris" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1525,6 +1627,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1561,10 +1668,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Tots el comentaris" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalls del paquet" @@ -2111,6 +2214,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/cs.po b/po/cs.po index a69a21dc..ef165358 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,11 +1,11 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Daniel Milde , 2017 -# Jaroslav Lichtblau , 2015-2016 -# Jaroslav Lichtblau , 2014 +# Jaroslav Lichtblau , 2015-2016 +# Jaroslav Lichtblau , 2014 # Jiří Vírava , 2017-2018 # Lukas Fleischer , 2011 # Pavel Ševeček , 2014 @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-31 10:10+0000\n" -"Last-Translator: Jiří Vírava \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aurweb/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,6 +78,10 @@ msgstr "Nelze obdržet informace pro vybraného uživatele." msgid "You do not have permission to edit this account." msgstr "Nemáte oprávnění pro úpravu tohoto účtu." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Pro vyhledání existujících účtů použíte tento formulář." @@ -372,10 +376,10 @@ msgid "Enter login credentials" msgstr "Vložit přihlašovací údaje" #: html/login.php -msgid "User name or email address" -msgstr "Uživatelské jméno nebo e-mailová adresa" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Heslo" @@ -436,8 +440,8 @@ msgid "Your password has been reset successfully." msgstr "Heslo bylo úspěšně resetováno." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Potvrďte svou e-mailovou adresu:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -454,13 +458,13 @@ msgstr "Pokračovat" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Pokud jste zapomněli emailovou adresu použitou při registraci, pošlete zprávu na %saur-general%s mailing list." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Zadejte emailovou adresu:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -652,19 +656,19 @@ msgstr "Odeslat žádost" msgid "Close Request" msgstr "Uzavřít žádost" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "První" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Předchozí" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Další" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Poslední" @@ -765,10 +769,18 @@ msgstr "Začíná a končí písmenem nebo číslicí" msgid "Can contain only one period, underscore or hyphen." msgstr "Může obsahovat pouze jednu tečku, podtržítko nebo spojovník." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Vadná emailová adresa." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Domovská stránka je neplatná, zadejte úplnou adresu URL HTTP(s)." @@ -808,6 +820,18 @@ msgstr "Adresa, %s%s%s, je již použita." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Veřejný SSH klíč, %s%s%s, je již použit." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1217,6 +1241,10 @@ msgstr "Zobrazit balíčky tohoto uživatele" msgid "Edit this user's account" msgstr "Upravit tento uživatelský účet" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1227,6 +1255,11 @@ msgstr "" msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "vyžadováno" @@ -1264,8 +1297,34 @@ msgid "Hide Email Address" msgstr "Skrýt email" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Heslo znovu" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1275,6 +1334,16 @@ msgstr "Jazyk" msgid "Timezone" msgstr "Časové pásmo" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Heslo znovu" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1301,6 +1370,24 @@ msgstr "Oznámení o aktualizacích balíčku" msgid "Notify of ownership changes" msgstr "Oznámit změnu vlastnictví" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1429,7 +1516,7 @@ msgstr "Hlasovat pro tento balíček" msgid "Disable notifications" msgstr "Vypnout oznámení" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Zapnout oznámení" @@ -1462,6 +1549,10 @@ msgstr "" msgid "read-only" msgstr "jen pro čtení" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1508,9 +1599,16 @@ msgstr "" msgid "Add Comment" msgstr "Přidat komentář" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Zobrazit všechny komentáře" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1520,6 +1618,10 @@ msgstr "Připnuté komentáře" msgid "Latest Comments" msgstr "Nejnovější komentáře" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1530,6 +1632,11 @@ msgstr "%s přidal komentář %s" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1566,10 +1673,6 @@ msgstr "Připnout komentář" msgid "Unpin comment" msgstr "Odepnout komentář" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Všechny komentáře" - #: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčku" @@ -2124,6 +2227,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/da.po b/po/da.po index f4e2c2e2..b78fc785 100644 --- a/po/da.po +++ b/po/da.po @@ -1,17 +1,18 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: +# Linuxbruger , 2018 # Louis Tim Larsen , 2015 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Danish (http://www.transifex.com/lfleischer/aurweb/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,29 +22,29 @@ msgstr "" #: html/404.php msgid "Page Not Found" -msgstr "Siden blev ikke fundet" +msgstr "Side ikke fundet" #: html/404.php msgid "Sorry, the page you've requested does not exist." -msgstr "Beklager, den forspurgte side findes ikke." +msgstr "Beklager, den forespurgte side eksisterer ikke." #: html/404.php template/pkgreq_close_form.php msgid "Note" -msgstr "" +msgstr "Note" #: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "Git klone URL'er, er ikke ment til at blive åbnet i en browser." #: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "For at klone Git lageret af %s, kør %s." #: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Klik %sher%s for at vende tilbage til %s detalje siden." #: html/503.php msgid "Service Unavailable" @@ -52,7 +53,7 @@ msgstr "Service utilgængelig" #: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "" +msgstr "Lad vær med at gå i panik! Denne side er nede på grund af vedligeholdelse. Vi vil være tilbage snart." #: html/account.php msgid "Account" @@ -74,6 +75,10 @@ msgstr "Kunne ikke hente information om den specifikke bruger." msgid "You do not have permission to edit this account." msgstr "Du har ikke tilladelse til at redigere denne konto." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Brug denne formular til at søge i eksisterende konti." @@ -84,11 +89,11 @@ msgstr "Du skal være logget ind for at se brugerinformation." #: html/addvote.php template/tu_list.php msgid "Add Proposal" -msgstr "" +msgstr "Tilføj Forslag" #: html/addvote.php msgid "Invalid token for user action." -msgstr "" +msgstr "Ugyldigt tegn for bruger handling." #: html/addvote.php msgid "Username does not exist." @@ -101,7 +106,7 @@ msgstr "%s har allerede et forslag kørende for dem." #: html/addvote.php msgid "Invalid type." -msgstr "" +msgstr "Ugyldig type." #: html/addvote.php msgid "Proposal cannot be empty." @@ -117,7 +122,7 @@ msgstr "Fremsæt et forslag til afstemning." #: html/addvote.php msgid "Applicant/TU" -msgstr "" +msgstr "Ansøger/TU" #: html/addvote.php msgid "(empty if not applicable)" @@ -130,15 +135,15 @@ msgstr "Type" #: html/addvote.php msgid "Addition of a TU" -msgstr "" +msgstr "Tilføjelse af en TU" #: html/addvote.php msgid "Removal of a TU" -msgstr "" +msgstr "Bortskaffelse af en TU" #: html/addvote.php msgid "Removal of a TU (undeclared inactivity)" -msgstr "" +msgstr "Bortskaffelse af en TU (ikke erklæret inaktivitet)" #: html/addvote.php msgid "Amendment of Bylaws" @@ -154,11 +159,11 @@ msgstr "Tilføj" #: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" -msgstr "" +msgstr "Håndter Co-vedligeholdere" #: html/commentedit.php template/pkg_comments.php msgid "Edit comment" -msgstr "" +msgstr "Rediger kommentar" #: html/home.php template/header.php msgid "Dashboard" @@ -170,78 +175,78 @@ msgstr "Hjem" #: html/home.php msgid "My Flagged Packages" -msgstr "" +msgstr "Mine Markerede Pakker" #: html/home.php msgid "My Requests" -msgstr "" +msgstr "Mine forespørgelser" #: html/home.php msgid "My Packages" -msgstr "Mine pakker" +msgstr "Mine Pakker" #: html/home.php msgid "Search for packages I maintain" -msgstr "" +msgstr "Søg efter pakker jeg vedligeholder" #: html/home.php msgid "Co-Maintained Packages" -msgstr "" +msgstr "Co-Vedligeholdt Pakker" #: html/home.php msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Søg efter pakker jeg co-vedligeholder" #: html/home.php #, php-format msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "" +msgstr "Velkommen til AUR! Venligst læs %sAUR Bruger Retningslinier %s og %sAUR TU Retningslinier%s for mere information." #: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "" +msgstr "Bidragede PKGBUILDs %sskal%s være i overensstemmelse med %sArch Pakke Standarder%s ellers vil de blive slettet!" #: html/home.php msgid "Remember to vote for your favourite packages!" -msgstr "" +msgstr "Husk at stemme for dine favorit pakker!" #: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "" +msgstr "Nogle pakker kan være stillet til rådighed som binær i (fællesskab)." #: html/home.php msgid "DISCLAIMER" -msgstr "" +msgstr "ANSVARSFRASKRIVELSE" #: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "" +msgstr "AUR pakker er bruger produceret materiale. Hvilken som helst brug af de filer der er stillet til rådighed er på din egen risiko." #: html/home.php msgid "Learn more..." -msgstr "" +msgstr "Lær mere..." #: html/home.php msgid "Support" -msgstr "" +msgstr "Support" #: html/home.php msgid "Package Requests" -msgstr "" +msgstr "Pakke Forespørgelser" #: html/home.php #, php-format msgid "" "There are three types of requests that can be filed in the %sPackage " "Actions%s box on the package details page:" -msgstr "" +msgstr "Der er tre typer af forespørgelser der kan udfyldes i%sPakke Handlinger%s boxen på pakke detaljer siden:" #: html/home.php msgid "Orphan Request" @@ -251,11 +256,11 @@ msgstr "" msgid "" "Request a package to be disowned, e.g. when the maintainer is inactive and " "the package has been flagged out-of-date for a long time." -msgstr "" +msgstr "Forespørg en pakke til at blive forstødt, f.eks når vedligeholderen er inaktiv og pakkerne er blevet markeret som dato-udløbet i lang tid." #: html/home.php msgid "Deletion Request" -msgstr "" +msgstr "Sletning Forespørgsel" #: html/home.php msgid "" @@ -368,10 +373,10 @@ msgid "Enter login credentials" msgstr "" #: html/login.php -msgid "User name or email address" +msgid "User name or primary email address" msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Adgangskode" @@ -432,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "Din adgangskode blev nulstillet." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Bekræft din nye mail-adresse:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -450,13 +455,13 @@ msgstr "Forsæt" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Indtast din mail-adresse:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -648,19 +653,19 @@ msgstr "" msgid "Close Request" msgstr "Luk forspørgsel" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Tidligere" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Næste" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Sidste" @@ -761,10 +766,18 @@ msgstr "Start og slut med et bogstav eller tal" msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun indeholde ét punktum, én bundstreg eller én bindestreg." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mail adressen er ugyldig." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -804,6 +817,18 @@ msgstr "" msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1213,6 +1238,10 @@ msgstr "Vis pakker fra denne bruger" msgid "Edit this user's account" msgstr "" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1223,6 +1252,11 @@ msgstr "" msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "påkrævet" @@ -1260,8 +1294,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Bekræft adgangskode" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1271,6 +1331,16 @@ msgstr "Sprog" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Bekræft adgangskode" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1297,6 +1367,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1425,7 +1513,7 @@ msgstr "Stem på denne pakke" msgid "Disable notifications" msgstr "Deaktiver notifikationer" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1456,6 +1544,10 @@ msgstr "" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1502,9 +1594,16 @@ msgstr "" msgid "Add Comment" msgstr "Tilføj kommentar" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Vis alle kommentarer" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1514,6 +1613,10 @@ msgstr "" msgid "Latest Comments" msgstr "Seneste kommentarer" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1524,6 +1627,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1560,10 +1668,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Alle kommentarer" - #: template/pkg_details.php msgid "Package Details" msgstr "Detaljer om pakken" @@ -2110,6 +2214,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/de.po b/po/de.po index 00ab95c2..8b2ea808 100644 --- a/po/de.po +++ b/po/de.po @@ -1,10 +1,10 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: -# Alexander Griesbaum , 2013 -# Alexander Griesbaum , 2013-2014 +# 9d91e189c22376bb4ee81489bc27fc28, 2013 +# 9d91e189c22376bb4ee81489bc27fc28, 2013-2014 # bjo , 2013 # FabianS_ , 2012 # go2sh , 2015-2016 @@ -17,17 +17,17 @@ # Matthias Gorissen , 2012 # Nuc1eoN , 2014 # Nuc1eoN , 2014 -# simon04 , 2018 +# Simon Legner , 2018 # Simon Schneider , 2011 -# Stefan Auditor , 2017-2018 +# Stefan Auditor , 2017-2018,2020 # Thomas_Do , 2013-2014 # Thomas_Do , 2012-2013 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 15:47+0000\n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 11:12+0000\n" "Last-Translator: Stefan Auditor \n" "Language-Team: German (http://www.transifex.com/lfleischer/aurweb/language/de/)\n" "MIME-Version: 1.0\n" @@ -91,6 +91,10 @@ msgstr "Es konnten keine Informationen für den angegebenen Benutzer geladen wer msgid "You do not have permission to edit this account." msgstr "Du hast keine Berechtigung, dieses Konto zu ändern." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "Passwort ungültig." + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Benutze dieses Formular, um vorhandene Konten zu suchen." @@ -385,10 +389,10 @@ msgid "Enter login credentials" msgstr "Zugangsdaten eingeben" #: html/login.php -msgid "User name or email address" -msgstr "Benutzername oder E-Mail-Adresse" +msgid "User name or primary email address" +msgstr "Benutzername oder primäre E-Mail-Adresse" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Passwort" @@ -449,8 +453,8 @@ msgid "Your password has been reset successfully." msgstr "Dein Passwort wurde erfolgreich zurückgesetzt." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Bestätige Deine E-Mail-Adresse:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "Benutzername oder primäre E-Mail-Adresse bestätigen:" #: html/passreset.php msgid "Enter your new password:" @@ -467,13 +471,13 @@ msgstr "Weiter" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Wenn Du die E-Mail-Adresse vergessen hast, die Du für Deine Registrierung benutzt hast, sende bitte eine Nachricht an die %saur-general%s Mailing-Liste." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Gib Deine E-Mail-Adresse ein:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "Benutzername oder primäre E-Mail-Adresse eingeben:" #: html/pkgbase.php msgid "Package Bases" @@ -665,19 +669,19 @@ msgstr "Anfrage absenden" msgid "Close Request" msgstr "Anfrage schließen" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Erste" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Zurück" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Weiter" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Letzte" @@ -778,10 +782,18 @@ msgstr "Muss mit einem Buchstaben oder einer Zahl beginnen und enden" msgid "Can contain only one period, underscore or hyphen." msgstr "Kann nur einen Punkt, Unter- oder Bindestrich enthalten." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "Bitte das neue Passwort bestätigen." + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Die E-Mail-Adresse ist ungültig." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "Die sicherungs E-Mail-Adresse ist ungültig." + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Diese Adresse ist ungültig, bitte eine vollständige HTTP(S) URL angeben." @@ -821,6 +833,18 @@ msgstr "Die Adresse %s%s%s wird bereits verwendet." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Der öffentliche SSH Schlüssel, %s%s%s, ist bereits in Benutzung." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "Das CPATCHA fehlt." + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "Das CAPTCHA ist abgelaufen. Bitte versuche es noch einmal." + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "Die eingegebene CAPTCHA Antwort ist ungültig." + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1230,6 +1254,10 @@ msgstr "Alle Pakete dieses Benutzers anzeigen" msgid "Edit this user's account" msgstr "Konto dieses Benutzers bearbeiten" +#: template/account_details.php +msgid "List this user's comments" +msgstr "Die Kommentare des Benutzers anzeigen" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1240,6 +1268,11 @@ msgstr "Klicke %shier%s, wenn du diesen Account unwiderruflich entfernen möchte msgid "Click %shere%s for user details." msgstr "Klicke %shere%s für Benutzerdetails." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "Notwendig" @@ -1277,8 +1310,34 @@ msgid "Hide Email Address" msgstr "Verstecke E-Mail-Adresse" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Bestätige das Passwort" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "Sicherungs E-Mail-Adresse" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1288,6 +1347,16 @@ msgstr "Sprache" msgid "Timezone" msgstr "Zeitzone" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Bestätige das Passwort" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1314,6 +1383,24 @@ msgstr "Benachrichtige Paketaktualisierungen" msgid "Notify of ownership changes" msgstr "Benachrichtige Besitzeränderungen" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "Um die Änderungen an deinem Profil zu bestätigen, gib bitte Dein aktuelles Paswort ein:" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "Dein aktuelles Passwort" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "Antwort" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1442,7 +1529,7 @@ msgstr "Für dieses Paket stimmen" msgid "Disable notifications" msgstr "Benachrichtigungen deaktivieren" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Benachrichtigungen aktivieren" @@ -1473,6 +1560,10 @@ msgstr "Git Clone URL" msgid "read-only" msgstr "nur lesen" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "kopieren" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1519,9 +1610,16 @@ msgstr "Bearbeite Kommentar für: %s" msgid "Add Comment" msgstr "Kommentar hinzufügen" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Zeige alle Kommentare" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "%sMarkdown syntax%s wird teilweise unterstützt." #: template/pkg_comments.php msgid "Pinned Comments" @@ -1531,6 +1629,10 @@ msgstr "Angeheftete Kommentare" msgid "Latest Comments" msgstr "Neueste Kommentare" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "Kommentare für" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1541,6 +1643,11 @@ msgstr "%s kommentierte %s" msgid "Anonymous comment on %s" msgstr "Anonym kommentierte %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1577,10 +1684,6 @@ msgstr "Kommentar anheften" msgid "Unpin comment" msgstr "Kommentar losheften" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Alle Kommentare" - #: template/pkg_details.php msgid "Package Details" msgstr "Paket-Details" @@ -2127,8 +2230,9 @@ msgstr "AUR Paket gelöscht: {pkgbase}" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "{user} [1] hat {old} [2] in {new} [3] gemerged.\n\nWenn Du keine weiteren Benachrichtigungen über das neue Paket erhalten möchtest, gehe bitte zu [3] und klicke \"{label}\"." +msgstr "" #: scripts/notify.py #, python-brace-format diff --git a/po/el.po b/po/el.po index 8eaa5f0f..7af57544 100644 --- a/po/el.po +++ b/po/el.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Achilleas Pipinellis, 2014 @@ -14,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aurweb/language/el/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -79,6 +79,10 @@ msgstr "Δεν ήταν δυνατή η λήψη πληροφοριών για msgid "You do not have permission to edit this account." msgstr "Δεν έχετε την άδεια να επεξεργαστείτε αυτόν τον λογαριασμό." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Χρησιμοποιήστε αυτή τη φόρμα για να αναζητήσετε υπάρχοντες λογαριασμούς." @@ -373,10 +377,10 @@ msgid "Enter login credentials" msgstr "Εισάγετε πιστοποιητικά εισόδου" #: html/login.php -msgid "User name or email address" +msgid "User name or primary email address" msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Κωδικός" @@ -437,8 +441,8 @@ msgid "Your password has been reset successfully." msgstr "Το συνθηματικό σας έχει επαναφερθεί με επιτυχία." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Παρακαλώ επιβεβαιώστε την διεύθυνση e-mail σας:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -455,13 +459,13 @@ msgstr "Συνεχίστε" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Εάν έχετε ξεχάσει την ηλεκτρονική διεύθυνση που χρησιμοποιήσατε για να εγγραφείτε, παρακαλώ στείλτε ένα μήνυμα στη λίστα ταχυδρομείου %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Εισάγετε την διεύθυνση e-mail σας:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -653,19 +657,19 @@ msgstr "" msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Πρώτο" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Προηγούμενο" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Επόμενο" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Τελευταίο" @@ -766,10 +770,18 @@ msgstr "Ξεκινήστε και τελειώστε με γράμμα ή αρι msgid "Can contain only one period, underscore or hyphen." msgstr "Μπορεί να περιλαμβάνει μόνο μία τελεία, κάτω παύλα ή παύλα." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Αυτή η διεύθυνση email δεν είναι έγκυρη." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -809,6 +821,18 @@ msgstr "Η διεύθυνση, %s%s%s, χρησιμοποιείται ήδη." msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1218,6 +1242,10 @@ msgstr "Δείτε τα πακέτα αυτού του χρήστη" msgid "Edit this user's account" msgstr "Τροποποιήστε το λογαριασμό αυτού του χρήστη" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1228,6 +1256,11 @@ msgstr "" msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "απαιτούμενο" @@ -1265,8 +1298,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Πληκτρολογήστε ξανά τον κωδικό σας." +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1276,6 +1335,16 @@ msgstr "Γλώσσα" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Πληκτρολογήστε ξανά τον κωδικό σας." + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1302,6 +1371,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1430,7 +1517,7 @@ msgstr "Ψηφίστε για αυτό το πακέτο" msgid "Disable notifications" msgstr "Απενεργοποιήστε τις ειδοποιήσεις" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1461,6 +1548,10 @@ msgstr "" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1507,8 +1598,15 @@ msgstr "" msgid "Add Comment" msgstr "Προσθέστε σχόλιο" -#: template/pkg_comments.php -msgid "View all comments" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." msgstr "" #: template/pkg_comments.php @@ -1519,6 +1617,10 @@ msgstr "" msgid "Latest Comments" msgstr "Τελευταία σχόλια" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1529,6 +1631,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1565,10 +1672,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Όλα τα σχόλια" - #: template/pkg_details.php msgid "Package Details" msgstr "Πληροφορίες Πακέτου" @@ -2115,6 +2218,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/es.po b/po/es.po index b4f62494..d60f45f1 100644 --- a/po/es.po +++ b/po/es.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Adolfo Jayme-Barrientos, 2015 @@ -19,9 +19,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2019-07-16 01:55+0000\n" -"Last-Translator: prflr88 \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Spanish (http://www.transifex.com/lfleischer/aurweb/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -84,6 +84,10 @@ msgstr "No se pudo obtener la información del usuario especificado." msgid "You do not have permission to edit this account." msgstr "No tienes los permisos para editar esta cuenta." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa este formulario para buscar cuentas existentes." @@ -378,10 +382,10 @@ msgid "Enter login credentials" msgstr "Proporciona tus datos de acceso" #: html/login.php -msgid "User name or email address" -msgstr "Nombre de usuario y dirección de correo" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" @@ -442,8 +446,8 @@ msgid "Your password has been reset successfully." msgstr "Se ha restablecido la contraseña correctamente." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Confirma tu dirección de correo:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -460,13 +464,13 @@ msgstr "Continuar" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si olvidaste la dirección de correo que usaste para registrarte, envía un mensaje a la %slista de correo general del AUR%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Introduce tu dirección de correo:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -658,19 +662,19 @@ msgstr "Enviar solicitud" msgid "Close Request" msgstr "Cerrar solicitud" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" @@ -771,10 +775,18 @@ msgstr "Comenzar y acabar con una letra o número" msgid "Can contain only one period, underscore or hyphen." msgstr "Solamente puede contener un punto, guion bajo o guion." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "La página de inicio no es válida. Especifica la dirección HTTP(S) completa." @@ -814,6 +826,18 @@ msgstr "La dirección, %s%s%s, ya está en uso." msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1223,6 +1247,10 @@ msgstr "Ver los paquetes de este usuario" msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1233,6 +1261,11 @@ msgstr "Haz clic %saquí%s si deseas eliminar permanentemente esta cuenta." msgid "Click %shere%s for user details." msgstr "Haz clic %saquí%s para ver los detalles del usuario." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "obligatorio" @@ -1270,8 +1303,34 @@ msgid "Hide Email Address" msgstr "Ocultar dirreción de correo" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Reescribe la contraseña" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1281,6 +1340,16 @@ msgstr "Idioma" msgid "Timezone" msgstr "Huso horario" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Reescribe la contraseña" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1307,6 +1376,24 @@ msgstr "Notificar de actualizaciones de un paquete" msgid "Notify of ownership changes" msgstr "Notificar de cambios de propietario" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1435,7 +1522,7 @@ msgstr "Votar por este paquete" msgid "Disable notifications" msgstr "Deshabilitar notificaciones" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Habilitar notificaciones" @@ -1466,6 +1553,10 @@ msgstr "Dirección URL de clonado con Git" msgid "read-only" msgstr "Solamente lectura" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1512,9 +1603,16 @@ msgstr "Editar comentario para: %s" msgid "Add Comment" msgstr "Añadir un comentario" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Ver todos los comentarios" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1524,6 +1622,10 @@ msgstr "Comentarios fijados" msgid "Latest Comments" msgstr "Últimos comentarios" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1534,6 +1636,11 @@ msgstr "%s comentó en %s" msgid "Anonymous comment on %s" msgstr "Comentario anónimo en %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1570,10 +1677,6 @@ msgstr "Comentario fijado" msgid "Unpin comment" msgstr "Comentario desfijado" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Todos los comentarios" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" @@ -2120,6 +2223,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/es_419.po b/po/es_419.po index 0c0e4602..444eccb7 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Angel Velasquez , 2011 @@ -17,9 +17,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2019-07-16 01:55+0000\n" -"Last-Translator: prflr88 \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Spanish (Latin America) (http://www.transifex.com/lfleischer/aurweb/language/es_419/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -82,6 +82,10 @@ msgstr "No se pudo obtener la información del usuario especificado." msgid "You do not have permission to edit this account." msgstr "No tiene permisos para editar esta cuenta." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Use este formulario para buscar cuentas existentes." @@ -376,10 +380,10 @@ msgid "Enter login credentials" msgstr "Introduce las credenciales de autentificación" #: html/login.php -msgid "User name or email address" -msgstr "Nombre de usuario y dirección de correo" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Contraseña" @@ -440,8 +444,8 @@ msgid "Your password has been reset successfully." msgstr "Su contraseña fue reiniciada con éxito." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Confirme su dirección de correo:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -458,13 +462,13 @@ msgstr "Continuar" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si olvidó la dirección de correo que usó para registrarse, envíe un mensaje a la %slista de correo aur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Introduzca su dirección de correo:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -656,19 +660,19 @@ msgstr "Enviar petición" msgid "Close Request" msgstr "Cerrar Petición" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primero" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Siguiente" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Último" @@ -769,10 +773,18 @@ msgstr "Comenzar y acabar con una letra o número" msgid "Can contain only one period, underscore or hyphen." msgstr "Solo puede contener un punto, guion bajo o guion." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "La dirección de correo no es válida." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "La página de inicio no es válida. Especifique la URL en HTTP(S) completa." @@ -812,6 +824,18 @@ msgstr "La dirección, %s%s%s, ya está en uso." msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clave pública SSH %s%s%s ya está en uso." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1221,6 +1245,10 @@ msgstr "Ver los paquetes de este usuario" msgid "Edit this user's account" msgstr "Editar la cuenta de este usuario" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1231,6 +1259,11 @@ msgstr "Haga clic %saquí%s si desea borrar permanentemente esa cuenta." msgid "Click %shere%s for user details." msgstr "Haga clic %saquí%s para ver los detalles del usuario." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "obligatorio" @@ -1268,8 +1301,34 @@ msgid "Hide Email Address" msgstr "Ocultar dirreción de correo" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Reescriba la contraseña" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1279,6 +1338,16 @@ msgstr "Idioma" msgid "Timezone" msgstr "Zona horaria" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Reescriba la contraseña" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1305,6 +1374,24 @@ msgstr "Notificar sobre actualizaciones de un paquete" msgid "Notify of ownership changes" msgstr "Notificarme de cambios de propietario" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1433,7 +1520,7 @@ msgstr "Votar por este paquete" msgid "Disable notifications" msgstr "Deshabilitar notificaciones" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Habilitar notificaciones" @@ -1464,6 +1551,10 @@ msgstr "URL de clonado con Git" msgid "read-only" msgstr "Solo lectura" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1510,9 +1601,16 @@ msgstr "Editar commentario para: %s" msgid "Add Comment" msgstr "Agregar un comentario" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Ver todos los comentarios" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1522,6 +1620,10 @@ msgstr "Comentarios anclados" msgid "Latest Comments" msgstr "Últimos comentarios" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1532,6 +1634,11 @@ msgstr "%s comentó en %s" msgid "Anonymous comment on %s" msgstr "Comentario anónimo en %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1568,10 +1675,6 @@ msgstr "Comentario anclado" msgid "Unpin comment" msgstr "Comentario desanclado" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Todos los comentarios" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalles del paquete" @@ -2118,6 +2221,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/fi.po b/po/fi.po index 166b3104..d2daad80 100644 --- a/po/fi.po +++ b/po/fi.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Elias Autio, 2016 @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2019-02-18 20:40+0000\n" -"Last-Translator: Nikolay Korotkiy \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Finnish (http://www.transifex.com/lfleischer/aurweb/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -76,6 +76,10 @@ msgstr "Valitun käyttäjän tietoja ei voitu noutaa." msgid "You do not have permission to edit this account." msgstr "Sinulla ei ole oikeuksia tämän käyttäjätlin muokkaamiseen." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Etsi käyttäjätilejä." @@ -370,10 +374,10 @@ msgid "Enter login credentials" msgstr "Kirjautumistiedot" #: html/login.php -msgid "User name or email address" -msgstr "Käyttäjänimi tai sähköpostiosoite" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Salasana" @@ -434,8 +438,8 @@ msgid "Your password has been reset successfully." msgstr "Salasanasi on palautettu onnistuneesti." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Vahvista sähköpostiositteesi:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -452,13 +456,13 @@ msgstr "Jatka" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Jos olet unohtanut rekisteröityessäsi käyttämäsi sähköpostiosoitteen lähetä viesti %saur-general%s postituslistalle." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Sähköpostiosoitteesi:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -650,19 +654,19 @@ msgstr "Lähetä pyyntö" msgid "Close Request" msgstr "Sulje pyyntö" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Ensimmäinen" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Edellinen" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seuraava" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Viimeinen" @@ -763,10 +767,18 @@ msgstr "Alkaa ja loppua kirjaimeen tai numeroon" msgid "Can contain only one period, underscore or hyphen." msgstr "Voi sisältää vain yhden väliviivan, alaviivan tai pisteen." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Sähköpostiosoite ei ole kelvollinen." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Kotisivun osoite on virheellinen, määrittele koko http(s) URL." @@ -806,6 +818,18 @@ msgstr "Osoite %s%s%s on jo käytössä." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Julkinen SSH-avain %s%s%s on jo käytössä." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1215,6 +1239,10 @@ msgstr "Näytä käyttäjän paketit" msgid "Edit this user's account" msgstr "" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1225,6 +1253,11 @@ msgstr "Klikkaa %stästä%s, jos haluat peruuttamattomasti poistaa tämän tilin msgid "Click %shere%s for user details." msgstr "Klikkaa %stästä%s saadaksesi käyttäjän tiedot." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "vaaditaan" @@ -1262,8 +1295,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Salasana uudelleen:" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1273,6 +1332,16 @@ msgstr "Kieli" msgid "Timezone" msgstr "Aikavyöhyke" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Salasana uudelleen:" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1299,6 +1368,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1348,7 +1435,7 @@ msgstr "" #: template/comaintainers_form.php msgid "Users" -msgstr "" +msgstr "Käyttäjät" #: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" @@ -1427,7 +1514,7 @@ msgstr "Äänestä pakettia" msgid "Disable notifications" msgstr "En halua enää ilmoituksia" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1458,6 +1545,10 @@ msgstr "Git-kloonausosoite" msgid "read-only" msgstr "vain luku" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1504,9 +1595,16 @@ msgstr "" msgid "Add Comment" msgstr "Lisää kommentti" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Näytä kaikki kommentit" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1516,6 +1614,10 @@ msgstr "" msgid "Latest Comments" msgstr "Uusimmat kommentit" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1526,6 +1628,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1562,10 +1669,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Kaikki kommentit" - #: template/pkg_details.php msgid "Package Details" msgstr "Paketin tiedot" @@ -1715,7 +1818,7 @@ msgstr "" #: template/pkgreq_results.php msgid "Date" -msgstr "" +msgstr "Päivämäärä" #: template/pkgreq_results.php #, php-format @@ -1753,7 +1856,7 @@ msgstr "" #: template/pkgreq_results.php msgid "Closed" -msgstr "" +msgstr "Suljettu" #: template/pkg_search_form.php msgid "Name, Description" @@ -1765,7 +1868,7 @@ msgstr "Pelkkä nimi" #: template/pkg_search_form.php msgid "Exact Name" -msgstr "" +msgstr "Nimi täsmälleen" #: template/pkg_search_form.php msgid "Exact Package Base" @@ -1974,7 +2077,7 @@ msgstr "Loppu" #: template/tu_details.php msgid "Result" -msgstr "" +msgstr "Tulos" #: template/tu_details.php template/tu_list.php msgid "No" @@ -2112,8 +2215,9 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "{user} [1] yhdisti paketin {old} [2] pakettiin {new} [3].\n\nJos et enää halua saada ilmoituksia uudesta paketista, mene osoitteeseen [3] ja klikkaa \"{label}\"." +msgstr "" #: scripts/notify.py #, python-brace-format diff --git a/po/fr.po b/po/fr.po index 8b650e25..e73a8c99 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Alexandre Macabies , 2018 @@ -16,9 +16,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2019-02-11 18:21+0000\n" -"Last-Translator: Xorg\n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: French (http://www.transifex.com/lfleischer/aurweb/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -81,6 +81,10 @@ msgstr "Impossible de trouver l’information pour l’utilisateur spécifié." msgid "You do not have permission to edit this account." msgstr "Vous n’avez pas la permission d’éditer ce compte." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilisez ce formulaire pour rechercher des comptes existants." @@ -375,10 +379,10 @@ msgid "Enter login credentials" msgstr "Entrez vos identifiants" #: html/login.php -msgid "User name or email address" -msgstr "Nom d'utilisateur ou adresse e-mail :" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Mot de passe" @@ -439,8 +443,8 @@ msgid "Your password has been reset successfully." msgstr "Votre mot de passe a été réinitialisé avec succès." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Confirmez votre adresse e-mail :" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -457,13 +461,13 @@ msgstr "Continuer" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Si vous avez oublié avec quelle adresse e-mail vous vous êtes inscrit, veuillez envoyer un message sur la mailing-list %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Entrez votre adresse e-mail :" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -655,19 +659,19 @@ msgstr "Soumettre une demande" msgid "Close Request" msgstr "Fermer la requête" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Première" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Précédente" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Suivant" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Dernière" @@ -768,10 +772,18 @@ msgstr "doit débuter et se terminer par une lettre ou un chiffre." msgid "Can contain only one period, underscore or hyphen." msgstr "ne peut contenir qu'un seul point, tiret bas ou virgule," +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'adresse email n'est pas valide." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "La page d'accueil est invalide, spécifiez l'URL HTTP(s) complet." @@ -811,6 +823,18 @@ msgstr "L’adresse %s%s%s est déjà utilisée." msgid "The SSH public key, %s%s%s, is already in use." msgstr "La clé SSH publique, %s%s%s, est déjà utilisée." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1220,6 +1244,10 @@ msgstr "Visualiser les paquets de cet utilisateur." msgid "Edit this user's account" msgstr "Éditer le compte de cet utilisateur." +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1230,6 +1258,11 @@ msgstr "Cliquez %sici%s si vous voulez effacer ce compte de façon définitive." msgid "Click %shere%s for user details." msgstr "Cliquez %sici%s pour obtenir les détails de l'utilisateur." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "requis" @@ -1267,8 +1300,34 @@ msgid "Hide Email Address" msgstr "Cacher l'adresse e-mail" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Retapez le mot de passe" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1278,6 +1337,16 @@ msgstr "Langue" msgid "Timezone" msgstr "Fuseau horaire" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Retapez le mot de passe" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1304,6 +1373,24 @@ msgstr "Notifications de mises à jour de paquets" msgid "Notify of ownership changes" msgstr "Notifier des changements de propriétaire" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1432,7 +1519,7 @@ msgstr "Voter pour ce paquet" msgid "Disable notifications" msgstr "Désactiver les notifications" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Activer les notifications" @@ -1463,6 +1550,10 @@ msgstr "URL de clone (Git)" msgid "read-only" msgstr "lecture seule" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1509,9 +1600,16 @@ msgstr "Commentaire édité le : %s" msgid "Add Comment" msgstr "Ajouter un commentaire" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Voir tous les commentaires" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1521,6 +1619,10 @@ msgstr "Commentaires épinglés" msgid "Latest Comments" msgstr "Derniers commentaires" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1531,6 +1633,11 @@ msgstr "%s a commenté le %s" msgid "Anonymous comment on %s" msgstr "Commentaire anonyme le %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1567,10 +1674,6 @@ msgstr "Épingler le commentaire" msgid "Unpin comment" msgstr "Désépingler le commentaire" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Tous les commentaires" - #: template/pkg_details.php msgid "Package Details" msgstr "Détails du paquet" @@ -2117,8 +2220,9 @@ msgstr "Paquet AUR supprimé : {pkgbase}" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "{user} [1] a fusionné {old} [2] dans {new} [3].\n\nSi vous ne souhaitez plus recevoir de notifications à propos du nouveau paquet, rendez-vous sur la page du paquet [3] et sélectionnez \"{label}\". " +msgstr "" #: scripts/notify.py #, python-brace-format diff --git a/po/he.po b/po/he.po index 16d1196d..21ca1c8b 100644 --- a/po/he.po +++ b/po/he.po @@ -1,18 +1,18 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # GenghisKhan , 2016 # Lukas Fleischer , 2011 -# Yaron Shahrabani , 2016-2018 +# Yaron Shahrabani , 2016-2020 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-02-01 14:37+0000\n" +"Last-Translator: Yaron Shahrabani \n" "Language-Team: Hebrew (http://www.transifex.com/lfleischer/aurweb/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -75,6 +75,10 @@ msgstr "לא ניתן לקבל נתונים עבור המשתמש שנבחר." msgid "You do not have permission to edit this account." msgstr "אין לך הרשאה לערוך חשבון זה." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "הססמה שגויה." + #: html/account.php msgid "Use this form to search existing accounts." msgstr "נא להשתמש בטופס על מנת לחפש אחר חשבונות קיימים." @@ -341,11 +345,11 @@ msgstr "ביטול הצבעה" #: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" -msgstr "התרעה" +msgstr "התראה" #: html/index.php template/pkg_search_results.php msgid "UnNotify" -msgstr "ביטול התרעה" +msgstr "ביטול התראה" #: html/index.php msgid "UnFlag" @@ -362,17 +366,17 @@ msgstr "נכנסת בשם: %s" #: html/login.php template/header.php msgid "Logout" -msgstr "ניתוק" +msgstr "יציאה" #: html/login.php msgid "Enter login credentials" msgstr "נא להזין פרטי גישה" #: html/login.php -msgid "User name or email address" -msgstr "שם משתמש או כתובת דוא״ל" +msgid "User name or primary email address" +msgstr "שם משתמש או כתובת דוא״ל עיקרית" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "ססמה" @@ -433,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "הססמה שלך התאפסה בהצלחה." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "אישור כתובת הדוא״ל שלך" +msgid "Confirm your user name or primary e-mail address:" +msgstr "אימות של שם המשתמש או כתובת הדוא״ל העיקרית:" #: html/passreset.php msgid "Enter your new password:" @@ -451,13 +455,13 @@ msgstr "המשך" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "אם שכחת את כתובת הדוא״ל בה השתמש כדי להירשם, נא לשלוח הודעה לקבוצת הדיוור %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "אם שכחת את שם המשתמש ואת כתובת הדוא״ל העיקרית בה השתמשת כדי להירשם, נא לשלוח הודעה לקבוצת הדיוור %saur-general%s." #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "נא להזין את כתובת הדוא״ל שלך:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "נא להקליד את שם המשתמש או את כתובת הדוא״ל העיקרית שלך:" #: html/pkgbase.php msgid "Package Bases" @@ -533,7 +537,7 @@ msgstr "ניתן להשתמש בטופס זה כדי לשלול את הבעלו msgid "" "By selecting the checkbox, you confirm that you want to no longer be a " "package co-maintainer." -msgstr "" +msgstr "סימון התיבה הזאת מהווה את אישורך להסיר את שותפותך בתחזוקת חבילה זו." #: html/pkgdisown.php #, php-format @@ -565,14 +569,14 @@ msgstr "סימון התגובה" #: html/pkgflag.php msgid "Flag Package Out-Of-Date" -msgstr "סימון תגובה כבלתי עדכנית" +msgstr "סימון תגובה כלא עדכנית" #: html/pkgflag.php #, php-format msgid "" "Use this form to flag the package base %s%s%s and the following packages " "out-of-date: " -msgstr "יש להשתמש בטופס זה כדי לסמן את בסיס החבילה %s%s%s ואת החבילות הבאות לבלתי עדכניות:" +msgstr "יש להשתמש בטופס זה כדי לסמן את בסיס החבילה %s%s%s ואת החבילות הבאות כלא עדכניות:" #: html/pkgflag.php #, php-format @@ -585,7 +589,7 @@ msgstr "נא %sלא%s להשתמש בטופס הזה כדי לדווח על תק msgid "" "Enter details on why the package is out-of-date below, preferably including " "links to the release announcement or the new release tarball." -msgstr "נא להזין את הפרטים על מדוע החבילה אינה בתוקף, מומלץ להוסיף קישורים להכרזות המתאימות או לקובצי הגרסה העדכנית." +msgstr "נא להזין את הפרטים על מדוע החבילה לא עדכנית, מומלץ להוסיף קישורים להכרזות המתאימות או לקובצי הגרסה העדכנית." #: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php #: template/pkgreq_results.php @@ -598,7 +602,7 @@ msgstr "סימון" #: html/pkgflag.php msgid "Only registered users can flag packages out-of-date." -msgstr "רק משתמשים רשומים יכולים לסמן חבילות כפגות תוקף." +msgstr "רק משתמשים רשומים יכולים לסמן חבילות כלא עדכניות." #: html/pkgmerge.php msgid "Package Merging" @@ -649,19 +653,19 @@ msgstr "שליחת בקשה" msgid "Close Request" msgstr "סגירת בקשה" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "ראשון" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "הקודם" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "הבא" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "אחרון" @@ -762,10 +766,18 @@ msgstr "יש להתחיל ולסיים עם תו או מספר" msgid "Can contain only one period, underscore or hyphen." msgstr "יכול הכיל רק נקודה אחת, קו תחתון או מקף." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "נא לאשר את הססמה החדשה שלך." + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "כתובת הדוא״ל שהוזנה אינה תקינה." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "כתובת הדוא״ל לגיבוי שגויה." + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "דף הבית שגוי, נא לציין את כתובת ה־HTTP(s) המלאה." @@ -805,6 +817,18 @@ msgstr "הכתובת, %s%s%s, כבר נמצאת בשימוש." msgid "The SSH public key, %s%s%s, is already in use." msgstr "מפתח ה־SSH הציבורי, %s%s%s, כבר נמצא בשימוש." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "הקאפצ׳ה חסרה." + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "תוקף הקאפצ׳ה פג. נא לנסות שוב." + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "התשובה שמילאת בקאפצ׳ה שגויה." + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1014,17 +1038,17 @@ msgstr "ההצבעות שלך נקלטו עבור החבילות המסומנו #: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." -msgstr "לא ניתן לצרף את רשימת ההתרעות." +msgstr "לא ניתן לצרף את רשימת ההתראות." #: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been added to the comment notification list for %s." -msgstr "צורפת אל רשימת ההתרעות עבור %s." +msgstr "צורפת אל רשימת ההתראות עבור %s." #: lib/pkgbasefuncs.inc.php #, php-format msgid "You have been removed from the comment notification list for %s." -msgstr "הוסרת מרשימה ההתרעות עבור ההערות של %s." +msgstr "הוסרת מרשימת ההתראות להערות של %s." #: lib/pkgbasefuncs.inc.php msgid "You are not allowed to undelete this comment." @@ -1214,6 +1238,10 @@ msgstr "צפייה בחבילות המשתמש" msgid "Edit this user's account" msgstr "עריכת החשבון של משתמש זה" +#: template/account_details.php +msgid "List this user's comments" +msgstr "הצגת תגובות המשתמש הזה" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1224,6 +1252,11 @@ msgstr "נא ללחוץ %sכאן%s אם רצונך הוא למחוק את החש msgid "Click %shere%s for user details." msgstr "יש ללחוץ %sכאן%s לפרטים על המשתמש." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "נא ללחוץ %sכאן%s כדי להציג את התגובות שהוגשו דרך החשבון הזה." + #: template/account_edit_form.php msgid "required" msgstr "נדרש" @@ -1261,8 +1294,34 @@ msgid "Hide Email Address" msgstr "הסתרת כתובת דוא״ל" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "הקלדת הססמה מחדש" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "אם בחירתך תהיה שלא להסתיר את כתובת הדוא״ל שלך, היא תהיה גלויה לכלל המשתמשים ב־AUR. בחירה הפוכה תגרום לכך שהכתובת תהיה גלויה בפני חברי הסגל של Arch לינוקס בלבד." + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "כתובת דוא״ל לגיבוי" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "באפשרותך לציין כתובת דוא״ל משנית בה ניתן להשתמש לשחזור החשבון שלך אם אבדה גישתך לכתובת הדוא״ל העיקרית שלך." + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "קישורים לאיפוס ססמה תמיד נשלחים לכתובת הדוא״ל העיקרית שלך ואל כתובת הדוא״ל שלך כגיבוי." + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "כתובת הדוא״ל שלך כגיבוי תמיד זמינה אך ורק לחברי הסגל של Arch לינוקס ללא תלות בהגדרה %s." #: template/account_edit_form.php msgid "Language" @@ -1272,6 +1331,16 @@ msgstr "שפה" msgid "Timezone" msgstr "אזור זמן" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "אם ברצונך לשנות את הססמה, נא להקליד ססמה חדשה ולאשר את הססמה על ידי הקלדתה פעם נוספת." + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "הקלדת הססמה מחדש" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1284,7 +1353,7 @@ msgstr "מפתח SSH ציבורי" #: template/account_edit_form.php msgid "Notification settings" -msgstr "הגדרות התרעה" +msgstr "הגדרות התראה" #: template/account_edit_form.php msgid "Notify of new comments" @@ -1298,6 +1367,24 @@ msgstr "להודיע לי ל עדכונים בחבילה" msgid "Notify of ownership changes" msgstr "להודיע לי על שינויים בבעלות" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "כדי לאשר את השינויים בפרופיל נא להקליד את הססמה הנוכחית שלך:" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "הססמה הנוכחית שלך" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "כדי להגן על AUR מפני יצירה אוטומטית של חשבונות, אנו מבקשים ממך לציין מה הפלט של הפקודה הבאה:" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "תשובה" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1361,12 +1448,12 @@ msgstr "הערת סימון כלא עדכנית: %s" #: template/flag_comment.php #, php-format msgid "%s%s%s flagged %s%s%s out-of-date on %s%s%s for the following reason:" -msgstr "%s%s%s סומנה בדגל %s%s%s כבלתי עדכנית %s%s%s מהסיבה הבאה:" +msgstr "%s%s%s סומנה בדגל %s%s%s כלא עדכנית %s%s%s מהסיבה הבאה:" #: template/flag_comment.php #, php-format msgid "%s%s%s is not flagged out-of-date." -msgstr "%s%s%s אינה מסומנת כפגת תוקף." +msgstr "%s%s%s אינה מסומנת כלא עדכנית." #: template/flag_comment.php msgid "Return to Details" @@ -1408,7 +1495,7 @@ msgstr "סימון כלא עדכנית (%s)" #: template/pkgbase_actions.php msgid "Flag package out-of-date" -msgstr "סימון החבילה כבלתי עדכנית" +msgstr "סימון החבילה כלא עדכנית" #: template/pkgbase_actions.php msgid "Unflag package" @@ -1424,11 +1511,11 @@ msgstr "להצביע לחבילה זו" #: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" -msgstr "נטרול התרעות" +msgstr "השבתת התראות" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" -msgstr "הפעלת התרעות" +msgstr "הפעלת התראות" #: template/pkgbase_actions.php msgid "Manage Co-Maintainers" @@ -1459,6 +1546,10 @@ msgstr "כתובת השכפול מ־Git" msgid "read-only" msgstr "לקריאה בלבד" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "ללחוץ להעתקה" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1490,7 +1581,7 @@ msgstr "פופולריות" #: template/pkgbase_details.php template/pkg_details.php msgid "First Submitted" -msgstr "נשלחה לראשונה" +msgstr "הוגשה לראשונה" #: template/pkgbase_details.php template/pkg_details.php msgid "Last Updated" @@ -1505,9 +1596,16 @@ msgstr "עריכת תגובה עבור: %s" msgid "Add Comment" msgstr "הוספת תגובה" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "הצגת כל התגובות" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "מזהי הגשות של Git שמפנים להגשות במאגר החבילות של AUR וכתובות מומרים אוטומטית לקישורים." + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "יש תמיכה חלקית ב%sתחביר Markdown%s" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1517,6 +1615,10 @@ msgstr "תגובות נעוצות" msgid "Latest Comments" msgstr "התגובות האחרונות" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "תגובות על" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1527,6 +1629,11 @@ msgstr "נכתבה תגובה ע״י %s ב־%s" msgid "Anonymous comment on %s" msgstr "תגובה אלמונית ב־%s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "הוגשה תגובה על החבילה %s ב־%s" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1563,10 +1670,6 @@ msgstr "הצמדת התגובה" msgid "Unpin comment" msgstr "ביטול הצמדת התגובה" -#: template/pkg_comments.php -msgid "All comments" -msgstr "כל התגובות" - #: template/pkg_details.php msgid "Package Details" msgstr "נתוני חבילה" @@ -1733,10 +1836,10 @@ msgstr[3] "נותרו ~%d ימים" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "נותרה שעה ~%d" -msgstr[1] "~%d שעות נותרו" -msgstr[2] "~%d שעות נותרו" -msgstr[3] "~%d שעות נותרו" +msgstr[0] "נותרה בערך שעה (%d)" +msgstr[1] "בערך שעתיים (%d) נותרו" +msgstr[2] "בערך %d שעות נותרו" +msgstr[3] "בערך %d שעות נותרו" #: template/pkgreq_results.php msgid "<1 hour left" @@ -1894,7 +1997,7 @@ msgstr "פעולות" #: template/pkg_search_results.php msgid "Unflag Out-of-date" -msgstr "ביטול סימון כלא מעודכן" +msgstr "ביטול סימון כלא עדכנית" #: template/pkg_search_results.php msgid "Adopt Packages" @@ -1922,7 +2025,7 @@ msgstr "חיפוש" #: template/stats/general_stats_table.php msgid "Statistics" -msgstr "סטטיסטיקות" +msgstr "סטטיסטיקה" #: template/stats/general_stats_table.php msgid "Orphan Packages" @@ -1970,12 +2073,12 @@ msgstr "פרטי הצעה" #: template/tu_details.php msgid "This vote is still running." -msgstr "ההצבעה עדיין קיימת." +msgstr "ההצבעה עדיין מתרחשת." #: template/tu_details.php #, php-format msgid "Submitted: %s by %s" -msgstr "נשלח: %s על ידי %s" +msgstr "הוגש: %s על ידי %s" #: template/tu_details.php template/tu_list.php msgid "End" @@ -2023,7 +2126,7 @@ msgstr "חזרה" #: scripts/notify.py msgid "AUR Password Reset" -msgstr "" +msgstr "איפוס ססמה ב־AUR" #: scripts/notify.py #, python-brace-format @@ -2031,98 +2134,99 @@ msgid "" "A password reset request was submitted for the account {user} associated " "with your email address. If you wish to reset your password follow the link " "[1] below, otherwise ignore this message and nothing will happen." -msgstr "" +msgstr "הוגשה בקשה לאיפוס ססמה לחשבון {user} שמקושר לכתובת הדוא״ל שלך. אם ברצונך לאפס את הססמה שלך עליך להיכנס לקישור [1] שלהלן, אם לא ביקשת מוטב להתעלם מההודעה הזאת ולא יתבצע אף שינוי." #: scripts/notify.py msgid "Welcome to the Arch User Repository" -msgstr "" +msgstr "ברוך בואך למאגר בתחזוקת המשתמשים של Arch" #: scripts/notify.py msgid "" "Welcome to the Arch User Repository! In order to set an initial password for" " your new account, please click the link [1] below. If the link does not " "work, try copying and pasting it into your browser." -msgstr "" +msgstr "ברוך הבא למאגר חבילות המשתמשים של Arch! כדי להגדיר ססמה ראשונית לחשבון החדש שלך נא ללחוץ על הקישור [1] שלהלן. אם הקישור לא עובד, נא לנסות להעתיק ולהדביק אותו בדפדפן." #: scripts/notify.py #, python-brace-format msgid "AUR Comment for {pkgbase}" -msgstr "" +msgstr "הערה ב־AUR על {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "{user} [1] added the following comment to {pkgbase} [2]:" -msgstr "" +msgstr "התגובה הבאה נוספה על ידי {user} [1] לחבילה {pkgbase} [2]:" #: scripts/notify.py #, python-brace-format msgid "" "If you no longer wish to receive notifications about this package, please go" " to the package page [2] and select \"{label}\"." -msgstr "" +msgstr "אם לא מעניין אותך לקבל יותר הודעות על החבילה הזאת נא לגשת לעמוד החבילה [2] ולבחור ב„{label}”." #: scripts/notify.py #, python-brace-format msgid "AUR Package Update: {pkgbase}" -msgstr "" +msgstr "עדכון בחבילת AUR:‏ {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "{user} [1] pushed a new commit to {pkgbase} [2]." -msgstr "" +msgstr "נדחפה הגשה חדשה מאת {user} [1] אל {pkgbase} [2]." #: scripts/notify.py #, python-brace-format msgid "AUR Out-of-date Notification for {pkgbase}" -msgstr "" +msgstr "התראת חבילה לא עדכנית ב־AUR עבור {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" -msgstr "" +msgstr "החבילה שלך {pkgbase} [1] סומנה כלא עדכנית על ידי {user} [2]:" #: scripts/notify.py #, python-brace-format msgid "AUR Ownership Notification for {pkgbase}" -msgstr "" +msgstr "הודעת בעלות ב־AUR על {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was adopted by {user} [2]." -msgstr "" +msgstr "החבילה {pkgbase} [1] אומצה על ידי {user} [2]." #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was disowned by {user} [2]." -msgstr "" +msgstr "החבילה {pkgbase} [1] נושלה על ידי {user} [2]." #: scripts/notify.py #, python-brace-format msgid "AUR Co-Maintainer Notification for {pkgbase}" -msgstr "" +msgstr "התראה למתחזקי משנה ב־AUR של {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "You were added to the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "נוספת לרשימת מתחזקי המשנה של {pkgbase} [1]." #: scripts/notify.py #, python-brace-format msgid "You were removed from the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "הוסרת מרשימת מתחזקי המשנה עבור {pkgbase} [1]." #: scripts/notify.py #, python-brace-format msgid "AUR Package deleted: {pkgbase}" -msgstr "" +msgstr "חבילה נמחקה ב־AUR‏: {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "" +msgstr "{old} [2] מוזג לתוך {new} [3] על ידי {user} [1].\n\n-- \nכדי לא לקבל עוד הודעות על החבילה החדשה, עליך לגשת אל [3] וללחוץ על „{label}”." #: scripts/notify.py #, python-brace-format @@ -2130,16 +2234,16 @@ msgid "" "{user} [1] deleted {pkgbase} [2].\n" "\n" "You will no longer receive notifications about this package." -msgstr "" +msgstr " {pkgbase} [2] נמחקה על ידי{user} [1].\n\nלא תישלחנה אליך התראות נוספות על חבילה זו." #: scripts/notify.py #, python-brace-format msgid "TU Vote Reminder: Proposal {id}" -msgstr "" +msgstr "תזכורת הצבעה למשתמש מהימן: הצעה {id}" #: scripts/notify.py #, python-brace-format msgid "" "Please remember to cast your vote on proposal {id} [1]. The voting period " "ends in less than 48 hours." -msgstr "" +msgstr "נא לזכור להצביע בהצעה {id} [1]. ההצבעה תסתיים בעוד פחות מ־48 שעות." diff --git a/po/hr.po b/po/hr.po index 56a101d6..0a522fb8 100644 --- a/po/hr.po +++ b/po/hr.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Lukas Fleischer , 2011 @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Croatian (http://www.transifex.com/lfleischer/aurweb/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -73,6 +73,10 @@ msgstr "Nije moguće naći informacije o zadanom korisniku." msgid "You do not have permission to edit this account." msgstr "Nemate ovlasti da bi mjenjali ovaj račun." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Koristite ovaj formular za pretraživanj postoječih računa." @@ -367,10 +371,10 @@ msgid "Enter login credentials" msgstr "" #: html/login.php -msgid "User name or email address" +msgid "User name or primary email address" msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" @@ -431,7 +435,7 @@ msgid "Your password has been reset successfully." msgstr "" #: html/passreset.php -msgid "Confirm your e-mail address:" +msgid "Confirm your user name or primary e-mail address:" msgstr "" #: html/passreset.php @@ -449,12 +453,12 @@ msgstr "" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" +msgid "Enter your user name or your primary e-mail address:" msgstr "" #: html/pkgbase.php @@ -647,19 +651,19 @@ msgstr "" msgid "Close Request" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sljedeći" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "" @@ -760,10 +764,18 @@ msgstr "Zapični i završi sa slovom ili brojkom" msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržavati samo jednu točku, donju crticu ili povlaku." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Email adresa je neispravna." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -803,6 +815,18 @@ msgstr "" msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1212,6 +1236,10 @@ msgstr "Pregledaj pakete ovog korisnika" msgid "Edit this user's account" msgstr "" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1222,6 +1250,11 @@ msgstr "" msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "obvezno" @@ -1259,8 +1292,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Ponovno upišite lozinku" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1270,6 +1329,16 @@ msgstr "Jezik" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Ponovno upišite lozinku" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1296,6 +1365,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1424,7 +1511,7 @@ msgstr "" msgid "Disable notifications" msgstr "" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1456,6 +1543,10 @@ msgstr "" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1502,8 +1593,15 @@ msgstr "" msgid "Add Comment" msgstr "" -#: template/pkg_comments.php -msgid "View all comments" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." msgstr "" #: template/pkg_comments.php @@ -1514,6 +1612,10 @@ msgstr "" msgid "Latest Comments" msgstr "" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1524,6 +1626,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1560,10 +1667,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalji o paketu" @@ -2114,6 +2217,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/hu.po b/po/hu.po index 8dd39982..1d4cf856 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Balló György , 2013 @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Hungarian (http://www.transifex.com/lfleischer/aurweb/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -76,6 +76,10 @@ msgstr "Nem sikerült letölteni a megadott felhasználó információit." msgid "You do not have permission to edit this account." msgstr "Nincs engedélyed ennek a fióknak a szerkesztéséhez." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Már meglévő felhasználói fiókok kereséséhez használd ezt az űrlapot." @@ -370,10 +374,10 @@ msgid "Enter login credentials" msgstr "Bejelentkezési adatok megadása" #: html/login.php -msgid "User name or email address" -msgstr "Felhasználónév vagy e-mail cím" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Jelszó" @@ -434,8 +438,8 @@ msgid "Your password has been reset successfully." msgstr "Jelszavad sikeresen visszaállításra került." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Erősíts meg az e-mail címedet:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -452,13 +456,13 @@ msgstr "Folytatás" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Ha elfelejtetted az e-mail címet, amit a regisztrációhoz használtál, akkor küldj egy üzenetet az %saur-general%s levelezőlistára." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Add meg az e-mail címedet:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -650,19 +654,19 @@ msgstr "Kérelem beküldése" msgid "Close Request" msgstr "Kérelem lezárása" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Első" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Előző" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Következő" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Utolsó" @@ -763,10 +767,18 @@ msgstr "Betűvel vagy számjeggyel kezdődjön és végződjön" msgid "Can contain only one period, underscore or hyphen." msgstr "Csak egyetlen pontot, aláhúzást vagy kötőjelet tartalmazhat." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Érvénytelen e-mail cím." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -806,6 +818,18 @@ msgstr "A(z) %s%s%s cím már használatban van." msgid "The SSH public key, %s%s%s, is already in use." msgstr "A(z) %s%s%s nyilvános SSH kulcs már használatban van." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1215,6 +1239,10 @@ msgstr "A felhasználó csomagjainak megtekintése" msgid "Edit this user's account" msgstr "Ezen felhasználó fiókjának szerkesztése" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1225,6 +1253,11 @@ msgstr "Kattints %side%s, ha véglegesen törölni szeretnéd ezt a fiókot." msgid "Click %shere%s for user details." msgstr "Kattints %side%s a felhasználó részleteihez." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "kötelező" @@ -1262,8 +1295,34 @@ msgid "Hide Email Address" msgstr "E-mail cím elrejtése" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Megismételt jelszó" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1273,6 +1332,16 @@ msgstr "Nyelv" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Megismételt jelszó" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1299,6 +1368,24 @@ msgstr "Értesítés csomagfrissítésekről." msgid "Notify of ownership changes" msgstr "Értesítés tulajdonváltozásokról" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1427,7 +1514,7 @@ msgstr "Szavazás erre a csomagra" msgid "Disable notifications" msgstr "Értesítések kikapcsolása" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Értesítések engedélyezése" @@ -1458,6 +1545,10 @@ msgstr "Git klónozási URL" msgid "read-only" msgstr "csak olvasható" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1504,9 +1595,16 @@ msgstr "Hozzászólás szerkesztése ehhez: %s" msgid "Add Comment" msgstr "Hosszászólás" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Összes megjegyzés megjelenítése" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1516,6 +1614,10 @@ msgstr "Rögzített hozzászólások" msgid "Latest Comments" msgstr "Legújabb hozzászólások" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1526,6 +1628,11 @@ msgstr "%s hozzászólt ekkor: %s" msgid "Anonymous comment on %s" msgstr "Névtelen hozzászólás ekkor: %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1562,10 +1669,6 @@ msgstr "Hozzászólás rögzítése" msgid "Unpin comment" msgstr "Hozzászólás feloldása" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Összes hozzászólás" - #: template/pkg_details.php msgid "Package Details" msgstr "Részletes csomaginformáció" @@ -2112,6 +2215,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/it.po b/po/it.po index 59da571b..5dfdd9fc 100644 --- a/po/it.po +++ b/po/it.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Giovanni Scafora , 2011-2015 @@ -11,9 +11,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2019-07-18 16:40+0000\n" -"Last-Translator: mattia_b89 \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Italian (http://www.transifex.com/lfleischer/aurweb/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -76,6 +76,10 @@ msgstr "Impossibile recuperare le informazioni dell'utente specificato." msgid "You do not have permission to edit this account." msgstr "Non hai i permessi necessari per modificare questo account." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Usa questo modulo per cercare gli account esistenti." @@ -370,10 +374,10 @@ msgid "Enter login credentials" msgstr "Inserisci le credenziali di accesso" #: html/login.php -msgid "User name or email address" -msgstr "Il nome utente o l'indirizzo email" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Password" @@ -434,8 +438,8 @@ msgid "Your password has been reset successfully." msgstr "La tua password è stata ripristinata con successo." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Conferma il tuo indirizzo e-mail:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -452,13 +456,13 @@ msgstr "Continua" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Se hai dimenticato l'indirizzo e-mail utilizzato per registrarti, invia un messaggio nella mailing list %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Inserisci il tuo indirizzo email:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -650,19 +654,19 @@ msgstr "Invia la richiesta" msgid "Close Request" msgstr "Chiudi la richiesta" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primo" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedente" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Successivo" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo" @@ -763,10 +767,18 @@ msgstr "Inizia e termina con una lettera o un numero" msgid "Can contain only one period, underscore or hyphen." msgstr "Può contenere solo un punto, un trattino basso o un trattino." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "L'indirizzo email non risulta valido." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "La homepage non è valida, per favore specificare l'URL HTTP(s) completo." @@ -806,6 +818,18 @@ msgstr "L'indirizzo %s%s%s è già in uso." msgid "The SSH public key, %s%s%s, is already in use." msgstr "La chiave pubblica SSH %s%s%s, è già in uso." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1215,6 +1239,10 @@ msgstr "Mostra i pacchetti di quest'utente" msgid "Edit this user's account" msgstr "Modifica l'account di quest'utente" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1225,6 +1253,11 @@ msgstr "Clicca %squi%s se vuoi eliminare definitivamente questo account." msgid "Click %shere%s for user details." msgstr "Click %squì%s per il dettagli dell'utente." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "obbligatorio" @@ -1262,8 +1295,34 @@ msgid "Hide Email Address" msgstr "Nascondi l'indirizzo email" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Riscrivi la password" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1273,6 +1332,16 @@ msgstr "Lingua" msgid "Timezone" msgstr "Fuso orario" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Riscrivi la password" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1299,6 +1368,24 @@ msgstr "Notifica degli aggiornamenti dei pacchetti" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1427,7 +1514,7 @@ msgstr "Vota per questo pacchetto" msgid "Disable notifications" msgstr "Disabilita le notifiche" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Abilita le notifiche" @@ -1458,6 +1545,10 @@ msgstr "Git Clone URL" msgid "read-only" msgstr "sola lettura" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1504,9 +1595,16 @@ msgstr "Modifica il commento di: %s" msgid "Add Comment" msgstr "Aggiungi un commento" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Mostra tutti i commenti" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1516,6 +1614,10 @@ msgstr "Elimina i commenti" msgid "Latest Comments" msgstr "Ultimi commenti" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1526,6 +1628,11 @@ msgstr "%s ha commentato su %s" msgid "Anonymous comment on %s" msgstr "Commento anonimo su %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1562,10 +1669,6 @@ msgstr "Inserisci il commento" msgid "Unpin comment" msgstr "Elimina il commento" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Tutti i commenti" - #: template/pkg_details.php msgid "Package Details" msgstr "Dettagli del pacchetto" @@ -2112,6 +2215,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/ja.po b/po/ja.po index 4c8034b9..337e7ee8 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,19 +1,19 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # kusakata, 2013 # kusakata, 2013 -# kusakata, 2013-2017 +# kusakata, 2013-2018 # 尾ノ上卓朗 , 2017 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aurweb/language/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -76,6 +76,10 @@ msgstr "指定のユーザーの情報が取得できませんでした。" msgid "You do not have permission to edit this account." msgstr "あなたはこのアカウントを編集する権利を持っていません。" +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "アカウントの検索はこのフォームを使って下さい。" @@ -370,10 +374,10 @@ msgid "Enter login credentials" msgstr "ログイン情報を入力してください" #: html/login.php -msgid "User name or email address" -msgstr "ユーザー名またはメールアドレス" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "パスワード" @@ -434,8 +438,8 @@ msgid "Your password has been reset successfully." msgstr "パスワードのリセットが成功しました。" #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "メールアドレスの確認:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -452,13 +456,13 @@ msgstr "続行" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "登録したメールアドレスを忘れてしまった場合は、%saur-general%s メーリングリストにメッセージを送って下さい。" +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "メールアドレスを入力:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -534,7 +538,7 @@ msgstr "このフォームを使って以下のパッケージを含むパッケ msgid "" "By selecting the checkbox, you confirm that you want to no longer be a " "package co-maintainer." -msgstr "" +msgstr "チェックボックスを選択して、パッケージの共同メンテナから降りることを確定してください。" #: html/pkgdisown.php #, php-format @@ -650,19 +654,19 @@ msgstr "リクエストを送信" msgid "Close Request" msgstr "リクエストをクローズ" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "最初" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "前へ" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "次へ" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後" @@ -763,10 +767,18 @@ msgstr "最初と最後の文字は英数字にしてください" msgid "Can contain only one period, underscore or hyphen." msgstr "ピリオド、アンダーライン、ハイフンはひとつだけ含めることができます。" +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "メールアドレスが不正です。" +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "ホームページが不正です。完全な HTTP(s) URL を入力してください。" @@ -806,6 +818,18 @@ msgstr "%s%s%s というメールアドレスは既に使われています。" msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開鍵、%s%s%s は既に使われています。" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1215,6 +1239,10 @@ msgstr "ユーザーのパッケージを見る" msgid "Edit this user's account" msgstr "このユーザーのアカウントを編集" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1225,6 +1253,11 @@ msgstr "このアカウントを恒久的に削除したい場合は%sこちら% msgid "Click %shere%s for user details." msgstr "ユーザーの詳細は%sこちら%sをクリック。" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "必須" @@ -1262,8 +1295,34 @@ msgid "Hide Email Address" msgstr "メールアドレスを非公開にする" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "パスワードの再入力" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1273,6 +1332,16 @@ msgstr "言語" msgid "Timezone" msgstr "タイムゾーン" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "パスワードの再入力" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1299,6 +1368,24 @@ msgstr "パッケージアップデートの通知" msgid "Notify of ownership changes" msgstr "所有者の変更の通知" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1427,7 +1514,7 @@ msgstr "このパッケージに投票する" msgid "Disable notifications" msgstr "通知を止める" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "通知を有効にする" @@ -1457,6 +1544,10 @@ msgstr "Git クローン URL" msgid "read-only" msgstr "リードオンリー" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1503,9 +1594,16 @@ msgstr "コメントを編集: %s" msgid "Add Comment" msgstr "コメントを投稿する" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "全てのコメントを表示" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1515,6 +1613,10 @@ msgstr "ピン留めされたコメント" msgid "Latest Comments" msgstr "最新のコメント" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1525,6 +1627,11 @@ msgstr "%s が %s にコメントを投稿しました" msgid "Anonymous comment on %s" msgstr "匿名ユーザーが %s にコメントを投稿しました" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1561,10 +1668,6 @@ msgstr "コメントをピン留めする" msgid "Unpin comment" msgstr "コメントのピン留めを解除" -#: template/pkg_comments.php -msgid "All comments" -msgstr "全てのコメント" - #: template/pkg_details.php msgid "Package Details" msgstr "パッケージの詳細" @@ -2009,7 +2112,7 @@ msgstr "前へ" #: scripts/notify.py msgid "AUR Password Reset" -msgstr "" +msgstr "AUR パスワードのリセット" #: scripts/notify.py #, python-brace-format @@ -2017,96 +2120,97 @@ msgid "" "A password reset request was submitted for the account {user} associated " "with your email address. If you wish to reset your password follow the link " "[1] below, otherwise ignore this message and nothing will happen." -msgstr "" +msgstr "あなたのメールアドレスと関連付けられたアカウント {user} のパスワードのリセットリクエストが送信されました。パスワードをリセットしたいときは下のリンク [1] を開いて下さい、そうでない場合はこのメッセージは無視して下さい。" #: scripts/notify.py msgid "Welcome to the Arch User Repository" -msgstr "" +msgstr "Arch User Repository にようこそ" #: scripts/notify.py msgid "" "Welcome to the Arch User Repository! In order to set an initial password for" " your new account, please click the link [1] below. If the link does not " "work, try copying and pasting it into your browser." -msgstr "" +msgstr "Arch User Repository にようこそ!アカウントのパスワードを設定するために、下のリンク [1] をクリックしてください。リンクを押せないときは、一旦ブラウザにURLをコピーしてください。" #: scripts/notify.py #, python-brace-format msgid "AUR Comment for {pkgbase}" -msgstr "" +msgstr "{pkgbase} の AUR コメント" #: scripts/notify.py #, python-brace-format msgid "{user} [1] added the following comment to {pkgbase} [2]:" -msgstr "" +msgstr "{user} [1] は以下のコメントを {pkgbase} [2] に追加しました:" #: scripts/notify.py #, python-brace-format msgid "" "If you no longer wish to receive notifications about this package, please go" " to the package page [2] and select \"{label}\"." -msgstr "" +msgstr "このパッケージの通知を受け取りたくない場合は、パッケージのページ [2] を開いて \"{label}\" を選択してください。" #: scripts/notify.py #, python-brace-format msgid "AUR Package Update: {pkgbase}" -msgstr "" +msgstr "AUR パッケージアップデート: {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "{user} [1] pushed a new commit to {pkgbase} [2]." -msgstr "" +msgstr "{user} [1] は {pkgbase} [2] に新しいコミットを投稿しました。" #: scripts/notify.py #, python-brace-format msgid "AUR Out-of-date Notification for {pkgbase}" -msgstr "" +msgstr "{pkgbase} の AUR Out-of-date 通知" #: scripts/notify.py #, python-brace-format msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" -msgstr "" +msgstr "あなたのパッケージ {pkgbase} [1] は {user} [2] によって out-of-date フラグが立てられました:" #: scripts/notify.py #, python-brace-format msgid "AUR Ownership Notification for {pkgbase}" -msgstr "" +msgstr "{pkgbase} の AUR 所有者通知" #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was adopted by {user} [2]." -msgstr "" +msgstr "パッケージ {pkgbase} [1] は {user} [2] によって継承されました。" #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was disowned by {user} [2]." -msgstr "" +msgstr "パッケージ {pkgbase} [1] は {user} [2] から放棄されました。" #: scripts/notify.py #, python-brace-format msgid "AUR Co-Maintainer Notification for {pkgbase}" -msgstr "" +msgstr "{pkgbase} の AUR 共同メンテナ通知" #: scripts/notify.py #, python-brace-format msgid "You were added to the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "あなたは {pkgbase} [1] の共同メンテナリストに追加されました。" #: scripts/notify.py #, python-brace-format msgid "You were removed from the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "あなたは {pkgbase} [1] の共同メンテナリストから削除されました。" #: scripts/notify.py #, python-brace-format msgid "AUR Package deleted: {pkgbase}" -msgstr "" +msgstr "AUR パッケージ削除: {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" @@ -2116,16 +2220,16 @@ msgid "" "{user} [1] deleted {pkgbase} [2].\n" "\n" "You will no longer receive notifications about this package." -msgstr "" +msgstr "{user} [1] は {pkgbase} [2] を削除しました。\n\nこのパッケージの通知が送信されることはありません。" #: scripts/notify.py #, python-brace-format msgid "TU Vote Reminder: Proposal {id}" -msgstr "" +msgstr "TU 投票リマインダー: 提案 {id}" #: scripts/notify.py #, python-brace-format msgid "" "Please remember to cast your vote on proposal {id} [1]. The voting period " "ends in less than 48 hours." -msgstr "" +msgstr "{id} [1] の提案について投票してください。投票期限は48時間以内です。" diff --git a/po/nb.po b/po/nb.po index 602d4163..200b6060 100644 --- a/po/nb.po +++ b/po/nb.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Alexander F Rødseth , 2015,2017-2019 @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2019-09-02 11:29+0000\n" -"Last-Translator: Alexander F Rødseth \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aurweb/language/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,6 +78,10 @@ msgstr "Kunne ikke hente informasjon om den valgte brukeren." msgid "You do not have permission to edit this account." msgstr "Du har ikke tilgang til å endre denne kontoen." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Bruk skjemaet for å søke etter eksisterende kontoer." @@ -372,10 +376,10 @@ msgid "Enter login credentials" msgstr "Fyll ut innloggingsinformasjon" #: html/login.php -msgid "User name or email address" -msgstr "Brukernavn eller e-postadresse" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Passord" @@ -436,8 +440,8 @@ msgid "Your password has been reset successfully." msgstr "Passordet ditt er nullstilt." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Bekreft e-postadressen din:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -454,13 +458,13 @@ msgstr "Fortsett" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Hvis du har glemt e-postadressen du brukte for å registrere deg, så kan du sende en e-post til listen %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Angi din e-postadresse:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -652,19 +656,19 @@ msgstr "Send inn forespørsel" msgid "Close Request" msgstr "Lukk forespørsel" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Første" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Forrige" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Neste" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Siste" @@ -765,10 +769,18 @@ msgstr "Start og slutt med en bokstav eller et siffer" msgid "Can contain only one period, underscore or hyphen." msgstr "Kan kun innehold ett punktum, en understrek, eller en bindestrek." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-postadressen er ugyldig." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Ugyldig hjemmeside, vennligst spesifiser hele HTTP(s) adressen." @@ -808,6 +820,18 @@ msgstr "Adressen, %s%s%s, er allerede i bruk." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Den offentlige SSH-nøkkelen, %s%s%s, er allerede i bruk." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1217,6 +1241,10 @@ msgstr "Vis pakkene til denne brukereren" msgid "Edit this user's account" msgstr "Endre brukerkonto" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1227,6 +1255,11 @@ msgstr "Klikk %sher%s hvis du vil slette denne kontoen for alltid." msgid "Click %shere%s for user details." msgstr "Klikk %sher%s for brukerdetaljer." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "trengs" @@ -1264,8 +1297,34 @@ msgid "Hide Email Address" msgstr "Gjem e-postadresse" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Skriv inn passordet på nytt" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1275,6 +1334,16 @@ msgstr "Språk" msgid "Timezone" msgstr "Tidssone" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Skriv inn passordet på nytt" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1301,6 +1370,24 @@ msgstr "Gi beskjed om pakkeoppdateringer" msgid "Notify of ownership changes" msgstr "Gi beskjed om endring av eierskap" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1429,7 +1516,7 @@ msgstr "Stem på denne pakken" msgid "Disable notifications" msgstr "Slå av beskjeder" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Gi beskjed" @@ -1460,6 +1547,10 @@ msgstr "Git-arkiv" msgid "read-only" msgstr "skrivebeskyttet" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1506,9 +1597,16 @@ msgstr "Rediger kommentar for: %s" msgid "Add Comment" msgstr "Legg til kommentar" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Vis alle kommentarer" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1518,6 +1616,10 @@ msgstr "La stå" msgid "Latest Comments" msgstr "Siste kommentarer" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1528,6 +1630,11 @@ msgstr "%s kommenterte %s" msgid "Anonymous comment on %s" msgstr "Anonym kommenterte %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1564,10 +1671,6 @@ msgstr "Fest kommentar" msgid "Unpin comment" msgstr "Løsne kommentar" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Alle kommentarer" - #: template/pkg_details.php msgid "Package Details" msgstr "Om pakken" @@ -2114,8 +2217,9 @@ msgstr "AUR pakken ble slettet: {pkgbase}" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "{user} [1] tok bort og slo sammen {old} [2] med {new} [3].\n\nDersom du ikke lenger vil ha beskjeder om denne pakken, vennligst gå til [3] og klikk på \"{label}\"." +msgstr "" #: scripts/notify.py #, python-brace-format diff --git a/po/nl.po b/po/nl.po index e062fe53..e5dc26d0 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Heimen Stoffels , 2015 @@ -12,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aurweb/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,6 +77,10 @@ msgstr "Kon geen informatie ophalen voor de opgegeven gebruiker." msgid "You do not have permission to edit this account." msgstr "U heeft geen toestemming om dit account te bewerken." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Gebruik dit formulier om bestaande accounts te zoeken." @@ -371,10 +375,10 @@ msgid "Enter login credentials" msgstr "Vul uw inloggegevens in" #: html/login.php -msgid "User name or email address" +msgid "User name or primary email address" msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Wachtwoord" @@ -435,8 +439,8 @@ msgid "Your password has been reset successfully." msgstr "Uw wachtwoord is met succes teruggezet." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Bevestig uw e-mailadres:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -453,13 +457,13 @@ msgstr "Doorgaan" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Als je het e-mail adres waarmee je geregistreerd hebt vergeten bent, stuur dan een bericht naar de %saur-general%s mailing list." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Vul uw e-mail adres in:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -651,19 +655,19 @@ msgstr "" msgid "Close Request" msgstr "Aanvraag sluiten" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Eerste" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Vorige" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Volgende" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Laatste" @@ -764,10 +768,18 @@ msgstr "Beginnen en eindigen met een letter of nummer" msgid "Can contain only one period, underscore or hyphen." msgstr "Kan maar één punt, komma of koppelteken bevatten." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Het e-mailadres is ongeldig." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -807,6 +819,18 @@ msgstr "Het adres %s%s%s is al in gebruik." msgid "The SSH public key, %s%s%s, is already in use." msgstr "De SSH publieke sleutel, %s%s%s, is al ingebruik." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1216,6 +1240,10 @@ msgstr "Bekijk gebruiker zijn pakketten" msgid "Edit this user's account" msgstr "Bewerk account van deze gebruiker" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1226,6 +1254,11 @@ msgstr "Klik %shier%s als u dit account permanent wilt verwijderen." msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "verplicht" @@ -1263,8 +1296,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Voer wachtwoord opnieuw in" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1274,6 +1333,16 @@ msgstr "Taal" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Voer wachtwoord opnieuw in" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1300,6 +1369,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1428,7 +1515,7 @@ msgstr "Stem voor dit pakket" msgid "Disable notifications" msgstr "Schakel notificaties uit" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1459,6 +1546,10 @@ msgstr "Git Clone URL" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1505,9 +1596,16 @@ msgstr "" msgid "Add Comment" msgstr "Voeg Comment Toe" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Bekijk alle commentaar" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1517,6 +1615,10 @@ msgstr "" msgid "Latest Comments" msgstr "Nieuwste Comments" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1527,6 +1629,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1563,10 +1670,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Alle comments" - #: template/pkg_details.php msgid "Package Details" msgstr "Pakketdetails" @@ -2113,6 +2216,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/pl.po b/po/pl.po index 909d2ccb..56e9f6bb 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,15 +1,16 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Bartłomiej Piotrowski , 2011 # Bartłomiej Piotrowski , 2014 +# hawkeye116477 , 2019 # Chris Warrick, 2013 # Chris Warrick, 2012 # Kwpolska , 2011 # Lukas Fleischer , 2011 -# Marcin Mikołajczak , 2017 +# Marcin Mikołajczak , 2017 # Michal T , 2016 # Nuc1eoN , 2014 # Piotr Strębski , 2017-2018 @@ -18,9 +19,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-06-11 15:26+0000\n" -"Last-Translator: Piotr Strębski \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Polish (http://www.transifex.com/lfleischer/aurweb/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -83,6 +84,10 @@ msgstr "Uzyskanie informacji o podanym użytkowniku nie powiodło się." msgid "You do not have permission to edit this account." msgstr "Nie masz uprawnień do edycji tego konta." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Przy użyciu tego formularza możesz przeszukać istniejące konta." @@ -195,11 +200,11 @@ msgstr "Wyszukaj pakiety, którymi się opiekuję" #: html/home.php msgid "Co-Maintained Packages" -msgstr "" +msgstr "Współ-utrzymywane pakiety" #: html/home.php msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Wyszukaj pakiety, które współ-utrzymuję" #: html/home.php #, php-format @@ -377,10 +382,10 @@ msgid "Enter login credentials" msgstr "Podaj poświadczenia logowania" #: html/login.php -msgid "User name or email address" -msgstr "Nazwa użytkownika lub adres e-mail" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Hasło" @@ -441,8 +446,8 @@ msgid "Your password has been reset successfully." msgstr "Twoje hasło zostało pomyślnie zresetowane." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Potwierdź swój adres e-mail:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -459,13 +464,13 @@ msgstr "Kontynuuj" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Jeśli zapomniałeś adresu e-mail, którego użyłeś do rejestracji, prosimy o wysłanie wiadomości na naszą listę dyskusyjną %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Wpisz swój adres e-mail:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -657,19 +662,19 @@ msgstr "Prześlij prośbę" msgid "Close Request" msgstr "Zamknij prośbę" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Pierwsza" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Poprzednia" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Następna" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ostatnia" @@ -701,7 +706,7 @@ msgstr "wydanie %d" #: html/tos.php msgid "I accept the terms and conditions above." -msgstr "" +msgstr "Akceptuję powyższe warunki i zasady." #: html/tu.php template/account_details.php template/header.php msgid "Trusted User" @@ -770,10 +775,18 @@ msgstr "Zacznij i zakończ literą lub cyfrą" msgid "Can contain only one period, underscore or hyphen." msgstr "Może zawierać tylko jedną kropkę, podkreślnik lub myślnik." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adres e-mail jest nieprawidłowy." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -813,6 +826,18 @@ msgstr "Adres, %s%s%s, jest już używany." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Publiczny klucz SSH, %s%s%s, jest już używany." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1222,6 +1247,10 @@ msgstr "Wyświetl pakiety tego użytkownika" msgid "Edit this user's account" msgstr "Edycja tego konta użytkownika" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1232,6 +1261,11 @@ msgstr "Kliknij %stutaj%s, jeśli chcesz nieodwracalnie usunąć to konto." msgid "Click %shere%s for user details." msgstr "Kliknij %stutaj%s by wyświetlić szczegóły użytkownika." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "wymagane" @@ -1269,8 +1303,34 @@ msgid "Hide Email Address" msgstr "Ukryj adres e-mail" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Hasło (ponownie)" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1280,6 +1340,16 @@ msgstr "Język" msgid "Timezone" msgstr "Strefa czasowa" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Hasło (ponownie)" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1306,6 +1376,24 @@ msgstr "Powiadom o aktualizacjach pakietu" msgid "Notify of ownership changes" msgstr "Powiadom o zmianie właściciela" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1434,7 +1522,7 @@ msgstr "Zagłosuj na ten pakiet" msgid "Disable notifications" msgstr "Wyłącz powiadomienia" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Włącz powiadomienia" @@ -1467,6 +1555,10 @@ msgstr "URL klonu Git" msgid "read-only" msgstr "tylko do odczytu" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1513,9 +1605,16 @@ msgstr "Edycja komentarza do: %s" msgid "Add Comment" msgstr "Dodaj komentarz" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Pokaż wszystkie komentarze" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1525,6 +1624,10 @@ msgstr "Przypięte komentarze" msgid "Latest Comments" msgstr "Ostatnie komentarze" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1535,6 +1638,11 @@ msgstr "%s skomentował dnia %s" msgid "Anonymous comment on %s" msgstr "Anonimowy komentarz do %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1571,10 +1679,6 @@ msgstr "Przypnij komentarz" msgid "Unpin comment" msgstr "Odepnij komentarz" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Wszystkie komentarze" - #: template/pkg_details.php msgid "Package Details" msgstr "Informacje o pakiecie" @@ -1700,7 +1804,7 @@ msgstr "" #: template/pkgreq_results.php msgid "No requests matched your search criteria." -msgstr "" +msgstr "Brak żądań spełniających podane kryteria wyszukiwania." #: template/pkgreq_results.php #, php-format @@ -2082,7 +2186,7 @@ msgstr "" #: scripts/notify.py #, python-brace-format msgid "AUR Out-of-date Notification for {pkgbase}" -msgstr "" +msgstr "Powiadomienie AUR o nieaktualnym pakiecie {pkgbase}" #: scripts/notify.py #, python-brace-format @@ -2129,6 +2233,7 @@ msgstr "Usunięty pakiet AUR: {pkgbase}" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/pt_BR.po b/po/pt_BR.po index 8c05a312..1a54b01a 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1,12 +1,12 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Albino Biasutti Neto Bino , 2011 # Fábio Nogueira , 2016 # Rafael Fontenelle , 2012-2015 -# Rafael Fontenelle , 2011,2015-2018 +# Rafael Fontenelle , 2011,2015-2018,2020 # Rafael Fontenelle , 2011 # Sandro , 2011 # Sandro , 2011 @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-21 18:28+0000\n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 12:57+0000\n" "Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aurweb/language/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -79,6 +79,10 @@ msgstr "Não foi possível obter informações para o usuário especificado." msgid "You do not have permission to edit this account." msgstr "Você não tem permissão para editar esta conta." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "Senha inválida." + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." @@ -373,10 +377,10 @@ msgid "Enter login credentials" msgstr "Digite as credenciais de login" #: html/login.php -msgid "User name or email address" -msgstr "Nome de usuário ou endereço de e-mail" +msgid "User name or primary email address" +msgstr "Nome de usuário ou endereço de e-mail primário" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Senha" @@ -437,8 +441,8 @@ msgid "Your password has been reset successfully." msgstr "Sua senha foi redefinida com sucesso." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Confirme seu endereço de e-mail:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "Confirme seu nome de usuário ou endereço de e-mail primário:" #: html/passreset.php msgid "Enter your new password:" @@ -455,13 +459,13 @@ msgstr "Continuar" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Se você esqueceu o endereço de e-mail que você usou para registrar, por favor envie uma mensagem para a lista de e-mail do %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "Se você esqueceu o nome de usuário e o endereço de e-mail primário que você usou para se registrar, envie uma mensagem para a lista de discussão %saur-general%s." #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Digite o seu endereço de e-mail:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "Digite seu nome de usuário ou seu endereço de e-mail primário:" #: html/pkgbase.php msgid "Package Bases" @@ -653,19 +657,19 @@ msgstr "Enviar requisição" msgid "Close Request" msgstr "Fechar requisição" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Próxima" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Última" @@ -766,10 +770,18 @@ msgstr "Começo e fim com uma letra ou um número" msgid "Can contain only one period, underscore or hyphen." msgstr "Pode conter somente um ponto, traço inferior ou hífen." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "Por favor, confirme sua nova senha." + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "O endereço de e-mail reserva é inválido" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "A página inicial é inválida. Por favor especificar a URL HTTP(s) completa." @@ -809,6 +821,18 @@ msgstr "O endereço, %s%s%s, já está sendo usado." msgid "The SSH public key, %s%s%s, is already in use." msgstr "A chave pública de SSH, %s%s%s, já está em uso." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "O CAPTCHA está faltando." + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "Este CAPTCHA expirou. Por favor, tente novamente." + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "A resposta de CAPTCHA inserida é inválida." + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1218,6 +1242,10 @@ msgstr "Visualizar pacotes deste usuário" msgid "Edit this user's account" msgstr "Edite a conta desse usuário" +#: template/account_details.php +msgid "List this user's comments" +msgstr "Listar os comentários deste usuário" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1228,6 +1256,11 @@ msgstr "Clique %saqui%s se você deseja excluir permanentemente esta conta." msgid "Click %shere%s for user details." msgstr "Clique %saqui%s para os detalhes do usuário." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "Clique %saqui%s para listar os comentários feitos por esta conta." + #: template/account_edit_form.php msgid "required" msgstr "obrigatório" @@ -1265,8 +1298,34 @@ msgid "Hide Email Address" msgstr "Ocultar endereço de e-mail" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Re-digite a senha" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "Se você não ocultar seu endereço de e-mail, ele ficará visível para todos os usuários registrados do AUR. Se você ocultar seu endereço de e-mail, ele estará visível apenas para membros da equipe do Arch Linux." + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "Endereço de e-mail reserva" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "Opcionalmente, forneça um endereço de e-mail secundário que possa ser usado para restaurar sua conta, caso você perca o acesso ao seu endereço de e-mail primário." + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "Os links de redefinição de senha são sempre enviados ao seu endereço de e-mail primário e reserva." + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "Seu endereço de e-mail reserva sempre é visível apenas para membros da equipe do Arch Linux, independentemente da configuração %s." #: template/account_edit_form.php msgid "Language" @@ -1276,6 +1335,16 @@ msgstr "Idioma" msgid "Timezone" msgstr "Fuso horário" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "Se você deseja alterar a senha, insira uma nova senha e confirme a nova senha digitando-a novamente." + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Re-digite a senha" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1302,6 +1371,24 @@ msgstr "Notificar sobre atualizações de pacotes" msgid "Notify of ownership changes" msgstr "Notificar sobre mudanças de mantenedor" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "Para confirmar as alterações no perfil, digite sua senha atual:" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "Sua senha atual" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "Para proteger o AUR contra a criação automatizada de contas, solicitamos que você forneça o resultado do seguinte comando:" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "Resposta" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1430,7 +1517,7 @@ msgstr "Votar neste pacote" msgid "Disable notifications" msgstr "Desabilitar notificações" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Habilitar notificações" @@ -1461,6 +1548,10 @@ msgstr "Git Clone URL" msgid "read-only" msgstr "somente leitura" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "clique para copiar" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1507,9 +1598,16 @@ msgstr "Editar comentário para: %s" msgid "Add Comment" msgstr "Adicionar comentário" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Ver todos os comentários" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "Os identificadores de commit Git que fazem referência a commits no repositório de pacote AUR e os URLs são convertidos em links automaticamente." + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "Há suporte parcial à %ssintaxe Markdown%s." #: template/pkg_comments.php msgid "Pinned Comments" @@ -1519,6 +1617,10 @@ msgstr "Comentários afixados" msgid "Latest Comments" msgstr "Últimos comentários" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "Comentários para" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1529,6 +1631,11 @@ msgstr "%s comentou em %s" msgid "Anonymous comment on %s" msgstr "Comentário anônimo em %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "Comentou no pacote %s em %s" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1565,10 +1672,6 @@ msgstr "Afixar comentário" msgid "Unpin comment" msgstr "Desafixar comentário" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Todos os comentários" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do pacote" @@ -2115,8 +2218,9 @@ msgstr "Pacote do AUR excluído: {pkgbase}" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "{user} [1] mesclou {old} [2] ao {new} [3].\n\nSe você não deseja mais receber notificações sobre o novo pacote, por favor acesse a [3] e clique em \"{label}\"." +msgstr "{user} [1] mesclou {old} [2] ao {new} [3].\n\n-- \nSe você não deseja mais receber notificações sobre o novo pacote, por favor acesse a [3] e clique em \"{label}\"." #: scripts/notify.py #, python-brace-format diff --git a/po/pt_PT.po b/po/pt_PT.po index 30a75434..0303993a 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -1,21 +1,21 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Christophe Silva , 2018 # Gaspar Santos , 2011 # R00KIE , 2013,2016 # R00KIE , 2011 -# DarkVenger, 2013-2015 -# DarkVenger, 2012 +# c0d75bae60e6967ec54315cff4da5848, 2013-2015 +# c0d75bae60e6967ec54315cff4da5848, 2012 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/aurweb/language/pt_PT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,6 +78,10 @@ msgstr "Não foi possível obter informações para o utilizador especificado." msgid "You do not have permission to edit this account." msgstr "Não tem autorização para editar esta conta." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Utilize este formulário para procurar contas existentes." @@ -372,10 +376,10 @@ msgid "Enter login credentials" msgstr "Introduza as credenciais para login" #: html/login.php -msgid "User name or email address" -msgstr "Usuário ou endereço de email" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Palavra-passe" @@ -436,8 +440,8 @@ msgid "Your password has been reset successfully." msgstr "A palavra-passe foi reiniciada com êxito." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Confirme o endereço de e-mail:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -454,13 +458,13 @@ msgstr "Continue" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Se se esqueceu do endereço de e-mail que utilizou para efectuar o registo, por favor envie uma mensagem para a lista de discussão %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Introduza o endereço de e-mail:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -652,19 +656,19 @@ msgstr "Submeter Pedido" msgid "Close Request" msgstr "Fechar Pedido" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Primeiro" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Anterior" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Seguinte" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultimo." @@ -765,10 +769,18 @@ msgstr "Começar e acabar com uma letra ou um número" msgid "Can contain only one period, underscore or hyphen." msgstr "Apenas pode conter um ponto, underscore ou hífen." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "O endereço de e-mail é inválido." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "A página inicial é inválida, especifique o URL de HTTP (s) completo (s)." @@ -808,6 +820,18 @@ msgstr "O endereço, %s%s%s, já está a ser utilizado." msgid "The SSH public key, %s%s%s, is already in use." msgstr "A chave pública SSH, %s %s %s, já está em uso." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1217,6 +1241,10 @@ msgstr "Ver os pacotes deste utilizador" msgid "Edit this user's account" msgstr "Editar a conta deste utilizador" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1227,6 +1255,11 @@ msgstr "" msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "necessário" @@ -1264,8 +1297,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Reintroduza a palavra-passe" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1275,6 +1334,16 @@ msgstr "Língua" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Reintroduza a palavra-passe" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1301,6 +1370,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1429,7 +1516,7 @@ msgstr "Votar neste pacote" msgid "Disable notifications" msgstr "Desativar notificações" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1460,6 +1547,10 @@ msgstr "" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1506,8 +1597,15 @@ msgstr "" msgid "Add Comment" msgstr "Adicionar comentário" -#: template/pkg_comments.php -msgid "View all comments" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." msgstr "" #: template/pkg_comments.php @@ -1518,6 +1616,10 @@ msgstr "" msgid "Latest Comments" msgstr "Últimos Comentários" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1528,6 +1630,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1564,10 +1671,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Todos os comentários" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalhes do Pacote" @@ -2114,6 +2217,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/ro.po b/po/ro.po index 0859fa42..7394ed83 100644 --- a/po/ro.po +++ b/po/ro.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Arthur Țițeică , 2013-2015 @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Romanian (http://www.transifex.com/lfleischer/aurweb/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -75,6 +75,10 @@ msgstr "Nu s-au putut prelua informații despre utilizatorul specificat." msgid "You do not have permission to edit this account." msgstr "Nu ai permisiune pentru a modifica acest cont." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Folosește acest formular pentru a căuta conturi existente." @@ -369,10 +373,10 @@ msgid "Enter login credentials" msgstr "Introdu datele de autentificare" #: html/login.php -msgid "User name or email address" +msgid "User name or primary email address" msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Parolă" @@ -433,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "Parola ta a fost restabilită cu succes." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Confirmă adresa de e-mail:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -451,13 +455,13 @@ msgstr "Continuă" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Dacă ai uitat adresa de email folosită la înregistrare, trimite un mesaj la lista de discuții %saur-general%s" +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Introdu adresa ta de e-mail:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -649,19 +653,19 @@ msgstr "" msgid "Close Request" msgstr "Închide cererea" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prim" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Precedent" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Înainte" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Ultim" @@ -762,10 +766,18 @@ msgstr "Începe și sfârșește cu o literă sau un număr." msgid "Can contain only one period, underscore or hyphen." msgstr "Poate conține doar o virgulă, linie joasă sau cratimă." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Adresa de email nu este validă." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -805,6 +817,18 @@ msgstr "Adresa %s%s%s este deja folosită." msgid "The SSH public key, %s%s%s, is already in use." msgstr "" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1214,6 +1238,10 @@ msgstr "Vezi pachetele acestui utilizator" msgid "Edit this user's account" msgstr "Modifică contul acestui utilizator" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1224,6 +1252,11 @@ msgstr "Clic %saici%s dacă dorești să ștergi definitiv acest cont." msgid "Click %shere%s for user details." msgstr "" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "cerut" @@ -1261,8 +1294,34 @@ msgid "Hide Email Address" msgstr "" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Rescrie parola" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1272,6 +1331,16 @@ msgstr "Limbă" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Rescrie parola" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1298,6 +1367,24 @@ msgstr "" msgid "Notify of ownership changes" msgstr "" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1426,7 +1513,7 @@ msgstr "Votează acest pachet" msgid "Disable notifications" msgstr "Dezactivează notificări" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "" @@ -1458,6 +1545,10 @@ msgstr "" msgid "read-only" msgstr "" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1504,9 +1595,16 @@ msgstr "" msgid "Add Comment" msgstr "Adaugă comentariu" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Vizualizează toate comentariile" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1516,6 +1614,10 @@ msgstr "" msgid "Latest Comments" msgstr "Ultimele comentarii" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1526,6 +1628,11 @@ msgstr "" msgid "Anonymous comment on %s" msgstr "" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1562,10 +1669,6 @@ msgstr "" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Toate comentariile" - #: template/pkg_details.php msgid "Package Details" msgstr "Detalii pachet" @@ -2116,6 +2219,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/ru.po b/po/ru.po index abe4a5c9..86a01cc6 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Evgeniy Alekseev , 2014-2015 @@ -17,9 +17,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Russian (http://www.transifex.com/lfleischer/aurweb/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -82,6 +82,10 @@ msgstr "Не удалось получить информацию об указ msgid "You do not have permission to edit this account." msgstr "Вы не имеете права редактировать эту учетную запись." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Используйте эту форму для поиска существующих учетных записей." @@ -376,10 +380,10 @@ msgid "Enter login credentials" msgstr "Введите учётные данные" #: html/login.php -msgid "User name or email address" -msgstr "Имя пользователя или email" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Пароль" @@ -440,8 +444,8 @@ msgid "Your password has been reset successfully." msgstr "Ваш пароль успешно сброшен." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Подтвердите адрес своей электронной почты:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -458,13 +462,13 @@ msgstr "Продолжить" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Если вы забыли электронный адрес, который вы использовали для регистрации, пожалуйста, отошлите сообщение в список рассылки %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Введите свой адрес электронной почты:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -656,19 +660,19 @@ msgstr "Отправить запрос" msgid "Close Request" msgstr "Закрыть запрос" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Первый" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Назад" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далее" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Последний" @@ -769,10 +773,18 @@ msgstr "Начинаются и заканчиваются цифрой или msgid "Can contain only one period, underscore or hyphen." msgstr "Может содержать только одну точку, подчёркивание или тире." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Неправильный адрес электронной почты." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Неверная домашняя страница, укажите полный адрес с указанием протокола HTTP(s)." @@ -812,6 +824,18 @@ msgstr "Адрес %s%s%s уже используется." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Публичный SSH ключ %s%s%s уже используется." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1221,6 +1245,10 @@ msgstr "Посмотреть пакеты этого пользователя" msgid "Edit this user's account" msgstr "Отредактировать этот аккаунт" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1231,6 +1259,11 @@ msgstr "Нажмите %sздесь%s, если Вы хотите удалить msgid "Click %shere%s for user details." msgstr "Нажмите %sздесь%s, чтобы просмотреть данные о пользователе." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "необходимо" @@ -1268,8 +1301,34 @@ msgid "Hide Email Address" msgstr "Скрыть email." #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Введите пароль еще раз" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1279,6 +1338,16 @@ msgstr "Язык" msgid "Timezone" msgstr "Часовой пояс" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Введите пароль еще раз" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1305,6 +1374,24 @@ msgstr "Уведомлять об обновлении пакета" msgid "Notify of ownership changes" msgstr "Уведомлять об измененях собственности" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1433,7 +1520,7 @@ msgstr "Проголосовать за пакет" msgid "Disable notifications" msgstr "Выключить уведомления" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Включить уведомления" @@ -1466,6 +1553,10 @@ msgstr "URL для git clone" msgid "read-only" msgstr "только чтение" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1512,9 +1603,16 @@ msgstr "Редактировать комментарий для: %s" msgid "Add Comment" msgstr "Добавить комментарий" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Посмотреть все комментарии" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1524,6 +1622,10 @@ msgstr "Закрепленные комментарии" msgid "Latest Comments" msgstr "Последние комментарии" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1534,6 +1636,11 @@ msgstr "%s прокомментировал %s" msgid "Anonymous comment on %s" msgstr "Анонимный комментарий для %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1570,10 +1677,6 @@ msgstr "Закрепить комментарий" msgid "Unpin comment" msgstr "Открепить комментарий" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Все комментарии" - #: template/pkg_details.php msgid "Package Details" msgstr "Информация о пакете" @@ -2128,6 +2231,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/sk.po b/po/sk.po index ffbd86c7..d54a9dab 100644 --- a/po/sk.po +++ b/po/sk.po @@ -1,17 +1,18 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # archetyp , 2013-2016 +# Jose Riha , 2018 # Matej Ľach , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Slovak (http://www.transifex.com/lfleischer/aurweb/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -74,6 +75,10 @@ msgstr "Nemožno získať informácie pre špecifikovaného užívateľa. " msgid "You do not have permission to edit this account." msgstr "Nemáte potrebné oprávnenia, pre úpravu tohoto účtu. " +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Použite tento formulár pre vyhľadávanie v existujúcich účtoch." @@ -368,10 +373,10 @@ msgid "Enter login credentials" msgstr "Zadajte prihlasovacie údaje" #: html/login.php -msgid "User name or email address" -msgstr "Užívateľské meno alebo emailová adresa" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Heslo" @@ -432,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "Heslo bolo úspešne obnovené." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Potvrďte svoju e-mailovú adresu:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -450,13 +455,13 @@ msgstr "Pokračuj" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Ak ste zabudli e-mailovú adresu, ktorú ste použili pri registrácii, pošlite prosím správu na %saur-general%s mailing list." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Zadajte svoju e-mailovú adresu:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -648,19 +653,19 @@ msgstr "Odoslať žiadosť" msgid "Close Request" msgstr "Zatvoriť žiadosť" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prvý" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Predchádzajúci" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" -msgstr "Ďaľej " +msgstr "Ďalej " -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Posledný" @@ -746,7 +751,7 @@ msgstr "Chýba ID užívateľa" #: lib/acctfuncs.inc.php msgid "The username is invalid." -msgstr "Užívateľké meno je neplatné." +msgstr "Užívateľské meno je neplatné." #: lib/acctfuncs.inc.php #, php-format @@ -761,10 +766,18 @@ msgstr "Začínať a končiť s písmenom alebo číslom" msgid "Can contain only one period, underscore or hyphen." msgstr "Môže obsahovať len jednu bodku, podčiarkovník alebo pomlčku." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-mailová adresa nie je platná." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -804,6 +817,18 @@ msgstr "Adresa %s%s%s sa už používa." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Verejný SSH kľúč %s%s%s sa už používa." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1213,6 +1238,10 @@ msgstr "Pozrieť balíčky tohto užívateľa" msgid "Edit this user's account" msgstr "Editovať účet tohto užívateľa" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1223,6 +1252,11 @@ msgstr "Kliknite %ssem%s ak chcete natrvalo vymazať tento účet." msgid "Click %shere%s for user details." msgstr "Kliknite %ssem%s pre informácie o užívateľovi." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "povinný" @@ -1260,8 +1294,34 @@ msgid "Hide Email Address" msgstr "Skryť emailovú adresu" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Potvrďte heslo" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1271,6 +1331,16 @@ msgstr "Jazyk" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Potvrďte heslo" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1297,6 +1367,24 @@ msgstr "Upozorni na aktualizácie balíčkov" msgid "Notify of ownership changes" msgstr "Upozorni na zmeny vo vlastníctve balíčka" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1342,7 +1430,7 @@ msgstr "Nie sú ďalšie výsledky na zobrazenie." #, php-format msgid "" "Use this form to add co-maintainers for %s%s%s (one user name per line):" -msgstr "Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno užívateľké meno na riadok):" +msgstr "Použite tento formulár pre pridanie spolupracovníkov pre %s%s%s (jedno užívateľské meno na riadok):" #: template/comaintainers_form.php msgid "Users" @@ -1425,7 +1513,7 @@ msgstr "Hlasuj za tento balíček" msgid "Disable notifications" msgstr "Vypni upozornenia" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Povoliť upozornenia" @@ -1458,6 +1546,10 @@ msgstr "Git Clone URL" msgid "read-only" msgstr "len na čítanie" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1504,9 +1596,16 @@ msgstr "Editovať komentár k: %s" msgid "Add Comment" msgstr "Pridať komentár" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Pozrieť všetky komentáre" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1516,6 +1615,10 @@ msgstr "Pripnuté komentáre" msgid "Latest Comments" msgstr "Posledné komentáre" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1526,6 +1629,11 @@ msgstr "%s dal komentár k %s" msgid "Anonymous comment on %s" msgstr "Anonymný komentár k %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1562,10 +1670,6 @@ msgstr "Pripnúť komentár" msgid "Unpin comment" msgstr "Odopnúť komentár" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Všetky komentáre" - #: template/pkg_details.php msgid "Package Details" msgstr "Detaily balíčka" @@ -2120,6 +2224,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/sr.po b/po/sr.po index 0a49ba72..24a52ab7 100644 --- a/po/sr.po +++ b/po/sr.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Lukas Fleischer , 2011 @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Serbian (http://www.transifex.com/lfleischer/aurweb/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -75,6 +75,10 @@ msgstr "Ne mogu da dobavim podatke o izabranom korisniku." msgid "You do not have permission to edit this account." msgstr "Nemate dozvole za uređivanje ovog naloga." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Ovim obrascem pretražujete postojeće naloge." @@ -369,10 +373,10 @@ msgid "Enter login credentials" msgstr "Unesite podatke za prijavu" #: html/login.php -msgid "User name or email address" -msgstr "Korisničko ime ili adresa e-pošte" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Lozinka" @@ -433,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "Vaša lozinka je uspešno resetovana." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Potvrdite adresu e-pošte:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -451,13 +455,13 @@ msgstr "Nastavi" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Ukoliko ste zaboravili registracionu adresu e-pošte, molimo pošaljite poruku na dopisnu listu %saur-general%s." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Unesite adresu e-pošte:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -649,19 +653,19 @@ msgstr "Podnesi zahtev" msgid "Close Request" msgstr "Zatvori zahtev" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Prva" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Prethodna" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Sledeća" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Zadnja" @@ -762,10 +766,18 @@ msgstr "Počnje i završava slovom ili brojem" msgid "Can contain only one period, underscore or hyphen." msgstr "Može sadržati samo jedan razmak, podvlaku ili crticu." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Neispravna adresa e-pošte." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Domaća stranica je neispravna, molimo navedite puni HTTP(s) URL." @@ -805,6 +817,18 @@ msgstr "Adresa %s%s%s je već u upotrebi." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Javni SSH ključ %s%s%s je već u upotrebi." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1214,6 +1238,10 @@ msgstr "Pregledaj korisnikove pakete" msgid "Edit this user's account" msgstr "Uređivanje naloga ovog korisnika" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1224,6 +1252,11 @@ msgstr "Kliknite %sovde%s ako želite trajno brisanje ovog naloga." msgid "Click %shere%s for user details." msgstr "Kliknite %sovde%s za podatke o korisniku." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "neophodno" @@ -1261,8 +1294,34 @@ msgid "Hide Email Address" msgstr "Skrij adresu e-pošte" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Ponovo unesite lozinku" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1272,6 +1331,16 @@ msgstr "Jezik" msgid "Timezone" msgstr "Vremenska zona" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Ponovo unesite lozinku" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1298,6 +1367,24 @@ msgstr "Obavesti o nadogradnjama paketa" msgid "Notify of ownership changes" msgstr "Obavesti o promenama vlasništva" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1426,7 +1513,7 @@ msgstr "Glasajte za paket" msgid "Disable notifications" msgstr "Ugasi obaveštenja" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Uključi obaveštenja" @@ -1458,6 +1545,10 @@ msgstr "URL za git kloniranje" msgid "read-only" msgstr "samo za čitanje" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1504,9 +1595,16 @@ msgstr "Uređivanje komentara za: %s" msgid "Add Comment" msgstr "Dodaj komentar" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Prikaži sve komentare" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1516,6 +1614,10 @@ msgstr "Izdvojeni komentari" msgid "Latest Comments" msgstr "Poslednji komentari" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1526,6 +1628,11 @@ msgstr "%s postavi komentar %s u" msgid "Anonymous comment on %s" msgstr "Anoniman komentar za %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1562,10 +1669,6 @@ msgstr "Izdvoji komentar" msgid "Unpin comment" msgstr "Odvoji komentar" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Svi komentari" - #: template/pkg_details.php msgid "Package Details" msgstr "Podaci o paketu" @@ -2116,6 +2219,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/tr.po b/po/tr.po index 95cb4707..04161700 100644 --- a/po/tr.po +++ b/po/tr.po @@ -1,11 +1,11 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # tarakbumba , 2011,2013-2015 # tarakbumba , 2012,2014 -# Demiray “tulliana” Muhterem , 2015 +# Demiray Muhterem , 2015 # Lukas Fleischer , 2011 # Samed Beyribey , 2012 # Samed Beyribey , 2012 @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Turkish (http://www.transifex.com/lfleischer/aurweb/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -80,6 +80,10 @@ msgstr "Belirtilen kullanıcı verileri alınamadı." msgid "You do not have permission to edit this account." msgstr "Bu hesap üzerinde değişiklik yapma izniniz yok." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Mevcut hesaplar içinde arama yapmak için bu formu kullanın." @@ -374,10 +378,10 @@ msgid "Enter login credentials" msgstr "Giriş bilgilerinizi doldurun" #: html/login.php -msgid "User name or email address" -msgstr "Kullanıcı adı veya e-posta adresi" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Parola" @@ -438,8 +442,8 @@ msgid "Your password has been reset successfully." msgstr "Parolanız başarıyla sıfırlandı." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "E-posta adresinizi onaylayın:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -456,13 +460,13 @@ msgstr "Devam" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Kayıt olurken kullandığınız e-posta adresini hatırlamıyorsanız lütfen %saur-general%s posta listesine mesaj gönderin." +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "E-posta adresinizi girin:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -654,19 +658,19 @@ msgstr "" msgid "Close Request" msgstr "Kapama Talebi" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "İlk" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Önceki" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "İleri" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Son" @@ -767,10 +771,18 @@ msgstr "Bir rakam veya harf ile başlatıp bitirmelisiniz" msgid "Can contain only one period, underscore or hyphen." msgstr "Sadece bir nokta, alt çizgi veya tire barındırabilir." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "E-posta adresi geçerli değil." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "" @@ -810,6 +822,18 @@ msgstr "Adres, %s%s%s, zaten kullanılıyor." msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH kamu anahtarı, %s%s%s, zaten kullanımda." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1219,6 +1243,10 @@ msgstr "Bu kullanıcı tarafından hazırlanan paketleri göster" msgid "Edit this user's account" msgstr "Bu kullanıcının hesabını düzenleyin" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1229,6 +1257,11 @@ msgstr "Bu hesabı temelli olarak silmek istiyorsanız %sburaya%s tıklayın." msgid "Click %shere%s for user details." msgstr "Kullanıcı detayları için %sburaya%s tıklayın." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "gerekli" @@ -1266,8 +1299,34 @@ msgid "Hide Email Address" msgstr "E-posta Adresini Gizle" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Parolayı tekrar girin" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1277,6 +1336,16 @@ msgstr "Dil" msgid "Timezone" msgstr "" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Parolayı tekrar girin" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1303,6 +1372,24 @@ msgstr "Paket güncellemelerini bildir" msgid "Notify of ownership changes" msgstr "Sahiplik değişikliklerini bildir." +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1431,7 +1518,7 @@ msgstr "Pakete oy ver" msgid "Disable notifications" msgstr "Bildirimleri kapat" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Bildirimleri etkinleştir" @@ -1462,6 +1549,10 @@ msgstr "Git Clone URL" msgid "read-only" msgstr "salt okunur" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1508,9 +1599,16 @@ msgstr "Yorumu düzenle: %s" msgid "Add Comment" msgstr "Yorum Ekle" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Tüm yorumları görünüle" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1520,6 +1618,10 @@ msgstr "İğnelenmiş Yorumlar" msgid "Latest Comments" msgstr "Son Yorumlar" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1530,6 +1632,11 @@ msgstr "%s, %s'e yorum yaptı." msgid "Anonymous comment on %s" msgstr "%s'e isimsiz yorum" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1566,10 +1673,6 @@ msgstr "Yorumu iğnele" msgid "Unpin comment" msgstr "" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Tüm yorumlar" - #: template/pkg_details.php msgid "Package Details" msgstr "Paket Ayrıntıları" @@ -2116,6 +2219,7 @@ msgstr "" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." msgstr "" diff --git a/po/uk.po b/po/uk.po index b4ec36d0..7dd65d90 100644 --- a/po/uk.po +++ b/po/uk.po @@ -1,20 +1,21 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # Lukas Fleischer , 2011 # Rax Garfield , 2012 # Rax Garfield , 2012 +# Vladislav Glinsky , 2019 # Yarema aka Knedlyk , 2011-2018 # Данило Коростіль , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-25 20:15+0000\n" -"Last-Translator: Yarema aka Knedlyk \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aurweb/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -46,7 +47,7 @@ msgstr "Щоб клонувати сховище Git з %s, виконайте % #: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "Клацніть %sтут%s для повернення на сторінку інформації %s." +msgstr "Клацніть %sтут%s для повернення на сторінку подробиць %s." #: html/503.php msgid "Service Unavailable" @@ -55,7 +56,7 @@ msgstr "Сервіс недоступний" #: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "Не панікуйте! Сторінка закрита на технічне обслуговування. Ми швидко повернемося." +msgstr "Не панікуйте! Сторінка закрита на технічне обслуговування. Ми скоро повернемося." #: html/account.php msgid "Account" @@ -77,6 +78,10 @@ msgstr "Не вдалося отримати інформацію про вка msgid "You do not have permission to edit this account." msgstr "У вас недостатньо прав для редагування цього облікового запису." +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "Шукайте облікові записи за допомогою цієї форми." @@ -91,7 +96,7 @@ msgstr "Додати пропозицію" #: html/addvote.php msgid "Invalid token for user action." -msgstr "Невірний маркер для дій користувача." +msgstr "Невірний маркер дії користувача." #: html/addvote.php msgid "Username does not exist." @@ -185,7 +190,7 @@ msgstr "Мої пакунки" #: html/home.php msgid "Search for packages I maintain" -msgstr "Пошук пакунків які я підтримую" +msgstr "Пошук пакунків, які я підтримую" #: html/home.php msgid "Co-Maintained Packages" @@ -248,7 +253,7 @@ msgstr "Існують три типи запитів, які можна ств #: html/home.php msgid "Orphan Request" -msgstr "Запит щодо покинення пакунку" +msgstr "Запит покинути пакунок" #: html/home.php msgid "" @@ -265,7 +270,7 @@ msgid "" "Request a package to be removed from the Arch User Repository. Please do not" " use this if a package is broken and can be fixed easily. Instead, contact " "the package maintainer and file orphan request if necessary." -msgstr "Запит щодо вилучення пакунку зі Сховища Користувацьких Пакунків AUR. Будь ласка, не використовуйте його, якщо пакунок містить ваду, яку можна легко виправити. Для цього зв’яжіться з супровідником пакунку і заповніть форму на покинення пакунку в разі необхідності." +msgstr "Запит щодо вилучення пакунку зі сховища користувацьких пакунків AUR. Будь ласка, не використовуйте його, якщо пакунок містить проблеми, які можна легко виправити. Натомість зв’яжіться з супровідником пакунку та в разі необхідності зробіть запит покинути пакунок." #: html/home.php msgid "Merge Request" @@ -371,10 +376,10 @@ msgid "Enter login credentials" msgstr "Увійдіть, ввівши облікові дані." #: html/login.php -msgid "User name or email address" -msgstr "Назва користувача або адреса електронної пошти" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "Пароль" @@ -435,8 +440,8 @@ msgid "Your password has been reset successfully." msgstr "Ваш пароль успішно скинуто." #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "Підтвердьте адресу електронної пошти:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -453,13 +458,13 @@ msgstr "Продовжити" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "Якщо Ви забули електронну адресу, використану при реєстрації, зверніться до списку розсилання %saur-general%s" +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "Введіть адресу електронної пошти:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -651,19 +656,19 @@ msgstr "Надіслати запит" msgid "Close Request" msgstr "Закриття запиту" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "Перший" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "Попередній" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "Далі" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "Останній" @@ -741,7 +746,7 @@ msgstr "Проголосували" msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Реєстрація рахунку закрита для Вашої адреси IP, можливо із-за інтенсивної спам-атаки. Вибачте за незручності." +msgstr "Реєстрація облікових записів закрита для вашої IP-адреси, можливо із-за інтенсивних спам-атак. Вибачте за незручності." #: lib/acctfuncs.inc.php msgid "Missing User ID" @@ -764,10 +769,18 @@ msgstr "Початок та кінець з літери або цифри" msgid "Can contain only one period, underscore or hyphen." msgstr "Може містити тільки один період, підкреслення або дефіс." +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "Адреса електронної пошти неправильна." +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "Неправильна домашня сторінка, вкажіть повну адресу HTTP(s)." @@ -782,7 +795,7 @@ msgstr "Неправильний публічний ключ SSH." #: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." -msgstr "Неможливо збільшити дозволи рахунку." +msgstr "Неможливо збільшити дозволи облікового запису." #: lib/acctfuncs.inc.php msgid "Language is not currently supported." @@ -807,15 +820,27 @@ msgstr "Адрес %s%s%s вже використовується." msgid "The SSH public key, %s%s%s, is already in use." msgstr "Публічний ключ SSH, %s%s%s, вже використовується." +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." -msgstr "Помилка при спробі створити рахунок %s%s%s." +msgstr "Помилка при спробі створити обліковий запис %s%s%s." #: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "Рахунок %s%s%s успішно створено." +msgstr "Обліковий запис %s%s%s успішно створено." #: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." @@ -828,12 +853,12 @@ msgstr "Використовуйте обліковий запис, увійшо #: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." -msgstr "Ніяких змін не внесено до рахунку, %s%s%s." +msgstr "Жодних змін до облікового запису %s%s%s не внесено." #: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "Рахунок %s%s%s успішно змінено." +msgstr "Обліковий запис %s%s%s успішно змінено." #: lib/acctfuncs.inc.php msgid "" @@ -843,7 +868,7 @@ msgstr "Форма логування зараз заборонена для В #: lib/acctfuncs.inc.php msgid "Account suspended" -msgstr "Рахунок вилучено" +msgstr "Обліковий запис вилучено" #: lib/acctfuncs.inc.php #, php-format @@ -851,7 +876,7 @@ msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Ваш пароль скинуто. Якщо Ви щойно створили новий рахунок, тоді використайте посилання електронного листа-підтвердження для встановлення початкового пароля. В протилежному випадку використайте запит щодо скидання паролю на сторінці %sPassword Reset%s." +msgstr "Ваш пароль скинуто. Якщо Ви щойно створили новий обліковий запис, використайте посилання з електронного листа-підтвердження для встановлення початкового пароля. В протилежному випадку використовайте запит щодо скидання пароля на сторінці %sPassword Reset%s." #: lib/acctfuncs.inc.php msgid "Bad username or password." @@ -872,7 +897,7 @@ msgstr "Немає" #: lib/aur.inc.php template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "View account information for %s" -msgstr "Показати інформацію про рахунок для %s" +msgstr "Переглянути інформацію облікового запису %s" #: lib/aurjson.class.php msgid "Package base ID or package base name missing." @@ -1113,7 +1138,7 @@ msgstr "Запит успішно закритий." #: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Ви можете використати цю форму для вилучення рахунку в AUR %s." +msgstr "Для безповоротного видалення облікового запису %s з AUR ви можете використати цю форму." #: template/account_delete.php #, php-format @@ -1214,7 +1239,11 @@ msgstr "Переглянути пакунки цього користувача" #: template/account_details.php msgid "Edit this user's account" -msgstr "Редагування рахунку цього користувача" +msgstr "Редагувати обліковий запис цього користувача" + +#: template/account_details.php +msgid "List this user's comments" +msgstr "" #: template/account_edit_form.php #, php-format @@ -1226,6 +1255,11 @@ msgstr "Натисніть %sтут%s, якщо Ви бажаєте безпов msgid "Click %shere%s for user details." msgstr "Клацніть %sтут%s, щоб дізнатися більше про користувача." +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "обов'язково" @@ -1263,8 +1297,34 @@ msgid "Hide Email Address" msgstr "Приховати адресу електронної пошти" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "Введіть пароль ще раз" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1274,6 +1334,16 @@ msgstr "Мова" msgid "Timezone" msgstr "Часова зона" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "Введіть пароль ще раз" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1300,6 +1370,24 @@ msgstr "Повідомлення про оновлення пакунків" msgid "Notify of ownership changes" msgstr "Сповіщення про зміну власника" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1381,7 +1469,7 @@ msgstr "Всі права застережено %s 2004-%d Команда Ро #: template/header.php msgid " My Account" -msgstr "Мій рахунок" +msgstr "Мій обліковий запис" #: template/pkgbase_actions.php msgid "Package Actions" @@ -1428,7 +1516,7 @@ msgstr "Голосувати за цей пакунок" msgid "Disable notifications" msgstr "Відключити сповіщення" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "Включити сповіщення" @@ -1461,6 +1549,10 @@ msgstr "Адреса URL для клонування Git" msgid "read-only" msgstr "тільки для читання" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1507,9 +1599,16 @@ msgstr "Редагувати коментар для: %s" msgid "Add Comment" msgstr "Додати коментар" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "Переглянути всі коментарі" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1519,6 +1618,10 @@ msgstr "Прикріплені коментарі" msgid "Latest Comments" msgstr "Останні коментарі" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1529,6 +1632,11 @@ msgstr "%s коментував про %s" msgid "Anonymous comment on %s" msgstr "Анонімний коментар про %s" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1565,10 +1673,6 @@ msgstr "Прикріпити коментар" msgid "Unpin comment" msgstr "Відкріпити коментар" -#: template/pkg_comments.php -msgid "All comments" -msgstr "Всі коментарі" - #: template/pkg_details.php msgid "Package Details" msgstr "Подробиці пакунку" @@ -1663,7 +1767,7 @@ msgstr "Вилучення" #: template/pkgreq_form.php msgid "Orphan" -msgstr "Позначити застарілим" +msgstr "Покинути" #: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" @@ -1690,7 +1794,7 @@ msgid "" "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "Надсилаючи запит на зречення, Ви просите Довіреного Користувача позбавити базу пакунків власника. Робіть це, якщо пакунок потребує якоїсь дії від супровідника, супровідник не робить жодних дій і Ви вже попередньо намагалися зв'язатися з ним." +msgstr "Надсилаючи запит покинути пакунок, Ви просите Довіреного Користувача позбавити базу пакунків власника. Робіть це, лише коли пакунок потребує якоїсь дії від супровідника, супровідник не робить жодних дій і ви вже попередньо намагалися зв'язатися з ним." #: template/pkgreq_results.php msgid "No requests matched your search criteria." @@ -2033,7 +2137,7 @@ msgid "" "A password reset request was submitted for the account {user} associated " "with your email address. If you wish to reset your password follow the link " "[1] below, otherwise ignore this message and nothing will happen." -msgstr "Запит на скидання паролю для облікового запису {user} надісланий на пов’язану з ним адресу електронної пошти. Щоб скинути пароль, натисніть на посилання [1] нижче; щоб залишити все як є, проігноруйте це повідомлення." +msgstr "Запит скидання пароля для облікового запису {user} надіслано на пов’язану з ним адресу електронної пошти. Щоб скинути пароль, перейдіть за посиланням [1] нижче; щоб залишити все як є, проігноруйте це повідомлення." #: scripts/notify.py msgid "Welcome to the Arch User Repository" @@ -2044,7 +2148,7 @@ msgid "" "Welcome to the Arch User Repository! In order to set an initial password for" " your new account, please click the link [1] below. If the link does not " "work, try copying and pasting it into your browser." -msgstr "Вітаємо в Сховищі Користувацьких Пакунків! Щоб встановити початковий пароль для Вашого рахунку натисніть на посилання [1] зверху. Якщо посилання не спрацьовує, скопіюйте його і вставте у Ваш переглядач інтернету." +msgstr "Вітаємо в AUR – сховищі користувацьких пакунків! Щоб встановити початковий пароль для вашого облікового запису натисніть на посилання [1] нижче. Якщо посилання не спрацьовує, скопіюйте його і вставте у ваш браузер." #: scripts/notify.py #, python-brace-format @@ -2123,8 +2227,9 @@ msgstr "Пакунок з AUR вилучено: {pkgbase}" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "{user} [1] об'єднав {old} [2] в {new} [3].\n\nЯкщо Ви не бажаєте більше отримувати повідомлень про новий пакунок, перейдіть до [3] і клацніть \"{label}\"." +msgstr "" #: scripts/notify.py #, python-brace-format diff --git a/po/zh_CN.po b/po/zh_CN.po index 15b4c74d..175ca3a2 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,6 +1,6 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: # leonfeng , 2015-2016 @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-23 12:28+0000\n" -"Last-Translator: pingplug \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-01-31 08:29+0000\n" +"Last-Translator: Lukas Fleischer\n" "Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aurweb/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -80,6 +80,10 @@ msgstr "无法获取指定用户的信息。" msgid "You do not have permission to edit this account." msgstr "您没有权限编辑此帐户。" +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表单查找存在的帐户。" @@ -374,10 +378,10 @@ msgid "Enter login credentials" msgstr "输入账户信息" #: html/login.php -msgid "User name or email address" -msgstr "用户名或 E-mail" +msgid "User name or primary email address" +msgstr "" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "密码" @@ -438,8 +442,8 @@ msgid "Your password has been reset successfully." msgstr "密码已经成功重置。" #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "确认邮箱地址:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "" #: html/passreset.php msgid "Enter your new password:" @@ -456,13 +460,13 @@ msgstr "继续" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "如果您忘记了注册账号时使用的邮件地址,请向 %saur-general%s 邮件列表寻求帮助。" +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "输入您的邮箱地址:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "" #: html/pkgbase.php msgid "Package Bases" @@ -654,19 +658,19 @@ msgstr "提交请求" msgid "Close Request" msgstr "关闭请求" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一页" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一页" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一页" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "末页" @@ -767,10 +771,18 @@ msgstr "开头和结尾是数字/英文字母" msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一个“.”,“_”,或“-”" +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "错误的 Email 地址。" +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "首页无效,请指定完整的 HTTP(s) URL。" @@ -810,6 +822,18 @@ msgstr "该地址 %s%s%s 已被使用。" msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公钥 %s%s%s 已被使用。" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1219,6 +1243,10 @@ msgstr "查看这个用户提交的软件包" msgid "Edit this user's account" msgstr "编辑此用户的帐号" +#: template/account_details.php +msgid "List this user's comments" +msgstr "" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1229,6 +1257,11 @@ msgstr "如果你想要彻底删除这个帐号,请点击%s这里%s。" msgid "Click %shere%s for user details." msgstr "点击 %s这里%s 访问用户详情页面" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "" + #: template/account_edit_form.php msgid "required" msgstr "必填" @@ -1266,8 +1299,34 @@ msgid "Hide Email Address" msgstr "隐藏 E-mail" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "确认密码" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "" #: template/account_edit_form.php msgid "Language" @@ -1277,6 +1336,16 @@ msgstr "语言" msgid "Timezone" msgstr "时区" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "确认密码" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1303,6 +1372,24 @@ msgstr "软件包更新提醒" msgid "Notify of ownership changes" msgstr "所有权更改提醒" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1431,7 +1518,7 @@ msgstr "为这个软件包投票" msgid "Disable notifications" msgstr "禁用通知" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "启用通知" @@ -1461,6 +1548,10 @@ msgstr "Git 克隆地址" msgid "read-only" msgstr "只读" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1507,9 +1598,16 @@ msgstr "编辑 %s 的评论" msgid "Add Comment" msgstr "添加评论" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "查看所有评论" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1519,6 +1617,10 @@ msgstr "已锁定评论" msgid "Latest Comments" msgstr "最新的评论" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1529,6 +1631,11 @@ msgstr "%s 在 %s 发表了评论" msgid "Anonymous comment on %s" msgstr "在 %s 发表的匿名评论" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1565,10 +1672,6 @@ msgstr "锁定评论" msgid "Unpin comment" msgstr "解锁评论" -#: template/pkg_comments.php -msgid "All comments" -msgstr "全部评论" - #: template/pkg_details.php msgid "Package Details" msgstr "软件包详情" @@ -2111,8 +2214,9 @@ msgstr "AUR 软件包删除:{pkgbase}" msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "用户 {user} [1] 将原软件包 {old} [2] 并入新软件包 {new} [3]。\n\n若您不愿再收到关于新软件包的通知,请到此软件包页面 [3] 并点击 \"{label}\"。" +msgstr "" #: scripts/notify.py #, python-brace-format diff --git a/po/zh_TW.po b/po/zh_TW.po index 43292889..5226940a 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1,16 +1,18 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the AUR package. +# This file is distributed under the same license as the AURWEB package. # # Translators: -# Jeff Huang , 2014-2017 +# byStarTW (pan93412) , 2018 +# 黃柏諺 , 2014-2017 +# 黃柏諺 , 2020 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" -"POT-Creation-Date: 2018-05-17 22:58+0200\n" -"PO-Revision-Date: 2018-05-18 04:38+0000\n" -"Last-Translator: Lukas Fleischer \n" +"POT-Creation-Date: 2020-01-31 09:29+0100\n" +"PO-Revision-Date: 2020-02-01 03:21+0000\n" +"Last-Translator: 黃柏諺 \n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aurweb/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -73,6 +75,10 @@ msgstr "無法擷取指定使用者的資訊。" msgid "You do not have permission to edit this account." msgstr "您沒有權限編輯此帳號。" +#: html/account.php lib/acctfuncs.inc.php +msgid "Invalid password." +msgstr "無效的密碼。" + #: html/account.php msgid "Use this form to search existing accounts." msgstr "使用此表單來搜尋已有的帳號。" @@ -367,10 +373,10 @@ msgid "Enter login credentials" msgstr "輸入登入資訊" #: html/login.php -msgid "User name or email address" -msgstr "使用者名稱或電子郵件地址" +msgid "User name or primary email address" +msgstr "使用者名稱或主要電子郵件地址" -#: html/login.php template/account_edit_form.php +#: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" msgstr "密碼" @@ -431,8 +437,8 @@ msgid "Your password has been reset successfully." msgstr "您的密碼已成功重置。" #: html/passreset.php -msgid "Confirm your e-mail address:" -msgstr "確認您的電子郵件位置:" +msgid "Confirm your user name or primary e-mail address:" +msgstr "確認您的使用者名稱或主要電子郵件地址:" #: html/passreset.php msgid "Enter your new password:" @@ -449,13 +455,13 @@ msgstr "繼續" #: html/passreset.php #, php-format msgid "" -"If you have forgotten the e-mail address you used to register, please send a" -" message to the %saur-general%s mailing list." -msgstr "如果您忘了您用來註冊的電子郵件地址,請寄一封訊息到 %saur-general%s 郵件列表中。" +"If you have forgotten the user name and the primary e-mail address you used " +"to register, please send a message to the %saur-general%s mailing list." +msgstr "如果您忘記了使用者名稱與您用於註冊的主要電子郵件地址,請傳送訊息到 %saur-general%s 郵件清單。" #: html/passreset.php -msgid "Enter your e-mail address:" -msgstr "輸入您的電子郵件地址:" +msgid "Enter your user name or your primary e-mail address:" +msgstr "輸入您的使用者名稱或您的主要電子郵件地址:" #: html/pkgbase.php msgid "Package Bases" @@ -531,7 +537,7 @@ msgstr "使用這個表單以棄置一個包含以下套件的套件基礎 %s%s% msgid "" "By selecting the checkbox, you confirm that you want to no longer be a " "package co-maintainer." -msgstr "" +msgstr "一核取此核取框,意味著你不想要再成為軟體包的共同維護者。" #: html/pkgdisown.php #, php-format @@ -647,19 +653,19 @@ msgstr "遞交請求" msgid "Close Request" msgstr "關閉請求" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" msgstr "第一頁" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Previous" msgstr "上一頁" -#: html/pkgreq.php lib/pkgfuncs.inc.php template/tu_list.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" msgstr "下一頁" -#: html/pkgreq.php lib/pkgfuncs.inc.php +#: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" msgstr "最後一頁" @@ -760,10 +766,18 @@ msgstr "以字母或數字當做開頭或結尾" msgid "Can contain only one period, underscore or hyphen." msgstr "最多包含一個「.」、「_」或「-」。" +#: lib/acctfuncs.inc.php +msgid "Please confirm your new password." +msgstr "請確認您的新密碼。" + #: lib/acctfuncs.inc.php msgid "The email address is invalid." msgstr "電子郵件地址無效。" +#: lib/acctfuncs.inc.php +msgid "The backup email address is invalid." +msgstr "備份電子郵件地址無效。" + #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." msgstr "首頁無效,請指定完整的 HTTP(s) URL。" @@ -803,6 +817,18 @@ msgstr "該位址 %s%s%s 已被使用。" msgid "The SSH public key, %s%s%s, is already in use." msgstr "SSH 公開金鑰,%s%s%s,已在使用中。" +#: lib/acctfuncs.inc.php +msgid "The CAPTCHA is missing." +msgstr "驗證碼遺失。" + +#: lib/acctfuncs.inc.php +msgid "This CAPTCHA has expired. Please try again." +msgstr "驗證碼已過期。請再試一次。" + +#: lib/acctfuncs.inc.php +msgid "The entered CAPTCHA answer is invalid." +msgstr "輸入的驗證碼答案無效。" + #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." @@ -1212,6 +1238,10 @@ msgstr "檢視此使用者的套件" msgid "Edit this user's account" msgstr "編輯此使用者的帳號" +#: template/account_details.php +msgid "List this user's comments" +msgstr "列出此使用者的留言" + #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." @@ -1222,6 +1252,11 @@ msgstr "如果您想要永久刪除此帳號,請點擊 %s這裡%s 。" msgid "Click %shere%s for user details." msgstr "點選 %s此處%s 來取得使用者的詳細資訊。" +#: template/account_edit_form.php +#, php-format +msgid "Click %shere%s to list the comments made by this account." +msgstr "點擊%s此處%s以列出此帳號的留言。" + #: template/account_edit_form.php msgid "required" msgstr "必填" @@ -1259,8 +1294,34 @@ msgid "Hide Email Address" msgstr "隱藏電子郵件地址" #: template/account_edit_form.php -msgid "Re-type password" -msgstr "重新輸入密碼" +msgid "" +"If you do not hide your email address, it is visible to all registered AUR " +"users. If you hide your email address, it is visible to members of the Arch " +"Linux staff only." +msgstr "如果您不隱藏您的電子郵件地址,它就是對所有已註冊的 AUR 使用者可見。如果您隱藏您的電子郵件地址,它就只對 Arch Linux 工作人員可見。" + +#: template/account_edit_form.php +msgid "Backup Email Address" +msgstr "備援電子郵件地址" + +#: template/account_edit_form.php +msgid "" +"Optionally provide a secondary email address that can be used to restore " +"your account in case you lose access to your primary email address." +msgstr "選擇性提供次要的電子郵件地址,讓您在您失去對主要電子郵件地址的存取權時,仍可復原您的帳號。" + +#: template/account_edit_form.php +msgid "" +"Password reset links are always sent to both your primary and your backup " +"email address." +msgstr "密碼重設連結一直都會同時寄往您的主要與備援電子郵件地址。" + +#: template/account_edit_form.php +#, php-format +msgid "" +"Your backup email address is always only visible to members of the Arch " +"Linux staff, independent of the %s setting." +msgstr "您的備援電子郵件地址只對 Arch Linux 工作人員可見,與 %s 設定無關。" #: template/account_edit_form.php msgid "Language" @@ -1270,6 +1331,16 @@ msgstr "語言" msgid "Timezone" msgstr "時區" +#: template/account_edit_form.php +msgid "" +"If you want to change the password, enter a new password and confirm the new" +" password by entering it again." +msgstr "如果您想要變更密碼,輸入新密碼並再輸入一次以確認新密碼。" + +#: template/account_edit_form.php +msgid "Re-type password" +msgstr "重新輸入密碼" + #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" @@ -1296,6 +1367,24 @@ msgstr "通知套件更新" msgid "Notify of ownership changes" msgstr "擁有者變更通知" +#: template/account_edit_form.php +msgid "To confirm the profile changes, please enter your current password:" +msgstr "要確認個人檔案變更,請輸入您目前的密碼:" + +#: template/account_edit_form.php +msgid "Your current password" +msgstr "您目前的密碼" + +#: template/account_edit_form.php +msgid "" +"To protect the AUR against automated account creation, we kindly ask you to " +"provide the output of the following command:" +msgstr "為了保護 AUR 不受自動建立帳號的侵擾,我們請您提供以下指令的輸出:" + +#: template/account_edit_form.php +msgid "Answer" +msgstr "回答" + #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" @@ -1424,7 +1513,7 @@ msgstr "為此套件投票" msgid "Disable notifications" msgstr "停用通知" -#: template/pkgbase_actions.php +#: template/pkgbase_actions.php template/pkg_comment_form.php msgid "Enable notifications" msgstr "啟用通知" @@ -1454,6 +1543,10 @@ msgstr "Git Clone URL" msgid "read-only" msgstr "唯讀" +#: template/pkgbase_details.php template/pkg_details.php +msgid "click to copy" +msgstr "點擊以複製" + #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" @@ -1500,9 +1593,16 @@ msgstr "編輯評論:%s" msgid "Add Comment" msgstr "新增評論" -#: template/pkg_comments.php -msgid "View all comments" -msgstr "檢視所有評論" +#: template/pkg_comment_form.php +msgid "" +"Git commit identifiers referencing commits in the AUR package repository and" +" URLs are converted to links automatically." +msgstr "引用 AUR 軟體庫的 Git 遞交識別符,URL 會自動轉換為連結。" + +#: template/pkg_comment_form.php +#, php-format +msgid "%sMarkdown syntax%s is partially supported." +msgstr "部份支援 %sMarkdown 語法%s" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1512,6 +1612,10 @@ msgstr "已釘選評論" msgid "Latest Comments" msgstr "最新的評論" +#: template/pkg_comments.php +msgid "Comments for" +msgstr "評論" + #: template/pkg_comments.php #, php-format msgid "%s commented on %s" @@ -1522,6 +1626,11 @@ msgstr "%s 在 %s 上評論" msgid "Anonymous comment on %s" msgstr "在 %s 上的匿名評論" +#: template/pkg_comments.php +#, php-format +msgid "Commented on package %s on %s" +msgstr "在軟體包 %s 的 %s 評論" + #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" @@ -1558,10 +1667,6 @@ msgstr "釘選評論" msgid "Unpin comment" msgstr "解除釘選評論" -#: template/pkg_comments.php -msgid "All comments" -msgstr "所有評論" - #: template/pkg_details.php msgid "Package Details" msgstr "套件詳細資訊" @@ -2006,7 +2111,7 @@ msgstr "返回" #: scripts/notify.py msgid "AUR Password Reset" -msgstr "" +msgstr "AUR 密碼重設" #: scripts/notify.py #, python-brace-format @@ -2014,98 +2119,99 @@ msgid "" "A password reset request was submitted for the account {user} associated " "with your email address. If you wish to reset your password follow the link " "[1] below, otherwise ignore this message and nothing will happen." -msgstr "" +msgstr "有一個關於您帳號 {user} 對應到電子信箱的密碼重設請求。若您想要重設您的密碼,請前往以下的網址 [1],否則忽略這訊息就沒事了。" #: scripts/notify.py msgid "Welcome to the Arch User Repository" -msgstr "" +msgstr "歡迎來到 Arch 使用者軟體庫" #: scripts/notify.py msgid "" "Welcome to the Arch User Repository! In order to set an initial password for" " your new account, please click the link [1] below. If the link does not " "work, try copying and pasting it into your browser." -msgstr "" +msgstr "歡迎來到 Arch 使用者軟體庫!為了要設定您新帳號的初始密碼,請點擊以下的連結 [1]。若連結沒辦法點擊,請嘗試複製並貼上連結到您的瀏覽器中。 " #: scripts/notify.py #, python-brace-format msgid "AUR Comment for {pkgbase}" -msgstr "" +msgstr "{pkgbase} 的 AUR 評論" #: scripts/notify.py #, python-brace-format msgid "{user} [1] added the following comment to {pkgbase} [2]:" -msgstr "" +msgstr "{user} [1] 加入以下留言到 {pkgbase} [2]:" #: scripts/notify.py #, python-brace-format msgid "" "If you no longer wish to receive notifications about this package, please go" " to the package page [2] and select \"{label}\"." -msgstr "" +msgstr "若您不再想收到此軟體包的通知,請前往軟體包頁面 [2] 並選擇「{label}」。" #: scripts/notify.py #, python-brace-format msgid "AUR Package Update: {pkgbase}" -msgstr "" +msgstr "AUR 軟體包更新:{pkgbase}" #: scripts/notify.py #, python-brace-format msgid "{user} [1] pushed a new commit to {pkgbase} [2]." -msgstr "" +msgstr "{user} [1] 推送了新的提交到 {pkgbase} [2]。" #: scripts/notify.py #, python-brace-format msgid "AUR Out-of-date Notification for {pkgbase}" -msgstr "" +msgstr "{pkgbase} 的 AUR 過期通知" #: scripts/notify.py #, python-brace-format msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" -msgstr "" +msgstr "您的軟體包 {pkgbase} [1] 已經被 {user} [2] 使用者標記為過期:" #: scripts/notify.py #, python-brace-format msgid "AUR Ownership Notification for {pkgbase}" -msgstr "" +msgstr "{pkgbase} 的 AUR 所有權通知" #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was adopted by {user} [2]." -msgstr "" +msgstr "軟體包 {pkgbase} [1] 已經被 {user} [2] 使用者採用。" #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was disowned by {user} [2]." -msgstr "" +msgstr "軟體包 {pkgbase} [1] 已經被 {user} [2] 使用者拋棄。" #: scripts/notify.py #, python-brace-format msgid "AUR Co-Maintainer Notification for {pkgbase}" -msgstr "" +msgstr "{pkgbase} 的 AUR 共同維護者通知" #: scripts/notify.py #, python-brace-format msgid "You were added to the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "您已經加入到 {pkgbase} [1] 的共同維護者列表中。" #: scripts/notify.py #, python-brace-format msgid "You were removed from the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "您已經從 {pkgbase} [1] 的共同維護者列表中移除了。" #: scripts/notify.py #, python-brace-format msgid "AUR Package deleted: {pkgbase}" -msgstr "" +msgstr "已刪除 AUR 軟體包:{pkgbase}" #: scripts/notify.py #, python-brace-format msgid "" "{user} [1] merged {old} [2] into {new} [3].\n" "\n" +"-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "" +msgstr "{user} [1] 已合併 {old} [2] 到 {new} [3].\n\n-- \n如果您不想要再收到關於新軟體包的通知,請到 [3] 然後點擊「{label}」。" #: scripts/notify.py #, python-brace-format @@ -2113,16 +2219,16 @@ msgid "" "{user} [1] deleted {pkgbase} [2].\n" "\n" "You will no longer receive notifications about this package." -msgstr "" +msgstr "{user} [1] 已經刪除 {pkgbase} [2]。\n\n您將再也不會收到此軟體包的通知。" #: scripts/notify.py #, python-brace-format msgid "TU Vote Reminder: Proposal {id}" -msgstr "" +msgstr "TU 投票提醒:編號為 {id} 的建議" #: scripts/notify.py #, python-brace-format msgid "" "Please remember to cast your vote on proposal {id} [1]. The voting period " "ends in less than 48 hours." -msgstr "" +msgstr "請記得在第 {id} [1] 號建議投下你的投票,投票期限即將在 48 個小時內結束。" From 3f2654e79e70caa828f3464386b0a3367cbac758 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 10 Feb 2020 15:25:03 +0100 Subject: [PATCH 0505/1891] Update README and convert to Markdown syntax Signed-off-by: Lukas Fleischer --- README => README.md | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) rename README => README.md (73%) diff --git a/README b/README.md similarity index 73% rename from README rename to README.md index e633ec3f..a4ab584e 100644 --- a/README +++ b/README.md @@ -17,32 +17,14 @@ The aurweb project includes Directory Layout ---------------- -aurweb:: - aurweb Python modules. - -conf:: - Configuration and configuration templates. - -doc:: - Project documentation. - -po:: - Translation files for strings in the aurweb interface. - -schema:: - Schema for the SQL database. Script for dummy data generation. - -scripts:: - Scripts for AUR maintenance. - -test:: - Test suite and test cases. - -upgrading:: - Instructions for upgrading setups from one release to another. - -web:: - Web interface for the AUR. +* `aurweb`: aurweb Python modules, Git interface and maintenance scripts +* `conf`: configuration and configuration templates +* `doc`: project documentation +* `po`: translation files for strings in the aurweb interface +* `schema`: schema for the SQL database +* `test`: test suite and test cases +* `upgrading`: instructions for upgrading setups from one release to another +* `web`: web interface for the AUR Links ----- From de549fb2d5063394f91e06f366bc5d426f5f0891 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 7 Feb 2020 13:22:29 +0100 Subject: [PATCH 0506/1891] Support smtplib for sending emails Support mail delivery without a local MTA. Instead, an SMTP server can now be configured using the smtp-server option in the [notifications] section. In order to use this option, the value of the sendmail option must be empty. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 22 ++++++++++++++++++---- conf/config.defaults | 3 ++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index b0f218b5..6c5c709e 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 import email.mime.text +import email.utils +import smtplib import subprocess import sys import textwrap @@ -63,7 +65,6 @@ class Notification: return body.rstrip() def send(self): - sendmail = aurweb.config.get('notifications', 'sendmail') sender = aurweb.config.get('notifications', 'sender') reply_to = aurweb.config.get('notifications', 'reply-to') reason = self.__class__.__name__ @@ -79,13 +80,26 @@ class Notification: msg['Reply-to'] = reply_to msg['To'] = to msg['X-AUR-Reason'] = reason + msg['Date'] = email.utils.formatdate(localtime=True) for key, value in self.get_headers().items(): msg[key] = value - p = subprocess.Popen([sendmail, '-t', '-oi'], - stdin=subprocess.PIPE) - p.communicate(msg.as_bytes()) + sendmail = aurweb.config.get('notifications', 'sendmail') + if sendmail: + # send email using the sendmail binary specified in the + # configuration file + p = subprocess.Popen([sendmail, '-t', '-oi'], + stdin=subprocess.PIPE) + p.communicate(msg.as_bytes()) + else: + # send email using smtplib; no local MTA required + server_addr = aurweb.config.get('notifications', 'smtp-server') + + server = smtplib.SMTP(server_addr) + server.set_debuglevel(0) + server.sendmail(sender, recipient, msg.as_bytes()) + server.quit() class ResetKeyNotification(Notification): diff --git a/conf/config.defaults b/conf/config.defaults index c519eae6..23d46b06 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -47,7 +47,8 @@ window_length = 86400 [notifications] notify-cmd = /usr/local/bin/aurweb-notify -sendmail = /usr/bin/sendmail +sendmail = +smtp-server = localhost sender = notify@aur.archlinux.org reply-to = noreply@aur.archlinux.org From b855ce9452ed7b83d0f6f538a17755918cc4132f Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 7 Feb 2020 13:44:29 +0100 Subject: [PATCH 0507/1891] Make SMTP port and authentication configurable Add more options to configure the smtplib implementation for sending notification emails. The port can be changed using the new smtp-port option. Encryption can be configured using smtp-use-ssl and smtp-use-starttls. Keep in mind that you usually also need to change the port when enabling either of these options. Authentication can be configured using smtp-user and smtp-password. Authentication is disabled if either of these values is empty. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 20 +++++++++++++++++++- conf/config.defaults | 5 +++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 6c5c709e..5b18a476 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -65,6 +65,7 @@ class Notification: return body.rstrip() def send(self): + sendmail = aurweb.config.get('notifications', 'sendmail') sender = aurweb.config.get('notifications', 'sender') reply_to = aurweb.config.get('notifications', 'reply-to') reason = self.__class__.__name__ @@ -95,8 +96,25 @@ class Notification: else: # send email using smtplib; no local MTA required server_addr = aurweb.config.get('notifications', 'smtp-server') + server_port = aurweb.config.getint('notifications', 'smtp-port') + use_ssl = aurweb.config.getboolean('notifications', 'smtp-use-ssl') + use_starttls = aurweb.config.getboolean('notifications', 'smtp-use-starttls') + user = aurweb.config.get('notifications', 'smtp-user') + passwd = aurweb.config.get('notifications', 'smtp-password') + + if use_ssl: + server = smtplib.SMTP_SSL(server_addr, server_port) + else: + server = smtplib.SMTP(server_addr, server_port) + + if use_starttls: + server.ehlo() + server.starttls() + server.ehlo() + + if user and passwd: + server.login(user, passwd) - server = smtplib.SMTP(server_addr) server.set_debuglevel(0) server.sendmail(sender, recipient, msg.as_bytes()) server.quit() diff --git a/conf/config.defaults b/conf/config.defaults index 23d46b06..b69d0312 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -49,6 +49,11 @@ window_length = 86400 notify-cmd = /usr/local/bin/aurweb-notify sendmail = smtp-server = localhost +smtp-port = 25 +smtp-use-ssl = 0 +smtp-use-starttls = 0 +smtp-user = +smtp-password = sender = notify@aur.archlinux.org reply-to = noreply@aur.archlinux.org From 65c98d12161906ab680fc2c9572f7c78b16efd82 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 11 Feb 2020 13:21:26 +0100 Subject: [PATCH 0508/1891] Use relative URIs for {source_file,log,commit}_uri Signed-off-by: Lukas Fleischer --- conf/config.defaults | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/config.defaults b/conf/config.defaults index b69d0312..447dacac 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -28,9 +28,9 @@ request_idle_time = 1209600 request_archive_time = 15552000 auto_orphan_age = 15552000 auto_delete_age = 86400 -source_file_uri = https://aur.archlinux.org/cgit/aur.git/tree/%s?h=%s -log_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s -commit_uri = https://aur.archlinux.org/cgit/aur.git/commit/?h=%s&id=%s +source_file_uri = /cgit/aur.git/tree/%s?h=%s +log_uri = /cgit/aur.git/log/?h=%s +commit_uri = /cgit/aur.git/commit/?h=%s&id=%s snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 From 5ca1e271f9023b41b613313745bc700dc15d802f Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 12 Feb 2020 15:16:37 -0500 Subject: [PATCH 0509/1891] Fix PHP 7.4 warnings If a db query returned NULL instead of an array, then accessing $row[0] now throws a warning. The undocumented behavior of evaluating to NULL is maintained, and we want to return NULL anyway, so add a check for the value and fall back on the default function return type. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/lib/aur.inc.php | 28 +++++++++++++++++++++------- web/lib/pkgfuncs.inc.php | 4 +++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index e9530fc0..dbcc23a4 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -197,7 +197,9 @@ function username_from_id($id) { } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** @@ -222,7 +224,9 @@ function username_from_sid($sid="") { } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** @@ -339,7 +343,9 @@ function email_from_sid($sid="") { } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** @@ -365,7 +371,9 @@ function account_from_sid($sid="") { } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** @@ -390,7 +398,9 @@ function uid_from_sid($sid="") { } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** @@ -512,7 +522,9 @@ function uid_from_username($username) { } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** @@ -546,7 +558,9 @@ function uid_from_email($email) { } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index a4cd17ac..8c915711 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -147,7 +147,9 @@ function pkg_from_name($name="") { return; } $row = $result->fetch(PDO::FETCH_NUM); - return $row[0]; + if ($row) { + return $row[0]; + } } /** From 050b08081a48887bcf03e9d943a1370aac949518 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Wed, 12 Feb 2020 15:16:38 -0500 Subject: [PATCH 0510/1891] Fix more PHP 7.4 warnings The try_login() function documents it returns an array containing an 'error' key, and our only caller *only* consults the 'error' key. Then the function returns null instead of an array, if the login succeeded! I question why we bother returning the new SID if we never use it, surely we could either return the error or return default null. But, for now, I'm just going to fix it to return what it's actually supposed to, without changing the API. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 443fb4b1..d238c0e0 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -659,6 +659,7 @@ function try_login() { } header("Location: " . get_uri($referer)); $login_error = ""; + return array('SID' => $new_sid, 'error' => null); } /** From 33d8fe035eab204f09363ace55a002c739050fa0 Mon Sep 17 00:00:00 2001 From: Yaron Shahrabani Date: Fri, 21 Feb 2020 09:25:12 +0200 Subject: [PATCH 0511/1891] README.md: fix a small typo Signed-off-by: Lukas Fleischer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a4ab584e..b2095b3f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ and installed using the Arch Linux package manager `pacman`. The aurweb project includes * A web interface to search for packaging scripts and display package details. -* A SSH/Git interface to submit and update packages and package meta data. +* An SSH/Git interface to submit and update packages and package meta data. * Community features such as comments, votes, package flagging and requests. * Editing/deletion of packages and accounts by Trusted Users and Developers. * Area for Trusted Users to post AUR-related proposals and vote on them. From afe3f5d0e562104fb930b650ca799ba433a68c2e Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 21 Feb 2020 10:41:29 +0100 Subject: [PATCH 0512/1891] README.md: add references to Transifex Signed-off-by: Lukas Fleischer --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index b2095b3f..f7285a51 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,11 @@ Links * Questions, comments, and patches related to aurweb can be sent to the AUR development mailing list: aur-dev@archlinux.org -- mailing list archives: https://mailman.archlinux.org/mailman/listinfo/aur-dev + +Translations +------------ + +Translations are welcome via our Transifex project at +https://www.transifex.com/lfleischer/aurweb; see `doc/i18n.txt` for details. + +![Transifex](http://www.transifex.net/projects/p/aurweb/chart/image_png) From cbab9870c1388f2d60a8d6cfbb936c384c1b58b6 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sat, 22 Feb 2020 12:06:17 +0100 Subject: [PATCH 0513/1891] Fix HTML code in the account search results table Do not add an opening

    tag for every row. Instead, wrap all rows in . While at it, also simplify the code used to color the rows. Signed-off-by: Lukas Fleischer --- web/template/account_search_results.php | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/web/template/account_search_results.php b/web/template/account_search_results.php index 81cd8185..0f7eb7a4 100644 --- a/web/template/account_search_results.php +++ b/web/template/account_search_results.php @@ -16,17 +16,9 @@ else: - $row): - if ($i % 2): - $c = "even"; - else: - $c = "odd"; - endif; - ?> - - + + $row): ?> + - + +
    "> @@ -49,10 +41,8 @@ else:
    From 4b2102ceb26b77bc8ee3e9b9d8929a915f1e65a9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 27 Feb 2020 16:44:04 +0100 Subject: [PATCH 0514/1891] Properly escape passwords in the account edit form Addresses FS#65639. Signed-off-by: Lukas Fleischer --- web/template/account_edit_form.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index a4ea9949..4ce6b875 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -157,12 +157,12 @@

    - +

    - +

    From 7188743fc3b1a9c1f5f65e323a6502d018bd95d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 16 Feb 2020 21:56:10 +0100 Subject: [PATCH 0515/1891] Migrate the database schema to SQLAlchemy The new schema was generated with sqlacodegen and then manually adjusted to fit schema/aur-schema.sql faithfully, both in the organisation of the code and in the SQL generated by SQLAlchemy. Initializing the database now requires the new tool aurweb.initdb. References to aur-schema.sql have been updated and the old schema dropped. Signed-off-by: Lukas Fleischer --- INSTALL | 12 +- TESTING | 23 +-- aurweb/db.py | 27 +++ aurweb/initdb.py | 47 +++++ aurweb/schema.py | 387 ++++++++++++++++++++++++++++++++++++++ schema/Makefile | 12 -- schema/aur-schema.sql | 415 ----------------------------------------- schema/reloadtestdb.sh | 29 --- test/Makefile | 6 +- test/setup.sh | 5 +- 10 files changed, 481 insertions(+), 482 deletions(-) create mode 100644 aurweb/initdb.py create mode 100644 aurweb/schema.py delete mode 100644 schema/Makefile delete mode 100644 schema/aur-schema.sql delete mode 100755 schema/reloadtestdb.sh diff --git a/INSTALL b/INSTALL index 7170aea1..68fe5dcd 100644 --- a/INSTALL +++ b/INSTALL @@ -45,16 +45,16 @@ read the instructions below. if the defaults file does not exist) and adjust the configuration (pay attention to disable_http_login, enable_maintenance and aur_location). -4) Create a new MySQL database and a user and import the aurweb SQL schema: +4) Install Python modules and dependencies: - $ mysql -uaur -p AUR = 1)) + aurweb.schema.metadata.create_all(engine) + feed_initial_data(engine.connect()) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + prog='python -m aurweb.initdb', + description='Initialize the aurweb database.') + parser.add_argument('-v', '--verbose', action='count', default=0, + help='increase verbosity') + args = parser.parse_args() + run(args) diff --git a/aurweb/schema.py b/aurweb/schema.py new file mode 100644 index 00000000..b1261e86 --- /dev/null +++ b/aurweb/schema.py @@ -0,0 +1,387 @@ +from sqlalchemy import CHAR, Column, ForeignKey, Index, MetaData, String, TIMESTAMP, Table, Text, text +from sqlalchemy.dialects.mysql import BIGINT, DECIMAL, INTEGER, TINYINT +from sqlalchemy.ext.compiler import compiles + + +@compiles(TINYINT, 'sqlite') +def compile_tinyint_sqlite(type_, compiler, **kw): + """TINYINT is not supported on SQLite. Substitute it with INTEGER.""" + return 'INTEGER' + + +metadata = MetaData() + +# Define the Account Types for the AUR. +AccountTypes = Table( + 'AccountTypes', metadata, + Column('ID', TINYINT(unsigned=True), primary_key=True), + Column('AccountType', String(32), nullable=False, server_default=text("''")), + mysql_engine='InnoDB', +) + + +# User information for each user regardless of type. +Users = Table( + 'Users', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('AccountTypeID', ForeignKey('AccountTypes.ID', ondelete="NO ACTION"), nullable=False, server_default=text("1")), + Column('Suspended', TINYINT(unsigned=True), nullable=False, server_default=text("0")), + Column('Username', String(32), nullable=False, unique=True), + Column('Email', String(254), nullable=False, unique=True), + Column('BackupEmail', String(254)), + Column('HideEmail', TINYINT(unsigned=True), nullable=False, server_default=text("0")), + Column('Passwd', String(255), nullable=False), + Column('Salt', CHAR(32), nullable=False, server_default=text("''")), + Column('ResetKey', CHAR(32), nullable=False, server_default=text("''")), + Column('RealName', String(64), nullable=False, server_default=text("''")), + Column('LangPreference', String(6), nullable=False, server_default=text("'en'")), + Column('Timezone', String(32), nullable=False, server_default=text("'UTC'")), + Column('Homepage', Text), + Column('IRCNick', String(32), nullable=False, server_default=text("''")), + Column('PGPKey', String(40)), + Column('LastLogin', BIGINT(unsigned=True), nullable=False, server_default=text("0")), + Column('LastLoginIPAddress', String(45)), + Column('LastSSHLogin', BIGINT(unsigned=True), nullable=False, server_default=text("0")), + Column('LastSSHLoginIPAddress', String(45)), + Column('InactivityTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), + Column('RegistrationTS', TIMESTAMP, nullable=False, server_default=text("CURRENT_TIMESTAMP")), + Column('CommentNotify', TINYINT(1), nullable=False, server_default=text("1")), + Column('UpdateNotify', TINYINT(1), nullable=False, server_default=text("0")), + Column('OwnershipNotify', TINYINT(1), nullable=False, server_default=text("1")), + Index('UsersAccountTypeID', 'AccountTypeID'), + mysql_engine='InnoDB', +) + + +# SSH public keys used for the aurweb SSH/Git interface. +SSHPubKeys = Table( + 'SSHPubKeys', metadata, + Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + Column('Fingerprint', String(44), primary_key=True), + Column('PubKey', String(4096), nullable=False), + mysql_engine='InnoDB', +) + + +# Track Users logging in/out of AUR web site. +Sessions = Table( + 'Sessions', metadata, + Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + Column('SessionID', CHAR(32), nullable=False, unique=True), + Column('LastUpdateTS', BIGINT(unsigned=True), nullable=False), + mysql_engine='InnoDB', +) + + +# Information on package bases +PackageBases = Table( + 'PackageBases', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('Name', String(255), nullable=False, unique=True), + Column('NumVotes', INTEGER(unsigned=True), nullable=False, server_default=text("0")), + Column('Popularity', DECIMAL(10, 6, unsigned=True), nullable=False, server_default=text("0")), + Column('OutOfDateTS', BIGINT(unsigned=True)), + Column('FlaggerComment', Text, nullable=False), + Column('SubmittedTS', BIGINT(unsigned=True), nullable=False), + Column('ModifiedTS', BIGINT(unsigned=True), nullable=False), + Column('FlaggerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # who flagged the package out-of-date? + # deleting a user will cause packages to be orphaned, not deleted + Column('SubmitterUID', ForeignKey('Users.ID', ondelete='SET NULL')), # who submitted it? + Column('MaintainerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # User + Column('PackagerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # Last packager + Index('BasesMaintainerUID', 'MaintainerUID'), + Index('BasesNumVotes', 'NumVotes'), + Index('BasesPackagerUID', 'PackagerUID'), + Index('BasesSubmitterUID', 'SubmitterUID'), + mysql_engine='InnoDB', +) + + +# Keywords of package bases +PackageKeywords = Table( + 'PackageKeywords', metadata, + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + Column('Keyword', String(255), primary_key=True, nullable=False, server_default=text("''")), + mysql_engine='InnoDB', +) + + +# Information about the actual packages +Packages = Table( + 'Packages', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), + Column('Name', String(255), nullable=False, unique=True), + Column('Version', String(255), nullable=False, server_default=text("''")), + Column('Description', String(255)), + Column('URL', String(8000)), + mysql_engine='InnoDB', +) + + +# Information about licenses +Licenses = Table( + 'Licenses', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('Name', String(255), nullable=False, unique=True), + mysql_engine='InnoDB', +) + + +# Information about package-license-relations +PackageLicenses = Table( + 'PackageLicenses', metadata, + Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + Column('LicenseID', ForeignKey('Licenses.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + mysql_engine='InnoDB', +) + + +# Information about groups +Groups = Table( + 'Groups', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('Name', String(255), nullable=False, unique=True), + mysql_engine='InnoDB', +) + + +# Information about package-group-relations +PackageGroups = Table( + 'PackageGroups', metadata, + Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + Column('GroupID', ForeignKey('Groups.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + mysql_engine='InnoDB', +) + + +# Define the package dependency types +DependencyTypes = Table( + 'DependencyTypes', metadata, + Column('ID', TINYINT(unsigned=True), primary_key=True), + Column('Name', String(32), nullable=False, server_default=text("''")), + mysql_engine='InnoDB', +) + + +# Track which dependencies a package has +PackageDepends = Table( + 'PackageDepends', metadata, + Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False), + Column('DepTypeID', ForeignKey('DependencyTypes.ID', ondelete="NO ACTION"), nullable=False), + Column('DepName', String(255), nullable=False), + Column('DepDesc', String(255)), + Column('DepCondition', String(255)), + Column('DepArch', String(255)), + Index('DependsDepName', 'DepName'), + Index('DependsPackageID', 'PackageID'), + mysql_engine='InnoDB', +) + + +# Define the package relation types +RelationTypes = Table( + 'RelationTypes', metadata, + Column('ID', TINYINT(unsigned=True), primary_key=True), + Column('Name', String(32), nullable=False, server_default=text("''")), + mysql_engine='InnoDB', +) + + +# Track which conflicts, provides and replaces a package has +PackageRelations = Table( + 'PackageRelations', metadata, + Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False), + Column('RelTypeID', ForeignKey('RelationTypes.ID', ondelete="NO ACTION"), nullable=False), + Column('RelName', String(255), nullable=False), + Column('RelCondition', String(255)), + Column('RelArch', String(255)), + Index('RelationsPackageID', 'PackageID'), + Index('RelationsRelName', 'RelName'), + mysql_engine='InnoDB', +) + + +# Track which sources a package has +PackageSources = Table( + 'PackageSources', metadata, + Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False), + Column('Source', String(8000), nullable=False, server_default=text("'/dev/null'")), + Column('SourceArch', String(255)), + Index('SourcesPackageID', 'PackageID'), + mysql_engine='InnoDB', +) + + +# Track votes for packages +PackageVotes = Table( + 'PackageVotes', metadata, + Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), + Column('VoteTS', BIGINT(unsigned=True)), + Index('VoteUsersIDPackageID', 'UsersID', 'PackageBaseID', unique=True), + Index('VotesPackageBaseID', 'PackageBaseID'), + Index('VotesUsersID', 'UsersID'), + mysql_engine='InnoDB', +) + + +# Record comments for packages +PackageComments = Table( + 'PackageComments', metadata, + Column('ID', BIGINT(unsigned=True), primary_key=True), + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), + Column('UsersID', ForeignKey('Users.ID', ondelete='SET NULL')), + Column('Comments', Text, nullable=False), + Column('RenderedComment', Text, nullable=False), + Column('CommentTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), + Column('EditedTS', BIGINT(unsigned=True)), + Column('EditedUsersID', ForeignKey('Users.ID', ondelete='SET NULL')), + Column('DelTS', BIGINT(unsigned=True)), + Column('DelUsersID', ForeignKey('Users.ID', ondelete='CASCADE')), + Column('PinnedTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), + Index('CommentsPackageBaseID', 'PackageBaseID'), + Index('CommentsUsersID', 'UsersID'), + mysql_engine='InnoDB', +) + + +# Package base co-maintainers +PackageComaintainers = Table( + 'PackageComaintainers', metadata, + Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), + Column('Priority', INTEGER(unsigned=True), nullable=False), + Index('ComaintainersPackageBaseID', 'PackageBaseID'), + Index('ComaintainersUsersID', 'UsersID'), + mysql_engine='InnoDB', +) + + +# Package base notifications +PackageNotifications = Table( + 'PackageNotifications', metadata, + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), + Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + Index('NotifyUserIDPkgID', 'UserID', 'PackageBaseID', unique=True), + mysql_engine='InnoDB', +) + + +# Package name blacklist +PackageBlacklist = Table( + 'PackageBlacklist', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('Name', String(64), nullable=False, unique=True), + mysql_engine='InnoDB', +) + + +# Providers in the official repositories +OfficialProviders = Table( + 'OfficialProviders', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('Name', String(64), nullable=False), + Column('Repo', String(64), nullable=False), + Column('Provides', String(64), nullable=False), + Index('ProviderNameProvides', 'Name', 'Provides', unique=True), + mysql_engine='InnoDB', +) + + +# Define package request types +RequestTypes = Table( + 'RequestTypes', metadata, + Column('ID', TINYINT(unsigned=True), primary_key=True), + Column('Name', String(32), nullable=False, server_default=text("''")), + mysql_engine='InnoDB', +) + + +# Package requests +PackageRequests = Table( + 'PackageRequests', metadata, + Column('ID', BIGINT(unsigned=True), primary_key=True), + Column('ReqTypeID', ForeignKey('RequestTypes.ID', ondelete="NO ACTION"), nullable=False), + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='SET NULL')), + Column('PackageBaseName', String(255), nullable=False), + Column('MergeBaseName', String(255)), + Column('UsersID', ForeignKey('Users.ID', ondelete='SET NULL')), + Column('Comments', Text, nullable=False), + Column('ClosureComment', Text, nullable=False), + Column('RequestTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), + Column('ClosedTS', BIGINT(unsigned=True)), + Column('ClosedUID', ForeignKey('Users.ID', ondelete='SET NULL')), + Column('Status', TINYINT(unsigned=True), nullable=False, server_default=text("0")), + Index('RequestsPackageBaseID', 'PackageBaseID'), + Index('RequestsUsersID', 'UsersID'), + mysql_engine='InnoDB', +) + + +# Vote information +TU_VoteInfo = Table( + 'TU_VoteInfo', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('Agenda', Text, nullable=False), + Column('User', String(32), nullable=False), + Column('Submitted', BIGINT(unsigned=True), nullable=False), + Column('End', BIGINT(unsigned=True), nullable=False), + Column('Quorum', DECIMAL(2, 2, unsigned=True), nullable=False), + Column('SubmitterID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + Column('Yes', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), + Column('No', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), + Column('Abstain', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), + Column('ActiveTUs', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), + mysql_engine='InnoDB', +) + + +# Individual vote records +TU_Votes = Table( + 'TU_Votes', metadata, + Column('VoteID', ForeignKey('TU_VoteInfo.ID', ondelete='CASCADE'), nullable=False), + Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + mysql_engine='InnoDB', +) + + +# Malicious user banning +Bans = Table( + 'Bans', metadata, + Column('IPAddress', String(45), primary_key=True), + Column('BanTS', TIMESTAMP, nullable=False), + mysql_engine='InnoDB', +) + + +# Terms and Conditions +Terms = Table( + 'Terms', metadata, + Column('ID', INTEGER(unsigned=True), primary_key=True), + Column('Description', String(255), nullable=False), + Column('URL', String(8000), nullable=False), + Column('Revision', INTEGER(unsigned=True), nullable=False, server_default=text("1")), + mysql_engine='InnoDB', +) + + +# Terms and Conditions accepted by users +AcceptedTerms = Table( + 'AcceptedTerms', metadata, + Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), + Column('TermsID', ForeignKey('Terms.ID', ondelete='CASCADE'), nullable=False), + Column('Revision', INTEGER(unsigned=True), nullable=False, server_default=text("0")), + mysql_engine='InnoDB', +) + + +# Rate limits for API +ApiRateLimit = Table( + 'ApiRateLimit', metadata, + Column('IP', String(45), primary_key=True), + Column('Requests', INTEGER(11), nullable=False), + Column('WindowStart', BIGINT(20), nullable=False), + Index('ApiRateLimitWindowStart', 'WindowStart'), + mysql_engine='InnoDB', +) diff --git a/schema/Makefile b/schema/Makefile deleted file mode 100644 index 62d08567..00000000 --- a/schema/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -aur-schema-sqlite.sql: aur-schema.sql - sed \ - -e 's/ ENGINE = InnoDB//' \ - -e 's/ [A-Z]* UNSIGNED NOT NULL AUTO_INCREMENT/ INTEGER NOT NULL/' \ - -e 's/([0-9, ]*) UNSIGNED / UNSIGNED /' \ - -e 's/ MySQL / SQLite /' \ - $< >$@ - -clean: - rm -rf aur-schema-sqlite.sql - -.PHONY: clean diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql deleted file mode 100644 index 1f86df20..00000000 --- a/schema/aur-schema.sql +++ /dev/null @@ -1,415 +0,0 @@ --- The MySQL database layout for the AUR. Certain data --- is also included such as AccountTypes, etc. --- - --- Define the Account Types for the AUR. --- -CREATE TABLE AccountTypes ( - ID TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, - AccountType VARCHAR(32) NOT NULL DEFAULT '', - PRIMARY KEY (ID) -) ENGINE = InnoDB; -INSERT INTO AccountTypes (ID, AccountType) VALUES (1, 'User'); -INSERT INTO AccountTypes (ID, AccountType) VALUES (2, 'Trusted User'); -INSERT INTO AccountTypes (ID, AccountType) VALUES (3, 'Developer'); -INSERT INTO AccountTypes (ID, AccountType) VALUES (4, 'Trusted User & Developer'); - - --- User information for each user regardless of type. --- -CREATE TABLE Users ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - AccountTypeID TINYINT UNSIGNED NOT NULL DEFAULT 1, - Suspended TINYINT UNSIGNED NOT NULL DEFAULT 0, - Username VARCHAR(32) NOT NULL, - Email VARCHAR(254) NOT NULL, - BackupEmail VARCHAR(254) NULL DEFAULT NULL, - HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0, - Passwd VARCHAR(255) NOT NULL, - Salt CHAR(32) NOT NULL DEFAULT '', - ResetKey CHAR(32) NOT NULL DEFAULT '', - RealName VARCHAR(64) NOT NULL DEFAULT '', - LangPreference VARCHAR(6) NOT NULL DEFAULT 'en', - Timezone VARCHAR(32) NOT NULL DEFAULT 'UTC', - Homepage TEXT NULL DEFAULT NULL, - IRCNick VARCHAR(32) NOT NULL DEFAULT '', - PGPKey VARCHAR(40) NULL DEFAULT NULL, - LastLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, - LastLoginIPAddress VARCHAR(45) NULL DEFAULT NULL, - LastSSHLogin BIGINT UNSIGNED NOT NULL DEFAULT 0, - LastSSHLoginIPAddress VARCHAR(45) NULL DEFAULT NULL, - InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0, - RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CommentNotify TINYINT(1) NOT NULL DEFAULT 1, - UpdateNotify TINYINT(1) NOT NULL DEFAULT 0, - OwnershipNotify TINYINT(1) NOT NULL DEFAULT 1, - PRIMARY KEY (ID), - UNIQUE (Username), - UNIQUE (Email), - FOREIGN KEY (AccountTypeID) REFERENCES AccountTypes(ID) ON DELETE NO ACTION -) ENGINE = InnoDB; -CREATE INDEX UsersAccountTypeID ON Users (AccountTypeID); - - --- SSH public keys used for the aurweb SSH/Git interface. --- -CREATE TABLE SSHPubKeys ( - UserID INTEGER UNSIGNED NOT NULL, - Fingerprint VARCHAR(44) NOT NULL, - PubKey VARCHAR(4096) NOT NULL, - PRIMARY KEY (Fingerprint), - FOREIGN KEY (UserID) REFERENCES Users(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - - --- Track Users logging in/out of AUR web site. --- -CREATE TABLE Sessions ( - UsersID INTEGER UNSIGNED NOT NULL, - SessionID CHAR(32) NOT NULL, - LastUpdateTS BIGINT UNSIGNED NOT NULL, - FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, - UNIQUE (SessionID) -) ENGINE = InnoDB; - - --- Information on package bases --- -CREATE TABLE PackageBases ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(255) NOT NULL, - NumVotes INTEGER UNSIGNED NOT NULL DEFAULT 0, - Popularity DECIMAL(10,6) UNSIGNED NOT NULL DEFAULT 0, - OutOfDateTS BIGINT UNSIGNED NULL DEFAULT NULL, - FlaggerComment TEXT NOT NULL, - SubmittedTS BIGINT UNSIGNED NOT NULL, - ModifiedTS BIGINT UNSIGNED NOT NULL, - FlaggerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- who flagged the package out-of-date? - SubmitterUID INTEGER UNSIGNED NULL DEFAULT NULL, -- who submitted it? - MaintainerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- User - PackagerUID INTEGER UNSIGNED NULL DEFAULT NULL, -- Last packager - PRIMARY KEY (ID), - UNIQUE (Name), - FOREIGN KEY (FlaggerUID) REFERENCES Users(ID) ON DELETE SET NULL, - -- deleting a user will cause packages to be orphaned, not deleted - FOREIGN KEY (SubmitterUID) REFERENCES Users(ID) ON DELETE SET NULL, - FOREIGN KEY (MaintainerUID) REFERENCES Users(ID) ON DELETE SET NULL, - FOREIGN KEY (PackagerUID) REFERENCES Users(ID) ON DELETE SET NULL -) ENGINE = InnoDB; -CREATE INDEX BasesNumVotes ON PackageBases (NumVotes); -CREATE INDEX BasesSubmitterUID ON PackageBases (SubmitterUID); -CREATE INDEX BasesMaintainerUID ON PackageBases (MaintainerUID); -CREATE INDEX BasesPackagerUID ON PackageBases (PackagerUID); - - --- Keywords of package bases --- -CREATE TABLE PackageKeywords ( - PackageBaseID INTEGER UNSIGNED NOT NULL, - Keyword VARCHAR(255) NOT NULL DEFAULT '', - PRIMARY KEY (PackageBaseID, Keyword), - FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - - --- Information about the actual packages --- -CREATE TABLE Packages ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - PackageBaseID INTEGER UNSIGNED NOT NULL, - Name VARCHAR(255) NOT NULL, - Version VARCHAR(255) NOT NULL DEFAULT '', - Description VARCHAR(255) NULL DEFAULT NULL, - URL VARCHAR(8000) NULL DEFAULT NULL, - PRIMARY KEY (ID), - UNIQUE (Name), - FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - - --- Information about licenses --- -CREATE TABLE Licenses ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(255) NOT NULL, - PRIMARY KEY (ID), - UNIQUE (Name) -) ENGINE = InnoDB; - - --- Information about package-license-relations --- -CREATE TABLE PackageLicenses ( - PackageID INTEGER UNSIGNED NOT NULL, - LicenseID INTEGER UNSIGNED NOT NULL, - PRIMARY KEY (PackageID, LicenseID), - FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE, - FOREIGN KEY (LicenseID) REFERENCES Licenses(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - - --- Information about groups --- -CREATE TABLE `Groups` ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(255) NOT NULL, - PRIMARY KEY (ID), - UNIQUE (Name) -) ENGINE = InnoDB; - - --- Information about package-group-relations --- -CREATE TABLE PackageGroups ( - PackageID INTEGER UNSIGNED NOT NULL, - GroupID INTEGER UNSIGNED NOT NULL, - PRIMARY KEY (PackageID, GroupID), - FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE, - FOREIGN KEY (GroupID) REFERENCES `Groups`(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - - --- Define the package dependency types --- -CREATE TABLE DependencyTypes ( - ID TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(32) NOT NULL DEFAULT '', - PRIMARY KEY (ID) -) ENGINE = InnoDB; -INSERT INTO DependencyTypes VALUES (1, 'depends'); -INSERT INTO DependencyTypes VALUES (2, 'makedepends'); -INSERT INTO DependencyTypes VALUES (3, 'checkdepends'); -INSERT INTO DependencyTypes VALUES (4, 'optdepends'); - - --- Track which dependencies a package has --- -CREATE TABLE PackageDepends ( - PackageID INTEGER UNSIGNED NOT NULL, - DepTypeID TINYINT UNSIGNED NOT NULL, - DepName VARCHAR(255) NOT NULL, - DepDesc VARCHAR(255) NULL DEFAULT NULL, - DepCondition VARCHAR(255), - DepArch VARCHAR(255) NULL DEFAULT NULL, - FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE, - FOREIGN KEY (DepTypeID) REFERENCES DependencyTypes(ID) ON DELETE NO ACTION -) ENGINE = InnoDB; -CREATE INDEX DependsPackageID ON PackageDepends (PackageID); -CREATE INDEX DependsDepName ON PackageDepends (DepName); - - --- Define the package relation types --- -CREATE TABLE RelationTypes ( - ID TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(32) NOT NULL DEFAULT '', - PRIMARY KEY (ID) -) ENGINE = InnoDB; -INSERT INTO RelationTypes VALUES (1, 'conflicts'); -INSERT INTO RelationTypes VALUES (2, 'provides'); -INSERT INTO RelationTypes VALUES (3, 'replaces'); - - --- Track which conflicts, provides and replaces a package has --- -CREATE TABLE PackageRelations ( - PackageID INTEGER UNSIGNED NOT NULL, - RelTypeID TINYINT UNSIGNED NOT NULL, - RelName VARCHAR(255) NOT NULL, - RelCondition VARCHAR(255), - RelArch VARCHAR(255) NULL DEFAULT NULL, - FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE, - FOREIGN KEY (RelTypeID) REFERENCES RelationTypes(ID) ON DELETE NO ACTION -) ENGINE = InnoDB; -CREATE INDEX RelationsPackageID ON PackageRelations (PackageID); -CREATE INDEX RelationsRelName ON PackageRelations (RelName); - - --- Track which sources a package has --- -CREATE TABLE PackageSources ( - PackageID INTEGER UNSIGNED NOT NULL, - Source VARCHAR(8000) NOT NULL DEFAULT '/dev/null', - SourceArch VARCHAR(255) NULL DEFAULT NULL, - FOREIGN KEY (PackageID) REFERENCES Packages(ID) ON DELETE CASCADE -) ENGINE = InnoDB; -CREATE INDEX SourcesPackageID ON PackageSources (PackageID); - - --- Track votes for packages --- -CREATE TABLE PackageVotes ( - UsersID INTEGER UNSIGNED NOT NULL, - PackageBaseID INTEGER UNSIGNED NOT NULL, - VoteTS BIGINT UNSIGNED NULL DEFAULT NULL, - FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, - FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE -) ENGINE = InnoDB; -CREATE UNIQUE INDEX VoteUsersIDPackageID ON PackageVotes (UsersID, PackageBaseID); -CREATE INDEX VotesUsersID ON PackageVotes (UsersID); -CREATE INDEX VotesPackageBaseID ON PackageVotes (PackageBaseID); - --- Record comments for packages --- -CREATE TABLE PackageComments ( - ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, - PackageBaseID INTEGER UNSIGNED NOT NULL, - UsersID INTEGER UNSIGNED NULL DEFAULT NULL, - Comments TEXT NOT NULL, - RenderedComment TEXT NOT NULL, - CommentTS BIGINT UNSIGNED NOT NULL DEFAULT 0, - EditedTS BIGINT UNSIGNED NULL DEFAULT NULL, - EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL, - DelTS BIGINT UNSIGNED NULL DEFAULT NULL, - DelUsersID INTEGER UNSIGNED NULL DEFAULT NULL, - PinnedTS BIGINT UNSIGNED NOT NULL DEFAULT 0, - PRIMARY KEY (ID), - FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE SET NULL, - FOREIGN KEY (EditedUsersID) REFERENCES Users(ID) ON DELETE SET NULL, - FOREIGN KEY (DelUsersID) REFERENCES Users(ID) ON DELETE CASCADE, - FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE -) ENGINE = InnoDB; -CREATE INDEX CommentsUsersID ON PackageComments (UsersID); -CREATE INDEX CommentsPackageBaseID ON PackageComments (PackageBaseID); - --- Package base co-maintainers --- -CREATE TABLE PackageComaintainers ( - UsersID INTEGER UNSIGNED NOT NULL, - PackageBaseID INTEGER UNSIGNED NOT NULL, - Priority INTEGER UNSIGNED NOT NULL, - FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, - FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE -) ENGINE = InnoDB; -CREATE INDEX ComaintainersUsersID ON PackageComaintainers (UsersID); -CREATE INDEX ComaintainersPackageBaseID ON PackageComaintainers (PackageBaseID); - --- Package base notifications --- -CREATE TABLE PackageNotifications ( - PackageBaseID INTEGER UNSIGNED NOT NULL, - UserID INTEGER UNSIGNED NOT NULL, - FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE, - FOREIGN KEY (UserID) REFERENCES Users(ID) ON DELETE CASCADE -) ENGINE = InnoDB; -CREATE UNIQUE INDEX NotifyUserIDPkgID ON PackageNotifications (UserID, PackageBaseID); - --- Package name blacklist --- -CREATE TABLE PackageBlacklist ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(64) NOT NULL, - PRIMARY KEY (ID), - UNIQUE (Name) -) ENGINE = InnoDB; - --- Providers in the official repositories --- -CREATE TABLE OfficialProviders ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(64) NOT NULL, - Repo VARCHAR(64) NOT NULL, - Provides VARCHAR(64) NOT NULL, - PRIMARY KEY (ID) -) ENGINE = InnoDB; -CREATE UNIQUE INDEX ProviderNameProvides ON OfficialProviders (Name, Provides); - --- Define package request types --- -CREATE TABLE RequestTypes ( - ID TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, - Name VARCHAR(32) NOT NULL DEFAULT '', - PRIMARY KEY (ID) -) ENGINE = InnoDB; -INSERT INTO RequestTypes VALUES (1, 'deletion'); -INSERT INTO RequestTypes VALUES (2, 'orphan'); -INSERT INTO RequestTypes VALUES (3, 'merge'); - --- Package requests --- -CREATE TABLE PackageRequests ( - ID BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, - ReqTypeID TINYINT UNSIGNED NOT NULL, - PackageBaseID INTEGER UNSIGNED NULL, - PackageBaseName VARCHAR(255) NOT NULL, - MergeBaseName VARCHAR(255) NULL, - UsersID INTEGER UNSIGNED NULL DEFAULT NULL, - Comments TEXT NOT NULL, - ClosureComment TEXT NOT NULL, - RequestTS BIGINT UNSIGNED NOT NULL DEFAULT 0, - ClosedTS BIGINT UNSIGNED NULL DEFAULT NULL, - ClosedUID INTEGER UNSIGNED NULL DEFAULT NULL, - Status TINYINT UNSIGNED NOT NULL DEFAULT 0, - PRIMARY KEY (ID), - FOREIGN KEY (ReqTypeID) REFERENCES RequestTypes(ID) ON DELETE NO ACTION, - FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE SET NULL, - FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE SET NULL, - FOREIGN KEY (ClosedUID) REFERENCES Users(ID) ON DELETE SET NULL -) ENGINE = InnoDB; -CREATE INDEX RequestsUsersID ON PackageRequests (UsersID); -CREATE INDEX RequestsPackageBaseID ON PackageRequests (PackageBaseID); - --- Vote information --- -CREATE TABLE IF NOT EXISTS TU_VoteInfo ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - Agenda TEXT NOT NULL, - User VARCHAR(32) NOT NULL, - Submitted BIGINT UNSIGNED NOT NULL, - End BIGINT UNSIGNED NOT NULL, - Quorum DECIMAL(2, 2) UNSIGNED NOT NULL, - SubmitterID INTEGER UNSIGNED NOT NULL, - Yes TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - No TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - Abstain TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - ActiveTUs TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', - PRIMARY KEY (ID), - FOREIGN KEY (SubmitterID) REFERENCES Users(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - --- Individual vote records --- -CREATE TABLE IF NOT EXISTS TU_Votes ( - VoteID INTEGER UNSIGNED NOT NULL, - UserID INTEGER UNSIGNED NOT NULL, - FOREIGN KEY (VoteID) REFERENCES TU_VoteInfo(ID) ON DELETE CASCADE, - FOREIGN KEY (UserID) REFERENCES Users(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - --- Malicious user banning --- -CREATE TABLE Bans ( - IPAddress VARCHAR(45) NOT NULL, - BanTS TIMESTAMP NOT NULL, - PRIMARY KEY (IPAddress) -) ENGINE = InnoDB; - --- Terms and Conditions --- -CREATE TABLE Terms ( - ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - Description VARCHAR(255) NOT NULL, - URL VARCHAR(8000) NOT NULL, - Revision INTEGER UNSIGNED NOT NULL DEFAULT 1, - PRIMARY KEY (ID) -) ENGINE = InnoDB; - --- Terms and Conditions accepted by users --- -CREATE TABLE AcceptedTerms ( - UsersID INTEGER UNSIGNED NOT NULL, - TermsID INTEGER UNSIGNED NOT NULL, - Revision INTEGER UNSIGNED NOT NULL DEFAULT 0, - FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE, - FOREIGN KEY (TermsID) REFERENCES Terms(ID) ON DELETE CASCADE -) ENGINE = InnoDB; - --- Rate limits for API --- -CREATE TABLE `ApiRateLimit` ( - IP VARCHAR(45) NOT NULL, - Requests INT(11) NOT NULL, - WindowStart BIGINT(20) NOT NULL, - PRIMARY KEY (`ip`) -) ENGINE = InnoDB; -CREATE INDEX ApiRateLimitWindowStart ON ApiRateLimit (WindowStart); diff --git a/schema/reloadtestdb.sh b/schema/reloadtestdb.sh deleted file mode 100755 index e839dcec..00000000 --- a/schema/reloadtestdb.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -e - -DB_NAME=${DB_NAME:-AUR} -DB_USER=${DB_USER:-aur} -# Password should allow empty definition -DB_PASS=${DB_PASS-aur} -DB_HOST=${DB_HOST:-localhost} -DATA_FILE=${DATA_FILE:-dummy-data.sql} - -echo "Using database $DB_NAME, user $DB_USER, host $DB_HOST" - -mydir=$(pwd) -if [ $(basename $mydir) != "schema" ]; then - echo "you must be in the aurweb/schema directory to run this script" - exit 1 -fi - -echo "recreating database..." -mysql -h $DB_HOST -u $DB_USER -p$DB_PASS < aur-schema.sql - -if [ ! -f $DATA_FILE ]; then - echo "creating dumy-data..." - python3 gendummydata.py $DATA_FILE -fi - -echo "loading dummy-data..." -mysql -h $DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME < $DATA_FILE - -echo "done." diff --git a/test/Makefile b/test/Makefile index 4ce9b9be..f559e169 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,10 +1,6 @@ -FOREIGN_TARGETS = ../schema/aur-schema-sqlite.sql T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) -check: $(FOREIGN_TARGETS) $(T) - -$(FOREIGN_TARGETS): - $(MAKE) -C $(dir $@) $(notdir $@) +check: $(T) clean: $(RM) -r test-results/ diff --git a/test/setup.sh b/test/setup.sh index 5c761f22..12f6edcc 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -110,10 +110,7 @@ SSH_TTY=/dev/pts/0 export SSH_CLIENT SSH_CONNECTION SSH_TTY # Initialize the test database. -DBSCHEMA="$TOPLEVEL/schema/aur-schema-sqlite.sql" -[ -f "$DBSCHEMA" ] || error 'SQLite database schema not found' -rm -f aur.db -sqlite3 aur.db <"$DBSCHEMA" +python -m aurweb.initdb echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 'en', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 'en', 2);" | sqlite3 aur.db From a8a1f74a9207339bf707bb09e8dba7b2c67abb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sat, 22 Feb 2020 22:31:26 +0100 Subject: [PATCH 0516/1891] Set up Alembic for database migrations Signed-off-by: Lukas Fleischer --- INSTALL | 4 +- TESTING | 3 +- alembic.ini | 86 +++++++++++++++++++++++++++++++++++++++ aurweb/initdb.py | 9 ++++ aurweb/schema.py | 8 ++++ migrations/README | 48 ++++++++++++++++++++++ migrations/env.py | 73 +++++++++++++++++++++++++++++++++ migrations/script.py.mako | 24 +++++++++++ 8 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 alembic.ini create mode 100644 migrations/README create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako diff --git a/INSTALL b/INSTALL index 68fe5dcd..7087aca2 100644 --- a/INSTALL +++ b/INSTALL @@ -47,8 +47,8 @@ read the instructions below. 4) Install Python modules and dependencies: - # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy - # pacman -S python-bleach python-markdown + # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy \ + python-bleach python-markdown python-alembic # python3 setup.py install 5) Create a new MySQL database and a user and import the aurweb SQL schema: diff --git a/TESTING b/TESTING index 190043f9..4a1e6f4c 100644 --- a/TESTING +++ b/TESTING @@ -11,7 +11,8 @@ INSTALL. 2) Install the necessary packages: - # pacman -S --needed php php-sqlite sqlite words fortune-mod python python-sqlalchemy + # pacman -S --needed php php-sqlite sqlite words fortune-mod \ + python python-sqlalchemy python-alembic Ensure to enable the pdo_sqlite extension in php.ini. diff --git a/alembic.ini b/alembic.ini new file mode 100644 index 00000000..6d3a3929 --- /dev/null +++ b/alembic.ini @@ -0,0 +1,86 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = migrations + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# timezone to use when rendering the date +# within the migration file as well as the filename. +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; this defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path +# version_locations = %(here)s/bar %(here)s/bat alembic/versions + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +# the database URL is generated in env.py +# sqlalchemy.url = driver://user:pass@localhost/dbname + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks=black +# black.type=console_scripts +# black.entrypoint=black +# black.options=-l 79 + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/aurweb/initdb.py b/aurweb/initdb.py index e3e96503..c02fb961 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -1,6 +1,8 @@ import aurweb.db import aurweb.schema +import alembic.command +import alembic.config import argparse import sqlalchemy @@ -31,10 +33,17 @@ def feed_initial_data(conn): def run(args): + # Ensure Alembic is fine before we do the real work, in order not to fail at + # the last step and leave the database in an inconsistent state. The + # configuration is loaded lazily, so we query it to force its loading. + alembic_config = alembic.config.Config('alembic.ini') + alembic_config.get_main_option('script_location') + engine = sqlalchemy.create_engine(aurweb.db.get_sqlalchemy_url(), echo=(args.verbose >= 1)) aurweb.schema.metadata.create_all(engine) feed_initial_data(engine.connect()) + alembic.command.stamp(alembic_config, 'head') if __name__ == '__main__': diff --git a/aurweb/schema.py b/aurweb/schema.py index b1261e86..fde6512f 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -1,3 +1,11 @@ +""" +Schema of aurweb's database. + +Changes here should always be accompanied by an Alembic migration, which can be +usually be automatically generated. See `migrations/README` for details. +""" + + from sqlalchemy import CHAR, Column, ForeignKey, Index, MetaData, String, TIMESTAMP, Table, Text, text from sqlalchemy.dialects.mysql import BIGINT, DECIMAL, INTEGER, TINYINT from sqlalchemy.ext.compiler import compiles diff --git a/migrations/README b/migrations/README new file mode 100644 index 00000000..301d0e54 --- /dev/null +++ b/migrations/README @@ -0,0 +1,48 @@ +This directory contains Alembic's environment for managing database migrations. + +From Alembic's documentation: Alembic is a lightweight database migration tool +for usage with the SQLAlchemy Database Toolkit for Python. +https://alembic.sqlalchemy.org/en/latest/index.html + + +Upgrading to the latest version +------------------------------- + +Simply run `alembic upgrade head` from aurweb's root. + + +Creating new migrations +----------------------- + +When working with Alembic and SQLAlchemy, you should never edit the database +schema manually. Please proceed like this instead: + +1. Edit `aurweb/schema.py` to your liking. +2. Run `alembic revision --autogenerate -m "your message"` +3. Proofread the generated migration. +4. Run `alembic upgrade head` to apply the changes to the database. +5. Commit the new migration. + +To revert a migration, you may run `alembic downgrade -1` and then manually +delete the migration file. Note that SQLite is limited and that it's sometimes +easier to recreate the database. + +For anything more complicated, please read Alembic's documentation. + + +Troubleshooting +--------------- + +- `ModuleNotFoundError: No module named 'aurweb'` + + You may either install the aurweb module with pip, or set PYTHONPATH to your + aurweb repository. Since alembic must be run from the aurweb root, you may + simply use: `PYTHONPATH=. alembic [...]`. + +- `FAILED: No config file 'alembic.ini' found, or file has no '[alembic]' section` + + You need to run Alembic from the project's root, and not from `migrations/`. + +- `configparser.NoSectionError: No section: 'database'` + + You need to set AUR_CONFIG, as explained in `TESTING`. diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 00000000..1627e693 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,73 @@ +import aurweb.db +import aurweb.schema + +from alembic import context +import logging.config +import sqlalchemy + + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +logging.config.fileConfig(config.config_file_name) + +# model MetaData for autogenerating migrations +target_metadata = aurweb.schema.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + context.configure( + url=aurweb.db.get_sqlalchemy_url(), + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = sqlalchemy.create_engine( + aurweb.db.get_sqlalchemy_url(), + poolclass=sqlalchemy.pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 00000000..2c015630 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} From e4cbe264cf6949f82338b7de705cba90c15f4d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 23 Feb 2020 19:52:12 +0100 Subject: [PATCH 0517/1891] Create an initial Alembic migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way the database will get stamped, and Git will create the `versions` directory without which Alembic won’t work. Signed-off-by: Lukas Fleischer --- .../versions/f47cad5d6d03_initial_revision.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 migrations/versions/f47cad5d6d03_initial_revision.py diff --git a/migrations/versions/f47cad5d6d03_initial_revision.py b/migrations/versions/f47cad5d6d03_initial_revision.py new file mode 100644 index 00000000..9e99490f --- /dev/null +++ b/migrations/versions/f47cad5d6d03_initial_revision.py @@ -0,0 +1,24 @@ +"""initial revision + +Revision ID: f47cad5d6d03 +Revises: +Create Date: 2020-02-23 13:23:32.331396 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f47cad5d6d03' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + pass + + +def downgrade(): + pass From 81d55e70ee0469018af86d203ceaf2fece691ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 23 Feb 2020 19:52:36 +0100 Subject: [PATCH 0518/1891] Disable Alembic support on test databases Signed-off-by: Lukas Fleischer --- aurweb/initdb.py | 12 +++++++++--- test/setup.sh | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/aurweb/initdb.py b/aurweb/initdb.py index c02fb961..91777f7e 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -36,14 +36,17 @@ def run(args): # Ensure Alembic is fine before we do the real work, in order not to fail at # the last step and leave the database in an inconsistent state. The # configuration is loaded lazily, so we query it to force its loading. - alembic_config = alembic.config.Config('alembic.ini') - alembic_config.get_main_option('script_location') + if args.use_alembic: + alembic_config = alembic.config.Config('alembic.ini') + alembic_config.get_main_option('script_location') engine = sqlalchemy.create_engine(aurweb.db.get_sqlalchemy_url(), echo=(args.verbose >= 1)) aurweb.schema.metadata.create_all(engine) feed_initial_data(engine.connect()) - alembic.command.stamp(alembic_config, 'head') + + if args.use_alembic: + alembic.command.stamp(alembic_config, 'head') if __name__ == '__main__': @@ -52,5 +55,8 @@ if __name__ == '__main__': description='Initialize the aurweb database.') parser.add_argument('-v', '--verbose', action='count', default=0, help='increase verbosity') + parser.add_argument('--no-alembic', + help='disable Alembic migrations support', + dest='use_alembic', action='store_false') args = parser.parse_args() run(args) diff --git a/test/setup.sh b/test/setup.sh index 12f6edcc..cad5cd66 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -110,7 +110,7 @@ SSH_TTY=/dev/pts/0 export SSH_CLIENT SSH_CONNECTION SSH_TTY # Initialize the test database. -python -m aurweb.initdb +python -m aurweb.initdb --no-alembic echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 'en', 1);" | sqlite3 aur.db echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 'en', 2);" | sqlite3 aur.db From e374a91febe53b72ff4cb73b153348f067374c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 23 Feb 2020 19:53:13 +0100 Subject: [PATCH 0519/1891] Change the extension of TAP test suites to .t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the common convention for TAP, and makes harnesses like prove automatically detect them. Plus, test suites don’t have to be shell scripts anymore. Signed-off-by: Lukas Fleischer --- test/Makefile | 2 +- test/{t1100-git-auth.sh => t1100-git-auth.t} | 0 test/{t1200-git-serve.sh => t1200-git-serve.t} | 0 test/{t1300-git-update.sh => t1300-git-update.t} | 0 test/{t2100-mkpkglists.sh => t2100-mkpkglists.t} | 0 test/{t2200-tuvotereminder.sh => t2200-tuvotereminder.t} | 0 test/{t2300-pkgmaint.sh => t2300-pkgmaint.t} | 0 test/{t2400-aurblup.sh => t2400-aurblup.t} | 0 test/{t2500-notify.sh => t2500-notify.t} | 0 test/{t2600-rendercomment.sh => t2600-rendercomment.t} | 0 test/{t2700-usermaint.sh => t2700-usermaint.t} | 0 11 files changed, 1 insertion(+), 1 deletion(-) rename test/{t1100-git-auth.sh => t1100-git-auth.t} (100%) rename test/{t1200-git-serve.sh => t1200-git-serve.t} (100%) rename test/{t1300-git-update.sh => t1300-git-update.t} (100%) rename test/{t2100-mkpkglists.sh => t2100-mkpkglists.t} (100%) rename test/{t2200-tuvotereminder.sh => t2200-tuvotereminder.t} (100%) rename test/{t2300-pkgmaint.sh => t2300-pkgmaint.t} (100%) rename test/{t2400-aurblup.sh => t2400-aurblup.t} (100%) rename test/{t2500-notify.sh => t2500-notify.t} (100%) rename test/{t2600-rendercomment.sh => t2600-rendercomment.t} (100%) rename test/{t2700-usermaint.sh => t2700-usermaint.t} (100%) diff --git a/test/Makefile b/test/Makefile index f559e169..d310c8f5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,4 +1,4 @@ -T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) +T = $(sort $(wildcard *.t)) check: $(T) diff --git a/test/t1100-git-auth.sh b/test/t1100-git-auth.t similarity index 100% rename from test/t1100-git-auth.sh rename to test/t1100-git-auth.t diff --git a/test/t1200-git-serve.sh b/test/t1200-git-serve.t similarity index 100% rename from test/t1200-git-serve.sh rename to test/t1200-git-serve.t diff --git a/test/t1300-git-update.sh b/test/t1300-git-update.t similarity index 100% rename from test/t1300-git-update.sh rename to test/t1300-git-update.t diff --git a/test/t2100-mkpkglists.sh b/test/t2100-mkpkglists.t similarity index 100% rename from test/t2100-mkpkglists.sh rename to test/t2100-mkpkglists.t diff --git a/test/t2200-tuvotereminder.sh b/test/t2200-tuvotereminder.t similarity index 100% rename from test/t2200-tuvotereminder.sh rename to test/t2200-tuvotereminder.t diff --git a/test/t2300-pkgmaint.sh b/test/t2300-pkgmaint.t similarity index 100% rename from test/t2300-pkgmaint.sh rename to test/t2300-pkgmaint.t diff --git a/test/t2400-aurblup.sh b/test/t2400-aurblup.t similarity index 100% rename from test/t2400-aurblup.sh rename to test/t2400-aurblup.t diff --git a/test/t2500-notify.sh b/test/t2500-notify.t similarity index 100% rename from test/t2500-notify.sh rename to test/t2500-notify.t diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.t similarity index 100% rename from test/t2600-rendercomment.sh rename to test/t2600-rendercomment.t diff --git a/test/t2700-usermaint.sh b/test/t2700-usermaint.t similarity index 100% rename from test/t2700-usermaint.sh rename to test/t2700-usermaint.t From 90c0a361b5cb8f72a9c908104b399451712fb7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sat, 29 Feb 2020 01:01:38 +0100 Subject: [PATCH 0520/1891] Support running tests from any directory Signed-off-by: Lukas Fleischer --- test/setup.sh | 5 ++--- test/t1100-git-auth.t | 2 +- test/t1200-git-serve.t | 2 +- test/t1300-git-update.t | 2 +- test/t2100-mkpkglists.t | 2 +- test/t2200-tuvotereminder.t | 2 +- test/t2300-pkgmaint.t | 2 +- test/t2400-aurblup.t | 2 +- test/t2500-notify.t | 2 +- test/t2600-rendercomment.t | 2 +- test/t2700-usermaint.t | 2 +- 11 files changed, 12 insertions(+), 13 deletions(-) diff --git a/test/setup.sh b/test/setup.sh index cad5cd66..4a6eb3b1 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -1,7 +1,6 @@ -TEST_DIRECTORY="$(pwd)" -TOPLEVEL="$(cd .. && pwd)" +TOPLEVEL="$(cd "$(dirname "$0")/.." && pwd)" -. ./sharness.sh +. "$TOPLEVEL/test/sharness.sh" # Configure python search path. PYTHONPATH="$TOPLEVEL" diff --git a/test/t1100-git-auth.t b/test/t1100-git-auth.t index 71d526f2..cbf16aed 100755 --- a/test/t1100-git-auth.t +++ b/test/t1100-git-auth.t @@ -2,7 +2,7 @@ test_description='git-auth tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test basic authentication.' ' "$GIT_AUTH" "$AUTH_KEYTYPE_USER" "$AUTH_KEYTEXT_USER" >out && diff --git a/test/t1200-git-serve.t b/test/t1200-git-serve.t index e817b2cf..1893cdcd 100755 --- a/test/t1200-git-serve.t +++ b/test/t1200-git-serve.t @@ -2,7 +2,7 @@ test_description='git-serve tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test interactive shell.' ' "$GIT_SERVE" 2>&1 | grep -q "Interactive shell is disabled." diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index 06d14984..82c0fb99 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -2,7 +2,7 @@ test_description='git-update tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" dump_package_info() { for t in Packages Licenses PackageLicenses Groups PackageGroups \ diff --git a/test/t2100-mkpkglists.t b/test/t2100-mkpkglists.t index fc11d073..5bf13de8 100755 --- a/test/t2100-mkpkglists.t +++ b/test/t2100-mkpkglists.t @@ -2,7 +2,7 @@ test_description='mkpkglists tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test package list generation with no packages.' ' echo "DELETE FROM Packages;" | sqlite3 aur.db && diff --git a/test/t2200-tuvotereminder.t b/test/t2200-tuvotereminder.t index c82ce874..5a8f3a25 100755 --- a/test/t2200-tuvotereminder.t +++ b/test/t2200-tuvotereminder.t @@ -2,7 +2,7 @@ test_description='tuvotereminder tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test Trusted User vote reminders.' ' now=$(date -d now +%s) && diff --git a/test/t2300-pkgmaint.t b/test/t2300-pkgmaint.t index 478df526..c390f5db 100755 --- a/test/t2300-pkgmaint.t +++ b/test/t2300-pkgmaint.t @@ -2,7 +2,7 @@ test_description='pkgmaint tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test package base cleanup script.' ' now=$(date -d now +%s) && diff --git a/test/t2400-aurblup.t b/test/t2400-aurblup.t index 708281c6..cc287a0f 100755 --- a/test/t2400-aurblup.t +++ b/test/t2400-aurblup.t @@ -2,7 +2,7 @@ test_description='aurblup tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test official provider update script.' ' mkdir -p remote/test/foobar-1.0-1 && diff --git a/test/t2500-notify.t b/test/t2500-notify.t index 380e65b8..5ef64c18 100755 --- a/test/t2500-notify.t +++ b/test/t2500-notify.t @@ -2,7 +2,7 @@ test_description='notify tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test out-of-date notifications.' ' cat <<-EOD | sqlite3 aur.db && diff --git a/test/t2600-rendercomment.t b/test/t2600-rendercomment.t index be408b80..e01904c6 100755 --- a/test/t2600-rendercomment.t +++ b/test/t2600-rendercomment.t @@ -2,7 +2,7 @@ test_description='rendercomment tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test comment rendering.' ' cat <<-EOD | sqlite3 aur.db && diff --git a/test/t2700-usermaint.t b/test/t2700-usermaint.t index 4f625142..f0bb449b 100755 --- a/test/t2700-usermaint.t +++ b/test/t2700-usermaint.t @@ -2,7 +2,7 @@ test_description='usermaint tests' -. ./setup.sh +. "$(dirname "$0")/setup.sh" test_expect_success 'Test removal of login IP addresses.' ' now=$(date -d now +%s) && From bf7c49158c360690f79b31b5a65f0bb42e3fccb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sat, 29 Feb 2020 01:02:04 +0100 Subject: [PATCH 0521/1891] test/Makefile: Run tests with prove when available Signed-off-by: Lukas Fleischer --- test/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/Makefile b/test/Makefile index d310c8f5..758befa3 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,6 +1,13 @@ T = $(sort $(wildcard *.t)) +PROVE := $(shell command -v prove 2> /dev/null) + +ifdef PROVE +check: + prove . +else check: $(T) +endif clean: $(RM) -r test-results/ From 28ba3f77dcd3741b2cb8dc82f47790e130063da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sat, 29 Feb 2020 01:02:42 +0100 Subject: [PATCH 0522/1891] Write test/README.md to help working with tests Signed-off-by: Lukas Fleischer --- test/README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 test/README.md diff --git a/test/README.md b/test/README.md new file mode 100644 index 00000000..de7eff18 --- /dev/null +++ b/test/README.md @@ -0,0 +1,37 @@ +Running tests +------------- + +To run all the tests, you may run `make check` under `test/`. + +For more control, you may use the `prove` command, which receives a directory +or a list of files to run, and produces a report. + +Each test script is standalone, so you may run them individually. Some tests +may receive command-line options to help debugging. See for example sharness's +documentation for shell test scripts: +https://github.com/chriscool/sharness/blob/master/README.git + +### Dependencies + +For all the test to run, the following Arch packages should be installed: + +- pyalpm +- python-alembic +- python-bleach +- python-markdown +- python-pygit2 +- python-sqlalchemy +- python-srcinfo + +Writing tests +------------- + +Test scripts must follow the Test Anything Protocol specification: +http://testanything.org/tap-specification.html + +Tests must support being run from any directory. They may use $0 to determine +their location. Python scripts should expect aurweb to be installed and +importable without toying with os.path or PYTHONPATH. + +Tests written in shell should use sharness. In general, new tests should be +consistent with existing tests unless they have a good reason not to. From 31a5b40b5cf355f3648d5e13d9dbd09b51f7cb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sat, 21 Mar 2020 19:13:45 +0100 Subject: [PATCH 0523/1891] Map BIGINT to INTEGER for SQLite Signed-off-by: Lukas Fleischer --- aurweb/schema.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/aurweb/schema.py b/aurweb/schema.py index fde6512f..6792cf1d 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -17,6 +17,17 @@ def compile_tinyint_sqlite(type_, compiler, **kw): return 'INTEGER' +@compiles(BIGINT, 'sqlite') +def compile_bigint_sqlite(type_, compiler, **kw): + """ + For SQLite's AUTOINCREMENT to work on BIGINT columns, we need to map BIGINT + to INTEGER. Aside from that, BIGINT is the same as INTEGER for SQLite. + + See https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#allowing-autoincrement-behavior-sqlalchemy-types-other-than-integer-integer + """ + return 'INTEGER' + + metadata = MetaData() # Define the Account Types for the AUR. From a09c4d81682a1ec76925315b497c475cadebf3ea Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 27 Mar 2020 08:31:46 -0400 Subject: [PATCH 0524/1891] Translation updates from Transifex Signed-off-by: Lukas Fleischer --- po/ast.po | 502 +++++++++++++++++++++++++++--------------------------- po/ja.po | 62 +++---- 2 files changed, 282 insertions(+), 282 deletions(-) diff --git a/po/ast.po b/po/ast.po index 5e08e86b..16c363a6 100644 --- a/po/ast.po +++ b/po/ast.po @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2020-01-31 08:29+0000\n" -"Last-Translator: Lukas Fleischer\n" +"PO-Revision-Date: 2020-03-07 17:55+0000\n" +"Last-Translator: enolp \n" "Language-Team: Asturian (http://www.transifex.com/lfleischer/aurweb/language/ast/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -22,15 +22,15 @@ msgstr "" #: html/404.php msgid "Page Not Found" -msgstr "Nun s'alcontró la páxina" +msgstr "" #: html/404.php msgid "Sorry, the page you've requested does not exist." -msgstr "Perdón, la páxina que pidisti nun esiste." +msgstr "" #: html/404.php template/pkgreq_close_form.php msgid "Note" -msgstr "Nota" +msgstr "" #: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." @@ -48,32 +48,32 @@ msgstr "" #: html/503.php msgid "Service Unavailable" -msgstr "Serviciu non disponible" +msgstr "" #: html/503.php msgid "" "Don't panic! This site is down due to maintenance. We will be back soon." -msgstr "¡Asela! Esti sitiu ta cayíu debío a caltenimientu. Volverémos ceo." +msgstr "" #: html/account.php msgid "Account" -msgstr "Cuenta" +msgstr "" #: html/account.php template/header.php msgid "Accounts" -msgstr "Cuentes" +msgstr "" #: html/account.php html/addvote.php msgid "You are not allowed to access this area." -msgstr "Nun tienes permisu p'acceder a esta area." +msgstr "" #: html/account.php msgid "Could not retrieve information for the specified user." -msgstr "Nun pudo recibise la información pal usuariu especificáu." +msgstr "" #: html/account.php msgid "You do not have permission to edit this account." -msgstr "Nun tienes permisu pa editar esta cuenta." +msgstr "" #: html/account.php lib/acctfuncs.inc.php msgid "Invalid password." @@ -81,40 +81,40 @@ msgstr "" #: html/account.php msgid "Use this form to search existing accounts." -msgstr "Usa esti formulariu pa guetar cuentes esistentes." +msgstr "" #: html/account.php msgid "You must log in to view user information." -msgstr "Tienes d'aniciar sesión pa ver la información del usuariu." +msgstr "" #: html/addvote.php template/tu_list.php msgid "Add Proposal" -msgstr "Amestar propuesta" +msgstr "" #: html/addvote.php msgid "Invalid token for user action." -msgstr "Token non válidu pa la aición del usuariu" +msgstr "" #: html/addvote.php msgid "Username does not exist." -msgstr "El nome d'usuariu nun esiste." +msgstr "" #: html/addvote.php #, php-format msgid "%s already has proposal running for them." -msgstr "%s yá tien la propuesta que cuerre pa ellos." +msgstr "" #: html/addvote.php msgid "Invalid type." -msgstr "Triba non válida." +msgstr "" #: html/addvote.php msgid "Proposal cannot be empty." -msgstr "La propuesta nun pue tar balera" +msgstr "" #: html/addvote.php msgid "New proposal submitted." -msgstr "Unvióse la propuesta nueva." +msgstr "" #: html/addvote.php msgid "Submit a proposal to vote on." @@ -122,20 +122,20 @@ msgstr "" #: html/addvote.php msgid "Applicant/TU" -msgstr "Aplicante/Usuariu d'Enfotu." +msgstr "" #: html/addvote.php msgid "(empty if not applicable)" -msgstr "(baletu si nun s'aplica)" +msgstr "" #: html/addvote.php template/account_search_results.php #: template/pkgreq_results.php msgid "Type" -msgstr "Triba" +msgstr "" #: html/addvote.php msgid "Addition of a TU" -msgstr "Añedir un Usuariu d'Enfotu" +msgstr "" #: html/addvote.php msgid "Removal of a TU" @@ -151,11 +151,11 @@ msgstr "" #: html/addvote.php template/tu_list.php msgid "Proposal" -msgstr "Propuesta" +msgstr "" #: html/addvote.php msgid "Submit" -msgstr "Unviar" +msgstr "" #: html/comaintainers.php template/comaintainers_form.php msgid "Manage Co-maintainers" @@ -171,7 +171,7 @@ msgstr "" #: html/home.php template/header.php msgid "Home" -msgstr "Aniciu" +msgstr "" #: html/home.php msgid "My Flagged Packages" @@ -183,7 +183,7 @@ msgstr "" #: html/home.php msgid "My Packages" -msgstr "Los mios paquetes" +msgstr "" #: html/home.php msgid "Search for packages I maintain" @@ -202,44 +202,44 @@ msgstr "" msgid "" "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU " "Guidelines%s for more information." -msgstr "¡Bienllegáu al AUR! Llei la %sGuía d'usuariu del AUR%s y la %sGuía d'usuariu TU del AUR%s pa más información." +msgstr "" #: html/home.php #, php-format msgid "" "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s " "otherwise they will be deleted!" -msgstr "Los PKGBUILD contribuyíos %stienen%s de ser compatibles col %sEstándar de empaquetado de Arch%s d'otra forma van ser esaniciaos." +msgstr "" #: html/home.php msgid "Remember to vote for your favourite packages!" -msgstr "¡Recuerda votar los tos paquetes favoritos!" +msgstr "" #: html/home.php msgid "Some packages may be provided as binaries in [community]." -msgstr "Dellos paquetes puen apurrise como binarios en [community]." +msgstr "" #: html/home.php msgid "DISCLAIMER" -msgstr "ACLARATORIA" +msgstr "" #: html/home.php template/footer.php msgid "" "AUR packages are user produced content. Any use of the provided files is at " "your own risk." -msgstr "Los paquetes d'AUR son conteníu producíu polos usuarios. Cualesquier usu de los ficheros forníos ta sol to propiu riesgu." +msgstr "" #: html/home.php msgid "Learn more..." -msgstr "Llei más..." +msgstr "" #: html/home.php msgid "Support" -msgstr "Sofitu" +msgstr "" #: html/home.php msgid "Package Requests" -msgstr "Solicitúes de paquetes" +msgstr "" #: html/home.php #, php-format @@ -250,7 +250,7 @@ msgstr "" #: html/home.php msgid "Orphan Request" -msgstr "Solicitú güérfana" +msgstr "" #: html/home.php msgid "" @@ -260,7 +260,7 @@ msgstr "" #: html/home.php msgid "Deletion Request" -msgstr "Solicitú de desaniciu" +msgstr "" #: html/home.php msgid "" @@ -271,7 +271,7 @@ msgstr "" #: html/home.php msgid "Merge Request" -msgstr "Solicitú de desanciu" +msgstr "" #: html/home.php msgid "" @@ -288,7 +288,7 @@ msgstr "" #: html/home.php msgid "Submitting Packages" -msgstr "Unviu de paquetes" +msgstr "" #: html/home.php #, php-format @@ -296,15 +296,15 @@ msgid "" "Git over SSH is now used to submit packages to the AUR. See the %sSubmitting" " packages%s section of the Arch User Repository ArchWiki page for more " "details." -msgstr "Agora úsase GIT sobro SSH pa unviar paquetes a AUR. Mira la estaya %sUnviu de paquetes%s de la páxina ArchWiki del AUR pa más detalles." +msgstr "" #: html/home.php msgid "The following SSH fingerprints are used for the AUR:" -msgstr "Les buelgues SSH de darréu úsense pal AUR:" +msgstr "" #: html/home.php msgid "Discussion" -msgstr "Discutiniu" +msgstr "" #: html/home.php #, php-format @@ -316,7 +316,7 @@ msgstr "" #: html/home.php msgid "Bug Reporting" -msgstr "Informe de fallos" +msgstr "" #: html/home.php #, php-format @@ -329,23 +329,23 @@ msgstr "" #: html/home.php msgid "Package Search" -msgstr "Gueta de paquetes" +msgstr "" #: html/index.php msgid "Adopt" -msgstr "Adoptar" +msgstr "" #: html/index.php msgid "Vote" -msgstr "Votar" +msgstr "" #: html/index.php msgid "UnVote" -msgstr "Retirar votu" +msgstr "" #: html/index.php template/pkg_search_form.php template/pkg_search_results.php msgid "Notify" -msgstr "Avisar" +msgstr "" #: html/index.php template/pkg_search_results.php msgid "UnNotify" @@ -357,7 +357,7 @@ msgstr "" #: html/login.php template/header.php msgid "Login" -msgstr "Aniciar sesión" +msgstr "" #: html/login.php html/tos.php #, php-format @@ -366,11 +366,11 @@ msgstr "" #: html/login.php template/header.php msgid "Logout" -msgstr "Zarrar sesión" +msgstr "" #: html/login.php msgid "Enter login credentials" -msgstr "Introduz les tos credenciales d'aniciu sesión" +msgstr "" #: html/login.php msgid "User name or primary email address" @@ -378,15 +378,15 @@ msgstr "" #: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" -msgstr "Contraseña" +msgstr "" #: html/login.php msgid "Remember me" -msgstr "Recordáime" +msgstr "" #: html/login.php msgid "Forgot Password" -msgstr "Escaecí la contraseña" +msgstr "" #: html/login.php #, php-format @@ -396,45 +396,45 @@ msgstr "" #: html/packages.php template/pkg_search_form.php msgid "Search Criteria" -msgstr "Criteriu de gueta" +msgstr "" #: html/packages.php template/header.php template/pkgbase_details.php #: template/stats/general_stats_table.php template/stats/user_table.php msgid "Packages" -msgstr "Paquetes" +msgstr "" #: html/packages.php msgid "Error trying to retrieve package details." -msgstr "Fallu intentando recibir los detalles del paquete." +msgstr "" #: html/passreset.php lib/acctfuncs.inc.php msgid "Missing a required field." -msgstr "Falta un campu riquíu." +msgstr "" #: html/passreset.php lib/acctfuncs.inc.php msgid "Password fields do not match." -msgstr "Nun concasen los campos de contraseñes" +msgstr "" #: html/passreset.php lib/acctfuncs.inc.php #, php-format msgid "Your password must be at least %s characters." -msgstr "La to contraseña tien de tener polo menos %s carauteres." +msgstr "" #: html/passreset.php msgid "Invalid e-mail." -msgstr "Corréu electrónicu non válidu" +msgstr "" #: html/passreset.php msgid "Password Reset" -msgstr "Reaniciu de contraseña" +msgstr "" #: html/passreset.php msgid "Check your e-mail for the confirmation link." -msgstr "Comprueba'l to corréu pal enllaz de confirmación." +msgstr "" #: html/passreset.php msgid "Your password has been reset successfully." -msgstr "La to contraseña reanicióse con ésitu." +msgstr "" #: html/passreset.php msgid "Confirm your user name or primary e-mail address:" @@ -442,15 +442,15 @@ msgstr "" #: html/passreset.php msgid "Enter your new password:" -msgstr "Introduz la to contraseña nueva:" +msgstr "" #: html/passreset.php msgid "Confirm your new password:" -msgstr "Confirma la to contraseña nueva:" +msgstr "" #: html/passreset.php html/tos.php msgid "Continue" -msgstr "Siguir" +msgstr "" #: html/passreset.php #, php-format @@ -489,7 +489,7 @@ msgstr "" #: html/pkgdel.php msgid "Package Deletion" -msgstr "Desaniciu de paquete" +msgstr "" #: html/pkgdel.php template/pkgbase_actions.php msgid "Delete Package" @@ -500,11 +500,11 @@ msgstr "" msgid "" "Use this form to delete the package base %s%s%s and the following packages " "from the AUR: " -msgstr "Usa esti formulariu pa desaniciar el paquete base %s%s%s y los paquetes siguientes d'AUR:" +msgstr "" #: html/pkgdel.php msgid "Deletion of a package is permanent. " -msgstr "El desaniciu d'un paquete ye permanente." +msgstr "" #: html/pkgdel.php html/pkgmerge.php msgid "Select the checkbox to confirm action." @@ -512,11 +512,11 @@ msgstr "" #: html/pkgdel.php msgid "Confirm package deletion" -msgstr "Confirmar desaniciu de paquete" +msgstr "" #: html/pkgdel.php template/account_delete.php msgid "Delete" -msgstr "Desaniciar" +msgstr "" #: html/pkgdel.php msgid "Only Trusted Users and Developers can delete packages." @@ -583,7 +583,7 @@ msgstr "" msgid "" "Please do %snot%s use this form to report bugs. Use the package comments " "instead." -msgstr "%sNun%s uses esti formulariu pa informar de fallos, por favor. Usa nel so llugar los comentarios del paquete." +msgstr "" #: html/pkgflag.php msgid "" @@ -594,7 +594,7 @@ msgstr "" #: html/pkgflag.php template/pkgreq_close_form.php template/pkgreq_form.php #: template/pkgreq_results.php msgid "Comments" -msgstr "Comentarios" +msgstr "" #: html/pkgflag.php msgid "Flag" @@ -619,7 +619,7 @@ msgstr "" #: html/pkgmerge.php msgid "The following packages will be deleted: " -msgstr "Desaniciaránse los paquetes de darréu:" +msgstr "" #: html/pkgmerge.php msgid "Once the package has been merged it cannot be reversed. " @@ -627,7 +627,7 @@ msgstr "" #: html/pkgmerge.php msgid "Enter the package name you wish to merge the package into. " -msgstr "Introduz el nome del paquete al que deseyes amestar" +msgstr "" #: html/pkgmerge.php msgid "Merge into:" @@ -651,7 +651,7 @@ msgstr "" #: html/pkgreq.php template/pkgreq_close_form.php msgid "Close Request" -msgstr "Zarar solicitú" +msgstr "" #: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "First" @@ -663,7 +663,7 @@ msgstr "" #: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php template/tu_list.php msgid "Next" -msgstr "Siguiente" +msgstr "" #: html/pkgreq.php lib/aur.inc.php lib/pkgfuncs.inc.php msgid "Last" @@ -671,15 +671,15 @@ msgstr "" #: html/pkgreq.php template/header.php msgid "Requests" -msgstr "Solicitúes" +msgstr "" #: html/register.php template/header.php msgid "Register" -msgstr "Rexistrase" +msgstr "" #: html/register.php msgid "Use this form to create an account." -msgstr "Usa esti formulariu pa crear una cuenta." +msgstr "" #: html/tos.php msgid "Terms of Service" @@ -725,19 +725,19 @@ msgstr "" #: html/tu.php msgid "Vote ID not valid." -msgstr "Nun ye válida la ID del votu." +msgstr "" #: html/tu.php template/tu_list.php msgid "Current Votes" -msgstr "Votos actuales" +msgstr "" #: html/tu.php msgid "Past Votes" -msgstr "Votos pasaos" +msgstr "" #: html/voters.php template/tu_details.php msgid "Voters" -msgstr "Votantes" +msgstr "" #: lib/acctfuncs.inc.php msgid "" @@ -747,16 +747,16 @@ msgstr "" #: lib/acctfuncs.inc.php msgid "Missing User ID" -msgstr "Falta la ID d'usuariu" +msgstr "" #: lib/acctfuncs.inc.php msgid "The username is invalid." -msgstr "El nome d'usuariu nun ye válidu" +msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "It must be between %s and %s characters long" -msgstr "Tien de tar ente %s y %s carauteres de llargor" +msgstr "" #: lib/acctfuncs.inc.php msgid "Start and end with a letter or number" @@ -772,7 +772,7 @@ msgstr "" #: lib/acctfuncs.inc.php msgid "The email address is invalid." -msgstr "La direición de corréu nun ye válida." +msgstr "" #: lib/acctfuncs.inc.php msgid "The backup email address is invalid." @@ -784,19 +784,19 @@ msgstr "" #: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." -msgstr "La buelga de la clave PGP nun ye válida." +msgstr "" #: lib/acctfuncs.inc.php msgid "The SSH public key is invalid." -msgstr "La clave SSH pública nun ye válida." +msgstr "" #: lib/acctfuncs.inc.php msgid "Cannot increase account permissions." -msgstr "Nun puen aumentase los permisos de la cuenta." +msgstr "" #: lib/acctfuncs.inc.php msgid "Language is not currently supported." -msgstr "La llingua nun ta anguaño sofitada." +msgstr "" #: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." @@ -805,17 +805,17 @@ msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "The username, %s%s%s, is already in use." -msgstr "El nome d'usuariu, %s%s%s, yá ta n'usu." +msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "The address, %s%s%s, is already in use." -msgstr "La direición, %s%s%s, yá ta n'usu." +msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "The SSH public key, %s%s%s, is already in use." -msgstr "La llave pública SSH, %s%s%s, ye yá n'usu." +msgstr "" #: lib/acctfuncs.inc.php msgid "The CAPTCHA is missing." @@ -832,12 +832,12 @@ msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." -msgstr "Fallu intentando crear la cuenta, %s%s%s." +msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "La cuenta, %s%s%s, creóse con ésitu." +msgstr "" #: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." @@ -845,17 +845,17 @@ msgstr "" #: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "Primi nel enllaz d'aniciu de sesión d'enriba pa usar la to cuenta" +msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "No changes were made to the account, %s%s%s." -msgstr "Nun se fixeron camudancies na cuenta, %s%s%s." +msgstr "" #: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "La cuenta, %s%s%s, modificóse con ésitu." +msgstr "" #: lib/acctfuncs.inc.php msgid "" @@ -865,7 +865,7 @@ msgstr "" #: lib/acctfuncs.inc.php msgid "Account suspended" -msgstr "Cuenta suspendida" +msgstr "" #: lib/acctfuncs.inc.php #, php-format @@ -873,15 +873,15 @@ msgid "" "Your password has been reset. If you just created a new account, please use " "the link from the confirmation email to set an initial password. Otherwise, " "please request a reset key on the %sPassword Reset%s page." -msgstr "Reanicióse la to contraseña. Si tas acabantes crear una cuenta nueva, usa l'enllaz del corréu de confirmación p'afitar una contraseña inicial, por favor. D'otramiente, solicita una clave de reaniciu na páxina %sReaniciu de contraseña%s, por favor." +msgstr "" #: lib/acctfuncs.inc.php msgid "Bad username or password." -msgstr "Nome d'usuariu o contraseña incorreutos" +msgstr "" #: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "Asocedió un fallu intentando xenerar una sesión d'usuariu." +msgstr "" #: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." @@ -902,19 +902,19 @@ msgstr "" #: lib/aurjson.class.php lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit this comment." -msgstr "Nun tienes permisu pa editar esti comentariu." +msgstr "" #: lib/aurjson.class.php msgid "Comment does not exist." -msgstr "Nun esiste'l comentariu." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "Comment cannot be empty." -msgstr "Nun pue tar baleru'l comentariu." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "Comment has been added." -msgstr "Amestóse'l comentariu." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can edit package information." @@ -922,7 +922,7 @@ msgstr "" #: lib/pkgbasefuncs.inc.php msgid "Missing comment ID." -msgstr "Falta la ID del comentariu." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." @@ -946,11 +946,11 @@ msgstr "" #: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." -msgstr "Fallu recibiendo los detalles de paquete." +msgstr "" #: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Package details could not be found." -msgstr "Nun pudieron alcontrase los detalles del paquete." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." @@ -986,11 +986,11 @@ msgstr "" #: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to delete." -msgstr "Nun esbillesti dengún ficheru pa desaniciar." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." -msgstr "Desaniciáronse los paquetes esbillaos." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can adopt packages." @@ -1038,7 +1038,7 @@ msgstr "" #: lib/pkgbasefuncs.inc.php msgid "Couldn't add to notification list." -msgstr "Nun pudo amestase al llistáu d'avisos." +msgstr "" #: lib/pkgbasefuncs.inc.php #, php-format @@ -1060,15 +1060,15 @@ msgstr "" #: lib/pkgbasefuncs.inc.php msgid "You are not allowed to delete this comment." -msgstr "Nun tienes permisu pa desaniciar esti comentariu." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "Comment has been deleted." -msgstr "El comentariu amestóse." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "Comment has been edited." -msgstr "Editóse'l comentariu." +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "You are not allowed to edit the keywords of this package base." @@ -1085,7 +1085,7 @@ msgstr "" #: lib/pkgbasefuncs.inc.php #, php-format msgid "Invalid user name: %s" -msgstr "Nome d'usuariu non válidu: %s" +msgstr "" #: lib/pkgbasefuncs.inc.php msgid "The package base co-maintainers have been updated." @@ -1093,7 +1093,7 @@ msgstr "" #: lib/pkgfuncs.inc.php template/pkgbase_details.php msgid "View packages details for" -msgstr "Ver detalles de paquetes pa" +msgstr "" #: lib/pkgfuncs.inc.php #, php-format @@ -1110,19 +1110,19 @@ msgstr "" #: lib/pkgreqfuncs.inc.php msgid "The comment field must not be empty." -msgstr "El campu del comentariu nun tien de tar baleru." +msgstr "" #: lib/pkgreqfuncs.inc.php msgid "Invalid request type." -msgstr "Triba de solicitú non válida." +msgstr "" #: lib/pkgreqfuncs.inc.php msgid "Added request successfully." -msgstr "Amestada con ésitu la solicitú." +msgstr "" #: lib/pkgreqfuncs.inc.php msgid "Invalid reason." -msgstr "Razón non válida." +msgstr "" #: lib/pkgreqfuncs.inc.php msgid "Only TUs and developers can close requests." @@ -1130,41 +1130,41 @@ msgstr "" #: lib/pkgreqfuncs.inc.php msgid "Request closed successfully." -msgstr "Solicitú zarrada con ésitu." +msgstr "" #: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "Pues usar esti formulariu pa desaniciar la cuenta del AUR %s dafechu." +msgstr "" #: template/account_delete.php #, php-format msgid "%sWARNING%s: This action cannot be undone." -msgstr "%sAVISU%s: Esta aición nun pue desfacese." +msgstr "" #: template/account_delete.php msgid "Confirm deletion" -msgstr "Confirmar desaniciu" +msgstr "" #: template/account_details.php template/account_edit_form.php #: template/account_search_results.php template/search_accounts_form.php msgid "Username" -msgstr "Nome d'usuariu" +msgstr "" #: template/account_details.php template/account_edit_form.php #: template/search_accounts_form.php msgid "Account Type" -msgstr "Triba de cuenta" +msgstr "" #: template/account_details.php template/tu_details.php #: template/tu_last_votes_list.php template/tu_list.php msgid "User" -msgstr "Usuariu" +msgstr "" #: template/account_details.php template/account_edit_form.php #: template/search_accounts_form.php msgid "Developer" -msgstr "Desendolcador" +msgstr "" #: template/account_details.php template/account_edit_form.php #: template/search_accounts_form.php @@ -1174,7 +1174,7 @@ msgstr "" #: template/account_details.php template/account_edit_form.php #: template/search_accounts_form.php msgid "Email Address" -msgstr "Direición de corréu" +msgstr "" #: template/account_details.php msgid "hidden" @@ -1183,7 +1183,7 @@ msgstr "" #: template/account_details.php template/account_edit_form.php #: template/account_search_results.php template/search_accounts_form.php msgid "Real Name" -msgstr "Nome real" +msgstr "" #: template/account_details.php template/account_edit_form.php msgid "Homepage" @@ -1192,25 +1192,25 @@ msgstr "" #: template/account_details.php template/account_edit_form.php #: template/account_search_results.php template/search_accounts_form.php msgid "IRC Nick" -msgstr "Alcuñu nel IRC" +msgstr "" #: template/account_details.php template/account_edit_form.php #: template/account_search_results.php msgid "PGP Key Fingerprint" -msgstr "Buelga de clave PGP" +msgstr "" #: template/account_details.php template/account_search_results.php #: template/pkgreq_results.php msgid "Status" -msgstr "Estáu" +msgstr "" #: template/account_details.php msgid "Inactive since" -msgstr "Inactivu dende" +msgstr "" #: template/account_details.php template/account_search_results.php msgid "Active" -msgstr "Activu" +msgstr "" #: template/account_details.php msgid "Registration date:" @@ -1220,7 +1220,7 @@ msgstr "" #: template/pkg_details.php template/pkgreq_results.php #: template/tu_details.php msgid "unknown" -msgstr "Desconocíu" +msgstr "" #: template/account_details.php msgid "Last Login" @@ -1228,7 +1228,7 @@ msgstr "" #: template/account_details.php msgid "Never" -msgstr "Enxamás" +msgstr "" #: template/account_details.php msgid "View this user's packages" @@ -1245,7 +1245,7 @@ msgstr "" #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "Primi %sequí%s si quies desaniciar esta cuenta dafechu." +msgstr "" #: template/account_edit_form.php #, php-format @@ -1259,7 +1259,7 @@ msgstr "" #: template/account_edit_form.php msgid "required" -msgstr "riquíu" +msgstr "" #: template/account_edit_form.php msgid "" @@ -1269,19 +1269,19 @@ msgstr "" #: template/account_edit_form.php template/search_accounts_form.php msgid "Normal user" -msgstr "Usuariu normal" +msgstr "" #: template/account_edit_form.php template/search_accounts_form.php msgid "Trusted user" -msgstr "Usuariu d'Enfotu" +msgstr "" #: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" -msgstr "Cuenta suspendida" +msgstr "" #: template/account_edit_form.php msgid "Inactive" -msgstr "Inactivu" +msgstr "" #: template/account_edit_form.php msgid "" @@ -1325,7 +1325,7 @@ msgstr "" #: template/account_edit_form.php msgid "Language" -msgstr "Llingua" +msgstr "" #: template/account_edit_form.php msgid "Timezone" @@ -1339,17 +1339,17 @@ msgstr "" #: template/account_edit_form.php msgid "Re-type password" -msgstr "Teclexa de nueves la contraseña" +msgstr "" #: template/account_edit_form.php msgid "" "The following information is only required if you want to submit packages to" " the Arch User Repository." -msgstr "La información de darréu namái se rique si quies xubir paquetes al AUR." +msgstr "" #: template/account_edit_form.php msgid "SSH Public Key" -msgstr "Clave SSH pública" +msgstr "" #: template/account_edit_form.php msgid "Notification settings" @@ -1388,15 +1388,15 @@ msgstr "" #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php msgid "Update" -msgstr "Anovar" +msgstr "" #: template/account_edit_form.php msgid "Create" -msgstr "Crear" +msgstr "" #: template/account_edit_form.php template/search_accounts_form.php msgid "Reset" -msgstr "Reafitar" +msgstr "" #: template/account_search_results.php msgid "No results matched your search criteria." @@ -1404,27 +1404,27 @@ msgstr "" #: template/account_search_results.php msgid "Edit Account" -msgstr "Editar cuenta" +msgstr "" #: template/account_search_results.php msgid "Suspended" -msgstr "Suspendíu" +msgstr "" #: template/account_search_results.php msgid "Edit" -msgstr "Editar" +msgstr "" #: template/account_search_results.php msgid "Less" -msgstr "Menos" +msgstr "" #: template/account_search_results.php msgid "More" -msgstr "Más" +msgstr "" #: template/account_search_results.php msgid "No more results to display." -msgstr "Nun hai más resultaos p'amosar." +msgstr "" #: template/comaintainers_form.php #, php-format @@ -1434,11 +1434,11 @@ msgstr "" #: template/comaintainers_form.php msgid "Users" -msgstr "Usuarios" +msgstr "" #: template/comaintainers_form.php template/pkg_comment_form.php msgid "Save" -msgstr "Guardar" +msgstr "" #: template/flag_comment.php #, php-format @@ -1466,27 +1466,27 @@ msgstr "" #: template/header.php msgid " My Account" -msgstr "La mio cuenta" +msgstr "" #: template/pkgbase_actions.php msgid "Package Actions" -msgstr "Aiciones de paquete" +msgstr "" #: template/pkgbase_actions.php msgid "View PKGBUILD" -msgstr "Ver PKGBUILD" +msgstr "" #: template/pkgbase_actions.php msgid "View Changes" -msgstr "Ver camudancies" +msgstr "" #: template/pkgbase_actions.php msgid "Download snapshot" -msgstr "Baxar instantánea" +msgstr "" #: template/pkgbase_actions.php msgid "Search wiki" -msgstr "Guetar na wiki" +msgstr "" #: template/pkgbase_actions.php #, php-format @@ -1495,19 +1495,19 @@ msgstr "" #: template/pkgbase_actions.php msgid "Flag package out-of-date" -msgstr "Marcáu como non actualizáu" +msgstr "" #: template/pkgbase_actions.php msgid "Unflag package" -msgstr "Quitar marca de non actualizáu" +msgstr "" #: template/pkgbase_actions.php msgid "Remove vote" -msgstr "Quitar votu" +msgstr "" #: template/pkgbase_actions.php msgid "Vote for this package" -msgstr "Votar pol paquete" +msgstr "" #: template/pkgbase_actions.php scripts/notify.py msgid "Disable notifications" @@ -1519,7 +1519,7 @@ msgstr "" #: template/pkgbase_actions.php msgid "Manage Co-Maintainers" -msgstr "Alministra comantenedores" +msgstr "" #: template/pkgbase_actions.php #, php-format @@ -1534,11 +1534,11 @@ msgstr "" #: template/pkgbase_details.php msgid "Package Base Details" -msgstr "Detalles del paquete base" +msgstr "" #: template/pkgbase_details.php template/pkg_details.php msgid "Git Clone URL" -msgstr "URL pa clonar con Git" +msgstr "" #: template/pkgbase_details.php template/pkg_details.php msgid "read-only" @@ -1551,7 +1551,7 @@ msgstr "" #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php msgid "Keywords" -msgstr "Pallabres clave" +msgstr "" #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php @@ -1561,7 +1561,7 @@ msgstr "" #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php template/pkg_search_results.php msgid "Maintainer" -msgstr "Caltenedor" +msgstr "" #: template/pkgbase_details.php template/pkg_details.php msgid "Last Packager" @@ -1570,7 +1570,7 @@ msgstr "" #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php template/pkg_search_results.php msgid "Votes" -msgstr "Votos" +msgstr "" #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php template/pkg_search_results.php @@ -1592,7 +1592,7 @@ msgstr "" #: template/pkg_comment_box.php template/pkg_comment_form.php msgid "Add Comment" -msgstr "Amestar comentariu" +msgstr "" #: template/pkg_comment_form.php msgid "" @@ -1611,7 +1611,7 @@ msgstr "" #: template/pkg_comments.php msgid "Latest Comments" -msgstr "Comentarios caberos" +msgstr "" #: template/pkg_comments.php msgid "Comments for" @@ -1658,7 +1658,7 @@ msgstr "" #: template/pkg_comments.php msgid "Delete comment" -msgstr "Desaniciar comentariu" +msgstr "" #: template/pkg_comments.php msgid "Pin comment" @@ -1670,15 +1670,15 @@ msgstr "" #: template/pkg_details.php msgid "Package Details" -msgstr "Detalles del paquete" +msgstr "" #: template/pkg_details.php template/pkg_search_form.php msgid "Package Base" -msgstr "Paquete base" +msgstr "" #: template/pkg_details.php template/pkg_search_results.php msgid "Description" -msgstr "Descripción" +msgstr "" #: template/pkg_details.php msgid "Upstream URL" @@ -1690,11 +1690,11 @@ msgstr "" #: template/pkg_details.php msgid "Licenses" -msgstr "Llicencies" +msgstr "" #: template/pkg_details.php msgid "Groups" -msgstr "Grupos" +msgstr "" #: template/pkg_details.php msgid "Conflicts" @@ -1702,48 +1702,48 @@ msgstr "" #: template/pkg_details.php msgid "Provides" -msgstr "Apurre" +msgstr "" #: template/pkg_details.php msgid "Replaces" -msgstr "Troca" +msgstr "" #: template/pkg_details.php msgid "Dependencies" -msgstr "Dependencies" +msgstr "" #: template/pkg_details.php msgid "Required by" -msgstr "Riquíu por" +msgstr "" #: template/pkg_details.php msgid "Sources" -msgstr "Fontes" +msgstr "" #: template/pkgreq_close_form.php #, php-format msgid "Use this form to close the request for package base %s%s%s." -msgstr "Usa esti formulariu pa zarrar la solicitú pal paquete base %s%s%s." +msgstr "" #: template/pkgreq_close_form.php msgid "" "The comments field can be left empty. However, it is highly recommended to " "add a comment when rejecting a request." -msgstr "El campu de comentarios pue dexase baleru, Por embargu, encamiéntase amestar un comentariu al refugar una solicitú." +msgstr "" #: template/pkgreq_close_form.php msgid "Reason" -msgstr "Razón" +msgstr "" #: template/pkgreq_close_form.php template/pkgreq_results.php #: template/tu_details.php msgid "Accepted" -msgstr "Aceutáu" +msgstr "" #: template/pkgreq_close_form.php template/pkgreq_results.php #: template/tu_details.php msgid "Rejected" -msgstr "Refugáu" +msgstr "" #: template/pkgreq_form.php #, php-format @@ -1754,15 +1754,15 @@ msgstr "" #: template/pkgreq_form.php msgid "Request type" -msgstr "Triba de solicitú" +msgstr "" #: template/pkgreq_form.php msgid "Deletion" -msgstr "Desaniciu" +msgstr "" #: template/pkgreq_form.php msgid "Orphan" -msgstr "Güérfanu" +msgstr "" #: template/pkgreq_form.php template/pkg_search_results.php msgid "Merge into" @@ -1805,11 +1805,11 @@ msgstr[1] "" #: template/pkgreq_results.php template/pkg_search_results.php #, php-format msgid "Page %d of %d." -msgstr "Páxina %d de %d" +msgstr "" #: template/pkgreq_results.php msgid "Package" -msgstr "Paquete" +msgstr "" #: template/pkgreq_results.php msgid "Filed by" @@ -1817,7 +1817,7 @@ msgstr "" #: template/pkgreq_results.php msgid "Date" -msgstr "Data" +msgstr "" #: template/pkgreq_results.php #, php-format @@ -1830,24 +1830,24 @@ msgstr[1] "" #, php-format msgid "~%d hour left" msgid_plural "~%d hours left" -msgstr[0] "Falta ~%d hora" -msgstr[1] "Falten ~%d hores" +msgstr[0] "" +msgstr[1] "" #: template/pkgreq_results.php msgid "<1 hour left" -msgstr "Falta menos d'una hora" +msgstr "" #: template/pkgreq_results.php msgid "Accept" -msgstr "Aceutar" +msgstr "" #: template/pkgreq_results.php msgid "Locked" -msgstr "Bloquiáu" +msgstr "" #: template/pkgreq_results.php msgid "Close" -msgstr "Zarrar" +msgstr "" #: template/pkgreq_results.php msgid "Pending" @@ -1855,23 +1855,23 @@ msgstr "" #: template/pkgreq_results.php msgid "Closed" -msgstr "Zarráu" +msgstr "" #: template/pkg_search_form.php msgid "Name, Description" -msgstr "Nome, descripción" +msgstr "" #: template/pkg_search_form.php msgid "Name Only" -msgstr "Namái nome" +msgstr "" #: template/pkg_search_form.php msgid "Exact Name" -msgstr "Nome exautu" +msgstr "" #: template/pkg_search_form.php msgid "Exact Package Base" -msgstr "Paquete base exautu" +msgstr "" #: template/pkg_search_form.php msgid "Co-maintainer" @@ -1883,7 +1883,7 @@ msgstr "" #: template/pkg_search_form.php msgid "All" -msgstr "Too" +msgstr "" #: template/pkg_search_form.php msgid "Flagged" @@ -1895,7 +1895,7 @@ msgstr "" #: template/pkg_search_form.php template/pkg_search_results.php msgid "Name" -msgstr "Nome" +msgstr "" #: template/pkg_search_form.php template/pkg_search_results.php #: template/tu_details.php template/tu_list.php @@ -1908,11 +1908,11 @@ msgstr "" #: template/pkg_search_form.php msgid "Ascending" -msgstr "Ascendente" +msgstr "" #: template/pkg_search_form.php msgid "Descending" -msgstr "Descendente" +msgstr "" #: template/pkg_search_form.php msgid "Enter search criteria" @@ -1920,31 +1920,31 @@ msgstr "" #: template/pkg_search_form.php msgid "Search by" -msgstr "Guetar per" +msgstr "" #: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" -msgstr "Ensin anovar" +msgstr "" #: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" -msgstr "Ordenar per" +msgstr "" #: template/pkg_search_form.php msgid "Sort order" -msgstr "Mou d'ordenación" +msgstr "" #: template/pkg_search_form.php msgid "Per page" -msgstr "Per páxina" +msgstr "" #: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" -msgstr "Dir" +msgstr "" #: template/pkg_search_form.php msgid "Orphans" -msgstr "Güérfanos" +msgstr "" #: template/pkg_search_results.php msgid "Error retrieving package list." @@ -1952,18 +1952,18 @@ msgstr "" #: template/pkg_search_results.php msgid "No packages matched your search criteria." -msgstr "Nun hai paquetes que concasen col criteriu de gueta." +msgstr "" #: template/pkg_search_results.php #, php-format msgid "%d package found." msgid_plural "%d packages found." -msgstr[0] "Alcontróse %d paquete." -msgstr[1] "Alcontráronse %d paquetes" +msgstr[0] "" +msgstr[1] "" #: template/pkg_search_results.php msgid "Version" -msgstr "Versión" +msgstr "" #: template/pkg_search_results.php #, php-format @@ -1975,15 +1975,15 @@ msgstr "" #: template/pkg_search_results.php template/tu_details.php #: template/tu_list.php msgid "Yes" -msgstr "Sí" +msgstr "" #: template/pkg_search_results.php msgid "orphan" -msgstr "güérfanu" +msgstr "" #: template/pkg_search_results.php msgid "Actions" -msgstr "Aiciones" +msgstr "" #: template/pkg_search_results.php msgid "Unflag Out-of-date" @@ -2015,39 +2015,39 @@ msgstr "" #: template/stats/general_stats_table.php msgid "Statistics" -msgstr "Estadístiques" +msgstr "" #: template/stats/general_stats_table.php msgid "Orphan Packages" -msgstr "Paquetes güérfanos" +msgstr "" #: template/stats/general_stats_table.php msgid "Packages added in the past 7 days" -msgstr "Paquetes amestaos nos pasaos 7 díes" +msgstr "" #: template/stats/general_stats_table.php msgid "Packages updated in the past 7 days" -msgstr "Paquetes anovaos nos pasaos 7 díes" +msgstr "" #: template/stats/general_stats_table.php msgid "Packages updated in the past year" -msgstr "Paquetes anovaos nel añu caberu" +msgstr "" #: template/stats/general_stats_table.php msgid "Packages never updated" -msgstr "Paquetes qu'enxamás s'anovaron" +msgstr "" #: template/stats/general_stats_table.php msgid "Registered Users" -msgstr "Usuarios rexistraos." +msgstr "" #: template/stats/general_stats_table.php msgid "Trusted Users" -msgstr "Usuarios d'enfotu." +msgstr "" #: template/stats/updates_table.php msgid "Recent Updates" -msgstr "Anovamientos recientes" +msgstr "" #: template/stats/updates_table.php msgid "more" @@ -2055,7 +2055,7 @@ msgstr "" #: template/stats/user_table.php msgid "My Statistics" -msgstr "Les mios estadístiques" +msgstr "" #: template/tu_details.php msgid "Proposal Details" @@ -2072,27 +2072,27 @@ msgstr "" #: template/tu_details.php template/tu_list.php msgid "End" -msgstr "Fin" +msgstr "" #: template/tu_details.php msgid "Result" -msgstr "Resultáu" +msgstr "" #: template/tu_details.php template/tu_list.php msgid "No" -msgstr "Non" +msgstr "" #: template/tu_details.php msgid "Abstain" -msgstr "Astención" +msgstr "" #: template/tu_details.php msgid "Total" -msgstr "Total" +msgstr "" #: template/tu_details.php msgid "Participation" -msgstr "Participación" +msgstr "" #: template/tu_last_votes_list.php msgid "Last Votes by TU" @@ -2104,7 +2104,7 @@ msgstr "" #: template/tu_last_votes_list.php template/tu_list.php msgid "No results found." -msgstr "Nun s'alcontró dengún resultáu." +msgstr "" #: template/tu_list.php msgid "Start" diff --git a/po/ja.po b/po/ja.po index 337e7ee8..d51319d2 100644 --- a/po/ja.po +++ b/po/ja.po @@ -5,15 +5,15 @@ # Translators: # kusakata, 2013 # kusakata, 2013 -# kusakata, 2013-2018 +# kusakata, 2013-2018,2020 # 尾ノ上卓朗 , 2017 msgid "" msgstr "" "Project-Id-Version: aurweb\n" "Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2020-01-31 08:29+0000\n" -"Last-Translator: Lukas Fleischer\n" +"PO-Revision-Date: 2020-02-26 12:49+0000\n" +"Last-Translator: kusakata\n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aurweb/language/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -78,7 +78,7 @@ msgstr "あなたはこのアカウントを編集する権利を持っていま #: html/account.php lib/acctfuncs.inc.php msgid "Invalid password." -msgstr "" +msgstr "不正なパスワード。" #: html/account.php msgid "Use this form to search existing accounts." @@ -375,7 +375,7 @@ msgstr "ログイン情報を入力してください" #: html/login.php msgid "User name or primary email address" -msgstr "" +msgstr "ユーザー名またはメインのメールアドレス" #: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" @@ -439,7 +439,7 @@ msgstr "パスワードのリセットが成功しました。" #: html/passreset.php msgid "Confirm your user name or primary e-mail address:" -msgstr "" +msgstr "ユーザー名またはメインのメールアドレスの確認:" #: html/passreset.php msgid "Enter your new password:" @@ -458,11 +458,11 @@ msgstr "続行" msgid "" "If you have forgotten the user name and the primary e-mail address you used " "to register, please send a message to the %saur-general%s mailing list." -msgstr "" +msgstr "登録したときに使用したユーザー名とメインのメールアドレスを忘れてしまった場合、メッセージを %saur-general%s メーリングリストに送信してください。" #: html/passreset.php msgid "Enter your user name or your primary e-mail address:" -msgstr "" +msgstr "ユーザー名またはメインのメールアドレスを入力:" #: html/pkgbase.php msgid "Package Bases" @@ -769,7 +769,7 @@ msgstr "ピリオド、アンダーライン、ハイフンはひとつだけ含 #: lib/acctfuncs.inc.php msgid "Please confirm your new password." -msgstr "" +msgstr "新しいパスワードを確認してください。" #: lib/acctfuncs.inc.php msgid "The email address is invalid." @@ -777,7 +777,7 @@ msgstr "メールアドレスが不正です。" #: lib/acctfuncs.inc.php msgid "The backup email address is invalid." -msgstr "" +msgstr "バックアップメールアドレスが不正です。" #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." @@ -820,15 +820,15 @@ msgstr "SSH 公開鍵、%s%s%s は既に使われています。" #: lib/acctfuncs.inc.php msgid "The CAPTCHA is missing." -msgstr "" +msgstr "CAPTCHA が入力されていません。" #: lib/acctfuncs.inc.php msgid "This CAPTCHA has expired. Please try again." -msgstr "" +msgstr "CAPTCHA の有効期限が切れました。もう一度入力してください。" #: lib/acctfuncs.inc.php msgid "The entered CAPTCHA answer is invalid." -msgstr "" +msgstr "入力された CAPTCHA の答えが合っていません。" #: lib/acctfuncs.inc.php #, php-format @@ -1241,7 +1241,7 @@ msgstr "このユーザーのアカウントを編集" #: template/account_details.php msgid "List this user's comments" -msgstr "" +msgstr "このユーザーのコメントを表示" #: template/account_edit_form.php #, php-format @@ -1256,7 +1256,7 @@ msgstr "ユーザーの詳細は%sこちら%sをクリック。" #: template/account_edit_form.php #, php-format msgid "Click %shere%s to list the comments made by this account." -msgstr "" +msgstr "このアカウントによって作成されたコメントを表示するには %sこちら%s をクリック。" #: template/account_edit_form.php msgid "required" @@ -1299,30 +1299,30 @@ msgid "" "If you do not hide your email address, it is visible to all registered AUR " "users. If you hide your email address, it is visible to members of the Arch " "Linux staff only." -msgstr "" +msgstr "メールアドレスを非公開にしない場合、登録されている AUR ユーザー全てから閲覧できる状態になります。メールアドレスを非表示にした場合、Arch Linux のスタッフからしか表示されません。" #: template/account_edit_form.php msgid "Backup Email Address" -msgstr "" +msgstr "バックアップメールアドレス" #: template/account_edit_form.php msgid "" "Optionally provide a secondary email address that can be used to restore " "your account in case you lose access to your primary email address." -msgstr "" +msgstr "メールアドレスをふたつ登録することで、メインのメールアドレスが使えなくなってしまった場合にアカウントを復帰することができます。" #: template/account_edit_form.php msgid "" "Password reset links are always sent to both your primary and your backup " "email address." -msgstr "" +msgstr "パスワードのリセットリンクはメインとバックアップ両方のメールアドレスに送信されます。" #: template/account_edit_form.php #, php-format msgid "" "Your backup email address is always only visible to members of the Arch " "Linux staff, independent of the %s setting." -msgstr "" +msgstr "%s の設定に関わらず、バックアップメールアドレスを確認できるのは Arch Linux のスタッフメンバーだけです。" #: template/account_edit_form.php msgid "Language" @@ -1336,7 +1336,7 @@ msgstr "タイムゾーン" msgid "" "If you want to change the password, enter a new password and confirm the new" " password by entering it again." -msgstr "" +msgstr "パスワードを変更したい場合、新しいパスワードを入力して、もう一度確認のため新しいパスワードを入力してください。" #: template/account_edit_form.php msgid "Re-type password" @@ -1370,21 +1370,21 @@ msgstr "所有者の変更の通知" #: template/account_edit_form.php msgid "To confirm the profile changes, please enter your current password:" -msgstr "" +msgstr "プロフィールの変更を確認するため、現在のパスワードを入力してください:" #: template/account_edit_form.php msgid "Your current password" -msgstr "" +msgstr "現在のパスワード" #: template/account_edit_form.php msgid "" "To protect the AUR against automated account creation, we kindly ask you to " "provide the output of the following command:" -msgstr "" +msgstr "機械的なアカウント作成から AUR を保護するため、次のコマンドの出力結果を入力してください:" #: template/account_edit_form.php msgid "Answer" -msgstr "" +msgstr "答え" #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php @@ -1546,7 +1546,7 @@ msgstr "リードオンリー" #: template/pkgbase_details.php template/pkg_details.php msgid "click to copy" -msgstr "" +msgstr "クリックしてコピー" #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php @@ -1598,12 +1598,12 @@ msgstr "コメントを投稿する" msgid "" "Git commit identifiers referencing commits in the AUR package repository and" " URLs are converted to links automatically." -msgstr "" +msgstr "AUR パッケージリポジトリの Git コミット ID や URL は自動的にリンクに変換されます。" #: template/pkg_comment_form.php #, php-format msgid "%sMarkdown syntax%s is partially supported." -msgstr "" +msgstr "%sMarkdown 構文%s が一部サポートされています。" #: template/pkg_comments.php msgid "Pinned Comments" @@ -1615,7 +1615,7 @@ msgstr "最新のコメント" #: template/pkg_comments.php msgid "Comments for" -msgstr "" +msgstr "コメント履歴" #: template/pkg_comments.php #, php-format @@ -1630,7 +1630,7 @@ msgstr "匿名ユーザーが %s にコメントを投稿しました" #: template/pkg_comments.php #, php-format msgid "Commented on package %s on %s" -msgstr "" +msgstr "%s パッケージのコメント欄に %s に投稿したコメント" #: template/pkg_comments.php #, php-format @@ -2212,7 +2212,7 @@ msgid "" "\n" "-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "" +msgstr "{user} [1] によって {old} [2] は {new} [3] にマージされました。\n\n-- \n新しいパッケージの通知を受け取りたくない場合、[3] を開いて \"{label}\" をクリックしてください。" #: scripts/notify.py #, python-brace-format From 279d8042e3889402079a4d0eaf10a386fdd4a2a9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 27 Mar 2020 08:37:46 -0400 Subject: [PATCH 0525/1891] Add new upgrade instructions Signed-off-by: Lukas Fleischer --- upgrading/{4.9.0.txt => 5.x.x.txt} | 8 ++++++++ 1 file changed, 8 insertions(+) rename upgrading/{4.9.0.txt => 5.x.x.txt} (54%) diff --git a/upgrading/4.9.0.txt b/upgrading/5.x.x.txt similarity index 54% rename from upgrading/4.9.0.txt rename to upgrading/5.x.x.txt index 241f24af..94f91c69 100644 --- a/upgrading/4.9.0.txt +++ b/upgrading/5.x.x.txt @@ -1,3 +1,11 @@ +Starting from release 5.0.0, Alembic is used for managing database migrations. + +Run `alembic upgrade head` from the aurweb root directory to upgrade your +database after upgrading the source code to a new release. + +When upgrading from 4.8.0, you also need to execute the following manual SQL +statements before doing so. + 1. Add new columns to store the timestamp and UID when closing requests: ---- From 853ed9a950cc3b70b57be3deb6d20c131c0cbfe3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Fri, 27 Mar 2020 08:51:15 -0400 Subject: [PATCH 0526/1891] Release 5.0.0 Signed-off-by: Lukas Fleischer --- web/lib/version.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php index 93ab51b2..27eef718 100644 --- a/web/lib/version.inc.php +++ b/web/lib/version.inc.php @@ -1,3 +1,3 @@ Date: Sun, 5 Apr 2020 10:56:35 -0400 Subject: [PATCH 0527/1891] Fix invalid session ID check Signed-off-by: Lukas Fleischer --- web/lib/aur.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index dbcc23a4..f4ad6b47 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -50,7 +50,7 @@ function check_sid() { $result = $dbh->query($q); $row = $result->fetch(PDO::FETCH_NUM); - if (!$row[0]) { + if (!$row) { # Invalid SessionID - hacker alert! # $failed = 1; From 169607f153f1dcb7bb8e7ebea1c53bac93d376b3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 5 Apr 2020 11:00:18 -0400 Subject: [PATCH 0528/1891] Fix PHP notices in the account form Signed-off-by: Lukas Fleischer --- web/html/account.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/html/account.php b/web/html/account.php index c05d136d..d70f4ced 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -25,7 +25,7 @@ if ($action == "UpdateAccount") { $update_account_message = ''; /* Details for account being updated */ /* Verify user permissions and that the request is a valid POST */ - if (can_edit_account($row) && check_token()) { + if ($row && can_edit_account($row) && check_token()) { /* Update the details for the existing account */ list($success, $update_account_message) = process_account_form( "edit", "UpdateAccount", @@ -55,7 +55,7 @@ if ($action == "UpdateAccount") { } } -if ($action == "AccountInfo") { +if ($row && $action == "AccountInfo") { html_header(__('Account') . ' ' . $row['Username']); } else { html_header(__('Accounts')); @@ -122,7 +122,7 @@ if (isset($_COOKIE["AURSID"])) { } elseif ($action == "DeleteAccount") { /* Details for account being deleted. */ - if (can_edit_account($row)) { + if ($row && can_edit_account($row)) { $uid_removal = $row['ID']; $uid_session = uid_from_sid($_COOKIE['AURSID']); $username = $row['Username']; @@ -155,7 +155,7 @@ if (isset($_COOKIE["AURSID"])) { } elseif ($action == "UpdateAccount") { print $update_account_message; - if (!$success) { + if ($row && !$success) { display_account_form("UpdateAccount", in_request("U"), in_request("T"), @@ -181,7 +181,7 @@ if (isset($_COOKIE["AURSID"])) { } } elseif ($action == "ListComments") { - if (has_credential(CRED_ACCOUNT_LIST_COMMENTS, array($row["ID"]))) { + if ($row && has_credential(CRED_ACCOUNT_LIST_COMMENTS, array($row["ID"]))) { # display the comment list if they're a TU/dev $total_comment_count = account_comments_count($row["ID"]); From 03a6fa2f7ec927625c64f980c3408ed395a9dcfc Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sat, 22 Aug 2020 22:08:43 +0200 Subject: [PATCH 0529/1891] Call sendmail with to, not recipient After f7a57c8 (Localize notification emails, 2018-05-17), the server.sendmail line was not updated to now send the to the email address but instead sends to (email, 'en') and as sendmail accepts an iterable an email is also send to 'en'. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 5b18a476..899f8acc 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -116,7 +116,7 @@ class Notification: server.login(user, passwd) server.set_debuglevel(0) - server.sendmail(sender, recipient, msg.as_bytes()) + server.sendmail(sender, to, msg.as_bytes()) server.quit() From c4f4ac510be1898e6969d13dd4f37c0a3f807aff Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 27 Aug 2020 07:11:17 -0400 Subject: [PATCH 0530/1891] Deliver emails to Cc in smtplib code path When using the sendmail() function with smtplib.SMTP or smtplib.SMTP_SSL, the list of actual recipients for the email (to be translated to RCPT commands) has to be provided as a parameter. Update the notification script and add all Cc recipients to that parameter. Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 18 ++++++++++++------ test/t2500-notify.t | 16 +++++++++++++--- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 899f8acc..9d4f3bde 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -14,10 +14,6 @@ import aurweb.l10n aur_location = aurweb.config.get('options', 'aur_location') -def headers_cc(cclist): - return {'Cc': str.join(', ', cclist)} - - def headers_msgid(thread_id): return {'Message-ID': thread_id} @@ -53,6 +49,9 @@ class Notification: def get_headers(self): return {} + def get_cc(self): + return [] + def get_body_fmt(self, lang): body = '' for line in self.get_body(lang).splitlines(): @@ -80,6 +79,8 @@ class Notification: msg['From'] = sender msg['Reply-to'] = reply_to msg['To'] = to + if self.get_cc(): + msg['Cc'] = str.join(', ', self.get_cc()) msg['X-AUR-Reason'] = reason msg['Date'] = email.utils.formatdate(localtime=True) @@ -116,6 +117,7 @@ class Notification: server.login(user, passwd) server.set_debuglevel(0) + deliver_to = [to] + self.get_cc() server.sendmail(sender, to, msg.as_bytes()) server.quit() @@ -444,6 +446,9 @@ class RequestOpenNotification(Notification): def get_recipients(self): return [(self._to, 'en')] + def get_cc(self): + return self._cc + def get_subject(self, lang): return '[PRQ#%d] %s Request for %s' % \ (self._reqid, self._reqtype.title(), self._pkgbase) @@ -472,7 +477,6 @@ class RequestOpenNotification(Notification): # Use a deterministic Message-ID for the first email referencing a # request. headers = headers_msgid(thread_id) - headers.update(headers_cc(self._cc)) return headers @@ -502,6 +506,9 @@ class RequestCloseNotification(Notification): def get_recipients(self): return [(self._to, 'en')] + def get_cc(self): + return self._cc + def get_subject(self, lang): return '[PRQ#%d] %s Request for %s %s' % (self._reqid, self._reqtype.title(), @@ -531,7 +538,6 @@ class RequestCloseNotification(Notification): def get_headers(self): thread_id = '' headers = headers_reply(thread_id) - headers.update(headers_cc(self._cc)) return headers diff --git a/test/t2500-notify.t b/test/t2500-notify.t index 5ef64c18..713b31e3 100755 --- a/test/t2500-notify.t +++ b/test/t2500-notify.t @@ -277,13 +277,18 @@ test_expect_success 'Test subject and body of merge notifications.' ' test_cmp actual expected ' -test_expect_success 'Test subject and body of request open notifications.' ' +test_expect_success 'Test Cc, subject and body of request open notifications.' ' cat <<-EOD | sqlite3 aur.db && /* Use package request IDs which can be distinguished from other IDs. */ - INSERT INTO PackageRequests (ID, PackageBaseID, PackageBaseName, UsersID, ReqTypeID, Comments, ClosureComment) VALUES (3001, 1001, "foobar", 1, 1, "This is a request test comment.", ""); + INSERT INTO PackageRequests (ID, PackageBaseID, PackageBaseName, UsersID, ReqTypeID, Comments, ClosureComment) VALUES (3001, 1001, "foobar", 2, 1, "This is a request test comment.", ""); EOD >sendmail.out && "$NOTIFY" request-open 1 3001 orphan 1001 && + grep ^Cc: sendmail.out >actual && + cat <<-EOD >expected && + Cc: user@localhost, tu@localhost + EOD + test_cmp actual expected && grep ^Subject: sendmail.out >actual && cat <<-EOD >expected && Subject: [PRQ#3001] Orphan Request for foobar @@ -324,9 +329,14 @@ test_expect_success 'Test subject and body of request open notifications for mer test_cmp actual expected ' -test_expect_success 'Test subject and body of request close notifications.' ' +test_expect_success 'Test Cc, subject and body of request close notifications.' ' >sendmail.out && "$NOTIFY" request-close 1 3001 accepted && + grep ^Cc: sendmail.out >actual && + cat <<-EOD >expected && + Cc: user@localhost, tu@localhost + EOD + test_cmp actual expected && grep ^Subject: sendmail.out >actual && cat <<-EOD >expected && Subject: [PRQ#3001] Deletion Request for foobar Accepted From 613364b773c6352ae17aea3d2a74786fe0ca607d Mon Sep 17 00:00:00 2001 From: Morten Linderud Date: Fri, 4 Sep 2020 09:27:34 +0200 Subject: [PATCH 0531/1891] pkg_search_page: Limit number of results on package search The current package search query is quite poorly optimized and becomes a resource hog when the offsets gets large enough. This DoSes the service. A quick fix is to just ensure we have some limit to the number of hits we return. The current hardcoding of 2500 is based on the following: * 250 hits per page max * 10 pages We can maybe consider having it lower, but it seems easier to just have this a multiple of 250 in the first iteration. Signed-off-by: Morten Linderud Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 8c915711..80758005 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -619,7 +619,7 @@ function pkg_search_page($params, $show_headers=true, $SID="") { /* Sanitize paging variables. */ if (isset($params['O'])) { - $params['O'] = max(intval($params['O']), 0); + $params['O'] = bound(intval($params['O']), 0, 2500); } else { $params['O'] = 0; } @@ -771,9 +771,8 @@ function pkg_search_page($params, $show_headers=true, $SID="") { $result_t = $dbh->query($q_total); if ($result_t) { $row = $result_t->fetch(PDO::FETCH_NUM); - $total = $row[0]; - } - else { + $total = min($row[0], 2500); + } else { $total = 0; } From d5e308550ad4682829c01feb32212540a6699100 Mon Sep 17 00:00:00 2001 From: Frederik Schwan Date: Wed, 14 Oct 2020 02:22:08 +0200 Subject: [PATCH 0532/1891] Fix requests not being sent to the Cc recipients Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 9d4f3bde..edae76f8 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -118,7 +118,7 @@ class Notification: server.set_debuglevel(0) deliver_to = [to] + self.get_cc() - server.sendmail(sender, to, msg.as_bytes()) + server.sendmail(sender, deliver_to, msg.as_bytes()) server.quit() From d92dd69aa3c23acc7e2e409decf42c3b3e37749c Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 16 Feb 2021 21:42:23 -0500 Subject: [PATCH 0533/1891] fix broken SQL query that always failed Due to missing whitespace at the end of strings during joining, we ended up with the query fragment "DelTS IS NULLAND NOT PinnedTS" which should be "DelTS IS NULL AND NOT PinnedTS" So the check for pinned comments > 5 likely always failed. In php 7, a completely broken query that raises exceptions in the database engine was silently ignored... in php 8, it raises Uncaught PDOException: SQLSTATE[HY000]: General error: 1 near "PinnedTS": syntax error in and aborts the page building. End result: users with permission to pin comments cannot see any comments, or indeed page content below the first comment header Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/lib/pkgbasefuncs.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index a4925891..4c8abba7 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -21,7 +21,7 @@ function pkgbase_comments_count($base_id, $include_deleted, $only_pinned=false) $q = "SELECT COUNT(*) FROM PackageComments "; $q.= "WHERE PackageBaseID = " . $base_id . " "; if (!$include_deleted) { - $q.= "AND DelTS IS NULL"; + $q.= "AND DelTS IS NULL "; } if ($only_pinned) { $q.= "AND NOT PinnedTS = 0"; From be5197a5fe11d93ebce0044179c6f04fa8ff4cbb Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 16 Feb 2021 21:50:23 -0500 Subject: [PATCH 0534/1891] prevent running mysql-specific query in sqlite We usually guard such queries and have both mysql and sqlite branches. But I have not implemented the sqlite branch. Given sqlite is typically used for local dev setups, the fact that "users with more than the configured max simultaneous logins" can avoid getting some logins annulled is probably not a huge risk. And this always *used* to fail on sqlite, silently. Now, in php 8, it raises PDOException, which prevents running the test server Document this as a FIXME for now, until someone reimplements the query for sqlite. Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index d238c0e0..30c4cfe0 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -597,7 +597,9 @@ function try_login() { /* Generate a session ID and store it. */ while (!$logged_in && $num_tries < 5) { $session_limit = config_get_int('options', 'max_sessions_per_user'); - if ($session_limit) { + # FIXME: this does not work for sqlite (JOIN in a DELETE clause) + # hence non-prod instances can have a naughty amount of simultaneous logins + if ($backend == "mysql" && $session_limit) { /* * Delete all user sessions except the * last ($session_limit - 1). From 71740a75a210907cee418a6c404e05ef4710fa9b Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 16 Feb 2021 22:09:36 -0500 Subject: [PATCH 0535/1891] rewrite query to support both mysql/sqlite Signed-off-by: Eli Schwartz Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 30c4cfe0..752abe97 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -597,21 +597,17 @@ function try_login() { /* Generate a session ID and store it. */ while (!$logged_in && $num_tries < 5) { $session_limit = config_get_int('options', 'max_sessions_per_user'); - # FIXME: this does not work for sqlite (JOIN in a DELETE clause) - # hence non-prod instances can have a naughty amount of simultaneous logins - if ($backend == "mysql" && $session_limit) { + if ($session_limit) { /* * Delete all user sessions except the * last ($session_limit - 1). */ - $q = "DELETE s.* FROM Sessions s "; - $q.= "LEFT JOIN (SELECT SessionID FROM Sessions "; + $q = "DELETE FROM Sessions "; $q.= "WHERE UsersId = " . $userID . " "; + $q.= "AND SessionID NOT IN (SELECT SessionID FROM Sessions "; + $q.= "WHERE UsersID = " . $userID . " "; $q.= "ORDER BY LastUpdateTS DESC "; - $q.= "LIMIT " . ($session_limit - 1) . ") q "; - $q.= "ON s.SessionID = q.SessionID "; - $q.= "WHERE s.UsersId = " . $userID . " "; - $q.= "AND q.SessionID IS NULL;"; + $q.= "LIMIT " . ($session_limit - 1) . ")"; $dbh->query($q); } From db02227cc467ac9b9abcd9ee28bb10b2ef62cf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Wed, 20 May 2020 23:15:16 +0100 Subject: [PATCH 0536/1891] ci: add gitlab ci MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- .gitlab-ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..d463b109 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,12 @@ +image: archlinux + +before_script: + - pacman -Syu --noconfirm --noprogressbar --needed + base-devel git gpgme protobuf pyalpm python-mysql-connector + python-pygit2 python-srcinfo python-bleach python-markdown + python-sqlalchemy python-alembic python-pytest python-werkzeug + python-pytest-tap + +test: + script: + - make -C test From 23f6dd16a7c8b6f81c229e2307838edd213d6149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Wed, 20 May 2020 23:27:50 +0100 Subject: [PATCH 0537/1891] ci: add cache to gitlab ci MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- .gitlab-ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d463b109..74784fce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,13 @@ image: archlinux +cache: + key: system-v1 + paths: + # For some reason Gitlab CI only supports storing cache/artifacts in a path relative to the build directory + - .pkg-cache + before_script: - - pacman -Syu --noconfirm --noprogressbar --needed + - pacman -Syu --noconfirm --noprogressbar --needed --cachedir .pkg-cache base-devel git gpgme protobuf pyalpm python-mysql-connector python-pygit2 python-srcinfo python-bleach python-markdown python-sqlalchemy python-alembic python-pytest python-werkzeug From 8a13500535942a1c99b97ae4de46e5a1c0297cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Sun, 19 Apr 2020 20:11:02 +0200 Subject: [PATCH 0538/1891] Create aurweb.spawn for spawing the test server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This program makes it easier for developers to spawn the PHP server since it fetches automatically what it needs from the configuration file, rather than having the user explicitly pass arguments to the php executable. When the setup gets more complicated as we introduce Python, aurweb.spawn will keep providing the same interface, while under the hood it is planned to support running multiple sub-processes. Its Python interface provides an way for the test suite to spawn the test server when it needs to perform HTTP requests to the test server. The current implementation is somewhat weak as it doesn’t detect when a child process dies, but this is not supposed to happen often, and it is only meant for aurweb developers. In the long term, aurweb.spawn will eventually become obsolete, and replaced by Docker or Flask’s tools. Signed-off-by: Lukas Fleischer --- TESTING | 7 +-- aurweb/spawn.py | 107 +++++++++++++++++++++++++++++++++++++++++++ conf/config.defaults | 3 ++ 3 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 aurweb/spawn.py diff --git a/TESTING b/TESTING index 4a1e6f4c..a5e08cb8 100644 --- a/TESTING +++ b/TESTING @@ -17,7 +17,8 @@ INSTALL. Ensure to enable the pdo_sqlite extension in php.ini. 3) Copy conf/config.defaults to conf/config and adjust the configuration - (pay attention to disable_http_login, enable_maintenance and aur_location). + Pay attention to disable_http_login, enable_maintenance, aur_location and + htmldir. Be sure to change backend to sqlite and name to the file location of your created test database. @@ -31,6 +32,6 @@ INSTALL. $ ./gendummydata.py out.sql $ sqlite3 path/to/aurweb.sqlite3 < out.sql -5) Run the PHP built-in web server: +5) Run the test server: - $ AUR_CONFIG='/path/to/aurweb/conf/config' php -S localhost:8080 -t /path/to/aurweb/web/html + $ AUR_CONFIG='/path/to/aurweb/conf/config' python -m aurweb.spawn diff --git a/aurweb/spawn.py b/aurweb/spawn.py new file mode 100644 index 00000000..5fa646b5 --- /dev/null +++ b/aurweb/spawn.py @@ -0,0 +1,107 @@ +""" +Provide an automatic way of spawing an HTTP test server running aurweb. + +It can be called from the command-line or from another Python module. + +This module uses a global state, since you can’t open two servers with the same +configuration anyway. +""" + + +import atexit +import argparse +import subprocess +import sys +import time +import urllib + +import aurweb.config +import aurweb.schema + + +children = [] +verbosity = 0 + + +class ProcessExceptions(Exception): + """ + Compound exception used by stop() to list all the errors that happened when + terminating child processes. + """ + def __init__(self, message, exceptions): + self.message = message + self.exceptions = exceptions + messages = [message] + [str(e) for e in exceptions] + super().__init__("\n- ".join(messages)) + + +def spawn_child(args): + """Open a subprocess and add it to the global state.""" + if verbosity >= 1: + print(f"Spawning {args}", file=sys.stderr) + children.append(subprocess.Popen(args)) + + +def start(): + """ + Spawn the test server. If it is already running, do nothing. + + The server can be stopped with stop(), or is automatically stopped when the + Python process ends using atexit. + """ + if children: + return + atexit.register(stop) + aur_location = aurweb.config.get("options", "aur_location") + aur_location_parts = urllib.parse.urlsplit(aur_location) + htmldir = aurweb.config.get("options", "htmldir") + spawn_child(["php", "-S", aur_location_parts.netloc, "-t", htmldir]) + + +def stop(): + """ + Stop all the child processes. + + If an exception occurs during the process, the process continues anyway + because we don’t want to leave runaway processes around, and all the + exceptions are finally raised as a single ProcessExceptions. + """ + global children + atexit.unregister(stop) + exceptions = [] + for p in children: + try: + p.terminate() + if verbosity >= 1: + print(f"Sent SIGTERM to {p.args}", file=sys.stderr) + except Exception as e: + exceptions.append(e) + for p in children: + try: + rc = p.wait() + if rc != 0 and rc != -15: + # rc = -15 indicates the process was terminated with SIGTERM, + # which is to be expected since we called terminate on them. + raise Exception(f"Process {p.args} exited with {rc}") + except Exception as e: + exceptions.append(e) + children = [] + if exceptions: + raise ProcessExceptions("Errors terminating the child processes:", + exceptions) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + prog='python -m aurweb.spawn', + description='Start aurweb\'s test server.') + parser.add_argument('-v', '--verbose', action='count', default=0, + help='increase verbosity') + args = parser.parse_args() + verbosity = args.verbose + start() + try: + while True: + time.sleep(60) + except KeyboardInterrupt: + stop() diff --git a/conf/config.defaults b/conf/config.defaults index 447dacac..86fe765c 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -41,6 +41,9 @@ cache = none cache_pkginfo_ttl = 86400 memcache_servers = 127.0.0.1:11211 +; Directory containing aurweb's PHP code, required by aurweb.spawn. +;htmldir = /path/to/web/html + [ratelimit] request_limit = 4000 window_length = 86400 From 48b58b1c2f74df0906231d2affd9f2b352a8e330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Sat, 23 May 2020 17:54:07 +0100 Subject: [PATCH 0539/1891] ci: remove Travis CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are are moving to Gitlab CI. Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- .travis.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5bbfda1f..00000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: python - -python: 3.6 - -addons: - apt: - packages: - - bsdtar - - libarchive-dev - - libgpgme11-dev - - libprotobuf-dev - -install: - - curl https://codeload.github.com/libgit2/libgit2/tar.gz/v0.26.0 | tar -xz - - curl https://sources.archlinux.org/other/pacman/pacman-5.0.2.tar.gz | tar -xz - - curl https://git.archlinux.org/pyalpm.git/snapshot/pyalpm-0.8.1.tar.gz | tar -xz - - ( cd libgit2-0.26.0 && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr && make && sudo make install ) - - ( cd pacman-5.0.2 && ./configure --prefix=/usr && make && sudo make install ) - - ( cd pyalpm-0.8.1 && python setup.py build && python setup.py install ) - - pip install mysql-connector-python-rf pygit2==0.26 srcinfo - - pip install bleach Markdown - -script: make -C test From 8d1be7ea8a8d7c270f692a6c375ef2614c5ac601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Mon, 1 Jun 2020 23:35:25 +0100 Subject: [PATCH 0540/1891] Refactor code to comply with flake8 and isort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- aurweb/git/auth.py | 3 +- aurweb/git/serve.py | 14 +- aurweb/git/update.py | 6 +- aurweb/initdb.py | 7 +- aurweb/l10n.py | 2 +- aurweb/schema.py | 4 +- aurweb/scripts/aurblup.py | 3 +- aurweb/scripts/rendercomment.py | 6 +- migrations/env.py | 9 +- schema/gendummydata.py | 346 ++++++++++++++++---------------- setup.py | 3 +- 11 files changed, 206 insertions(+), 197 deletions(-) diff --git a/aurweb/git/auth.py b/aurweb/git/auth.py index 3b1e485f..abecd276 100755 --- a/aurweb/git/auth.py +++ b/aurweb/git/auth.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 -import os -import shlex import re +import shlex import sys import aurweb.config diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 64d51b9e..b91f1a13 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -175,11 +175,11 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged): i += 1 for userid in uids_rem: - cur = conn.execute("DELETE FROM PackageComaintainers " + - "WHERE PackageBaseID = ? AND UsersID = ?", - [pkgbase_id, userid]) - subprocess.Popen((notify_cmd, 'comaintainer-remove', - str(userid), str(pkgbase_id))) + cur = conn.execute("DELETE FROM PackageComaintainers " + + "WHERE PackageBaseID = ? AND UsersID = ?", + [pkgbase_id, userid]) + subprocess.Popen((notify_cmd, 'comaintainer-remove', + str(userid), str(pkgbase_id))) conn.commit() conn.close() @@ -268,7 +268,7 @@ def pkgbase_disown(pkgbase, user, privileged): cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] if userid == 0: - raise aurweb.exceptions.InvalidUserException(user) + raise aurweb.exceptions.InvalidUserException(user) subprocess.Popen((notify_cmd, 'disown', str(userid), str(pkgbase_id))) @@ -472,7 +472,7 @@ def checkarg(cmdargv, *argdesc): checkarg_atmost(cmdargv, *argdesc) -def serve(action, cmdargv, user, privileged, remote_addr): +def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901 if enable_maintenance: if remote_addr not in maintenance_exc: raise aurweb.exceptions.MaintenanceException diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 39128f8b..929b254e 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 import os -import pygit2 import re import subprocess import sys import time +import pygit2 import srcinfo.parse import srcinfo.utils @@ -75,7 +75,7 @@ def create_pkgbase(conn, pkgbase, user): return pkgbase_id -def save_metadata(metadata, conn, user): +def save_metadata(metadata, conn, user): # noqa: C901 # Obtain package base ID and previous maintainer. pkgbase = metadata['pkgbase'] cur = conn.execute("SELECT ID, MaintainerUID FROM PackageBases " @@ -232,7 +232,7 @@ def die_commit(msg, commit): exit(1) -def main(): +def main(): # noqa: C901 repo = pygit2.Repository(repo_path) user = os.environ.get("AUR_USER") diff --git a/aurweb/initdb.py b/aurweb/initdb.py index 91777f7e..c8d0b2ae 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -1,11 +1,12 @@ -import aurweb.db -import aurweb.schema +import argparse import alembic.command import alembic.config -import argparse import sqlalchemy +import aurweb.db +import aurweb.schema + def feed_initial_data(conn): conn.execute(aurweb.schema.AccountTypes.insert(), [ diff --git a/aurweb/l10n.py b/aurweb/l10n.py index a7c0103e..492200b3 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -16,4 +16,4 @@ class Translator: self._localedir, languages=[lang]) self._translator[lang].install() - return _(s) + return _(s) # _ is not defined, what is this? # noqa: F821 diff --git a/aurweb/schema.py b/aurweb/schema.py index 6792cf1d..20f3e5ce 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -6,7 +6,7 @@ usually be automatically generated. See `migrations/README` for details. """ -from sqlalchemy import CHAR, Column, ForeignKey, Index, MetaData, String, TIMESTAMP, Table, Text, text +from sqlalchemy import CHAR, TIMESTAMP, Column, ForeignKey, Index, MetaData, String, Table, Text, text from sqlalchemy.dialects.mysql import BIGINT, DECIMAL, INTEGER, TINYINT from sqlalchemy.ext.compiler import compiles @@ -24,7 +24,7 @@ def compile_bigint_sqlite(type_, compiler, **kw): to INTEGER. Aside from that, BIGINT is the same as INTEGER for SQLite. See https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#allowing-autoincrement-behavior-sqlalchemy-types-other-than-integer-integer - """ + """ # noqa: E501 return 'INTEGER' diff --git a/aurweb/scripts/aurblup.py b/aurweb/scripts/aurblup.py index a7d43f12..e32937ce 100755 --- a/aurweb/scripts/aurblup.py +++ b/aurweb/scripts/aurblup.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -import pyalpm import re +import pyalpm + import aurweb.config import aurweb.db diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 76865d27..422dd33b 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -import re -import pygit2 import sys + import bleach import markdown +import pygit2 import aurweb.config import aurweb.db @@ -47,7 +47,7 @@ class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): class FlysprayLinksExtension(markdown.extensions.Extension): def extendMarkdown(self, md, md_globals): - processor = FlysprayLinksInlineProcessor(r'\bFS#(\d+)\b',md) + processor = FlysprayLinksInlineProcessor(r'\bFS#(\d+)\b', md) md.inlinePatterns.register(processor, 'flyspray-links', 118) diff --git a/migrations/env.py b/migrations/env.py index 1627e693..c2ff58c1 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -1,10 +1,11 @@ -import aurweb.db -import aurweb.schema - -from alembic import context import logging.config + import sqlalchemy +from alembic import context + +import aurweb.db +import aurweb.schema # this is the Alembic Config object, which provides # access to the values within the .ini file in use. diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 1f3d0476..b3a73ef2 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -10,33 +10,32 @@ usage: gendummydata.py outputfilename.sql # insert these users/packages into the AUR database. # import hashlib -import random -import time -import os -import sys -import io import logging +import os +import random +import sys +import time -LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output +LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output SEED_FILE = "/usr/share/dict/words" -DB_HOST = os.getenv("DB_HOST", "localhost") -DB_NAME = os.getenv("DB_NAME", "AUR") -DB_USER = os.getenv("DB_USER", "aur") -DB_PASS = os.getenv("DB_PASS", "aur") -USER_ID = 5 # Users.ID of first bogus user -PKG_ID = 1 # Packages.ID of first package +DB_HOST = os.getenv("DB_HOST", "localhost") +DB_NAME = os.getenv("DB_NAME", "AUR") +DB_USER = os.getenv("DB_USER", "aur") +DB_PASS = os.getenv("DB_PASS", "aur") +USER_ID = 5 # Users.ID of first bogus user +PKG_ID = 1 # Packages.ID of first package MAX_USERS = 300 # how many users to 'register' -MAX_DEVS = .1 # what percentage of MAX_USERS are Developers -MAX_TUS = .2 # what percentage of MAX_USERS are Trusted Users -MAX_PKGS = 900 # how many packages to load -PKG_DEPS = (1, 15) # min/max depends a package has -PKG_RELS = (1, 5) # min/max relations a package has -PKG_SRC = (1, 3) # min/max sources a package has +MAX_DEVS = .1 # what percentage of MAX_USERS are Developers +MAX_TUS = .2 # what percentage of MAX_USERS are Trusted Users +MAX_PKGS = 900 # how many packages to load +PKG_DEPS = (1, 15) # min/max depends a package has +PKG_RELS = (1, 5) # min/max relations a package has +PKG_SRC = (1, 3) # min/max sources a package has PKG_CMNTS = (1, 5) # min/max number of comments a package has CATEGORIES_COUNT = 17 # the number of categories from aur-schema -VOTING = (0, .30) # percentage range for package voting -OPEN_PROPOSALS = 5 # number of open trusted user proposals -CLOSE_PROPOSALS = 15 # number of closed trusted user proposals +VOTING = (0, .30) # percentage range for package voting +OPEN_PROPOSALS = 5 # number of open trusted user proposals +CLOSE_PROPOSALS = 15 # number of closed trusted user proposals RANDOM_TLDS = ("edu", "com", "org", "net", "tw", "ru", "pl", "de", "es") RANDOM_URL = ("http://www.", "ftp://ftp.", "http://", "ftp://") RANDOM_LOCS = ("pub", "release", "files", "downloads", "src") @@ -48,20 +47,20 @@ logging.basicConfig(format=logformat, level=LOG_LEVEL) log = logging.getLogger() if len(sys.argv) != 2: - log.error("Missing output filename argument") - raise SystemExit + log.error("Missing output filename argument") + raise SystemExit # make sure the seed file exists # if not os.path.exists(SEED_FILE): - log.error("Please install the 'words' Arch package") - raise SystemExit + log.error("Please install the 'words' Arch package") + raise SystemExit # make sure comments can be created # if not os.path.exists(FORTUNE_FILE): - log.error("Please install the 'fortune-mod' Arch package") - raise SystemExit + log.error("Please install the 'fortune-mod' Arch package") + raise SystemExit # track what users/package names have been used # @@ -69,21 +68,28 @@ seen_users = {} seen_pkgs = {} user_keys = [] + # some functions to generate random data # def genVersion(): - ver = [] - ver.append("%d" % random.randrange(0,10)) - ver.append("%d" % random.randrange(0,20)) - if random.randrange(0,2) == 0: - ver.append("%d" % random.randrange(0,100)) - return ".".join(ver) + "-%d" % random.randrange(1,11) + ver = [] + ver.append("%d" % random.randrange(0, 10)) + ver.append("%d" % random.randrange(0, 20)) + if random.randrange(0, 2) == 0: + ver.append("%d" % random.randrange(0, 100)) + return ".".join(ver) + "-%d" % random.randrange(1, 11) + + def genCategory(): - return random.randrange(1,CATEGORIES_COUNT) + return random.randrange(1, CATEGORIES_COUNT) + + def genUID(): - return seen_users[user_keys[random.randrange(0,len(user_keys))]] + return seen_users[user_keys[random.randrange(0, len(user_keys))]] + + def genFortune(): - return fortunes[random.randrange(0,len(fortunes))].replace("'", "") + return fortunes[random.randrange(0, len(fortunes))].replace("'", "") # load the words, and make sure there are enough words for users/pkgs @@ -93,25 +99,25 @@ fp = open(SEED_FILE, "r", encoding="utf-8") contents = fp.readlines() fp.close() if MAX_USERS > len(contents): - MAX_USERS = len(contents) + MAX_USERS = len(contents) if MAX_PKGS > len(contents): - MAX_PKGS = len(contents) + MAX_PKGS = len(contents) if len(contents) - MAX_USERS > MAX_PKGS: - need_dupes = 0 + need_dupes = 0 else: - need_dupes = 1 + need_dupes = 1 # select random usernames # log.debug("Generating random user names...") user_id = USER_ID while len(seen_users) < MAX_USERS: - user = random.randrange(0, len(contents)) - word = contents[user].replace("'", "").replace(".","").replace(" ", "_") - word = word.strip().lower() - if word not in seen_users: - seen_users[word] = user_id - user_id += 1 + user = random.randrange(0, len(contents)) + word = contents[user].replace("'", "").replace(".", "").replace(" ", "_") + word = word.strip().lower() + if word not in seen_users: + seen_users[word] = user_id + user_id += 1 user_keys = list(seen_users.keys()) # select random package names @@ -119,17 +125,17 @@ user_keys = list(seen_users.keys()) log.debug("Generating random package names...") num_pkgs = PKG_ID while len(seen_pkgs) < MAX_PKGS: - pkg = random.randrange(0, len(contents)) - word = contents[pkg].replace("'", "").replace(".","").replace(" ", "_") - word = word.strip().lower() - if not need_dupes: - if word not in seen_pkgs and word not in seen_users: - seen_pkgs[word] = num_pkgs - num_pkgs += 1 - else: - if word not in seen_pkgs: - seen_pkgs[word] = num_pkgs - num_pkgs += 1 + pkg = random.randrange(0, len(contents)) + word = contents[pkg].replace("'", "").replace(".", "").replace(" ", "_") + word = word.strip().lower() + if not need_dupes: + if word not in seen_pkgs and word not in seen_users: + seen_pkgs[word] = num_pkgs + num_pkgs += 1 + else: + if word not in seen_pkgs: + seen_pkgs[word] = num_pkgs + num_pkgs += 1 # free up contents memory # @@ -151,32 +157,32 @@ out.write("BEGIN;\n") # log.debug("Creating SQL statements for users.") for u in user_keys: - account_type = 1 # default to normal user - if not has_devs or not has_tus: - account_type = random.randrange(1, 4) - if account_type == 3 and not has_devs: - # this will be a dev account - # - developers.append(seen_users[u]) - if len(developers) >= MAX_DEVS * MAX_USERS: - has_devs = 1 - elif account_type == 2 and not has_tus: - # this will be a trusted user account - # - trustedusers.append(seen_users[u]) - if len(trustedusers) >= MAX_TUS * MAX_USERS: - has_tus = 1 - else: - # a normal user account - # - pass + account_type = 1 # default to normal user + if not has_devs or not has_tus: + account_type = random.randrange(1, 4) + if account_type == 3 and not has_devs: + # this will be a dev account + # + developers.append(seen_users[u]) + if len(developers) >= MAX_DEVS * MAX_USERS: + has_devs = 1 + elif account_type == 2 and not has_tus: + # this will be a trusted user account + # + trustedusers.append(seen_users[u]) + if len(trustedusers) >= MAX_TUS * MAX_USERS: + has_tus = 1 + else: + # a normal user account + # + pass - h = hashlib.new('md5') - h.update(u.encode()); - s = ("INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd)" - " VALUES (%d, %d, '%s', '%s@example.com', '%s');\n") - s = s % (seen_users[u], account_type, u, u, h.hexdigest()) - out.write(s) + h = hashlib.new('md5') + h.update(u.encode()) + s = ("INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd)" + " VALUES (%d, %d, '%s', '%s@example.com', '%s');\n") + s = s % (seen_users[u], account_type, u, u, h.hexdigest()) + out.write(s) log.debug("Number of developers: %d" % len(developers)) log.debug("Number of trusted users: %d" % len(trustedusers)) @@ -193,123 +199,123 @@ fp.close() log.debug("Creating SQL statements for packages.") count = 0 for p in list(seen_pkgs.keys()): - NOW = int(time.time()) - if count % 2 == 0: - muid = developers[random.randrange(0,len(developers))] - puid = developers[random.randrange(0,len(developers))] - else: - muid = trustedusers[random.randrange(0,len(trustedusers))] - puid = trustedusers[random.randrange(0,len(trustedusers))] - if count % 20 == 0: # every so often, there are orphans... - muid = "NULL" + NOW = int(time.time()) + if count % 2 == 0: + muid = developers[random.randrange(0, len(developers))] + puid = developers[random.randrange(0, len(developers))] + else: + muid = trustedusers[random.randrange(0, len(trustedusers))] + puid = trustedusers[random.randrange(0, len(trustedusers))] + if count % 20 == 0: # every so often, there are orphans... + muid = "NULL" - uuid = genUID() # the submitter/user + uuid = genUID() # the submitter/user - s = ("INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, " + s = ("INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, " "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', '', %d, %d, %d, %s, %s);\n") - s = s % (seen_pkgs[p], p, NOW, NOW, uuid, muid, puid) - out.write(s) + s = s % (seen_pkgs[p], p, NOW, NOW, uuid, muid, puid) + out.write(s) - s = ("INSERT INTO Packages (ID, PackageBaseID, Name, Version) VALUES " + s = ("INSERT INTO Packages (ID, PackageBaseID, Name, Version) VALUES " "(%d, %d, '%s', '%s');\n") - s = s % (seen_pkgs[p], seen_pkgs[p], p, genVersion()) - out.write(s) + s = s % (seen_pkgs[p], seen_pkgs[p], p, genVersion()) + out.write(s) - count += 1 + count += 1 - # create random comments for this package - # - num_comments = random.randrange(PKG_CMNTS[0], PKG_CMNTS[1]) - for i in range(0, num_comments): - now = NOW + random.randrange(400, 86400*3) - s = ("INSERT INTO PackageComments (PackageBaseID, UsersID," - " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n") - s = s % (seen_pkgs[p], genUID(), genFortune(), now) - out.write(s) + # create random comments for this package + # + num_comments = random.randrange(PKG_CMNTS[0], PKG_CMNTS[1]) + for i in range(0, num_comments): + now = NOW + random.randrange(400, 86400*3) + s = ("INSERT INTO PackageComments (PackageBaseID, UsersID," + " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n") + s = s % (seen_pkgs[p], genUID(), genFortune(), now) + out.write(s) # Cast votes # track_votes = {} log.debug("Casting votes for packages.") for u in user_keys: - num_votes = random.randrange(int(len(seen_pkgs)*VOTING[0]), - int(len(seen_pkgs)*VOTING[1])) - pkgvote = {} - for v in range(num_votes): - pkg = random.randrange(1, len(seen_pkgs) + 1) - if pkg not in pkgvote: - s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID)" - " VALUES (%d, %d);\n") - s = s % (seen_users[u], pkg) - pkgvote[pkg] = 1 - if pkg not in track_votes: - track_votes[pkg] = 0 - track_votes[pkg] += 1 - out.write(s) + num_votes = random.randrange(int(len(seen_pkgs)*VOTING[0]), + int(len(seen_pkgs)*VOTING[1])) + pkgvote = {} + for v in range(num_votes): + pkg = random.randrange(1, len(seen_pkgs) + 1) + if pkg not in pkgvote: + s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID)" + " VALUES (%d, %d);\n") + s = s % (seen_users[u], pkg) + pkgvote[pkg] = 1 + if pkg not in track_votes: + track_votes[pkg] = 0 + track_votes[pkg] += 1 + out.write(s) # Update statements for package votes # for p in list(track_votes.keys()): - s = "UPDATE PackageBases SET NumVotes = %d WHERE ID = %d;\n" - s = s % (track_votes[p], p) - out.write(s) + s = "UPDATE PackageBases SET NumVotes = %d WHERE ID = %d;\n" + s = s % (track_votes[p], p) + out.write(s) # Create package dependencies and sources # log.debug("Creating statements for package depends/sources.") for p in list(seen_pkgs.keys()): - num_deps = random.randrange(PKG_DEPS[0], PKG_DEPS[1]) - for i in range(0, num_deps): - dep = random.choice([k for k in seen_pkgs]) - deptype = random.randrange(1, 5) - if deptype == 4: - dep += ": for " + random.choice([k for k in seen_pkgs]) - s = "INSERT INTO PackageDepends(PackageID, DepTypeID, DepName) VALUES (%d, %d, '%s');\n" - s = s % (seen_pkgs[p], deptype, dep) - out.write(s) + num_deps = random.randrange(PKG_DEPS[0], PKG_DEPS[1]) + for i in range(0, num_deps): + dep = random.choice([k for k in seen_pkgs]) + deptype = random.randrange(1, 5) + if deptype == 4: + dep += ": for " + random.choice([k for k in seen_pkgs]) + s = "INSERT INTO PackageDepends(PackageID, DepTypeID, DepName) VALUES (%d, %d, '%s');\n" + s = s % (seen_pkgs[p], deptype, dep) + out.write(s) - num_rels = random.randrange(PKG_RELS[0], PKG_RELS[1]) - for i in range(0, num_deps): - rel = random.choice([k for k in seen_pkgs]) - reltype = random.randrange(1, 4) - s = "INSERT INTO PackageRelations(PackageID, RelTypeID, RelName) VALUES (%d, %d, '%s');\n" - s = s % (seen_pkgs[p], reltype, rel) - out.write(s) + num_rels = random.randrange(PKG_RELS[0], PKG_RELS[1]) + for i in range(0, num_deps): + rel = random.choice([k for k in seen_pkgs]) + reltype = random.randrange(1, 4) + s = "INSERT INTO PackageRelations(PackageID, RelTypeID, RelName) VALUES (%d, %d, '%s');\n" + s = s % (seen_pkgs[p], reltype, rel) + out.write(s) - num_sources = random.randrange(PKG_SRC[0], PKG_SRC[1]) - for i in range(num_sources): - src_file = user_keys[random.randrange(0, len(user_keys))] - src = "%s%s.%s/%s/%s-%s.tar.gz" % ( - RANDOM_URL[random.randrange(0,len(RANDOM_URL))], - p, RANDOM_TLDS[random.randrange(0,len(RANDOM_TLDS))], - RANDOM_LOCS[random.randrange(0,len(RANDOM_LOCS))], - src_file, genVersion()) - s = "INSERT INTO PackageSources(PackageID, Source) VALUES (%d, '%s');\n" - s = s % (seen_pkgs[p], src) - out.write(s) + num_sources = random.randrange(PKG_SRC[0], PKG_SRC[1]) + for i in range(num_sources): + src_file = user_keys[random.randrange(0, len(user_keys))] + src = "%s%s.%s/%s/%s-%s.tar.gz" % ( + RANDOM_URL[random.randrange(0, len(RANDOM_URL))], + p, RANDOM_TLDS[random.randrange(0, len(RANDOM_TLDS))], + RANDOM_LOCS[random.randrange(0, len(RANDOM_LOCS))], + src_file, genVersion()) + s = "INSERT INTO PackageSources(PackageID, Source) VALUES (%d, '%s');\n" + s = s % (seen_pkgs[p], src) + out.write(s) # Create trusted user proposals # log.debug("Creating SQL statements for trusted user proposals.") -count=0 +count = 0 for t in range(0, OPEN_PROPOSALS+CLOSE_PROPOSALS): - now = int(time.time()) - if count < CLOSE_PROPOSALS: - start = now - random.randrange(3600*24*7, 3600*24*21) - end = now - random.randrange(0, 3600*24*7) - else: - start = now - end = now + random.randrange(3600*24, 3600*24*7) - if count % 5 == 0: # Don't make the vote about anyone once in a while - user = "" - else: - user = user_keys[random.randrange(0,len(user_keys))] - suid = trustedusers[random.randrange(0,len(trustedusers))] - s = ("INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End," - " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n") - s = s % (genFortune(), user, start, end, suid) - out.write(s) - count += 1 + now = int(time.time()) + if count < CLOSE_PROPOSALS: + start = now - random.randrange(3600*24*7, 3600*24*21) + end = now - random.randrange(0, 3600*24*7) + else: + start = now + end = now + random.randrange(3600*24, 3600*24*7) + if count % 5 == 0: # Don't make the vote about anyone once in a while + user = "" + else: + user = user_keys[random.randrange(0, len(user_keys))] + suid = trustedusers[random.randrange(0, len(trustedusers))] + s = ("INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End," + " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n") + s = s % (genFortune(), user, start, end, suid) + out.write(s) + count += 1 # close output file # diff --git a/setup.py b/setup.py index ca26f0d8..cf88488c 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,8 @@ import re -from setuptools import setup, find_packages import sys +from setuptools import find_packages, setup + version = None with open('web/lib/version.inc.php', 'r') as f: for line in f.readlines(): From 4cf94816ae022be88540a25356a3abbe10a452eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Mon, 1 Jun 2020 23:35:26 +0100 Subject: [PATCH 0541/1891] flake8: add initial config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- setup.cfg | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..04f5b8ba --- /dev/null +++ b/setup.cfg @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 127 +max-complexity = 10 + From 8f47b8d731e0d650ea671e169cddaafa64c44055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Mon, 1 Jun 2020 23:35:27 +0100 Subject: [PATCH 0542/1891] isort: add initial config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- setup.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.cfg b/setup.cfg index 04f5b8ba..b868c096 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,3 +2,7 @@ max-line-length = 127 max-complexity = 10 +[isort] +line_length = 127 +lines_between_types = 1 + From 41a84934114f5d77f51d7064c4a64b2e279c1ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Mon, 1 Jun 2020 23:35:28 +0100 Subject: [PATCH 0543/1891] pre-commit: add initial config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- .pre-commit-config.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..525c7eb8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +hooks: + - &base + language: python + types: [python] + require_serial: true + exclude: ^migrations/versions + - &flake8 + id: flake8 + name: flake8 + entry: flake8 + <<: *base + - &isort + id: isort + name: isort + entry: isort + <<: *base + +repos: + - repo: local + hooks: + - <<: *flake8 + - <<: *isort + args: ['--check-only', '--diff'] + From d4abe0b72d1215906806ee84474115961e79f7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Mon, 1 Jun 2020 23:35:29 +0100 Subject: [PATCH 0544/1891] Add CONTRIBUTING.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- CONTRIBUTING.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..a37d980a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,10 @@ +# Contributing + +Patches should be sent to the [aur-dev@archlinux.org][1] mailing list. + +Before sending patched you are recomended to run the `flake8` and `isort`. + +You can add git hook to do this by installing `python-pre-install` and running +`pre-install install`. + +[1] https://lists.archlinux.org/listinfo/aur-dev From 5be07a8a9e9777d54cf7122be52aa0a7b1b51e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 1 Jun 2020 18:49:37 +0200 Subject: [PATCH 0545/1891] aurweb.spawn: Integrate FastAPI and nginx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aurweb.spawn used to launch only PHP’s built-in server. Now it spawns a dummy FastAPI application too. Since both stacks spawn their own HTTP server, aurweb.spawn also spawns nginx as a reverse proxy to mount them under the same base URL, defined by aur_location in the configuration. Signed-off-by: Lukas Fleischer --- .gitlab-ci.yml | 2 +- TESTING | 3 +- aurweb/asgi.py | 8 +++++ aurweb/spawn.py | 80 +++++++++++++++++++++++++++++++++++++------- conf/config.defaults | 7 ++++ 5 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 aurweb/asgi.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 74784fce..f6260ebb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ before_script: base-devel git gpgme protobuf pyalpm python-mysql-connector python-pygit2 python-srcinfo python-bleach python-markdown python-sqlalchemy python-alembic python-pytest python-werkzeug - python-pytest-tap + python-pytest-tap python-fastapi uvicorn nginx test: script: diff --git a/TESTING b/TESTING index a5e08cb8..31e3bcbd 100644 --- a/TESTING +++ b/TESTING @@ -12,7 +12,8 @@ INSTALL. 2) Install the necessary packages: # pacman -S --needed php php-sqlite sqlite words fortune-mod \ - python python-sqlalchemy python-alembic + python python-sqlalchemy python-alembic \ + python-fastapi uvicorn nginx Ensure to enable the pdo_sqlite extension in php.ini. diff --git a/aurweb/asgi.py b/aurweb/asgi.py new file mode 100644 index 00000000..5f30471a --- /dev/null +++ b/aurweb/asgi.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/hello/") +async def hello(): + return {"message": "Hello from FastAPI!"} diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 5fa646b5..0506afa4 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -10,8 +10,10 @@ configuration anyway. import atexit import argparse +import os import subprocess import sys +import tempfile import time import urllib @@ -20,6 +22,7 @@ import aurweb.schema children = [] +temporary_dir = None verbosity = 0 @@ -35,10 +38,42 @@ class ProcessExceptions(Exception): super().__init__("\n- ".join(messages)) +def generate_nginx_config(): + """ + Generate an nginx configuration based on aurweb's configuration. + The file is generated under `temporary_dir`. + Returns the path to the created configuration file. + """ + aur_location = aurweb.config.get("options", "aur_location") + aur_location_parts = urllib.parse.urlsplit(aur_location) + config_path = os.path.join(temporary_dir, "nginx.conf") + config = open(config_path, "w") + # We double nginx's braces because they conflict with Python's f-strings. + config.write(f""" + events {{}} + daemon off; + error_log /dev/stderr info; + pid {os.path.join(temporary_dir, "nginx.pid")}; + http {{ + access_log /dev/stdout; + server {{ + listen {aur_location_parts.netloc}; + location / {{ + proxy_pass http://{aurweb.config.get("php", "bind_address")}; + }} + location /hello {{ + proxy_pass http://{aurweb.config.get("fastapi", "bind_address")}; + }} + }} + }} + """) + return config_path + + def spawn_child(args): """Open a subprocess and add it to the global state.""" if verbosity >= 1: - print(f"Spawning {args}", file=sys.stderr) + print(f":: Spawning {args}", file=sys.stderr) children.append(subprocess.Popen(args)) @@ -52,10 +87,29 @@ def start(): if children: return atexit.register(stop) - aur_location = aurweb.config.get("options", "aur_location") - aur_location_parts = urllib.parse.urlsplit(aur_location) - htmldir = aurweb.config.get("options", "htmldir") - spawn_child(["php", "-S", aur_location_parts.netloc, "-t", htmldir]) + + print("{ruler}\n" + "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n" + "Check out {aur_location}\n" + "Hit ^C to terminate everything.\n" + "{ruler}" + .format(ruler=("-" * os.get_terminal_size().columns), + aur_location=aurweb.config.get('options', 'aur_location'))) + + # PHP + php_address = aurweb.config.get("php", "bind_address") + htmldir = aurweb.config.get("php", "htmldir") + spawn_child(["php", "-S", php_address, "-t", htmldir]) + + # FastAPI + host, port = aurweb.config.get("fastapi", "bind_address").rsplit(":", 1) + spawn_child(["python", "-m", "uvicorn", + "--host", host, + "--port", port, + "aurweb.asgi:app"]) + + # nginx + spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()]) def stop(): @@ -73,7 +127,7 @@ def stop(): try: p.terminate() if verbosity >= 1: - print(f"Sent SIGTERM to {p.args}", file=sys.stderr) + print(f":: Sent SIGTERM to {p.args}", file=sys.stderr) except Exception as e: exceptions.append(e) for p in children: @@ -99,9 +153,11 @@ if __name__ == '__main__': help='increase verbosity') args = parser.parse_args() verbosity = args.verbose - start() - try: - while True: - time.sleep(60) - except KeyboardInterrupt: - stop() + with tempfile.TemporaryDirectory(prefix="aurweb-") as tmpdirname: + temporary_dir = tmpdirname + start() + try: + while True: + time.sleep(60) + except KeyboardInterrupt: + stop() diff --git a/conf/config.defaults b/conf/config.defaults index 86fe765c..ed495168 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -41,9 +41,16 @@ cache = none cache_pkginfo_ttl = 86400 memcache_servers = 127.0.0.1:11211 +[php] +; Address PHP should bind when spawned in development mode by aurweb.spawn. +bind_address = 127.0.0.1:8081 ; Directory containing aurweb's PHP code, required by aurweb.spawn. ;htmldir = /path/to/web/html +[fastapi] +; Address uvicorn should bind when spawned in development mode by aurweb.spawn. +bind_address = 127.0.0.1:8082 + [ratelimit] request_limit = 4000 window_length = 86400 From 8c868e088c8becc7640327db2e5e2a1cb10bab41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Wed, 3 Jun 2020 02:04:02 +0200 Subject: [PATCH 0546/1891] Introduce conf/config.dev for development MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit conf/config.dev’s purpose is to provide a lighter configuration template for developers, and split development-specific options off the default configuration file. Signed-off-by: Lukas Fleischer --- TESTING | 11 ++++++----- conf/config.defaults | 10 ---------- conf/config.dev | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 conf/config.dev diff --git a/TESTING b/TESTING index 31e3bcbd..7261df92 100644 --- a/TESTING +++ b/TESTING @@ -17,12 +17,13 @@ INSTALL. Ensure to enable the pdo_sqlite extension in php.ini. -3) Copy conf/config.defaults to conf/config and adjust the configuration - Pay attention to disable_http_login, enable_maintenance, aur_location and - htmldir. +3) Copy conf/config.dev to conf/config and replace YOUR_AUR_ROOT by the absolute + path to the root of your aurweb clone. sed can do both tasks for you: - Be sure to change backend to sqlite and name to the file location of your - created test database. + $ sed -e "s;YOUR_AUR_ROOT;$PWD;g" conf/config.dev > conf/config + + Note that when the upstream config.dev is updated, you should compare it to + your conf/config, or regenerate your configuration with the command above. 4) Prepare the testing database: diff --git a/conf/config.defaults b/conf/config.defaults index ed495168..447dacac 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -41,16 +41,6 @@ cache = none cache_pkginfo_ttl = 86400 memcache_servers = 127.0.0.1:11211 -[php] -; Address PHP should bind when spawned in development mode by aurweb.spawn. -bind_address = 127.0.0.1:8081 -; Directory containing aurweb's PHP code, required by aurweb.spawn. -;htmldir = /path/to/web/html - -[fastapi] -; Address uvicorn should bind when spawned in development mode by aurweb.spawn. -bind_address = 127.0.0.1:8082 - [ratelimit] request_limit = 4000 window_length = 86400 diff --git a/conf/config.dev b/conf/config.dev new file mode 100644 index 00000000..d752f61f --- /dev/null +++ b/conf/config.dev @@ -0,0 +1,32 @@ +; Configuration file for aurweb development. +; +; Options are implicitly inherited from conf/config.defaults, which lists all +; available options for productions, and their default values. This current file +; overrides only options useful for development, and introduces +; development-specific options too. + +[database] +backend = sqlite +name = YOUR_AUR_ROOT/aurweb.sqlite3 + +; Alternative MySQL configuration +;backend = mysql +;name = aurweb +;user = aur +;password = aur + +[options] +aur_location = http://127.0.0.1:8080 +disable_http_login = 0 +enable-maintenance = 0 + +[php] +; Address PHP should bind when spawned in development mode by aurweb.spawn. +bind_address = 127.0.0.1:8081 + +; Directory containing aurweb's PHP code, required by aurweb.spawn. +htmldir = YOUR_AUR_ROOT/web/html + +[fastapi] +; Address uvicorn should bind when spawned in development mode by aurweb.spawn. +bind_address = 127.0.0.1:8082 From 0e3bd8b5969f3c3d6ba9273b15ae1e093fc934e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Thu, 4 Jun 2020 21:59:34 +0200 Subject: [PATCH 0547/1891] Remove the FastAPI /hello test route Signed-off-by: Lukas Fleischer --- aurweb/asgi.py | 5 ----- aurweb/spawn.py | 3 --- 2 files changed, 8 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 5f30471a..9bb71ecc 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -1,8 +1,3 @@ from fastapi import FastAPI app = FastAPI() - - -@app.get("/hello/") -async def hello(): - return {"message": "Hello from FastAPI!"} diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 0506afa4..7fe59e65 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -61,9 +61,6 @@ def generate_nginx_config(): location / {{ proxy_pass http://{aurweb.config.get("php", "bind_address")}; }} - location /hello {{ - proxy_pass http://{aurweb.config.get("fastapi", "bind_address")}; - }} }} }} """) From b1300117ac6fc0f5e9cf1048576db8fb97470bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Thu, 4 Jun 2020 21:59:48 +0200 Subject: [PATCH 0548/1891] aurweb.spawn: Fix isort errors Signed-off-by: Lukas Fleischer --- aurweb/spawn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 7fe59e65..e86f29fe 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -8,8 +8,8 @@ configuration anyway. """ -import atexit import argparse +import atexit import os import subprocess import sys @@ -20,7 +20,6 @@ import urllib import aurweb.config import aurweb.schema - children = [] temporary_dir = None verbosity = 0 From 3b347d3989592293661a47a5bac7645afb8d61d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Thu, 4 Jun 2020 22:00:20 +0200 Subject: [PATCH 0549/1891] Crude OpenID Connect client using Authlib Developers can go to /sso/login to get redirected to the SSO. On successful login, the ID token is displayed. Signed-off-by: Lukas Fleischer --- .gitlab-ci.yml | 3 ++- TESTING | 3 ++- aurweb/asgi.py | 13 +++++++++++++ aurweb/routers/__init__.py | 5 +++++ aurweb/routers/sso.py | 30 ++++++++++++++++++++++++++++++ aurweb/spawn.py | 3 +++ conf/config.defaults | 8 ++++++++ conf/config.dev | 9 +++++++++ 8 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 aurweb/routers/__init__.py create mode 100644 aurweb/routers/sso.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f6260ebb..9dc951aa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,8 @@ before_script: base-devel git gpgme protobuf pyalpm python-mysql-connector python-pygit2 python-srcinfo python-bleach python-markdown python-sqlalchemy python-alembic python-pytest python-werkzeug - python-pytest-tap python-fastapi uvicorn nginx + python-pytest-tap python-fastapi uvicorn nginx python-authlib + python-itsdangerous python-httpx test: script: diff --git a/TESTING b/TESTING index 7261df92..d7df3672 100644 --- a/TESTING +++ b/TESTING @@ -13,7 +13,8 @@ INSTALL. # pacman -S --needed php php-sqlite sqlite words fortune-mod \ python python-sqlalchemy python-alembic \ - python-fastapi uvicorn nginx + python-fastapi uvicorn nginx \ + python-authlib python-itsdangerous python-httpx Ensure to enable the pdo_sqlite extension in php.ini. diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 9bb71ecc..60c7ade7 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -1,3 +1,16 @@ from fastapi import FastAPI +from starlette.middleware.sessions import SessionMiddleware + +import aurweb.config + +from aurweb.routers import sso app = FastAPI() + +session_secret = aurweb.config.get("fastapi", "session_secret") +if not session_secret: + raise Exception("[fastapi] session_secret must not be empty") + +app.add_middleware(SessionMiddleware, secret_key=session_secret) + +app.include_router(sso.router) diff --git a/aurweb/routers/__init__.py b/aurweb/routers/__init__.py new file mode 100644 index 00000000..35d43c03 --- /dev/null +++ b/aurweb/routers/__init__.py @@ -0,0 +1,5 @@ +""" +API routers for FastAPI. + +See https://fastapi.tiangolo.com/tutorial/bigger-applications/ +""" diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py new file mode 100644 index 00000000..b16edffb --- /dev/null +++ b/aurweb/routers/sso.py @@ -0,0 +1,30 @@ +import fastapi + +from authlib.integrations.starlette_client import OAuth +from starlette.requests import Request + +import aurweb.config + +router = fastapi.APIRouter() + +oauth = OAuth() +oauth.register( + name="sso", + server_metadata_url=aurweb.config.get("sso", "openid_configuration"), + client_kwargs={"scope": "openid"}, + client_id=aurweb.config.get("sso", "client_id"), + client_secret=aurweb.config.get("sso", "client_secret"), +) + + +@router.get("/sso/login") +async def login(request: Request): + redirect_uri = aurweb.config.get("options", "aur_location") + "/sso/authenticate" + return await oauth.sso.authorize_redirect(request, redirect_uri, prompt="login") + + +@router.get("/sso/authenticate") +async def authenticate(request: Request): + token = await oauth.sso.authorize_access_token(request) + user = await oauth.sso.parse_id_token(request, token) + return dict(user) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index e86f29fe..5da8587e 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -60,6 +60,9 @@ def generate_nginx_config(): location / {{ proxy_pass http://{aurweb.config.get("php", "bind_address")}; }} + location /sso {{ + proxy_pass http://{aurweb.config.get("fastapi", "bind_address")}; + }} }} }} """) diff --git a/conf/config.defaults b/conf/config.defaults index 447dacac..49259754 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -68,6 +68,14 @@ username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ git-serve-cmd = /usr/local/bin/aurweb-git-serve ssh-options = restrict +[sso] +openid_configuration = +client_id = +client_secret = + +[fastapi] +session_secret = + [serve] repo-path = /srv/http/aurweb/aur.git/ repo-regex = [a-z0-9][a-z0-9.+_-]*$ diff --git a/conf/config.dev b/conf/config.dev index d752f61f..893e8fd6 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -20,6 +20,12 @@ aur_location = http://127.0.0.1:8080 disable_http_login = 0 enable-maintenance = 0 +; Single sign-on +[sso] +openid_configuration = http://127.0.0.1:8083/auth/realms/aurweb/.well-known/openid-configuration +client_id = aurweb +client_secret = + [php] ; Address PHP should bind when spawned in development mode by aurweb.spawn. bind_address = 127.0.0.1:8081 @@ -30,3 +36,6 @@ htmldir = YOUR_AUR_ROOT/web/html [fastapi] ; Address uvicorn should bind when spawned in development mode by aurweb.spawn. bind_address = 127.0.0.1:8082 + +; Passphrase FastAPI uses to sign client-side sessions. +session_secret = secret From 2b439b819908a7f6e9cbd9029d82de617230312f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Thu, 4 Jun 2020 22:00:34 +0200 Subject: [PATCH 0550/1891] Guide to setting up Keycloak for the SSO Signed-off-by: Lukas Fleischer --- conf/config.dev | 2 +- doc/sso.txt | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 doc/sso.txt diff --git a/conf/config.dev b/conf/config.dev index 893e8fd6..37f38c45 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -20,7 +20,7 @@ aur_location = http://127.0.0.1:8080 disable_http_login = 0 enable-maintenance = 0 -; Single sign-on +; Single sign-on; see doc/sso.txt. [sso] openid_configuration = http://127.0.0.1:8083/auth/realms/aurweb/.well-known/openid-configuration client_id = aurweb diff --git a/doc/sso.txt b/doc/sso.txt new file mode 100644 index 00000000..1b0b1f7d --- /dev/null +++ b/doc/sso.txt @@ -0,0 +1,38 @@ +Single Sign-On (SSO) +==================== + +This guide will walk you through setting up Keycloak for use with aurweb. For +extensive documentation, see . + +Installing Keycloak +------------------- + +Keycloak is in the official Arch repositories: + + # pacman -S keycloak + +The default port is 8080, which conflicts with aurweb’s default port. You need +to edit `/etc/keycloak/standalone.xml`, looking for this line: + + + +The default developer configuration assumes it is set to 8083. Alternatively, +you may customize [options] aur_location and [sso] openid_configuration in +`conf/config`. + +You may then start `keycloak.service` through systemd. + +See also ArchWiki . + +Configuring a realm +------------------- + +Go to and log in as administrator. Then, hover the +text right below the Keycloak logo at the top left, by default *Master*. Click +*Add realm* and name it *aurweb*. + +Open the *Clients* tab, and create a new *openid-connect* client. Call it +*aurweb*, and set the root URL to (your aur_location). + +Create a user from the *Users* tab and try logging in from +. From 3f31d149a6dd736007c6583a6162aeda1bcc37b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 9 Jun 2020 20:25:22 +0200 Subject: [PATCH 0551/1891] aurweb.l10n: Translate without side effects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The install method in Python’s gettext API aliases the translator’s gettext method to an application-global _(). We don’t use that anywhere, and it’s clear from aurweb’s Translator interface that we want to translate a piece of text without affecting any global namespace. Signed-off-by: Lukas Fleischer --- aurweb/l10n.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aurweb/l10n.py b/aurweb/l10n.py index 492200b3..51b56abb 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -15,5 +15,4 @@ class Translator: self._translator[lang] = gettext.translation("aurweb", self._localedir, languages=[lang]) - self._translator[lang].install() - return _(s) # _ is not defined, what is this? # noqa: F821 + return self._translator[lang].gettext(s) From a5554c19a9712ede5fe5a996bd1bec11cfc9f66a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 8 Jun 2020 20:16:27 +0200 Subject: [PATCH 0552/1891] Add SSO account ID in table Users This column holds a user ID issed by the single sign-on provider. For Keycloak, it is an UUID. For more flexibility, we will be using a standardly-sized VARCHAR field. Signed-off-by: Lukas Fleischer --- aurweb/schema.py | 1 + ...6e1cd_add_sso_account_id_in_table_users.py | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py diff --git a/aurweb/schema.py b/aurweb/schema.py index 20f3e5ce..a1d56281 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -67,6 +67,7 @@ Users = Table( Column('CommentNotify', TINYINT(1), nullable=False, server_default=text("1")), Column('UpdateNotify', TINYINT(1), nullable=False, server_default=text("0")), Column('OwnershipNotify', TINYINT(1), nullable=False, server_default=text("1")), + Column('SSOAccountID', String(255), nullable=True, unique=True), Index('UsersAccountTypeID', 'AccountTypeID'), mysql_engine='InnoDB', ) diff --git a/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py b/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py new file mode 100644 index 00000000..9e125165 --- /dev/null +++ b/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py @@ -0,0 +1,30 @@ +"""Add SSO account ID in table Users + +Revision ID: ef39fcd6e1cd +Revises: f47cad5d6d03 +Create Date: 2020-06-08 10:04:13.898617 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ef39fcd6e1cd' +down_revision = 'f47cad5d6d03' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('Users', sa.Column('SSOAccountID', sa.String(length=255), nullable=True)) + op.create_unique_constraint(None, 'Users', ['SSOAccountID']) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'Users', type_='unique') + op.drop_column('Users', 'SSOAccountID') + # ### end Alembic commands ### From c77e9d1de0d14253ab3c3b958f459b04b233aeb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 8 Jun 2020 20:16:36 +0200 Subject: [PATCH 0553/1891] Integrate SQLAlchemy into FastAPI Signed-off-by: Lukas Fleischer --- aurweb/db.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/aurweb/db.py b/aurweb/db.py index 1ccd9a07..02aeba38 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -10,6 +10,8 @@ except ImportError: import aurweb.config +engine = None # See get_engine + def get_sqlalchemy_url(): """ @@ -38,6 +40,34 @@ def get_sqlalchemy_url(): raise ValueError('unsupported database backend') +def get_engine(): + """ + Return the global SQLAlchemy engine. + + The engine is created on the first call to get_engine and then stored in the + `engine` global variable for the next calls. + """ + from sqlalchemy import create_engine + global engine + if engine is None: + engine = create_engine(get_sqlalchemy_url(), + # check_same_thread is for a SQLite technicality + # https://fastapi.tiangolo.com/tutorial/sql-databases/#note + connect_args={"check_same_thread": False}) + return engine + + +def connect(): + """ + Return an SQLAlchemy connection. Connections are usually pooled. See + . + + Since SQLAlchemy connections are context managers too, you should use it + with Python’s `with` operator, or with FastAPI’s dependency injection. + """ + return get_engine().connect() + + class Connection: _conn = None _paramstyle = None From 42f8f160b6c556a8c2006788a25b6fafe7be1c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 8 Jun 2020 20:16:49 +0200 Subject: [PATCH 0554/1891] Open AUR sessions from SSO Only the core functionality is implemented here. See the TODOs. Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 51 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index b16edffb..d0802c34 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -1,9 +1,18 @@ +import time +import uuid + import fastapi from authlib.integrations.starlette_client import OAuth +from fastapi import Depends, HTTPException +from fastapi.responses import RedirectResponse +from sqlalchemy.sql import select from starlette.requests import Request import aurweb.config +import aurweb.db + +from aurweb.schema import Sessions, Users router = fastapi.APIRouter() @@ -23,8 +32,46 @@ async def login(request: Request): return await oauth.sso.authorize_redirect(request, redirect_uri, prompt="login") +def open_session(conn, user_id): + """ + Create a new user session into the database. Return its SID. + """ + # TODO check for account suspension + # TODO apply [options] max_sessions_per_user + sid = uuid.uuid4().hex + conn.execute(Sessions.insert().values( + UsersID=user_id, + SessionID=sid, + LastUpdateTS=time.time(), + )) + # TODO update Users.LastLogin and Users.LastLoginIPAddress + return sid + + @router.get("/sso/authenticate") -async def authenticate(request: Request): +async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): + """ + Receive an OpenID Connect ID token, validate it, then process it to create + an new AUR session. + """ + # TODO check for banned IPs token = await oauth.sso.authorize_access_token(request) user = await oauth.sso.parse_id_token(request, token) - return dict(user) + sub = user.get("sub") # this is the SSO account ID in JWT terminology + if not sub: + raise HTTPException(status_code=400, detail="JWT is missing its `sub` field.") + + aur_accounts = conn.execute(select([Users.c.ID]).where(Users.c.SSOAccountID == sub)) \ + .fetchall() + if not aur_accounts: + return "Sorry, we don’t seem to know you Sir " + sub + elif len(aur_accounts) == 1: + sid = open_session(conn, aur_accounts[0][Users.c.ID]) + response = RedirectResponse("/") + # TODO redirect to the referrer + response.set_cookie(key="AURSID", value=sid, httponly=True, + secure=request.url.scheme == "https") + return response + else: + # We’ve got a severe integrity violation. + raise Exception("Multiple accounts found for SSO account " + sub) From 8d5244d0c0c3b38f29b9b087c5e85082f0bb1f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 13 Jul 2020 17:05:37 +0200 Subject: [PATCH 0555/1891] Fix typos in CONTRIBUTING.md Signed-off-by: Lukas Fleischer --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a37d980a..7b9ff466 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,9 @@ Patches should be sent to the [aur-dev@archlinux.org][1] mailing list. -Before sending patched you are recomended to run the `flake8` and `isort`. +Before sending patches, you are recommended to run `flake8` and `isort`. -You can add git hook to do this by installing `python-pre-install` and running -`pre-install install`. +You can add a git hook to do this by installing `python-pre-commit` and running +`pre-commit install`. [1] https://lists.archlinux.org/listinfo/aur-dev From 4bf8228324e4c3811b48069a4b2ae7fd840c78a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 14 Jul 2020 15:34:06 +0200 Subject: [PATCH 0556/1891] SSO: Explain the rationale behind prompt=login We might reconsider it in the future. Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index d0802c34..e1ec7efe 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -28,6 +28,13 @@ oauth.register( @router.get("/sso/login") async def login(request: Request): + """ + Redirect the user to the SSO provider’s login page. + + We specify prompt=login to force the user to input their credentials even + if they’re already logged on the SSO. This is less practical, but given AUR + has the potential to impact many users, better safe than sorry. + """ redirect_uri = aurweb.config.get("options", "aur_location") + "/sso/authenticate" return await oauth.sso.authorize_redirect(request, redirect_uri, prompt="login") From d12ea08fcaa62211cbf4d83bba91124b90f861cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 14 Jul 2020 15:34:23 +0200 Subject: [PATCH 0557/1891] SSO: Add an SSO option in the login page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We’ll probably change the whole login page in the future, but this makes development easier. Signed-off-by: Lukas Fleischer --- web/html/login.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/html/login.php b/web/html/login.php index 01454414..3a146f60 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -40,6 +40,9 @@ html_header('AUR ' . __("Login"));

    " /> [] + + [] + From 4d0f2d2279ed9fcdf6bb76015ac0da9c6e938d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 14 Jul 2020 15:35:05 +0200 Subject: [PATCH 0558/1891] Implement SSO logout Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 18 ++++++++++++++++++ web/html/logout.php | 14 +++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index e1ec7efe..a8d4b141 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -1,6 +1,8 @@ import time import uuid +from urllib.parse import urlencode + import fastapi from authlib.integrations.starlette_client import OAuth @@ -82,3 +84,19 @@ async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): else: # We’ve got a severe integrity violation. raise Exception("Multiple accounts found for SSO account " + sub) + + +@router.get("/sso/logout") +async def logout(): + """ + Disconnect the user from the SSO provider, potentially affecting every + other Arch service. AUR logout is performed by `/logout`, before it + redirects to `/sso/logout`. + + Based on the OpenID Connect Session Management specification: + https://openid.net/specs/openid-connect-session-1_0.html#RPLogout + """ + metadata = await oauth.sso.load_server_metadata() + # TODO Supply id_token_hint to the end session endpoint. + query = urlencode({'post_logout_redirect_uri': aurweb.config.get('options', 'aur_location')}) + return RedirectResponse(metadata["end_session_endpoint"] + '?' + query) diff --git a/web/html/logout.php b/web/html/logout.php index 14022001..9fd63943 100644 --- a/web/html/logout.php +++ b/web/html/logout.php @@ -5,16 +5,28 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); # access AUR common functions include_once("acctfuncs.inc.php"); # access AUR common functions +$redirect_uri = '/'; + # if they've got a cookie, log them out - need to do this before # sending any HTML output. # if (isset($_COOKIE["AURSID"])) { + $uid = uid_from_sid($_COOKIE['AURSID']); delete_session_id($_COOKIE["AURSID"]); # setting expiration to 1 means '1 second after midnight January 1, 1970' setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); unset($_COOKIE['AURSID']); clear_expired_sessions(); + + # If the account is linked to an SSO account, disconnect the user from the SSO too. + if (isset($uid)) { + $dbh = DB::connect(); + $sso_account_id = $dbh->query("SELECT SSOAccountID FROM Users WHERE ID = " . $dbh->quote($uid)) + ->fetchColumn(); + if ($sso_account_id) + $redirect_uri = '/sso/logout'; + } } -header('Location: /'); +header("Location: $redirect_uri"); From 357dba87b3ee784a4201a7bb56befb105b81bbf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 14 Jul 2020 15:35:24 +0200 Subject: [PATCH 0559/1891] Save id_token for the SSO logout As far as I can see, Keycloak ignores it entirely. I can login in as SSO user A, then disconnect from the SSO directly and reconnect as user B, but when I disconnect user A from AUR, Keycloak disconnects B even though AUR passed it an ID token for A. Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index a8d4b141..04ecdca6 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -80,6 +80,11 @@ async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): # TODO redirect to the referrer response.set_cookie(key="AURSID", value=sid, httponly=True, secure=request.url.scheme == "https") + if "id_token" in token: + # We save the id_token for the SSO logout. It’s not too important + # though, so if we can’t find it, we can live without it. + response.set_cookie(key="SSO_ID_TOKEN", value=token["id_token"], path="/sso/", + httponly=True, secure=request.url.scheme == "https") return response else: # We’ve got a severe integrity violation. @@ -87,7 +92,7 @@ async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): @router.get("/sso/logout") -async def logout(): +async def logout(request: Request): """ Disconnect the user from the SSO provider, potentially affecting every other Arch service. AUR logout is performed by `/logout`, before it @@ -96,7 +101,13 @@ async def logout(): Based on the OpenID Connect Session Management specification: https://openid.net/specs/openid-connect-session-1_0.html#RPLogout """ + id_token = request.cookies.get("SSO_ID_TOKEN") + if not id_token: + return RedirectResponse("/") + metadata = await oauth.sso.load_server_metadata() - # TODO Supply id_token_hint to the end session endpoint. - query = urlencode({'post_logout_redirect_uri': aurweb.config.get('options', 'aur_location')}) - return RedirectResponse(metadata["end_session_endpoint"] + '?' + query) + query = urlencode({'post_logout_redirect_uri': aurweb.config.get('options', 'aur_location'), + 'id_token_hint': id_token}) + response = RedirectResponse(metadata["end_session_endpoint"] + '?' + query) + response.delete_cookie("SSO_ID_TOKEN", path="/sso/") + return response From 0e08b151e5c3606e573b1f7113466b5dd6efdcef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 20 Jul 2020 16:25:11 +0200 Subject: [PATCH 0560/1891] SSO: Port IP ban checking Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 04ecdca6..efd4462c 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -14,7 +14,7 @@ from starlette.requests import Request import aurweb.config import aurweb.db -from aurweb.schema import Sessions, Users +from aurweb.schema import Bans, Sessions, Users router = fastapi.APIRouter() @@ -57,13 +57,28 @@ def open_session(conn, user_id): return sid +def is_ip_banned(conn, ip): + """ + Check if an IP is banned. `ip` is a string and may be an IPv4 as well as an + IPv6, depending on the server’s configuration. + """ + result = conn.execute(Bans.select().where(Bans.c.IPAddress == ip)) + return result.fetchone() is not None + + @router.get("/sso/authenticate") async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): """ Receive an OpenID Connect ID token, validate it, then process it to create an new AUR session. """ - # TODO check for banned IPs + # TODO Handle translations + if is_ip_banned(conn, request.client.host): + raise HTTPException( + status_code=403, + detail='The login form is currently disabled for your IP address, ' + 'probably due to sustained spam attacks. Sorry for the ' + 'inconvenience.') token = await oauth.sso.authorize_access_token(request) user = await oauth.sso.parse_id_token(request, token) sub = user.get("sub") # this is the SSO account ID in JWT terminology From e323156947a93ba65a99f927ed2d99c738c34f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 20 Jul 2020 16:25:22 +0200 Subject: [PATCH 0561/1891] SSO: Port account suspension Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index efd4462c..3e3b743d 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -41,11 +41,20 @@ async def login(request: Request): return await oauth.sso.authorize_redirect(request, redirect_uri, prompt="login") +def is_account_suspended(conn, user_id): + row = conn.execute(select([Users.c.Suspended]).where(Users.c.ID == user_id)).fetchone() + return row is not None and bool(row[0]) + + def open_session(conn, user_id): """ Create a new user session into the database. Return its SID. """ - # TODO check for account suspension + # TODO Handle translations. + if is_account_suspended(conn, user_id): + raise HTTPException(status_code=403, detail='Account suspended') + # TODO This is a terrible message because it could imply the attempt at + # logging in just caused the suspension. # TODO apply [options] max_sessions_per_user sid = uuid.uuid4().hex conn.execute(Sessions.insert().values( From 239988def7479cba6407901ee4671b6794d0b2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 20 Jul 2020 16:25:28 +0200 Subject: [PATCH 0562/1891] Build a translation facility for FastAPI Signed-off-by: Lukas Fleischer --- aurweb/l10n.py | 22 ++++++++++++++++++++++ aurweb/routers/sso.py | 20 +++++++++++--------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/aurweb/l10n.py b/aurweb/l10n.py index 51b56abb..a476ecd8 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -16,3 +16,25 @@ class Translator: self._localedir, languages=[lang]) return self._translator[lang].gettext(s) + + +def get_translator_for_request(request): + """ + Determine the preferred language from a FastAPI request object and build a + translator function for it. + + Example: + ```python + _ = get_translator_for_request(request) + print(_("Hello")) + ``` + """ + lang = request.cookies.get("AURLANG") + if lang is None: + lang = aurweb.config.get("options", "default_lang") + translator = Translator() + + def translate(message): + return translator.translate(message, lang) + + return translate diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 3e3b743d..7b9c67c8 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -14,6 +14,7 @@ from starlette.requests import Request import aurweb.config import aurweb.db +from aurweb.l10n import get_translator_for_request from aurweb.schema import Bans, Sessions, Users router = fastapi.APIRouter() @@ -46,13 +47,13 @@ def is_account_suspended(conn, user_id): return row is not None and bool(row[0]) -def open_session(conn, user_id): +def open_session(request, conn, user_id): """ Create a new user session into the database. Return its SID. """ - # TODO Handle translations. if is_account_suspended(conn, user_id): - raise HTTPException(status_code=403, detail='Account suspended') + _ = get_translator_for_request(request) + raise HTTPException(status_code=403, detail=_('Account suspended')) # TODO This is a terrible message because it could imply the attempt at # logging in just caused the suspension. # TODO apply [options] max_sessions_per_user @@ -81,25 +82,26 @@ async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): Receive an OpenID Connect ID token, validate it, then process it to create an new AUR session. """ - # TODO Handle translations if is_ip_banned(conn, request.client.host): + _ = get_translator_for_request(request) raise HTTPException( status_code=403, - detail='The login form is currently disabled for your IP address, ' - 'probably due to sustained spam attacks. Sorry for the ' - 'inconvenience.') + detail=_('The login form is currently disabled for your IP address, ' + 'probably due to sustained spam attacks. Sorry for the ' + 'inconvenience.')) token = await oauth.sso.authorize_access_token(request) user = await oauth.sso.parse_id_token(request, token) sub = user.get("sub") # this is the SSO account ID in JWT terminology if not sub: - raise HTTPException(status_code=400, detail="JWT is missing its `sub` field.") + _ = get_translator_for_request(request) + raise HTTPException(status_code=400, detail=_("JWT is missing its `sub` field.")) aur_accounts = conn.execute(select([Users.c.ID]).where(Users.c.SSOAccountID == sub)) \ .fetchall() if not aur_accounts: return "Sorry, we don’t seem to know you Sir " + sub elif len(aur_accounts) == 1: - sid = open_session(conn, aur_accounts[0][Users.c.ID]) + sid = open_session(request, conn, aur_accounts[0][Users.c.ID]) response = RedirectResponse("/") # TODO redirect to the referrer response.set_cookie(key="AURSID", value=sid, httponly=True, From efe99dc16f2a94be1d4e5917a07fee2260f3d547 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 5 Jul 2020 18:19:06 -0700 Subject: [PATCH 0563/1891] Support conjunctive keyword search in RPC interface Newly supported API Version 6 modifies `type=search` for _by_ type `name-desc`: it now behaves the same as `name-desc` search through the https://aur.archlinux.org/packages/ search page. Search for packages containing the literal keyword `blah blah` AND `haha`: https://aur.archlinux.org/rpc/?v=6&type=search&arg="blah blah"%20haha Search for packages containing the literal keyword `abc 123`: https://aur.archlinux.org/rpc/?v=6&type=search&arg="abc 123" The following example searches for packages that contain `blah` AND `abc`: https://aur.archlinux.org/rpc/?v=6&type=search&arg=blah%20abc The legacy method still searches for packages that contain `blah abc`: https://aur.archlinux.org/rpc/?v=5&type=search&arg=blah%20abc https://aur.archlinux.org/rpc/?v=5&type=search&arg=blah%20abc API Version 6 is currently only considered during a `search` of `name-desc`. Note: This change was written as a solution to https://bugs.archlinux.org/task/49133. PS: + Some spacing issues fixed in comments. Signed-off-by: Kevin Morris Signed-off-by: Lukas Fleischer --- doc/rpc.txt | 4 ++++ web/lib/aurjson.class.php | 29 +++++++++++++++++++---------- web/lib/pkgfuncs.inc.php | 34 ++++++++++++++++++++-------------- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/doc/rpc.txt b/doc/rpc.txt index 3148ebea..b0f5c4e1 100644 --- a/doc/rpc.txt +++ b/doc/rpc.txt @@ -39,6 +39,10 @@ Examples `/rpc/?v=5&type=search&by=makedepends&arg=boost` `search` with callback:: `/rpc/?v=5&type=search&arg=foobar&callback=jsonp1192244621103` +`search` with API Version 6 for packages containing `cookie` AND `milk`:: + `/rpc/?v=6&type=search&arg=cookie%20milk` +`search` with API Version 6 for packages containing `cookie milk`:: + `/rpc/?v=6&type=search&arg="cookie milk"` `info`:: `/rpc/?v=5&type=info&arg[]=foobar` `info` with multiple packages:: diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 0ac586fe..86eae22b 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -1,6 +1,7 @@ version = intval($http_data['v']); } - if ($this->version < 1 || $this->version > 5) { + if ($this->version < 1 || $this->version > 6) { return $this->json_error('Invalid version specified.'); } @@ -140,7 +141,7 @@ class AurJSON { } /* - * Check if an IP needs to be rate limited. + * Check if an IP needs to be rate limited. * * @param $ip IP of the current request * @@ -192,7 +193,7 @@ class AurJSON { $value = get_cache_value('ratelimit-ws:' . $ip, $status); if (!$status || ($status && $value < $deletion_time)) { if (set_cache_value('ratelimit-ws:' . $ip, $time, $window_length) && - set_cache_value('ratelimit:' . $ip, 1, $window_length)) { + set_cache_value('ratelimit:' . $ip, 1, $window_length)) { return; } } else { @@ -370,7 +371,7 @@ class AurJSON { } elseif ($this->version >= 2) { if ($this->version == 2 || $this->version == 3) { $fields = implode(',', self::$fields_v2); - } else if ($this->version == 4 || $this->version == 5) { + } else if ($this->version >= 4 && $this->version <= 6) { $fields = implode(',', self::$fields_v4); } $query = "SELECT {$fields} " . @@ -492,13 +493,21 @@ class AurJSON { if (strlen($keyword_string) < 2) { return $this->json_error('Query arg too small.'); } - $keyword_string = $this->dbh->quote("%" . addcslashes($keyword_string, '%_') . "%"); - if ($search_by === 'name') { - $where_condition = "(Packages.Name LIKE $keyword_string)"; - } else if ($search_by === 'name-desc') { - $where_condition = "(Packages.Name LIKE $keyword_string OR "; - $where_condition .= "Description LIKE $keyword_string)"; + if ($this->version >= 6 && $search_by === 'name-desc') { + $where_condition = construct_keyword_search($this->dbh, + $keyword_string, true, false); + } else { + $keyword_string = $this->dbh->quote( + "%" . addcslashes($keyword_string, '%_') . "%"); + + if ($search_by === 'name') { + $where_condition = "(Packages.Name LIKE $keyword_string)"; + } else if ($search_by === 'name-desc') { + $where_condition = "(Packages.Name LIKE $keyword_string "; + $where_condition .= "OR Description LIKE $keyword_string)"; + } + } } else if ($search_by === 'maintainer') { if (empty($keyword_string)) { diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 80758005..ac5c8cfe 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -696,8 +696,10 @@ function pkg_search_page($params, $show_headers=true, $SID="") { $q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") "; } elseif (isset($params["SeB"]) && $params["SeB"] == "k") { - /* Search by keywords. */ - $q_where .= construct_keyword_search($dbh, $params['K'], false); + /* Search by name. */ + $q_where .= "AND ("; + $q_where .= construct_keyword_search($dbh, $params['K'], false, true); + $q_where .= ") "; } elseif (isset($params["SeB"]) && $params["SeB"] == "N") { /* Search by name (exact match). */ @@ -709,7 +711,9 @@ function pkg_search_page($params, $show_headers=true, $SID="") { } else { /* Keyword search (default). */ - $q_where .= construct_keyword_search($dbh, $params['K'], true); + $q_where .= "AND ("; + $q_where .= construct_keyword_search($dbh, $params['K'], true, true); + $q_where .= ") "; } } @@ -832,10 +836,11 @@ function pkg_search_page($params, $show_headers=true, $SID="") { * @param handle $dbh Database handle * @param string $keywords The search term * @param bool $namedesc Search name and description fields + * @param bool $keyword Search packages with a matching PackageBases.Keyword * * @return string WHERE part of the SQL clause */ -function construct_keyword_search($dbh, $keywords, $namedesc) { +function construct_keyword_search($dbh, $keywords, $namedesc, $keyword=false) { $count = 0; $where_part = ""; $q_keywords = ""; @@ -860,13 +865,18 @@ function construct_keyword_search($dbh, $keywords, $namedesc) { $term = "%" . addcslashes($term, '%_') . "%"; $q_keywords .= $op . " ("; + $q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " "; if ($namedesc) { - $q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " OR "; - $q_keywords .= "Description LIKE " . $dbh->quote($term) . " OR "; + $q_keywords .= "OR Description LIKE " . $dbh->quote($term) . " "; + } + + if ($keyword) { + $q_keywords .= "OR EXISTS (SELECT * FROM PackageKeywords WHERE "; + $q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND "; + $q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) "; + } else { + $q_keywords .= ") "; } - $q_keywords .= "EXISTS (SELECT * FROM PackageKeywords WHERE "; - $q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND "; - $q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) "; $count++; if ($count >= 20) { @@ -875,11 +885,7 @@ function construct_keyword_search($dbh, $keywords, $namedesc) { $op = "AND "; } - if (!empty($q_keywords)) { - $where_part = "AND (" . $q_keywords . ") "; - } - - return $where_part; + return $q_keywords; } /** From 445a991ef1b8c76fb1d51837c4fb692dbfb080e6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 15 Jul 2020 11:45:54 -0700 Subject: [PATCH 0564/1891] Exclude suspended Users from being notified The existing notify.py script was grabbing entries regardless of user suspension. This has been modified to only send notifications to unsuspended users. This change was written as a solution to https://bugs.archlinux.org/task/65554. Signed-off-by: Kevin Morris Signed-off-by: Lukas Fleischer --- aurweb/scripts/notify.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index edae76f8..7f8e7168 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -126,7 +126,7 @@ class ResetKeyNotification(Notification): def __init__(self, conn, uid): cur = conn.execute('SELECT UserName, Email, BackupEmail, ' + 'LangPreference, ResetKey ' + - 'FROM Users WHERE ID = ?', [uid]) + 'FROM Users WHERE ID = ? AND Suspended = 0', [uid]) self._username, self._to, self._backup, self._lang, self._resetkey = cur.fetchone() super().__init__() @@ -173,7 +173,8 @@ class CommentNotification(Notification): 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.CommentNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', + 'PackageNotifications.PackageBaseID = ? AND ' + + 'Users.Suspended = 0', [uid, pkgbase_id]) self._recipients = cur.fetchall() cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', @@ -220,7 +221,8 @@ class UpdateNotification(Notification): 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.UpdateNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', + 'PackageNotifications.PackageBaseID = ? AND ' + + 'Users.Suspended = 0', [uid, pkgbase_id]) self._recipients = cur.fetchall() super().__init__() @@ -266,7 +268,8 @@ class FlagNotification(Notification): 'INNER JOIN PackageBases ' + 'ON PackageBases.MaintainerUID = Users.ID OR ' + 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + - 'WHERE PackageBases.ID = ?', [pkgbase_id]) + 'WHERE PackageBases.ID = ? AND ' + + 'Users.Suspended = 0', [pkgbase_id]) self._recipients = cur.fetchall() cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + 'ID = ?', [pkgbase_id]) @@ -304,7 +307,8 @@ class OwnershipEventNotification(Notification): 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.OwnershipNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', + 'PackageNotifications.PackageBaseID = ? AND ' + + 'Users.Suspended = 0', [uid, pkgbase_id]) self._recipients = cur.fetchall() cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + @@ -343,7 +347,7 @@ class ComaintainershipEventNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._pkgbase = pkgbase_from_id(conn, pkgbase_id) cur = conn.execute('SELECT Email, LangPreference FROM Users ' + - 'WHERE ID = ?', [uid]) + 'WHERE ID = ? AND Suspended = 0', [uid]) self._to, self._lang = cur.fetchone() super().__init__() @@ -386,7 +390,8 @@ class DeleteNotification(Notification): 'INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ?', + 'PackageNotifications.PackageBaseID = ? AND ' + + 'Users.Suspended = 0', [uid, old_pkgbase_id]) self._recipients = cur.fetchall() super().__init__() @@ -433,7 +438,8 @@ class RequestOpenNotification(Notification): 'INNER JOIN Users ' + 'ON Users.ID = PackageRequests.UsersID ' + 'OR Users.ID = PackageBases.MaintainerUID ' + - 'WHERE PackageRequests.ID = ?', [reqid]) + 'WHERE PackageRequests.ID = ? AND ' + + 'Users.Suspended = 0', [reqid]) self._to = aurweb.config.get('options', 'aur_request_ml') self._cc = [row[0] for row in cur.fetchall()] cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?', @@ -489,7 +495,8 @@ class RequestCloseNotification(Notification): 'INNER JOIN Users ' + 'ON Users.ID = PackageRequests.UsersID ' + 'OR Users.ID = PackageBases.MaintainerUID ' + - 'WHERE PackageRequests.ID = ?', [reqid]) + 'WHERE PackageRequests.ID = ? AND ' + + 'Users.Suspended = 0', [reqid]) self._to = aurweb.config.get('options', 'aur_request_ml') self._cc = [row[0] for row in cur.fetchall()] cur = conn.execute('SELECT PackageRequests.ClosureComment, ' + @@ -547,7 +554,8 @@ class TUVoteReminderNotification(Notification): cur = conn.execute('SELECT Email, LangPreference FROM Users ' + 'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' + '(SELECT UserID FROM TU_Votes ' + - 'WHERE TU_Votes.VoteID = ?)', [vote_id]) + 'WHERE TU_Votes.VoteID = ?) AND ' + + 'Users.Suspended = 0', [vote_id]) self._recipients = cur.fetchall() super().__init__() From a1a742b518b7ead1ea32b13dd52d5ea5248e8bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 27 Jul 2020 14:43:48 +0200 Subject: [PATCH 0565/1891] aurweb.spawn: Support stdout redirections to non-tty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only ttys have a terminal size. If we can’t obtain it, we’ll just use 80 as a sane default. Signed-off-by: Lukas Fleischer --- aurweb/spawn.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 5da8587e..46d534d9 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -87,12 +87,16 @@ def start(): return atexit.register(stop) + try: + terminal_width = os.get_terminal_size().columns + except OSError: + terminal_width = 80 print("{ruler}\n" "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n" "Check out {aur_location}\n" "Hit ^C to terminate everything.\n" "{ruler}" - .format(ruler=("-" * os.get_terminal_size().columns), + .format(ruler=("-" * terminal_width), aur_location=aurweb.config.get('options', 'aur_location'))) # PHP From 9290eee1385b4ac9e09fec4a784868789ea5a15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Mon, 27 Jul 2020 14:44:03 +0200 Subject: [PATCH 0566/1891] Stop redirecting stderr with proc_open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Error outputs were piped to a temporary buffer that wasn’t read by anyone, making debugging hard because errors were completely silenced. By not explicitly redirecting stderr on proc_open, the subprocess inherits its parent stderr. Signed-off-by: Lukas Fleischer --- web/lib/acctfuncs.inc.php | 2 -- web/lib/pkgbasefuncs.inc.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 752abe97..b3822eaf 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -1347,7 +1347,6 @@ function notify($params) { $descspec = array( 0 => array('pipe', 'r'), 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') ); $p = proc_open($cmd, $descspec, $pipes); @@ -1358,7 +1357,6 @@ function notify($params) { fclose($pipes[0]); fclose($pipes[1]); - fclose($pipes[2]); return proc_close($p); } diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 4c8abba7..4a49898c 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -96,7 +96,6 @@ function render_comment($id) { $descspec = array( 0 => array('pipe', 'r'), 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') ); $p = proc_open($cmd, $descspec, $pipes); @@ -107,7 +106,6 @@ function render_comment($id) { fclose($pipes[0]); fclose($pipes[1]); - fclose($pipes[2]); return proc_close($p); } From 202ffd8923bc3a08bc6d4f18ac6d91441b0b0cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 28 Jul 2020 16:33:12 +0200 Subject: [PATCH 0567/1891] Update last login information on SSO login Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 7b9c67c8..817adadb 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -63,7 +63,13 @@ def open_session(request, conn, user_id): SessionID=sid, LastUpdateTS=time.time(), )) - # TODO update Users.LastLogin and Users.LastLoginIPAddress + + # Update user’s last login information. + conn.execute(Users.update() + .where(Users.c.ID == user_id) + .values(LastLogin=int(time.time()), + LastLoginIPAddress=request.client.host)) + return sid From 5fb4fc12de1dc374395340724d192271d4aa31f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 28 Jul 2020 16:33:27 +0200 Subject: [PATCH 0568/1891] HTML error pages for FastAPI Signed-off-by: Lukas Fleischer --- aurweb/asgi.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 60c7ade7..9293ed77 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -1,4 +1,7 @@ -from fastapi import FastAPI +import http + +from fastapi import FastAPI, HTTPException +from fastapi.responses import HTMLResponse from starlette.middleware.sessions import SessionMiddleware import aurweb.config @@ -14,3 +17,14 @@ if not session_secret: app.add_middleware(SessionMiddleware, secret_key=session_secret) app.include_router(sso.router) + + +@app.exception_handler(HTTPException) +async def http_exception_handler(request, exc): + """ + Dirty HTML error page to replace the default JSON error responses. + In the future this should use a proper Arch-themed HTML template. + """ + phrase = http.HTTPStatus(exc.status_code).phrase + return HTMLResponse(f"

    {exc.status_code} {phrase}

    {exc.detail}

    ", + status_code=exc.status_code) From be31675b6589e66c8b10a64b44591b594d2eb735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Tue, 28 Jul 2020 16:33:41 +0200 Subject: [PATCH 0569/1891] Guard OAuth exceptions to provide better messages Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 817adadb..2e4fbacc 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -5,7 +5,7 @@ from urllib.parse import urlencode import fastapi -from authlib.integrations.starlette_client import OAuth +from authlib.integrations.starlette_client import OAuth, OAuthError from fastapi import Depends, HTTPException from fastapi.responses import RedirectResponse from sqlalchemy.sql import select @@ -95,8 +95,18 @@ async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): detail=_('The login form is currently disabled for your IP address, ' 'probably due to sustained spam attacks. Sorry for the ' 'inconvenience.')) - token = await oauth.sso.authorize_access_token(request) - user = await oauth.sso.parse_id_token(request, token) + + try: + token = await oauth.sso.authorize_access_token(request) + user = await oauth.sso.parse_id_token(request, token) + except OAuthError: + # Here, most OAuth errors should be caused by forged or expired tokens. + # Let’s give attackers as little information as possible. + _ = get_translator_for_request(request) + raise HTTPException( + status_code=400, + detail=_('Bad OAuth token. Please retry logging in from the start.')) + sub = user.get("sub") # this is the SSO account ID in JWT terminology if not sub: _ = get_translator_for_request(request) From 87815d37c078c315ac3254741973cfba2bfccace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Wed, 29 Jul 2020 13:46:10 +0200 Subject: [PATCH 0570/1891] Remove the per-user session limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This feature was originally introduced by f961ffd9c7f2d3d51d3e3b060990a4fef9e56c1b as a fix for FS#12898 . As of today, it is broken because of the `q.SessionID IS NULL` condition in the WHERE clause, which can’t be true because SessionID is not nullable. As a consequence, the session limit was not applied. The fact the absence of the session limit hasn’t caused any issue so far, and hadn’t even been noticed, suggests the feature is unneeded. Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 2 +- conf/config.defaults | 1 - web/lib/acctfuncs.inc.php | 15 --------------- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 2e4fbacc..73c884a4 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -56,7 +56,7 @@ def open_session(request, conn, user_id): raise HTTPException(status_code=403, detail=_('Account suspended')) # TODO This is a terrible message because it could imply the attempt at # logging in just caused the suspension. - # TODO apply [options] max_sessions_per_user + sid = uuid.uuid4().hex conn.execute(Sessions.insert().values( UsersID=user_id, diff --git a/conf/config.defaults b/conf/config.defaults index 49259754..98e033b7 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -13,7 +13,6 @@ passwd_min_len = 8 default_lang = en default_timezone = UTC sql_debug = 0 -max_sessions_per_user = 8 login_timeout = 7200 persistent_cookie_timeout = 2592000 max_filesize_uncompressed = 8388608 diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index b3822eaf..bc603d3b 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -596,21 +596,6 @@ function try_login() { /* Generate a session ID and store it. */ while (!$logged_in && $num_tries < 5) { - $session_limit = config_get_int('options', 'max_sessions_per_user'); - if ($session_limit) { - /* - * Delete all user sessions except the - * last ($session_limit - 1). - */ - $q = "DELETE FROM Sessions "; - $q.= "WHERE UsersId = " . $userID . " "; - $q.= "AND SessionID NOT IN (SELECT SessionID FROM Sessions "; - $q.= "WHERE UsersID = " . $userID . " "; - $q.= "ORDER BY LastUpdateTS DESC "; - $q.= "LIMIT " . ($session_limit - 1) . ")"; - $dbh->query($q); - } - $new_sid = new_sid(); $q = "INSERT INTO Sessions (UsersID, SessionID, LastUpdateTS)" ." VALUES (" . $userID . ", '" . $new_sid . "', " . strval(time()) . ")"; From 8c28ba6e7f1c99f4b16c651857224b1d19f93466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Mangano-Tarumi?= Date: Wed, 29 Jul 2020 17:25:44 +0200 Subject: [PATCH 0571/1891] Redirect to referer after SSO login Introduce a `redirect` query argument to SSO login endpoints so that users are redirected to the page they were originally on when they clicked the Login link. Signed-off-by: Lukas Fleischer --- aurweb/routers/sso.py | 23 +++++++++++++++++------ web/html/login.php | 18 ++++++++++++------ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 73c884a4..4b12b932 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -30,16 +30,21 @@ oauth.register( @router.get("/sso/login") -async def login(request: Request): +async def login(request: Request, redirect: str = None): """ Redirect the user to the SSO provider’s login page. We specify prompt=login to force the user to input their credentials even if they’re already logged on the SSO. This is less practical, but given AUR has the potential to impact many users, better safe than sorry. + + The `redirect` argument is a query parameter specifying the post-login + redirect URL. """ - redirect_uri = aurweb.config.get("options", "aur_location") + "/sso/authenticate" - return await oauth.sso.authorize_redirect(request, redirect_uri, prompt="login") + authenticate_url = aurweb.config.get("options", "aur_location") + "/sso/authenticate" + if redirect: + authenticate_url = authenticate_url + "?" + urlencode([("redirect", redirect)]) + return await oauth.sso.authorize_redirect(request, authenticate_url, prompt="login") def is_account_suspended(conn, user_id): @@ -82,8 +87,15 @@ def is_ip_banned(conn, ip): return result.fetchone() is not None +def is_aur_url(url): + aur_location = aurweb.config.get("options", "aur_location") + if not aur_location.endswith("/"): + aur_location = aur_location + "/" + return url.startswith(aur_location) + + @router.get("/sso/authenticate") -async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): +async def authenticate(request: Request, redirect: str = None, conn=Depends(aurweb.db.connect)): """ Receive an OpenID Connect ID token, validate it, then process it to create an new AUR session. @@ -118,8 +130,7 @@ async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): return "Sorry, we don’t seem to know you Sir " + sub elif len(aur_accounts) == 1: sid = open_session(request, conn, aur_accounts[0][Users.c.ID]) - response = RedirectResponse("/") - # TODO redirect to the referrer + response = RedirectResponse(redirect if redirect and is_aur_url(redirect) else "/") response.set_cookie(key="AURSID", value=sid, httponly=True, secure=request.url.scheme == "https") if "id_token" in token: diff --git a/web/html/login.php b/web/html/login.php index 3a146f60..3f3d66cc 100644 --- a/web/html/login.php +++ b/web/html/login.php @@ -9,6 +9,10 @@ if (!$disable_http_login || (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'])) { $login_error = $login['error']; } +$referer = in_request('referer'); +if ($referer === '') + $referer = $_SERVER['HTTP_REFERER']; + html_header('AUR ' . __("Login")); ?>
    @@ -40,13 +44,15 @@ html_header('AUR ' . __("Login"));

    " /> [] - - [] + + [] - - - - + +

    From 83d228d9e8c2b067dfd5565d22437363f7590d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 13 Aug 2020 15:45:58 +0100 Subject: [PATCH 0572/1891] spawn: expand AUR_CONFIG to the full path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows using a relative path for the config. PHP didn't play well with it. Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- aurweb/spawn.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 46d534d9..3c5130d7 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -11,6 +11,7 @@ configuration anyway. import argparse import atexit import os +import os.path import subprocess import sys import tempfile @@ -87,6 +88,9 @@ def start(): return atexit.register(stop) + if 'AUR_CONFIG' in os.environ: + os.environ['AUR_CONFIG'] = os.path.realpath(os.environ['AUR_CONFIG']) + try: terminal_width = os.get_terminal_size().columns except OSError: From 4e4f5855f17acc2bd353093566ea853aa523f933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 13 Aug 2020 15:46:00 +0100 Subject: [PATCH 0573/1891] doc: fix AUR_CONFIG in TESTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- TESTING | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TESTING b/TESTING index d7df3672..17c6fbc7 100644 --- a/TESTING +++ b/TESTING @@ -29,7 +29,7 @@ INSTALL. 4) Prepare the testing database: $ cd /path/to/aurweb/ - $ python -m aurweb.initdb + $ AUR_CONFIG=conf/config python -m aurweb.initdb $ cd /path/to/aurweb/schema $ ./gendummydata.py out.sql @@ -37,4 +37,4 @@ INSTALL. 5) Run the test server: - $ AUR_CONFIG='/path/to/aurweb/conf/config' python -m aurweb.spawn + $ AUR_CONFIG=conf/config python -m aurweb.spawn From e62d472708e722e6123f9bfa01d2c32ec9838755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 13 Aug 2020 15:46:01 +0100 Subject: [PATCH 0574/1891] doc: add missing gendummydata.py dependencies in TESTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- TESTING | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TESTING b/TESTING index 17c6fbc7..d666b3ca 100644 --- a/TESTING +++ b/TESTING @@ -14,7 +14,8 @@ INSTALL. # pacman -S --needed php php-sqlite sqlite words fortune-mod \ python python-sqlalchemy python-alembic \ python-fastapi uvicorn nginx \ - python-authlib python-itsdangerous python-httpx + python-authlib python-itsdangerous python-httpx \ + words fortune-mod Ensure to enable the pdo_sqlite extension in php.ini. From db75a5528e45c13a427813c177bf9657a1cb8350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 13 Aug 2020 15:46:02 +0100 Subject: [PATCH 0575/1891] doc: simplify database setup instructions in TESTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns Signed-off-by: Lukas Fleischer --- TESTING | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TESTING b/TESTING index d666b3ca..972bce2c 100644 --- a/TESTING +++ b/TESTING @@ -30,11 +30,11 @@ INSTALL. 4) Prepare the testing database: $ cd /path/to/aurweb/ + $ AUR_CONFIG=conf/config python -m aurweb.initdb - $ cd /path/to/aurweb/schema - $ ./gendummydata.py out.sql - $ sqlite3 path/to/aurweb.sqlite3 < out.sql + $ schema/gendummydata.py data.sql + $ sqlite3 aurweb.sqlite3 < data.sql 5) Run the test server: From 92e315465b19e18b67ba7bff0b14c9658db579f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Fri, 4 Sep 2020 23:06:43 +0200 Subject: [PATCH 0576/1891] gendummydata.py: remove unused database connection variables Signed-off-by: Lukas Fleischer --- schema/gendummydata.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index b3a73ef2..8b15ac69 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -18,10 +18,6 @@ import time LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output SEED_FILE = "/usr/share/dict/words" -DB_HOST = os.getenv("DB_HOST", "localhost") -DB_NAME = os.getenv("DB_NAME", "AUR") -DB_USER = os.getenv("DB_USER", "aur") -DB_PASS = os.getenv("DB_PASS", "aur") USER_ID = 5 # Users.ID of first bogus user PKG_ID = 1 # Packages.ID of first package MAX_USERS = 300 # how many users to 'register' From 879c0622d66a04b38b281f879ebbf06ba97c62c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Fri, 4 Sep 2020 23:13:56 +0200 Subject: [PATCH 0577/1891] gendummydata.py: set exit code to 1 when there is an error Of course the default exit code is 0... Signed-off-by: Lukas Fleischer --- schema/gendummydata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 8b15ac69..224c82e5 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -44,19 +44,19 @@ log = logging.getLogger() if len(sys.argv) != 2: log.error("Missing output filename argument") - raise SystemExit + raise SystemExit(1) # make sure the seed file exists # if not os.path.exists(SEED_FILE): log.error("Please install the 'words' Arch package") - raise SystemExit + raise SystemExit(1) # make sure comments can be created # if not os.path.exists(FORTUNE_FILE): log.error("Please install the 'fortune-mod' Arch package") - raise SystemExit + raise SystemExit(1) # track what users/package names have been used # From 51a353582010a45b2121c25a5ad995111f1842a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Fri, 4 Sep 2020 23:10:20 +0200 Subject: [PATCH 0578/1891] gendummydata.py: set MAX_USERS and MAX_PKGS to more realistic values Signed-off-by: Lukas Fleischer --- schema/gendummydata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 224c82e5..91a580c2 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -20,16 +20,16 @@ LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output SEED_FILE = "/usr/share/dict/words" USER_ID = 5 # Users.ID of first bogus user PKG_ID = 1 # Packages.ID of first package -MAX_USERS = 300 # how many users to 'register' +MAX_USERS = 76000 # how many users to 'register' MAX_DEVS = .1 # what percentage of MAX_USERS are Developers MAX_TUS = .2 # what percentage of MAX_USERS are Trusted Users -MAX_PKGS = 900 # how many packages to load +MAX_PKGS = 64000 # how many packages to load PKG_DEPS = (1, 15) # min/max depends a package has PKG_RELS = (1, 5) # min/max relations a package has PKG_SRC = (1, 3) # min/max sources a package has PKG_CMNTS = (1, 5) # min/max number of comments a package has CATEGORIES_COUNT = 17 # the number of categories from aur-schema -VOTING = (0, .30) # percentage range for package voting +VOTING = (0, .001) # percentage range for package voting OPEN_PROPOSALS = 5 # number of open trusted user proposals CLOSE_PROPOSALS = 15 # number of closed trusted user proposals RANDOM_TLDS = ("edu", "com", "org", "net", "tw", "ru", "pl", "de", "es") From 3062a78a92d32144f423fdb460e96a309732d9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Fri, 4 Sep 2020 23:53:07 +0200 Subject: [PATCH 0579/1891] gendummydata.py: optimize iteration for big numbers of pkgs Signed-off-by: Lukas Fleischer --- schema/gendummydata.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 91a580c2..c7b3a06d 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -259,20 +259,23 @@ for p in list(track_votes.keys()): # Create package dependencies and sources # log.debug("Creating statements for package depends/sources.") -for p in list(seen_pkgs.keys()): +# the keys of seen_pkgs are accessed many times by random.choice, +# so the list has to be created outside the loops to keep it efficient +seen_pkgs_keys = list(seen_pkgs.keys()) +for p in seen_pkgs_keys: num_deps = random.randrange(PKG_DEPS[0], PKG_DEPS[1]) for i in range(0, num_deps): - dep = random.choice([k for k in seen_pkgs]) + dep = random.choice(seen_pkgs_keys) deptype = random.randrange(1, 5) if deptype == 4: - dep += ": for " + random.choice([k for k in seen_pkgs]) + dep += ": for " + random.choice(seen_pkgs_keys) s = "INSERT INTO PackageDepends(PackageID, DepTypeID, DepName) VALUES (%d, %d, '%s');\n" s = s % (seen_pkgs[p], deptype, dep) out.write(s) num_rels = random.randrange(PKG_RELS[0], PKG_RELS[1]) for i in range(0, num_deps): - rel = random.choice([k for k in seen_pkgs]) + rel = random.choice(seen_pkgs_keys) reltype = random.randrange(1, 4) s = "INSERT INTO PackageRelations(PackageID, RelTypeID, RelName) VALUES (%d, %d, '%s');\n" s = s % (seen_pkgs[p], reltype, rel) From bc972089a158459005700a7eaa8cee3ba666e2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sat, 5 Sep 2020 22:15:22 +0200 Subject: [PATCH 0580/1891] Fix WHERE clause for keyword search queries with empty keywords When the keyword parameter is empty, the AND clause has to be omitted, otherwise we get an SQL syntax error: ... WHERE PackageBases.PackagerUID IS NOT NULL AND () ... This got broken in commit 9e30013aa4fc6ce3a3c9f6f83a6fe789c1fc2456 Author: Kevin Morris Date: Sun Jul 5 18:19:06 2020 -0700 Support conjunctive keyword search in RPC interface Signed-off-by: Lukas Fleischer --- web/lib/pkgfuncs.inc.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index ac5c8cfe..eb3afab6 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -697,9 +697,7 @@ function pkg_search_page($params, $show_headers=true, $SID="") { } elseif (isset($params["SeB"]) && $params["SeB"] == "k") { /* Search by name. */ - $q_where .= "AND ("; $q_where .= construct_keyword_search($dbh, $params['K'], false, true); - $q_where .= ") "; } elseif (isset($params["SeB"]) && $params["SeB"] == "N") { /* Search by name (exact match). */ @@ -711,9 +709,7 @@ function pkg_search_page($params, $show_headers=true, $SID="") { } else { /* Keyword search (default). */ - $q_where .= "AND ("; $q_where .= construct_keyword_search($dbh, $params['K'], true, true); - $q_where .= ") "; } } @@ -885,7 +881,11 @@ function construct_keyword_search($dbh, $keywords, $namedesc, $keyword=false) { $op = "AND "; } - return $q_keywords; + if (!empty($q_keywords)) { + $where_part = "AND (" . $q_keywords . ") "; + } + + return $where_part; } /** From 568e0d2fa33d17ea4c45d046d9870d8ba0376789 Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Thu, 19 Nov 2020 23:16:17 +0100 Subject: [PATCH 0581/1891] RSS: Add atom self link https://validator.w3.org/feed/docs/warning/MissingAtomSelfLink.html Signed-off-by: Lukas Fleischer --- web/lib/feedcreator.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/lib/feedcreator.class.php b/web/lib/feedcreator.class.php index 802eebbe..e881f252 100644 --- a/web/lib/feedcreator.class.php +++ b/web/lib/feedcreator.class.php @@ -906,12 +906,13 @@ class RSSCreator091 extends FeedCreator { $feed = "encoding."\"?>\n"; $feed.= $this->_createGeneratorComment(); $feed.= $this->_createStylesheetReferences(); - $feed.= "RSSVersion."\">\n"; + $feed.= "RSSVersion."\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"; $feed.= " \n"; $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; $this->descriptionTruncSize = 500; $feed.= " ".$this->getDescription()."\n"; $feed.= " ".$this->link."\n"; + $feed.= " syndicationURL."\" rel=\"self\" type=\"application/rss+xml\" />\n"; $now = new FeedDate(); $feed.= " ".htmlspecialchars($now->rfc822())."\n"; $feed.= " ".FEEDCREATOR_VERSION."\n"; From 78dbbd3dfa916e0b054a231ff7cd56049ff7dc2f Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Thu, 19 Nov 2020 23:17:49 +0100 Subject: [PATCH 0582/1891] RSS: Set proper content type header https://validator.w3.org/feed/docs/warning/UnexpectedContentType.html Signed-off-by: Lukas Fleischer --- web/html/rss.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/html/rss.php b/web/html/rss.php index d6e7825a..245a2171 100644 --- a/web/html/rss.php +++ b/web/html/rss.php @@ -11,6 +11,8 @@ $host = $_SERVER['HTTP_HOST']; $feed_key = 'pkg-feed-' . $protocol; +header("Content-Type: application/rss+xml"); + $bool = false; $ret = get_cache_value($feed_key, $bool); if ($bool) { From 1d0c6ffe24c692d4279ce6ad6cb03aeb38a2303e Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Thu, 19 Nov 2020 23:18:33 +0100 Subject: [PATCH 0583/1891] RSS: Make sure image title matches channel title https://validator.w3.org/feed/docs/warning/ImageTitleDoesntMatch.html Signed-off-by: Lukas Fleischer --- web/html/rss.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/rss.php b/web/html/rss.php index 245a2171..5720d3d1 100644 --- a/web/html/rss.php +++ b/web/html/rss.php @@ -33,7 +33,7 @@ $rss->description = "The latest and greatest packages in the AUR"; $rss->link = "${protocol}://{$host}"; $rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); $image = new FeedImage(); -$image->title = "AUR"; +$image->title = "AUR Newest Packages"; $image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; $image->link = $rss->link; $image->description = "AUR Newest Packages Feed"; From eb11943fed16462e089891b128fd01f9e460b114 Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Thu, 19 Nov 2020 23:22:11 +0100 Subject: [PATCH 0584/1891] RSS: Always provide a GUID https://validator.w3.org/feed/docs/warning/MissingGuid.html Signed-off-by: Lukas Fleischer --- web/html/rss.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/html/rss.php b/web/html/rss.php index 5720d3d1..b67f862d 100644 --- a/web/html/rss.php +++ b/web/html/rss.php @@ -50,6 +50,7 @@ foreach ($packages as $indx => $row) { $item->date = intval($row["SubmittedTS"]); $item->source = "{$protocol}://{$host}"; $item->author = username_from_id($row["MaintainerUID"]); + $item->guid = $item->link; $rss->addItem($item); } From d5d333005eafb338fc5aefff9d4426cc23dbd84c Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Thu, 19 Nov 2020 23:27:21 +0100 Subject: [PATCH 0585/1891] RSS: Decrease cache time and increase item count I think after 10-15 years we might want to adjust those values. With a 30min cache and 20 items per creation I would bet some new AUR packages might be swept under the carpet. Signed-off-by: Lukas Fleischer --- web/html/rss.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/html/rss.php b/web/html/rss.php index b67f862d..1e6335cf 100644 --- a/web/html/rss.php +++ b/web/html/rss.php @@ -40,7 +40,7 @@ $image->description = "AUR Newest Packages Feed"; $rss->image = $image; #Get the latest packages and add items for them -$packages = latest_pkgs(20); +$packages = latest_pkgs(100); foreach ($packages as $indx => $row) { $item = new FeedItem(); @@ -56,6 +56,6 @@ foreach ($packages as $indx => $row) { #save it so that useCached() can find it $feedContent = $rss->createFeed(); -set_cache_value($feed_key, $feedContent, 1800); +set_cache_value($feed_key, $feedContent, 600); echo $feedContent; ?> From 62b413f6b76fd852abf728897f9929c4bf7024ea Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Sun, 27 Dec 2020 19:38:48 -0500 Subject: [PATCH 0586/1891] .gitignore: add test/trash directory* Signed-off-by: Lukas Fleischer --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7c9fa60b..4d961d13 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ aur.git/ __pycache__/ *.py[cod] test/test-results/ +test/trash directory* schema/aur-schema-sqlite.sql From 933d2705f935011035ee661e4a7acac37cd7aca3 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 28 Dec 2020 13:03:24 -0500 Subject: [PATCH 0587/1891] Fetch Transifex image from https://www.transifex.com Fixes GitLab issue #3. Signed-off-by: Lukas Fleischer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7285a51..77f3b13d 100644 --- a/README.md +++ b/README.md @@ -45,4 +45,4 @@ Translations Translations are welcome via our Transifex project at https://www.transifex.com/lfleischer/aurweb; see `doc/i18n.txt` for details. -![Transifex](http://www.transifex.net/projects/p/aurweb/chart/image_png) +![Transifex](https://www.transifex.com/projects/p/aurweb/chart/image_png) From 21c457817fe8ec5db60a10e2270f9fcf951aca5f Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Sat, 23 Jan 2021 00:43:57 +0800 Subject: [PATCH 0588/1891] Use jsDelivr instead of Google CDN for jquery jsdelivr is another free CDN service for open source projects. The main motivation for this change is that it is the only one that works fairly well across the globe. The Google CDN service is known to be hardly accessible in mainland China, unfortunately. Signed-off-by: Lukas Fleischer --- web/html/home.php | 2 +- web/html/packages.php | 2 +- web/html/pkgmerge.php | 2 +- web/template/pkgreq_form.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/html/home.php b/web/html/home.php index 0ce89f40..8fb05246 100644 --- a/web/html/home.php +++ b/web/html/home.php @@ -202,7 +202,7 @@ if (isset($_COOKIE["AURSID"])) {
    - + + + + ", ""); EOD - "$RENDERCOMMENT" 3 && + cover "$RENDERCOMMENT" 3 && cat <<-EOD >expected && <script>alert("XSS!");</script> EOD @@ -61,7 +61,7 @@ test_expect_success 'Test link conversion.' ' [arch]: https://www.archlinux.org/ ", ""); EOD - "$RENDERCOMMENT" 4 && + cover "$RENDERCOMMENT" 4 && cat <<-EOD >expected &&

    Visit https://www.archlinux.org/#_test_. Visit https://www.archlinux.org/. @@ -89,7 +89,7 @@ test_expect_success 'Test Git commit linkification.' ' http://example.com/$oid ", ""); EOD - "$RENDERCOMMENT" 5 && + cover "$RENDERCOMMENT" 5 && cat <<-EOD >expected &&

    ${oid:0:12} ${oid:0:7} @@ -116,7 +116,7 @@ test_expect_success 'Test Flyspray issue linkification.' ' https://archlinux.org/?test=FS#1234 ", ""); EOD - "$RENDERCOMMENT" 6 && + cover "$RENDERCOMMENT" 6 && cat <<-EOD >expected &&

    FS#1234567. FS#1234 @@ -142,7 +142,7 @@ test_expect_success 'Test headings lowering.' ' ###### Six ", ""); EOD - "$RENDERCOMMENT" 7 && + cover "$RENDERCOMMENT" 7 && cat <<-EOD >expected &&

    One
    Two
    diff --git a/test/t2700-usermaint.t b/test/t2700-usermaint.t index f0bb449b..c119e3f4 100755 --- a/test/t2700-usermaint.t +++ b/test/t2700-usermaint.t @@ -16,7 +16,7 @@ test_expect_success 'Test removal of login IP addresses.' ' UPDATE Users SET LastLogin = 0, LastLoginIPAddress = "5.6.7.8" WHERE ID = 5; UPDATE Users SET LastLogin = $tendaysago, LastLoginIPAddress = "6.7.8.9" WHERE ID = 6; EOD - "$USERMAINT" && + cover "$USERMAINT" && cat <<-EOD >expected && 1.2.3.4 3.4.5.6 @@ -37,7 +37,7 @@ test_expect_success 'Test removal of SSH login IP addresses.' ' UPDATE Users SET LastSSHLogin = 0, LastSSHLoginIPAddress = "5.6.7.8" WHERE ID = 5; UPDATE Users SET LastSSHLogin = $tendaysago, LastSSHLoginIPAddress = "6.7.8.9" WHERE ID = 6; EOD - "$USERMAINT" && + cover "$USERMAINT" && cat <<-EOD >expected && 1.2.3.4 2.3.4.5 From 4b7609681deb8ce6627919b4c43f879601c49d30 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Dec 2020 18:26:32 -0800 Subject: [PATCH 0604/1891] add test_exceptions.py This helps gain coverage over aurweb.exceptions regardless of their actual use in the testing base. Signed-off-by: Kevin Morris --- test/test_exceptions.py | 102 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 test/test_exceptions.py diff --git a/test/test_exceptions.py b/test/test_exceptions.py new file mode 100644 index 00000000..feac2656 --- /dev/null +++ b/test/test_exceptions.py @@ -0,0 +1,102 @@ +from aurweb.exceptions import (AlreadyVotedException, AurwebException, BannedException, BrokenUpdateHookException, + InvalidArgumentsException, InvalidCommentException, InvalidPackageBaseException, + InvalidReasonException, InvalidRepositoryNameException, InvalidUserException, + MaintenanceException, NotVotedException, PackageBaseExistsException, PermissionDeniedException) + + +def test_aurweb_exception(): + try: + raise AurwebException("test") + except AurwebException as exc: + assert str(exc) == "test" + + +def test_maintenance_exception(): + try: + raise MaintenanceException("test") + except MaintenanceException as exc: + assert str(exc) == "test" + + +def test_banned_exception(): + try: + raise BannedException("test") + except BannedException as exc: + assert str(exc) == "test" + + +def test_already_voted_exception(): + try: + raise AlreadyVotedException("test") + except AlreadyVotedException as exc: + assert str(exc) == "already voted for package base: test" + + +def test_broken_update_hook_exception(): + try: + raise BrokenUpdateHookException("test") + except BrokenUpdateHookException as exc: + assert str(exc) == "broken update hook: test" + + +def test_invalid_arguments_exception(): + try: + raise InvalidArgumentsException("test") + except InvalidArgumentsException as exc: + assert str(exc) == "test" + + +def test_invalid_packagebase_exception(): + try: + raise InvalidPackageBaseException("test") + except InvalidPackageBaseException as exc: + assert str(exc) == "package base not found: test" + + +def test_invalid_comment_exception(): + try: + raise InvalidCommentException("test") + except InvalidCommentException as exc: + assert str(exc) == "comment is too short: test" + + +def test_invalid_reason_exception(): + try: + raise InvalidReasonException("test") + except InvalidReasonException as exc: + assert str(exc) == "invalid reason: test" + + +def test_invalid_user_exception(): + try: + raise InvalidUserException("test") + except InvalidUserException as exc: + assert str(exc) == "unknown user: test" + + +def test_not_voted_exception(): + try: + raise NotVotedException("test") + except NotVotedException as exc: + assert str(exc) == "missing vote for package base: test" + + +def test_packagebase_exists_exception(): + try: + raise PackageBaseExistsException("test") + except PackageBaseExistsException as exc: + assert str(exc) == "package base already exists: test" + + +def test_permission_denied_exception(): + try: + raise PermissionDeniedException("test") + except PermissionDeniedException as exc: + assert str(exc) == "permission denied: test" + + +def test_repository_name_exception(): + try: + raise InvalidRepositoryNameException("test") + except InvalidRepositoryNameException as exc: + assert str(exc) == "invalid repository name: test" From 6d08789ac1f759b66006ab2ec225513863308f91 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 31 Dec 2020 22:00:15 -0800 Subject: [PATCH 0605/1891] add test_popupdate.py We had no coverage over aurweb.scripts.popupdate. This test covers all of its functionality. Signed-off-by: Kevin Morris --- aurweb/db.py | 3 +++ aurweb/scripts/popupdate.py | 1 - test/test_popupdate.py | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test/test_popupdate.py diff --git a/aurweb/db.py b/aurweb/db.py index 8ca32165..04b40f43 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,3 +1,5 @@ +import math + try: import mysql.connector except ImportError: @@ -95,6 +97,7 @@ class Connection: elif aur_db_backend == 'sqlite': aur_db_name = aurweb.config.get('database', 'name') self._conn = sqlite3.connect(aur_db_name) + self._conn.create_function("POWER", 2, math.pow) self._paramstyle = sqlite3.paramstyle else: raise ValueError('unsupported database backend') diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index b64deedb..b1e70403 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -7,7 +7,6 @@ import aurweb.db def main(): conn = aurweb.db.Connection() - conn.execute("UPDATE PackageBases SET NumVotes = (" + "SELECT COUNT(*) FROM PackageVotes " + "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") diff --git a/test/test_popupdate.py b/test/test_popupdate.py new file mode 100644 index 00000000..93f86f10 --- /dev/null +++ b/test/test_popupdate.py @@ -0,0 +1,5 @@ +from aurweb.scripts import popupdate + + +def test_popupdate(): + popupdate.main() From 57c11ae13fea0276359cf552ab59455fe2c579a3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 20 Jan 2021 14:08:39 -0800 Subject: [PATCH 0606/1891] install aurweb package & init db on GitLab CI Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 71c14457..6db573d2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,5 +18,8 @@ before_script: test: script: + - python setup.py install + - sed -r "s;YOUR_AUR_ROOT;$(pwd);g" conf/config.dev > conf/config + - AUR_CONFIG=conf/config python -m aurweb.initdb - make -C test - coverage report --include='aurweb/*' From 52ab056e1876fa68c70d3ff1b1d63ea9f74d6e31 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 21 Dec 2020 22:33:46 -0800 Subject: [PATCH 0607/1891] update documentation for FastAPI tests and deps. Additionally, we now ask for two more favors from contributors: 1. All source modified or added within a patchset **must** maintain equivalent or increased coverage by providing tests that use the functionality. 2. Please keep your source within an 80 column width. PS: Sneak a few test Makefile and gitlab fixes. Signed-off-by: Kevin Morris --- CONTRIBUTING.md | 9 +++++++++ INSTALL | 4 ++-- README.md | 9 ++++++++- test/README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b9ff466..1d57d742 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,3 +8,12 @@ You can add a git hook to do this by installing `python-pre-commit` and running `pre-commit install`. [1] https://lists.archlinux.org/listinfo/aur-dev + +### Coding Guidelines + +1. All source modified or added within a patchset **must** maintain equivalent + or increased coverage by providing tests that use the functionality. + +2. Please keep your source within an 80 column width. + +Test patches that increase coverage in the codebase are always welcome. diff --git a/INSTALL b/INSTALL index a32d6f5a..8607b07f 100644 --- a/INSTALL +++ b/INSTALL @@ -48,8 +48,8 @@ read the instructions below. 4) Install Python modules and dependencies: # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy \ - python-bleach python-markdown python-alembic python-jinja \ - python-itsdangerous python-authlib python-httpx hypercorn + python-bleach python-markdown python-alembic hypercorn \ + python-itsdangerous python-authlib python-httpx # python3 setup.py install 5) Create a new MySQL database and a user and import the aurweb SQL schema: diff --git a/README.md b/README.md index 77f3b13d..7521b4d9 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,14 @@ Directory Layout * `aurweb`: aurweb Python modules, Git interface and maintenance scripts * `conf`: configuration and configuration templates +* `static`: static resource files +* `templates`: jinja2 template collection * `doc`: project documentation * `po`: translation files for strings in the aurweb interface * `schema`: schema for the SQL database * `test`: test suite and test cases * `upgrading`: instructions for upgrading setups from one release to another -* `web`: web interface for the AUR +* `web`: PHP-based web interface for the AUR Links ----- @@ -46,3 +48,8 @@ Translations are welcome via our Transifex project at https://www.transifex.com/lfleischer/aurweb; see `doc/i18n.txt` for details. ![Transifex](https://www.transifex.com/projects/p/aurweb/chart/image_png) + +Testing +------- + +See [test/README.md](test/README.md) for details on dependencies and testing. diff --git a/test/README.md b/test/README.md index de7eff18..3261899b 100644 --- a/test/README.md +++ b/test/README.md @@ -1,10 +1,11 @@ Running tests ------------- -To run all the tests, you may run `make check` under `test/`. +To run all tests, you may run `make check` under `test/` (alternative targets: +`make pytest`, `make sh`). -For more control, you may use the `prove` command, which receives a directory -or a list of files to run, and produces a report. +For more control, you may use the `prove` or `pytest` command, which receives a +directory or a list of files to run, and produces a report. Each test script is standalone, so you may run them individually. Some tests may receive command-line options to help debugging. See for example sharness's @@ -22,16 +23,60 @@ For all the test to run, the following Arch packages should be installed: - python-pygit2 - python-sqlalchemy - python-srcinfo +- python-coverage +- python-pytest +- python-pytest-cov +- python-pytest-asyncio + +Running tests +------------- + +Recommended method of running tests: `make check`. + +First, setup the test configuration: + + $ sed -r 's;YOUR_AUR_ROOT;$(pwd);g' conf/config.dev > conf/config + +With those installed, one can run Python tests manually with any AUR config +specified by `AUR_CONFIG`: + + $ AUR_CONFIG=conf/config coverage run --append /usr/bin/pytest test/ + +After tests are run (particularly, with `coverage run` included), one can +produce coverage reports. + + # Print out a CLI coverage report. + $ coverage report + # Produce an HTML-based coverage report. + $ coverage html + +When running `make -C test`, all tests ran will produce coverage data via +`coverage run --append`. After running `make -C test`, one can continue with +coverage reporting steps above. Running tests through `make` will test and +cover code ran by both aurweb scripts and our pytest collection. Writing tests ------------- -Test scripts must follow the Test Anything Protocol specification: +Shell test scripts must follow the Test Anything Protocol specification: http://testanything.org/tap-specification.html +Python tests must be compatible with `pytest` and included in `pytest test/` +execution after setting up a configuration. + Tests must support being run from any directory. They may use $0 to determine their location. Python scripts should expect aurweb to be installed and importable without toying with os.path or PYTHONPATH. Tests written in shell should use sharness. In general, new tests should be consistent with existing tests unless they have a good reason not to. + +Debugging tests +--------------- + +By default, `make -C test` is quiet and does not print out verbose information +about tests being run. If a test is failing, one can look into verbose details +of sharness tests by executing them with the `--verbose` flag. Example: +`./t1100_git_auth.t --verbose`. This is particularly useful when tests happen +to fail in a remote continuous integration environment, where the reader does +not have complete access to the runner. From cd3e880264339ffd73e507775b4fb7e9d740a24d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 23 Dec 2020 16:11:40 -0800 Subject: [PATCH 0608/1891] add Dockerfile This docker file downloads deps, sets up some things beforehand and finishes with running our entire collection of tests. Signed-off-by: Kevin Morris Signed-off-by: Lukas Fleischer --- Dockerfile | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..7e981340 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +FROM archlinux +COPY . /aurweb +WORKDIR /aurweb + +# Install dependencies. +RUN pacman -Syu --noconfirm base-devel git gpgme protobuf pyalpm \ + python-mysql-connector python-pygit2 python-srcinfo python-bleach \ + python-markdown python-sqlalchemy python-alembic python-pytest \ + python-werkzeug python-pytest-tap python-fastapi nginx python-authlib \ + python-itsdangerous python-httpx python-jinja python-pytest-cov \ + python-requests python-aiofiles python-python-multipart \ + python-pytest-asyncio python-coverage hypercorn + +# Remove aurweb.sqlite3 if it was copied over via COPY. +RUN rm -fv aurweb.sqlite3 + +# Setup our test config. +RUN sed -r "s;YOUR_AUR_ROOT;/aurweb;g" conf/config.dev > conf/config + +# Install translations. +RUN AUR_CONFIG=conf/config make -C po all install + +# Initialize the database. +RUN AUR_CONFIG=conf/config python -m aurweb.initdb + +# Test everything! +RUN make -C test + +# Produce a coverage report. +RUN coverage report --include='aurweb/*' From 21140e28a8d5aa6ccf7a3366ca0d5fe7de8d2364 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Wed, 7 Apr 2021 09:56:16 +0100 Subject: [PATCH 0609/1891] Filter out current username from co-maintainers list. Closes: #8 Signed-off-by: Leonidas Spyropoulos Signed-off-by: Eli Schwartz --- web/lib/pkgbasefuncs.inc.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 4a49898c..a053962e 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -1189,7 +1189,8 @@ function pkgbase_get_comaintainer_uids($base_ids) { * @return array Tuple of success/failure indicator and error message */ function pkgbase_set_comaintainers($base_id, $users, $override=false) { - if (!$override && !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) { + $maintainer_uid = pkgbase_maintainer_uid($base_id); + if (!$override && !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array($maintainer_uid))) { return array(false, __("You are not allowed to manage co-maintainers of this package base.")); } @@ -1207,9 +1208,12 @@ function pkgbase_set_comaintainers($base_id, $users, $override=false) { if (!$uid) { return array(false, __("Invalid user name: %s", $user)); + } elseif ($uid == $maintainer_uid) { + // silently ignore when maintainer == co-maintainer + continue; + } else { + $uids_new[] = $uid; } - - $uids_new[] = $uid; } $q = sprintf("SELECT UsersID FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id); From c1e29e90ca2a7e58faef573c975ddf47f108e048 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:17:17 -0700 Subject: [PATCH 0610/1891] aurweb: Globalize a Translator instance, add more utility + Added SUPPORTED_LANGUAGES, a global constant dictionary of language => display pairs for languages we support. + Add Translator.get_translator, a function used to retrieve a translator after initializing it (if needed). Use `fallback=True` while creating languages, in case we setup a language that we don't have a translation for, it will noop the translation. This is particularly useful for "en," since we do not translate it, but doing this will allow us to go through our normal translation flow in any case. + Added typing. + Added get_request_language, a function that grabs the language for a request session, defaulting to aurweb.config [options] default_lang. + Added get_raw_translator_for_request, a function that retrieves the concrete translation object for a given language. + Added tr, a jinja2 contextfilter that can be used to inline translate strings in jinja2 templates. + Added `python-jinja` dep to .gitlab-ci.yml. This needs to be included in documentation before this set is merged in. + Introduce pytest units (test_l10n.py) in `test` along with __init__.py, which marks `test` as a test package. + Additionally, fix up notify.py to use the global translator. Also reduce its source width to <= 80 by newlining some code. + Additionally, prepare locale in .gitlab-ci.yml and add aurweb.config [options] localedir to config.dev with YOUR_AUR_ROOT like others. Signed-off-by: Kevin Morris Signed-off-by: Lukas Fleischer --- .gitlab-ci.yml | 1 + aurweb/l10n.py | 79 +++++++++++-- aurweb/scripts/notify.py | 238 ++++++++++++++++++++------------------- conf/config.dev | 1 + test/__init__.py | 0 test/test_l10n.py | 44 ++++++++ 6 files changed, 240 insertions(+), 123 deletions(-) create mode 100644 test/__init__.py create mode 100644 test/test_l10n.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6db573d2..1e287748 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,6 +20,7 @@ test: script: - python setup.py install - sed -r "s;YOUR_AUR_ROOT;$(pwd);g" conf/config.dev > conf/config + - AUR_CONFIG=conf/config make -C po all install - AUR_CONFIG=conf/config python -m aurweb.initdb - make -C test - coverage report --include='aurweb/*' diff --git a/aurweb/l10n.py b/aurweb/l10n.py index a476ecd8..030ab274 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -1,24 +1,79 @@ import gettext +import typing + +from collections import OrderedDict + +from fastapi import Request +from jinja2 import contextfilter import aurweb.config +SUPPORTED_LANGUAGES = OrderedDict({ + "ar": "العربية", + "ast": "Asturianu", + "ca": "Català", + "cs": "Český", + "da": "Dansk", + "de": "Deutsch", + "el": "Ελληνικά", + "en": "English", + "es": "Español", + "es_419": "Español (Latinoamérica)", + "fi": "Suomi", + "fr": "Français", + "he": "עברית", + "hr": "Hrvatski", + "hu": "Magyar", + "it": "Italiano", + "ja": "日本語", + "nb": "Norsk", + "nl": "Nederlands", + "pl": "Polski", + "pt_BR": "Português (Brasil)", + "pt_PT": "Português (Portugal)", + "ro": "Română", + "ru": "Русский", + "sk": "Slovenčina", + "sr": "Srpski", + "tr": "Türkçe", + "uk": "Українська", + "zh_CN": "简体中文", + "zh_TW": "正體中文" +}) + class Translator: def __init__(self): self._localedir = aurweb.config.get('options', 'localedir') self._translator = {} - def translate(self, s, lang): - if lang == 'en': - return s + def get_translator(self, lang: str): if lang not in self._translator: self._translator[lang] = gettext.translation("aurweb", self._localedir, - languages=[lang]) - return self._translator[lang].gettext(s) + languages=[lang], + fallback=True) + return self._translator.get(lang) + + def translate(self, s: str, lang: str): + return self.get_translator(lang).gettext(s) -def get_translator_for_request(request): +# Global translator object. +translator = Translator() + + +def get_request_language(request: Request): + return request.cookies.get("AURLANG", + aurweb.config.get("options", "default_lang")) + + +def get_raw_translator_for_request(request: Request): + lang = get_request_language(request) + return translator.get_translator(lang) + + +def get_translator_for_request(request: Request): """ Determine the preferred language from a FastAPI request object and build a translator function for it. @@ -29,12 +84,16 @@ def get_translator_for_request(request): print(_("Hello")) ``` """ - lang = request.cookies.get("AURLANG") - if lang is None: - lang = aurweb.config.get("options", "default_lang") - translator = Translator() + lang = get_request_language(request) def translate(message): return translator.translate(message, lang) return translate + + +@contextfilter +def tr(context: typing.Any, value: str): + """ A translation filter; example: {{ "Hello" | tr("de") }}. """ + _ = get_translator_for_request(context.get("request")) + return _(value) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 7f8e7168..1df0175a 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -40,9 +40,6 @@ def pkgbase_from_pkgreq(conn, reqid): class Notification: - def __init__(self): - self._l10n = aurweb.l10n.Translator() - def get_refs(self): return () @@ -97,9 +94,12 @@ class Notification: else: # send email using smtplib; no local MTA required server_addr = aurweb.config.get('notifications', 'smtp-server') - server_port = aurweb.config.getint('notifications', 'smtp-port') - use_ssl = aurweb.config.getboolean('notifications', 'smtp-use-ssl') - use_starttls = aurweb.config.getboolean('notifications', 'smtp-use-starttls') + server_port = aurweb.config.getint('notifications', + 'smtp-port') + use_ssl = aurweb.config.getboolean('notifications', + 'smtp-use-ssl') + use_starttls = aurweb.config.getboolean('notifications', + 'smtp-use-starttls') user = aurweb.config.get('notifications', 'smtp-user') passwd = aurweb.config.get('notifications', 'smtp-password') @@ -127,7 +127,8 @@ class ResetKeyNotification(Notification): cur = conn.execute('SELECT UserName, Email, BackupEmail, ' + 'LangPreference, ResetKey ' + 'FROM Users WHERE ID = ? AND Suspended = 0', [uid]) - self._username, self._to, self._backup, self._lang, self._resetkey = cur.fetchone() + self._username, self._to, self._backup, self._lang, self._resetkey = \ + cur.fetchone() super().__init__() def get_recipients(self): @@ -137,15 +138,15 @@ class ResetKeyNotification(Notification): return [(self._to, self._lang)] def get_subject(self, lang): - return self._l10n.translate('AUR Password Reset', lang) + return aurweb.l10n.translator.translate('AUR Password Reset', lang) def get_body(self, lang): - return self._l10n.translate( - 'A password reset request was submitted for the account ' - '{user} associated with your email address. If you wish to ' - 'reset your password follow the link [1] below, otherwise ' - 'ignore this message and nothing will happen.', - lang).format(user=self._username) + return aurweb.l10n.translator.translate( + 'A password reset request was submitted for the account ' + '{user} associated with your email address. If you wish to ' + 'reset your password follow the link [1] below, otherwise ' + 'ignore this message and nothing will happen.', + lang).format(user=self._username) def get_refs(self): return (aur_location + '/passreset/?resetkey=' + self._resetkey,) @@ -153,15 +154,16 @@ class ResetKeyNotification(Notification): class WelcomeNotification(ResetKeyNotification): def get_subject(self, lang): - return self._l10n.translate('Welcome to the Arch User Repository', - lang) + return aurweb.l10n.translator.translate( + 'Welcome to the Arch User Repository', + lang) def get_body(self, lang): - return self._l10n.translate( - 'Welcome to the Arch User Repository! In order to set an ' - 'initial password for your new account, please click the ' - 'link [1] below. If the link does not work, try copying and ' - 'pasting it into your browser.', lang) + return aurweb.l10n.translator.translate( + 'Welcome to the Arch User Repository! In order to set an ' + 'initial password for your new account, please click the ' + 'link [1] below. If the link does not work, try copying and ' + 'pasting it into your browser.', lang) class CommentNotification(Notification): @@ -186,19 +188,21 @@ class CommentNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Comment for {pkgbase}', - lang).format(pkgbase=self._pkgbase) + return aurweb.l10n.translator.translate( + 'AUR Comment for {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_body(self, lang): - body = self._l10n.translate( - '{user} [1] added the following comment to {pkgbase} [2]:', - lang).format(user=self._user, pkgbase=self._pkgbase) + body = aurweb.l10n.translator.translate( + '{user} [1] added the following comment to {pkgbase} [2]:', + lang).format(user=self._user, pkgbase=self._pkgbase) body += '\n\n' + self._text + '\n\n-- \n' - dnlabel = self._l10n.translate('Disable notifications', lang) - body += self._l10n.translate( - 'If you no longer wish to receive notifications about this ' - 'package, please go to the package page [2] and select ' - '"{label}".', lang).format(label=dnlabel) + dnlabel = aurweb.l10n.translator.translate( + 'Disable notifications', lang) + body += aurweb.l10n.translator.translate( + 'If you no longer wish to receive notifications about this ' + 'package, please go to the package page [2] and select ' + '"{label}".', lang).format(label=dnlabel) return body def get_refs(self): @@ -231,20 +235,21 @@ class UpdateNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Package Update: {pkgbase}', - lang).format(pkgbase=self._pkgbase) + return aurweb.l10n.translator.translate( + 'AUR Package Update: {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_body(self, lang): - body = self._l10n.translate('{user} [1] pushed a new commit to ' - '{pkgbase} [2].', lang).format( - user=self._user, - pkgbase=self._pkgbase) + body = aurweb.l10n.translator.translate( + '{user} [1] pushed a new commit to {pkgbase} [2].', + lang).format(user=self._user, pkgbase=self._pkgbase) body += '\n\n-- \n' - dnlabel = self._l10n.translate('Disable notifications', lang) - body += self._l10n.translate( - 'If you no longer wish to receive notifications about this ' - 'package, please go to the package page [2] and select ' - '"{label}".', lang).format(label=dnlabel) + dnlabel = aurweb.l10n.translator.translate( + 'Disable notifications', lang) + body += aurweb.l10n.translator.translate( + 'If you no longer wish to receive notifications about this ' + 'package, please go to the package page [2] and select ' + '"{label}".', lang).format(label=dnlabel) return body def get_refs(self): @@ -261,15 +266,16 @@ class FlagNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email, ' + - 'Users.LangPreference FROM Users ' + - 'LEFT JOIN PackageComaintainers ' + - 'ON PackageComaintainers.UsersID = Users.ID ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.MaintainerUID = Users.ID OR ' + - 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + - 'WHERE PackageBases.ID = ? AND ' + - 'Users.Suspended = 0', [pkgbase_id]) + cur = conn.execute( + 'SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + + 'LEFT JOIN PackageComaintainers ' + + 'ON PackageComaintainers.UsersID = Users.ID ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.MaintainerUID = Users.ID OR ' + + 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + + 'WHERE PackageBases.ID = ? AND ' + + 'Users.Suspended = 0', [pkgbase_id]) self._recipients = cur.fetchall() cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + 'ID = ?', [pkgbase_id]) @@ -280,15 +286,15 @@ class FlagNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Out-of-date Notification for ' - '{pkgbase}', - lang).format(pkgbase=self._pkgbase) + return aurweb.l10n.translator.translate( + 'AUR Out-of-date Notification for {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_body(self, lang): - body = self._l10n.translate( - 'Your package {pkgbase} [1] has been flagged out-of-date by ' - '{user} [2]:', lang).format(pkgbase=self._pkgbase, - user=self._user) + body = aurweb.l10n.translator.translate( + 'Your package {pkgbase} [1] has been flagged out-of-date by ' + '{user} [2]:', lang).format(pkgbase=self._pkgbase, + user=self._user) body += '\n\n' + self._text return body @@ -320,8 +326,9 @@ class OwnershipEventNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Ownership Notification for {pkgbase}', - lang).format(pkgbase=self._pkgbase) + return aurweb.l10n.translator.translate( + 'AUR Ownership Notification for {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/', @@ -330,17 +337,17 @@ class OwnershipEventNotification(Notification): class AdoptNotification(OwnershipEventNotification): def get_body(self, lang): - return self._l10n.translate( - 'The package {pkgbase} [1] was adopted by {user} [2].', - lang).format(pkgbase=self._pkgbase, user=self._user) + return aurweb.l10n.translator.translate( + 'The package {pkgbase} [1] was adopted by {user} [2].', + lang).format(pkgbase=self._pkgbase, user=self._user) class DisownNotification(OwnershipEventNotification): def get_body(self, lang): - return self._l10n.translate( - 'The package {pkgbase} [1] was disowned by {user} ' - '[2].', lang).format(pkgbase=self._pkgbase, - user=self._user) + return aurweb.l10n.translator.translate( + 'The package {pkgbase} [1] was disowned by {user} ' + '[2].', lang).format(pkgbase=self._pkgbase, + user=self._user) class ComaintainershipEventNotification(Notification): @@ -355,9 +362,9 @@ class ComaintainershipEventNotification(Notification): return [(self._to, self._lang)] def get_subject(self, lang): - return self._l10n.translate('AUR Co-Maintainer Notification for ' - '{pkgbase}', - lang).format(pkgbase=self._pkgbase) + return aurweb.l10n.translator.translate( + 'AUR Co-Maintainer Notification for {pkgbase}', + lang).format(pkgbase=self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/',) @@ -365,16 +372,16 @@ class ComaintainershipEventNotification(Notification): class ComaintainerAddNotification(ComaintainershipEventNotification): def get_body(self, lang): - return self._l10n.translate( - 'You were added to the co-maintainer list of {pkgbase} [1].', - lang).format(pkgbase=self._pkgbase) + return aurweb.l10n.translator.translate( + 'You were added to the co-maintainer list of {pkgbase} [1].', + lang).format(pkgbase=self._pkgbase) class ComaintainerRemoveNotification(ComaintainershipEventNotification): def get_body(self, lang): - return self._l10n.translate( - 'You were removed from the co-maintainer list of {pkgbase} ' - '[1].', lang).format(pkgbase=self._pkgbase) + return aurweb.l10n.translator.translate( + 'You were removed from the co-maintainer list of {pkgbase} ' + '[1].', lang).format(pkgbase=self._pkgbase) class DeleteNotification(Notification): @@ -400,25 +407,27 @@ class DeleteNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('AUR Package deleted: {pkgbase}', - lang).format(pkgbase=self._old_pkgbase) + return aurweb.l10n.translator.translate( + 'AUR Package deleted: {pkgbase}', + lang).format(pkgbase=self._old_pkgbase) def get_body(self, lang): if self._new_pkgbase: - dnlabel = self._l10n.translate('Disable notifications', lang) - return self._l10n.translate( - '{user} [1] merged {old} [2] into {new} [3].\n\n' - '-- \n' - 'If you no longer wish receive notifications about the ' - 'new package, please go to [3] and click "{label}".', - lang).format(user=self._user, old=self._old_pkgbase, - new=self._new_pkgbase, label=dnlabel) + dnlabel = aurweb.l10n.translator.translate( + 'Disable notifications', lang) + return aurweb.l10n.translator.translate( + '{user} [1] merged {old} [2] into {new} [3].\n\n' + '-- \n' + 'If you no longer wish receive notifications about the ' + 'new package, please go to [3] and click "{label}".', + lang).format(user=self._user, old=self._old_pkgbase, + new=self._new_pkgbase, label=dnlabel) else: - return self._l10n.translate( - '{user} [1] deleted {pkgbase} [2].\n\n' - 'You will no longer receive notifications about this ' - 'package.', lang).format(user=self._user, - pkgbase=self._old_pkgbase) + return aurweb.l10n.translator.translate( + '{user} [1] deleted {pkgbase} [2].\n\n' + 'You will no longer receive notifications about this ' + 'package.', lang).format(user=self._user, + pkgbase=self._old_pkgbase) def get_refs(self): refs = (aur_location + '/account/' + self._user + '/', @@ -432,14 +441,15 @@ class RequestOpenNotification(Notification): def __init__(self, conn, uid, reqid, reqtype, pkgbase_id, merge_into=None): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + - 'INNER JOIN Users ' + - 'ON Users.ID = PackageRequests.UsersID ' + - 'OR Users.ID = PackageBases.MaintainerUID ' + - 'WHERE PackageRequests.ID = ? AND ' + - 'Users.Suspended = 0', [reqid]) + cur = conn.execute( + 'SELECT DISTINCT Users.Email FROM PackageRequests ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + + 'INNER JOIN Users ' + + 'ON Users.ID = PackageRequests.UsersID ' + + 'OR Users.ID = PackageBases.MaintainerUID ' + + 'WHERE PackageRequests.ID = ? AND ' + + 'Users.Suspended = 0', [reqid]) self._to = aurweb.config.get('options', 'aur_request_ml') self._cc = [row[0] for row in cur.fetchall()] cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?', @@ -489,14 +499,15 @@ class RequestOpenNotification(Notification): class RequestCloseNotification(Notification): def __init__(self, conn, uid, reqid, reason): self._user = username_from_id(conn, uid) if int(uid) else None - cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + - 'INNER JOIN Users ' + - 'ON Users.ID = PackageRequests.UsersID ' + - 'OR Users.ID = PackageBases.MaintainerUID ' + - 'WHERE PackageRequests.ID = ? AND ' + - 'Users.Suspended = 0', [reqid]) + cur = conn.execute( + 'SELECT DISTINCT Users.Email FROM PackageRequests ' + + 'INNER JOIN PackageBases ' + + 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + + 'INNER JOIN Users ' + + 'ON Users.ID = PackageRequests.UsersID ' + + 'OR Users.ID = PackageBases.MaintainerUID ' + + 'WHERE PackageRequests.ID = ? AND ' + + 'Users.Suspended = 0', [reqid]) self._to = aurweb.config.get('options', 'aur_request_ml') self._cc = [row[0] for row in cur.fetchall()] cur = conn.execute('SELECT PackageRequests.ClosureComment, ' + @@ -563,14 +574,15 @@ class TUVoteReminderNotification(Notification): return self._recipients def get_subject(self, lang): - return self._l10n.translate('TU Vote Reminder: Proposal {id}', - lang).format(id=self._vote_id) + return aurweb.l10n.translator.translate( + 'TU Vote Reminder: Proposal {id}', + lang).format(id=self._vote_id) def get_body(self, lang): - return self._l10n.translate( - 'Please remember to cast your vote on proposal {id} [1]. ' - 'The voting period ends in less than 48 hours.', - lang).format(id=self._vote_id) + return aurweb.l10n.translator.translate( + 'Please remember to cast your vote on proposal {id} [1]. ' + 'The voting period ends in less than 48 hours.', + lang).format(id=self._vote_id) def get_refs(self): return (aur_location + '/tu/?id=' + str(self._vote_id),) diff --git a/conf/config.dev b/conf/config.dev index 37f38c45..ef7b5ed7 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -19,6 +19,7 @@ name = YOUR_AUR_ROOT/aurweb.sqlite3 aur_location = http://127.0.0.1:8080 disable_http_login = 0 enable-maintenance = 0 +localedir = YOUR_AUR_ROOT/web/locale ; Single sign-on; see doc/sso.txt. [sso] diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/test_l10n.py b/test/test_l10n.py new file mode 100644 index 00000000..1a1ef3e6 --- /dev/null +++ b/test/test_l10n.py @@ -0,0 +1,44 @@ +""" Test our l10n module. """ +from aurweb import l10n + + +class FakeRequest: + """ A fake Request doppleganger; use this to change request.cookies + easily and with no side-effects. """ + + def __init__(self, *args, **kwargs): + self.cookies = kwargs.pop("cookies", dict()) + + +def test_translator(): + """ Test creating l10n translation tools. """ + de_home = l10n.translator.translate("Home", "de") + assert de_home == "Startseite" + + +def test_get_request_language(): + """ First, tests default_lang, then tests a modified AURLANG cookie. """ + request = FakeRequest() + assert l10n.get_request_language(request) == "en" + + request.cookies["AURLANG"] = "de" + assert l10n.get_request_language(request) == "de" + + +def test_get_raw_translator_for_request(): + """ Make sure that get_raw_translator_for_request is giving us + the translator we expect. """ + request = FakeRequest(cookies={"AURLANG": "de"}) + + translator = l10n.get_raw_translator_for_request(request) + assert translator.gettext("Home") == \ + l10n.translator.translate("Home", "de") + + +def test_get_translator_for_request(): + """ Make sure that get_translator_for_request is giving us back + our expected translation function. """ + request = FakeRequest(cookies={"AURLANG": "de"}) + + translate = l10n.get_translator_for_request(request) + assert translate("Home") == "Startseite" From bda9256ab11101397977282236af6cbc6d664181 Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Fri, 7 May 2021 18:50:41 +0200 Subject: [PATCH 0611/1891] Add error color when package is orphaned Signed-off-by: Eli Schwartz From 1ff822bb1492497adb284f278e0e537ea9be00f3 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Tue, 11 May 2021 00:01:13 +0200 Subject: [PATCH 0612/1891] Use the clipboard API for copy paste The Document.execCommand API is deprecated and no longer recommended to be used. It's replacement is the much simpler navigator.clipboard API which is supported in all browsers except internet explorer. Signed-off-by: Eli Schwartz --- web/template/pkg_details.php | 10 +++------- web/template/pkgbase_details.php | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index c6bb32d8..047de9a7 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -308,14 +308,10 @@ endif; diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index a6857c4e..35ad217a 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -137,14 +137,10 @@ endif; From 2df90ce28087d02e7b1dbd0e8efd5d5f99407793 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:20:04 -0700 Subject: [PATCH 0613/1891] port over base HTML layout from PHP to FastAPI+Jinja2 + Mounted static files (at web/html) to /static. + Added AURWEB_VERSION to aurweb.config (this is used around HTML to refer back to aurweb's release on git.archlinux.org), so we need it easily accessible in the Python codebase. + Implemented basic Jinja2 partials to put together whole aurweb pages. This may be missing some things currently and is a WIP until this set is ready to be merged. + Added config [options] aurwebdir = YOUR_AUR_ROOT; this configuration option should specify the root directory of the aurweb project. It is used by various parts of the FastAPI codebase to target project directories. Added routes via aurweb.routers.html: * POST /language: Set your session language. * GET /favicon.ico: Redirect to /static/images/favicon.ico. * Some browsers always look for $ROOT/favicon.ico to get an icon for the page being loaded, regardless of a specified "shortcut icon" given in a directive. * GET /: Home page; WIP. * Updated aurweb.routers.html.language passes query parameters to its next redirection. When calling aurweb.templates.render_template, the context passed should be formed via the aurweb.templates.make_context. See aurweb.routers.html.index for an example of this. Signed-off-by: Kevin Morris --- .coveragerc | 1 + INSTALL | 4 +- aurweb/asgi.py | 23 ++++++++- aurweb/config.py | 5 ++ aurweb/routers/html.py | 50 +++++++++++++++++++ aurweb/templates.py | 57 +++++++++++++++++++++ conf/config.dev | 1 + templates/index.html | 4 ++ templates/partials/archdev-navbar.html | 8 +++ templates/partials/body.html | 10 ++++ templates/partials/footer.html | 5 ++ templates/partials/head.html | 16 ++++++ templates/partials/layout.html | 10 ++++ templates/partials/meta.html | 1 + templates/partials/navbar.html | 19 +++++++ templates/partials/set_lang.html | 28 +++++++++++ templates/partials/typeahead.html | 30 +++++++++++ test/test_routes.py | 69 ++++++++++++++++++++++++++ 18 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 aurweb/routers/html.py create mode 100644 aurweb/templates.py create mode 100644 templates/index.html create mode 100644 templates/partials/archdev-navbar.html create mode 100644 templates/partials/body.html create mode 100644 templates/partials/footer.html create mode 100644 templates/partials/head.html create mode 100644 templates/partials/layout.html create mode 100644 templates/partials/meta.html create mode 100644 templates/partials/navbar.html create mode 100644 templates/partials/set_lang.html create mode 100644 templates/partials/typeahead.html create mode 100644 test/test_routes.py diff --git a/.coveragerc b/.coveragerc index 144a9f5c..9dcfca18 100644 --- a/.coveragerc +++ b/.coveragerc @@ -3,5 +3,6 @@ disable_warnings = already-imported [report] include = aurweb/* +fail_under = 85 exclude_lines = if __name__ == .__main__.: diff --git a/INSTALL b/INSTALL index 8607b07f..e4c52480 100644 --- a/INSTALL +++ b/INSTALL @@ -49,7 +49,9 @@ read the instructions below. # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy \ python-bleach python-markdown python-alembic hypercorn \ - python-itsdangerous python-authlib python-httpx + python-itsdangerous python-authlib python-httpx \ + python-jinja python-aiofiles python-python-multipart \ + python-requests # python3 setup.py install 5) Create a new MySQL database and a user and import the aurweb SQL schema: diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 9293ed77..00d7c595 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -2,13 +2,26 @@ import http from fastapi import FastAPI, HTTPException from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles from starlette.middleware.sessions import SessionMiddleware import aurweb.config -from aurweb.routers import sso +from aurweb.routers import html, sso +routes = set() + +# Setup the FastAPI app. app = FastAPI() +app.mount("/static/css", + StaticFiles(directory="web/html/css"), + name="static_css") +app.mount("/static/js", + StaticFiles(directory="web/html/js"), + name="static_js") +app.mount("/static/images", + StaticFiles(directory="web/html/images"), + name="static_images") session_secret = aurweb.config.get("fastapi", "session_secret") if not session_secret: @@ -17,6 +30,14 @@ if not session_secret: app.add_middleware(SessionMiddleware, secret_key=session_secret) app.include_router(sso.router) +app.include_router(html.router) + +# NOTE: Always keep this dictionary updated with all routes +# that the application contains. We use this to check for +# parameter value verification. +routes = {route.path for route in app.routes} +routes.update({route.path for route in sso.router.routes}) +routes.update({route.path for route in html.router.routes}) @app.exception_handler(HTTPException) diff --git a/aurweb/config.py b/aurweb/config.py index 52ec461e..020c3b80 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -1,6 +1,11 @@ import configparser import os +# Publicly visible version of aurweb. This is used to display +# aurweb versioning in the footer and must be maintained. +# Todo: Make this dynamic/automated. +AURWEB_VERSION = "v5.0.0" + _parser = None diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py new file mode 100644 index 00000000..ae08c764 --- /dev/null +++ b/aurweb/routers/html.py @@ -0,0 +1,50 @@ +""" AURWeb's primary routing module. Define all routes via @app.app.{get,post} +decorators in some way; more complex routes should be defined in their +own modules and imported here. """ +from http import HTTPStatus +from urllib.parse import unquote + +from fastapi import APIRouter, Form, Request +from fastapi.responses import HTMLResponse, RedirectResponse + +from aurweb.templates import make_context, render_template + +router = APIRouter() + + +@router.get("/favicon.ico") +async def favicon(request: Request): + """ Some browsers attempt to find a website's favicon via root uri at + /favicon.ico, so provide a redirection here to our static icon. """ + return RedirectResponse("/static/images/favicon.ico") + + +@router.post("/language", response_class=RedirectResponse) +async def language(request: Request, + set_lang: str = Form(...), + next: str = Form(...), + q: str = Form(default=None)): + """ A POST route used to set a session's language. + + Return a 303 See Other redirect to {next}?next={next}. If we are + setting the language on any page, we want to preserve query + parameters across the redirect. + """ + from aurweb.asgi import routes + if unquote(next) not in routes: + return HTMLResponse( + b"Invalid 'next' parameter.", + status_code=400) + + query_string = "?" + q if q else str() + response = RedirectResponse(url=f"{next}{query_string}", + status_code=int(HTTPStatus.SEE_OTHER)) + response.set_cookie("AURLANG", set_lang) + return response + + +@router.get("/", response_class=HTMLResponse) +async def index(request: Request): + """ Homepage route. """ + context = make_context(request, "Home") + return render_template("index.html", context) diff --git a/aurweb/templates.py b/aurweb/templates.py new file mode 100644 index 00000000..c05dce79 --- /dev/null +++ b/aurweb/templates.py @@ -0,0 +1,57 @@ +import copy +import os + +from datetime import datetime +from http import HTTPStatus + +import jinja2 + +from fastapi import Request +from fastapi.responses import HTMLResponse + +import aurweb.config + +from aurweb import l10n + +# Prepare jinja2 objects. +loader = jinja2.FileSystemLoader(os.path.join( + aurweb.config.get("options", "aurwebdir"), "templates")) +env = jinja2.Environment(loader=loader, autoescape=True, + extensions=["jinja2.ext.i18n"]) + +# Add tr translation filter. +env.filters["tr"] = l10n.tr + + +def make_context(request: Request, title: str, next: str = None): + """ Create a context for a jinja2 TemplateResponse. """ + + return { + "request": request, + "language": l10n.get_request_language(request), + "languages": l10n.SUPPORTED_LANGUAGES, + "title": title, + # The 'now' context variable will not show proper datetimes + # until we've implemented timezone support here. + "now": datetime.now(), + "config": aurweb.config, + "next": next if next else request.url.path + } + + +def render_template(path: str, context: dict, status_code=int(HTTPStatus.OK)): + """ Render a Jinja2 multi-lingual template with some context. """ + + # Create a deep copy of our jinja2 environment. The environment in + # total by itself is 48 bytes large (according to sys.getsizeof). + # This is done so we can install gettext translations on the template + # environment being rendered without installing them into a global + # which is reused in this function. + templates = copy.copy(env) + + translator = l10n.get_raw_translator_for_request(context.get("request")) + templates.install_gettext_translations(translator) + + template = templates.get_template(path) + rendered = template.render(context) + return HTMLResponse(rendered, status_code=status_code) diff --git a/conf/config.dev b/conf/config.dev index ef7b5ed7..ccb01f4f 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -16,6 +16,7 @@ name = YOUR_AUR_ROOT/aurweb.sqlite3 ;password = aur [options] +aurwebdir = YOUR_AUR_ROOT aur_location = http://127.0.0.1:8080 disable_http_login = 0 enable-maintenance = 0 diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 00000000..27d3375d --- /dev/null +++ b/templates/index.html @@ -0,0 +1,4 @@ +{% extends 'partials/layout.html' %} + +{% block pageContent %} +{% endblock %} diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html new file mode 100644 index 00000000..55338bc4 --- /dev/null +++ b/templates/partials/archdev-navbar.html @@ -0,0 +1,8 @@ + diff --git a/templates/partials/body.html b/templates/partials/body.html new file mode 100644 index 00000000..ccae0fe3 --- /dev/null +++ b/templates/partials/body.html @@ -0,0 +1,10 @@ +
    + {% include 'partials/set_lang.html' %} + {% include 'partials/archdev-navbar.html' %} + + {% block pageContent %} + + {% endblock %} + + {% include 'partials/footer.html' %} +
    diff --git a/templates/partials/footer.html b/templates/partials/footer.html new file mode 100644 index 00000000..0ac4d089 --- /dev/null +++ b/templates/partials/footer.html @@ -0,0 +1,5 @@ + diff --git a/templates/partials/head.html b/templates/partials/head.html new file mode 100644 index 00000000..0351fd6e --- /dev/null +++ b/templates/partials/head.html @@ -0,0 +1,16 @@ + + {% include 'partials/meta.html' %} + + + + + + + + + + + + AUR ({{ language }}) - {{ title | tr }} + diff --git a/templates/partials/layout.html b/templates/partials/layout.html new file mode 100644 index 00000000..d30208a9 --- /dev/null +++ b/templates/partials/layout.html @@ -0,0 +1,10 @@ + + + {% include 'partials/head.html' %} + + + {% include 'partials/navbar.html' %} + {% extends 'partials/body.html' %} + {% include 'partials/typeahead.html' %} + + diff --git a/templates/partials/meta.html b/templates/partials/meta.html new file mode 100644 index 00000000..727100b9 --- /dev/null +++ b/templates/partials/meta.html @@ -0,0 +1 @@ + diff --git a/templates/partials/navbar.html b/templates/partials/navbar.html new file mode 100644 index 00000000..199b2067 --- /dev/null +++ b/templates/partials/navbar.html @@ -0,0 +1,19 @@ + diff --git a/templates/partials/set_lang.html b/templates/partials/set_lang.html new file mode 100644 index 00000000..e9590050 --- /dev/null +++ b/templates/partials/set_lang.html @@ -0,0 +1,28 @@ +
    +
    +
    +
    + + + + + + + + + +
    +
    + +
    diff --git a/templates/partials/typeahead.html b/templates/partials/typeahead.html new file mode 100644 index 00000000..d943dbc4 --- /dev/null +++ b/templates/partials/typeahead.html @@ -0,0 +1,30 @@ + + + diff --git a/test/test_routes.py b/test/test_routes.py new file mode 100644 index 00000000..46ba39f5 --- /dev/null +++ b/test/test_routes.py @@ -0,0 +1,69 @@ +import urllib.parse + +from http import HTTPStatus + +import pytest + +from fastapi.testclient import TestClient + +from aurweb.asgi import app +from aurweb.testing import setup_test_db + +client = TestClient(app) + + +@pytest.fixture +def setup(): + setup_test_db("Users", "Session") + + +def test_index(): + """ Test the index route at '/'. """ + # Use `with` to trigger FastAPI app events. + with client as req: + response = req.get("/") + assert response.status_code == int(HTTPStatus.OK) + + +def test_favicon(): + """ Test the favicon route at '/favicon.ico'. """ + response1 = client.get("/static/images/favicon.ico") + response2 = client.get("/favicon.ico") + assert response1.status_code == int(HTTPStatus.OK) + assert response1.content == response2.content + + +def test_language(): + """ Test the language post route at '/language'. """ + post_data = { + "set_lang": "de", + "next": "/" + } + with client as req: + response = req.post("/language", data=post_data) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_language_invalid_next(): + """ Test an invalid next route at '/language'. """ + post_data = { + "set_lang": "de", + "next": "/BLAHBLAHFAKE" + } + with client as req: + response = req.post("/language", data=post_data) + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + +def test_language_query_params(): + """ Test the language post route with query params. """ + next = urllib.parse.quote_plus("/") + post_data = { + "set_lang": "de", + "next": "/", + "q": f"next={next}" + } + q = post_data.get("q") + with client as req: + response = req.post("/language", data=post_data) + assert response.headers.get("location") == f"/?{q}" + assert response.status_code == int(HTTPStatus.SEE_OTHER) From 7c65604dad8d9c68bee59129b03af05d26db1582 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:20:19 -0700 Subject: [PATCH 0614/1891] move off env.py's active code to __name__ == "__main__" * Moved migrations/env.py's logging initialization and migration execution into a `__name__ == "__main__"` stanza so it doesn't immediately happen when imported by another module. Signed-off-by: Kevin Morris --- migrations/env.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/migrations/env.py b/migrations/env.py index c2ff58c1..23759123 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -11,10 +11,6 @@ import aurweb.schema # access to the values within the .ini file in use. config = context.config -# Interpret the config file for Python logging. -# This line sets up loggers basically. -logging.config.fileConfig(config.config_file_name) - # model MetaData for autogenerating migrations target_metadata = aurweb.schema.metadata @@ -68,7 +64,12 @@ def run_migrations_online(): context.run_migrations() -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() +if __name__ == "__main__": + # Interpret the config file for Python logging. + # This line sets up loggers basically. + logging.config.fileConfig(config.config_file_name) + + if context.is_offline_mode(): + run_migrations_offline() + else: + run_migrations_online() From 4238a9fc6855242121402b392581ba5b695e2f90 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:20:23 -0700 Subject: [PATCH 0615/1891] add aurweb.db.session + Added Session class and global session object to aurweb.db, these are sessions created by sqlalchemy ORM's sessionmaker and will allow us to use declarative/imperative models. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 36 +++++---- aurweb/config.py | 7 ++ aurweb/db.py | 33 ++++----- test/test_asgi.py | 29 ++++++++ test/test_config.py | 13 ++++ test/test_db.py | 174 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 260 insertions(+), 32 deletions(-) create mode 100644 test/test_asgi.py create mode 100644 test/test_config.py create mode 100644 test/test_db.py diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 00d7c595..b6e15582 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -7,30 +7,36 @@ from starlette.middleware.sessions import SessionMiddleware import aurweb.config +from aurweb.db import get_engine from aurweb.routers import html, sso routes = set() # Setup the FastAPI app. app = FastAPI() -app.mount("/static/css", - StaticFiles(directory="web/html/css"), - name="static_css") -app.mount("/static/js", - StaticFiles(directory="web/html/js"), - name="static_js") -app.mount("/static/images", - StaticFiles(directory="web/html/images"), - name="static_images") -session_secret = aurweb.config.get("fastapi", "session_secret") -if not session_secret: - raise Exception("[fastapi] session_secret must not be empty") -app.add_middleware(SessionMiddleware, secret_key=session_secret) +@app.on_event("startup") +async def app_startup(): + session_secret = aurweb.config.get("fastapi", "session_secret") + if not session_secret: + raise Exception("[fastapi] session_secret must not be empty") -app.include_router(sso.router) -app.include_router(html.router) + app.mount("/static/css", + StaticFiles(directory="web/html/css"), + name="static_css") + app.mount("/static/js", + StaticFiles(directory="web/html/js"), + name="static_js") + app.mount("/static/images", + StaticFiles(directory="web/html/images"), + name="static_images") + + app.add_middleware(SessionMiddleware, secret_key=session_secret) + app.include_router(sso.router) + app.include_router(html.router) + + get_engine() # NOTE: Always keep this dictionary updated with all routes # that the application contains. We use this to check for diff --git a/aurweb/config.py b/aurweb/config.py index 020c3b80..49a2765a 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -25,6 +25,13 @@ def _get_parser(): return _parser +def rehash(): + """ Globally rehash the configuration parser. """ + global _parser + _parser = None + _get_parser() + + def get(section, option): return _get_parser().get(section, option) diff --git a/aurweb/db.py b/aurweb/db.py index 04b40f43..7993dfdb 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,19 +1,15 @@ import math -try: - import mysql.connector -except ImportError: - pass - -try: - import sqlite3 -except ImportError: - pass - import aurweb.config engine = None # See get_engine +# ORM Session class. +Session = None + +# Global ORM Session object. +session = None + def get_sqlalchemy_url(): """ @@ -49,14 +45,15 @@ def get_engine(): `engine` global variable for the next calls. """ from sqlalchemy import create_engine - global engine + from sqlalchemy.orm import sessionmaker + + global engine, session, Session + if engine is None: - connect_args = dict() - if aurweb.config.get("database", "backend") == "sqlite": - # check_same_thread is for a SQLite technicality - # https://fastapi.tiangolo.com/tutorial/sql-databases/#note - connect_args["check_same_thread"] = False - engine = create_engine(get_sqlalchemy_url(), connect_args=connect_args) + engine = create_engine(get_sqlalchemy_url(), + # check_same_thread is for a SQLite technicality + # https://fastapi.tiangolo.com/tutorial/sql-databases/#note + connect_args={"check_same_thread": False}) Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = Session() @@ -82,6 +79,7 @@ class Connection: aur_db_backend = aurweb.config.get('database', 'backend') if aur_db_backend == 'mysql': + import mysql.connector aur_db_host = aurweb.config.get('database', 'host') aur_db_name = aurweb.config.get('database', 'name') aur_db_user = aurweb.config.get('database', 'user') @@ -95,6 +93,7 @@ class Connection: buffered=True) self._paramstyle = mysql.connector.paramstyle elif aur_db_backend == 'sqlite': + import sqlite3 aur_db_name = aurweb.config.get('database', 'name') self._conn = sqlite3.connect(aur_db_name) self._conn.create_function("POWER", 2, math.pow) diff --git a/test/test_asgi.py b/test/test_asgi.py new file mode 100644 index 00000000..79b34daf --- /dev/null +++ b/test/test_asgi.py @@ -0,0 +1,29 @@ +import http +import os + +from unittest import mock + +import pytest + +from fastapi import HTTPException + +import aurweb.asgi +import aurweb.config + + +@pytest.mark.asyncio +async def test_asgi_startup_exception(monkeypatch): + with mock.patch.dict(os.environ, {"AUR_CONFIG": "conf/config.defaults"}): + aurweb.config.rehash() + with pytest.raises(Exception): + await aurweb.asgi.app_startup() + aurweb.config.rehash() + + +@pytest.mark.asyncio +async def test_asgi_http_exception_handler(): + exc = HTTPException(status_code=422, detail="EXCEPTION!") + phrase = http.HTTPStatus(exc.status_code).phrase + response = await aurweb.asgi.http_exception_handler(None, exc) + assert response.body.decode() == \ + f"

    {exc.status_code} {phrase}

    {exc.detail}

    " diff --git a/test/test_config.py b/test/test_config.py new file mode 100644 index 00000000..4f10b60d --- /dev/null +++ b/test/test_config.py @@ -0,0 +1,13 @@ +from aurweb import config + + +def test_get(): + assert config.get("options", "disable_http_login") == "0" + + +def test_getboolean(): + assert not config.getboolean("options", "disable_http_login") + + +def test_getint(): + assert config.getint("options", "disable_http_login") == 0 diff --git a/test/test_db.py b/test/test_db.py new file mode 100644 index 00000000..0a134541 --- /dev/null +++ b/test/test_db.py @@ -0,0 +1,174 @@ +import os +import re +import sqlite3 +import tempfile + +from unittest import mock + +import mysql.connector +import pytest + +import aurweb.config + +from aurweb import db +from aurweb.testing import setup_test_db + + +class DBCursor: + """ A fake database cursor object used in tests. """ + items = [] + + def execute(self, *args, **kwargs): + self.items = list(args) + return self + + def fetchall(self): + return self.items + + +class DBConnection: + """ A fake database connection object used in tests. """ + @staticmethod + def cursor(): + return DBCursor() + + @staticmethod + def create_function(name, num_args, func): + pass + + +@pytest.fixture(autouse=True) +def setup_db(): + setup_test_db() + + +def test_sqlalchemy_sqlite_url(): + with mock.patch.dict(os.environ, {"AUR_CONFIG": "conf/config.dev"}): + aurweb.config.rehash() + assert db.get_sqlalchemy_url() + aurweb.config.rehash() + + +def test_sqlalchemy_mysql_url(): + with mock.patch.dict(os.environ, {"AUR_CONFIG": "conf/config.defaults"}): + aurweb.config.rehash() + assert db.get_sqlalchemy_url() + aurweb.config.rehash() + + +def make_temp_config(backend): + if not os.path.isdir("/tmp"): + os.mkdir("/tmp") + tmpdir = tempfile.mkdtemp() + tmp = os.path.join(tmpdir, "config.tmp") + with open("conf/config") as f: + config = re.sub(r'backend = sqlite', f'backend = {backend}', f.read()) + with open(tmp, "w") as o: + o.write(config) + return (tmpdir, tmp) + + +def test_sqlalchemy_unknown_backend(): + tmpdir, tmp = make_temp_config("blah") + + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() + with pytest.raises(ValueError): + db.get_sqlalchemy_url() + aurweb.config.rehash() + + os.remove(tmp) + os.removedirs(tmpdir) + + +def test_db_connects_without_fail(): + db.connect() + assert db.engine is not None + + +def test_connection_class_without_fail(): + conn = db.Connection() + + cur = conn.execute( + "SELECT AccountType FROM AccountTypes WHERE ID = ?", (1,)) + account_type = cur.fetchone()[0] + + assert account_type == "User" + + +def test_connection_class_unsupported_backend(): + tmpdir, tmp = make_temp_config("blah") + + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() + with pytest.raises(ValueError): + db.Connection() + aurweb.config.rehash() + + os.remove(tmp) + os.removedirs(tmpdir) + + +@mock.patch("mysql.connector.connect", mock.MagicMock(return_value=True)) +@mock.patch.object(mysql.connector, "paramstyle", "qmark") +def test_connection_mysql(): + tmpdir, tmp = make_temp_config("mysql") + with mock.patch.dict(os.environ, { + "AUR_CONFIG": tmp, + "AUR_CONFIG_DEFAULTS": "conf/config.defaults" + }): + aurweb.config.rehash() + db.Connection() + aurweb.config.rehash() + + os.remove(tmp) + os.removedirs(tmpdir) + + +@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) +@mock.patch.object(sqlite3, "paramstyle", "qmark") +def test_connection_sqlite(): + db.Connection() + + +@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) +@mock.patch.object(sqlite3, "paramstyle", "format") +def test_connection_execute_paramstyle_format(): + conn = db.Connection() + + # First, test ? to %s format replacement. + account_types = conn\ + .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"])\ + .fetchall() + assert account_types == \ + ["SELECT * FROM AccountTypes WHERE AccountType = %s", ["User"]] + + # Test other format replacement. + account_types = conn\ + .execute("SELECT * FROM AccountTypes WHERE AccountType = %", ["User"])\ + .fetchall() + assert account_types == \ + ["SELECT * FROM AccountTypes WHERE AccountType = %%", ["User"]] + + +@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) +@mock.patch.object(sqlite3, "paramstyle", "qmark") +def test_connection_execute_paramstyle_qmark(): + conn = db.Connection() + # We don't modify anything when using qmark, so test equality. + account_types = conn\ + .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"])\ + .fetchall() + assert account_types == \ + ["SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"]] + + +@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) +@mock.patch.object(sqlite3, "paramstyle", "unsupported") +def test_connection_execute_paramstyle_unsupported(): + conn = db.Connection() + with pytest.raises(ValueError, match="unsupported paramstyle"): + conn.execute( + "SELECT * FROM AccountTypes WHERE AccountType = ?", + ["User"] + ).fetchall() From 32f289309579554d85a9971be59ccc24c973840c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:20:26 -0700 Subject: [PATCH 0616/1891] add aurweb.models.account_type.AccountType Signed-off-by: Kevin Morris --- aurweb/models/__init__.py | 0 aurweb/models/account_type.py | 20 ++++++++++++++++++++ test/test_account_type.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 aurweb/models/__init__.py create mode 100644 aurweb/models/account_type.py create mode 100644 test/test_account_type.py diff --git a/aurweb/models/__init__.py b/aurweb/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py new file mode 100644 index 00000000..44225e35 --- /dev/null +++ b/aurweb/models/account_type.py @@ -0,0 +1,20 @@ +from sqlalchemy.orm import mapper + +from aurweb.schema import AccountTypes + + +class AccountType: + """ An ORM model of a single AccountTypes record. """ + + def __init__(self, **kwargs): + self.AccountType = kwargs.pop("AccountType") + + def __str__(self): + return str(self.AccountType) + + def __repr__(self): + return "" % ( + self.ID, str(self)) + + +mapper(AccountType, AccountTypes, confirm_deleted_rows=False) diff --git a/test/test_account_type.py b/test/test_account_type.py new file mode 100644 index 00000000..b6a12363 --- /dev/null +++ b/test/test_account_type.py @@ -0,0 +1,28 @@ +import pytest + +from aurweb.models.account_type import AccountType +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db() + + +def test_account_type(): + """ Test creating an AccountType, and reading its columns. """ + from aurweb.db import session + account_type = AccountType(AccountType="TestUser") + session.add(account_type) + session.commit() + + # Make sure it got created and was given an ID. + assert bool(account_type.ID) + + # Next, test our string functions. + assert str(account_type) == "TestUser" + assert repr(account_type) == \ + "" % ( + account_type.ID) + + session.delete(account_type) From e860d828b6f9babaa5829db92951087de3774b78 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:20:28 -0700 Subject: [PATCH 0617/1891] add aurweb.testing, a module with testing utilities Signed-off-by: Kevin Morris --- aurweb/testing.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 aurweb/testing.py diff --git a/aurweb/testing.py b/aurweb/testing.py new file mode 100644 index 00000000..7516d918 --- /dev/null +++ b/aurweb/testing.py @@ -0,0 +1,30 @@ +from aurweb.db import get_engine + + +def setup_test_db(*args): + """ This function is to be used to setup a test database before + using it. It takes a variable number of table strings, and for + each table in that set of table strings, it deletes all records. + + The primary goal of this method is to configure empty tables + that tests can use from scratch. This means that tests using + this function should make sure they do not depend on external + records and keep their logic self-contained. + + Generally used inside of pytest fixtures, this function + can be used anywhere, but keep in mind its functionality when + doing so. + + Examples: + setup_test_db("Users", "Sessions") + + test_tables = ["Users", "Sessions"]; + setup_test_db(*test_tables) + """ + engine = get_engine() + conn = engine.connect() + + tables = list(args) + for table in tables: + conn.execute(f"DELETE FROM {table}") + conn.close() From 8a47afd2ea8ce56b17aba95503d7c97f22023dff Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:20:32 -0700 Subject: [PATCH 0618/1891] add aurweb.models.user.User + Added aurweb.models.user.User class. This is the first example of an sqlalchemy ORM model. We can search for users via for example: `session.query(User).filter(User.ID==1).first()`, where `session` is a configured `aurweb.db.session` object. + Along with the User class, defined the AccountType class. Each User maintains a relationship to its AccountType via User.AccountType. + Added AccountType.users backref. Signed-off-by: Kevin Morris --- aurweb/models/user.py | 43 +++++++++++++++++++++++++++++++++++ test/test_user.py | 52 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 aurweb/models/user.py create mode 100644 test/test_user.py diff --git a/aurweb/models/user.py b/aurweb/models/user.py new file mode 100644 index 00000000..ba91c439 --- /dev/null +++ b/aurweb/models/user.py @@ -0,0 +1,43 @@ +from sqlalchemy.orm import backref, mapper, relationship + +from aurweb.models.account_type import AccountType +from aurweb.schema import Users + + +class User: + """ An ORM model of a single Users record. """ + + def __init__(self, **kwargs): + self.AccountTypeID = kwargs.get("AccountTypeID") + + account_type = kwargs.get("AccountType") + if account_type: + self.AccountType = account_type + + self.Username = kwargs.get("Username") + self.Email = kwargs.get("Email") + self.BackupEmail = kwargs.get("BackupEmail") + self.Passwd = kwargs.get("Passwd") + self.Salt = kwargs.get("Salt") + self.RealName = kwargs.get("RealName") + self.LangPreference = kwargs.get("LangPreference") + self.Timezone = kwargs.get("Timezone") + self.Homepage = kwargs.get("Homepage") + self.IRCNick = kwargs.get("IRCNick") + self.PGPKey = kwargs.get("PGPKey") + self.RegistrationTS = kwargs.get("RegistrationTS") + self.CommentNotify = kwargs.get("CommentNotify") + self.UpdateNotify = kwargs.get("UpdateNotify") + self.OwnershipNotify = kwargs.get("OwnershipNotify") + self.SSOAccountID = kwargs.get("SSOAccountID") + + def __repr__(self): + return "" % ( + self.ID, str(self.AccountType), self.Username) + + +# Map schema.Users to User and give it some relationships. +mapper(User, Users, properties={ + "AccountType": relationship(AccountType, + backref=backref("users", lazy="dynamic")) +}) diff --git a/test/test_user.py b/test/test_user.py new file mode 100644 index 00000000..8ac9b00b --- /dev/null +++ b/test/test_user.py @@ -0,0 +1,52 @@ +import pytest + +from aurweb.models.account_type import AccountType +from aurweb.models.user import User +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db("Users") + + +def test_user(): + """ Test creating a user and reading its columns. """ + from aurweb.db import session + + # First, grab our target AccountType. + account_type = session.query(AccountType).filter( + AccountType.AccountType == "User").first() + + user = User( + AccountType=account_type, + RealName="Test User", Username="test", + Email="test@example.org", Passwd="abcd", + IRCNick="tester", + Salt="efgh", ResetKey="blahblah") + session.add(user) + session.commit() + + assert user in account_type.users + + # Make sure the user was created and given an ID. + assert bool(user.ID) + + # Search for the user via query API. + result = session.query(User).filter(User.ID == user.ID).first() + + # Compare the result and our original user. + assert result.ID == user.ID + assert result.AccountType.ID == user.AccountType.ID + assert result.Username == user.Username + assert result.Email == user.Email + + # Ensure we've got the correct account type. + assert user.AccountType.ID == account_type.ID + assert user.AccountType.AccountType == account_type.AccountType + + # Test out user string functions. + assert repr(user) == f"" + + session.delete(user) From 02311eab7604d29de7b70721cb1e10329178cfc7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Mar 2021 15:20:34 -0700 Subject: [PATCH 0619/1891] add test_initdb.py IMPORTANT: This test completely wipes out the database it's using. Make sure you've got AUR_CONFIG set to a test database configuration! Signed-off-by: Kevin Morris --- test/test_initdb.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/test_initdb.py diff --git a/test/test_initdb.py b/test/test_initdb.py new file mode 100644 index 00000000..ff089b63 --- /dev/null +++ b/test/test_initdb.py @@ -0,0 +1,27 @@ +import pytest + +import aurweb.config +import aurweb.db +import aurweb.initdb + +from aurweb.models.account_type import AccountType +from aurweb.schema import metadata +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db() + + tables = metadata.tables.keys() + for table in tables: + aurweb.db.session.execute(f"DROP TABLE IF EXISTS {table}") + + +def test_run(): + class Args: + use_alembic = True + verbose = False + aurweb.initdb.run(Args()) + assert aurweb.db.session.query(AccountType).filter( + AccountType.AccountType == "User").first() is not None From 81856f3b646ad2bf27008a97b1604a5325eea03c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 13 May 2021 21:05:34 -0700 Subject: [PATCH 0620/1891] Fix incorrect construction of MySQL SQLAlchemy URL Signed-off-by: Kevin Morris From 82f3871a83bf234983f8d63d2f1861d876a52fb1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 13 May 2021 21:11:57 -0700 Subject: [PATCH 0621/1891] Support SQLAlchemy 1.4 URL.create recommendation This fixes a deprecating warning when using SQLAlchemy 1.4. Signed-off-by: Kevin Morris --- .coveragerc | 1 + aurweb/db.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.coveragerc b/.coveragerc index 9dcfca18..69c153ce 100644 --- a/.coveragerc +++ b/.coveragerc @@ -6,3 +6,4 @@ include = aurweb/* fail_under = 85 exclude_lines = if __name__ == .__main__.: + pragma: no cover diff --git a/aurweb/db.py b/aurweb/db.py index 7993dfdb..49e0abd2 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -16,9 +16,18 @@ def get_sqlalchemy_url(): Build an SQLAlchemy for use with create_engine based on the aurweb configuration. """ import sqlalchemy + + constructor = sqlalchemy.engine.url.URL + + parts = sqlalchemy.__version__.split('.') + major = int(parts[0]) + minor = int(parts[1]) + if major == 1 and minor >= 4: # pragma: no cover + constructor = sqlalchemy.engine.url.URL.create + aur_db_backend = aurweb.config.get('database', 'backend') if aur_db_backend == 'mysql': - return sqlalchemy.engine.url.URL( + return constructor( 'mysql+mysqlconnector', username=aurweb.config.get('database', 'user'), password=aurweb.config.get('database', 'password'), @@ -29,7 +38,7 @@ def get_sqlalchemy_url(): }, ) elif aur_db_backend == 'sqlite': - return sqlalchemy.engine.url.URL( + return constructor( 'sqlite', database=aurweb.config.get('database', 'name'), ) From cdf75ced9abe855753e33b48cc869c4ac64506ba Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Thu, 13 May 2021 00:08:15 +0200 Subject: [PATCH 0622/1891] Adding error 404 catcher --- aurweb/routers/errors.py | 14 ++++++++++++++ templates/errors/404.html | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 aurweb/routers/errors.py create mode 100644 templates/errors/404.html diff --git a/aurweb/routers/errors.py b/aurweb/routers/errors.py new file mode 100644 index 00000000..5d4ca4ce --- /dev/null +++ b/aurweb/routers/errors.py @@ -0,0 +1,14 @@ +from aurweb.templates import make_context, render_template +from aurweb import l10n + + +async def not_found(request, exc): + _ = l10n.get_translator_for_request(request) + context = make_context(request, f"404 - {_('Page Not Found')}") + return render_template("errors/404.html", context) + + +# Maps HTTP errors to functions +exceptions = { + 404: not_found, +} diff --git a/templates/errors/404.html b/templates/errors/404.html new file mode 100644 index 00000000..0afdd2fa --- /dev/null +++ b/templates/errors/404.html @@ -0,0 +1,8 @@ +{% extends 'partials/layout.html' %} + +{% block pageContent %} +
    +

    404 - {% trans %}Page Not Found{% endtrans %}

    +

    {% trans %}Sorry, the page you've requested does not exist.{% endtrans %}

    +
    + {% endblock %} From f6744d3e39fd044f797f9a702d8c9883fe40c527 Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Thu, 13 May 2021 00:08:15 +0200 Subject: [PATCH 0623/1891] Adding error 503 catcher --- aurweb/asgi.py | 4 ++-- aurweb/routers/errors.py | 6 ++++++ templates/errors/503.html | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 templates/errors/503.html diff --git a/aurweb/asgi.py b/aurweb/asgi.py index b6e15582..c03a00f7 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -8,12 +8,12 @@ from starlette.middleware.sessions import SessionMiddleware import aurweb.config from aurweb.db import get_engine -from aurweb.routers import html, sso +from aurweb.routers import html, sso, errors routes = set() # Setup the FastAPI app. -app = FastAPI() +app = FastAPI(exception_handlers=errors.exceptions) @app.on_event("startup") diff --git a/aurweb/routers/errors.py b/aurweb/routers/errors.py index 5d4ca4ce..3bdaeb9d 100644 --- a/aurweb/routers/errors.py +++ b/aurweb/routers/errors.py @@ -8,7 +8,13 @@ async def not_found(request, exc): return render_template("errors/404.html", context) +async def service_unavailable(request, exc): + _ = l10n.get_translator_for_request(request) + context = make_context(request, "503 - {_('Service Unavailable')}") + return render_template("errors/503.html", context) + # Maps HTTP errors to functions exceptions = { 404: not_found, + 503: service_unavailable } diff --git a/templates/errors/503.html b/templates/errors/503.html new file mode 100644 index 00000000..d31666a1 --- /dev/null +++ b/templates/errors/503.html @@ -0,0 +1,8 @@ +{% extends 'partials/layout.html' %} + +{% block pageContent %} +
    +

    503 - {% trans %}Service Unavailable{% endtrans %}

    +

    {% trans %}Don't panic! This site is down due to maintenance. We will be back soon.{% endtrans %}

    +
    +{% endblock %} From 1d5827007f205c8972d07eee138372e8f9303684 Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Thu, 13 May 2021 22:02:50 +0200 Subject: [PATCH 0624/1891] Adding route tests Removing status code from 404 title Removing status code from 503 title Adding id to 503 error box Indatation fix --- aurweb/routers/errors.py | 11 ++++------- aurweb/routers/html.py | 8 +++++++- templates/errors/404.html | 4 ++-- templates/errors/503.html | 2 +- test/test_routes.py | 7 +++++++ 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/aurweb/routers/errors.py b/aurweb/routers/errors.py index 3bdaeb9d..111d802a 100644 --- a/aurweb/routers/errors.py +++ b/aurweb/routers/errors.py @@ -1,17 +1,14 @@ from aurweb.templates import make_context, render_template -from aurweb import l10n async def not_found(request, exc): - _ = l10n.get_translator_for_request(request) - context = make_context(request, f"404 - {_('Page Not Found')}") - return render_template("errors/404.html", context) + context = make_context(request, "Page Not Found") + return render_template("errors/404.html", context, 404) async def service_unavailable(request, exc): - _ = l10n.get_translator_for_request(request) - context = make_context(request, "503 - {_('Service Unavailable')}") - return render_template("errors/503.html", context) + context = make_context(request, "Service Unavailable") + return render_template("errors/503.html", context, 503) # Maps HTTP errors to functions exceptions = { diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index ae08c764..50b62450 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -4,7 +4,7 @@ own modules and imported here. """ from http import HTTPStatus from urllib.parse import unquote -from fastapi import APIRouter, Form, Request +from fastapi import APIRouter, Form, Request, HTTPException from fastapi.responses import HTMLResponse, RedirectResponse from aurweb.templates import make_context, render_template @@ -48,3 +48,9 @@ async def index(request: Request): """ Homepage route. """ context = make_context(request, "Home") return render_template("index.html", context) + + +# A route that returns a error 503. For testing purposes. +@router.get("/raisefivethree", response_class=HTMLResponse) +async def raise_service_unavailable(request: Request): + raise HTTPException(status_code=503) diff --git a/templates/errors/404.html b/templates/errors/404.html index 0afdd2fa..4926aff6 100644 --- a/templates/errors/404.html +++ b/templates/errors/404.html @@ -1,8 +1,8 @@ {% extends 'partials/layout.html' %} {% block pageContent %} -
    +

    404 - {% trans %}Page Not Found{% endtrans %}

    {% trans %}Sorry, the page you've requested does not exist.{% endtrans %}

    - {% endblock %} +{% endblock %} diff --git a/templates/errors/503.html b/templates/errors/503.html index d31666a1..9a0ed56a 100644 --- a/templates/errors/503.html +++ b/templates/errors/503.html @@ -1,7 +1,7 @@ {% extends 'partials/layout.html' %} {% block pageContent %} -
    +

    503 - {% trans %}Service Unavailable{% endtrans %}

    {% trans %}Don't panic! This site is down due to maintenance. We will be back soon.{% endtrans %}

    diff --git a/test/test_routes.py b/test/test_routes.py index 46ba39f5..86221108 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -67,3 +67,10 @@ def test_language_query_params(): response = req.post("/language", data=post_data) assert response.headers.get("location") == f"/?{q}" assert response.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_error_messages(): + response1 = client.get("/thisroutedoesnotexist") + response2 = client.get("/raisefivethree") + assert response1.status_code == int(HTTPStatus.NOT_FOUND) + assert response2.status_code == int(HTTPStatus.SERVICE_UNAVAILABLE) \ No newline at end of file From e0eb6b0e76311bc4e2df02e083edea28c42c178c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 16 May 2021 06:26:38 -0700 Subject: [PATCH 0625/1891] test_db: remove use of mkdtemp and os.removedirs Signed-off-by: Kevin Morris --- test/test_db.py | 52 +++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/test/test_db.py b/test/test_db.py index 0a134541..f5902e4c 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -57,10 +57,8 @@ def test_sqlalchemy_mysql_url(): def make_temp_config(backend): - if not os.path.isdir("/tmp"): - os.mkdir("/tmp") - tmpdir = tempfile.mkdtemp() - tmp = os.path.join(tmpdir, "config.tmp") + tmpdir = tempfile.TemporaryDirectory() + tmp = os.path.join(tmpdir.name, "config.tmp") with open("conf/config") as f: config = re.sub(r'backend = sqlite', f'backend = {backend}', f.read()) with open(tmp, "w") as o: @@ -69,16 +67,14 @@ def make_temp_config(backend): def test_sqlalchemy_unknown_backend(): - tmpdir, tmp = make_temp_config("blah") + tmpctx, tmp = make_temp_config("blah") - with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + with tmpctx: + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() + with pytest.raises(ValueError): + db.get_sqlalchemy_url() aurweb.config.rehash() - with pytest.raises(ValueError): - db.get_sqlalchemy_url() - aurweb.config.rehash() - - os.remove(tmp) - os.removedirs(tmpdir) def test_db_connects_without_fail(): @@ -97,32 +93,28 @@ def test_connection_class_without_fail(): def test_connection_class_unsupported_backend(): - tmpdir, tmp = make_temp_config("blah") + tmpctx, tmp = make_temp_config("blah") - with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + with tmpctx: + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() + with pytest.raises(ValueError): + db.Connection() aurweb.config.rehash() - with pytest.raises(ValueError): - db.Connection() - aurweb.config.rehash() - - os.remove(tmp) - os.removedirs(tmpdir) @mock.patch("mysql.connector.connect", mock.MagicMock(return_value=True)) @mock.patch.object(mysql.connector, "paramstyle", "qmark") def test_connection_mysql(): - tmpdir, tmp = make_temp_config("mysql") - with mock.patch.dict(os.environ, { - "AUR_CONFIG": tmp, - "AUR_CONFIG_DEFAULTS": "conf/config.defaults" - }): + tmpctx, tmp = make_temp_config("mysql") + with tmpctx: + with mock.patch.dict(os.environ, { + "AUR_CONFIG": tmp, + "AUR_CONFIG_DEFAULTS": "conf/config.defaults" + }): + aurweb.config.rehash() + db.Connection() aurweb.config.rehash() - db.Connection() - aurweb.config.rehash() - - os.remove(tmp) - os.removedirs(tmpdir) @mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) From 3f1f03e03c904f1c8202a692bc18ca153c529f50 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 16 May 2021 01:40:19 -0700 Subject: [PATCH 0626/1891] aurweb.db: only pass check_same_thread with sqlite Signed-off-by: Kevin Morris --- aurweb/db.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/aurweb/db.py b/aurweb/db.py index 49e0abd2..f5530bcf 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -59,10 +59,12 @@ def get_engine(): global engine, session, Session if engine is None: - engine = create_engine(get_sqlalchemy_url(), - # check_same_thread is for a SQLite technicality - # https://fastapi.tiangolo.com/tutorial/sql-databases/#note - connect_args={"check_same_thread": False}) + connect_args = dict() + if aurweb.config.get("database", "backend") == "sqlite": + # check_same_thread is for a SQLite technicality + # https://fastapi.tiangolo.com/tutorial/sql-databases/#note + connect_args["check_same_thread"] = False + engine = create_engine(get_sqlalchemy_url(), connect_args=connect_args) Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = Session() From 66189c4460d1516344b13ad6a381aca6a7a0786e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 18 May 2021 02:46:56 -0700 Subject: [PATCH 0627/1891] alembic: restore logging, fix pytest conflicts In this case, when running pytests, we do not allow alembic to configure loggers. Signed-off-by: Kevin Morris --- aurweb/initdb.py | 1 + migrations/env.py | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/aurweb/initdb.py b/aurweb/initdb.py index c8d0b2ae..5f55bfc9 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -40,6 +40,7 @@ def run(args): if args.use_alembic: alembic_config = alembic.config.Config('alembic.ini') alembic_config.get_main_option('script_location') + alembic_config.attributes["configure_logger"] = False engine = sqlalchemy.create_engine(aurweb.db.get_sqlalchemy_url(), echo=(args.verbose >= 1)) diff --git a/migrations/env.py b/migrations/env.py index 23759123..dfe14804 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -20,6 +20,12 @@ target_metadata = aurweb.schema.metadata # ... etc. +# If configure_logger is either True or not specified, +# configure the logger via fileConfig. +if config.attributes.get("configure_logger", True): + logging.config.fileConfig(config.config_file_name) + + def run_migrations_offline(): """Run migrations in 'offline' mode. @@ -64,12 +70,7 @@ def run_migrations_online(): context.run_migrations() -if __name__ == "__main__": - # Interpret the config file for Python logging. - # This line sets up loggers basically. - logging.config.fileConfig(config.config_file_name) - - if context.is_offline_mode(): - run_migrations_offline() - else: - run_migrations_online() +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() From 72f755817c012a5c38255175522f32a059f976c0 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 17 May 2021 19:12:05 +0100 Subject: [PATCH 0628/1891] Adds Alembic migration for DB/Tables conversion to utf8mb4 MySql defaults to `utf8` and case insensitive collation so migrate these to case sensitive and `utf8mb4` Closes #21 Signed-off-by: Leonidas Spyropoulos From 7b7c3abbe2dab35bf4a7bb67c7ab4121a0ee7566 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 18 May 2021 13:04:20 +0100 Subject: [PATCH 0629/1891] Conditionally apply SSOAccountId migration to support misaligned databases Closes: #34 Signed-off-by: Leonidas Spyropoulos From ac31f520ea25d31f675dd4e2ac236078418c2f69 Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Mon, 10 May 2021 22:34:19 +0200 Subject: [PATCH 0630/1891] Add coverage report for "Test Coverage Visualization"[1] [1] https://docs.gitlab.com/ee/user/project/merge_requests/test_coverage_visualization.html --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e287748..ca3055ad 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,3 +24,7 @@ test: - AUR_CONFIG=conf/config python -m aurweb.initdb - make -C test - coverage report --include='aurweb/*' + - coverage xml --include='aurweb/*' + artifacts: + reports: + cobertura: coverage.xml From 64bc93926f87aa9a0a29b4f014af2374e527fc8a Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 18 May 2021 13:15:47 +0100 Subject: [PATCH 0631/1891] Add support for configuring database with port instead of socket Signed-off-by: Leonidas Spyropoulos --- .gitignore | 1 + aurweb/config.py | 4 ++++ aurweb/db.py | 11 ++++++++--- conf/config.defaults | 1 + conf/config.dev | 5 ++++- test/test_db.py | 24 +++++++++++++++++------- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 372fa105..35b571d7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ fastapi_aw/ .vim/ .pylintrc .coverage +.idea diff --git a/aurweb/config.py b/aurweb/config.py index 49a2765a..2a6cfc3e 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -32,6 +32,10 @@ def rehash(): _get_parser() +def get_with_fallback(section, option, fallback): + return _get_parser().get(section, option, fallback=fallback) + + def get(section, option): return _get_parser().get(section, option) diff --git a/aurweb/db.py b/aurweb/db.py index f5530bcf..491ce9e2 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -27,15 +27,20 @@ def get_sqlalchemy_url(): aur_db_backend = aurweb.config.get('database', 'backend') if aur_db_backend == 'mysql': + if aurweb.config.get_with_fallback('database', 'port', fallback=None): + port = aurweb.config.get('database', 'port') + param_query = None + else: + port = None + param_query = {'unix_socket': aurweb.config.get('database', 'socket')} return constructor( 'mysql+mysqlconnector', username=aurweb.config.get('database', 'user'), password=aurweb.config.get('database', 'password'), host=aurweb.config.get('database', 'host'), database=aurweb.config.get('database', 'name'), - query={ - 'unix_socket': aurweb.config.get('database', 'socket'), - }, + port=port, + query=param_query ) elif aur_db_backend == 'sqlite': return constructor( diff --git a/conf/config.defaults b/conf/config.defaults index 98e033b7..c05648d5 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -2,6 +2,7 @@ backend = mysql host = localhost socket = /var/run/mysqld/mysqld.sock +;port = 3306 name = AUR user = aur password = aur diff --git a/conf/config.dev b/conf/config.dev index ccb01f4f..194a3bf8 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -9,11 +9,14 @@ backend = sqlite name = YOUR_AUR_ROOT/aurweb.sqlite3 -; Alternative MySQL configuration +; Alternative MySQL configuration (Use either port of socket, if both defined port takes priority) ;backend = mysql ;name = aurweb ;user = aur ;password = aur +;host = localhost +;port = 3306 +;socket = /var/run/mysqld/mysqld.sock [options] aurwebdir = YOUR_AUR_ROOT diff --git a/test/test_db.py b/test/test_db.py index f5902e4c..41936321 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -56,18 +56,28 @@ def test_sqlalchemy_mysql_url(): aurweb.config.rehash() -def make_temp_config(backend): +def test_sqlalchemy_mysql_port_url(): + tmpctx, tmp = make_temp_config("conf/config.defaults", ";port = 3306", "port = 3306") + + with tmpctx: + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() + assert db.get_sqlalchemy_url() + aurweb.config.rehash() + + +def make_temp_config(config_file, src_str, replace_with): tmpdir = tempfile.TemporaryDirectory() tmp = os.path.join(tmpdir.name, "config.tmp") - with open("conf/config") as f: - config = re.sub(r'backend = sqlite', f'backend = {backend}', f.read()) + with open(config_file) as f: + config = re.sub(src_str, f'{replace_with}', f.read()) with open(tmp, "w") as o: o.write(config) - return (tmpdir, tmp) + return tmpdir, tmp def test_sqlalchemy_unknown_backend(): - tmpctx, tmp = make_temp_config("blah") + tmpctx, tmp = make_temp_config("conf/config", "backend = sqlite", "backend = blah") with tmpctx: with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): @@ -93,7 +103,7 @@ def test_connection_class_without_fail(): def test_connection_class_unsupported_backend(): - tmpctx, tmp = make_temp_config("blah") + tmpctx, tmp = make_temp_config("conf/config", "backend = sqlite", "backend = blah") with tmpctx: with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): @@ -106,7 +116,7 @@ def test_connection_class_unsupported_backend(): @mock.patch("mysql.connector.connect", mock.MagicMock(return_value=True)) @mock.patch.object(mysql.connector, "paramstyle", "qmark") def test_connection_mysql(): - tmpctx, tmp = make_temp_config("mysql") + tmpctx, tmp = make_temp_config("conf/config", "backend = sqlite", "backend = mysql") with tmpctx: with mock.patch.dict(os.environ, { "AUR_CONFIG": tmp, From 5185df629ee7d2190fac7f0268935e3f4477d114 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 24 Dec 2020 20:48:35 -0800 Subject: [PATCH 0632/1891] move aurweb.testing to its own package + Added aurweb.testing.setup_test_db(*tables) + Added aurweb.testing.models.make_user(**kwargs) + Added aurweb.testing.models.make_session(**kwargs) + Added aurweb.testing.requests.Client + Added aurweb.testing.requests.Request * Updated test_l10n.py to use our new Request Signed-off-by: Kevin Morris --- aurweb/{testing.py => testing/__init__.py} | 4 ++-- aurweb/testing/models.py | 25 ++++++++++++++++++++++ aurweb/testing/requests.py | 8 +++++++ test/test_l10n.py | 18 ++++++---------- 4 files changed, 41 insertions(+), 14 deletions(-) rename aurweb/{testing.py => testing/__init__.py} (93%) create mode 100644 aurweb/testing/models.py create mode 100644 aurweb/testing/requests.py diff --git a/aurweb/testing.py b/aurweb/testing/__init__.py similarity index 93% rename from aurweb/testing.py rename to aurweb/testing/__init__.py index 7516d918..0a807b40 100644 --- a/aurweb/testing.py +++ b/aurweb/testing/__init__.py @@ -1,4 +1,4 @@ -from aurweb.db import get_engine +import aurweb.db def setup_test_db(*args): @@ -21,7 +21,7 @@ def setup_test_db(*args): test_tables = ["Users", "Sessions"]; setup_test_db(*test_tables) """ - engine = get_engine() + engine = aurweb.db.get_engine() conn = engine.connect() tables = list(args) diff --git a/aurweb/testing/models.py b/aurweb/testing/models.py new file mode 100644 index 00000000..8a27c409 --- /dev/null +++ b/aurweb/testing/models.py @@ -0,0 +1,25 @@ +import warnings + +from sqlalchemy import exc + +import aurweb.db + + +def make_user(**kwargs): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", exc.SAWarning) + from aurweb.models.user import User + user = User(**kwargs) + aurweb.db.session.add(user) + aurweb.db.session.commit() + return user + + +def make_session(**kwargs): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", exc.SAWarning) + from aurweb.models.session import Session + session = Session(**kwargs) + aurweb.db.session.add(session) + aurweb.db.session.commit() + return session diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py new file mode 100644 index 00000000..2839c93f --- /dev/null +++ b/aurweb/testing/requests.py @@ -0,0 +1,8 @@ +class Client: + host = "127.0.0.1" + + +class Request: + client = Client() + cookies = dict() + headers = dict() diff --git a/test/test_l10n.py b/test/test_l10n.py index 1a1ef3e6..e833cd44 100644 --- a/test/test_l10n.py +++ b/test/test_l10n.py @@ -1,13 +1,6 @@ """ Test our l10n module. """ from aurweb import l10n - - -class FakeRequest: - """ A fake Request doppleganger; use this to change request.cookies - easily and with no side-effects. """ - - def __init__(self, *args, **kwargs): - self.cookies = kwargs.pop("cookies", dict()) +from aurweb.testing.requests import Request def test_translator(): @@ -18,7 +11,7 @@ def test_translator(): def test_get_request_language(): """ First, tests default_lang, then tests a modified AURLANG cookie. """ - request = FakeRequest() + request = Request() assert l10n.get_request_language(request) == "en" request.cookies["AURLANG"] = "de" @@ -28,8 +21,8 @@ def test_get_request_language(): def test_get_raw_translator_for_request(): """ Make sure that get_raw_translator_for_request is giving us the translator we expect. """ - request = FakeRequest(cookies={"AURLANG": "de"}) - + request = Request() + request.cookies["AURLANG"] = "de" translator = l10n.get_raw_translator_for_request(request) assert translator.gettext("Home") == \ l10n.translator.translate("Home", "de") @@ -38,7 +31,8 @@ def test_get_raw_translator_for_request(): def test_get_translator_for_request(): """ Make sure that get_translator_for_request is giving us back our expected translation function. """ - request = FakeRequest(cookies={"AURLANG": "de"}) + request = Request() + request.cookies["AURLANG"] = "de" translate = l10n.get_translator_for_request(request) assert translate("Home") == "Startseite" From a836892cde9a8f89fb7cb9e159bc8d4711f88439 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 14 Jan 2021 21:06:41 -0800 Subject: [PATCH 0633/1891] aurweb.db: add query, create, delete helpers Takes sqlalchemy kwargs or stanzas: query(Model, Model.Column == value) query(Model, and_(Model.Column == value, Model.Column != "BAD!")) Updated tests to reflect the new utility and a comment about upcoming function deprecation is added to get_account_type(). From here on, phase out the use of get_account_type(). + aurweb.db: Added create utility function + aurweb.db: Added delete utility function The `delete` function can be used to delete a record by search kwargs directly. Example: delete(User, User.ID == 6) All three functions added in this commit are typically useful to perform these operations without having to import aurweb.db.session. Removes a bit of redundancy overall. Signed-off-by: Kevin Morris --- aurweb/db.py | 18 ++++++++++++++++++ test/test_account_type.py | 40 ++++++++++++++++++++++++++++++++++----- test/test_db.py | 13 ++++++++++++- test/test_routes.py | 18 ++++++++++++++++-- test/test_user.py | 4 +++- 5 files changed, 84 insertions(+), 9 deletions(-) diff --git a/aurweb/db.py b/aurweb/db.py index 491ce9e2..9ca51de2 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -11,6 +11,24 @@ Session = None session = None +def query(model, *args, **kwargs): + return session.query(model).filter(*args, **kwargs) + + +def create(model, *args, **kwargs): + instance = model(*args, **kwargs) + session.add(instance) + session.commit() + return instance + + +def delete(model, *args, **kwargs): + instance = session.query(model).filter(*args, **kwargs) + for record in instance: + session.delete(record) + session.commit() + + def get_sqlalchemy_url(): """ Build an SQLAlchemy for use with create_engine based on the aurweb configuration. diff --git a/test/test_account_type.py b/test/test_account_type.py index b6a12363..9419970c 100644 --- a/test/test_account_type.py +++ b/test/test_account_type.py @@ -1,20 +1,34 @@ import pytest from aurweb.models.account_type import AccountType +from aurweb.models.user import User from aurweb.testing import setup_test_db +from aurweb.testing.models import make_user + +account_type = None @pytest.fixture(autouse=True) def setup(): - setup_test_db() + setup_test_db("Users") + + from aurweb.db import session + + global account_type + + account_type = AccountType(AccountType="TestUser") + session.add(account_type) + session.commit() + + yield account_type + + session.delete(account_type) + session.commit() def test_account_type(): """ Test creating an AccountType, and reading its columns. """ from aurweb.db import session - account_type = AccountType(AccountType="TestUser") - session.add(account_type) - session.commit() # Make sure it got created and was given an ID. assert bool(account_type.ID) @@ -25,4 +39,20 @@ def test_account_type(): "" % ( account_type.ID) - session.delete(account_type) + record = session.query(AccountType).filter( + AccountType.AccountType == "TestUser").first() + assert account_type == record + + +def test_user_account_type_relationship(): + from aurweb.db import session + + user = make_user(Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + assert user.AccountType == account_type + assert account_type.users.filter(User.ID == user.ID).first() + + session.delete(user) + session.commit() diff --git a/test/test_db.py b/test/test_db.py index 41936321..1eb0dc28 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -3,6 +3,7 @@ import re import sqlite3 import tempfile +from datetime import datetime from unittest import mock import mysql.connector @@ -11,6 +12,7 @@ import pytest import aurweb.config from aurweb import db +from aurweb.models.account_type import AccountType from aurweb.testing import setup_test_db @@ -39,7 +41,7 @@ class DBConnection: @pytest.fixture(autouse=True) def setup_db(): - setup_test_db() + setup_test_db("Bans") def test_sqlalchemy_sqlite_url(): @@ -174,3 +176,12 @@ def test_connection_execute_paramstyle_unsupported(): "SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"] ).fetchall() + + +def test_create_delete(): + db.create(AccountType, AccountType="test") + record = db.query(AccountType, AccountType.AccountType == "test").first() + assert record is not None + db.delete(AccountType, AccountType.AccountType == "test") + record = db.query(AccountType, AccountType.AccountType == "test").first() + assert record is None diff --git a/test/test_routes.py b/test/test_routes.py index 86221108..950d9b71 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -7,14 +7,26 @@ import pytest from fastapi.testclient import TestClient from aurweb.asgi import app +from aurweb.db import query +from aurweb.models.account_type import AccountType from aurweb.testing import setup_test_db client = TestClient(app) +user = None + @pytest.fixture def setup(): - setup_test_db("Users", "Session") + global user + + setup_test_db("Users", "Sessions") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = make_user(Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) def test_index(): @@ -54,6 +66,7 @@ def test_language_invalid_next(): response = req.post("/language", data=post_data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) + def test_language_query_params(): """ Test the language post route with query params. """ next = urllib.parse.quote_plus("/") @@ -73,4 +86,5 @@ def test_error_messages(): response1 = client.get("/thisroutedoesnotexist") response2 = client.get("/raisefivethree") assert response1.status_code == int(HTTPStatus.NOT_FOUND) - assert response2.status_code == int(HTTPStatus.SERVICE_UNAVAILABLE) \ No newline at end of file + assert response2.status_code == int(HTTPStatus.SERVICE_UNAVAILABLE) + diff --git a/test/test_user.py b/test/test_user.py index 8ac9b00b..5a56a035 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -1,5 +1,8 @@ import pytest +import aurweb.config + +from aurweb.db import query from aurweb.models.account_type import AccountType from aurweb.models.user import User from aurweb.testing import setup_test_db @@ -26,7 +29,6 @@ def test_user(): Salt="efgh", ResetKey="blahblah") session.add(user) session.commit() - assert user in account_type.users # Make sure the user was created and given an ID. From adc9fccb7d0e984cd780cd1a785911e36a6316b1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Dec 2020 19:29:19 -0800 Subject: [PATCH 0634/1891] add aurweb.models.ban.Ban ORM mapping Signed-off-by: Kevin Morris --- aurweb/models/ban.py | 19 +++++++++++++ test/test_ban.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 aurweb/models/ban.py create mode 100644 test/test_ban.py diff --git a/aurweb/models/ban.py b/aurweb/models/ban.py new file mode 100644 index 00000000..be030380 --- /dev/null +++ b/aurweb/models/ban.py @@ -0,0 +1,19 @@ +from fastapi import Request +from sqlalchemy.orm import mapper + +from aurweb.schema import Bans + + +class Ban: + def __init__(self, **kwargs): + self.IPAddress = kwargs.get("IPAddress") + self.BanTS = kwargs.get("BanTS") + + +def is_banned(request: Request): + from aurweb.db import session + ip = request.client.host + return session.query(Ban).filter(Ban.IPAddress == ip).first() is not None + + +mapper(Ban, Bans) diff --git a/test/test_ban.py b/test/test_ban.py new file mode 100644 index 00000000..de4f5b1b --- /dev/null +++ b/test/test_ban.py @@ -0,0 +1,63 @@ +import warnings + +from datetime import datetime, timedelta + +import pytest + +from sqlalchemy import exc as sa_exc + +from aurweb.models.ban import Ban, is_banned +from aurweb.testing import setup_test_db +from aurweb.testing.requests import Request + +ban = None + +request = Request() + + +@pytest.fixture(autouse=True) +def setup(): + from aurweb.db import session + + global ban + + setup_test_db("Bans") + + ban = Ban(IPAddress="127.0.0.1", + BanTS=datetime.utcnow() + timedelta(seconds=30)) + session.add(ban) + session.commit() + + +def test_ban(): + assert ban.IPAddress == "127.0.0.1" + assert bool(ban.BanTS) + + +def test_invalid_ban(): + from aurweb.db import session + + with pytest.raises(sa_exc.IntegrityError, + match="NOT NULL constraint failed: Bans.IPAddress"): + bad_ban = Ban(BanTS=datetime.utcnow()) + session.add(bad_ban) + + # We're adding a ban with no primary key; this causes an + # SQLAlchemy warnings when committing to the DB. + # Ignore them. + with warnings.catch_warnings(): + warnings.simplefilter("ignore", sa_exc.SAWarning) + session.commit() + + # Since we got a transaction failure, we need to rollback. + session.rollback() + + +def test_banned(): + request.client.host = "127.0.0.1" + assert is_banned(request) + + +def test_not_banned(): + request.client.host = "192.168.0.1" + assert not is_banned(request) From 1922e5380d819501b1ee3f9b50ff69bc583dbf6c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Dec 2020 20:55:43 -0800 Subject: [PATCH 0635/1891] add aurweb.models.session.Session ORM database object + Added aurweb.util module. - Added make_random_string function. + Added aurweb.db.make_random_value function. - Takes a model and a column and introspects them to figure out the proper column length to create a random string for; then creates a unique string for that column. Signed-off-by: Kevin Morris --- aurweb/db.py | 42 +++++++++++++++++++++++++++++- aurweb/models/session.py | 25 ++++++++++++++++++ aurweb/util.py | 7 +++++ test/test_session.py | 56 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 aurweb/models/session.py create mode 100644 aurweb/util.py create mode 100644 test/test_session.py diff --git a/aurweb/db.py b/aurweb/db.py index 9ca51de2..3f5731a9 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,8 +1,10 @@ import math import aurweb.config +import aurweb.util -engine = None # See get_engine +# See get_engine. +engine = None # ORM Session class. Session = None @@ -10,6 +12,44 @@ Session = None # Global ORM Session object. session = None +# Global introspected object memo. +introspected = dict() + + +def make_random_value(table: str, column: str): + """ Generate a unique, random value for a string column in a table. + + This can be used to generate for example, session IDs that + align with the properties of the database column with regards + to size. + + Internally, we use SQLAlchemy introspection to look at column + to decide which length to use for random string generation. + + :return: A unique string that is not in the database + """ + global introspected + + # Make sure column is converted to a string for memo interaction. + scolumn = str(column) + + # If the target column is not yet introspected, store its introspection + # object into our global `introspected` memo. + if scolumn not in introspected: + from sqlalchemy import inspect + target_column = scolumn.split('.')[-1] + col = list(filter(lambda c: c.name == target_column, + inspect(table).columns))[0] + introspected[scolumn] = col + + col = introspected.get(scolumn) + length = col.type.length + + string = aurweb.util.make_random_string(length) + while session.query(table).filter(column == string).first(): + string = aurweb.util.make_random_string(length) + return string + def query(model, *args, **kwargs): return session.query(model).filter(*args, **kwargs) diff --git a/aurweb/models/session.py b/aurweb/models/session.py new file mode 100644 index 00000000..60749303 --- /dev/null +++ b/aurweb/models/session.py @@ -0,0 +1,25 @@ +from sqlalchemy import Column, Integer +from sqlalchemy.orm import backref, mapper, relationship + +from aurweb.db import make_random_value +from aurweb.models.user import User +from aurweb.schema import Sessions + + +class Session: + UsersID = Column(Integer, nullable=True) + + def __init__(self, **kwargs): + self.UsersID = kwargs.get("UsersID") + self.SessionID = kwargs.get("SessionID") + self.LastUpdateTS = kwargs.get("LastUpdateTS") + + +mapper(Session, Sessions, primary_key=[Sessions.c.SessionID], properties={ + "User": relationship(User, backref=backref("session", + uselist=False)) +}) + + +def generate_unique_sid(): + return make_random_value(Session, Session.SessionID) diff --git a/aurweb/util.py b/aurweb/util.py new file mode 100644 index 00000000..65f18a4c --- /dev/null +++ b/aurweb/util.py @@ -0,0 +1,7 @@ +import random +import string + + +def make_random_string(length): + return ''.join(random.choices(string.ascii_lowercase + + string.digits, k=length)) diff --git a/test/test_session.py b/test/test_session.py new file mode 100644 index 00000000..560f628c --- /dev/null +++ b/test/test_session.py @@ -0,0 +1,56 @@ +""" Test our Session model. """ +from datetime import datetime +from unittest import mock + +import pytest + +from aurweb.models.account_type import AccountType +from aurweb.models.session import generate_unique_sid +from aurweb.testing import setup_test_db +from aurweb.testing.models import make_session, make_user + +user, _session = None, None + + +@pytest.fixture(autouse=True) +def setup(): + from aurweb.db import session + + global user, _session + + setup_test_db("Users", "Sessions") + + account_type = session.query(AccountType).filter( + AccountType.AccountType == "User").first() + user = make_user(Username="test", Email="test@example.org", + ResetKey="testReset", Passwd="testPassword", + AccountType=account_type) + _session = make_session(UsersID=user.ID, SessionID="testSession", + LastUpdateTS=datetime.utcnow()) + + +def test_session(): + assert _session.SessionID == "testSession" + assert _session.UsersID == user.ID + + +def test_session_user_association(): + # Make sure that the Session user attribute is correct. + assert _session.User == user + + +def test_generate_unique_sid(): + # Mock up aurweb.models.session.generate_sid by returning + # sids[i % 2] from 0 .. n. This will swap between each sid + # between each call. + sids = ["testSession", "realSession"] + i = 0 + + def mock_generate_sid(length): + nonlocal i + sid = sids[i % 2] + i += 1 + return sid + + with mock.patch("aurweb.util.make_random_string", mock_generate_sid): + assert generate_unique_sid() == "realSession" From 137c050f99e29f3d039c42f3b693dd9ef7ed4bd1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Jan 2021 16:43:35 -0800 Subject: [PATCH 0636/1891] add python-bcrypt dependency Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 +- Dockerfile | 2 +- INSTALL | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca3055ad..4ad97393 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ before_script: python-pytest-tap python-fastapi hypercorn nginx python-authlib python-itsdangerous python-httpx python-jinja python-pytest-cov python-requests python-aiofiles python-python-multipart - python-pytest-asyncio python-coverage + python-pytest-asyncio python-coverage python-bcrypt test: script: diff --git a/Dockerfile b/Dockerfile index 7e981340..6638f9a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN pacman -Syu --noconfirm base-devel git gpgme protobuf pyalpm \ python-werkzeug python-pytest-tap python-fastapi nginx python-authlib \ python-itsdangerous python-httpx python-jinja python-pytest-cov \ python-requests python-aiofiles python-python-multipart \ - python-pytest-asyncio python-coverage hypercorn + python-pytest-asyncio python-coverage hypercorn python-bcrypt # Remove aurweb.sqlite3 if it was copied over via COPY. RUN rm -fv aurweb.sqlite3 diff --git a/INSTALL b/INSTALL index e4c52480..6c43fec8 100644 --- a/INSTALL +++ b/INSTALL @@ -51,7 +51,7 @@ read the instructions below. python-bleach python-markdown python-alembic hypercorn \ python-itsdangerous python-authlib python-httpx \ python-jinja python-aiofiles python-python-multipart \ - python-requests + python-requests hypercorn python-bcrypt # python3 setup.py install 5) Create a new MySQL database and a user and import the aurweb SQL schema: From 56f2798279f3cbde46389aa65a27fb58bfb0bcfc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Dec 2020 20:54:53 -0800 Subject: [PATCH 0637/1891] add aurweb.auth and authentication to User + Added aurweb.auth.AnonymousUser * An instance of this model is returned as the request user when the request is not authenticated + Added aurweb.auth.BasicAuthBackend + Add starlette's AuthenticationMiddleware to app middleware, which uses our BasicAuthBackend facility + Added User.is_authenticated() + Added User.authenticate(password) + Added User.login(request, password) + Added User.logout(request) + Added repr(User(...)) representation + Added aurweb.auth.auth_required decorator. This change uses the same AURSID logic in the PHP implementation. Additionally, introduce a few helpers for authentication, one of which being `User.update_password(password, rounds = 12)` where `rounds` is a configurable number of salt rounds. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 8 +++ aurweb/auth.py | 77 +++++++++++++++++++++++ aurweb/models/user.py | 125 ++++++++++++++++++++++++++++++++++++- test/test_auth.py | 80 ++++++++++++++++++++++++ test/test_user.py | 142 +++++++++++++++++++++++++++++++++++++----- 5 files changed, 412 insertions(+), 20 deletions(-) create mode 100644 aurweb/auth.py create mode 100644 test/test_auth.py diff --git a/aurweb/asgi.py b/aurweb/asgi.py index c03a00f7..4d21ad03 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -1,12 +1,15 @@ import http +import os from fastapi import FastAPI, HTTPException from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles +from starlette.middleware.authentication import AuthenticationMiddleware from starlette.middleware.sessions import SessionMiddleware import aurweb.config +from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine from aurweb.routers import html, sso, errors @@ -32,10 +35,15 @@ async def app_startup(): StaticFiles(directory="web/html/images"), name="static_images") + # Add application middlewares. + app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend()) app.add_middleware(SessionMiddleware, secret_key=session_secret) + + # Add application routes. app.include_router(sso.router) app.include_router(html.router) + # Initialize the database engine and ORM. get_engine() # NOTE: Always keep this dictionary updated with all routes diff --git a/aurweb/auth.py b/aurweb/auth.py new file mode 100644 index 00000000..8608a82a --- /dev/null +++ b/aurweb/auth.py @@ -0,0 +1,77 @@ +import functools + +from datetime import datetime +from http import HTTPStatus + +from fastapi.responses import RedirectResponse +from starlette.authentication import AuthCredentials, AuthenticationBackend, AuthenticationError +from starlette.requests import HTTPConnection + +from aurweb.models.session import Session +from aurweb.models.user import User +from aurweb.templates import make_context, render_template + + +class AnonymousUser: + @staticmethod + def is_authenticated(): + return False + + +class BasicAuthBackend(AuthenticationBackend): + async def authenticate(self, conn: HTTPConnection): + from aurweb.db import session + + sid = conn.cookies.get("AURSID") + if not sid: + return None, AnonymousUser() + + now_ts = datetime.utcnow().timestamp() + record = session.query(Session).filter( + Session.SessionID == sid, Session.LastUpdateTS >= now_ts).first() + if not record: + return None, AnonymousUser() + + user = session.query(User).filter(User.ID == record.UsersID).first() + if not user: + raise AuthenticationError(f"Invalid User ID: {record.UsersID}") + + user.authenticated = True + return AuthCredentials(["authenticated"]), user + + +def auth_required(is_required: bool = True, + redirect: str = "/", + template: tuple = None): + """ Authentication route decorator. + + If redirect is given, the user will be redirected if the auth state + does not match is_required. + + If template is given, it will be rendered with Unauthorized if + is_required does not match and take priority over redirect. + + :param is_required: A boolean indicating whether the function requires auth + :param redirect: Path to redirect to if is_required isn't True + :param template: A template tuple: ("template.html", "Template Page") + """ + + def decorator(func): + @functools.wraps(func) + async def wrapper(request, *args, **kwargs): + if request.user.is_authenticated() != is_required: + status_code = int(HTTPStatus.UNAUTHORIZED) + url = "/" + if redirect: + status_code = int(HTTPStatus.SEE_OTHER) + url = redirect + if template: + path, title = template + context = make_context(request, title) + return render_template(request, path, context, + status_code=int(HTTPStatus.UNAUTHORIZED)) + return RedirectResponse(url=url, status_code=status_code) + return await func(request, *args, **kwargs) + return wrapper + + return decorator diff --git a/aurweb/models/user.py b/aurweb/models/user.py index ba91c439..aff4ce6b 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -1,13 +1,25 @@ +import hashlib + +from datetime import datetime + +import bcrypt + +from fastapi import Request from sqlalchemy.orm import backref, mapper, relationship +import aurweb.config + from aurweb.models.account_type import AccountType +from aurweb.models.ban import is_banned from aurweb.schema import Users class User: """ An ORM model of a single Users record. """ + authenticated = False def __init__(self, **kwargs): + # Set AccountTypeID if it was passed. self.AccountTypeID = kwargs.get("AccountTypeID") account_type = kwargs.get("AccountType") @@ -15,22 +27,129 @@ class User: self.AccountType = account_type self.Username = kwargs.get("Username") + + self.ResetKey = kwargs.get("ResetKey") self.Email = kwargs.get("Email") self.BackupEmail = kwargs.get("BackupEmail") - self.Passwd = kwargs.get("Passwd") - self.Salt = kwargs.get("Salt") self.RealName = kwargs.get("RealName") self.LangPreference = kwargs.get("LangPreference") self.Timezone = kwargs.get("Timezone") self.Homepage = kwargs.get("Homepage") self.IRCNick = kwargs.get("IRCNick") self.PGPKey = kwargs.get("PGPKey") - self.RegistrationTS = kwargs.get("RegistrationTS") + self.RegistrationTS = datetime.utcnow() self.CommentNotify = kwargs.get("CommentNotify") self.UpdateNotify = kwargs.get("UpdateNotify") self.OwnershipNotify = kwargs.get("OwnershipNotify") self.SSOAccountID = kwargs.get("SSOAccountID") + self.Salt = None + self.Passwd = str() + + passwd = kwargs.get("Passwd") + if passwd: + self.update_password(passwd) + + def update_password(self, password, salt_rounds=12): + from aurweb.db import session + self.Passwd = bcrypt.hashpw( + password.encode(), + bcrypt.gensalt(rounds=salt_rounds)).decode() + session.commit() + + @staticmethod + def minimum_passwd_length(): + return aurweb.config.getint("options", "passwd_min_len") + + def is_authenticated(self): + """ Return internal authenticated state. """ + return self.authenticated + + def valid_password(self, password: str): + """ Check authentication against a given password. """ + from aurweb.db import session + + if password is None: + return False + + password_is_valid = False + + try: + password_is_valid = bcrypt.checkpw(password.encode(), + self.Passwd.encode()) + except ValueError: + pass + + # If our Salt column is not empty, we're using a legacy password. + if not password_is_valid and self.Salt != str(): + # Try to login with legacy method. + password_is_valid = hashlib.md5( + f"{self.Salt}{password}".encode() + ).hexdigest() == self.Passwd + + # We got here, we passed the legacy authentication. + # Update the password to our modern hash style. + if password_is_valid: + self.update_password(password) + + return password_is_valid + + def _login_approved(self, request: Request): + return not is_banned(request) and not self.Suspended + + def login(self, request: Request, password: str, session_time=0): + """ Login and authenticate a request. """ + + from aurweb.db import session + from aurweb.models.session import Session, generate_unique_sid + + if not self._login_approved(request): + return None + + self.authenticated = self.valid_password(password) + if not self.authenticated: + return None + + self.LastLogin = now_ts = datetime.utcnow().timestamp() + self.LastLoginIPAddress = request.client.host + session.commit() + + session_ts = now_ts + ( + session_time if session_time + else aurweb.config.getint("options", "login_timeout") + ) + + sid = None + + if not self.session: + sid = generate_unique_sid() + self.session = Session(UsersID=self.ID, SessionID=sid, + LastUpdateTS=session_ts) + session.add(self.session) + else: + last_updated = self.session.LastUpdateTS + if last_updated and last_updated < now_ts: + self.session.SessionID = sid = generate_unique_sid() + else: + # Session is still valid; retrieve the current SID. + sid = self.session.SessionID + + self.session.LastUpdateTS = session_ts + + session.commit() + + request.cookies["AURSID"] = self.session.SessionID + return self.session.SessionID + + def logout(self, request): + from aurweb.db import session + + del request.cookies["AURSID"] + self.authenticated = False + if self.session: + session.delete(self.session) + session.commit() + def __repr__(self): return "" % ( self.ID, str(self.AccountType), self.Username) diff --git a/test/test_auth.py b/test/test_auth.py new file mode 100644 index 00000000..d2251de4 --- /dev/null +++ b/test/test_auth.py @@ -0,0 +1,80 @@ +from datetime import datetime + +import pytest + +from starlette.authentication import AuthenticationError + +from aurweb.db import query +from aurweb.auth import BasicAuthBackend +from aurweb.models.account_type import AccountType +from aurweb.testing import setup_test_db +from aurweb.testing.models import make_session, make_user +from aurweb.testing.requests import Request + +# Persistent user object, initialized in our setup fixture. +user = None +backend = None +request = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, backend, request + + setup_test_db("Users", "Sessions") + + from aurweb.db import session + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = make_user(Username="test", Email="test@example.com", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + session.add(user) + session.commit() + + backend = BasicAuthBackend() + request = Request() + + +@pytest.mark.asyncio +async def test_auth_backend_missing_sid(): + # The request has no AURSID cookie, so authentication fails, and + # AnonymousUser is returned. + _, result = await backend.authenticate(request) + assert not result.is_authenticated() + + +@pytest.mark.asyncio +async def test_auth_backend_invalid_sid(): + # Provide a fake AURSID that won't be found in the database. + # This results in our path going down the invalid sid route, + # which gives us an AnonymousUser. + request.cookies["AURSID"] = "fake" + _, result = await backend.authenticate(request) + assert not result.is_authenticated() + + +@pytest.mark.asyncio +async def test_auth_backend_invalid_user_id(): + # Create a new session with a fake user id. + now_ts = datetime.utcnow().timestamp() + make_session(UsersID=666, SessionID="realSession", + LastUpdateTS=now_ts + 5) + + # Here, we specify a real SID; but it's user is not there. + request.cookies["AURSID"] = "realSession" + with pytest.raises(AuthenticationError, match="Invalid User ID: 666"): + await backend.authenticate(request) + + +@pytest.mark.asyncio +async def test_basic_auth_backend(): + # This time, everything matches up. We expect the user to + # equal the real_user. + now_ts = datetime.utcnow().timestamp() + make_session(UsersID=user.ID, SessionID="realSession", + LastUpdateTS=now_ts + 5) + _, result = await backend.authenticate(request) + assert result == user diff --git a/test/test_user.py b/test/test_user.py index 5a56a035..b8d4248a 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -1,48 +1,86 @@ +import hashlib + +from datetime import datetime, timedelta + +import bcrypt import pytest +import aurweb.auth import aurweb.config from aurweb.db import query from aurweb.models.account_type import AccountType +from aurweb.models.ban import Ban +from aurweb.models.session import Session from aurweb.models.user import User from aurweb.testing import setup_test_db +from aurweb.testing.models import make_session, make_user +from aurweb.testing.requests import Request + +account_type, user = None, None @pytest.fixture(autouse=True) def setup(): - setup_test_db("Users") - - -def test_user(): - """ Test creating a user and reading its columns. """ from aurweb.db import session - # First, grab our target AccountType. + global account_type, user + + setup_test_db("Users", "Sessions", "Bans") + account_type = session.query(AccountType).filter( AccountType.AccountType == "User").first() - user = User( - AccountType=account_type, - RealName="Test User", Username="test", - Email="test@example.org", Passwd="abcd", - IRCNick="tester", - Salt="efgh", ResetKey="blahblah") - session.add(user) - session.commit() + user = make_user(Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + +def test_user_login_logout(): + """ Test creating a user and reading its columns. """ + from aurweb.db import session + + # Assert that make_user created a valid user. + assert bool(user.ID) + + # Test authentication. + assert user.valid_password("testPassword") + assert not user.valid_password("badPassword") + assert user in account_type.users - # Make sure the user was created and given an ID. - assert bool(user.ID) + # Make a raw request. + request = Request() + assert not user.login(request, "badPassword") + assert not user.is_authenticated() + + sid = user.login(request, "testPassword") + assert sid is not None + assert user.is_authenticated() + assert "AURSID" in request.cookies + + # Expect that User session relationships work right. + user_session = session.query(Session).filter( + Session.UsersID == user.ID).first() + assert user_session == user.session + assert user.session.SessionID == sid + assert user.session.User == user # Search for the user via query API. result = session.query(User).filter(User.ID == user.ID).first() # Compare the result and our original user. + assert result == user assert result.ID == user.ID assert result.AccountType.ID == user.AccountType.ID assert result.Username == user.Username assert result.Email == user.Email + # Test result authenticate methods to ensure they work the same. + assert not result.valid_password("badPassword") + assert result.valid_password("testPassword") + assert result.is_authenticated() + # Ensure we've got the correct account type. assert user.AccountType.ID == account_type.ID assert user.AccountType.AccountType == account_type.AccountType @@ -51,4 +89,74 @@ def test_user(): assert repr(user) == f"" - session.delete(user) + # Test logout. + user.logout(request) + assert "AURSID" not in request.cookies + assert not user.is_authenticated() + + +def test_user_login_twice(): + request = Request() + assert user.login(request, "testPassword") + assert user.login(request, "testPassword") + + +def test_user_login_banned(): + from aurweb.db import session + + # Add ban for the next 30 seconds. + banned_timestamp = datetime.utcnow() + timedelta(seconds=30) + ban = Ban(IPAddress="127.0.0.1", BanTS=banned_timestamp) + session.add(ban) + session.commit() + + request = Request() + request.client.host = "127.0.0.1" + assert not user.login(request, "testPassword") + + +def test_user_login_suspended(): + from aurweb.db import session + user.Suspended = True + session.commit() + assert not user.login(Request(), "testPassword") + + +def test_legacy_user_authentication(): + from aurweb.db import session + + user.Salt = bcrypt.gensalt().decode() + user.Passwd = hashlib.md5(f"{user.Salt}testPassword".encode()).hexdigest() + session.commit() + + assert not user.valid_password("badPassword") + assert user.valid_password("testPassword") + + # Test by passing a password of None value in. + assert not user.valid_password(None) + + +def test_user_login_with_outdated_sid(): + from aurweb.db import session + + # Make a session with a LastUpdateTS 5 seconds ago, causing + # user.login to update it with a new sid. + _session = make_session(UsersID=user.ID, SessionID="stub", + LastUpdateTS=datetime.utcnow().timestamp() - 5) + sid = user.login(Request(), "testPassword") + assert sid and user.is_authenticated() + assert sid != "stub" + + session.delete(_session) + session.commit() + + +def test_user_update_password(): + user.update_password("secondPassword") + assert not user.valid_password("testPassword") + assert user.valid_password("secondPassword") + + +def test_user_minimum_passwd_length(): + passwd_min_len = aurweb.config.getint("options", "passwd_min_len") + assert User.minimum_passwd_length() == passwd_min_len From 5d4a5deddf59806a691cda8d6933c7049b84db53 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 31 Dec 2020 20:44:59 -0800 Subject: [PATCH 0638/1891] implement login + logout routes and templates + Added route: GET `/login` via `aurweb.routers.auth.login_get` + Added route: POST `/login` via `aurweb.routers.auth.login_post` + Added route: GET `/logout` via `aurweb.routers.auth.logout` + Added route: POST `/logout` via `aurweb.routers.auth.logout_post` * Modify archdev-navbar.html template to toggle displays on auth state + Added login.html template Signed-off-by: Kevin Morris --- aurweb/asgi.py | 3 +- aurweb/routers/auth.py | 85 +++++++++++++++++ templates/login.html | 84 +++++++++++++++++ templates/partials/archdev-navbar.html | 18 +++- test/test_auth_routes.py | 126 +++++++++++++++++++++++++ 5 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 aurweb/routers/auth.py create mode 100644 templates/login.html create mode 100644 test/test_auth_routes.py diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 4d21ad03..b15e5874 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -11,7 +11,7 @@ import aurweb.config from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine -from aurweb.routers import html, sso, errors +from aurweb.routers import auth, html, sso, errors routes = set() @@ -42,6 +42,7 @@ async def app_startup(): # Add application routes. app.include_router(sso.router) app.include_router(html.router) + app.include_router(auth.router) # Initialize the database engine and ORM. get_engine() diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py new file mode 100644 index 00000000..24f5d4e3 --- /dev/null +++ b/aurweb/routers/auth.py @@ -0,0 +1,85 @@ +from datetime import datetime +from http import HTTPStatus + +from fastapi import APIRouter, Form, Request +from fastapi.responses import HTMLResponse, RedirectResponse + +import aurweb.config + +from aurweb.models.user import User +from aurweb.templates import make_context, render_template + +router = APIRouter() + + +def login_template(request: Request, next: str, errors: list = None): + """ Provide login-specific template context to render_template. """ + context = make_context(request, "Login", next) + context["errors"] = errors + context["url_base"] = f"{request.url.scheme}://{request.url.netloc}" + return render_template("login.html", context) + + +@router.get("/login", response_class=HTMLResponse) +async def login_get(request: Request, next: str = "/"): + """ Homepage route. """ + return login_template(request, next) + + +@router.post("/login", response_class=HTMLResponse) +async def login_post(request: Request, + next: str = Form(...), + user: str = Form(default=str()), + passwd: str = Form(default=str()), + remember_me: bool = Form(default=False)): + from aurweb.db import session + + user = session.query(User).filter(User.Username == user).first() + if not user: + return login_template(request, next, + errors=["Bad username or password."]) + + cookie_timeout = 0 + + if remember_me: + cookie_timeout = aurweb.config.getint( + "options", "persistent_cookie_timeout") + + _, sid = user.login(request, passwd, cookie_timeout) + if not _: + return login_template(request, next, + errors=["Bad username or password."]) + + login_timeout = aurweb.config.getint("options", "login_timeout") + + expires_at = int(datetime.utcnow().timestamp() + + max(cookie_timeout, login_timeout)) + + response = RedirectResponse(url=next, + status_code=int(HTTPStatus.SEE_OTHER)) + response.set_cookie("AURSID", sid, expires=expires_at) + return response + + +@router.get("/logout") +async def logout(request: Request, next: str = "/"): + """ A GET and POST route for logging out. + + @param request FastAPI request + @param next Route to redirect to + """ + if request.user.is_authenticated(): + request.user.logout(request) + + # Use 303 since we may be handling a post request, that'll get it + # to redirect to a get request. + response = RedirectResponse(url=next, + status_code=int(HTTPStatus.SEE_OTHER)) + response.delete_cookie("AURSID") + response.delete_cookie("AURTZ") + return response + + +@router.post("/logout") +async def logout_post(request: Request, next: str = "/"): + return await logout(request=request, next=next) diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 00000000..da7bd722 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,84 @@ +{% extends 'partials/layout.html' %} + +{% block pageContent %} + +
    +

    AUR {% trans %}Login{% endtrans %}

    + + {% if request.url.scheme == "http" and config.getboolean("options", "disable_http_login") %} + {% set https_login = url_base.replace("http://", "https://") + "/login/" %} +

    + {{ "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." + | tr + | format( + '' | format(https_login), + "") + | safe + }} +

    + {% else %} + {% if request.user.is_authenticated() %} +

    + {{ "Logged-in as: %s" + | tr + | format("%s" | format(request.user.Username)) + | safe + }} + [{% trans %}Logout{% endtrans %}] +

    + {% else %} +
    +
    + {% trans %}Enter login credentials{% endtrans %} + + {% if errors %} +
      + {% for error in errors %} +
    • {{ error }}
    • + {% endfor %} +
    + {% endif %} + +

    + + + +

    + +

    + + +

    + +

    + + +

    + +

    + + + [{% trans %}Forgot Password{% endtrans %}] + + + +

    + +
    + + {% endif %} + {% endif %} + +
    + +{% endblock %} diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index 55338bc4..7662e3a4 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -1,8 +1,22 @@ diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py new file mode 100644 index 00000000..adf75329 --- /dev/null +++ b/test/test_auth_routes.py @@ -0,0 +1,126 @@ +from datetime import datetime +from http import HTTPStatus + +import pytest + +from fastapi.testclient import TestClient + +import aurweb.config + +from aurweb.asgi import app +from aurweb.db import query +from aurweb.models.account_type import AccountType +from aurweb.models.session import Session +from aurweb.testing import setup_test_db +from aurweb.testing.models import make_user + +client = TestClient(app) + +user = None + + +@pytest.fixture(autouse=True) +def setup(): + global user + + setup_test_db("Users", "Sessions", "Bans") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = make_user(Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + +def test_login_logout(): + post_data = { + "user": "test", + "passwd": "testPassword", + "next": "/" + } + + with client as request: + response = client.get("/login") + assert response.status_code == int(HTTPStatus.OK) + + response = request.post("/login", data=post_data, + allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + response = request.get(response.headers.get("location"), cookies={ + "AURSID": response.cookies.get("AURSID") + }) + assert response.status_code == int(HTTPStatus.OK) + + response = request.post("/logout", data=post_data, + allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + response = request.post("/logout", data=post_data, cookies={ + "AURSID": response.cookies.get("AURSID") + }, allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert "AURSID" not in response.cookies + + +def test_login_missing_username(): + post_data = { + "passwd": "testPassword", + "next": "/" + } + + with client as request: + response = request.post("/login", data=post_data) + assert "AURSID" not in response.cookies + + +def test_login_remember_me(): + from aurweb.db import session + + post_data = { + "user": "test", + "passwd": "testPassword", + "next": "/", + "remember_me": True + } + + with client as request: + response = request.post("/login", data=post_data, + allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert "AURSID" in response.cookies + + cookie_timeout = aurweb.config.getint( + "options", "persistent_cookie_timeout") + expected_ts = datetime.utcnow().timestamp() + cookie_timeout + + _session = session.query(Session).filter( + Session.UsersID == user.ID).first() + + # Expect that LastUpdateTS was within 5 seconds of the expected_ts, + # which is equal to the current timestamp + persistent_cookie_timeout. + assert _session.LastUpdateTS > expected_ts - 5 + assert _session.LastUpdateTS < expected_ts + 5 + + +def test_login_missing_password(): + post_data = { + "user": "test", + "next": "/" + } + + with client as request: + response = request.post("/login", data=post_data) + assert "AURSID" not in response.cookies + + +def test_login_incorrect_password(): + post_data = { + "user": "test", + "passwd": "badPassword", + "next": "/" + } + + with client as request: + response = request.post("/login", data=post_data) + assert "AURSID" not in response.cookies From 4423326cec91dbfc9cd90294fc09ca40e917bc63 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 8 Jan 2021 20:24:22 -0800 Subject: [PATCH 0639/1891] add the request parameter to render_template This allows us to inspect things about the request we're rendering from. * Use render_template(request, ...) in aurweb.routers.auth Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 2 +- aurweb/routers/errors.py | 4 ++-- aurweb/routers/html.py | 2 +- aurweb/templates.py | 10 ++++++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 24f5d4e3..3a1c7192 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -17,7 +17,7 @@ def login_template(request: Request, next: str, errors: list = None): context = make_context(request, "Login", next) context["errors"] = errors context["url_base"] = f"{request.url.scheme}://{request.url.netloc}" - return render_template("login.html", context) + return render_template(request, "login.html", context) @router.get("/login", response_class=HTMLResponse) diff --git a/aurweb/routers/errors.py b/aurweb/routers/errors.py index 111d802a..eb935b57 100644 --- a/aurweb/routers/errors.py +++ b/aurweb/routers/errors.py @@ -3,12 +3,12 @@ from aurweb.templates import make_context, render_template async def not_found(request, exc): context = make_context(request, "Page Not Found") - return render_template("errors/404.html", context, 404) + return render_template(request, "errors/404.html", context, 404) async def service_unavailable(request, exc): context = make_context(request, "Service Unavailable") - return render_template("errors/503.html", context, 503) + return render_template(request, "errors/503.html", context, 503) # Maps HTTP errors to functions exceptions = { diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 50b62450..32a7e630 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -47,7 +47,7 @@ async def language(request: Request, async def index(request: Request): """ Homepage route. """ context = make_context(request, "Home") - return render_template("index.html", context) + return render_template(request, "index.html", context) # A route that returns a error 503. For testing purposes. diff --git a/aurweb/templates.py b/aurweb/templates.py index c05dce79..c5f378b8 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -39,7 +39,10 @@ def make_context(request: Request, title: str, next: str = None): } -def render_template(path: str, context: dict, status_code=int(HTTPStatus.OK)): +def render_template(request: Request, + path: str, + context: dict, + status_code=int(HTTPStatus.OK)): """ Render a Jinja2 multi-lingual template with some context. """ # Create a deep copy of our jinja2 environment. The environment in @@ -54,4 +57,7 @@ def render_template(path: str, context: dict, status_code=int(HTTPStatus.OK)): template = templates.get_template(path) rendered = template.render(context) - return HTMLResponse(rendered, status_code=status_code) + + response = HTMLResponse(rendered, status_code=status_code) + response.set_cookie("AURLANG", context.get("language")) + return response From a33d076d8bae9ab2e988aaa5bc3ab5d8eabd44d3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 6 Jan 2021 21:00:12 -0800 Subject: [PATCH 0640/1891] add passreset routes Introduced `get|post` `/passreset` routes. These routes mimic the behavior of the existing PHP implementation, with the exception of HTTP status code returns. Routes added: GET /passreset POST /passreset Routers added: aurweb.routers.accounts * On an unknown user or mismatched resetkey (where resetkey must == user.resetkey), return HTTP status NOT_FOUND (404). * On another error in the request, return HTTP status BAD_REQUEST (400). Both `get|post` routes requires that the current user is **not** authenticated, hence `@auth_required(False, redirect="/")`. + Added auth_required decorator to aurweb.auth. + Added some more utility to aurweb.models.user.User. + Added `partials/error.html` template. + Added `passreset.html` template. + Added aurweb.db.ConnectionExecutor functor for paramstyle logic. Decoupling the executor logic from the database connection logic is needed for us to easily use the same logic with a fastapi database session, when we need to use aurweb.scripts modules. At this point, notification configuration is now required to complete tests involved with notifications properly, like passreset. `conf/config.dev` has been modified to include [notifications] sendmail, sender and reply-to overrides. Dockerfile and .gitlab-ci.yml have been updated to setup /etc/hosts and start postfix before running tests. * setup.cfg: ignore E741, C901 in aurweb.routers.accounts These two warnings (shown in the commit) are not dangerous and a bi-product of maintaining compatibility with our current code flow. Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 + aurweb/asgi.py | 4 +- aurweb/db.py | 70 +++++++---- aurweb/routers/accounts.py | 102 ++++++++++++++++ aurweb/routers/auth.py | 10 +- conf/config.dev | 6 + setup.cfg | 13 ++ templates/partials/error.html | 15 +++ templates/passreset.html | 76 ++++++++++++ test/README.md | 5 + test/test_accounts_routes.py | 218 ++++++++++++++++++++++++++++++++++ test/test_auth_routes.py | 51 ++++++-- test/test_db.py | 13 +- test/test_user.py | 6 +- util/sendmail | 2 + 15 files changed, 552 insertions(+), 41 deletions(-) create mode 100644 aurweb/routers/accounts.py create mode 100644 templates/partials/error.html create mode 100644 templates/passreset.html create mode 100644 test/test_accounts_routes.py create mode 100755 util/sendmail diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4ad97393..db7dec9b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,6 +15,8 @@ before_script: python-itsdangerous python-httpx python-jinja python-pytest-cov python-requests python-aiofiles python-python-multipart python-pytest-asyncio python-coverage python-bcrypt + - bash -c "echo '127.0.0.1' > /etc/hosts" + - bash -c "echo '::1' >> /etc/hosts" test: script: diff --git a/aurweb/asgi.py b/aurweb/asgi.py index b15e5874..1a61b1f4 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -1,5 +1,4 @@ import http -import os from fastapi import FastAPI, HTTPException from fastapi.responses import HTMLResponse @@ -11,7 +10,7 @@ import aurweb.config from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine -from aurweb.routers import auth, html, sso, errors +from aurweb.routers import accounts, auth, errors, html, sso routes = set() @@ -43,6 +42,7 @@ async def app_startup(): app.include_router(sso.router) app.include_router(html.router) app.include_router(auth.router) + app.include_router(accounts.router) # Initialize the database engine and ORM. get_engine() diff --git a/aurweb/db.py b/aurweb/db.py index 3f5731a9..7dab6c4a 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -145,35 +145,21 @@ def connect(): return get_engine().connect() -class Connection: +class ConnectionExecutor: _conn = None _paramstyle = None - def __init__(self): - aur_db_backend = aurweb.config.get('database', 'backend') - - if aur_db_backend == 'mysql': + def __init__(self, conn, backend=aurweb.config.get("database", "backend")): + self._conn = conn + if backend == "mysql": import mysql.connector - aur_db_host = aurweb.config.get('database', 'host') - aur_db_name = aurweb.config.get('database', 'name') - aur_db_user = aurweb.config.get('database', 'user') - aur_db_pass = aurweb.config.get('database', 'password') - aur_db_socket = aurweb.config.get('database', 'socket') - self._conn = mysql.connector.connect(host=aur_db_host, - user=aur_db_user, - passwd=aur_db_pass, - db=aur_db_name, - unix_socket=aur_db_socket, - buffered=True) self._paramstyle = mysql.connector.paramstyle - elif aur_db_backend == 'sqlite': + elif backend == "sqlite": import sqlite3 - aur_db_name = aurweb.config.get('database', 'name') - self._conn = sqlite3.connect(aur_db_name) - self._conn.create_function("POWER", 2, math.pow) self._paramstyle = sqlite3.paramstyle - else: - raise ValueError('unsupported database backend') + + def paramstyle(self): + return self._paramstyle def execute(self, query, params=()): if self._paramstyle in ('format', 'pyformat'): @@ -193,3 +179,43 @@ class Connection: def close(self): self._conn.close() + + +class Connection: + _executor = None + _conn = None + + def __init__(self): + aur_db_backend = aurweb.config.get('database', 'backend') + + if aur_db_backend == 'mysql': + import mysql.connector + aur_db_host = aurweb.config.get('database', 'host') + aur_db_name = aurweb.config.get('database', 'name') + aur_db_user = aurweb.config.get('database', 'user') + aur_db_pass = aurweb.config.get('database', 'password') + aur_db_socket = aurweb.config.get('database', 'socket') + self._conn = mysql.connector.connect(host=aur_db_host, + user=aur_db_user, + passwd=aur_db_pass, + db=aur_db_name, + unix_socket=aur_db_socket, + buffered=True) + elif aur_db_backend == 'sqlite': + import sqlite3 + aur_db_name = aurweb.config.get('database', 'name') + self._conn = sqlite3.connect(aur_db_name) + self._conn.create_function("POWER", 2, math.pow) + else: + raise ValueError('unsupported database backend') + + self._conn = ConnectionExecutor(self._conn) + + def execute(self, query, params=()): + return self._conn.execute(query, params) + + def commit(self): + self._conn.commit() + + def close(self): + self._conn.close() diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py new file mode 100644 index 00000000..0839f64e --- /dev/null +++ b/aurweb/routers/accounts.py @@ -0,0 +1,102 @@ +from http import HTTPStatus + +from fastapi import APIRouter, Form, Request +from fastapi.responses import HTMLResponse, RedirectResponse +from sqlalchemy import or_ + +from aurweb import db +from aurweb.auth import auth_required +from aurweb.l10n import get_translator_for_request +from aurweb.models.user import User +from aurweb.scripts.notify import ResetKeyNotification +from aurweb.templates import make_context, render_template + +router = APIRouter() + + +@router.get("/passreset", response_class=HTMLResponse) +@auth_required(False) +async def passreset(request: Request): + context = make_context(request, "Password Reset") + + for k, v in request.query_params.items(): + context[k] = v + + return render_template(request, "passreset.html", context) + + +@router.post("/passreset", response_class=HTMLResponse) +@auth_required(False) +async def passreset_post(request: Request, + user: str = Form(...), + resetkey: str = Form(default=None), + password: str = Form(default=None), + confirm: str = Form(default=None)): + from aurweb.db import session + + context = make_context(request, "Password Reset") + + for k, v in dict(await request.form()).items(): + context[k] = v + + # The user parameter being required, we can match against + user = db.query(User, or_(User.Username == user, + User.Email == user)).first() + if not user: + context["errors"] = ["Invalid e-mail."] + return render_template(request, "passreset.html", context, + status_code=int(HTTPStatus.NOT_FOUND)) + + if resetkey: + context["resetkey"] = resetkey + + if not user.ResetKey or resetkey != user.ResetKey: + context["errors"] = ["Invalid e-mail."] + return render_template(request, "passreset.html", context, + status_code=int(HTTPStatus.NOT_FOUND)) + + if not user or not password: + context["errors"] = ["Missing a required field."] + return render_template(request, "passreset.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + + if password != confirm: + # If the provided password does not match the provided confirm. + context["errors"] = ["Password fields do not match."] + return render_template(request, "passreset.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + + if len(password) < User.minimum_passwd_length(): + # Translate the error here, which simplifies error output + # in the jinja2 template. + _ = get_translator_for_request(request) + context["errors"] = [_( + "Your password must be at least %s characters.") % ( + str(User.minimum_passwd_length()))] + return render_template(request, "passreset.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + + # We got to this point; everything matched up. Update the password + # and remove the ResetKey. + user.ResetKey = str() + user.update_password(password) + + if user.session: + session.delete(user.session) + session.commit() + + # Render ?step=complete. + return RedirectResponse(url="/passreset?step=complete", + status_code=int(HTTPStatus.SEE_OTHER)) + + # If we got here, we continue with issuing a resetkey for the user. + resetkey = db.make_random_value(User, User.ResetKey) + user.ResetKey = resetkey + session.commit() + + executor = db.ConnectionExecutor(db.get_engine().raw_connection()) + ResetKeyNotification(executor, user.ID).send() + + # Render ?step=confirm. + return RedirectResponse(url="/passreset?step=confirm", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 3a1c7192..e4864424 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -6,6 +6,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse import aurweb.config +from aurweb.auth import auth_required from aurweb.models.user import User from aurweb.templates import make_context, render_template @@ -21,12 +22,13 @@ def login_template(request: Request, next: str, errors: list = None): @router.get("/login", response_class=HTMLResponse) +@auth_required(False) async def login_get(request: Request, next: str = "/"): - """ Homepage route. """ return login_template(request, next) @router.post("/login", response_class=HTMLResponse) +@auth_required(False) async def login_post(request: Request, next: str = Form(...), user: str = Form(default=str()), @@ -45,8 +47,8 @@ async def login_post(request: Request, cookie_timeout = aurweb.config.getint( "options", "persistent_cookie_timeout") - _, sid = user.login(request, passwd, cookie_timeout) - if not _: + sid = user.login(request, passwd, cookie_timeout) + if not sid: return login_template(request, next, errors=["Bad username or password."]) @@ -62,6 +64,7 @@ async def login_post(request: Request, @router.get("/logout") +@auth_required() async def logout(request: Request, next: str = "/"): """ A GET and POST route for logging out. @@ -81,5 +84,6 @@ async def logout(request: Request, next: str = "/"): @router.post("/logout") +@auth_required() async def logout_post(request: Request, next: str = "/"): return await logout(request=request, next=next) diff --git a/conf/config.dev b/conf/config.dev index 194a3bf8..94775a92 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -25,6 +25,12 @@ disable_http_login = 0 enable-maintenance = 0 localedir = YOUR_AUR_ROOT/web/locale +[notifications] +; For development/testing, use /usr/bin/sendmail +sendmail = YOUR_AUR_ROOT/util/sendmail +sender = notify@localhost +reply-to = noreply@localhost + ; Single sign-on; see doc/sso.txt. [sso] openid_configuration = http://127.0.0.1:8083/auth/realms/aurweb/.well-known/openid-configuration diff --git a/setup.cfg b/setup.cfg index b868c096..98261651 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,6 +2,19 @@ max-line-length = 127 max-complexity = 10 +# Ignore some unavoidable flake8 warnings; we know this is against +# pycodestyle, but some of the existing codebase uses `I` variables, +# so specifically silence warnings about it in pre-defined files. +# In E741, the 'I', 'O', 'l' are ambiguous variable names. +# Our current implementation uses these variables through HTTP +# and the FastAPI form specification wants them named as such. +# In C901's case, our process_account_form function is way too +# complex for PEP (too many if statements). However, we need to +# process these anyways, and making it any more complex would +# just add confusion to the implementation. +per-file-ignores = + aurweb/routers/accounts.py:E741,C901 + [isort] line_length = 127 lines_between_types = 1 diff --git a/templates/partials/error.html b/templates/partials/error.html new file mode 100644 index 00000000..6043dfd1 --- /dev/null +++ b/templates/partials/error.html @@ -0,0 +1,15 @@ +{% if errors %} +
      + {% for error in errors %} + {% if error is string %} +
    • {{ error | tr | safe }}
    • + {% elif error is iterable %} +
        + {% for e in error %} +
      • {{ e | tr | safe }}
      • + {% endfor %} +
      + {% endif %} + {% endfor %} +
    +{% endif %} diff --git a/templates/passreset.html b/templates/passreset.html new file mode 100644 index 00000000..d2c3c2ee --- /dev/null +++ b/templates/passreset.html @@ -0,0 +1,76 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {% trans %}Password Reset{% endtrans %}

    + +

    + {% if step == "confirm" %} + {% trans %}Check your e-mail for the confirmation link.{% endtrans %} + {% elif step == "complete" %} + {% trans %}Your password has been reset successfully.{% endtrans %} + {% elif resetkey %} + + {% include "partials/error.html" %} + +
    +

    + + + + + + + + + + + + + + +
    {% trans %}Confirm your user name or primary e-mail address:{% endtrans %} + +
    {% trans %}Enter your new password:{% endtrans %} + +
    {% trans %}Confirm your new password:{% endtrans %} + +
    +
    + + + + {% else %} + + {% set url = "https://mailman.archlinux.org/mailman/listinfo/aur-general" %} + {{ "If you have forgotten the user name and the primary e-mail " + "address you used to register, please send a message to the " + "%saur-general%s mailing list." + | tr + | format( + '' | format(url), + "") + | safe + }} +

    + + {% include "partials/error.html" %} + +
    +

    + {% trans %}Enter your user name or your primary e-mail address:{% endtrans %} + +

    + +
    + {% endif %} +

    + +{% endblock %} diff --git a/test/README.md b/test/README.md index 3261899b..872d980b 100644 --- a/test/README.md +++ b/test/README.md @@ -27,6 +27,7 @@ For all the test to run, the following Arch packages should be installed: - python-pytest - python-pytest-cov - python-pytest-asyncio +- postfix Running tests ------------- @@ -37,6 +38,10 @@ First, setup the test configuration: $ sed -r 's;YOUR_AUR_ROOT;$(pwd);g' conf/config.dev > conf/config +You'll need to make sure that emails can be sent out by aurweb.scripts.notify. +If you don't have anything setup, just install postfix and start it before +running tests. + With those installed, one can run Python tests manually with any AUR config specified by `AUR_CONFIG`: diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py new file mode 100644 index 00000000..0f548805 --- /dev/null +++ b/test/test_accounts_routes.py @@ -0,0 +1,218 @@ +from http import HTTPStatus + +import pytest + +from fastapi.testclient import TestClient + +from aurweb.asgi import app +from aurweb.db import query +from aurweb.models.account_type import AccountType +from aurweb.models.session import Session +from aurweb.models.user import User +from aurweb.testing import setup_test_db +from aurweb.testing.models import make_user +from aurweb.testing.requests import Request + +# Some test global constants. +TEST_USERNAME = "test" +TEST_EMAIL = "test@example.org" + +# Global mutables. +client = TestClient(app) +user = None + + +@pytest.fixture(autouse=True) +def setup(): + global user + + setup_test_db("Users", "Sessions", "Bans") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = make_user(Username=TEST_USERNAME, Email=TEST_EMAIL, + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + +def test_get_passreset_authed_redirects(): + sid = user.login(Request(), "testPassword") + assert sid is not None + + with client as request: + response = request.get("/passreset", cookies={"AURSID": sid}, + allow_redirects=False) + + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/" + + +def test_get_passreset(): + with client as request: + response = request.get("/passreset") + assert response.status_code == int(HTTPStatus.OK) + + +def test_get_passreset_translation(): + # Test that translation works. + with client as request: + response = request.get("/passreset", cookies={"AURLANG": "de"}) + + # The header title should be translated. + assert "Passwort zurücksetzen".encode("utf-8") in response.content + + # The form input label should be translated. + assert "Benutzername oder primäre E-Mail-Adresse eingeben:".encode( + "utf-8") in response.content + + # And the button. + assert "Weiter".encode("utf-8") in response.content + + +def test_get_passreset_with_resetkey(): + with client as request: + response = request.get("/passreset", data={"resetkey": "abcd"}) + assert response.status_code == int(HTTPStatus.OK) + + +def test_post_passreset_authed_redirects(): + sid = user.login(Request(), "testPassword") + assert sid is not None + + with client as request: + response = request.post("/passreset", + cookies={"AURSID": sid}, + data={"user": "blah"}, + allow_redirects=False) + + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/" + + +def test_post_passreset_user(): + # With username. + with client as request: + response = request.post("/passreset", data={"user": TEST_USERNAME}) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/passreset?step=confirm" + + # With e-mail. + with client as request: + response = request.post("/passreset", data={"user": TEST_EMAIL}) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/passreset?step=confirm" + + +def test_post_passreset_resetkey(): + from aurweb.db import session + + user.session = Session(UsersID=user.ID, SessionID="blah", + LastUpdateTS=datetime.utcnow().timestamp()) + session.commit() + + # Prepare a password reset. + with client as request: + response = request.post("/passreset", data={"user": TEST_USERNAME}) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/passreset?step=confirm" + + # Now that we've prepared the password reset, prepare a POST + # request with the user's ResetKey. + resetkey = user.ResetKey + post_data = { + "user": TEST_USERNAME, + "resetkey": resetkey, + "password": "abcd1234", + "confirm": "abcd1234" + } + + with client as request: + response = request.post("/passreset", data=post_data) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/passreset?step=complete" + + +def test_post_passreset_error_invalid_email(): + # First, test with a user that doesn't even exist. + with client as request: + response = request.post("/passreset", data={"user": "invalid"}) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + error = "Invalid e-mail." + assert error in response.content.decode("utf-8") + + # Then, test with an invalid resetkey for a real user. + _ = make_resetkey() + post_data = make_passreset_data("fake") + post_data["password"] = "abcd1234" + post_data["confirm"] = "abcd1234" + + with client as request: + response = request.post("/passreset", data=post_data) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + assert error in response.content.decode("utf-8") + + +def make_resetkey(): + with client as request: + response = request.post("/passreset", data={"user": TEST_USERNAME}) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/passreset?step=confirm" + return user.ResetKey + + +def make_passreset_data(resetkey): + return { + "user": user.Username, + "resetkey": resetkey + } + + +def test_post_passreset_error_missing_field(): + # Now that we've prepared the password reset, prepare a POST + # request with the user's ResetKey. + resetkey = make_resetkey() + post_data = make_passreset_data(resetkey) + + with client as request: + response = request.post("/passreset", data=post_data) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + error = "Missing a required field." + assert error in response.content.decode("utf-8") + + +def test_post_passreset_error_password_mismatch(): + resetkey = make_resetkey() + post_data = make_passreset_data(resetkey) + + post_data["password"] = "abcd1234" + post_data["confirm"] = "mismatched" + + with client as request: + response = request.post("/passreset", data=post_data) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + error = "Password fields do not match." + assert error in response.content.decode("utf-8") + + +def test_post_passreset_error_password_requirements(): + resetkey = make_resetkey() + post_data = make_passreset_data(resetkey) + + passwd_min_len = User.minimum_passwd_length() + assert passwd_min_len >= 4 + + post_data["password"] = "x" + post_data["confirm"] = "x" + + with client as request: + response = request.post("/passreset", data=post_data) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + error = f"Your password must be at least {passwd_min_len} characters." + assert error in response.content.decode("utf-8") diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index adf75329..ff8a08e9 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -14,8 +14,12 @@ from aurweb.models.session import Session from aurweb.testing import setup_test_db from aurweb.testing.models import make_user -client = TestClient(app) +# Some test global constants. +TEST_USERNAME = "test" +TEST_EMAIL = "test@example.org" +# Global mutables. +client = TestClient(app) user = None @@ -27,7 +31,8 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.org", + + user = make_user(Username=TEST_USERNAME, Email=TEST_EMAIL, RealName="Test User", Passwd="testPassword", AccountType=account_type) @@ -40,16 +45,16 @@ def test_login_logout(): } with client as request: - response = client.get("/login") + # First, let's test get /login. + response = request.get("/login") assert response.status_code == int(HTTPStatus.OK) response = request.post("/login", data=post_data, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) - response = request.get(response.headers.get("location"), cookies={ - "AURSID": response.cookies.get("AURSID") - }) + # Simulate following the redirect location from above's response. + response = request.get(response.headers.get("location")) assert response.status_code == int(HTTPStatus.OK) response = request.post("/logout", data=post_data, @@ -60,9 +65,37 @@ def test_login_logout(): "AURSID": response.cookies.get("AURSID") }, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert "AURSID" not in response.cookies +def test_authenticated_login_forbidden(): + post_data = { + "user": "test", + "passwd": "testPassword", + "next": "/" + } + + with client as request: + # Login. + response = request.post("/login", data=post_data, + allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + # Now, let's verify that we receive 403 Forbidden when we + # try to get /login as an authenticated user. + response = request.get("/login", allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_unauthenticated_logout_unauthorized(): + with client as request: + # Alright, let's verify that attempting to /logout when not + # authenticated returns 401 Unauthorized. + response = request.get("/logout", allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + def test_login_missing_username(): post_data = { "passwd": "testPassword", @@ -75,8 +108,6 @@ def test_login_missing_username(): def test_login_remember_me(): - from aurweb.db import session - post_data = { "user": "test", "passwd": "testPassword", @@ -94,8 +125,8 @@ def test_login_remember_me(): "options", "persistent_cookie_timeout") expected_ts = datetime.utcnow().timestamp() + cookie_timeout - _session = session.query(Session).filter( - Session.UsersID == user.ID).first() + _session = query(Session, + Session.UsersID == user.ID).first() # Expect that LastUpdateTS was within 5 seconds of the expected_ts, # which is equal to the current timestamp + persistent_cookie_timeout. diff --git a/test/test_db.py b/test/test_db.py index 1eb0dc28..e0946ed5 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -3,7 +3,6 @@ import re import sqlite3 import tempfile -from datetime import datetime from unittest import mock import mysql.connector @@ -185,3 +184,15 @@ def test_create_delete(): db.delete(AccountType, AccountType.AccountType == "test") record = db.query(AccountType, AccountType.AccountType == "test").first() assert record is None + + +@mock.patch("mysql.connector.paramstyle", "qmark") +def test_connection_executor_mysql_paramstyle(): + executor = db.ConnectionExecutor(None, backend="mysql") + assert executor.paramstyle() == "qmark" + + +@mock.patch("sqlite3.paramstyle", "pyformat") +def test_connection_executor_sqlite_paramstyle(): + executor = db.ConnectionExecutor(None, backend="sqlite") + assert executor.paramstyle() == "pyformat" diff --git a/test/test_user.py b/test/test_user.py index b8d4248a..4f144819 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -28,8 +28,8 @@ def setup(): setup_test_db("Users", "Sessions", "Bans") - account_type = session.query(AccountType).filter( - AccountType.AccountType == "User").first() + account_type = query(AccountType, + AccountType.AccountType == "User").first() user = make_user(Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", @@ -67,7 +67,7 @@ def test_user_login_logout(): assert user.session.User == user # Search for the user via query API. - result = session.query(User).filter(User.ID == user.ID).first() + result = query(User, User.ID == user.ID).first() # Compare the result and our original user. assert result == user diff --git a/util/sendmail b/util/sendmail new file mode 100755 index 00000000..06bd9865 --- /dev/null +++ b/util/sendmail @@ -0,0 +1,2 @@ +#!/bin/bash +exit 0 From 9fdbe3f775a3d13e92a02a11e5eb4830e6daf875 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 8 Jan 2021 20:10:45 -0800 Subject: [PATCH 0641/1891] add authenticated User LangPreference tracking + Use User.LangPreference when there is no set AURSID if request.user.is_authenticated is true. + Updated post /language to update LangPreference when request.user.is_authenticated. + Restore language during test where we change it. + Added the user attribute to aurweb.testing.requests.Request. Signed-off-by: Kevin Morris --- aurweb/l10n.py | 12 ++++-------- aurweb/routers/html.py | 11 ++++++++++- aurweb/testing/requests.py | 19 +++++++++++++++++++ test/test_accounts_routes.py | 6 +++++- test/test_routes.py | 25 +++++++++++++++++++++---- 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/aurweb/l10n.py b/aurweb/l10n.py index 030ab274..4a5c1a46 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -64,8 +64,10 @@ translator = Translator() def get_request_language(request: Request): - return request.cookies.get("AURLANG", - aurweb.config.get("options", "default_lang")) + if request.user.is_authenticated(): + return request.user.LangPreference + default_lang = aurweb.config.get("options", "default_lang") + return request.cookies.get("AURLANG", default_lang) def get_raw_translator_for_request(request: Request): @@ -77,12 +79,6 @@ def get_translator_for_request(request: Request): """ Determine the preferred language from a FastAPI request object and build a translator function for it. - - Example: - ```python - _ = get_translator_for_request(request) - print(_("Hello")) - ``` """ lang = get_request_language(request) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 32a7e630..e947d213 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -24,12 +24,14 @@ async def language(request: Request, set_lang: str = Form(...), next: str = Form(...), q: str = Form(default=None)): - """ A POST route used to set a session's language. + """ + A POST route used to set a session's language. Return a 303 See Other redirect to {next}?next={next}. If we are setting the language on any page, we want to preserve query parameters across the redirect. """ + from aurweb.db import session from aurweb.asgi import routes if unquote(next) not in routes: return HTMLResponse( @@ -37,6 +39,13 @@ async def language(request: Request, status_code=400) query_string = "?" + q if q else str() + + # If the user is authenticated, update the user's LangPreference. + if request.user.is_authenticated(): + request.user.LangPreference = set_lang + session.commit() + + # In any case, set the response's AURLANG cookie that never expires. response = RedirectResponse(url=f"{next}{query_string}", status_code=int(HTTPStatus.SEE_OTHER)) response.set_cookie("AURLANG", set_lang) diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py index 2839c93f..2e64fd3d 100644 --- a/aurweb/testing/requests.py +++ b/aurweb/testing/requests.py @@ -1,8 +1,27 @@ +import aurweb.config + + +class User: + """ A fake User model. """ + # Fake columns. + LangPreference = aurweb.config.get("options", "default_lang") + + # A fake authenticated flag. + authenticated = False + + def is_authenticated(self): + return self.authenticated + + class Client: + """ A fake FastAPI Request.client object. """ + # A fake host. host = "127.0.0.1" class Request: + """ A fake Request object which mimics a FastAPI Request for tests. """ client = Client() cookies = dict() headers = dict() + user = User() diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 0f548805..69896a0f 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -54,7 +54,7 @@ def test_get_passreset(): def test_get_passreset_translation(): - # Test that translation works. + # Test that translation works; set it to de. with client as request: response = request.get("/passreset", cookies={"AURLANG": "de"}) @@ -68,6 +68,10 @@ def test_get_passreset_translation(): # And the button. assert "Weiter".encode("utf-8") in response.content + # Restore english. + with client as request: + response = request.get("/passreset", cookies={"AURLANG": "en"}) + def test_get_passreset_with_resetkey(): with client as request: diff --git a/test/test_routes.py b/test/test_routes.py index 950d9b71..d512a172 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -10,13 +10,14 @@ from aurweb.asgi import app from aurweb.db import query from aurweb.models.account_type import AccountType from aurweb.testing import setup_test_db +from aurweb.testing.models import make_user +from aurweb.testing.requests import Request client = TestClient(app) - user = None -@pytest.fixture +@pytest.fixture(autouse=True) def setup(): global user @@ -46,7 +47,7 @@ def test_favicon(): def test_language(): - """ Test the language post route at '/language'. """ + """ Test the language post route as a guest user. """ post_data = { "set_lang": "de", "next": "/" @@ -67,6 +68,23 @@ def test_language_invalid_next(): assert response.status_code == int(HTTPStatus.BAD_REQUEST) +def test_user_language(): + """ Test the language post route as an authenticated user. """ + post_data = { + "set_lang": "de", + "next": "/" + } + + sid = user.login(Request(), "testPassword") + assert sid is not None + + with client as req: + response = req.post("/language", data=post_data, + cookies={"AURSID": sid}) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert user.LangPreference == "de" + + def test_language_query_params(): """ Test the language post route with query params. """ next = urllib.parse.quote_plus("/") @@ -87,4 +105,3 @@ def test_error_messages(): response2 = client.get("/raisefivethree") assert response1.status_code == int(HTTPStatus.NOT_FOUND) assert response2.status_code == int(HTTPStatus.SERVICE_UNAVAILABLE) - From 670f711b593ed6c040ed3facb6212d327a3c38af Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 13 Jan 2021 06:46:30 -0800 Subject: [PATCH 0642/1891] add SSHPubKey ORM model Includes `aurweb.models.ssh_pub_key.get_fingerprint(pubkey)` helper. Signed-off-by: Kevin Morris --- aurweb/models/ssh_pub_key.py | 41 +++++++++++++++++++++++++ test/test_ssh_pub_key.py | 58 ++++++++++++++++++++++++++++++++++++ test/test_user.py | 20 ++++++++++++- 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 aurweb/models/ssh_pub_key.py create mode 100644 test/test_ssh_pub_key.py diff --git a/aurweb/models/ssh_pub_key.py b/aurweb/models/ssh_pub_key.py new file mode 100644 index 00000000..01ff558e --- /dev/null +++ b/aurweb/models/ssh_pub_key.py @@ -0,0 +1,41 @@ +import os +import tempfile + +from subprocess import PIPE, Popen + +from sqlalchemy.orm import backref, mapper, relationship + +from aurweb.models.user import User +from aurweb.schema import SSHPubKeys + + +class SSHPubKey: + def __init__(self, **kwargs): + self.UserID = kwargs.get("UserID") + self.Fingerprint = kwargs.get("Fingerprint") + self.PubKey = kwargs.get("PubKey") + + +def get_fingerprint(pubkey): + with tempfile.TemporaryDirectory() as tmpdir: + pk = os.path.join(tmpdir, "ssh.pub") + + with open(pk, "w") as f: + f.write(pubkey) + + proc = Popen(["ssh-keygen", "-l", "-f", pk], stdout=PIPE, stderr=PIPE) + out, err = proc.communicate() + + # Invalid SSH Public Key. Return None to the caller. + if proc.returncode != 0: + return None + + parts = out.decode().split() + fp = parts[1].replace("SHA256:", "") + + return fp + + +mapper(SSHPubKey, SSHPubKeys, properties={ + "User": relationship(User, backref=backref("ssh_pub_key", uselist=False)) +}) diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py new file mode 100644 index 00000000..fe9df047 --- /dev/null +++ b/test/test_ssh_pub_key.py @@ -0,0 +1,58 @@ +import pytest + +from aurweb.db import query +from aurweb.models.account_type import AccountType +from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint +from aurweb.testing import setup_test_db +from aurweb.testing.models import make_user + +TEST_SSH_PUBKEY = """ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCycoCi5yGCvSclH2wmNBUuwsYEzRZZBJaQquRc4ysl+Tg+/jiDkR3Zn9fIznC4KnFoyrIHzkKuePZ3bNDYwkZxkJKoWBCh4hXKDXSm87FMN0+VDC+1QxF/z0XaAGr/P6f4XukabyddypBdnHcZiplbw+YOSqcAE2TCqOlSXwNMOcF9U89UsR/Q9i9I52hlvU0q8+fZVGhou1KCowFSnHYtrr5KYJ04CXkJ13DkVf3+pjQWyrByvBcf1hGEaczlgfobrrv/y96jDhgfXucxliNKLdufDPPkii3LhhsNcDmmI1VZ3v0irKvd9WZuauqloobY84zEFcDTyjn0hxGjVeYFejm4fBnvjga0yZXORuWksdNfXWLDxFk6MDDd1jF0ExRbP+OxDuU4IVyIuDL7S3cnbf2YjGhkms/8voYT2OBE7FwNlfv98Kr0NUp51zpf55Arxn9j0Rz9xTA7FiODQgCn6iQ0SDtzUNL0IKTCw26xJY5gzMxbfpvzPQGeulx/ioM= kevr@volcano +""" + +user, ssh_pub_key = None, None + + +@pytest.fixture(autouse=True) +def setup(): + from aurweb.db import session + + global user, ssh_pub_key + + setup_test_db("Users", "SSHPubKeys") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = make_user(Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + assert account_type == user.AccountType + assert account_type.ID == user.AccountTypeID + + ssh_pub_key = SSHPubKey(UserID=user.ID, + Fingerprint="testFingerprint", + PubKey="testPubKey") + + session.add(ssh_pub_key) + session.commit() + + yield ssh_pub_key + + session.delete(ssh_pub_key) + session.commit() + + +def test_ssh_pub_key(): + assert ssh_pub_key.UserID == user.ID + assert ssh_pub_key.User == user + assert ssh_pub_key.Fingerprint == "testFingerprint" + assert ssh_pub_key.PubKey == "testPubKey" + + +def test_ssh_pub_key_fingerprint(): + assert get_fingerprint(TEST_SSH_PUBKEY) is not None + + +def test_ssh_pub_key_invalid_fingerprint(): + assert get_fingerprint("ssh-rsa fake and invalid") is None diff --git a/test/test_user.py b/test/test_user.py index 4f144819..473b035a 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -12,6 +12,7 @@ from aurweb.db import query from aurweb.models.account_type import AccountType from aurweb.models.ban import Ban from aurweb.models.session import Session +from aurweb.models.ssh_pub_key import SSHPubKey from aurweb.models.user import User from aurweb.testing import setup_test_db from aurweb.testing.models import make_session, make_user @@ -26,7 +27,7 @@ def setup(): global account_type, user - setup_test_db("Users", "Sessions", "Bans") + setup_test_db("Users", "Sessions", "Bans", "SSHPubKeys") account_type = query(AccountType, AccountType.AccountType == "User").first() @@ -160,3 +161,20 @@ def test_user_update_password(): def test_user_minimum_passwd_length(): passwd_min_len = aurweb.config.getint("options", "passwd_min_len") assert User.minimum_passwd_length() == passwd_min_len + + +def test_user_ssh_pub_key(): + from aurweb.db import session + + assert user.ssh_pub_key is None + + ssh_pub_key = SSHPubKey(UserID=user.ID, + Fingerprint="testFingerprint", + PubKey="testPubKey") + session.add(ssh_pub_key) + session.commit() + + assert user.ssh_pub_key == ssh_pub_key + + session.delete(ssh_pub_key) + session.commit() From 07d5907ecda5e93ebe44bd591a7f0ce87fb73cc2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 25 Jan 2021 16:30:47 -0800 Subject: [PATCH 0643/1891] aurweb.auth: add user credentials and matcher functions This clones the behavior already present in the PHP implementation, but it uses a global dict with credential constant keys to validation functions to determine if a given user has a credential. Signed-off-by: Kevin Morris --- aurweb/auth.py | 101 ++++++++++++++++++++++++++++++++++++++++++ aurweb/models/user.py | 5 +++ test/test_auth.py | 7 ++- test/test_user.py | 42 ++++++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 8608a82a..53c853de 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -17,6 +17,10 @@ class AnonymousUser: def is_authenticated(): return False + @staticmethod + def has_credential(credential): + return False + class BasicAuthBackend(AuthenticationBackend): async def authenticate(self, conn: HTTPConnection): @@ -75,3 +79,100 @@ def auth_required(is_required: bool = True, return wrapper return decorator + + +CRED_ACCOUNT_CHANGE_TYPE = 1 +CRED_ACCOUNT_EDIT = 2 +CRED_ACCOUNT_EDIT_DEV = 3 +CRED_ACCOUNT_LAST_LOGIN = 4 +CRED_ACCOUNT_SEARCH = 5 +CRED_ACCOUNT_LIST_COMMENTS = 28 +CRED_COMMENT_DELETE = 6 +CRED_COMMENT_UNDELETE = 27 +CRED_COMMENT_VIEW_DELETED = 22 +CRED_COMMENT_EDIT = 25 +CRED_COMMENT_PIN = 26 +CRED_PKGBASE_ADOPT = 7 +CRED_PKGBASE_SET_KEYWORDS = 8 +CRED_PKGBASE_DELETE = 9 +CRED_PKGBASE_DISOWN = 10 +CRED_PKGBASE_EDIT_COMAINTAINERS = 24 +CRED_PKGBASE_FLAG = 11 +CRED_PKGBASE_LIST_VOTERS = 12 +CRED_PKGBASE_NOTIFY = 13 +CRED_PKGBASE_UNFLAG = 15 +CRED_PKGBASE_VOTE = 16 +CRED_PKGREQ_FILE = 23 +CRED_PKGREQ_CLOSE = 17 +CRED_PKGREQ_LIST = 18 +CRED_TU_ADD_VOTE = 19 +CRED_TU_LIST_VOTES = 20 +CRED_TU_VOTE = 21 + + +def has_any(user, *account_types): + return str(user.AccountType) in set(account_types) + + +def user_developer_or_trusted_user(user): + return has_any(user, "User", "Trusted User", "Developer", + "Trusted User & Developer") + + +def trusted_user(user): + return has_any(user, "Trusted User", "Trusted User & Developer") + + +def developer(user): + return has_any(user, "Developer", "Trusted User & Developer") + + +def trusted_user_or_dev(user): + return has_any(user, "Trusted User", "Developer", + "Trusted User & Developer") + + +# A mapping of functions that users must pass to have credentials. +cred_filters = { + CRED_PKGBASE_FLAG: user_developer_or_trusted_user, + CRED_PKGBASE_NOTIFY: user_developer_or_trusted_user, + CRED_PKGBASE_VOTE: user_developer_or_trusted_user, + CRED_PKGREQ_FILE: user_developer_or_trusted_user, + CRED_ACCOUNT_CHANGE_TYPE: trusted_user_or_dev, + CRED_ACCOUNT_EDIT: trusted_user_or_dev, + CRED_ACCOUNT_LAST_LOGIN: trusted_user_or_dev, + CRED_ACCOUNT_LIST_COMMENTS: trusted_user_or_dev, + CRED_ACCOUNT_SEARCH: trusted_user_or_dev, + CRED_COMMENT_DELETE: trusted_user_or_dev, + CRED_COMMENT_UNDELETE: trusted_user_or_dev, + CRED_COMMENT_VIEW_DELETED: trusted_user_or_dev, + CRED_COMMENT_EDIT: trusted_user_or_dev, + CRED_COMMENT_PIN: trusted_user_or_dev, + CRED_PKGBASE_ADOPT: trusted_user_or_dev, + CRED_PKGBASE_SET_KEYWORDS: trusted_user_or_dev, + CRED_PKGBASE_DELETE: trusted_user_or_dev, + CRED_PKGBASE_EDIT_COMAINTAINERS: trusted_user_or_dev, + CRED_PKGBASE_DISOWN: trusted_user_or_dev, + CRED_PKGBASE_LIST_VOTERS: trusted_user_or_dev, + CRED_PKGBASE_UNFLAG: trusted_user_or_dev, + CRED_PKGREQ_CLOSE: trusted_user_or_dev, + CRED_PKGREQ_LIST: trusted_user_or_dev, + CRED_TU_ADD_VOTE: trusted_user, + CRED_TU_LIST_VOTES: trusted_user, + CRED_TU_VOTE: trusted_user, + CRED_ACCOUNT_EDIT_DEV: developer, +} + + +def has_credential(user: User, + credential: int, + approved_users: list = tuple()): + + if user in approved_users: + return True + + if credential in cred_filters: + cred_filter = cred_filters.get(credential) + return cred_filter(user) + + return False diff --git a/aurweb/models/user.py b/aurweb/models/user.py index aff4ce6b..3983e098 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -141,6 +141,11 @@ class User: request.cookies["AURSID"] = self.session.SessionID return self.session.SessionID + def has_credential(self, credential: str, approved: list = tuple()): + import aurweb.auth + cred = getattr(aurweb.auth, credential) + return aurweb.auth.has_credential(self, cred, approved) + def logout(self, request): from aurweb.db import session diff --git a/test/test_auth.py b/test/test_auth.py index d2251de4..d43459cd 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -4,8 +4,8 @@ import pytest from starlette.authentication import AuthenticationError +from aurweb.auth import BasicAuthBackend, has_credential from aurweb.db import query -from aurweb.auth import BasicAuthBackend from aurweb.models.account_type import AccountType from aurweb.testing import setup_test_db from aurweb.testing.models import make_session, make_user @@ -78,3 +78,8 @@ async def test_basic_auth_backend(): LastUpdateTS=now_ts + 5) _, result = await backend.authenticate(request) assert result == user + + +def test_has_fake_credential_fails(): + # Fake credential 666 does not exist. + assert not has_credential(user, 666) diff --git a/test/test_user.py b/test/test_user.py index 473b035a..e8056681 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -163,6 +163,11 @@ def test_user_minimum_passwd_length(): assert User.minimum_passwd_length() == passwd_min_len +def test_user_has_credential(): + assert user.has_credential("CRED_PKGBASE_FLAG") + assert not user.has_credential("CRED_ACCOUNT_CHANGE_TYPE") + + def test_user_ssh_pub_key(): from aurweb.db import session @@ -178,3 +183,40 @@ def test_user_ssh_pub_key(): session.delete(ssh_pub_key) session.commit() + + +def test_user_credential_types(): + from aurweb.db import session + + assert aurweb.auth.user_developer_or_trusted_user(user) + assert not aurweb.auth.trusted_user(user) + assert not aurweb.auth.developer(user) + assert not aurweb.auth.trusted_user_or_dev(user) + + trusted_user_type = query(AccountType, + AccountType.AccountType == "Trusted User")\ + .first() + user.AccountType = trusted_user_type + session.commit() + + assert aurweb.auth.trusted_user(user) + assert aurweb.auth.trusted_user_or_dev(user) + + developer_type = query(AccountType, + AccountType.AccountType == "Developer")\ + .first() + user.AccountType = developer_type + session.commit() + + assert aurweb.auth.developer(user) + assert aurweb.auth.trusted_user_or_dev(user) + + type_str = "Trusted User & Developer" + elevated_type = query(AccountType, + AccountType.AccountType == type_str).first() + user.AccountType = elevated_type + session.commit() + + assert aurweb.auth.trusted_user(user) + assert aurweb.auth.developer(user) + assert aurweb.auth.trusted_user_or_dev(user) From 9052688ed247bccda516ffa84183b7ed442f0a04 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 25 Jan 2021 16:52:14 -0800 Subject: [PATCH 0644/1891] add aurweb.time module This module includes timezone-based utilities for a FastAPI request. This commit introduces use of the AURTZ cookie within get_request_timezone. This cookie should be set to the user or session's timezone. * `make_context` has been modified to parse the request's timezone and include the "timezone" and "timezones" variables, along with a timezone specified "now" date. + Added `Timezone` attribute to aurweb.testing.requests.Request.user. Signed-off-by: Kevin Morris --- aurweb/templates.py | 11 ++++--- aurweb/testing/requests.py | 1 + aurweb/time.py | 63 ++++++++++++++++++++++++++++++++++++++ test/test_time.py | 33 ++++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 aurweb/time.py create mode 100644 test/test_time.py diff --git a/aurweb/templates.py b/aurweb/templates.py index c5f378b8..564f3149 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -1,5 +1,6 @@ import copy import os +import zoneinfo from datetime import datetime from http import HTTPStatus @@ -11,7 +12,7 @@ from fastapi.responses import HTMLResponse import aurweb.config -from aurweb import l10n +from aurweb import l10n, time # Prepare jinja2 objects. loader = jinja2.FileSystemLoader(os.path.join( @@ -26,14 +27,15 @@ env.filters["tr"] = l10n.tr def make_context(request: Request, title: str, next: str = None): """ Create a context for a jinja2 TemplateResponse. """ + timezone = time.get_request_timezone(request) return { "request": request, "language": l10n.get_request_language(request), "languages": l10n.SUPPORTED_LANGUAGES, + "timezone": timezone, + "timezones": time.SUPPORTED_TIMEZONES, "title": title, - # The 'now' context variable will not show proper datetimes - # until we've implemented timezone support here. - "now": datetime.now(), + "now": datetime.now(tz=zoneinfo.ZoneInfo(timezone)), "config": aurweb.config, "next": next if next else request.url.path } @@ -60,4 +62,5 @@ def render_template(request: Request, response = HTMLResponse(rendered, status_code=status_code) response.set_cookie("AURLANG", context.get("language")) + response.set_cookie("AURTZ", context.get("timezone")) return response diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py index 2e64fd3d..9976b6fb 100644 --- a/aurweb/testing/requests.py +++ b/aurweb/testing/requests.py @@ -5,6 +5,7 @@ class User: """ A fake User model. """ # Fake columns. LangPreference = aurweb.config.get("options", "default_lang") + Timezone = aurweb.config.get("options", "default_timezone") # A fake authenticated flag. authenticated = False diff --git a/aurweb/time.py b/aurweb/time.py new file mode 100644 index 00000000..0b1dff11 --- /dev/null +++ b/aurweb/time.py @@ -0,0 +1,63 @@ +import zoneinfo + +from collections import OrderedDict +from datetime import datetime + +from fastapi import Request + +import aurweb.config + + +def tz_offset(name: str): + """ Get a timezone offset in the form "+00:00" by its name. + + Example: tz_offset('America/Los_Angeles') + + :param name: Timezone name + :return: UTC offset in the form "+00:00" + """ + dt = datetime.now(tz=zoneinfo.ZoneInfo(name)) + + # Our offset in hours. + offset = dt.utcoffset().total_seconds() / 60 / 60 + + # Prefix the offset string with a - or +. + offset_string = '-' if offset < 0 else '+' + + # Remove any negativity from the offset. We want a good offset. :) + offset = abs(offset) + + # Truncate the floating point digits, giving the hours. + hours = int(offset) + + # Subtract hours from the offset, and multiply the remaining fraction + # (0 - 0.99[repeated]) with 60 minutes to get the number of minutes + # remaining in the hour. + minutes = int((offset - hours) * 60) + + # Pad the hours and minutes by two places. + offset_string += "{:0>2}:{:0>2}".format(hours, minutes) + return offset_string + + +SUPPORTED_TIMEZONES = OrderedDict({ + # Flatten out the list of tuples into an OrderedDict. + timezone: offset for timezone, offset in sorted([ + # Comprehend a list of tuples (timezone, offset display string) + # and sort them by (offset, timezone). + (tz, "(UTC%s) %s" % (tz_offset(tz), tz)) + for tz in zoneinfo.available_timezones() + ], key=lambda element: (tz_offset(element[0]), element[0])) +}) + + +def get_request_timezone(request: Request): + """ Get a request's timezone by its AURTZ cookie. We use the + configuration's [options] default_timezone otherwise. + + @param request FastAPI request + """ + if request.user.is_authenticated(): + return request.user.Timezone + default_tz = aurweb.config.get("options", "default_timezone") + return request.cookies.get("AURTZ", default_tz) diff --git a/test/test_time.py b/test/test_time.py new file mode 100644 index 00000000..2134d217 --- /dev/null +++ b/test/test_time.py @@ -0,0 +1,33 @@ +import aurweb.config + +from aurweb.testing.requests import Request +from aurweb.time import get_request_timezone, tz_offset + + +def test_tz_offset_utc(): + offset = tz_offset("UTC") + assert offset == "+00:00" + + +def test_tz_offset_mst(): + offset = tz_offset("MST") + assert offset == "-07:00" + + +def test_request_timezone(): + request = Request() + tz = get_request_timezone(request) + assert tz == aurweb.config.get("options", "default_timezone") + + +def test_authenticated_request_timezone(): + # Modify a fake request to be authenticated with the + # America/Los_Angeles timezone. + request = Request() + request.user.authenticated = True + request.user.Timezone = "America/Los_Angeles" + + # Get the request's timezone, it should be America/Los_Angeles. + tz = get_request_timezone(request) + assert tz == request.user.Timezone + assert tz == "America/Los_Angeles" From a5be6fc9beaa8a195b9c8e382d25b5bb51225412 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 27 Jan 2021 18:30:57 -0800 Subject: [PATCH 0645/1891] aurweb.templates: add make_variable_context A new make_context wrapper which additionally includes either query parameters (get) or form data (post) in the context. Use this to simplify setting context variables for form data in particular. Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 13 +++---------- aurweb/templates.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 0839f64e..db23bc3a 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -9,7 +9,7 @@ from aurweb.auth import auth_required from aurweb.l10n import get_translator_for_request from aurweb.models.user import User from aurweb.scripts.notify import ResetKeyNotification -from aurweb.templates import make_context, render_template +from aurweb.templates import make_variable_context, render_template router = APIRouter() @@ -17,11 +17,7 @@ router = APIRouter() @router.get("/passreset", response_class=HTMLResponse) @auth_required(False) async def passreset(request: Request): - context = make_context(request, "Password Reset") - - for k, v in request.query_params.items(): - context[k] = v - + context = await make_variable_context(request, "Password Reset") return render_template(request, "passreset.html", context) @@ -34,10 +30,7 @@ async def passreset_post(request: Request, confirm: str = Form(default=None)): from aurweb.db import session - context = make_context(request, "Password Reset") - - for k, v in dict(await request.form()).items(): - context[k] = v + context = await make_variable_context(request, "Password Reset") # The user parameter being required, we can match against user = db.query(User, or_(User.Username == user, diff --git a/aurweb/templates.py b/aurweb/templates.py index 564f3149..4ea74a62 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -41,6 +41,20 @@ def make_context(request: Request, title: str, next: str = None): } +async def make_variable_context(request: Request, title: str, next: str = None): + """ Make a context with variables provided by the user + (query params via GET or form data via POST). """ + context = make_context(request, title, next) + to_copy = dict(request.query_params) \ + if request.method.lower() == "get" \ + else dict(await request.form()) + + for k, v in to_copy.items(): + context[k] = v + + return context + + def render_template(request: Request, path: str, context: dict, From 7a6a38592e63db1ca8a5a1748458afe659d5be3f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 27 Jan 2021 18:36:06 -0800 Subject: [PATCH 0646/1891] add python-email-validator dependency Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 1 + Dockerfile | 3 ++- INSTALL | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index db7dec9b..f1fe5e6f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,6 +15,7 @@ before_script: python-itsdangerous python-httpx python-jinja python-pytest-cov python-requests python-aiofiles python-python-multipart python-pytest-asyncio python-coverage python-bcrypt + python-email-validator - bash -c "echo '127.0.0.1' > /etc/hosts" - bash -c "echo '::1' >> /etc/hosts" diff --git a/Dockerfile b/Dockerfile index 6638f9a2..f65acc7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,8 @@ RUN pacman -Syu --noconfirm base-devel git gpgme protobuf pyalpm \ python-werkzeug python-pytest-tap python-fastapi nginx python-authlib \ python-itsdangerous python-httpx python-jinja python-pytest-cov \ python-requests python-aiofiles python-python-multipart \ - python-pytest-asyncio python-coverage hypercorn python-bcrypt + python-pytest-asyncio python-coverage hypercorn python-bcrypt \ + python-email-validator # Remove aurweb.sqlite3 if it was copied over via COPY. RUN rm -fv aurweb.sqlite3 diff --git a/INSTALL b/INSTALL index 6c43fec8..04ccd69e 100644 --- a/INSTALL +++ b/INSTALL @@ -51,7 +51,7 @@ read the instructions below. python-bleach python-markdown python-alembic hypercorn \ python-itsdangerous python-authlib python-httpx \ python-jinja python-aiofiles python-python-multipart \ - python-requests hypercorn python-bcrypt + python-requests hypercorn python-bcrypt python-email-validator # python3 setup.py install 5) Create a new MySQL database and a user and import the aurweb SQL schema: From df0a637d2b5da4a2fc6dae0c7f07bcd7f50e4828 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 28 Jan 2021 16:52:56 -0800 Subject: [PATCH 0647/1891] add aurweb.captcha, a CAPTCHA utility module This CAPTCHA workflow is the same workflow used by our current PHP implementation of account registration. Signed-off-by: Kevin Morris --- aurweb/captcha.py | 54 +++++++++++++++++++++++++++++++++++++++ aurweb/templates.py | 6 ++++- test/test_captcha.py | 60 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 aurweb/captcha.py create mode 100644 test/test_captcha.py diff --git a/aurweb/captcha.py b/aurweb/captcha.py new file mode 100644 index 00000000..5475d85f --- /dev/null +++ b/aurweb/captcha.py @@ -0,0 +1,54 @@ +""" This module consists of aurweb's CAPTCHA utility functions and filters. """ +import hashlib + +import jinja2 + +from aurweb.db import query +from aurweb.models.user import User + + +def get_captcha_salts(): + """ Produce salts based on the current user count. """ + count = query(User).count() + salts = [] + for i in range(0, 6): + salts.append(f"aurweb-{count - i}") + return salts + + +def get_captcha_token(salt): + """ Produce a token for the CAPTCHA salt. """ + return hashlib.md5(salt.encode()).hexdigest()[:3] + + +def get_captcha_challenge(salt): + """ Get a CAPTCHA challenge string (shell command) for a salt. """ + token = get_captcha_token(salt) + return f"LC_ALL=C pacman -V|sed -r 's#[0-9]+#{token}#g'|md5sum|cut -c1-6" + + +def get_captcha_answer(token): + """ Compute the answer via md5 of the real template text, return the + first six digits of the hexadecimal hash. """ + text = r""" + .--. Pacman v%s.%s.%s - libalpm v%s.%s.%s +/ _.-' .-. .-. .-. Copyright (C) %s-%s Pacman Development Team +\ '-. '-' '-' '-' Copyright (C) %s-%s Judd Vinet + '--' + This program may be freely redistributed under + the terms of the GNU General Public License. +""" % tuple([token] * 10) + return hashlib.md5((text + "\n").encode()).hexdigest()[:6] + + +@jinja2.contextfilter +def captcha_salt_filter(context): + """ Returns the most recent CAPTCHA salt in the list of salts. """ + salts = get_captcha_salts() + return salts[0] + + +@jinja2.contextfilter +def captcha_cmdline_filter(context, salt): + """ Returns a CAPTCHA challenge for a given salt. """ + return get_captcha_challenge(salt) diff --git a/aurweb/templates.py b/aurweb/templates.py index 4ea74a62..d548e92b 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -12,7 +12,7 @@ from fastapi.responses import HTMLResponse import aurweb.config -from aurweb import l10n, time +from aurweb import captcha, l10n, time # Prepare jinja2 objects. loader = jinja2.FileSystemLoader(os.path.join( @@ -23,6 +23,10 @@ env = jinja2.Environment(loader=loader, autoescape=True, # Add tr translation filter. env.filters["tr"] = l10n.tr +# Add captcha filters. +env.filters["captcha_salt"] = captcha.captcha_salt_filter +env.filters["captcha_cmdline"] = captcha.captcha_cmdline_filter + def make_context(request: Request, title: str, next: str = None): """ Create a context for a jinja2 TemplateResponse. """ diff --git a/test/test_captcha.py b/test/test_captcha.py new file mode 100644 index 00000000..ec19dee9 --- /dev/null +++ b/test/test_captcha.py @@ -0,0 +1,60 @@ +import hashlib + +from aurweb import captcha + + +def test_captcha_salts(): + """ Make sure we can get some captcha salts. """ + salts = captcha.get_captcha_salts() + assert len(salts) == 6 + + +def test_captcha_token(): + """ Make sure getting a captcha salt's token matches up against + the first three digits of the md5 hash of the salt. """ + salts = captcha.get_captcha_salts() + salt = salts[0] + + token1 = captcha.get_captcha_token(salt) + token2 = hashlib.md5(salt.encode()).hexdigest()[:3] + + assert token1 == token2 + + +def test_captcha_challenge_answer(): + """ Make sure that executing the captcha challenge via shell + produces the correct result by comparing it against a straight + up token conversion. """ + salts = captcha.get_captcha_salts() + salt = salts[0] + + challenge = captcha.get_captcha_challenge(salt) + + token = captcha.get_captcha_token(salt) + challenge2 = f"LC_ALL=C pacman -V|sed -r 's#[0-9]+#{token}#g'|md5sum|cut -c1-6" + + assert challenge == challenge2 + + +def test_captcha_salt_filter(): + """ Make sure captcha_salt_filter returns the first salt from + get_captcha_salts(). + + Example usage: + + """ + salt = captcha.captcha_salt_filter(None) + assert salt == captcha.get_captcha_salts()[0] + + +def test_captcha_cmdline_filter(): + """ Make sure that the captcha_cmdline filter gives us the + same challenge that get_captcha_challenge does. + + Example usage: + {{ captcha_salt | captcha_cmdline }} + """ + salt = captcha.captcha_salt_filter(None) + display1 = captcha.captcha_cmdline_filter(None, salt) + display2 = captcha.get_captcha_challenge(salt) + assert display1 == display2 From 19b4a896f111c34fcf57a5d6fb0b40cd9ad43e51 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Jan 2021 02:08:59 -0800 Subject: [PATCH 0648/1891] add openssh to test dependencies Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 +- Dockerfile | 2 +- test/README.md | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f1fe5e6f..58fb9fed 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,7 +15,7 @@ before_script: python-itsdangerous python-httpx python-jinja python-pytest-cov python-requests python-aiofiles python-python-multipart python-pytest-asyncio python-coverage python-bcrypt - python-email-validator + python-email-validator openssh - bash -c "echo '127.0.0.1' > /etc/hosts" - bash -c "echo '::1' >> /etc/hosts" diff --git a/Dockerfile b/Dockerfile index f65acc7c..cf54a13c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN pacman -Syu --noconfirm base-devel git gpgme protobuf pyalpm \ python-itsdangerous python-httpx python-jinja python-pytest-cov \ python-requests python-aiofiles python-python-multipart \ python-pytest-asyncio python-coverage hypercorn python-bcrypt \ - python-email-validator + python-email-validator openssh # Remove aurweb.sqlite3 if it was copied over via COPY. RUN rm -fv aurweb.sqlite3 diff --git a/test/README.md b/test/README.md index 872d980b..0f3f4cbd 100644 --- a/test/README.md +++ b/test/README.md @@ -28,6 +28,7 @@ For all the test to run, the following Arch packages should be installed: - python-pytest-cov - python-pytest-asyncio - postfix +- openssh Running tests ------------- From c94793b0b11b372a299fb6d23e39562066b7531b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 28 Jan 2021 20:26:34 -0800 Subject: [PATCH 0649/1891] add user registration routes * Added /register get and post routes. + Added default attributes to AnonymousUser, including a new AnonymousList which behaves like an sqlalchemy relationship list. + aurweb.util: Added validation functions for various user fields used throughout registration. + test_accounts_routes: Added get|post register route tests. Signed-off-by: Kevin Morris --- aurweb/auth.py | 10 + aurweb/routers/accounts.py | 320 +++++++++++++++++++++++- aurweb/util.py | 84 +++++++ templates/partials/account_form.html | 343 ++++++++++++++++++++++++++ templates/register.html | 30 +++ test/test_accounts_routes.py | 356 ++++++++++++++++++++++++++- 6 files changed, 1140 insertions(+), 3 deletions(-) create mode 100644 templates/partials/account_form.html create mode 100644 templates/register.html diff --git a/aurweb/auth.py b/aurweb/auth.py index 53c853de..a4ff2167 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -7,12 +7,22 @@ from fastapi.responses import RedirectResponse from starlette.authentication import AuthCredentials, AuthenticationBackend, AuthenticationError from starlette.requests import HTTPConnection +import aurweb.config + from aurweb.models.session import Session from aurweb.models.user import User from aurweb.templates import make_context, render_template class AnonymousUser: + # Stub attributes used to mimic a real user. + ID = 0 + LangPreference = aurweb.config.get("options", "default_lang") + Timezone = aurweb.config.get("options", "default_timezone") + + # A stub ssh_pub_key relationship. + ssh_pub_key = None + @staticmethod def is_authenticated(): return False diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index db23bc3a..a43ba9f7 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -1,12 +1,20 @@ +import copy + from http import HTTPStatus from fastapi import APIRouter, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse -from sqlalchemy import or_ +from sqlalchemy import and_, func, or_ -from aurweb import db +import aurweb.config + +from aurweb import db, l10n, time, util from aurweb.auth import auth_required +from aurweb.captcha import get_captcha_answer, get_captcha_salts, get_captcha_token from aurweb.l10n import get_translator_for_request +from aurweb.models.account_type import AccountType +from aurweb.models.ban import Ban +from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.user import User from aurweb.scripts.notify import ResetKeyNotification from aurweb.templates import make_variable_context, render_template @@ -93,3 +101,311 @@ async def passreset_post(request: Request, # Render ?step=confirm. return RedirectResponse(url="/passreset?step=confirm", status_code=int(HTTPStatus.SEE_OTHER)) + + +def process_account_form(request: Request, user: User, args: dict): + """ Process an account form. All fields are optional and only checks + requirements in the case they are present. + + ``` + context = await make_variable_context(request, "Accounts") + ok, errors = process_account_form(request, user, **kwargs) + if not ok: + context["errors"] = errors + return render_template(request, "some_account_template.html", context) + ``` + + :param request: An incoming FastAPI request + :param user: The user model of the account being processed + :param args: A dictionary of arguments generated via request.form() + :return: A (passed processing boolean, list of errors) tuple + """ + + # Get a local translator. + _ = get_translator_for_request(request) + + host = request.client.host + ban = db.query(Ban, Ban.IPAddress == host).first() + if ban: + return False, [ + "Account registration has been disabled for your " + + "IP address, probably due to sustained spam attacks. " + + "Sorry for the inconvenience." + ] + + if request.user.is_authenticated(): + if not request.user.valid_password(args.get("passwd", None)): + return False, ["Invalid password."] + + email = args.get("E", None) + username = args.get("U", None) + + if not email or not username: + return False, ["Missing a required field."] + + username_min_len = aurweb.config.getint("options", "username_min_len") + username_max_len = aurweb.config.getint("options", "username_max_len") + if not util.valid_username(args.get("U")): + return False, [ + "The username is invalid.", + [ + _("It must be between %s and %s characters long") % ( + username_min_len, username_max_len), + "Start and end with a letter or number", + "Can contain only one period, underscore or hyphen.", + ] + ] + + password = args.get("P", None) + if password: + confirmation = args.get("C", None) + if not util.valid_password(password): + return False, [ + _("Your password must be at least %s characters.") % ( + username_min_len) + ] + elif not confirmation: + return False, ["Please confirm your new password."] + elif password != confirmation: + return False, ["Password fields do not match."] + + backup_email = args.get("BE", None) + homepage = args.get("HP", None) + pgp_key = args.get("K", None) + ssh_pubkey = args.get("PK", None) + language = args.get("L", None) + timezone = args.get("TZ", None) + + def username_exists(username): + return and_(User.ID != user.ID, + func.lower(User.Username) == username.lower()) + + def email_exists(email): + return and_(User.ID != user.ID, + func.lower(User.Email) == email.lower()) + + if not util.valid_email(email): + return False, ["The email address is invalid."] + elif backup_email and not util.valid_email(backup_email): + return False, ["The backup email address is invalid."] + elif homepage and not util.valid_homepage(homepage): + return False, [ + "The home page is invalid, please specify the full HTTP(s) URL."] + elif pgp_key and not util.valid_pgp_fingerprint(pgp_key): + return False, ["The PGP key fingerprint is invalid."] + elif ssh_pubkey and not util.valid_ssh_pubkey(ssh_pubkey): + return False, ["The SSH public key is invalid."] + elif language and language not in l10n.SUPPORTED_LANGUAGES: + return False, ["Language is not currently supported."] + elif timezone and timezone not in time.SUPPORTED_TIMEZONES: + return False, ["Timezone is not currently supported."] + elif db.query(User, username_exists(username)).first(): + # If the username already exists... + return False, [ + _("The username, %s%s%s, is already in use.") % ( + "", username, "") + ] + elif db.query(User, email_exists(email)).first(): + # If the email already exists... + return False, [ + _("The address, %s%s%s, is already in use.") % ( + "", email, "") + ] + + def ssh_fingerprint_exists(fingerprint): + return and_(SSHPubKey.UserID != user.ID, + SSHPubKey.Fingerprint == fingerprint) + + if ssh_pubkey: + fingerprint = get_fingerprint(ssh_pubkey.strip().rstrip()) + if fingerprint is None: + return False, ["The SSH public key is invalid."] + + if db.query(SSHPubKey, ssh_fingerprint_exists(fingerprint)).first(): + return False, [ + _("The SSH public key, %s%s%s, is already in use.") % ( + "", fingerprint, "") + ] + + captcha_salt = args.get("captcha_salt", None) + if captcha_salt and captcha_salt not in get_captcha_salts(): + return False, ["This CAPTCHA has expired. Please try again."] + + captcha = args.get("captcha", None) + if captcha: + answer = get_captcha_answer(get_captcha_token(captcha_salt)) + if captcha != answer: + return False, ["The entered CAPTCHA answer is invalid."] + + return True, [] + + +def make_account_form_context(context: dict, + request: Request, + user: User, + args: dict): + """ Modify a FastAPI context and add attributes for the account form. + + :param context: FastAPI context + :param request: FastAPI request + :param user: Target user + :param args: Persistent arguments: request.form() + :return: FastAPI context adjusted for account form + """ + # Do not modify the original context. + context = copy.copy(context) + + context["account_types"] = [ + (1, "Normal User"), + (2, "Trusted User") + ] + + user_account_type_id = context.get("account_types")[0][0] + + if request.user.has_credential("CRED_ACCOUNT_EDIT_DEV"): + context["account_types"].append((3, "Developer")) + context["account_types"].append((4, "Trusted User & Developer")) + + if request.user.is_authenticated(): + context["username"] = args.get("U", user.Username) + context["account_type"] = args.get("T", user.AccountType.ID) + context["suspended"] = args.get("S", user.Suspended) + context["email"] = args.get("E", user.Email) + context["hide_email"] = args.get("H", user.HideEmail) + context["backup_email"] = args.get("BE", user.BackupEmail) + context["realname"] = args.get("R", user.RealName) + context["homepage"] = args.get("HP", user.Homepage or str()) + context["ircnick"] = args.get("I", user.IRCNick) + context["pgp"] = args.get("K", user.PGPKey or str()) + context["lang"] = args.get("L", user.LangPreference) + context["tz"] = args.get("TZ", user.Timezone) + ssh_pk = user.ssh_pub_key.PubKey if user.ssh_pub_key else str() + context["ssh_pk"] = args.get("PK", ssh_pk) + context["cn"] = args.get("CN", user.CommentNotify) + context["un"] = args.get("UN", user.UpdateNotify) + context["on"] = args.get("ON", user.OwnershipNotify) + else: + context["username"] = args.get("U", str()) + context["account_type"] = args.get("T", user_account_type_id) + context["suspended"] = args.get("S", False) + context["email"] = args.get("E", str()) + context["hide_email"] = args.get("H", False) + context["backup_email"] = args.get("BE", str()) + context["realname"] = args.get("R", str()) + context["homepage"] = args.get("HP", str()) + context["ircnick"] = args.get("I", str()) + context["pgp"] = args.get("K", str()) + context["lang"] = args.get("L", context.get("language")) + context["tz"] = args.get("TZ", context.get("timezone")) + context["ssh_pk"] = args.get("PK", str()) + context["cn"] = args.get("CN", True) + context["un"] = args.get("UN", False) + context["on"] = args.get("ON", True) + + context["password"] = args.get("P", str()) + context["confirm"] = args.get("C", str()) + + return context + + +@router.get("/register", response_class=HTMLResponse) +@auth_required(False) +async def account_register(request: Request, + U: str = Form(default=str()), # Username + E: str = Form(default=str()), # Email + H: str = Form(default=False), # Hide Email + BE: str = Form(default=None), # Backup Email + R: str = Form(default=None), # Real Name + HP: str = Form(default=None), # Homepage + I: str = Form(default=None), # IRC Nick + K: str = Form(default=None), # PGP Key FP + L: str = Form(default=aurweb.config.get( + "options", "default_lang")), + TZ: str = Form(default=aurweb.config.get( + "options", "default_timezone")), + PK: str = Form(default=None), + CN: bool = Form(default=False), # Comment Notify + CU: bool = Form(default=False), # Update Notify + CO: bool = Form(default=False), # Owner Notify + captcha: str = Form(default=str())): + context = await make_variable_context(request, "Register") + context["captcha_salt"] = get_captcha_salts()[0] + context = make_account_form_context(context, request, None, dict()) + return render_template(request, "register.html", context) + + +@router.post("/register", response_class=HTMLResponse) +@auth_required(False) +async def account_register_post(request: Request, + U: str = Form(default=str()), # Username + E: str = Form(default=str()), # Email + H: str = Form(default=False), # Hide Email + BE: str = Form(default=None), # Backup Email + R: str = Form(default=''), # Real Name + HP: str = Form(default=None), # Homepage + I: str = Form(default=None), # IRC Nick + K: str = Form(default=None), # PGP Key + L: str = Form(default=aurweb.config.get( + "options", "default_lang")), + TZ: str = Form(default=aurweb.config.get( + "options", "default_timezone")), + PK: str = Form(default=None), # SSH PubKey + CN: bool = Form(default=False), + UN: bool = Form(default=False), + ON: bool = Form(default=False), + captcha: str = Form(default=None), + captcha_salt: str = Form(...)): + from aurweb.db import session + + context = await make_variable_context(request, "Register") + + args = dict(await request.form()) + context = make_account_form_context(context, request, None, args) + + ok, errors = process_account_form(request, request.user, args) + + if not ok: + # If the field values given do not meet the requirements, + # return HTTP 400 with an error. + context["errors"] = errors + return render_template(request, "register.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + + if not captcha: + context["errors"] = ["The CAPTCHA is missing."] + return render_template(request, "register.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + + # Create a user with no password with a resetkey, then send + # an email off about it. + resetkey = db.make_random_value(User, User.ResetKey) + + # By default, we grab the User account type to associate with. + account_type = db.query(AccountType, + AccountType.AccountType == "User").first() + + # Create a user given all parameters available. + user = db.create(User, Username=U, Email=E, HideEmail=H, BackupEmail=BE, + RealName=R, Homepage=HP, IRCNick=I, PGPKey=K, + LangPreference=L, Timezone=TZ, CommentNotify=CN, + UpdateNotify=UN, OwnershipNotify=ON, ResetKey=resetkey, + AccountType=account_type) + + # If a PK was given and either one does not exist or the given + # PK mismatches the existing user's SSHPubKey.PubKey. + if PK: + # Get the second element in the PK, which is the actual key. + pubkey = PK.strip().rstrip() + fingerprint = get_fingerprint(pubkey) + user.ssh_pub_key = SSHPubKey(UserID=user.ID, + PubKey=pubkey, + Fingerprint=fingerprint) + session.commit() + + # Send a reset key notification to the new user. + executor = db.ConnectionExecutor(db.get_engine().raw_connection()) + ResetKeyNotification(executor, user.ID).send() + + context["complete"] = True + context["user"] = user + return render_template(request, "register.html", context) diff --git a/aurweb/util.py b/aurweb/util.py index 65f18a4c..5e1717bd 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -1,7 +1,91 @@ +import base64 import random +import re import string +from urllib.parse import urlparse + +import jinja2 + +from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email + +import aurweb.config + def make_random_string(length): return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length)) + + +def valid_username(username): + min_len = aurweb.config.getint("options", "username_min_len") + max_len = aurweb.config.getint("options", "username_max_len") + if not (min_len <= len(username) <= max_len): + return False + + # Check that username contains: one or more alphanumeric + # characters, an optional separator of '.', '-' or '_', followed + # by alphanumeric characters. + return re.match(r'^[a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$', username) + + +def valid_email(email): + try: + validate_email(email) + except EmailUndeliverableError: + return False + except EmailNotValidError: + return False + return True + + +def valid_homepage(homepage): + parts = urlparse(homepage) + return parts.scheme in ("http", "https") and bool(parts.netloc) + + +def valid_password(password): + min_len = aurweb.config.getint("options", "passwd_min_len") + return len(password) >= min_len + + +def valid_pgp_fingerprint(fp): + fp = fp.replace(" ", "") + try: + # Attempt to convert the fingerprint to an int via base16. + # If it can't, it's not a hex string. + int(fp, 16) + except ValueError: + return False + + # Check the length; must be 40 hexadecimal digits. + return len(fp) == 40 + + +def valid_ssh_pubkey(pk): + valid_prefixes = ("ssh-rsa", "ecdsa-sha2-nistp256", + "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", + "ssh-ed25519") + + has_valid_prefix = False + for prefix in valid_prefixes: + if "%s " % prefix in pk: + has_valid_prefix = True + break + if not has_valid_prefix: + return False + + tokens = pk.strip().rstrip().split(" ") + if len(tokens) < 2: + return False + + return base64.b64encode(base64.b64decode(tokens[1])).decode() == tokens[1] + + +@jinja2.contextfilter +def account_url(context, user): + request = context.get("request") + base = f"{request.url.scheme}://{request.url.hostname}" + if request.url.scheme == "http" and request.url.port != 80: + base += f":{request.url.port}" + return f"{base}/account/{user.Username}" diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html new file mode 100644 index 00000000..3af13368 --- /dev/null +++ b/templates/partials/account_form.html @@ -0,0 +1,343 @@ + +
    +
    + +
    +
    + +

    + + + + ({% trans %}required{% endtrans %}) +

    +

    + {{ "Your user name is the name you will use to login. " + "It is visible to the general public, even if your " + "account is inactive." | tr }} +

    + + {% if request.user.has_credential("CRED_ACCOUNT_CHANGE_TYPE") %} +

    + + +

    + +

    + + + +

    + {% endif %} + + +

    + + + + ({% trans %}required{% endtrans %}) +

    +

    + {{ "Please ensure you correctly entered your email " + "address, otherwise you will be locked out." | tr }} +

    + + +

    + + + +

    +

    + {{ "If you do not hide your email address, it is " + "visible to all registered AUR users. If you hide your " + "email address, it is visible to members of the Arch " + "Linux staff only." | tr }} +

    + + +

    + + + +

    +

    + + {{ "Optionally provide a secondary email address that " + "can be used to restore your account in case you lose " + "access to your primary email address." | tr }} + {{ "Password reset links are always sent to both your " + "primary and your backup email address." | tr }} + {{ "Your backup email address is always only visible to " + "members of the Arch Linux staff, independent of the %s " + "setting." | tr + | format("%s" | format("Hide Email Address" | tr)) + | safe }} + +

    + + +

    + + + +

    + + +

    + + + +

    + + +

    + + + +

    + + +

    + + + +

    + + +

    + + + +

    + + +

    + + + +

    + +
    + + {% if form_type == "UpdateAccount" %} +
    + + {{ + "If you want to change the password, enter a new password " + "and confirm the new password by entering it again." | tr + }} + +

    + + +

    + +

    + + + +

    +
    + {% endif %} + +
    + + {{ + "The following information is only required if you " + "want to submit packages to the Arch User Repository." | tr + }} + +

    + + + + +

    +
    + +
    + {% trans%}Notification settings{% endtrans %}: +

    + + + +

    +

    + + + +

    +

    + + + +

    +
    + +
    + {% if form_type == "UpdateAccount" %} + + {{ "To confirm the profile changes, please enter " + "your current password:" | tr }} + +

    + + +

    + {% else %} + + + {{ "To protect the AUR against automated account creation, " + "we kindly ask you to provide the output of the following " + "command:" | tr }} + + {{ captcha_salt | captcha_cmdline }} + + +

    + + + ({% trans %}required{% endtrans %}) + + +

    + {% endif %} +
    + +
    +

    + + {% if form_type == "UpdateAccount" %} +   + {% else %} +   + {% endif %} + +

    +
    +
    diff --git a/templates/register.html b/templates/register.html new file mode 100644 index 00000000..a15971a1 --- /dev/null +++ b/templates/register.html @@ -0,0 +1,30 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {% trans %}Register{% endtrans %}

    + + {% if complete %} + {{ + "The account, %s%s%s, has been successfully created." + | tr + | format("", "'" + user.Username + "'", "") + | safe + }} +

    + {% trans %}A password reset key has been sent to your e-mail address.{% endtrans %} +

    + {% else %} + {% if errors %} + {% include "partials/error.html" %} + {% else %} +

    + {% trans %}Use this form to create an account.{% endtrans %} +

    + {% endif %} + + {% set form_type = "NewAccount" %} + {% include "partials/account_form.html" %} + {% endif %} +
    +{% endblock %} diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 69896a0f..d79137bf 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -1,13 +1,21 @@ +import re +import tempfile + +from datetime import datetime from http import HTTPStatus +from subprocess import Popen import pytest from fastapi.testclient import TestClient +from aurweb import captcha from aurweb.asgi import app -from aurweb.db import query +from aurweb.db import create, delete, query from aurweb.models.account_type import AccountType +from aurweb.models.ban import Ban from aurweb.models.session import Session +from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.user import User from aurweb.testing import setup_test_db from aurweb.testing.models import make_user @@ -220,3 +228,349 @@ def test_post_passreset_error_password_requirements(): error = f"Your password must be at least {passwd_min_len} characters." assert error in response.content.decode("utf-8") + + +def test_get_register(): + with client as request: + response = request.get("/register") + assert response.status_code == int(HTTPStatus.OK) + + +def post_register(request, **kwargs): + """ A simple helper that allows overrides to test defaults. """ + salt = captcha.get_captcha_salts()[0] + token = captcha.get_captcha_token(salt) + answer = captcha.get_captcha_answer(token) + + data = { + "U": "newUser", + "E": "newUser@email.org", + "P": "newUserPassword", + "C": "newUserPassword", + "L": "en", + "TZ": "UTC", + "captcha": answer, + "captcha_salt": salt + } + + # For any kwargs given, override their k:v pairs in data. + args = dict(kwargs) + for k, v in args.items(): + data[k] = v + + return request.post("/register", data=data, allow_redirects=False) + + +def test_post_register(): + with client as request: + response = post_register(request) + assert response.status_code == int(HTTPStatus.OK) + + expected = "The account, 'newUser', " + expected += "has been successfully created." + assert expected in response.content.decode() + + +def test_post_register_rejects_case_insensitive_spoof(): + with client as request: + response = post_register(request, U="newUser", E="newUser@example.org") + assert response.status_code == int(HTTPStatus.OK) + + with client as request: + response = post_register(request, U="NEWUSER", E="BLAH@GMAIL.COM") + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + expected = "The username, NEWUSER, is already in use." + assert expected in response.content.decode() + + with client as request: + response = post_register(request, U="BLAH", E="NEWUSER@EXAMPLE.ORG") + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + expected = "The address, NEWUSER@EXAMPLE.ORG, " + expected += "is already in use." + assert expected in response.content.decode() + + +def test_post_register_error_expired_captcha(): + with client as request: + response = post_register(request, captcha_salt="invalid-salt") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "This CAPTCHA has expired. Please try again." in content + + +def test_post_register_error_missing_captcha(): + with client as request: + response = post_register(request, captcha=None) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The CAPTCHA is missing." in content + + +def test_post_register_error_invalid_captcha(): + with client as request: + response = post_register(request, captcha="invalid blah blah") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The entered CAPTCHA answer is invalid." in content + + +def test_post_register_error_ip_banned(): + # 'testclient' is used as request.client.host via FastAPI TestClient. + create(Ban, IPAddress="testclient", BanTS=datetime.utcnow()) + + with client as request: + response = post_register(request) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert ("Account registration has been disabled for your IP address, " + + "probably due to sustained spam attacks. Sorry for the " + + "inconvenience.") in content + + +def test_post_register_error_missing_username(): + with client as request: + response = post_register(request, U="") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "Missing a required field." in content + + +def test_post_register_error_missing_email(): + with client as request: + response = post_register(request, E="") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "Missing a required field." in content + + +def test_post_register_error_invalid_username(): + with client as request: + # Our test config requires at least three characters for a + # valid username, so test against two characters: 'ba'. + response = post_register(request, U="ba") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The username is invalid." in content + + +def test_post_register_invalid_password(): + with client as request: + response = post_register(request, P="abc", C="abc") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = r"Your password must be at least \d+ characters." + assert re.search(expected, content) + + +def test_post_register_error_missing_confirm(): + with client as request: + response = post_register(request, C=None) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "Please confirm your new password." in content + + +def test_post_register_error_mismatched_confirm(): + with client as request: + response = post_register(request, C="mismatched") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "Password fields do not match." in content + + +def test_post_register_error_invalid_email(): + with client as request: + response = post_register(request, E="bad@email") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The email address is invalid." in content + + +def test_post_register_error_undeliverable_email(): + with client as request: + # At the time of writing, webchat.freenode.net does not contain + # mx records; if it ever does, it'll break this test. + response = post_register(request, E="email@bad.c") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The email address is invalid." in content + + +def test_post_register_invalid_backup_email(): + with client as request: + response = post_register(request, BE="bad@email") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The backup email address is invalid." in content + + +def test_post_register_error_invalid_homepage(): + with client as request: + response = post_register(request, HP="bad") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = "The home page is invalid, please specify the full HTTP(s) URL." + assert expected in content + + +def test_post_register_error_invalid_pgp_fingerprints(): + with client as request: + response = post_register(request, K="bad") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = "The PGP key fingerprint is invalid." + assert expected in content + + pk = 'z' + ('a' * 39) + with client as request: + response = post_register(request, K=pk) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = "The PGP key fingerprint is invalid." + assert expected in content + + +def test_post_register_error_invalid_ssh_pubkeys(): + with client as request: + response = post_register(request, PK="bad") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The SSH public key is invalid." in content + + with client as request: + response = post_register(request, PK="ssh-rsa ") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "The SSH public key is invalid." in content + + +def test_post_register_error_unsupported_language(): + with client as request: + response = post_register(request, L="bad") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = "Language is not currently supported." + assert expected in content + + +def test_post_register_error_unsupported_timezone(): + with client as request: + response = post_register(request, TZ="ABCDEFGH") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = "Timezone is not currently supported." + assert expected in content + + +def test_post_register_error_username_taken(): + with client as request: + response = post_register(request, U="test") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = r"The username, .*, is already in use." + assert re.search(expected, content) + + +def test_post_register_error_email_taken(): + with client as request: + response = post_register(request, E="test@example.org") + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = r"The address, .*, is already in use." + assert re.search(expected, content) + + +def test_post_register_error_ssh_pubkey_taken(): + pk = str() + + # Create a public key with ssh-keygen (this adds ssh-keygen as a + # dependency to passing this test). + with tempfile.TemporaryDirectory() as tmpdir: + with open("/dev/null", "w") as null: + proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, stderr=null) + proc.wait() + assert proc.returncode == 0 + + # Read in the public key, then delete the temp dir we made. + pk = open(f"{tmpdir}/test.ssh.pub").read().rstrip() + + # Take the sha256 fingerprint of the ssh public key, create it. + fp = get_fingerprint(pk) + create(SSHPubKey, UserID=user.ID, PubKey=pk, Fingerprint=fp) + + with client as request: + response = post_register(request, PK=pk) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + expected = r"The SSH public key, .*, is already in use." + assert re.search(expected, content) + + +def test_post_register_with_ssh_pubkey(): + pk = str() + + # Create a public key with ssh-keygen (this adds ssh-keygen as a + # dependency to passing this test). + with tempfile.TemporaryDirectory() as tmpdir: + with open("/dev/null", "w") as null: + proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, stderr=null) + proc.wait() + assert proc.returncode == 0 + + # Read in the public key, then delete the temp dir we made. + pk = open(f"{tmpdir}/test.ssh.pub").read().rstrip() + + with client as request: + response = post_register(request, PK=pk) + + assert response.status_code == int(HTTPStatus.OK) From d323c1f95b666eb5d607919c14c719884b5e1457 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Jan 2021 02:09:34 -0800 Subject: [PATCH 0650/1891] add python-lxml to dependencies Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 +- Dockerfile | 2 +- INSTALL | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 58fb9fed..5bdf427c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,7 +15,7 @@ before_script: python-itsdangerous python-httpx python-jinja python-pytest-cov python-requests python-aiofiles python-python-multipart python-pytest-asyncio python-coverage python-bcrypt - python-email-validator openssh + python-email-validator openssh python-lxml - bash -c "echo '127.0.0.1' > /etc/hosts" - bash -c "echo '::1' >> /etc/hosts" diff --git a/Dockerfile b/Dockerfile index cf54a13c..c432f73f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN pacman -Syu --noconfirm base-devel git gpgme protobuf pyalpm \ python-itsdangerous python-httpx python-jinja python-pytest-cov \ python-requests python-aiofiles python-python-multipart \ python-pytest-asyncio python-coverage hypercorn python-bcrypt \ - python-email-validator openssh + python-email-validator openssh python-lxml # Remove aurweb.sqlite3 if it was copied over via COPY. RUN rm -fv aurweb.sqlite3 diff --git a/INSTALL b/INSTALL index 04ccd69e..3381daf5 100644 --- a/INSTALL +++ b/INSTALL @@ -51,7 +51,8 @@ read the instructions below. python-bleach python-markdown python-alembic hypercorn \ python-itsdangerous python-authlib python-httpx \ python-jinja python-aiofiles python-python-multipart \ - python-requests hypercorn python-bcrypt python-email-validator + python-requests hypercorn python-bcrypt python-email-validator \ + python-lxml # python3 setup.py install 5) Create a new MySQL database and a user and import the aurweb SQL schema: From 4e9ef6fb00211378ca7373b0e41ee29479c9aa44 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 28 Jan 2021 20:34:27 -0800 Subject: [PATCH 0651/1891] add account edit (settings) routes * Added account_url filter to jinja2 environment. This produces a path to the user's account url (/account/{username}). * Updated archdev-navbar to link to new edit route. + Added migrate_cookies(request, response) to aurweb.util, a function that simply migrates the request cookies to response and returns it. + Added account_edit tests to test_accounts_routes.py. Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 145 ++++++++++++ aurweb/templates.py | 5 +- aurweb/util.py | 6 + templates/account/edit.html | 46 ++++ templates/partials/account_form.html | 9 + templates/partials/archdev-navbar.html | 20 +- test/test_accounts_routes.py | 296 +++++++++++++++++++++++++ 7 files changed, 522 insertions(+), 5 deletions(-) create mode 100644 templates/account/edit.html diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index a43ba9f7..689f7f58 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -1,5 +1,6 @@ import copy +from datetime import datetime from http import HTTPStatus from fastapi import APIRouter, Form, Request @@ -284,6 +285,7 @@ def make_account_form_context(context: dict, context["cn"] = args.get("CN", user.CommentNotify) context["un"] = args.get("UN", user.UpdateNotify) context["on"] = args.get("ON", user.OwnershipNotify) + context["inactive"] = args.get("J", user.InactivityTS != 0) else: context["username"] = args.get("U", str()) context["account_type"] = args.get("T", user_account_type_id) @@ -301,6 +303,7 @@ def make_account_form_context(context: dict, context["cn"] = args.get("CN", True) context["un"] = args.get("UN", False) context["on"] = args.get("ON", True) + context["inactive"] = args.get("J", False) context["password"] = args.get("P", str()) context["confirm"] = args.get("C", str()) @@ -409,3 +412,145 @@ async def account_register_post(request: Request, context["complete"] = True context["user"] = user return render_template(request, "register.html", context) + + +def cannot_edit(request, user): + """ Return a 401 HTMLResponse if the request user doesn't + have authorization, otherwise None. """ + has_dev_cred = request.user.has_credential("CRED_ACCOUNT_EDIT_DEV", + approved=[user]) + if not has_dev_cred: + return HTMLResponse(status_code=int(HTTPStatus.UNAUTHORIZED)) + return None + + +@router.get("/account/{username}/edit", response_class=HTMLResponse) +@auth_required(True) +async def account_edit(request: Request, + username: str): + user = db.query(User, User.Username == username).first() + response = cannot_edit(request, user) + if response: + return response + + context = await make_variable_context(request, "Accounts") + context["user"] = user + + context = make_account_form_context(context, request, user, dict()) + return render_template(request, "account/edit.html", context) + + +@router.post("/account/{username}/edit", response_class=HTMLResponse) +@auth_required(True) +async def account_edit_post(request: Request, + username: str, + U: str = Form(default=str()), # Username + J: bool = Form(default=False), + E: str = Form(default=str()), # Email + H: str = Form(default=False), # Hide Email + BE: str = Form(default=None), # Backup Email + R: str = Form(default=None), # Real Name + HP: str = Form(default=None), # Homepage + I: str = Form(default=None), # IRC Nick + K: str = Form(default=None), # PGP Key + L: str = Form(aurweb.config.get( + "options", "default_lang")), + TZ: str = Form(aurweb.config.get( + "options", "default_timezone")), + P: str = Form(default=str()), # New Password + C: str = Form(default=None), # Password Confirm + PK: str = Form(default=None), # PubKey + CN: bool = Form(default=False), # Comment Notify + UN: bool = Form(default=False), # Update Notify + ON: bool = Form(default=False), # Owner Notify + passwd: str = Form(default=str())): + from aurweb.db import session + + user = session.query(User).filter(User.Username == username).first() + response = cannot_edit(request, user) + if response: + return response + + context = await make_variable_context(request, "Accounts") + context["user"] = user + + if not passwd: + context["errors"] = ["Invalid password."] + return render_template(request, "account/edit.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + + args = dict(await request.form()) + context = make_account_form_context(context, request, user, args) + ok, errors = process_account_form(request, user, args) + + if not ok: + context["errors"] = errors + return render_template(request, "account/edit.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + + # Set all updated fields as needed. + user.Username = U or user.Username + user.Email = E or user.Email + user.HideEmail = bool(H) + user.BackupEmail = BE or user.BackupEmail + user.RealName = R or user.RealName + user.Homepage = HP or user.Homepage + user.IRCNick = I or user.IRCNick + user.PGPKey = K or user.PGPKey + user.InactivityTS = datetime.utcnow().timestamp() if J else 0 + + # If we update the language, update the cookie as well. + if L and L != user.LangPreference: + request.cookies["AURLANG"] = L + user.LangPreference = L + context["language"] = L + + # If we update the timezone, also update the cookie. + if TZ and TZ != user.Timezone: + user.Timezone = TZ + request.cookies["AURTZ"] = TZ + context["timezone"] = TZ + + user.CommentNotify = bool(CN) + user.UpdateNotify = bool(UN) + user.OwnershipNotify = bool(ON) + + # If a PK is given, compare it against the target user's PK. + if PK: + # Get the second token in the public key, which is the actual key. + pubkey = PK.strip().rstrip() + fingerprint = get_fingerprint(pubkey) + if not user.ssh_pub_key: + # No public key exists, create one. + user.ssh_pub_key = SSHPubKey(UserID=user.ID, + PubKey=PK, + Fingerprint=fingerprint) + elif user.ssh_pub_key.Fingerprint != fingerprint: + # A public key already exists, update it. + user.ssh_pub_key.PubKey = PK + user.ssh_pub_key.Fingerprint = fingerprint + elif user.ssh_pub_key: + # Else, if the user has a public key already, delete it. + session.delete(user.ssh_pub_key) + + # Commit changes, if any. + session.commit() + + if P and not user.valid_password(P): + # Remove the fields we consumed for passwords. + context["P"] = context["C"] = str() + + # If a password was given and it doesn't match the user's, update it. + user.update_password(P) + if user == request.user: + # If the target user is the request user, login with + # the updated password and update AURSID. + request.cookies["AURSID"] = user.login(request, P) + + if not errors: + context["complete"] = True + + # Update cookies with requests, in case they were changed. + response = render_template(request, "account/edit.html", context) + return util.migrate_cookies(request, response) +>>>>>> > dddd1137... add account edit(settings) routes diff --git a/aurweb/templates.py b/aurweb/templates.py index d548e92b..c0472b2e 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -12,7 +12,7 @@ from fastapi.responses import HTMLResponse import aurweb.config -from aurweb import captcha, l10n, time +from aurweb import captcha, l10n, time, util # Prepare jinja2 objects. loader = jinja2.FileSystemLoader(os.path.join( @@ -27,6 +27,9 @@ env.filters["tr"] = l10n.tr env.filters["captcha_salt"] = captcha.captcha_salt_filter env.filters["captcha_cmdline"] = captcha.captcha_cmdline_filter +# Add account utility filters. +env.filters["account_url"] = util.account_url + def make_context(request: Request, title: str, next: str = None): """ Create a context for a jinja2 TemplateResponse. """ diff --git a/aurweb/util.py b/aurweb/util.py index 5e1717bd..8b6ddbe7 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -82,6 +82,12 @@ def valid_ssh_pubkey(pk): return base64.b64encode(base64.b64decode(tokens[1])).decode() == tokens[1] +def migrate_cookies(request, response): + for k, v in request.cookies.items(): + response.set_cookie(k, v) + return response + + @jinja2.contextfilter def account_url(context, user): request = context.get("request") diff --git a/templates/account/edit.html b/templates/account/edit.html new file mode 100644 index 00000000..f8895d92 --- /dev/null +++ b/templates/account/edit.html @@ -0,0 +1,46 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {% trans %}Accounts{% endtrans %}

    + + {% if complete %} + + {{ + "The account, %s%s%s, has been successfully modified." + | tr + | format("", user.Username, "") + | safe + }} + + {% else %} + {% if errors %} + {% include "partials/error.html" %} + {% else %} +

    + {{ "Click %shere%s if you want to permanently delete this account." + | tr + | format('' | format(user | account_url), + "") + | safe + }} + {{ "Click %shere%s for user details." + | tr + | format('' | format(user | account_url), + "") + | safe + }} + {{ "Click %shere%s to list the comments made by this account." + | tr + | format('' | format(user | account_url), + "") + | safe + }} +

    + {% endif %} + + {% set form_type = "UpdateAccount" %} + {% include "partials/account_form.html" %} + {% endif %} +
    +{% endblock %} diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 3af13368..5ae18131 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -42,6 +42,15 @@ "account is inactive." | tr }}

    +

    + + +

    + {% if request.user.has_credential("CRED_ACCOUNT_CHANGE_TYPE") %}

  • AUR {% trans %}Home{% endtrans %}
  • {% endif %}
  • {% trans %}Packages{% endtrans %}
  • -
  • {% trans %}Register{% endtrans %}
  • -
  • - {% if request.user.is_authenticated() %} + {% if request.user.is_authenticated() %} +
  • + + {% trans %} My Account{% endtrans %} + +
  • +
  • {% trans %}Logout{% endtrans %} - {% else %} +
  • + {% else %} +
  • + + {% trans %}Register{% endtrans %} + +
  • +
  • {% trans %}Login{% endtrans %} +
  • {% endif %} diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index d79137bf..540adde7 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -5,6 +5,7 @@ from datetime import datetime from http import HTTPStatus from subprocess import Popen +import lxml.html import pytest from fastapi.testclient import TestClient @@ -574,3 +575,298 @@ def test_post_register_with_ssh_pubkey(): response = post_register(request, PK=pk) assert response.status_code == int(HTTPStatus.OK) + + +def test_get_account_edit(): + request = Request() + sid = user.login(request, "testPassword") + + with client as request: + response = request.get("/account/test/edit", cookies={ + "AURSID": sid + }, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + +def test_get_account_edit_unauthorized(): + request = Request() + sid = user.login(request, "testPassword") + + create(User, Username="test2", Email="test2@example.org", + Passwd="testPassword") + + with client as request: + # Try to edit `test2` while authenticated as `test`. + response = request.get("/account/test2/edit", cookies={ + "AURSID": sid + }, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.UNAUTHORIZED) + + +def test_post_account_edit(): + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test666@example.org", + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + expected = "The account, test, " + expected += "has been successfully modified." + assert expected in response.content.decode() + + +def test_post_account_edit_dev(): + from aurweb.db import session + + # Modify our user to be a "Trusted User & Developer" + name = "Trusted User & Developer" + tu_or_dev = query(AccountType, AccountType.AccountType == name).first() + user.AccountType = tu_or_dev + session.commit() + + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test666@example.org", + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + expected = "The account, test, " + expected += "has been successfully modified." + assert expected in response.content.decode() + + +def test_post_account_edit_language(): + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "L": "de", # German + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + # Parse the response content html into an lxml root, then make + # sure we see a 'de' option selected on the page. + content = response.content.decode() + root = lxml.html.fromstring(content) + lang_nodes = root.xpath('//option[@value="de"]/@selected') + assert lang_nodes and len(lang_nodes) != 0 + assert lang_nodes[0] == "selected" + + +def test_post_account_edit_timezone(): + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "TZ": "CET", + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + +def test_post_account_edit_error_missing_password(): + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "TZ": "CET", + "passwd": "" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "Invalid password." in content + + +def test_post_account_edit_error_invalid_password(): + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "TZ": "CET", + "passwd": "invalid" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + content = response.content.decode() + assert "Invalid password." in content + + +def test_post_account_edit_error_unauthorized(): + request = Request() + sid = user.login(request, "testPassword") + + test2 = create(User, Username="test2", Email="test2@example.org", + Passwd="testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "TZ": "CET", + "passwd": "testPassword" + } + + with client as request: + # Attempt to edit 'test2' while logged in as 'test'. + response = request.post("/account/test2/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.UNAUTHORIZED) + + +def test_post_account_edit_ssh_pub_key(): + pk = str() + + # Create a public key with ssh-keygen (this adds ssh-keygen as a + # dependency to passing this test). + with tempfile.TemporaryDirectory() as tmpdir: + with open("/dev/null", "w") as null: + proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, stderr=null) + proc.wait() + assert proc.returncode == 0 + + # Read in the public key, then delete the temp dir we made. + pk = open(f"{tmpdir}/test.ssh.pub").read().rstrip() + + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "PK": pk, + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + # Now let's update what's already there to gain coverage over that path. + pk = str() + with tempfile.TemporaryDirectory() as tmpdir: + with open("/dev/null", "w") as null: + proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, stderr=null) + proc.wait() + assert proc.returncode == 0 + + # Read in the public key, then delete the temp dir we made. + pk = open(f"{tmpdir}/test.ssh.pub").read().rstrip() + + post_data["PK"] = pk + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + +def test_post_account_edit_invalid_ssh_pubkey(): + pubkey = "ssh-rsa fake key" + + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "P": "newPassword", + "C": "newPassword", + "PK": pubkey, + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + +def test_post_account_edit_password(): + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": "test", + "E": "test@example.org", + "P": "newPassword", + "C": "newPassword", + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + assert user.valid_password("newPassword") + + +>>>>>> > dddd1137... add account edit(settings) routes From 4f928b45770b3b8fd6013473b57feb223679f884 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 29 Jan 2021 23:40:38 -0800 Subject: [PATCH 0652/1891] add account (view) route + Added get /account/{username} route. + Added account/show.html template which shows a single use Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 18 ++++++- templates/account/show.html | 96 ++++++++++++++++++++++++++++++++++++ test/test_accounts_routes.py | 31 +++++++++++- 3 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 templates/account/show.html diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 689f7f58..c7c96003 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -3,7 +3,7 @@ import copy from datetime import datetime from http import HTTPStatus -from fastapi import APIRouter, Form, Request +from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, func, or_ @@ -553,4 +553,18 @@ async def account_edit_post(request: Request, # Update cookies with requests, in case they were changed. response = render_template(request, "account/edit.html", context) return util.migrate_cookies(request, response) ->>>>>> > dddd1137... add account edit(settings) routes + + +@router.get("/account/{username}") +@auth_required(True, template=("account/show.html", "Accounts")) +async def account(request: Request, username: str): + user = db.query(User, User.Username == username).first() + + context = await make_variable_context(request, "Accounts") + + if not user: + raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) + + context["user"] = user + + return render_template(request, "account/show.html", context) diff --git a/templates/account/show.html b/templates/account/show.html new file mode 100644 index 00000000..139ff1f5 --- /dev/null +++ b/templates/account/show.html @@ -0,0 +1,96 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {% trans %}Accounts{% endtrans %}

    + + {% if not request.user.is_authenticated() %} + {% trans %}You must log in to view user information.{% endtrans %} + {% else %} + + + + + +
    +

    {{ user.Username }}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {% trans %}Username{% endtrans %}:{{ user.Username }}
    {% trans %}Account Type{% endtrans %}:{{ user.AccountType }}
    {% trans %}Email Address{% endtrans %}: + {{ user.Email }} +
    {% trans %}Real Name{% endtrans %}:{{ user.RealName }}
    {% trans %}Homepage{% endtrans %}: + {% if user.Homepage %} + {{ user.Homepage }} + {% endif %} +
    {% trans %}IRC Nick{% endtrans %}:{{ user.IRCNick }}
    {% trans %}PGP Key Fingerprint{% endtrans %}:{{ user.PGPKey or '' }}
    {% trans %}Status{% endtrans %}:{{ "Active" if not user.Suspended else "Suspended" | tr }}
    {% trans %}Registration date{% endtrans %}: + {{ user.RegistrationTS.strftime("%Y-%m-%d") }} +
    {% trans %}Links{% endtrans %}: + +
    +
    + {% endif %} +
    +{% endblock %} diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 540adde7..c42736fa 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -869,4 +869,33 @@ def test_post_account_edit_password(): assert user.valid_password("newPassword") ->>>>>> > dddd1137... add account edit(settings) routes +def test_get_account(): + request = Request() + sid = user.login(request, "testPassword") + + with client as request: + response = request.get("/account/test", cookies={"AURSID": sid}, + allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + +def test_get_account_not_found(): + request = Request() + sid = user.login(request, "testPassword") + + with client as request: + response = request.get("/account/not_found", cookies={"AURSID": sid}, + allow_redirects=False) + + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_get_account_unauthenticated(): + with client as request: + response = request.get("/account/test", allow_redirects=False) + + assert response.status_code == int(HTTPStatus.UNAUTHORIZED) + + content = response.content.decode() + assert "You must log in to view user information." in content From 32abdbafaed74a0a9dbf3c75401dfa1002f62ba6 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 24 May 2021 12:42:57 +0100 Subject: [PATCH 0653/1891] fastapi: Jinja contextfilter renamed to pass_context Closes: #23 Signed-off-by: Leonidas Spyropoulos --- aurweb/captcha.py | 6 +++--- aurweb/l10n.py | 4 ++-- aurweb/util.py | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/aurweb/captcha.py b/aurweb/captcha.py index 5475d85f..9451f42c 100644 --- a/aurweb/captcha.py +++ b/aurweb/captcha.py @@ -1,7 +1,7 @@ """ This module consists of aurweb's CAPTCHA utility functions and filters. """ import hashlib -import jinja2 +from jinja2 import pass_context from aurweb.db import query from aurweb.models.user import User @@ -41,14 +41,14 @@ def get_captcha_answer(token): return hashlib.md5((text + "\n").encode()).hexdigest()[:6] -@jinja2.contextfilter +@pass_context def captcha_salt_filter(context): """ Returns the most recent CAPTCHA salt in the list of salts. """ salts = get_captcha_salts() return salts[0] -@jinja2.contextfilter +@pass_context def captcha_cmdline_filter(context, salt): """ Returns a CAPTCHA challenge for a given salt. """ return get_captcha_challenge(salt) diff --git a/aurweb/l10n.py b/aurweb/l10n.py index 4a5c1a46..9270f3ce 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -4,7 +4,7 @@ import typing from collections import OrderedDict from fastapi import Request -from jinja2 import contextfilter +from jinja2 import pass_context import aurweb.config @@ -88,7 +88,7 @@ def get_translator_for_request(request: Request): return translate -@contextfilter +@pass_context def tr(context: typing.Any, value: str): """ A translation filter; example: {{ "Hello" | tr("de") }}. """ _ = get_translator_for_request(context.get("request")) diff --git a/aurweb/util.py b/aurweb/util.py index 8b6ddbe7..8e4b291d 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -5,9 +5,8 @@ import string from urllib.parse import urlparse -import jinja2 - from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email +from jinja2 import pass_context import aurweb.config @@ -88,7 +87,7 @@ def migrate_cookies(request, response): return response -@jinja2.contextfilter +@pass_context def account_url(context, user): request = context.get("request") base = f"{request.url.scheme}://{request.url.hostname}" From 822905be7d41fbd52790de58ba20f0d82ce69efc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 24 May 2021 05:19:57 -0700 Subject: [PATCH 0654/1891] bugfix: relax `next` verification AUR renders its own 404 Not Found page when a bad route is encountered. Introducing the previous verification caused an error in this case when setting a language while viewing the Not Found page. So, instead of checking through routes, just make sure that the next parameter starts with a '/' character, which removes the possibility of any cross attacks. + Removed aurweb.asgi.routes; no longer needed. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 9 --------- aurweb/routers/html.py | 8 +++----- test/test_routes.py | 2 +- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 1a61b1f4..861f6056 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -12,8 +12,6 @@ from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine from aurweb.routers import accounts, auth, errors, html, sso -routes = set() - # Setup the FastAPI app. app = FastAPI(exception_handlers=errors.exceptions) @@ -47,13 +45,6 @@ async def app_startup(): # Initialize the database engine and ORM. get_engine() -# NOTE: Always keep this dictionary updated with all routes -# that the application contains. We use this to check for -# parameter value verification. -routes = {route.path for route in app.routes} -routes.update({route.path for route in sso.router.routes}) -routes.update({route.path for route in html.router.routes}) - @app.exception_handler(HTTPException) async def http_exception_handler(request, exc): diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index e947d213..8f89e05c 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -32,11 +32,9 @@ async def language(request: Request, parameters across the redirect. """ from aurweb.db import session - from aurweb.asgi import routes - if unquote(next) not in routes: - return HTMLResponse( - b"Invalid 'next' parameter.", - status_code=400) + + if next[0] != '/': + return HTMLResponse(b"Invalid 'next' parameter.", status_code=400) query_string = "?" + q if q else str() diff --git a/test/test_routes.py b/test/test_routes.py index d512a172..e4816231 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -61,7 +61,7 @@ def test_language_invalid_next(): """ Test an invalid next route at '/language'. """ post_data = { "set_lang": "de", - "next": "/BLAHBLAHFAKE" + "next": "https://evil.net" } with client as req: response = req.post("/language", data=post_data) From a7e5498197ebac1986b7b05c4acb6026d9c6f24d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 30 May 2021 16:38:16 -0700 Subject: [PATCH 0655/1891] add PackageBase SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/db.py | 7 +++++ aurweb/models/package_base.py | 39 ++++++++++++++++++++++++ test/test_package_base.py | 57 +++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 aurweb/models/package_base.py create mode 100644 test/test_package_base.py diff --git a/aurweb/db.py b/aurweb/db.py index 7dab6c4a..bb58c0c8 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,5 +1,7 @@ import math +from sqlalchemy.orm import backref, relationship + import aurweb.config import aurweb.util @@ -51,6 +53,11 @@ def make_random_value(table: str, column: str): return string +def make_relationship(model, foreign_key, backref_): + return relationship(model, foreign_keys=[foreign_key], + backref=backref(backref_, lazy="dynamic")) + + def query(model, *args, **kwargs): return session.query(model).filter(*args, **kwargs) diff --git a/aurweb/models/package_base.py b/aurweb/models/package_base.py new file mode 100644 index 00000000..57e5a46b --- /dev/null +++ b/aurweb/models/package_base.py @@ -0,0 +1,39 @@ +from datetime import datetime + +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.user import User +from aurweb.schema import PackageBases + + +class PackageBase: + def __init__(self, Name: str = None, Flagger: User = None, + Maintainer: User = None, Submitter: User = None, + Packager: User = None, **kwargs): + self.Name = Name + self.Flagger = Flagger + self.Maintainer = Maintainer + self.Submitter = Submitter + self.Packager = Packager + + self.NumVotes = kwargs.get("NumVotes") + self.Popularity = kwargs.get("Popularity") + self.OutOfDateTS = kwargs.get("OutOfDateTS") + self.FlaggerComment = kwargs.get("FlaggerComment", str()) + self.SubmittedTS = kwargs.get("SubmittedTS", + datetime.utcnow().timestamp()) + self.ModifiedTS = kwargs.get("ModifiedTS", + datetime.utcnow().timestamp()) + + +mapper(PackageBase, PackageBases, properties={ + "Flagger": make_relationship(User, PackageBases.c.FlaggerUID, + "flagged_bases"), + "Submitter": make_relationship(User, PackageBases.c.SubmitterUID, + "submitted_bases"), + "Maintainer": make_relationship(User, PackageBases.c.MaintainerUID, + "maintained_bases"), + "Packager": make_relationship(User, PackageBases.c.PackagerUID, + "package_bases") +}) diff --git a/test/test_package_base.py b/test/test_package_base.py new file mode 100644 index 00000000..dcb0eb9e --- /dev/null +++ b/test/test_package_base.py @@ -0,0 +1,57 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query +from aurweb.models.account_type import AccountType +from aurweb.models.package_base import PackageBase +from aurweb.testing import setup_test_db +from aurweb.testing.models import make_user + +user = None + + +@pytest.fixture(autouse=True) +def setup(): + global user + + setup_test_db("Users", "PackageBases") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = make_user(Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + yield user + + +def test_package_base(): + pkgbase = create(PackageBase, + Name="beautiful-package", + Maintainer=user) + assert pkgbase in user.maintained_bases + + assert not pkgbase.OutOfDateTS + assert pkgbase.SubmittedTS > 0 + assert pkgbase.ModifiedTS > 0 + + +def test_package_base_relationships(): + pkgbase = create(PackageBase, + Name="beautiful-package", + Flagger=user, + Maintainer=user, + Submitter=user, + Packager=user) + assert pkgbase in user.flagged_bases + assert pkgbase in user.maintained_bases + assert pkgbase in user.submitted_bases + assert pkgbase in user.package_bases + + +def test_package_base_null_name_raises_exception(): + from aurweb.db import session + + with pytest.raises(IntegrityError): + create(PackageBase) + session.rollback() From fb210158113307d2fb17cd6377eee8e27a2cec05 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 30 May 2021 18:12:46 -0700 Subject: [PATCH 0656/1891] add PackageKeyword SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_keyword.py | 20 ++++++++++++ test/test_package_keyword.py | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 aurweb/models/package_keyword.py create mode 100644 test/test_package_keyword.py diff --git a/aurweb/models/package_keyword.py b/aurweb/models/package_keyword.py new file mode 100644 index 00000000..87d97558 --- /dev/null +++ b/aurweb/models/package_keyword.py @@ -0,0 +1,20 @@ +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.package_base import PackageBase +from aurweb.schema import PackageKeywords + + +class PackageKeyword: + def __init__(self, + PackageBase: PackageBase = None, + Keyword: str = None): + self.PackageBase = PackageBase + self.Keyword = Keyword + + +mapper(PackageKeyword, PackageKeywords, properties={ + "PackageBase": make_relationship(PackageBase, + PackageKeywords.c.PackageBaseID, + "keywords") +}) diff --git a/test/test_package_keyword.py b/test/test_package_keyword.py new file mode 100644 index 00000000..6e2df344 --- /dev/null +++ b/test/test_package_keyword.py @@ -0,0 +1,54 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query +from aurweb.models.account_type import AccountType +from aurweb.models.package_base import PackageBase +from aurweb.models.package_keyword import PackageKeyword +from aurweb.testing import setup_test_db +from aurweb.testing.models import make_user + +user, pkgbase = None, None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase + + setup_test_db("Users", "PackageBases", "PackageKeywords") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = make_user(Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + pkgbase = create(PackageBase, + Name="beautiful-package", + Maintainer=user) + + yield pkgbase + + from aurweb.db import session + session.delete(pkgbase) + session.commit() + + +def test_package_keyword(): + from aurweb.db import session + pkg_keyword = create(PackageKeyword, + PackageBase=pkgbase, + Keyword="test") + assert pkg_keyword in pkgbase.keywords + assert pkgbase == pkg_keyword.PackageBase + session.delete(pkg_keyword) + session.commit() + + +def test_package_keyword_null_pkgbase_raises_exception(): + from aurweb.db import session + + with pytest.raises(IntegrityError): + create(PackageKeyword, + Keyword="test") + session.rollback() From 29db2ee5139baaa7cf4e9989e5916afca6f98bf1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 30 May 2021 22:28:43 -0700 Subject: [PATCH 0657/1891] add Term SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/term.py | 15 +++++++++++++++ test/test_term.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 aurweb/models/term.py create mode 100644 test/test_term.py diff --git a/aurweb/models/term.py b/aurweb/models/term.py new file mode 100644 index 00000000..1b4902f7 --- /dev/null +++ b/aurweb/models/term.py @@ -0,0 +1,15 @@ +from sqlalchemy.orm import mapper + +from aurweb.schema import Terms + + +class Term: + def __init__(self, + Description: str = None, URL: str = None, + Revision: int = None): + self.Description = Description + self.URL = URL + self.Revision = Revision + + +mapper(Term, Terms) diff --git a/test/test_term.py b/test/test_term.py new file mode 100644 index 00000000..4ae1e1cd --- /dev/null +++ b/test/test_term.py @@ -0,0 +1,30 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, delete +from aurweb.models.term import Term + + +def test_term_creation(): + term = create(Term, Description="Term description", + URL="https://fake_url.io") + assert bool(term.ID) + assert term.Description == "Term description" + assert term.URL == "https://fake_url.io" + assert term.Revision == 1 + delete(Term, Term.ID == term.ID) + + +def test_term_null_description_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(Term, URL="https://fake_url.io") + session.rollback() + + +def test_term_null_url_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(Term, Description="Term description") + session.rollback() From 718fa48a5cb0be18cea315bfb1742ef95f30da98 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 30 May 2021 22:29:01 -0700 Subject: [PATCH 0658/1891] add AcceptedTerm SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/accepted_term.py | 24 ++++++++++++++ test/test_accepted_term.py | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 aurweb/models/accepted_term.py create mode 100644 test/test_accepted_term.py diff --git a/aurweb/models/accepted_term.py b/aurweb/models/accepted_term.py new file mode 100644 index 00000000..6e8ffe99 --- /dev/null +++ b/aurweb/models/accepted_term.py @@ -0,0 +1,24 @@ +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.term import Term +from aurweb.models.user import User +from aurweb.schema import AcceptedTerms + + +class AcceptedTerm: + def __init__(self, + User: User = None, Term: Term = None, + Revision: int = None): + self.User = User + self.Term = Term + self.Revision = Revision + + +properties = { + "User": make_relationship(User, AcceptedTerms.c.UsersID, "accepted_terms"), + "Term": make_relationship(Term, AcceptedTerms.c.TermsID, "accepted") +} + +mapper(AcceptedTerm, AcceptedTerms, properties=properties, + primary_key=[AcceptedTerms.c.UsersID, AcceptedTerms.c.TermsID]) diff --git a/test/test_accepted_term.py b/test/test_accepted_term.py new file mode 100644 index 00000000..4dd8a5ca --- /dev/null +++ b/test/test_accepted_term.py @@ -0,0 +1,57 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, delete, query +from aurweb.models.accepted_term import AcceptedTerm +from aurweb.models.account_type import AccountType +from aurweb.models.term import Term +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user, term, accepted_term = None, None, None + + +@pytest.fixture(autouse=True) +def setup(): + global user, term, accepted_term + + setup_test_db("Users", "AcceptedTerms", "Terms") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + account_type=account_type) + + term = create(Term, Description="Test term", URL="https://test.term") + + yield term + + delete(Term, Term.ID == term.ID) + delete(User, User.ID == user.ID) + + +def test_accepted_term(): + accepted_term = create(AcceptedTerm, User=user, Term=term) + + # Make sure our AcceptedTerm relationships got initialized properly. + assert accepted_term.User == user + assert accepted_term in user.accepted_terms + assert accepted_term in term.accepted + + delete(AcceptedTerm, AcceptedTerm.User == user, AcceptedTerm.Term == term) + + +def test_accepted_term_null_user_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(AcceptedTerm, Term=term) + session.rollback() + + +def test_accepted_term_null_term_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(AcceptedTerm, User=user) + session.rollback() From e1ab02c2bf88e2a2fcf2048da212f586c6e3a389 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 30 May 2021 23:06:33 -0700 Subject: [PATCH 0659/1891] Fix database initialization in test_term.py Signed-off-by: Kevin Morris --- test/test_term.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_term.py b/test/test_term.py index 4ae1e1cd..00397b33 100644 --- a/test/test_term.py +++ b/test/test_term.py @@ -2,10 +2,15 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, delete +from aurweb.db import create, delete, get_engine from aurweb.models.term import Term +@pytest.fixture(autouse=True) +def setup(): + get_engine() + + def test_term_creation(): term = create(Term, Description="Term description", URL="https://fake_url.io") From b692b11f62efffd8554fce95c7a0f2a2cdb9014b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 30 May 2021 23:05:16 -0700 Subject: [PATCH 0660/1891] add Group SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/group.py | 11 +++++++++++ test/test_group.py | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 aurweb/models/group.py create mode 100644 test/test_group.py diff --git a/aurweb/models/group.py b/aurweb/models/group.py new file mode 100644 index 00000000..5d4f3834 --- /dev/null +++ b/aurweb/models/group.py @@ -0,0 +1,11 @@ +from sqlalchemy.orm import mapper + +from aurweb.schema import Groups + + +class Group: + def __init__(self, Name: str = None): + self.Name = Name + + +mapper(Group, Groups) diff --git a/test/test_group.py b/test/test_group.py new file mode 100644 index 00000000..bbb774b9 --- /dev/null +++ b/test/test_group.py @@ -0,0 +1,21 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, delete, get_engine +from aurweb.models.group import Group + + +def test_group_creation(): + get_engine() + group = create(Group, Name="Test Group") + assert bool(group.ID) + assert group.Name == "Test Group" + delete(Group, Group.ID == group.ID) + + +def test_group_null_name_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(Group) + session.rollback() From 794868b20f700461fd8978be9c162c708db43c57 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 31 May 2021 22:41:06 -0700 Subject: [PATCH 0661/1891] aurweb.testing.setup_test_db: Expunge objects This is needed to avoid redundant objects in SQLAlchemy's IdentityMap, since we pass a direct .execute to delete the tables passed in. Additionally, remove our engine.connect() call in favor of relying on the already-established Session. Signed-off-by: Kevin Morris --- aurweb/testing/__init__.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py index 0a807b40..02c21a4c 100644 --- a/aurweb/testing/__init__.py +++ b/aurweb/testing/__init__.py @@ -21,10 +21,12 @@ def setup_test_db(*args): test_tables = ["Users", "Sessions"]; setup_test_db(*test_tables) """ - engine = aurweb.db.get_engine() - conn = engine.connect() + # Make sure that we've grabbed the engine before using the session. + aurweb.db.get_engine() tables = list(args) for table in tables: - conn.execute(f"DELETE FROM {table}") - conn.close() + aurweb.db.session.execute(f"DELETE FROM {table}") + + # Expunge all objects from SQLAlchemy's IdentityMap. + aurweb.db.session.expunge_all() From f8a6049de24a1b92b6d1c3456570c47f464aaf21 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 31 May 2021 22:43:28 -0700 Subject: [PATCH 0662/1891] aurweb.db.session: Use autoflush=True for Sessions We'd like SQLAlchemy to automatically maintain flushes for us. Signed-off-by: Kevin Morris --- aurweb/db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/db.py b/aurweb/db.py index bb58c0c8..ca5ce412 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -135,7 +135,7 @@ def get_engine(): # https://fastapi.tiangolo.com/tutorial/sql-databases/#note connect_args["check_same_thread"] = False engine = create_engine(get_sqlalchemy_url(), connect_args=connect_args) - Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) + Session = sessionmaker(autocommit=False, autoflush=True, bind=engine) session = Session() return engine From 621e459dfbd3d6e8e0d7a790dae4e14b092078ad Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 31 May 2021 22:45:30 -0700 Subject: [PATCH 0663/1891] aurweb.models.user: Remove session.commit() from construction We don't want to do this on construction. We only want to do this when we want to actually add the user to the database (or modify it). Signed-off-by: Kevin Morris --- aurweb/models/user.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 3983e098..6c5c6e21 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -51,11 +51,9 @@ class User: self.update_password(passwd) def update_password(self, password, salt_rounds=12): - from aurweb.db import session self.Passwd = bcrypt.hashpw( password.encode(), bcrypt.gensalt(rounds=salt_rounds)).decode() - session.commit() @staticmethod def minimum_passwd_length(): From 15b1332656a7f2bb0aa2abe108af4ede0629b749 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 00:25:49 -0700 Subject: [PATCH 0664/1891] add Package SQLAlchemy ORM model Additionally, add an optional **kwargs passing via make_relationship. This allows us to use things like `uselist=False`, which was needed for test/test_package.py. Signed-off-by: Kevin Morris --- aurweb/db.py | 5 ++- aurweb/models/package.py | 24 ++++++++++++ test/test_package.py | 79 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 aurweb/models/package.py create mode 100644 test/test_package.py diff --git a/aurweb/db.py b/aurweb/db.py index ca5ce412..500cf95a 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -53,9 +53,10 @@ def make_random_value(table: str, column: str): return string -def make_relationship(model, foreign_key, backref_): +def make_relationship(model, foreign_key: str, backref_: str, **kwargs): return relationship(model, foreign_keys=[foreign_key], - backref=backref(backref_, lazy="dynamic")) + backref=backref(backref_, lazy="dynamic"), + **kwargs) def query(model, *args, **kwargs): diff --git a/aurweb/models/package.py b/aurweb/models/package.py new file mode 100644 index 00000000..fa82bb74 --- /dev/null +++ b/aurweb/models/package.py @@ -0,0 +1,24 @@ +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.package_base import PackageBase +from aurweb.schema import Packages + + +class Package: + def __init__(self, + PackageBase: PackageBase = None, + Name: str = None, Version: str = None, + Description: str = None, URL: str = None): + self.PackageBase = PackageBase + self.Name = Name + self.Version = Version + self.Description = Description + self.URL = URL + + +mapper(Package, Packages, properties={ + "PackageBase": make_relationship(PackageBase, + Packages.c.PackageBaseID, + "package", uselist=False) +}) diff --git a/test/test_package.py b/test/test_package.py new file mode 100644 index 00000000..1d670087 --- /dev/null +++ b/test/test_package.py @@ -0,0 +1,79 @@ +import pytest + +from sqlalchemy import and_ +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query +from aurweb.models.account_type import AccountType +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = package = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase, package + + setup_test_db("Users", "PackageBases", "Packages") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + pkgbase = create(PackageBase, + Name="beautiful-package", + Maintainer=user) + package = create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") + + yield package + + +def test_package(): + from aurweb.db import session + + assert pkgbase == package.PackageBase + assert package.Name == "beautiful-package" + assert package.Description == "Test description." + assert package.Version == str() # Default version. + assert package.URL == "https://test.package" + + # Update package Version. + package.Version = "1.2.3" + session.commit() + + # Make sure it got updated in the database. + record = query(Package, + and_(Package.ID == package.ID, + Package.Version == "1.2.3")).first() + assert record is not None + + +def test_package_null_pkgbase_raises_exception(): + from aurweb.db import session + + with pytest.raises(IntegrityError): + create(Package, + Name="some-package", + Description="Some description.", + URL="https://some.package") + session.rollback() + + +def test_package_null_name_raises_exception(): + from aurweb.db import session + + with pytest.raises(IntegrityError): + create(Package, + PackageBase=pkgbase, + Description="Some description.", + URL="https://some.package") + session.rollback() From f2121fb833d2279c5fb6b5863988209e45176fd0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 00:26:32 -0700 Subject: [PATCH 0665/1891] simplify test_package_keyword.py We no longer need to delete records like this; in fact, it causes errors now. Fix this by removing the deletions and allow setup_test_db to do it's job. We'll need to do this for other tests as well. Signed-off-by: Kevin Morris --- test/test_package_keyword.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/test_package_keyword.py b/test/test_package_keyword.py index 6e2df344..f110b123 100644 --- a/test/test_package_keyword.py +++ b/test/test_package_keyword.py @@ -29,20 +29,13 @@ def setup(): yield pkgbase - from aurweb.db import session - session.delete(pkgbase) - session.commit() - def test_package_keyword(): - from aurweb.db import session pkg_keyword = create(PackageKeyword, PackageBase=pkgbase, Keyword="test") assert pkg_keyword in pkgbase.keywords assert pkgbase == pkg_keyword.PackageBase - session.delete(pkg_keyword) - session.commit() def test_package_keyword_null_pkgbase_raises_exception(): From 38dc2bb99dcbab372c4c7fcd3716f7f532c22ee0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 03:26:14 -0700 Subject: [PATCH 0666/1891] Sanitize and modernize pytests Some of these tests were written before some of our convenient tooling existed. Additionally, some of the tests were not cooperating with PEP-8 guidelines or isorted. This commit does the following: - Replaces all calls to make_(user|session) with aurweb.db.create(Model, ...). - Replace calls to session.add(...) + session.commit() with aurweb.db.create. - Removes the majority of calls to (session|aurweb.db).delete(...). - Replaces session.query calls with aurweb.db.query. - Initializes all mutable globals in pytest fixture setup(). - Makes mutable global declarations more concise: `var1, var2 = None, None` -> `var1 = var2 = None` - Defines a warning exclusion for test/test_ssh_pub_key.py. - Removes the aurweb.testing.models module. - Removes some useless pytest.fixture yielding. As of this commit, developers should use the following guidelines when writing tests: - Always use aurweb.db.(create|delete|query) for database operations, where possible. - Always define mutable globals in the style: `var1 = var2 = None`. - `yield` the most dependent model in pytest setup fixture **iff** you must delete records after test runs to maintain database integrity. Example: test/test_account_type.py. This all makes the test code look and behave much cleaner. Previously, aurweb.testing.setup_test_db was buggy and leaving objects around in SQLAlchemy's IdentityMap. Signed-off-by: Kevin Morris --- aurweb/testing/models.py | 25 --------------- setup.cfg | 28 +++++++++++------ test/test_accepted_term.py | 11 ++----- test/test_account_type.py | 28 ++++++----------- test/test_accounts_routes.py | 13 ++++---- test/test_auth.py | 29 +++++++---------- test/test_auth_routes.py | 17 +++++----- test/test_ban.py | 16 ++++------ test/test_exceptions.py | 61 +++++++++++++++++------------------- test/test_group.py | 10 ++++-- test/test_initdb.py | 5 +-- test/test_package.py | 2 -- test/test_package_base.py | 9 +++--- test/test_package_keyword.py | 12 +++---- test/test_routes.py | 17 +++++----- test/test_session.py | 31 +++++++++--------- test/test_ssh_pub_key.py | 29 ++++++----------- test/test_term.py | 6 ++-- test/test_user.py | 50 +++++++++-------------------- 19 files changed, 160 insertions(+), 239 deletions(-) delete mode 100644 aurweb/testing/models.py diff --git a/aurweb/testing/models.py b/aurweb/testing/models.py deleted file mode 100644 index 8a27c409..00000000 --- a/aurweb/testing/models.py +++ /dev/null @@ -1,25 +0,0 @@ -import warnings - -from sqlalchemy import exc - -import aurweb.db - - -def make_user(**kwargs): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", exc.SAWarning) - from aurweb.models.user import User - user = User(**kwargs) - aurweb.db.session.add(user) - aurweb.db.session.commit() - return user - - -def make_session(**kwargs): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", exc.SAWarning) - from aurweb.models.session import Session - session = Session(**kwargs) - aurweb.db.session.add(session) - aurweb.db.session.commit() - return session diff --git a/setup.cfg b/setup.cfg index 98261651..31a0eb8a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,18 +2,26 @@ max-line-length = 127 max-complexity = 10 -# Ignore some unavoidable flake8 warnings; we know this is against -# pycodestyle, but some of the existing codebase uses `I` variables, -# so specifically silence warnings about it in pre-defined files. -# In E741, the 'I', 'O', 'l' are ambiguous variable names. -# Our current implementation uses these variables through HTTP -# and the FastAPI form specification wants them named as such. -# In C901's case, our process_account_form function is way too -# complex for PEP (too many if statements). However, we need to -# process these anyways, and making it any more complex would -# just add confusion to the implementation. +# aurweb/routers/accounts.py +# Ignore some unavoidable flake8 warnings; we know this is against +# pycodestyle, but some of the existing codebase uses `I` variables, +# so specifically silence warnings about it in pre-defined files. +# In E741, the 'I', 'O', 'l' are ambiguous variable names. +# Our current implementation uses these variables through HTTP +# and the FastAPI form specification wants them named as such. +# In C901's case, our process_account_form function is way too +# complex for PEP (too many if statements). However, we need to +# process these anyways, and making it any more complex would +# just add confusion to the implementation. +# +# test/test_ssh_pub_key.py +# E501 is detected due to our >127 width test constant. Ignore it. +# Due to this, line width should _always_ be looked at in code reviews. +# Anything like this should be questioned. +# per-file-ignores = aurweb/routers/accounts.py:E741,C901 + test/test_ssh_pub_key.py:E501 [isort] line_length = 127 diff --git a/test/test_accepted_term.py b/test/test_accepted_term.py index 4dd8a5ca..4ddf1fc3 100644 --- a/test/test_accepted_term.py +++ b/test/test_accepted_term.py @@ -2,14 +2,14 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, delete, query +from aurweb.db import create, query from aurweb.models.accepted_term import AcceptedTerm from aurweb.models.account_type import AccountType from aurweb.models.term import Term from aurweb.models.user import User from aurweb.testing import setup_test_db -user, term, accepted_term = None, None, None +user = term = accepted_term = None @pytest.fixture(autouse=True) @@ -26,11 +26,6 @@ def setup(): term = create(Term, Description="Test term", URL="https://test.term") - yield term - - delete(Term, Term.ID == term.ID) - delete(User, User.ID == user.ID) - def test_accepted_term(): accepted_term = create(AcceptedTerm, User=user, Term=term) @@ -40,8 +35,6 @@ def test_accepted_term(): assert accepted_term in user.accepted_terms assert accepted_term in term.accepted - delete(AcceptedTerm, AcceptedTerm.User == user, AcceptedTerm.Term == term) - def test_accepted_term_null_user_raises_exception(): from aurweb.db import session diff --git a/test/test_account_type.py b/test/test_account_type.py index 9419970c..3bd76d1e 100644 --- a/test/test_account_type.py +++ b/test/test_account_type.py @@ -1,9 +1,9 @@ import pytest +from aurweb.db import create, delete, query from aurweb.models.account_type import AccountType from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_user account_type = None @@ -12,24 +12,17 @@ account_type = None def setup(): setup_test_db("Users") - from aurweb.db import session - global account_type - account_type = AccountType(AccountType="TestUser") - session.add(account_type) - session.commit() + account_type = create(AccountType, AccountType="TestUser") yield account_type - session.delete(account_type) - session.commit() + delete(AccountType, AccountType.ID == account_type.ID) def test_account_type(): """ Test creating an AccountType, and reading its columns. """ - from aurweb.db import session - # Make sure it got created and was given an ID. assert bool(account_type.ID) @@ -39,20 +32,17 @@ def test_account_type(): "" % ( account_type.ID) - record = session.query(AccountType).filter( - AccountType.AccountType == "TestUser").first() + record = query(AccountType, + AccountType.AccountType == "TestUser").first() assert account_type == record def test_user_account_type_relationship(): - from aurweb.db import session - - user = make_user(Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) assert user.AccountType == account_type assert account_type.users.filter(User.ID == user.ID).first() - session.delete(user) - session.commit() + delete(User, User.ID == user.ID) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index c42736fa..0f813823 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -12,14 +12,13 @@ from fastapi.testclient import TestClient from aurweb import captcha from aurweb.asgi import app -from aurweb.db import create, delete, query +from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.ban import Ban from aurweb.models.session import Session from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_user from aurweb.testing.requests import Request # Some test global constants. @@ -39,9 +38,9 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username=TEST_USERNAME, Email=TEST_EMAIL, - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, + RealName="Test User", Passwd="testPassword", + AccountType=account_type) def test_get_passreset_authed_redirects(): @@ -751,8 +750,8 @@ def test_post_account_edit_error_unauthorized(): request = Request() sid = user.login(request, "testPassword") - test2 = create(User, Username="test2", Email="test2@example.org", - Passwd="testPassword") + create(User, Username="test2", + Email="test2@example.org", Passwd="testPassword") post_data = { "U": "test", diff --git a/test/test_auth.py b/test/test_auth.py index d43459cd..7837e7f7 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -5,16 +5,14 @@ import pytest from starlette.authentication import AuthenticationError from aurweb.auth import BasicAuthBackend, has_credential -from aurweb.db import query +from aurweb.db import create, query from aurweb.models.account_type import AccountType +from aurweb.models.session import Session +from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_session, make_user from aurweb.testing.requests import Request -# Persistent user object, initialized in our setup fixture. -user = None -backend = None -request = None +user = backend = request = None @pytest.fixture(autouse=True) @@ -23,16 +21,11 @@ def setup(): setup_test_db("Users", "Sessions") - from aurweb.db import session - account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.com", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - - session.add(user) - session.commit() + user = create(User, Username="test", Email="test@example.com", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) backend = BasicAuthBackend() request = Request() @@ -60,8 +53,8 @@ async def test_auth_backend_invalid_sid(): async def test_auth_backend_invalid_user_id(): # Create a new session with a fake user id. now_ts = datetime.utcnow().timestamp() - make_session(UsersID=666, SessionID="realSession", - LastUpdateTS=now_ts + 5) + create(Session, UsersID=666, SessionID="realSession", + LastUpdateTS=now_ts + 5) # Here, we specify a real SID; but it's user is not there. request.cookies["AURSID"] = "realSession" @@ -74,8 +67,8 @@ async def test_basic_auth_backend(): # This time, everything matches up. We expect the user to # equal the real_user. now_ts = datetime.utcnow().timestamp() - make_session(UsersID=user.ID, SessionID="realSession", - LastUpdateTS=now_ts + 5) + create(Session, UsersID=user.ID, SessionID="realSession", + LastUpdateTS=now_ts + 5) _, result = await backend.authenticate(request) assert result == user diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index ff8a08e9..360b48cc 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -8,33 +8,34 @@ from fastapi.testclient import TestClient import aurweb.config from aurweb.asgi import app -from aurweb.db import query +from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.session import Session +from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_user # Some test global constants. TEST_USERNAME = "test" TEST_EMAIL = "test@example.org" # Global mutables. -client = TestClient(app) -user = None +user = client = None @pytest.fixture(autouse=True) def setup(): - global user + global user, client setup_test_db("Users", "Sessions", "Bans") account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username=TEST_USERNAME, Email=TEST_EMAIL, - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + client = TestClient(app) def test_login_logout(): diff --git a/test/test_ban.py b/test/test_ban.py index de4f5b1b..a4fa5a28 100644 --- a/test/test_ban.py +++ b/test/test_ban.py @@ -6,27 +6,23 @@ import pytest from sqlalchemy import exc as sa_exc +from aurweb.db import create from aurweb.models.ban import Ban, is_banned from aurweb.testing import setup_test_db from aurweb.testing.requests import Request -ban = None - -request = Request() +ban = request = None @pytest.fixture(autouse=True) def setup(): - from aurweb.db import session - - global ban + global ban, request setup_test_db("Bans") - ban = Ban(IPAddress="127.0.0.1", - BanTS=datetime.utcnow() + timedelta(seconds=30)) - session.add(ban) - session.commit() + ts = datetime.utcnow() + timedelta(seconds=30) + ban = create(Ban, IPAddress="127.0.0.1", BanTS=ts) + request = Request() def test_ban(): diff --git a/test/test_exceptions.py b/test/test_exceptions.py index feac2656..7247106b 100644 --- a/test/test_exceptions.py +++ b/test/test_exceptions.py @@ -1,102 +1,99 @@ -from aurweb.exceptions import (AlreadyVotedException, AurwebException, BannedException, BrokenUpdateHookException, - InvalidArgumentsException, InvalidCommentException, InvalidPackageBaseException, - InvalidReasonException, InvalidRepositoryNameException, InvalidUserException, - MaintenanceException, NotVotedException, PackageBaseExistsException, PermissionDeniedException) +from aurweb import exceptions def test_aurweb_exception(): try: - raise AurwebException("test") - except AurwebException as exc: + raise exceptions.AurwebException("test") + except exceptions.AurwebException as exc: assert str(exc) == "test" def test_maintenance_exception(): try: - raise MaintenanceException("test") - except MaintenanceException as exc: + raise exceptions.MaintenanceException("test") + except exceptions.MaintenanceException as exc: assert str(exc) == "test" def test_banned_exception(): try: - raise BannedException("test") - except BannedException as exc: + raise exceptions.BannedException("test") + except exceptions.BannedException as exc: assert str(exc) == "test" def test_already_voted_exception(): try: - raise AlreadyVotedException("test") - except AlreadyVotedException as exc: + raise exceptions.AlreadyVotedException("test") + except exceptions.AlreadyVotedException as exc: assert str(exc) == "already voted for package base: test" def test_broken_update_hook_exception(): try: - raise BrokenUpdateHookException("test") - except BrokenUpdateHookException as exc: + raise exceptions.BrokenUpdateHookException("test") + except exceptions.BrokenUpdateHookException as exc: assert str(exc) == "broken update hook: test" def test_invalid_arguments_exception(): try: - raise InvalidArgumentsException("test") - except InvalidArgumentsException as exc: + raise exceptions.InvalidArgumentsException("test") + except exceptions.InvalidArgumentsException as exc: assert str(exc) == "test" def test_invalid_packagebase_exception(): try: - raise InvalidPackageBaseException("test") - except InvalidPackageBaseException as exc: + raise exceptions.InvalidPackageBaseException("test") + except exceptions.InvalidPackageBaseException as exc: assert str(exc) == "package base not found: test" def test_invalid_comment_exception(): try: - raise InvalidCommentException("test") - except InvalidCommentException as exc: + raise exceptions.InvalidCommentException("test") + except exceptions.InvalidCommentException as exc: assert str(exc) == "comment is too short: test" def test_invalid_reason_exception(): try: - raise InvalidReasonException("test") - except InvalidReasonException as exc: + raise exceptions.InvalidReasonException("test") + except exceptions.InvalidReasonException as exc: assert str(exc) == "invalid reason: test" def test_invalid_user_exception(): try: - raise InvalidUserException("test") - except InvalidUserException as exc: + raise exceptions.InvalidUserException("test") + except exceptions.InvalidUserException as exc: assert str(exc) == "unknown user: test" def test_not_voted_exception(): try: - raise NotVotedException("test") - except NotVotedException as exc: + raise exceptions.NotVotedException("test") + except exceptions.NotVotedException as exc: assert str(exc) == "missing vote for package base: test" def test_packagebase_exists_exception(): try: - raise PackageBaseExistsException("test") - except PackageBaseExistsException as exc: + raise exceptions.PackageBaseExistsException("test") + except exceptions.PackageBaseExistsException as exc: assert str(exc) == "package base already exists: test" def test_permission_denied_exception(): try: - raise PermissionDeniedException("test") - except PermissionDeniedException as exc: + raise exceptions.PermissionDeniedException("test") + except exceptions.PermissionDeniedException as exc: assert str(exc) == "permission denied: test" def test_repository_name_exception(): try: - raise InvalidRepositoryNameException("test") - except InvalidRepositoryNameException as exc: + raise exceptions.InvalidRepositoryNameException("test") + except exceptions.InvalidRepositoryNameException as exc: assert str(exc) == "invalid repository name: test" diff --git a/test/test_group.py b/test/test_group.py index bbb774b9..da017a96 100644 --- a/test/test_group.py +++ b/test/test_group.py @@ -2,16 +2,20 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, delete, get_engine +from aurweb.db import create from aurweb.models.group import Group +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db("Groups") def test_group_creation(): - get_engine() group = create(Group, Name="Test Group") assert bool(group.ID) assert group.Name == "Test Group" - delete(Group, Group.ID == group.ID) def test_group_null_name_raises_exception(): diff --git a/test/test_initdb.py b/test/test_initdb.py index ff089b63..eae33007 100644 --- a/test/test_initdb.py +++ b/test/test_initdb.py @@ -23,5 +23,6 @@ def test_run(): use_alembic = True verbose = False aurweb.initdb.run(Args()) - assert aurweb.db.session.query(AccountType).filter( - AccountType.AccountType == "User").first() is not None + record = aurweb.db.query(AccountType, + AccountType.AccountType == "User").first() + assert record is not None diff --git a/test/test_package.py b/test/test_package.py index 1d670087..66d557f3 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -34,8 +34,6 @@ def setup(): Description="Test description.", URL="https://test.package") - yield package - def test_package(): from aurweb.db import session diff --git a/test/test_package_base.py b/test/test_package_base.py index dcb0eb9e..e0359f4f 100644 --- a/test/test_package_base.py +++ b/test/test_package_base.py @@ -5,8 +5,8 @@ from sqlalchemy.exc import IntegrityError from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.package_base import PackageBase +from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_user user = None @@ -19,10 +19,9 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - yield user + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) def test_package_base(): diff --git a/test/test_package_keyword.py b/test/test_package_keyword.py index f110b123..316e7ca8 100644 --- a/test/test_package_keyword.py +++ b/test/test_package_keyword.py @@ -6,10 +6,10 @@ from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.package_base import PackageBase from aurweb.models.package_keyword import PackageKeyword +from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_user -user, pkgbase = None, None +user = pkgbase = None @pytest.fixture(autouse=True) @@ -20,15 +20,13 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) pkgbase = create(PackageBase, Name="beautiful-package", Maintainer=user) - yield pkgbase - def test_package_keyword(): pkg_keyword = create(PackageKeyword, diff --git a/test/test_routes.py b/test/test_routes.py index e4816231..f4bb063f 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -7,27 +7,28 @@ import pytest from fastapi.testclient import TestClient from aurweb.asgi import app -from aurweb.db import query +from aurweb.db import create, query from aurweb.models.account_type import AccountType +from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_user from aurweb.testing.requests import Request -client = TestClient(app) -user = None +user = client = None @pytest.fixture(autouse=True) def setup(): - global user + global user, client setup_test_db("Users", "Sessions") account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + client = TestClient(app) def test_index(): diff --git a/test/test_session.py b/test/test_session.py index 560f628c..2877ea7f 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -4,39 +4,38 @@ from unittest import mock import pytest +from aurweb.db import create, query from aurweb.models.account_type import AccountType -from aurweb.models.session import generate_unique_sid +from aurweb.models.session import Session, generate_unique_sid +from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_session, make_user -user, _session = None, None +user = session = None @pytest.fixture(autouse=True) def setup(): - from aurweb.db import session - - global user, _session + global user, session setup_test_db("Users", "Sessions") - account_type = session.query(AccountType).filter( - AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.org", - ResetKey="testReset", Passwd="testPassword", - AccountType=account_type) - _session = make_session(UsersID=user.ID, SessionID="testSession", - LastUpdateTS=datetime.utcnow()) + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + ResetKey="testReset", Passwd="testPassword", + AccountType=account_type) + session = create(Session, UsersID=user.ID, SessionID="testSession", + LastUpdateTS=datetime.utcnow()) def test_session(): - assert _session.SessionID == "testSession" - assert _session.UsersID == user.ID + assert session.SessionID == "testSession" + assert session.UsersID == user.ID def test_session_user_association(): # Make sure that the Session user attribute is correct. - assert _session.User == user + assert session.User == user def test_generate_unique_sid(): diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py index fe9df047..4072549e 100644 --- a/test/test_ssh_pub_key.py +++ b/test/test_ssh_pub_key.py @@ -1,46 +1,37 @@ import pytest -from aurweb.db import query +from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint +from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_user TEST_SSH_PUBKEY = """ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCycoCi5yGCvSclH2wmNBUuwsYEzRZZBJaQquRc4ysl+Tg+/jiDkR3Zn9fIznC4KnFoyrIHzkKuePZ3bNDYwkZxkJKoWBCh4hXKDXSm87FMN0+VDC+1QxF/z0XaAGr/P6f4XukabyddypBdnHcZiplbw+YOSqcAE2TCqOlSXwNMOcF9U89UsR/Q9i9I52hlvU0q8+fZVGhou1KCowFSnHYtrr5KYJ04CXkJ13DkVf3+pjQWyrByvBcf1hGEaczlgfobrrv/y96jDhgfXucxliNKLdufDPPkii3LhhsNcDmmI1VZ3v0irKvd9WZuauqloobY84zEFcDTyjn0hxGjVeYFejm4fBnvjga0yZXORuWksdNfXWLDxFk6MDDd1jF0ExRbP+OxDuU4IVyIuDL7S3cnbf2YjGhkms/8voYT2OBE7FwNlfv98Kr0NUp51zpf55Arxn9j0Rz9xTA7FiODQgCn6iQ0SDtzUNL0IKTCw26xJY5gzMxbfpvzPQGeulx/ioM= kevr@volcano """ -user, ssh_pub_key = None, None +user = ssh_pub_key = None @pytest.fixture(autouse=True) def setup(): - from aurweb.db import session - global user, ssh_pub_key setup_test_db("Users", "SSHPubKeys") account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) assert account_type == user.AccountType assert account_type.ID == user.AccountTypeID - ssh_pub_key = SSHPubKey(UserID=user.ID, - Fingerprint="testFingerprint", - PubKey="testPubKey") - - session.add(ssh_pub_key) - session.commit() - - yield ssh_pub_key - - session.delete(ssh_pub_key) - session.commit() + ssh_pub_key = create(SSHPubKey, + UserID=user.ID, + Fingerprint="testFingerprint", + PubKey="testPubKey") def test_ssh_pub_key(): diff --git a/test/test_term.py b/test/test_term.py index 00397b33..aa1dfcc6 100644 --- a/test/test_term.py +++ b/test/test_term.py @@ -2,13 +2,14 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, delete, get_engine +from aurweb.db import create from aurweb.models.term import Term +from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) def setup(): - get_engine() + setup_test_db("Terms") def test_term_creation(): @@ -18,7 +19,6 @@ def test_term_creation(): assert term.Description == "Term description" assert term.URL == "https://fake_url.io" assert term.Revision == 1 - delete(Term, Term.ID == term.ID) def test_term_null_description_raises_exception(): diff --git a/test/test_user.py b/test/test_user.py index e8056681..8b4da61e 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -8,23 +8,20 @@ import pytest import aurweb.auth import aurweb.config -from aurweb.db import query +from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.ban import Ban from aurweb.models.session import Session from aurweb.models.ssh_pub_key import SSHPubKey from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.models import make_session, make_user from aurweb.testing.requests import Request -account_type, user = None, None +account_type = user = None @pytest.fixture(autouse=True) def setup(): - from aurweb.db import session - global account_type, user setup_test_db("Users", "Sessions", "Bans", "SSHPubKeys") @@ -32,15 +29,13 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = make_user(Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) def test_user_login_logout(): """ Test creating a user and reading its columns. """ - from aurweb.db import session - # Assert that make_user created a valid user. assert bool(user.ID) @@ -61,8 +56,8 @@ def test_user_login_logout(): assert "AURSID" in request.cookies # Expect that User session relationships work right. - user_session = session.query(Session).filter( - Session.UsersID == user.ID).first() + user_session = query(Session, + Session.UsersID == user.ID).first() assert user_session == user.session assert user.session.SessionID == sid assert user.session.User == user @@ -103,13 +98,9 @@ def test_user_login_twice(): def test_user_login_banned(): - from aurweb.db import session - # Add ban for the next 30 seconds. banned_timestamp = datetime.utcnow() + timedelta(seconds=30) - ban = Ban(IPAddress="127.0.0.1", BanTS=banned_timestamp) - session.add(ban) - session.commit() + create(Ban, IPAddress="127.0.0.1", BanTS=banned_timestamp) request = Request() request.client.host = "127.0.0.1" @@ -138,19 +129,14 @@ def test_legacy_user_authentication(): def test_user_login_with_outdated_sid(): - from aurweb.db import session - # Make a session with a LastUpdateTS 5 seconds ago, causing # user.login to update it with a new sid. - _session = make_session(UsersID=user.ID, SessionID="stub", - LastUpdateTS=datetime.utcnow().timestamp() - 5) + create(Session, UsersID=user.ID, SessionID="stub", + LastUpdateTS=datetime.utcnow().timestamp() - 5) sid = user.login(Request(), "testPassword") assert sid and user.is_authenticated() assert sid != "stub" - session.delete(_session) - session.commit() - def test_user_update_password(): user.update_password("secondPassword") @@ -169,21 +155,14 @@ def test_user_has_credential(): def test_user_ssh_pub_key(): - from aurweb.db import session - assert user.ssh_pub_key is None - ssh_pub_key = SSHPubKey(UserID=user.ID, - Fingerprint="testFingerprint", - PubKey="testPubKey") - session.add(ssh_pub_key) - session.commit() + ssh_pub_key = create(SSHPubKey, UserID=user.ID, + Fingerprint="testFingerprint", + PubKey="testPubKey") assert user.ssh_pub_key == ssh_pub_key - session.delete(ssh_pub_key) - session.commit() - def test_user_credential_types(): from aurweb.db import session @@ -203,8 +182,7 @@ def test_user_credential_types(): assert aurweb.auth.trusted_user_or_dev(user) developer_type = query(AccountType, - AccountType.AccountType == "Developer")\ - .first() + AccountType.AccountType == "Developer").first() user.AccountType = developer_type session.commit() From 943d97efac1f6fca6c823e0edb416b3c300f4b3d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 04:48:49 -0700 Subject: [PATCH 0667/1891] add License SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/license.py | 11 +++++++++++ test/test_license.py | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 aurweb/models/license.py create mode 100644 test/test_license.py diff --git a/aurweb/models/license.py b/aurweb/models/license.py new file mode 100644 index 00000000..1c174925 --- /dev/null +++ b/aurweb/models/license.py @@ -0,0 +1,11 @@ +from sqlalchemy.orm import mapper + +from aurweb.schema import Licenses + + +class License: + def __init__(self, Name: str = None): + self.Name = Name + + +mapper(License, Licenses) diff --git a/test/test_license.py b/test/test_license.py new file mode 100644 index 00000000..feb7a396 --- /dev/null +++ b/test/test_license.py @@ -0,0 +1,25 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create +from aurweb.models.license import License +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db("Licenses") + + +def test_license_creation(): + license = create(License, Name="Test License") + assert bool(license.ID) + assert license.Name == "Test License" + + +def test_license_null_name_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(License) + session.rollback() From 75cc0be189271ed3583486c0b66463f8e43605f4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 05:06:38 -0700 Subject: [PATCH 0668/1891] add PackageLicense SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_license.py | 27 +++++++++++++++++ test/test_package_license.py | 52 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 aurweb/models/package_license.py create mode 100644 test/test_package_license.py diff --git a/aurweb/models/package_license.py b/aurweb/models/package_license.py new file mode 100644 index 00000000..187b113e --- /dev/null +++ b/aurweb/models/package_license.py @@ -0,0 +1,27 @@ +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.license import License +from aurweb.models.package import Package +from aurweb.schema import PackageLicenses + + +class PackageLicense: + def __init__(self, Package: Package = None, License: License = None): + self.Package = Package + self.License = License + + +properties = { + "Package": make_relationship(Package, + PackageLicenses.c.PackageID, + "package_license", + uselist=False), + "License": make_relationship(License, + PackageLicenses.c.LicenseID, + "package_license", + uselist=False) +} + +mapper(PackageLicense, PackageLicenses, properties=properties, + primary_key=[PackageLicenses.c.PackageID, PackageLicenses.c.LicenseID]) diff --git a/test/test_package_license.py b/test/test_package_license.py new file mode 100644 index 00000000..72eb3681 --- /dev/null +++ b/test/test_package_license.py @@ -0,0 +1,52 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query +from aurweb.models.account_type import AccountType +from aurweb.models.license import License +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_license import PackageLicense +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = license = pkgbase = package = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, license, pkgbase, package + + setup_test_db("Users", "PackageBases", "Packages", + "Licenses", "PackageLicenses") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + account_type=account_type) + + license = create(License, Name="Test License") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + package = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + + +def test_package_license(): + package_license = create(PackageLicense, Package=package, License=license) + assert package_license.License == license + assert package_license.Package == package + + +def test_package_license_null_package_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(PackageLicense, License=license) + session.rollback() + + +def test_package_license_null_license_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(PackageLicense, Package=package) + session.rollback() From a8a9c28783d606863b57066103e15b64d75fdb69 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 05:21:01 -0700 Subject: [PATCH 0669/1891] Jinja bugfix: add xmlns + xml:lang to This was not brought over during the initial commit involving partisl/layout.html. Signed-off-by: Kevin Morris --- templates/partials/layout.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/partials/layout.html b/templates/partials/layout.html index d30208a9..019ebff7 100644 --- a/templates/partials/layout.html +++ b/templates/partials/layout.html @@ -1,5 +1,6 @@ - + {% include 'partials/head.html' %} From 4201348dea2b74bfc172573209561f76b1a36597 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 05:34:27 -0700 Subject: [PATCH 0670/1891] add PackageGroup SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_group.py | 27 ++++++++++++++++++ test/test_package_group.py | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 aurweb/models/package_group.py create mode 100644 test/test_package_group.py diff --git a/aurweb/models/package_group.py b/aurweb/models/package_group.py new file mode 100644 index 00000000..8a32c00b --- /dev/null +++ b/aurweb/models/package_group.py @@ -0,0 +1,27 @@ +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.group import Group +from aurweb.models.package import Package +from aurweb.schema import PackageGroups + + +class PackageGroup: + def __init__(self, Package: Package = None, Group: Group = None): + self.Package = Package + self.Group = Group + + +properties = { + "Package": make_relationship(Package, + PackageGroups.c.PackageID, + "package_group", + uselist=False), + "Group": make_relationship(Group, + PackageGroups.c.GroupID, + "package_group", + uselist=False) +} + +mapper(PackageGroup, PackageGroups, properties=properties, + primary_key=[PackageGroups.c.PackageID, PackageGroups.c.GroupID]) diff --git a/test/test_package_group.py b/test/test_package_group.py new file mode 100644 index 00000000..28047a7f --- /dev/null +++ b/test/test_package_group.py @@ -0,0 +1,52 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query +from aurweb.models.account_type import AccountType +from aurweb.models.group import Group +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_group import PackageGroup +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = group = pkgbase = package = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, group, pkgbase, package + + setup_test_db("Users", "PackageBases", "Packages", + "Groups", "PackageGroups") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + account_type=account_type) + + group = create(Group, Name="Test Group") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + package = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + + +def test_package_group(): + package_group = create(PackageGroup, Package=package, Group=group) + assert package_group.Group == group + assert package_group.Package == package + + +def test_package_group_null_package_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(PackageGroup, Group=group) + session.rollback() + + +def test_package_group_null_group_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(PackageGroup, Package=package) + session.rollback() From 068c8ba638dd032df917d82af8fe6ffe70264ab3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 06:44:24 -0700 Subject: [PATCH 0671/1891] add DependencyType SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/dependency_type.py | 11 +++++++++++ test/test_dependency_type.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 aurweb/models/dependency_type.py create mode 100644 test/test_dependency_type.py diff --git a/aurweb/models/dependency_type.py b/aurweb/models/dependency_type.py new file mode 100644 index 00000000..87b38069 --- /dev/null +++ b/aurweb/models/dependency_type.py @@ -0,0 +1,11 @@ +from sqlalchemy.orm import mapper + +from aurweb.schema import DependencyTypes + + +class DependencyType: + def __init__(self, Name: str = None): + self.Name = Name + + +mapper(DependencyType, DependencyTypes) diff --git a/test/test_dependency_type.py b/test/test_dependency_type.py new file mode 100644 index 00000000..6c37cc58 --- /dev/null +++ b/test/test_dependency_type.py @@ -0,0 +1,31 @@ +import pytest + +from aurweb.db import create, delete, query +from aurweb.models.dependency_type import DependencyType +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db() + + +def test_dependency_types(): + dep_types = ["depends", "makedepends", "checkdepends", "optdepends"] + for dep_type in dep_types: + dependency_type = query(DependencyType, + DependencyType.Name == dep_type).first() + assert dependency_type is not None + + +def test_dependency_type_creation(): + dependency_type = create(DependencyType, Name="Test Type") + assert bool(dependency_type.ID) + assert dependency_type.Name == "Test Type" + delete(DependencyType, DependencyType.ID == dependency_type.ID) + + +def test_dependency_type_null_name_uses_default(): + dependency_type = create(DependencyType) + assert dependency_type.Name == str() + delete(DependencyType, DependencyType.ID == dependency_type.ID) From e401b92acb82a52f62441f8decb209448ce457a1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 07:21:54 -0700 Subject: [PATCH 0672/1891] add PackageDependency (PackageDepends) ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_dependency.py | 31 ++++++++ test/test_package_dependency.py | 113 ++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 aurweb/models/package_dependency.py create mode 100644 test/test_package_dependency.py diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py new file mode 100644 index 00000000..ae6ae62a --- /dev/null +++ b/aurweb/models/package_dependency.py @@ -0,0 +1,31 @@ +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.dependency_type import DependencyType +from aurweb.models.package import Package +from aurweb.schema import PackageDepends + + +class PackageDependency: + def __init__(self, Package: Package = None, + DependencyType: DependencyType = None, + DepName: str = None, DepDesc: str = None, + DepCondition: str = None, DepArch: str = None): + self.Package = Package + self.DependencyType = DependencyType + self.DepName = DepName # nullable=False + self.DepDesc = DepDesc + self.DepCondition = DepCondition + self.DepArch = DepArch + + +properties = { + "Package": make_relationship(Package, PackageDepends.c.PackageID, + "package_dependencies"), + "DependencyType": make_relationship(DependencyType, + PackageDepends.c.DepTypeID, + "package_dependencies") +} + +mapper(PackageDependency, PackageDepends, properties=properties, + primary_key=[PackageDepends.c.PackageID, PackageDepends.c.DepTypeID]) diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py new file mode 100644 index 00000000..fc21a08c --- /dev/null +++ b/test/test_package_dependency.py @@ -0,0 +1,113 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query +from aurweb.models.account_type import AccountType +from aurweb.models.dependency_type import DependencyType +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_dependency import PackageDependency +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = package = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase, package + + setup_test_db("Users", "PackageBases", "Packages", "PackageDepends") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + pkgbase = create(PackageBase, + Name="test-package", + Maintainer=user) + package = create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") + + +def test_package_dependencies(): + depends = query(DependencyType, DependencyType.Name == "depends").first() + pkgdep = create(PackageDependency, Package=package, + DependencyType=depends, + DepName="test-dep") + assert pkgdep.DepName == "test-dep" + assert pkgdep.Package == package + assert pkgdep.DependencyType == depends + assert pkgdep in depends.package_dependencies + assert pkgdep in package.package_dependencies + + makedepends = query(DependencyType, + DependencyType.Name == "makedepends").first() + pkgdep = create(PackageDependency, Package=package, + DependencyType=makedepends, + DepName="test-dep") + assert pkgdep.DepName == "test-dep" + assert pkgdep.Package == package + assert pkgdep.DependencyType == makedepends + assert pkgdep in makedepends.package_dependencies + assert pkgdep in package.package_dependencies + + checkdepends = query(DependencyType, + DependencyType.Name == "checkdepends").first() + pkgdep = create(PackageDependency, Package=package, + DependencyType=checkdepends, + DepName="test-dep") + assert pkgdep.DepName == "test-dep" + assert pkgdep.Package == package + assert pkgdep.DependencyType == checkdepends + assert pkgdep in checkdepends.package_dependencies + assert pkgdep in package.package_dependencies + + optdepends = query(DependencyType, + DependencyType.Name == "optdepends").first() + pkgdep = create(PackageDependency, Package=package, + DependencyType=optdepends, + DepName="test-dep") + assert pkgdep.DepName == "test-dep" + assert pkgdep.Package == package + assert pkgdep.DependencyType == optdepends + assert pkgdep in optdepends.package_dependencies + assert pkgdep in package.package_dependencies + + +def test_package_dependencies_null_package_raises_exception(): + from aurweb.db import session + + depends = query(DependencyType, DependencyType.Name == "depends").first() + with pytest.raises(IntegrityError): + create(PackageDependency, + DependencyType=depends, + DepName="test-dep") + session.rollback() + + +def test_package_dependencies_null_dependency_type_raises_exception(): + from aurweb.db import session + + with pytest.raises(IntegrityError): + create(PackageDependency, + Package=package, + DepName="test-dep") + session.rollback() + + +def test_package_dependencies_null_depname_raises_exception(): + from aurweb.db import session + + depends = query(DependencyType, DependencyType.Name == "depends").first() + with pytest.raises(IntegrityError): + create(PackageDependency, + Package=package, + DependencyType=depends) + session.rollback() From a9cfbce11e3c16c22d168f8fc55238f17ea78273 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 07:37:05 -0700 Subject: [PATCH 0673/1891] add RelationType SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/relation_type.py | 11 +++++++++++ test/test_relation_type.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 aurweb/models/relation_type.py create mode 100644 test/test_relation_type.py diff --git a/aurweb/models/relation_type.py b/aurweb/models/relation_type.py new file mode 100644 index 00000000..b4d1efbc --- /dev/null +++ b/aurweb/models/relation_type.py @@ -0,0 +1,11 @@ +from sqlalchemy.orm import mapper + +from aurweb.schema import RelationTypes + + +class RelationType: + def __init__(self, Name: str = None): + self.Name = Name + + +mapper(RelationType, RelationTypes) diff --git a/test/test_relation_type.py b/test/test_relation_type.py new file mode 100644 index 00000000..bf23505c --- /dev/null +++ b/test/test_relation_type.py @@ -0,0 +1,32 @@ +import pytest + +from aurweb.db import create, delete, query +from aurweb.models.relation_type import RelationType +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db() + + +def test_relation_type_creation(): + relation_type = create(RelationType, Name="test-relation") + assert bool(relation_type.ID) + assert relation_type.Name == "test-relation" + + delete(RelationType, RelationType.ID == relation_type.ID) + + +def test_relation_types(): + conflicts = query(RelationType, RelationType.Name == "conflicts").first() + assert conflicts is not None + assert conflicts.Name == "conflicts" + + provides = query(RelationType, RelationType.Name == "provides").first() + assert provides is not None + assert provides.Name == "provides" + + replaces = query(RelationType, RelationType.Name == "replaces").first() + assert replaces is not None + assert replaces.Name == "replaces" From 2b83d2fb6bb8b5066053220b5929d5d67333f9dd Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 1 Jun 2021 07:52:22 -0700 Subject: [PATCH 0674/1891] add PackageRelation SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_relation.py | 33 ++++++++++ test/test_package_relation.py | 100 ++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 aurweb/models/package_relation.py create mode 100644 test/test_package_relation.py diff --git a/aurweb/models/package_relation.py b/aurweb/models/package_relation.py new file mode 100644 index 00000000..196f1dee --- /dev/null +++ b/aurweb/models/package_relation.py @@ -0,0 +1,33 @@ +from sqlalchemy.orm import mapper + +from aurweb.db import make_relationship +from aurweb.models.package import Package +from aurweb.models.relation_type import RelationType +from aurweb.schema import PackageRelations + + +class PackageRelation: + def __init__(self, Package: Package = None, + RelationType: RelationType = None, + RelName: str = None, RelCondition: str = None, + RelArch: str = None): + self.Package = Package + self.RelationType = RelationType + self.RelName = RelName # nullable=False + self.RelCondition = RelCondition + self.RelArch = RelArch + + +properties = { + "Package": make_relationship(Package, PackageRelations.c.PackageID, + "package_relations"), + "RelationType": make_relationship(RelationType, + PackageRelations.c.RelTypeID, + "package_relations") +} + +mapper(PackageRelation, PackageRelations, properties=properties, + primary_key=[ + PackageRelations.c.PackageID, + PackageRelations.c.RelTypeID + ]) diff --git a/test/test_package_relation.py b/test/test_package_relation.py new file mode 100644 index 00000000..dd0455cd --- /dev/null +++ b/test/test_package_relation.py @@ -0,0 +1,100 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query +from aurweb.models.account_type import AccountType +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_relation import PackageRelation +from aurweb.models.relation_type import RelationType +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = package = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase, package + + setup_test_db("Users", "PackageBases", "Packages", "PackageRelations") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + pkgbase = create(PackageBase, + Name="test-package", + Maintainer=user) + package = create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") + + +def test_package_dependencies(): + conflicts = query(RelationType, RelationType.Name == "conflicts").first() + pkgrel = create(PackageRelation, Package=package, + RelationType=conflicts, + RelName="test-relation") + assert pkgrel.RelName == "test-relation" + assert pkgrel.Package == package + assert pkgrel.RelationType == conflicts + assert pkgrel in conflicts.package_relations + assert pkgrel in package.package_relations + + provides = query(RelationType, RelationType.Name == "provides").first() + pkgrel = create(PackageRelation, Package=package, + RelationType=provides, + RelName="test-relation") + assert pkgrel.RelName == "test-relation" + assert pkgrel.Package == package + assert pkgrel.RelationType == provides + assert pkgrel in provides.package_relations + assert pkgrel in package.package_relations + + replaces = query(RelationType, RelationType.Name == "replaces").first() + pkgrel = create(PackageRelation, Package=package, + RelationType=replaces, + RelName="test-relation") + assert pkgrel.RelName == "test-relation" + assert pkgrel.Package == package + assert pkgrel.RelationType == replaces + assert pkgrel in replaces.package_relations + assert pkgrel in package.package_relations + + +def test_package_dependencies_null_package_raises_exception(): + from aurweb.db import session + + conflicts = query(RelationType, RelationType.Name == "conflicts").first() + with pytest.raises(IntegrityError): + create(PackageRelation, + RelationType=conflicts, + RelName="test-relation") + session.rollback() + + +def test_package_dependencies_null_dependency_type_raises_exception(): + from aurweb.db import session + + with pytest.raises(IntegrityError): + create(PackageRelation, + Package=package, + RelName="test-relation") + session.rollback() + + +def test_package_dependencies_null_depname_raises_exception(): + from aurweb.db import session + + depends = query(RelationType, RelationType.Name == "depends").first() + with pytest.raises(IntegrityError): + create(PackageRelation, + Package=package, + RelationType=depends) + session.rollback() From a65a60604ab09e83f18cec58afb7a807b1eb2b30 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 3 Jun 2021 10:51:46 -0700 Subject: [PATCH 0675/1891] add ApiRateLimit SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/api_rate_limit.py | 15 +++++++++++++ test/test_api_rate_limit.py | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 aurweb/models/api_rate_limit.py create mode 100644 test/test_api_rate_limit.py diff --git a/aurweb/models/api_rate_limit.py b/aurweb/models/api_rate_limit.py new file mode 100644 index 00000000..44e7a463 --- /dev/null +++ b/aurweb/models/api_rate_limit.py @@ -0,0 +1,15 @@ +from sqlalchemy.orm import mapper + +from aurweb.schema import ApiRateLimit as _ApiRateLimit + + +class ApiRateLimit: + def __init__(self, IP: str = None, + Requests: int = None, + WindowStart: int = None): + self.IP = IP + self.Requests = Requests + self.WindowStart = WindowStart + + +mapper(ApiRateLimit, _ApiRateLimit, primary_key=[_ApiRateLimit.c.IP]) diff --git a/test/test_api_rate_limit.py b/test/test_api_rate_limit.py new file mode 100644 index 00000000..91ab5854 --- /dev/null +++ b/test/test_api_rate_limit.py @@ -0,0 +1,40 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create +from aurweb.models.api_rate_limit import ApiRateLimit +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db("ApiRateLimit") + + +def test_api_rate_key_creation(): + rate = create(ApiRateLimit, IP="127.0.0.1", Requests=10, WindowStart=1) + assert rate.IP == "127.0.0.1" + assert rate.Requests == 10 + assert rate.WindowStart == 1 + + +def test_api_rate_key_null_ip_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(ApiRateLimit, Requests=10, WindowStart=1) + session.rollback() + + +def test_api_rate_key_null_requests_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(ApiRateLimit, IP="127.0.0.1", WindowStart=1) + session.rollback() + + +def test_api_rate_key_null_window_start_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(ApiRateLimit, IP="127.0.0.1", WindowStart=1) + session.rollback() From e5df083d4553440af309be89c5dcdd11d68dc7d5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 3 Jun 2021 22:56:47 -0700 Subject: [PATCH 0676/1891] use String(max_len) for DECIMAL types with sqlite This solves an issue where DECIMAL is not native to sqlite by using a string to store values and converting them to float in user code. Signed-off-by: Kevin Morris --- aurweb/schema.py | 10 ++++++++-- web/html/addvote.php | 7 +++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/aurweb/schema.py b/aurweb/schema.py index f0162045..0d40e272 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -107,7 +107,10 @@ PackageBases = Table( Column('ID', INTEGER(unsigned=True), primary_key=True), Column('Name', String(255), nullable=False, unique=True), Column('NumVotes', INTEGER(unsigned=True), nullable=False, server_default=text("0")), - Column('Popularity', DECIMAL(10, 6, unsigned=True), nullable=False, server_default=text("0")), + Column('Popularity', + DECIMAL(10, 6, unsigned=True) + if db_backend == "mysql" else String(16), # Stubbed out to test. + nullable=False, server_default=text("0")), Column('OutOfDateTS', BIGINT(unsigned=True)), Column('FlaggerComment', Text, nullable=False), Column('SubmittedTS', BIGINT(unsigned=True), nullable=False), @@ -383,7 +386,10 @@ TU_VoteInfo = Table( Column('User', String(32), nullable=False), Column('Submitted', BIGINT(unsigned=True), nullable=False), Column('End', BIGINT(unsigned=True), nullable=False), - Column('Quorum', DECIMAL(2, 2, unsigned=True), nullable=False), + Column('Quorum', + DECIMAL(2, 2, unsigned=True) + if db_backend == "mysql" else String(4), + nullable=False), Column('SubmitterID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('Yes', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), Column('No', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), diff --git a/web/html/addvote.php b/web/html/addvote.php index 3672c031..70280cfd 100644 --- a/web/html/addvote.php +++ b/web/html/addvote.php @@ -67,8 +67,11 @@ if (has_credential(CRED_TU_ADD_VOTE)) { } } - if (!empty($_POST['addVote']) && empty($error)) { - add_tu_proposal($_POST['agenda'], $_POST['user'], $len, $quorum, $uid); + if (!empty($_POST['addVote']) && empty($error)) { + // Convert $quorum to a String of maximum length "12.34" (5). + $quorum_str = substr(strval($quorum), min(5, strlen($quorum)); + add_tu_proposal($_POST['agenda'], $_POST['user'], + $len, $quorum_str, $uid); print "

    " . __("New proposal submitted.") . "

    \n"; } else { From d7481b96499f06be0d9ca983bb9efc578b38eb97 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 4 Jun 2021 00:31:15 -0700 Subject: [PATCH 0677/1891] modify schema primary keys to be nullable+defaulted This fixes SQLAlchemy warnings related to primary keys not having an auto_increment or nullable. We've done this by making all foreign primary keys nullable. In ApiRateLimit's case, we can set a default str to act as a null, which seems a bit more sensible. Signed-off-by: Kevin Morris --- aurweb/models/package_group.py | 12 ++++++++++++ aurweb/models/package_keyword.py | 7 +++++++ aurweb/models/package_license.py | 14 ++++++++++++++ aurweb/schema.py | 12 ++++++------ test/test_api_rate_limit.py | 8 +++----- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/aurweb/models/package_group.py b/aurweb/models/package_group.py index 8a32c00b..c155fe00 100644 --- a/aurweb/models/package_group.py +++ b/aurweb/models/package_group.py @@ -1,4 +1,5 @@ from sqlalchemy.orm import mapper +from sqlalchemy.exc import IntegrityError from aurweb.db import make_relationship from aurweb.models.group import Group @@ -9,7 +10,18 @@ from aurweb.schema import PackageGroups class PackageGroup: def __init__(self, Package: Package = None, Group: Group = None): self.Package = Package + if not self.Package: + raise IntegrityError( + statement="Primary key PackageID cannot be null.", + orig="PackageGroups.PackageID", + params=("NULL")) + self.Group = Group + if not self.Group: + raise IntegrityError( + statement="Primary key GroupID cannot be null.", + orig="PackageGroups.GroupID", + params=("NULL")) properties = { diff --git a/aurweb/models/package_keyword.py b/aurweb/models/package_keyword.py index 87d97558..4a66f38e 100644 --- a/aurweb/models/package_keyword.py +++ b/aurweb/models/package_keyword.py @@ -1,4 +1,5 @@ from sqlalchemy.orm import mapper +from sqlalchemy.exc import IntegrityError from aurweb.db import make_relationship from aurweb.models.package_base import PackageBase @@ -10,6 +11,12 @@ class PackageKeyword: PackageBase: PackageBase = None, Keyword: str = None): self.PackageBase = PackageBase + if not self.PackageBase: + raise IntegrityError( + statement="Primary key PackageBaseID cannot be null.", + orig="PackageKeywords.PackageBaseID", + params=("NULL")) + self.Keyword = Keyword diff --git a/aurweb/models/package_license.py b/aurweb/models/package_license.py index 187b113e..6f23f84a 100644 --- a/aurweb/models/package_license.py +++ b/aurweb/models/package_license.py @@ -1,4 +1,5 @@ from sqlalchemy.orm import mapper +from sqlalchemy.exc import IntegrityError from aurweb.db import make_relationship from aurweb.models.license import License @@ -9,7 +10,18 @@ from aurweb.schema import PackageLicenses class PackageLicense: def __init__(self, Package: Package = None, License: License = None): self.Package = Package + if not self.Package: + raise IntegrityError( + statement="Primary key PackageID cannot be null.", + orig="PackageLicenses.PackageID", + params=("NULL")) + self.License = License + if not self.License: + raise IntegrityError( + statement="Primary key LicenseID cannot be null.", + orig="PackageLicenses.LicenseID", + params=("NULL")) properties = { @@ -21,6 +33,8 @@ properties = { PackageLicenses.c.LicenseID, "package_license", uselist=False) + + } mapper(PackageLicense, PackageLicenses, properties=properties, diff --git a/aurweb/schema.py b/aurweb/schema.py index 0d40e272..fa8923a3 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -133,7 +133,7 @@ PackageBases = Table( # Keywords of package bases PackageKeywords = Table( 'PackageKeywords', metadata, - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), primary_key=True, nullable=True), Column('Keyword', String(255), primary_key=True, nullable=False, server_default=text("''")), mysql_engine='InnoDB', mysql_charset='utf8mb4', @@ -170,8 +170,8 @@ Licenses = Table( # Information about package-license-relations PackageLicenses = Table( 'PackageLicenses', metadata, - Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=False), - Column('LicenseID', ForeignKey('Licenses.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=True), + Column('LicenseID', ForeignKey('Licenses.ID', ondelete='CASCADE'), primary_key=True, nullable=True), mysql_engine='InnoDB', ) @@ -190,8 +190,8 @@ Groups = Table( # Information about package-group-relations PackageGroups = Table( 'PackageGroups', metadata, - Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=False), - Column('GroupID', ForeignKey('Groups.ID', ondelete='CASCADE'), primary_key=True, nullable=False), + Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=True), + Column('GroupID', ForeignKey('Groups.ID', ondelete='CASCADE'), primary_key=True, nullable=True), mysql_engine='InnoDB', ) @@ -445,7 +445,7 @@ AcceptedTerms = Table( # Rate limits for API ApiRateLimit = Table( 'ApiRateLimit', metadata, - Column('IP', String(45), primary_key=True), + Column('IP', String(45), primary_key=True, unique=True, default=str()), Column('Requests', INTEGER(11), nullable=False), Column('WindowStart', BIGINT(20), nullable=False), Index('ApiRateLimitWindowStart', 'WindowStart'), diff --git a/test/test_api_rate_limit.py b/test/test_api_rate_limit.py index 91ab5854..c599ddcf 100644 --- a/test/test_api_rate_limit.py +++ b/test/test_api_rate_limit.py @@ -19,11 +19,9 @@ def test_api_rate_key_creation(): assert rate.WindowStart == 1 -def test_api_rate_key_null_ip_raises_exception(): - from aurweb.db import session - with pytest.raises(IntegrityError): - create(ApiRateLimit, Requests=10, WindowStart=1) - session.rollback() +def test_api_rate_key_ip_default(): + api_rate_limit = create(ApiRateLimit, Requests=10, WindowStart=1) + assert api_rate_limit.IP == str() def test_api_rate_key_null_requests_raises_exception(): From aecb64947354283a9b2dd357a67e997c78f4adac Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 4 Jun 2021 00:43:57 -0700 Subject: [PATCH 0678/1891] use mysql backend in config.dev First off: This commit changes the default development database backend to mysql. sqlite, however, is still completely supported with the caveat that a user must now modify config.dev to use the sqlite backend. While looking into this, it was discovered that our SQLAlchemy backend for mysql (mysql-connector) completely broke model attributes when we switched to utf8mb4_bin (binary) -- it does not correct the correct conversion to and from binary utf8mb4. The new, replacement dependency mysqlclient does. mysqlclient is also recommended in SQLAlchemy documentation as the "best" one available. The mysqlclient backend uses a different exception flow then sqlite, and so tests expecting IntegrityError has to be modified to expect OperationalError from sqlalchemy.exc. So, for each model that we define, check keys that can't be NULL and raise sqlalchemy.exc.IntegrityError if we have to. This way we keep our exceptions uniform. Signed-off-by: Kevin Morris --- aurweb/db.py | 39 ++++-- aurweb/initdb.py | 6 +- aurweb/models/accepted_term.py | 13 ++ aurweb/models/api_rate_limit.py | 13 ++ aurweb/models/group.py | 6 + aurweb/models/license.py | 6 + aurweb/models/package.py | 13 ++ aurweb/models/package_base.py | 7 + aurweb/models/package_dependency.py | 21 ++- aurweb/models/package_group.py | 2 +- aurweb/models/package_keyword.py | 2 +- aurweb/models/package_license.py | 2 +- aurweb/models/package_relation.py | 19 +++ aurweb/models/session.py | 12 +- aurweb/models/term.py | 13 ++ conf/config.dev | 20 +-- test/Makefile | 2 +- test/test_accounts_routes.py | 42 ++++-- test/test_api_rate_limit.py | 2 +- test/test_auth.py | 13 +- test/test_ban.py | 3 +- test/test_db.py | 202 ++++++++++++++++++++-------- test/test_initdb.py | 20 +-- test/test_package_relation.py | 18 ++- test/test_session.py | 2 +- 25 files changed, 363 insertions(+), 135 deletions(-) diff --git a/aurweb/db.py b/aurweb/db.py index 500cf95a..590712e0 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -98,9 +98,11 @@ def get_sqlalchemy_url(): param_query = None else: port = None - param_query = {'unix_socket': aurweb.config.get('database', 'socket')} + param_query = { + 'unix_socket': aurweb.config.get('database', 'socket') + } return constructor( - 'mysql+mysqlconnector', + 'mysql+mysqldb', username=aurweb.config.get('database', 'user'), password=aurweb.config.get('database', 'password'), host=aurweb.config.get('database', 'host'), @@ -117,7 +119,7 @@ def get_sqlalchemy_url(): raise ValueError('unsupported database backend') -def get_engine(): +def get_engine(echo: bool = False): """ Return the global SQLAlchemy engine. @@ -135,13 +137,24 @@ def get_engine(): # check_same_thread is for a SQLite technicality # https://fastapi.tiangolo.com/tutorial/sql-databases/#note connect_args["check_same_thread"] = False - engine = create_engine(get_sqlalchemy_url(), connect_args=connect_args) + + engine = create_engine(get_sqlalchemy_url(), + connect_args=connect_args, + echo=echo) Session = sessionmaker(autocommit=False, autoflush=True, bind=engine) session = Session() return engine +def kill_engine(): + global engine, Session, session + if engine: + session.close() + engine.dispose() + engine = Session = session = None + + def connect(): """ Return an SQLAlchemy connection. Connections are usually pooled. See @@ -160,8 +173,7 @@ class ConnectionExecutor: def __init__(self, conn, backend=aurweb.config.get("database", "backend")): self._conn = conn if backend == "mysql": - import mysql.connector - self._paramstyle = mysql.connector.paramstyle + self._paramstyle = "format" elif backend == "sqlite": import sqlite3 self._paramstyle = sqlite3.paramstyle @@ -197,18 +209,17 @@ class Connection: aur_db_backend = aurweb.config.get('database', 'backend') if aur_db_backend == 'mysql': - import mysql.connector + import MySQLdb aur_db_host = aurweb.config.get('database', 'host') aur_db_name = aurweb.config.get('database', 'name') aur_db_user = aurweb.config.get('database', 'user') aur_db_pass = aurweb.config.get('database', 'password') aur_db_socket = aurweb.config.get('database', 'socket') - self._conn = mysql.connector.connect(host=aur_db_host, - user=aur_db_user, - passwd=aur_db_pass, - db=aur_db_name, - unix_socket=aur_db_socket, - buffered=True) + self._conn = MySQLdb.connect(host=aur_db_host, + user=aur_db_user, + passwd=aur_db_pass, + db=aur_db_name, + unix_socket=aur_db_socket) elif aur_db_backend == 'sqlite': import sqlite3 aur_db_name = aurweb.config.get('database', 'name') @@ -217,7 +228,7 @@ class Connection: else: raise ValueError('unsupported database backend') - self._conn = ConnectionExecutor(self._conn) + self._conn = ConnectionExecutor(self._conn, aur_db_backend) def execute(self, query, params=()): return self._conn.execute(query, params) diff --git a/aurweb/initdb.py b/aurweb/initdb.py index 5f55bfc9..46f079c0 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -2,7 +2,6 @@ import argparse import alembic.command import alembic.config -import sqlalchemy import aurweb.db import aurweb.schema @@ -34,6 +33,8 @@ def feed_initial_data(conn): def run(args): + aurweb.config.rehash() + # Ensure Alembic is fine before we do the real work, in order not to fail at # the last step and leave the database in an inconsistent state. The # configuration is loaded lazily, so we query it to force its loading. @@ -42,8 +43,7 @@ def run(args): alembic_config.get_main_option('script_location') alembic_config.attributes["configure_logger"] = False - engine = sqlalchemy.create_engine(aurweb.db.get_sqlalchemy_url(), - echo=(args.verbose >= 1)) + engine = aurweb.db.get_engine(echo=(args.verbose >= 1)) aurweb.schema.metadata.create_all(engine) feed_initial_data(engine.connect()) diff --git a/aurweb/models/accepted_term.py b/aurweb/models/accepted_term.py index 6e8ffe99..483109f1 100644 --- a/aurweb/models/accepted_term.py +++ b/aurweb/models/accepted_term.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.db import make_relationship @@ -11,7 +12,19 @@ class AcceptedTerm: User: User = None, Term: Term = None, Revision: int = None): self.User = User + if not self.User: + raise IntegrityError( + statement="Foreign key UserID cannot be null.", + orig="AcceptedTerms.UserID", + params=("NULL")) + self.Term = Term + if not self.Term: + raise IntegrityError( + statement="Foreign key TermID cannot be null.", + orig="AcceptedTerms.TermID", + params=("NULL")) + self.Revision = Revision diff --git a/aurweb/models/api_rate_limit.py b/aurweb/models/api_rate_limit.py index 44e7a463..8b945b6a 100644 --- a/aurweb/models/api_rate_limit.py +++ b/aurweb/models/api_rate_limit.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.schema import ApiRateLimit as _ApiRateLimit @@ -8,8 +9,20 @@ class ApiRateLimit: Requests: int = None, WindowStart: int = None): self.IP = IP + self.Requests = Requests + if self.Requests is None: + raise IntegrityError( + statement="Column Requests cannot be null.", + orig="ApiRateLimit.Requests", + params=("NULL")) + self.WindowStart = WindowStart + if self.WindowStart is None: + raise IntegrityError( + statement="Column WindowStart cannot be null.", + orig="ApiRateLimit.WindowStart", + params=("NULL")) mapper(ApiRateLimit, _ApiRateLimit, primary_key=[_ApiRateLimit.c.IP]) diff --git a/aurweb/models/group.py b/aurweb/models/group.py index 5d4f3834..c5583eb4 100644 --- a/aurweb/models/group.py +++ b/aurweb/models/group.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.schema import Groups @@ -6,6 +7,11 @@ from aurweb.schema import Groups class Group: def __init__(self, Name: str = None): self.Name = Name + if not self.Name: + raise IntegrityError( + statement="Column Name cannot be null.", + orig="Groups.Name", + params=("NULL")) mapper(Group, Groups) diff --git a/aurweb/models/license.py b/aurweb/models/license.py index 1c174925..bcc02713 100644 --- a/aurweb/models/license.py +++ b/aurweb/models/license.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.schema import Licenses @@ -6,6 +7,11 @@ from aurweb.schema import Licenses class License: def __init__(self, Name: str = None): self.Name = Name + if not self.Name: + raise IntegrityError( + statement="Column Name cannot be null.", + orig="Licenses.Name", + params=("NULL")) mapper(License, Licenses) diff --git a/aurweb/models/package.py b/aurweb/models/package.py index fa82bb74..28a13791 100644 --- a/aurweb/models/package.py +++ b/aurweb/models/package.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.db import make_relationship @@ -11,7 +12,19 @@ class Package: Name: str = None, Version: str = None, Description: str = None, URL: str = None): self.PackageBase = PackageBase + if not self.PackageBase: + raise IntegrityError( + statement="Foreign key UserID cannot be null.", + orig="Packages.PackageBaseID", + params=("NULL")) + self.Name = Name + if not self.Name: + raise IntegrityError( + statement="Column Name cannot be null.", + orig="Packages.Name", + params=("NULL")) + self.Version = Version self.Description = Description self.URL = URL diff --git a/aurweb/models/package_base.py b/aurweb/models/package_base.py index 57e5a46b..699559d5 100644 --- a/aurweb/models/package_base.py +++ b/aurweb/models/package_base.py @@ -1,5 +1,6 @@ from datetime import datetime +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.db import make_relationship @@ -12,6 +13,12 @@ class PackageBase: Maintainer: User = None, Submitter: User = None, Packager: User = None, **kwargs): self.Name = Name + if not self.Name: + raise IntegrityError( + statement="Column Name cannot be null.", + orig="PackageBases.Name", + params=("NULL")) + self.Flagger = Flagger self.Maintainer = Maintainer self.Submitter = Submitter diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index ae6ae62a..21801802 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.db import make_relationship @@ -12,8 +13,26 @@ class PackageDependency: DepName: str = None, DepDesc: str = None, DepCondition: str = None, DepArch: str = None): self.Package = Package + if not self.Package: + raise IntegrityError( + statement="Foreign key PackageID cannot be null.", + orig="PackageDependencies.PackageID", + params=("NULL")) + self.DependencyType = DependencyType - self.DepName = DepName # nullable=False + if not self.DependencyType: + raise IntegrityError( + statement="Foreign key DepTypeID cannot be null.", + orig="PackageDependencies.DepTypeID", + params=("NULL")) + + self.DepName = DepName + if not self.DepName: + raise IntegrityError( + statement="Column DepName cannot be null.", + orig="PackageDependencies.DepName", + params=("NULL")) + self.DepDesc = DepDesc self.DepCondition = DepCondition self.DepArch = DepArch diff --git a/aurweb/models/package_group.py b/aurweb/models/package_group.py index c155fe00..19a11c80 100644 --- a/aurweb/models/package_group.py +++ b/aurweb/models/package_group.py @@ -1,5 +1,5 @@ -from sqlalchemy.orm import mapper from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import mapper from aurweb.db import make_relationship from aurweb.models.group import Group diff --git a/aurweb/models/package_keyword.py b/aurweb/models/package_keyword.py index 4a66f38e..2bae223c 100644 --- a/aurweb/models/package_keyword.py +++ b/aurweb/models/package_keyword.py @@ -1,5 +1,5 @@ -from sqlalchemy.orm import mapper from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import mapper from aurweb.db import make_relationship from aurweb.models.package_base import PackageBase diff --git a/aurweb/models/package_license.py b/aurweb/models/package_license.py index 6f23f84a..491874a4 100644 --- a/aurweb/models/package_license.py +++ b/aurweb/models/package_license.py @@ -1,5 +1,5 @@ -from sqlalchemy.orm import mapper from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import mapper from aurweb.db import make_relationship from aurweb.models.license import License diff --git a/aurweb/models/package_relation.py b/aurweb/models/package_relation.py index 196f1dee..d9ade727 100644 --- a/aurweb/models/package_relation.py +++ b/aurweb/models/package_relation.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.db import make_relationship @@ -12,8 +13,26 @@ class PackageRelation: RelName: str = None, RelCondition: str = None, RelArch: str = None): self.Package = Package + if not self.Package: + raise IntegrityError( + statement="Foreign key PackageID cannot be null.", + orig="PackageRelations.PackageID", + params=("NULL")) + self.RelationType = RelationType + if not self.RelationType: + raise IntegrityError( + statement="Foreign key RelTypeID cannot be null.", + orig="PackageRelations.RelTypeID", + params=("NULL")) + self.RelName = RelName # nullable=False + if not self.RelName: + raise IntegrityError( + statement="Column RelName cannot be null.", + orig="PackageRelations.RelName", + params=("NULL")) + self.RelCondition = RelCondition self.RelArch = RelArch diff --git a/aurweb/models/session.py b/aurweb/models/session.py index 60749303..f1e0fff5 100644 --- a/aurweb/models/session.py +++ b/aurweb/models/session.py @@ -1,16 +1,20 @@ -from sqlalchemy import Column, Integer +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, mapper, relationship -from aurweb.db import make_random_value +from aurweb.db import make_random_value, query from aurweb.models.user import User from aurweb.schema import Sessions class Session: - UsersID = Column(Integer, nullable=True) - def __init__(self, **kwargs): self.UsersID = kwargs.get("UsersID") + if not query(User, User.ID == self.UsersID).first(): + raise IntegrityError( + statement="Foreign key UsersID cannot be null.", + orig="Sessions.UsersID", + params=("NULL")) + self.SessionID = kwargs.get("SessionID") self.LastUpdateTS = kwargs.get("LastUpdateTS") diff --git a/aurweb/models/term.py b/aurweb/models/term.py index 1b4902f7..1a0780df 100644 --- a/aurweb/models/term.py +++ b/aurweb/models/term.py @@ -1,3 +1,4 @@ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import mapper from aurweb.schema import Terms @@ -8,7 +9,19 @@ class Term: Description: str = None, URL: str = None, Revision: int = None): self.Description = Description + if not self.Description: + raise IntegrityError( + statement="Column Description cannot be null.", + orig="Terms.Description", + params=("NULL")) + self.URL = URL + if not self.URL: + raise IntegrityError( + statement="Column URL cannot be null.", + orig="Terms.URL", + params=("NULL")) + self.Revision = Revision diff --git a/conf/config.dev b/conf/config.dev index 94775a92..45d940e6 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -6,17 +6,19 @@ ; development-specific options too. [database] -backend = sqlite -name = YOUR_AUR_ROOT/aurweb.sqlite3 +; Options: mysql, sqlite. +backend = mysql -; Alternative MySQL configuration (Use either port of socket, if both defined port takes priority) -;backend = mysql -;name = aurweb -;user = aur -;password = aur -;host = localhost +; If using sqlite, set name to the database file path. +name = aurweb + +; MySQL database information. User defaults to root for containerized +; testing with mysqldb. This should be set to a non-root user. +user = root +;password = non-root-user-password +host = localhost ;port = 3306 -;socket = /var/run/mysqld/mysqld.sock +socket = /var/run/mysqld/mysqld.sock [options] aurwebdir = YOUR_AUR_ROOT diff --git a/test/Makefile b/test/Makefile index 060e57c2..920c7113 100644 --- a/test/Makefile +++ b/test/Makefile @@ -8,7 +8,7 @@ MAKEFLAGS = -j1 check: sh pytest pytest: - cd .. && AUR_CONFIG=conf/config coverage run --append /usr/bin/pytest test + cd .. && coverage run --append /usr/bin/pytest test ifdef PROVE sh: diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 0f813823..3080a505 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -802,18 +802,40 @@ def test_post_account_edit_ssh_pub_key(): assert response.status_code == int(HTTPStatus.OK) # Now let's update what's already there to gain coverage over that path. - pk = str() - with tempfile.TemporaryDirectory() as tmpdir: - with open("/dev/null", "w") as null: - proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], - stdout=null, stderr=null) - proc.wait() - assert proc.returncode == 0 + post_data["PK"] = make_ssh_pubkey() - # Read in the public key, then delete the temp dir we made. - pk = open(f"{tmpdir}/test.ssh.pub").read().rstrip() + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) - post_data["PK"] = pk + assert response.status_code == int(HTTPStatus.OK) + + +def test_post_account_edit_missing_ssh_pubkey(): + request = Request() + sid = user.login(request, "testPassword") + + post_data = { + "U": user.Username, + "E": user.Email, + "PK": make_ssh_pubkey(), + "passwd": "testPassword" + } + + with client as request: + response = request.post("/account/test/edit", cookies={ + "AURSID": sid + }, data=post_data, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + post_data = { + "U": user.Username, + "E": user.Email, + "PK": str(), # Pass an empty string now to walk the delete path. + "passwd": "testPassword" + } with client as request: response = request.post("/account/test/edit", cookies={ diff --git a/test/test_api_rate_limit.py b/test/test_api_rate_limit.py index c599ddcf..536e3841 100644 --- a/test/test_api_rate_limit.py +++ b/test/test_api_rate_limit.py @@ -34,5 +34,5 @@ def test_api_rate_key_null_requests_raises_exception(): def test_api_rate_key_null_window_start_raises_exception(): from aurweb.db import session with pytest.raises(IntegrityError): - create(ApiRateLimit, IP="127.0.0.1", WindowStart=1) + create(ApiRateLimit, IP="127.0.0.1", Requests=1) session.rollback() diff --git a/test/test_auth.py b/test/test_auth.py index 7837e7f7..42eac040 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -4,6 +4,8 @@ import pytest from starlette.authentication import AuthenticationError +import aurweb.config + from aurweb.auth import BasicAuthBackend, has_credential from aurweb.db import create, query from aurweb.models.account_type import AccountType @@ -53,13 +55,12 @@ async def test_auth_backend_invalid_sid(): async def test_auth_backend_invalid_user_id(): # Create a new session with a fake user id. now_ts = datetime.utcnow().timestamp() - create(Session, UsersID=666, SessionID="realSession", - LastUpdateTS=now_ts + 5) + db_backend = aurweb.config.get("database", "backend") + with pytest.raises(IntegrityError): + create(Session, UsersID=666, SessionID="realSession", + LastUpdateTS=now_ts + 5) - # Here, we specify a real SID; but it's user is not there. - request.cookies["AURSID"] = "realSession" - with pytest.raises(AuthenticationError, match="Invalid User ID: 666"): - await backend.authenticate(request) + session.rollback() @pytest.mark.asyncio diff --git a/test/test_ban.py b/test/test_ban.py index a4fa5a28..b728644b 100644 --- a/test/test_ban.py +++ b/test/test_ban.py @@ -33,8 +33,7 @@ def test_ban(): def test_invalid_ban(): from aurweb.db import session - with pytest.raises(sa_exc.IntegrityError, - match="NOT NULL constraint failed: Bans.IPAddress"): + with pytest.raises(sa_exc.IntegrityError): bad_ban = Ban(BanTS=datetime.utcnow()) session.add(bad_ban) diff --git a/test/test_db.py b/test/test_db.py index e0946ed5..3911134f 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -5,16 +5,22 @@ import tempfile from unittest import mock -import mysql.connector import pytest import aurweb.config +import aurweb.initdb from aurweb import db from aurweb.models.account_type import AccountType from aurweb.testing import setup_test_db +class Args: + """ Stub arguments used for running aurweb.initdb. """ + use_alembic = True + verbose = True + + class DBCursor: """ A fake database cursor object used in tests. """ items = [] @@ -38,27 +44,73 @@ class DBConnection: pass +def make_temp_config(config_file, *replacements): + """ Generate a temporary config file with a set of replacements. + + :param *replacements: A variable number of tuple regex replacement pairs + :return: A tuple containing (temp directory, temp config file) + """ + tmpdir = tempfile.TemporaryDirectory() + tmp = os.path.join(tmpdir.name, "config.tmp") + with open(config_file) as f: + config = f.read() + for repl in list(replacements): + config = re.sub(repl[0], repl[1], config) + with open(tmp, "w") as o: + o.write(config) + aurwebdir = aurweb.config.get("options", "aurwebdir") + defaults = os.path.join(aurwebdir, "conf/config.defaults") + with open(defaults) as i: + with open(f"{tmp}.defaults", "w") as o: + o.write(i.read()) + return tmpdir, tmp + + +def make_temp_sqlite_config(config_file): + return make_temp_config(config_file, + (r"backend = .*", "backend = sqlite"), + (r"name = .*", "name = /tmp/aurweb.sqlite3")) + + +def make_temp_mysql_config(config_file): + return make_temp_config(config_file, + (r"backend = .*", "backend = mysql"), + (r"name = .*", "name = aurweb")) + + @pytest.fixture(autouse=True) def setup_db(): - setup_test_db("Bans") + if os.path.exists("/tmp/aurweb.sqlite3"): + os.remove("/tmp/aurweb.sqlite3") + + # In various places in this test, we reinitialize the engine. + # Make sure we kill the previous engine before initializing + # it via setup_test_db(). + aurweb.db.kill_engine() + setup_test_db() def test_sqlalchemy_sqlite_url(): - with mock.patch.dict(os.environ, {"AUR_CONFIG": "conf/config.dev"}): - aurweb.config.rehash() - assert db.get_sqlalchemy_url() + tmpctx, tmp = make_temp_sqlite_config("conf/config") + with tmpctx: + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() + assert db.get_sqlalchemy_url() aurweb.config.rehash() def test_sqlalchemy_mysql_url(): - with mock.patch.dict(os.environ, {"AUR_CONFIG": "conf/config.defaults"}): - aurweb.config.rehash() - assert db.get_sqlalchemy_url() + tmpctx, tmp = make_temp_mysql_config("conf/config") + with tmpctx: + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() + assert db.get_sqlalchemy_url() aurweb.config.rehash() def test_sqlalchemy_mysql_port_url(): - tmpctx, tmp = make_temp_config("conf/config.defaults", ";port = 3306", "port = 3306") + tmpctx, tmp = make_temp_config("conf/config", + (r";port = 3306", "port = 3306")) with tmpctx: with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): @@ -67,18 +119,9 @@ def test_sqlalchemy_mysql_port_url(): aurweb.config.rehash() -def make_temp_config(config_file, src_str, replace_with): - tmpdir = tempfile.TemporaryDirectory() - tmp = os.path.join(tmpdir.name, "config.tmp") - with open(config_file) as f: - config = re.sub(src_str, f'{replace_with}', f.read()) - with open(tmp, "w") as o: - o.write(config) - return tmpdir, tmp - - def test_sqlalchemy_unknown_backend(): - tmpctx, tmp = make_temp_config("conf/config", "backend = sqlite", "backend = blah") + tmpctx, tmp = make_temp_config("conf/config", + (r"backend = mysql", "backend = blah")) with tmpctx: with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): @@ -89,22 +132,31 @@ def test_sqlalchemy_unknown_backend(): def test_db_connects_without_fail(): + """ This only tests the actual config supplied to pytest. """ db.connect() assert db.engine is not None -def test_connection_class_without_fail(): - conn = db.Connection() +def test_connection_class_sqlite_without_fail(): + tmpctx, tmp = make_temp_sqlite_config("conf/config") + with tmpctx: + with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): + aurweb.config.rehash() - cur = conn.execute( - "SELECT AccountType FROM AccountTypes WHERE ID = ?", (1,)) - account_type = cur.fetchone()[0] + aurweb.db.kill_engine() + aurweb.initdb.run(Args()) - assert account_type == "User" + conn = db.Connection() + cur = conn.execute( + "SELECT AccountType FROM AccountTypes WHERE ID = ?", (1,)) + account_type = cur.fetchone()[0] + assert account_type == "User" + aurweb.config.rehash() def test_connection_class_unsupported_backend(): - tmpctx, tmp = make_temp_config("conf/config", "backend = sqlite", "backend = blah") + tmpctx, tmp = make_temp_config("conf/config", + (r"backend = mysql", "backend = blah")) with tmpctx: with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): @@ -114,10 +166,9 @@ def test_connection_class_unsupported_backend(): aurweb.config.rehash() -@mock.patch("mysql.connector.connect", mock.MagicMock(return_value=True)) -@mock.patch.object(mysql.connector, "paramstyle", "qmark") +@mock.patch("MySQLdb.connect", mock.MagicMock(return_value=True)) def test_connection_mysql(): - tmpctx, tmp = make_temp_config("conf/config", "backend = sqlite", "backend = mysql") + tmpctx, tmp = make_temp_mysql_config("conf/config") with tmpctx: with mock.patch.dict(os.environ, { "AUR_CONFIG": tmp, @@ -137,44 +188,78 @@ def test_connection_sqlite(): @mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) @mock.patch.object(sqlite3, "paramstyle", "format") def test_connection_execute_paramstyle_format(): - conn = db.Connection() + tmpctx, tmp = make_temp_sqlite_config("conf/config") - # First, test ? to %s format replacement. - account_types = conn\ - .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"])\ - .fetchall() - assert account_types == \ - ["SELECT * FROM AccountTypes WHERE AccountType = %s", ["User"]] + with tmpctx: + with mock.patch.dict(os.environ, { + "AUR_CONFIG": tmp, + "AUR_CONFIG_DEFAULTS": "conf/config.defaults" + }): + aurweb.config.rehash() - # Test other format replacement. - account_types = conn\ - .execute("SELECT * FROM AccountTypes WHERE AccountType = %", ["User"])\ - .fetchall() - assert account_types == \ - ["SELECT * FROM AccountTypes WHERE AccountType = %%", ["User"]] + aurweb.db.kill_engine() + aurweb.initdb.run(Args()) + + conn = db.Connection() + + # First, test ? to %s format replacement. + account_types = conn\ + .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", + ["User"]).fetchall() + assert account_types == \ + ["SELECT * FROM AccountTypes WHERE AccountType = %s", ["User"]] + + # Test other format replacement. + account_types = conn\ + .execute("SELECT * FROM AccountTypes WHERE AccountType = %", + ["User"]).fetchall() + assert account_types == \ + ["SELECT * FROM AccountTypes WHERE AccountType = %%", ["User"]] + aurweb.config.rehash() @mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) @mock.patch.object(sqlite3, "paramstyle", "qmark") def test_connection_execute_paramstyle_qmark(): - conn = db.Connection() - # We don't modify anything when using qmark, so test equality. - account_types = conn\ - .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"])\ - .fetchall() - assert account_types == \ - ["SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"]] + tmpctx, tmp = make_temp_sqlite_config("conf/config") + + with tmpctx: + with mock.patch.dict(os.environ, { + "AUR_CONFIG": tmp, + "AUR_CONFIG_DEFAULTS": "conf/config.defaults" + }): + aurweb.config.rehash() + + aurweb.db.kill_engine() + aurweb.initdb.run(Args()) + + conn = db.Connection() + # We don't modify anything when using qmark, so test equality. + account_types = conn\ + .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", + ["User"]).fetchall() + assert account_types == \ + ["SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"]] + aurweb.config.rehash() @mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) @mock.patch.object(sqlite3, "paramstyle", "unsupported") def test_connection_execute_paramstyle_unsupported(): - conn = db.Connection() - with pytest.raises(ValueError, match="unsupported paramstyle"): - conn.execute( - "SELECT * FROM AccountTypes WHERE AccountType = ?", - ["User"] - ).fetchall() + tmpctx, tmp = make_temp_sqlite_config("conf/config") + with tmpctx: + with mock.patch.dict(os.environ, { + "AUR_CONFIG": tmp, + "AUR_CONFIG_DEFAULTS": "conf/config.defaults" + }): + aurweb.config.rehash() + conn = db.Connection() + with pytest.raises(ValueError, match="unsupported paramstyle"): + conn.execute( + "SELECT * FROM AccountTypes WHERE AccountType = ?", + ["User"] + ).fetchall() + aurweb.config.rehash() def test_create_delete(): @@ -186,13 +271,12 @@ def test_create_delete(): assert record is None -@mock.patch("mysql.connector.paramstyle", "qmark") def test_connection_executor_mysql_paramstyle(): executor = db.ConnectionExecutor(None, backend="mysql") - assert executor.paramstyle() == "qmark" + assert executor.paramstyle() == "format" @mock.patch("sqlite3.paramstyle", "pyformat") def test_connection_executor_sqlite_paramstyle(): executor = db.ConnectionExecutor(None, backend="sqlite") - assert executor.paramstyle() == "pyformat" + assert executor.paramstyle() == sqlite3.paramstyle diff --git a/test/test_initdb.py b/test/test_initdb.py index eae33007..c7d29ee2 100644 --- a/test/test_initdb.py +++ b/test/test_initdb.py @@ -1,27 +1,19 @@ -import pytest - import aurweb.config import aurweb.db import aurweb.initdb from aurweb.models.account_type import AccountType -from aurweb.schema import metadata -from aurweb.testing import setup_test_db -@pytest.fixture(autouse=True) -def setup(): - setup_test_db() - - tables = metadata.tables.keys() - for table in tables: - aurweb.db.session.execute(f"DROP TABLE IF EXISTS {table}") +class Args: + use_alembic = True + verbose = True def test_run(): - class Args: - use_alembic = True - verbose = False + from aurweb.schema import metadata + aurweb.db.kill_engine() + metadata.drop_all(aurweb.db.get_engine()) aurweb.initdb.run(Args()) record = aurweb.db.query(AccountType, AccountType.AccountType == "User").first() diff --git a/test/test_package_relation.py b/test/test_package_relation.py index dd0455cd..96932f40 100644 --- a/test/test_package_relation.py +++ b/test/test_package_relation.py @@ -1,6 +1,6 @@ import pytest -from sqlalchemy.exc import IntegrityError +from sqlalchemy.exc import IntegrityError, OperationalError from aurweb.db import create, query from aurweb.models.account_type import AccountType @@ -36,7 +36,7 @@ def setup(): URL="https://test.package") -def test_package_dependencies(): +def test_package_relation(): conflicts = query(RelationType, RelationType.Name == "conflicts").first() pkgrel = create(PackageRelation, Package=package, RelationType=conflicts, @@ -68,10 +68,12 @@ def test_package_dependencies(): assert pkgrel in package.package_relations -def test_package_dependencies_null_package_raises_exception(): +def test_package_relation_null_package_raises_exception(): from aurweb.db import session conflicts = query(RelationType, RelationType.Name == "conflicts").first() + assert conflicts is not None + with pytest.raises(IntegrityError): create(PackageRelation, RelationType=conflicts, @@ -79,7 +81,7 @@ def test_package_dependencies_null_package_raises_exception(): session.rollback() -def test_package_dependencies_null_dependency_type_raises_exception(): +def test_package_relation_null_relation_type_raises_exception(): from aurweb.db import session with pytest.raises(IntegrityError): @@ -89,11 +91,13 @@ def test_package_dependencies_null_dependency_type_raises_exception(): session.rollback() -def test_package_dependencies_null_depname_raises_exception(): +def test_package_relation_null_relname_raises_exception(): from aurweb.db import session - depends = query(RelationType, RelationType.Name == "depends").first() - with pytest.raises(IntegrityError): + depends = query(RelationType, RelationType.Name == "conflicts").first() + assert depends is not None + + with pytest.raises((OperationalError, IntegrityError)): create(PackageRelation, Package=package, RelationType=depends) diff --git a/test/test_session.py b/test/test_session.py index 2877ea7f..c324a739 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -25,7 +25,7 @@ def setup(): ResetKey="testReset", Passwd="testPassword", AccountType=account_type) session = create(Session, UsersID=user.ID, SessionID="testSession", - LastUpdateTS=datetime.utcnow()) + LastUpdateTS=datetime.utcnow().timestamp()) def test_session(): From 228bc8fe7c3ea7cef66f00f1608b699d00838c43 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 4 Jun 2021 23:09:38 -0700 Subject: [PATCH 0679/1891] fix aurweb.auth test coverage With mysqlclient, we no longer need to account for a user not existing when an ssh key is found. Signed-off-by: Kevin Morris --- aurweb/auth.py | 14 +++++++++----- test/test_auth.py | 7 ++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index a4ff2167..401ed6ae 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -4,7 +4,8 @@ from datetime import datetime from http import HTTPStatus from fastapi.responses import RedirectResponse -from starlette.authentication import AuthCredentials, AuthenticationBackend, AuthenticationError +from sqlalchemy import and_ +from starlette.authentication import AuthCredentials, AuthenticationBackend from starlette.requests import HTTPConnection import aurweb.config @@ -42,14 +43,17 @@ class BasicAuthBackend(AuthenticationBackend): now_ts = datetime.utcnow().timestamp() record = session.query(Session).filter( - Session.SessionID == sid, Session.LastUpdateTS >= now_ts).first() + and_(Session.SessionID == sid, + Session.LastUpdateTS >= now_ts)).first() + + # If no session with sid and a LastUpdateTS now or later exists. if not record: return None, AnonymousUser() + # At this point, we cannot have an invalid user if the record + # exists, due to ForeignKey constraints in the schema upheld + # by mysqlclient. user = session.query(User).filter(User.ID == record.UsersID).first() - if not user: - raise AuthenticationError(f"Invalid User ID: {record.UsersID}") - user.authenticated = True return AuthCredentials(["authenticated"]), user diff --git a/test/test_auth.py b/test/test_auth.py index 42eac040..05dd2020 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -2,7 +2,7 @@ from datetime import datetime import pytest -from starlette.authentication import AuthenticationError +from sqlalchemy.exc import IntegrityError import aurweb.config @@ -53,13 +53,13 @@ async def test_auth_backend_invalid_sid(): @pytest.mark.asyncio async def test_auth_backend_invalid_user_id(): + from aurweb.db import session + # Create a new session with a fake user id. now_ts = datetime.utcnow().timestamp() - db_backend = aurweb.config.get("database", "backend") with pytest.raises(IntegrityError): create(Session, UsersID=666, SessionID="realSession", LastUpdateTS=now_ts + 5) - session.rollback() @@ -70,6 +70,7 @@ async def test_basic_auth_backend(): now_ts = datetime.utcnow().timestamp() create(Session, UsersID=user.ID, SessionID="realSession", LastUpdateTS=now_ts + 5) + request.cookies["AURSID"] = "realSession" _, result = await backend.authenticate(request) assert result == user From 62e58b122f905b4e5462df6b0bbebd278bb56419 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 4 Jun 2021 23:13:05 -0700 Subject: [PATCH 0680/1891] fix test_accounts_routes test coverage Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 +- test/test_accounts_routes.py | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5bdf427c..8e14f77f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,7 +8,7 @@ cache: before_script: - pacman -Syu --noconfirm --noprogressbar --needed --cachedir .pkg-cache - base-devel git gpgme protobuf pyalpm python-mysql-connector + base-devel git gpgme protobuf pyalpm python-mysqlclient python-pygit2 python-srcinfo python-bleach python-markdown python-sqlalchemy python-alembic python-pytest python-werkzeug python-pytest-tap python-fastapi hypercorn nginx python-authlib diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 3080a505..d5fd089e 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -30,6 +30,20 @@ client = TestClient(app) user = None +def make_ssh_pubkey(): + # Create a public key with ssh-keygen (this adds ssh-keygen as a + # dependency to passing this test). + with tempfile.TemporaryDirectory() as tmpdir: + with open("/dev/null", "w") as null: + proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, stderr=null) + proc.wait() + assert proc.returncode == 0 + + # Read in the public key, then delete the temp dir we made. + return open(f"{tmpdir}/test.ssh.pub").read().rstrip() + + @pytest.fixture(autouse=True) def setup(): global user @@ -770,27 +784,13 @@ def test_post_account_edit_error_unauthorized(): def test_post_account_edit_ssh_pub_key(): - pk = str() - - # Create a public key with ssh-keygen (this adds ssh-keygen as a - # dependency to passing this test). - with tempfile.TemporaryDirectory() as tmpdir: - with open("/dev/null", "w") as null: - proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], - stdout=null, stderr=null) - proc.wait() - assert proc.returncode == 0 - - # Read in the public key, then delete the temp dir we made. - pk = open(f"{tmpdir}/test.ssh.pub").read().rstrip() - request = Request() sid = user.login(request, "testPassword") post_data = { "U": "test", "E": "test@example.org", - "PK": pk, + "PK": make_ssh_pubkey(), "passwd": "testPassword" } From 4d1faca4477bc510e81513b659f199f0d8c41bb1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 5 Jun 2021 01:07:56 -0700 Subject: [PATCH 0681/1891] test both mysql and sqlite in .gitlab-ci.yml Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8e14f77f..e65b4343 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,9 @@ cache: # For some reason Gitlab CI only supports storing cache/artifacts in a path relative to the build directory - .pkg-cache +variables: + AUR_CONFIG: conf/config + before_script: - pacman -Syu --noconfirm --noprogressbar --needed --cachedir .pkg-cache base-devel git gpgme protobuf pyalpm python-mysqlclient @@ -15,17 +18,31 @@ before_script: python-itsdangerous python-httpx python-jinja python-pytest-cov python-requests python-aiofiles python-python-multipart python-pytest-asyncio python-coverage python-bcrypt - python-email-validator openssh python-lxml + python-email-validator openssh python-lxml mariadb - bash -c "echo '127.0.0.1' > /etc/hosts" - bash -c "echo '::1' >> /etc/hosts" + - mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + - (cd '/usr' && /usr/bin/mysqld_safe --datadir='/var/lib/mysql') & + - 'until : > /dev/tcp/127.0.0.1/3306; do sleep 1s; done' + - mysql -u root -e "CREATE USER 'aur'@'localhost' IDENTIFIED BY 'aur';" + - mysql -u root -e "CREATE DATABASE aurweb;" + - mysql -u root -e "GRANT ALL PRIVILEGES ON aurweb.* TO 'aur'@'localhost';" + - mysql -u root -e "FLUSH PRIVILEGES;" + - sed -r "s;YOUR_AUR_ROOT;$(pwd);g" conf/config.dev > conf/config + - cp conf/config conf/config.sqlite + - cp conf/config.defaults conf/config.sqlite.defaults + - sed -i -r 's;backend = .*;backend = sqlite;' conf/config.sqlite + - sed -i -r "s;name = .*;name = $(pwd)/aurweb.sqlite3;" conf/config.sqlite + - AUR_CONFIG=conf/config.sqlite python -m aurweb.initdb test: script: - python setup.py install - - sed -r "s;YOUR_AUR_ROOT;$(pwd);g" conf/config.dev > conf/config - - AUR_CONFIG=conf/config make -C po all install - - AUR_CONFIG=conf/config python -m aurweb.initdb - - make -C test + - make -C po all install + - python -m aurweb.initdb + - make -C test sh # sharness tests use sqlite. + - make -C test pytest # pytest with mysql. + - AUR_CONFIG=conf/config.sqlite make -C test pytest # pytest with sqlite. - coverage report --include='aurweb/*' - coverage xml --include='aurweb/*' artifacts: From 5ceeb88bee1575427008c119d2c7cd37274f0919 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 5 Jun 2021 21:19:20 -0700 Subject: [PATCH 0682/1891] remove unused imports, rectify isort violations Files got into the branch that violate both PEP-8 guidelines and isorts. This fixes them. Signed-off-by: Kevin Morris --- aurweb/git/update.py | 4 ++-- aurweb/models/user.py | 2 -- aurweb/routers/html.py | 3 +-- ...56e2ce8e2ffa_utf8mb4_charset_and_collation.py | 16 ++++++++-------- ...fcd6e1cd_add_sso_account_id_in_table_users.py | 1 + .../versions/f47cad5d6d03_initial_revision.py | 5 ----- test/test_auth.py | 2 -- 7 files changed, 12 insertions(+), 21 deletions(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 3c9c3785..2424bf6c 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -305,9 +305,9 @@ def main(): # noqa: C901 try: metadata_pkgbase = metadata['pkgbase'] - except KeyError as e: + except KeyError: die_commit('invalid .SRCINFO, does not contain a pkgbase (is the file empty?)', - str(commit.id)) + str(commit.id)) if not re.match(repo_regex, metadata_pkgbase): die_commit('invalid pkgbase: {:s}'.format(metadata_pkgbase), str(commit.id)) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 6c5c6e21..1961228e 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -65,8 +65,6 @@ class User: def valid_password(self, password: str): """ Check authentication against a given password. """ - from aurweb.db import session - if password is None: return False diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 8f89e05c..890aff88 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -2,9 +2,8 @@ decorators in some way; more complex routes should be defined in their own modules and imported here. """ from http import HTTPStatus -from urllib.parse import unquote -from fastapi import APIRouter, Form, Request, HTTPException +from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse from aurweb.templates import make_context, render_template diff --git a/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py b/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py index e198c34c..67f0c065 100644 --- a/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py +++ b/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py @@ -56,14 +56,14 @@ db_backend = aurweb.config.get("database", "backend") def rebuild_unique_indexes_with_str_cols(): for idx_name in indexes: sql = f""" -DROP INDEX IF EXISTS {idx_name} +DROP INDEX IF EXISTS {idx_name} ON {indexes.get(idx_name)[0]} """ op.execute(sql) sql = f""" -CREATE UNIQUE INDEX {idx_name} -ON {indexes.get(idx_name)[0]} -({indexes.get(idx_name)[1]}, {indexes.get(idx_name)[2]}) +CREATE UNIQUE INDEX {idx_name} +ON {indexes.get(idx_name)[0]} +({indexes.get(idx_name)[1]}, {indexes.get(idx_name)[2]}) """ op.execute(sql) @@ -77,8 +77,8 @@ def upgrade(): def op_execute(table_meta): table, charset, collate = table_meta sql = f""" -ALTER TABLE {table} -CONVERT TO CHARACTER SET {charset} +ALTER TABLE {table} +CONVERT TO CHARACTER SET {charset} COLLATE {collate} """ op.execute(sql) @@ -94,8 +94,8 @@ def downgrade(): def op_execute(table_meta): table, charset, collate = table_meta sql = f""" -ALTER TABLE {table} -CONVERT TO CHARACTER SET {src_charset} +ALTER TABLE {table} +CONVERT TO CHARACTER SET {src_charset} COLLATE {src_collate} """ op.execute(sql) diff --git a/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py b/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py index 2b257e9d..49bf055a 100644 --- a/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py +++ b/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py @@ -6,6 +6,7 @@ Create Date: 2020-06-08 10:04:13.898617 """ import sqlalchemy as sa + from alembic import op from sqlalchemy.engine.reflection import Inspector diff --git a/migrations/versions/f47cad5d6d03_initial_revision.py b/migrations/versions/f47cad5d6d03_initial_revision.py index 9e99490f..b214beea 100644 --- a/migrations/versions/f47cad5d6d03_initial_revision.py +++ b/migrations/versions/f47cad5d6d03_initial_revision.py @@ -1,14 +1,9 @@ """initial revision Revision ID: f47cad5d6d03 -Revises: Create Date: 2020-02-23 13:23:32.331396 """ -from alembic import op -import sqlalchemy as sa - - # revision identifiers, used by Alembic. revision = 'f47cad5d6d03' down_revision = None diff --git a/test/test_auth.py b/test/test_auth.py index 05dd2020..e5e1de11 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -4,8 +4,6 @@ import pytest from sqlalchemy.exc import IntegrityError -import aurweb.config - from aurweb.auth import BasicAuthBackend, has_credential from aurweb.db import create, query from aurweb.models.account_type import AccountType From e865a6347f16edba73e405a4dabc1f76d3ca6509 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 5 Jun 2021 21:28:26 -0700 Subject: [PATCH 0683/1891] .gitlab-ci.yml: enforce isort and flake8 compliance Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e65b4343..a9947dfe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,6 +19,7 @@ before_script: python-requests python-aiofiles python-python-multipart python-pytest-asyncio python-coverage python-bcrypt python-email-validator openssh python-lxml mariadb + python-isort flake8 - bash -c "echo '127.0.0.1' > /etc/hosts" - bash -c "echo '::1' >> /etc/hosts" - mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql @@ -45,6 +46,12 @@ test: - AUR_CONFIG=conf/config.sqlite make -C test pytest # pytest with sqlite. - coverage report --include='aurweb/*' - coverage xml --include='aurweb/*' + - flake8 --count aurweb # Assert no flake8 violations in aurweb. + - flake8 --count test # Assert no flake8 violations in test. + - flake8 --count migrations # Assert no flake8 violations in migrations. + - isort --check-only aurweb # Assert no isort violations in aurweb. + - isort --check-only test # Assert no flake8 violations in test. + - isort --check-only migrations # Assert no flake8 violations in migrations. artifacts: reports: cobertura: coverage.xml From 1874e821f5883c2338b07c4803b67c6802621c38 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 5 Jun 2021 18:13:10 -0700 Subject: [PATCH 0684/1891] add case [in]sensitivity tests + add OfficialProvider model `ci` in this context means "Case Insensitive". `cs` in this context means "Case Sensitive". New models created: - OfficialProvider This was required to write a test for checking that OfficialProviders behaves as we expect, which was the starter for the original aurblup bug. New tests created: - test_official_provider Modified tests: - test_package_base: add ci test - test_package: add ci test - test_session: add cs test - test_ssh_pub_key: add cs test Signed-off-by: Kevin Morris --- aurweb/models/official_provider.py | 34 ++++++++++++++ test/test_official_provider.py | 75 ++++++++++++++++++++++++++++++ test/test_package.py | 16 +++++++ test/test_package_base.py | 21 +++++++++ test/test_session.py | 9 ++++ test/test_ssh_pub_key.py | 12 +++++ 6 files changed, 167 insertions(+) create mode 100644 aurweb/models/official_provider.py create mode 100644 test/test_official_provider.py diff --git a/aurweb/models/official_provider.py b/aurweb/models/official_provider.py new file mode 100644 index 00000000..073eb435 --- /dev/null +++ b/aurweb/models/official_provider.py @@ -0,0 +1,34 @@ +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import mapper + +from aurweb.schema import OfficialProviders + + +class OfficialProvider: + def __init__(self, + Name: str = None, + Repo: str = None, + Provides: str = None): + self.Name = Name + if not self.Name: + raise IntegrityError( + statement="Column Name cannot be null.", + orig="OfficialProviders.Name", + params=("NULL")) + + self.Repo = Repo + if not self.Repo: + raise IntegrityError( + statement="Column Repo cannot be null.", + orig="OfficialProviders.Repo", + params=("NULL")) + + self.Provides = Provides + if not self.Provides: + raise IntegrityError( + statement="Column Provides cannot be null.", + orig="OfficialProviders.Provides", + params=("NULL")) + + +mapper(OfficialProvider, OfficialProviders) diff --git a/test/test_official_provider.py b/test/test_official_provider.py new file mode 100644 index 00000000..a1d3d54a --- /dev/null +++ b/test/test_official_provider.py @@ -0,0 +1,75 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create +from aurweb.models.official_provider import OfficialProvider +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db("OfficialProviders") + + +def test_official_provider_creation(): + oprovider = create(OfficialProvider, + Name="some-name", + Repo="some-repo", + Provides="some-provides") + assert bool(oprovider.ID) + assert oprovider.Name == "some-name" + assert oprovider.Repo == "some-repo" + assert oprovider.Provides == "some-provides" + + +def test_official_provider_cs(): + """ Test case sensitivity of the database table. """ + oprovider = create(OfficialProvider, + Name="some-name", + Repo="some-repo", + Provides="some-provides") + assert bool(oprovider.ID) + + oprovider_cs = create(OfficialProvider, + Name="SOME-NAME", + Repo="SOME-REPO", + Provides="SOME-PROVIDES") + assert bool(oprovider_cs.ID) + + assert oprovider.ID != oprovider_cs.ID + + assert oprovider.Name == "some-name" + assert oprovider.Repo == "some-repo" + assert oprovider.Provides == "some-provides" + + assert oprovider_cs.Name == "SOME-NAME" + assert oprovider_cs.Repo == "SOME-REPO" + assert oprovider_cs.Provides == "SOME-PROVIDES" + + +def test_official_provider_null_name_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(OfficialProvider, + Repo="some-repo", + Provides="some-provides") + session.rollback() + + +def test_official_provider_null_repo_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(OfficialProvider, + Name="some-name", + Provides="some-provides") + session.rollback() + + +def test_official_provider_null_provides_raises_exception(): + from aurweb.db import session + with pytest.raises(IntegrityError): + create(OfficialProvider, + Name="some-name", + Repo="some-repo") + session.rollback() diff --git a/test/test_package.py b/test/test_package.py index 66d557f3..a994f096 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -3,6 +3,8 @@ import pytest from sqlalchemy import and_ from sqlalchemy.exc import IntegrityError +import aurweb.config + from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.package import Package @@ -55,6 +57,20 @@ def test_package(): assert record is not None +def test_package_ci(): + """ Test case insensitivity of the database table. """ + if aurweb.config.get("database", "backend") == "sqlite": + return None # SQLite doesn't seem handle this. + + from aurweb.db import session + + with pytest.raises(IntegrityError): + create(Package, + PackageBase=pkgbase, + Name="Beautiful-Package") + session.rollback() + + def test_package_null_pkgbase_raises_exception(): from aurweb.db import session diff --git a/test/test_package_base.py b/test/test_package_base.py index e0359f4f..7f608c2c 100644 --- a/test/test_package_base.py +++ b/test/test_package_base.py @@ -2,6 +2,8 @@ import pytest from sqlalchemy.exc import IntegrityError +import aurweb.config + from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.package_base import PackageBase @@ -35,6 +37,25 @@ def test_package_base(): assert pkgbase.ModifiedTS > 0 +def test_package_base_ci(): + """ Test case insensitivity of the database table. """ + if aurweb.config.get("database", "backend") == "sqlite": + return None # SQLite doesn't seem handle this. + + from aurweb.db import session + + pkgbase = create(PackageBase, + Name="beautiful-package", + Maintainer=user) + assert bool(pkgbase.ID) + + with pytest.raises(IntegrityError): + create(PackageBase, + Name="Beautiful-Package", + Maintainer=user) + session.rollback() + + def test_package_base_relationships(): pkgbase = create(PackageBase, Name="beautiful-package", diff --git a/test/test_session.py b/test/test_session.py index c324a739..1dd82db1 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -33,6 +33,15 @@ def test_session(): assert session.UsersID == user.ID +def test_session_cs(): + """ Test case sensitivity of the database table. """ + session_cs = create(Session, UsersID=user.ID, + SessionID="TESTSESSION", + LastUpdateTS=datetime.utcnow().timestamp()) + assert session_cs.SessionID == "TESTSESSION" + assert session.SessionID == "testSession" + + def test_session_user_association(): # Make sure that the Session user attribute is correct. assert session.User == user diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py index 4072549e..0793199a 100644 --- a/test/test_ssh_pub_key.py +++ b/test/test_ssh_pub_key.py @@ -41,6 +41,18 @@ def test_ssh_pub_key(): assert ssh_pub_key.PubKey == "testPubKey" +def test_ssh_pub_key_cs(): + """ Test case sensitivity of the database table. """ + ssh_pub_key_cs = create(SSHPubKey, UserID=user.ID, + Fingerprint="TESTFINGERPRINT", + PubKey="TESTPUBKEY") + + assert ssh_pub_key_cs.Fingerprint == "TESTFINGERPRINT" + assert ssh_pub_key_cs.PubKey == "TESTPUBKEY" + assert ssh_pub_key.Fingerprint == "testFingerprint" + assert ssh_pub_key.PubKey == "testPubKey" + + def test_ssh_pub_key_fingerprint(): assert get_fingerprint(TEST_SSH_PUBKEY) is not None From 889d358a6daff60d5aac3df62b54a7f939b9bc8a Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sun, 6 Jun 2021 21:49:27 +0200 Subject: [PATCH 0685/1891] Add missing ) for addvote.php --- web/html/addvote.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/addvote.php b/web/html/addvote.php index 70280cfd..3e4def44 100644 --- a/web/html/addvote.php +++ b/web/html/addvote.php @@ -69,7 +69,7 @@ if (has_credential(CRED_TU_ADD_VOTE)) { if (!empty($_POST['addVote']) && empty($error)) { // Convert $quorum to a String of maximum length "12.34" (5). - $quorum_str = substr(strval($quorum), min(5, strlen($quorum)); + $quorum_str = substr(strval($quorum), min(5, strlen($quorum))); add_tu_proposal($_POST['agenda'], $_POST['user'], $len, $quorum_str, $uid); From f9f41dc99beb9fd75d3f772bf4023168b53c9180 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 6 Jun 2021 16:30:16 -0700 Subject: [PATCH 0686/1891] restore TU_VoteInfo -> utf8mb4_general_ci Signed-off-by: Kevin Morris --- aurweb/schema.py | 4 +++- .../versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/aurweb/schema.py b/aurweb/schema.py index f0162045..a0bb7e09 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -389,7 +389,9 @@ TU_VoteInfo = Table( Column('No', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), Column('Abstain', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), Column('ActiveTUs', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), - mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', + mysql_engine='InnoDB', + mysql_charset='utf8mb4', + mysql_collate='utf8mb4_general_ci', ) diff --git a/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py b/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py index e198c34c..03982676 100644 --- a/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py +++ b/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py @@ -37,7 +37,7 @@ tables = [ ('RequestTypes', 'utf8mb4', 'utf8mb4_general_ci'), ('SSHPubKeys', 'utf8mb4', 'utf8mb4_bin'), ('Sessions', 'utf8mb4', 'utf8mb4_bin'), - ('TU_VoteInfo', 'utf8mb4', 'utf8mb4_bin'), + ('TU_VoteInfo', 'utf8mb4', 'utf8mb4_general_ci'), ('Terms', 'utf8mb4', 'utf8mb4_general_ci'), ('Users', 'utf8mb4', 'utf8mb4_general_ci') ] From 4f09e939ae1d605f6568a180d8ab86033e847a0f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 6 Jun 2021 21:34:42 -0700 Subject: [PATCH 0687/1891] bugfix: gendummydata.py was producing invalid usernames As per our regex and policies, usernames should consist of ascii alphanumeric characters and possibly (-, _ or .). gendummydata.py was creating unicode versions of some usernames and adding them into the DB. With our newfound collations, this becomes a problem as it treats them as the same. This should have never been the case here, and so, gendummydata.py has been patched to normalize all of its usernames and package names. Signed-off-by: Kevin Morris --- schema/gendummydata.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index c7b3a06d..35805d6c 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -98,11 +98,19 @@ if MAX_USERS > len(contents): MAX_USERS = len(contents) if MAX_PKGS > len(contents): MAX_PKGS = len(contents) -if len(contents) - MAX_USERS > MAX_PKGS: - need_dupes = 0 -else: + +need_dupes = 0 +if not len(contents) - MAX_USERS > MAX_PKGS: need_dupes = 1 + +def normalize(unicode_data): + """ We only accept ascii for usernames. Also use this to normalize + package names; our database utf8mb4 collations compare with Unicode + Equivalence. """ + return unicode_data.encode('ascii', 'ignore').decode('ascii') + + # select random usernames # log.debug("Generating random user names...") @@ -110,12 +118,13 @@ user_id = USER_ID while len(seen_users) < MAX_USERS: user = random.randrange(0, len(contents)) word = contents[user].replace("'", "").replace(".", "").replace(" ", "_") - word = word.strip().lower() + word = normalize(word.strip().lower()) if word not in seen_users: seen_users[word] = user_id user_id += 1 user_keys = list(seen_users.keys()) + # select random package names # log.debug("Generating random package names...") @@ -123,7 +132,7 @@ num_pkgs = PKG_ID while len(seen_pkgs) < MAX_PKGS: pkg = random.randrange(0, len(contents)) word = contents[pkg].replace("'", "").replace(".", "").replace(" ", "_") - word = word.strip().lower() + word = normalize(word.strip().lower()) if not need_dupes: if word not in seen_pkgs and word not in seen_users: seen_pkgs[word] = num_pkgs @@ -285,10 +294,10 @@ for p in seen_pkgs_keys: for i in range(num_sources): src_file = user_keys[random.randrange(0, len(user_keys))] src = "%s%s.%s/%s/%s-%s.tar.gz" % ( - RANDOM_URL[random.randrange(0, len(RANDOM_URL))], - p, RANDOM_TLDS[random.randrange(0, len(RANDOM_TLDS))], - RANDOM_LOCS[random.randrange(0, len(RANDOM_LOCS))], - src_file, genVersion()) + RANDOM_URL[random.randrange(0, len(RANDOM_URL))], + p, RANDOM_TLDS[random.randrange(0, len(RANDOM_TLDS))], + RANDOM_LOCS[random.randrange(0, len(RANDOM_LOCS))], + src_file, genVersion()) s = "INSERT INTO PackageSources(PackageID, Source) VALUES (%d, '%s');\n" s = s % (seen_pkgs[p], src) out.write(s) From 7f7a975614f3c02517b4cbb94537fc4c60b26603 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 10 Jun 2021 01:11:41 -0700 Subject: [PATCH 0688/1891] remove autoflush from aurweb.db.Session This causes issues with the declarative API. Signed-off-by: Kevin Morris --- aurweb/db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/db.py b/aurweb/db.py index 590712e0..1f6f50d8 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -141,7 +141,7 @@ def get_engine(echo: bool = False): engine = create_engine(get_sqlalchemy_url(), connect_args=connect_args, echo=echo) - Session = sessionmaker(autocommit=False, autoflush=True, bind=engine) + Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = Session() return engine From a625df07e294866398385548501656eb8645e610 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Thu, 10 Jun 2021 14:46:24 -0400 Subject: [PATCH 0689/1891] Source valid ssh prefixes from config Signed-off-by: Eli Schwartz --- web/lib/acctfuncs.inc.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index df016c6d..0d021f99 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -875,10 +875,7 @@ function valid_pgp_fingerprint($fingerprint) { * @return bool True if the SSH public key is valid, otherwise false */ function valid_ssh_pubkey($pubkey) { - $valid_prefixes = array( - "ssh-rsa", "ssh-dss", "ecdsa-sha2-nistp256", - "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "ssh-ed25519" - ); + $valid_prefixes = explode(' ', config_get('auth', 'valid-keytypes')); $has_valid_prefix = false; foreach ($valid_prefixes as $prefix) { From b32022a176ede116068a405c928cf25e23ffb691 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Thu, 10 Jun 2021 14:35:13 -0400 Subject: [PATCH 0690/1891] Add FIDO/U2F ssh keytypes to default config Signed-off-by: Eli Schwartz --- conf/config.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.defaults b/conf/config.defaults index 98e033b7..e6961520 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -62,7 +62,7 @@ ECDSA = SHA256:L71Q91yHwmHPYYkJMDgj0xmUuw16qFOhJbBr1mzsiOI RSA = SHA256:Ju+yWiMb/2O+gKQ9RJCDqvRg7l+Q95KFAeqM5sr6l2s [auth] -valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 +valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 sk-ssh-ecdsa@openssh.com sk-ssh-ed25519@openssh.com username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ git-serve-cmd = /usr/local/bin/aurweb-git-serve ssh-options = restrict From 888cf5118aa1f794f9c87413aa29b5db54adc84a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 6 Jun 2021 22:45:40 -0700 Subject: [PATCH 0691/1891] use declarative_base for all ORM models This rewrites the entire model base as declarative models. This allows us to more easily customize overlay fields in tables and is more common. This effort also brought some DB violations to light which this commit addresses. Signed-off-by: Kevin Morris --- aurweb/db.py | 13 ++---- aurweb/models/__init__.py | 1 + aurweb/models/accepted_term.py | 41 ++++++++++------- aurweb/models/account_type.py | 14 +++--- aurweb/models/api_rate_limit.py | 18 +++++--- aurweb/models/ban.py | 15 ++++--- aurweb/models/declarative.py | 10 +++++ aurweb/models/dependency_type.py | 15 ++++--- aurweb/models/group.py | 15 ++++--- aurweb/models/license.py | 15 ++++--- aurweb/models/official_provider.py | 15 ++++--- aurweb/models/package.py | 42 +++++++++++------- aurweb/models/package_base.py | 58 +++++++++++++++--------- aurweb/models/package_dependency.py | 55 ++++++++++++++--------- aurweb/models/package_group.py | 48 +++++++++++--------- aurweb/models/package_keyword.py | 32 +++++++------ aurweb/models/package_license.py | 52 ++++++++++++---------- aurweb/models/package_relation.py | 52 ++++++++++++---------- aurweb/models/relation_type.py | 15 ++++--- aurweb/models/session.py | 24 ++++++---- aurweb/models/ssh_pub_key.py | 26 +++++++---- aurweb/models/term.py | 15 ++++--- aurweb/models/user.py | 69 ++++++++++++----------------- test/test_accepted_term.py | 4 +- test/test_account_type.py | 3 +- test/test_package.py | 10 ++--- test/test_package_group.py | 2 +- test/test_package_license.py | 2 +- test/test_session.py | 9 ++-- 29 files changed, 398 insertions(+), 292 deletions(-) create mode 100644 aurweb/models/declarative.py diff --git a/aurweb/db.py b/aurweb/db.py index 1f6f50d8..9837c746 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,7 +1,5 @@ import math -from sqlalchemy.orm import backref, relationship - import aurweb.config import aurweb.util @@ -53,12 +51,6 @@ def make_random_value(table: str, column: str): return string -def make_relationship(model, foreign_key: str, backref_: str, **kwargs): - return relationship(model, foreign_keys=[foreign_key], - backref=backref(backref_, lazy="dynamic"), - **kwargs) - - def query(model, *args, **kwargs): return session.query(model).filter(*args, **kwargs) @@ -77,6 +69,10 @@ def delete(model, *args, **kwargs): session.commit() +def rollback(): + session.rollback() + + def get_sqlalchemy_url(): """ Build an SQLAlchemy for use with create_engine based on the aurweb configuration. @@ -137,7 +133,6 @@ def get_engine(echo: bool = False): # check_same_thread is for a SQLite technicality # https://fastapi.tiangolo.com/tutorial/sql-databases/#note connect_args["check_same_thread"] = False - engine = create_engine(get_sqlalchemy_url(), connect_args=connect_args, echo=echo) diff --git a/aurweb/models/__init__.py b/aurweb/models/__init__.py index e69de29b..ed0532c6 100644 --- a/aurweb/models/__init__.py +++ b/aurweb/models/__init__.py @@ -0,0 +1 @@ +# aurweb SQLAlchemy ORM model collection. diff --git a/aurweb/models/accepted_term.py b/aurweb/models/accepted_term.py index 483109f1..b46d086b 100644 --- a/aurweb/models/accepted_term.py +++ b/aurweb/models/accepted_term.py @@ -1,15 +1,33 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.term import Term -from aurweb.models.user import User -from aurweb.schema import AcceptedTerms +import aurweb.models.term +import aurweb.models.user + +from aurweb.models.declarative import Base -class AcceptedTerm: +class AcceptedTerm(Base): + __tablename__ = "AcceptedTerms" + + UsersID = Column(Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + User = relationship( + "User", backref=backref("accepted_terms", lazy="dynamic"), + foreign_keys=[UsersID]) + + TermsID = Column(Integer, ForeignKey("Terms.ID", ondelete="CASCADE"), + nullable=False) + Term = relationship( + "Term", backref=backref("accepted_terms", lazy="dynamic"), + foreign_keys=[TermsID]) + + __mapper_args__ = {"primary_key": [TermsID]} + def __init__(self, - User: User = None, Term: Term = None, + User: aurweb.models.user.User = None, + Term: aurweb.models.term.Term = None, Revision: int = None): self.User = User if not self.User: @@ -26,12 +44,3 @@ class AcceptedTerm: params=("NULL")) self.Revision = Revision - - -properties = { - "User": make_relationship(User, AcceptedTerms.c.UsersID, "accepted_terms"), - "Term": make_relationship(Term, AcceptedTerms.c.TermsID, "accepted") -} - -mapper(AcceptedTerm, AcceptedTerms, properties=properties, - primary_key=[AcceptedTerms.c.UsersID, AcceptedTerms.c.TermsID]) diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py index 44225e35..502a86b1 100644 --- a/aurweb/models/account_type.py +++ b/aurweb/models/account_type.py @@ -1,10 +1,15 @@ -from sqlalchemy.orm import mapper +from sqlalchemy import Column, Integer -from aurweb.schema import AccountTypes +from aurweb.models.declarative import Base -class AccountType: +class AccountType(Base): """ An ORM model of a single AccountTypes record. """ + __tablename__ = "AccountTypes" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} def __init__(self, **kwargs): self.AccountType = kwargs.pop("AccountType") @@ -15,6 +20,3 @@ class AccountType: def __repr__(self): return "" % ( self.ID, str(self)) - - -mapper(AccountType, AccountTypes, confirm_deleted_rows=False) diff --git a/aurweb/models/api_rate_limit.py b/aurweb/models/api_rate_limit.py index 8b945b6a..f4590553 100644 --- a/aurweb/models/api_rate_limit.py +++ b/aurweb/models/api_rate_limit.py @@ -1,11 +1,18 @@ +from sqlalchemy import Column, String from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper -from aurweb.schema import ApiRateLimit as _ApiRateLimit +from aurweb.models.declarative import Base -class ApiRateLimit: - def __init__(self, IP: str = None, +class ApiRateLimit(Base): + __tablename__ = "ApiRateLimit" + + IP = Column(String(45), primary_key=True, unique=True, default=str()) + + __mapper_args__ = {"primary_key": [IP]} + + def __init__(self, + IP: str = None, Requests: int = None, WindowStart: int = None): self.IP = IP @@ -23,6 +30,3 @@ class ApiRateLimit: statement="Column WindowStart cannot be null.", orig="ApiRateLimit.WindowStart", params=("NULL")) - - -mapper(ApiRateLimit, _ApiRateLimit, primary_key=[_ApiRateLimit.c.IP]) diff --git a/aurweb/models/ban.py b/aurweb/models/ban.py index be030380..e10087b0 100644 --- a/aurweb/models/ban.py +++ b/aurweb/models/ban.py @@ -1,10 +1,16 @@ from fastapi import Request -from sqlalchemy.orm import mapper +from sqlalchemy import Column, String -from aurweb.schema import Bans +from aurweb.models.declarative import Base -class Ban: +class Ban(Base): + __tablename__ = "Bans" + + IPAddress = Column(String(45), primary_key=True) + + __mapper_args__ = {"primary_key": [IPAddress]} + def __init__(self, **kwargs): self.IPAddress = kwargs.get("IPAddress") self.BanTS = kwargs.get("BanTS") @@ -14,6 +20,3 @@ def is_banned(request: Request): from aurweb.db import session ip = request.client.host return session.query(Ban).filter(Ban.IPAddress == ip).first() is not None - - -mapper(Ban, Bans) diff --git a/aurweb/models/declarative.py b/aurweb/models/declarative.py new file mode 100644 index 00000000..45a629ce --- /dev/null +++ b/aurweb/models/declarative.py @@ -0,0 +1,10 @@ +from sqlalchemy.ext.declarative import declarative_base + +import aurweb.db + +Base = declarative_base() +Base.__table_args__ = { + "autoload": True, + "autoload_with": aurweb.db.get_engine(), + "extend_existing": True +} diff --git a/aurweb/models/dependency_type.py b/aurweb/models/dependency_type.py index 87b38069..71acf368 100644 --- a/aurweb/models/dependency_type.py +++ b/aurweb/models/dependency_type.py @@ -1,11 +1,14 @@ -from sqlalchemy.orm import mapper +from sqlalchemy import Column, Integer -from aurweb.schema import DependencyTypes +from aurweb.models.declarative import Base -class DependencyType: +class DependencyType(Base): + __tablename__ = "DependencyTypes" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} + def __init__(self, Name: str = None): self.Name = Name - - -mapper(DependencyType, DependencyTypes) diff --git a/aurweb/models/group.py b/aurweb/models/group.py index c5583eb4..1bd3a402 100644 --- a/aurweb/models/group.py +++ b/aurweb/models/group.py @@ -1,10 +1,16 @@ +from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper -from aurweb.schema import Groups +from aurweb.models.declarative import Base -class Group: +class Group(Base): + __tablename__ = "Groups" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} + def __init__(self, Name: str = None): self.Name = Name if not self.Name: @@ -12,6 +18,3 @@ class Group: statement="Column Name cannot be null.", orig="Groups.Name", params=("NULL")) - - -mapper(Group, Groups) diff --git a/aurweb/models/license.py b/aurweb/models/license.py index bcc02713..aef6a619 100644 --- a/aurweb/models/license.py +++ b/aurweb/models/license.py @@ -1,10 +1,16 @@ +from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper -from aurweb.schema import Licenses +from aurweb.models.declarative import Base -class License: +class License(Base): + __tablename__ = "Licenses" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} + def __init__(self, Name: str = None): self.Name = Name if not self.Name: @@ -12,6 +18,3 @@ class License: statement="Column Name cannot be null.", orig="Licenses.Name", params=("NULL")) - - -mapper(License, Licenses) diff --git a/aurweb/models/official_provider.py b/aurweb/models/official_provider.py index 073eb435..756be843 100644 --- a/aurweb/models/official_provider.py +++ b/aurweb/models/official_provider.py @@ -1,10 +1,16 @@ +from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper -from aurweb.schema import OfficialProviders +from aurweb.models.declarative import Base -class OfficialProvider: +class OfficialProvider(Base): + __tablename__ = "OfficialProviders" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} + def __init__(self, Name: str = None, Repo: str = None, @@ -29,6 +35,3 @@ class OfficialProvider: statement="Column Provides cannot be null.", orig="OfficialProviders.Provides", params=("NULL")) - - -mapper(OfficialProvider, OfficialProviders) diff --git a/aurweb/models/package.py b/aurweb/models/package.py index 28a13791..ff518f20 100644 --- a/aurweb/models/package.py +++ b/aurweb/models/package.py @@ -1,20 +1,37 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.package_base import PackageBase -from aurweb.schema import Packages +import aurweb.db +import aurweb.models.package_base + +from aurweb.models.declarative import Base -class Package: +class Package(Base): + __tablename__ = "Packages" + + ID = Column(Integer, primary_key=True) + + PackageBaseID = Column( + Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False) + PackageBase = relationship( + "PackageBase", backref=backref("package", uselist=False), + foreign_keys=[PackageBaseID]) + + __mapper_args__ = {"primary_key": [ID]} + def __init__(self, - PackageBase: PackageBase = None, - Name: str = None, Version: str = None, - Description: str = None, URL: str = None): + PackageBase: aurweb.models.package_base.PackageBase = None, + Name: str = None, + Version: str = None, + Description: str = None, + URL: str = None): self.PackageBase = PackageBase if not self.PackageBase: raise IntegrityError( - statement="Foreign key UserID cannot be null.", + statement="Foreign key PackageBaseID cannot be null.", orig="Packages.PackageBaseID", params=("NULL")) @@ -28,10 +45,3 @@ class Package: self.Version = Version self.Description = Description self.URL = URL - - -mapper(Package, Packages, properties={ - "PackageBase": make_relationship(PackageBase, - Packages.c.PackageBaseID, - "package", uselist=False) -}) diff --git a/aurweb/models/package_base.py b/aurweb/models/package_base.py index 699559d5..261c30f3 100644 --- a/aurweb/models/package_base.py +++ b/aurweb/models/package_base.py @@ -1,17 +1,47 @@ from datetime import datetime +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.user import User -from aurweb.schema import PackageBases +import aurweb.models.user + +from aurweb.models.declarative import Base -class PackageBase: - def __init__(self, Name: str = None, Flagger: User = None, - Maintainer: User = None, Submitter: User = None, - Packager: User = None, **kwargs): +class PackageBase(Base): + __tablename__ = "PackageBases" + + FlaggerUID = Column(Integer, + ForeignKey("Users.ID", ondelete="SET NULL")) + Flagger = relationship( + "User", backref=backref("flagged_bases", lazy="dynamic"), + foreign_keys=[FlaggerUID]) + + SubmitterUID = Column(Integer, + ForeignKey("Users.ID", ondelete="SET NULL")) + Submitter = relationship( + "User", backref=backref("submitted_bases", lazy="dynamic"), + foreign_keys=[SubmitterUID]) + + MaintainerUID = Column(Integer, + ForeignKey("Users.ID", ondelete="SET NULL")) + Maintainer = relationship( + "User", backref=backref("maintained_bases", lazy="dynamic"), + foreign_keys=[MaintainerUID]) + + PackagerUID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) + Packager = relationship( + "User", backref=backref("package_bases", lazy="dynamic"), + foreign_keys=[PackagerUID]) + + def __init__(self, Name: str = None, + Flagger: aurweb.models.user.User = None, + Maintainer: aurweb.models.user.User = None, + Submitter: aurweb.models.user.User = None, + Packager: aurweb.models.user.User = None, + **kwargs): + super().__init__(**kwargs) self.Name = Name if not self.Name: raise IntegrityError( @@ -32,15 +62,3 @@ class PackageBase: datetime.utcnow().timestamp()) self.ModifiedTS = kwargs.get("ModifiedTS", datetime.utcnow().timestamp()) - - -mapper(PackageBase, PackageBases, properties={ - "Flagger": make_relationship(User, PackageBases.c.FlaggerUID, - "flagged_bases"), - "Submitter": make_relationship(User, PackageBases.c.SubmitterUID, - "submitted_bases"), - "Maintainer": make_relationship(User, PackageBases.c.MaintainerUID, - "maintained_bases"), - "Packager": make_relationship(User, PackageBases.c.PackagerUID, - "package_bases") -}) diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index 21801802..0bd84073 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -1,17 +1,40 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.dependency_type import DependencyType -from aurweb.models.package import Package -from aurweb.schema import PackageDepends +import aurweb.models.package + +from aurweb.models import dependency_type +from aurweb.models.declarative import Base -class PackageDependency: - def __init__(self, Package: Package = None, - DependencyType: DependencyType = None, - DepName: str = None, DepDesc: str = None, - DepCondition: str = None, DepArch: str = None): +class PackageDependency(Base): + __tablename__ = "PackageDepends" + + PackageID = Column( + Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), + nullable=False) + Package = relationship( + "Package", backref=backref("package_dependencies", lazy="dynamic"), + foreign_keys=[PackageID], lazy="select") + + DepTypeID = Column( + Integer, ForeignKey("DependencyTypes.ID", ondelete="NO ACTION"), + nullable=False) + DependencyType = relationship( + "DependencyType", + backref=backref("package_dependencies", lazy="dynamic"), + foreign_keys=[DepTypeID], lazy="select") + + __mapper_args__ = {"primary_key": [PackageID, DepTypeID]} + + def __init__(self, + Package: aurweb.models.package.Package = None, + DependencyType: dependency_type.DependencyType = None, + DepName: str = None, + DepDesc: str = None, + DepCondition: str = None, + DepArch: str = None): self.Package = Package if not self.Package: raise IntegrityError( @@ -36,15 +59,3 @@ class PackageDependency: self.DepDesc = DepDesc self.DepCondition = DepCondition self.DepArch = DepArch - - -properties = { - "Package": make_relationship(Package, PackageDepends.c.PackageID, - "package_dependencies"), - "DependencyType": make_relationship(DependencyType, - PackageDepends.c.DepTypeID, - "package_dependencies") -} - -mapper(PackageDependency, PackageDepends, properties=properties, - primary_key=[PackageDepends.c.PackageID, PackageDepends.c.DepTypeID]) diff --git a/aurweb/models/package_group.py b/aurweb/models/package_group.py index 19a11c80..a8031e0d 100644 --- a/aurweb/models/package_group.py +++ b/aurweb/models/package_group.py @@ -1,14 +1,33 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.group import Group -from aurweb.models.package import Package -from aurweb.schema import PackageGroups +import aurweb.models.group +import aurweb.models.package + +from aurweb.models.declarative import Base -class PackageGroup: - def __init__(self, Package: Package = None, Group: Group = None): +class PackageGroup(Base): + __tablename__ = "PackageGroups" + + PackageID = Column(Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), + primary_key=True, nullable=True) + Package = relationship( + "Package", backref=backref("package_groups", lazy="dynamic"), + foreign_keys=[PackageID]) + + GroupID = Column(Integer, ForeignKey("Groups.ID", ondelete="CASCADE"), + primary_key=True, nullable=True) + Group = relationship( + "Group", backref=backref("package_groups", lazy="dynamic"), + foreign_keys=[GroupID]) + + __mapper_args__ = {"primary_key": [PackageID, GroupID]} + + def __init__(self, + Package: aurweb.models.package.Package = None, + Group: aurweb.models.group.Group = None): self.Package = Package if not self.Package: raise IntegrityError( @@ -22,18 +41,3 @@ class PackageGroup: statement="Primary key GroupID cannot be null.", orig="PackageGroups.GroupID", params=("NULL")) - - -properties = { - "Package": make_relationship(Package, - PackageGroups.c.PackageID, - "package_group", - uselist=False), - "Group": make_relationship(Group, - PackageGroups.c.GroupID, - "package_group", - uselist=False) -} - -mapper(PackageGroup, PackageGroups, properties=properties, - primary_key=[PackageGroups.c.PackageID, PackageGroups.c.GroupID]) diff --git a/aurweb/models/package_keyword.py b/aurweb/models/package_keyword.py index 2bae223c..2926740d 100644 --- a/aurweb/models/package_keyword.py +++ b/aurweb/models/package_keyword.py @@ -1,14 +1,27 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.package_base import PackageBase -from aurweb.schema import PackageKeywords +import aurweb.db +import aurweb.models.package_base + +from aurweb.models.declarative import Base -class PackageKeyword: +class PackageKeyword(Base): + __tablename__ = "PackageKeywords" + + PackageBaseID = Column( + Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), + primary_key=True, nullable=True) + PackageBase = relationship( + "PackageBase", backref=backref("keywords", lazy="dynamic"), + foreign_keys=[PackageBaseID]) + + __mapper_args__ = {"primary_key": [PackageBaseID]} + def __init__(self, - PackageBase: PackageBase = None, + PackageBase: aurweb.models.package_base.PackageBase = None, Keyword: str = None): self.PackageBase = PackageBase if not self.PackageBase: @@ -18,10 +31,3 @@ class PackageKeyword: params=("NULL")) self.Keyword = Keyword - - -mapper(PackageKeyword, PackageKeywords, properties={ - "PackageBase": make_relationship(PackageBase, - PackageKeywords.c.PackageBaseID, - "keywords") -}) diff --git a/aurweb/models/package_license.py b/aurweb/models/package_license.py index 491874a4..0689562f 100644 --- a/aurweb/models/package_license.py +++ b/aurweb/models/package_license.py @@ -1,14 +1,35 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.license import License -from aurweb.models.package import Package -from aurweb.schema import PackageLicenses +import aurweb.models.license +import aurweb.models.package + +from aurweb.models.declarative import Base -class PackageLicense: - def __init__(self, Package: Package = None, License: License = None): +class PackageLicense(Base): + __tablename__ = "PackageLicenses" + + PackageID = Column( + Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), + primary_key=True, nullable=True) + Package = relationship( + "Package", backref=backref("package_license", uselist=False), + foreign_keys=[PackageID]) + + LicenseID = Column( + Integer, ForeignKey("Licenses.ID", ondelete="CASCADE"), + primary_key=True, nullable=True) + License = relationship( + "License", backref=backref("package_license", uselist=False), + foreign_keys=[LicenseID]) + + __mapper_args__ = {"primary_key": [PackageID, LicenseID]} + + def __init__(self, + Package: aurweb.models.package.Package = None, + License: aurweb.models.license.License = None): self.Package = Package if not self.Package: raise IntegrityError( @@ -22,20 +43,3 @@ class PackageLicense: statement="Primary key LicenseID cannot be null.", orig="PackageLicenses.LicenseID", params=("NULL")) - - -properties = { - "Package": make_relationship(Package, - PackageLicenses.c.PackageID, - "package_license", - uselist=False), - "License": make_relationship(License, - PackageLicenses.c.LicenseID, - "package_license", - uselist=False) - - -} - -mapper(PackageLicense, PackageLicenses, properties=properties, - primary_key=[PackageLicenses.c.PackageID, PackageLicenses.c.LicenseID]) diff --git a/aurweb/models/package_relation.py b/aurweb/models/package_relation.py index d9ade727..9204af59 100644 --- a/aurweb/models/package_relation.py +++ b/aurweb/models/package_relation.py @@ -1,15 +1,36 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper +from sqlalchemy.orm import backref, relationship -from aurweb.db import make_relationship -from aurweb.models.package import Package -from aurweb.models.relation_type import RelationType -from aurweb.schema import PackageRelations +import aurweb.db +import aurweb.models.package +import aurweb.models.relation_type + +from aurweb.models.declarative import Base -class PackageRelation: - def __init__(self, Package: Package = None, - RelationType: RelationType = None, +class PackageRelation(Base): + __tablename__ = "PackageRelations" + + PackageID = Column( + Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), + nullable=False) + Package = relationship( + "Package", backref=backref("package_relations", lazy="dynamic"), + foreign_keys=[PackageID]) + + RelTypeID = Column( + Integer, ForeignKey("RelationTypes.ID", ondelete="CASCADE"), + nullable=False) + RelationType = relationship( + "RelationType", backref=backref("package_relations", lazy="dynamic"), + foreign_keys=[RelTypeID]) + + __mapper_args__ = {"primary_key": [PackageID, RelTypeID]} + + def __init__(self, + Package: aurweb.models.package.Package = None, + RelationType: aurweb.models.relation_type.RelationType = None, RelName: str = None, RelCondition: str = None, RelArch: str = None): self.Package = Package @@ -35,18 +56,3 @@ class PackageRelation: self.RelCondition = RelCondition self.RelArch = RelArch - - -properties = { - "Package": make_relationship(Package, PackageRelations.c.PackageID, - "package_relations"), - "RelationType": make_relationship(RelationType, - PackageRelations.c.RelTypeID, - "package_relations") -} - -mapper(PackageRelation, PackageRelations, properties=properties, - primary_key=[ - PackageRelations.c.PackageID, - PackageRelations.c.RelTypeID - ]) diff --git a/aurweb/models/relation_type.py b/aurweb/models/relation_type.py index b4d1efbc..319fb7f4 100644 --- a/aurweb/models/relation_type.py +++ b/aurweb/models/relation_type.py @@ -1,11 +1,14 @@ -from sqlalchemy.orm import mapper +from sqlalchemy import Column, Integer -from aurweb.schema import RelationTypes +from aurweb.models.declarative import Base -class RelationType: +class RelationType(Base): + __tablename__ = "RelationTypes" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} + def __init__(self, Name: str = None): self.Name = Name - - -mapper(RelationType, RelationTypes) diff --git a/aurweb/models/session.py b/aurweb/models/session.py index f1e0fff5..9154178e 100644 --- a/aurweb/models/session.py +++ b/aurweb/models/session.py @@ -1,12 +1,24 @@ +from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import backref, mapper, relationship +from sqlalchemy.orm import backref, relationship from aurweb.db import make_random_value, query +from aurweb.models.declarative import Base from aurweb.models.user import User -from aurweb.schema import Sessions -class Session: +class Session(Base): + __tablename__ = "Sessions" + + UsersID = Column( + Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + User = relationship( + "User", backref=backref("session", uselist=False), + foreign_keys=[UsersID]) + + __mapper_args__ = {"primary_key": [UsersID]} + def __init__(self, **kwargs): self.UsersID = kwargs.get("UsersID") if not query(User, User.ID == self.UsersID).first(): @@ -19,11 +31,5 @@ class Session: self.LastUpdateTS = kwargs.get("LastUpdateTS") -mapper(Session, Sessions, primary_key=[Sessions.c.SessionID], properties={ - "User": relationship(User, backref=backref("session", - uselist=False)) -}) - - def generate_unique_sid(): return make_random_value(Session, Session.SessionID) diff --git a/aurweb/models/ssh_pub_key.py b/aurweb/models/ssh_pub_key.py index 01ff558e..268a585b 100644 --- a/aurweb/models/ssh_pub_key.py +++ b/aurweb/models/ssh_pub_key.py @@ -3,13 +3,26 @@ import tempfile from subprocess import PIPE, Popen -from sqlalchemy.orm import backref, mapper, relationship +from sqlalchemy import Column, ForeignKey, Integer, String +from sqlalchemy.orm import backref, relationship -from aurweb.models.user import User -from aurweb.schema import SSHPubKeys +from aurweb.models.declarative import Base -class SSHPubKey: +class SSHPubKey(Base): + __tablename__ = "SSHPubKeys" + + UserID = Column( + Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + User = relationship( + "User", backref=backref("ssh_pub_key", uselist=False), + foreign_keys=[UserID]) + + Fingerprint = Column(String(44), primary_key=True) + + __mapper_args__ = {"primary_key": Fingerprint} + def __init__(self, **kwargs): self.UserID = kwargs.get("UserID") self.Fingerprint = kwargs.get("Fingerprint") @@ -34,8 +47,3 @@ def get_fingerprint(pubkey): fp = parts[1].replace("SHA256:", "") return fp - - -mapper(SSHPubKey, SSHPubKeys, properties={ - "User": relationship(User, backref=backref("ssh_pub_key", uselist=False)) -}) diff --git a/aurweb/models/term.py b/aurweb/models/term.py index 1a0780df..b0da71f7 100644 --- a/aurweb/models/term.py +++ b/aurweb/models/term.py @@ -1,10 +1,16 @@ +from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError -from sqlalchemy.orm import mapper -from aurweb.schema import Terms +from aurweb.models.declarative import Base -class Term: +class Term(Base): + __tablename__ = "Terms" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} + def __init__(self, Description: str = None, URL: str = None, Revision: int = None): @@ -23,6 +29,3 @@ class Term: params=("NULL")) self.Revision = Revision - - -mapper(Term, Terms) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 1961228e..83cde5f1 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -5,50 +5,44 @@ from datetime import datetime import bcrypt from fastapi import Request -from sqlalchemy.orm import backref, mapper, relationship +from sqlalchemy import Column, ForeignKey, Integer, String, text +from sqlalchemy.orm import backref, relationship import aurweb.config +import aurweb.models.account_type +import aurweb.schema -from aurweb.models.account_type import AccountType from aurweb.models.ban import is_banned -from aurweb.schema import Users +from aurweb.models.declarative import Base -class User: +class User(Base): """ An ORM model of a single Users record. """ + __tablename__ = "Users" + + ID = Column(Integer, primary_key=True) + + AccountTypeID = Column( + Integer, ForeignKey("AccountTypes.ID", ondelete="NO ACTION"), + nullable=False, server_default=text("1")) + AccountType = relationship( + "AccountType", + backref=backref("users", lazy="dynamic"), + foreign_keys=[AccountTypeID], + uselist=False) + + Passwd = Column(String(255), default=str()) + + __mapper_args__ = {"primary_key": [ID]} + + # High-level variables used to track authentication (not in DB). authenticated = False - def __init__(self, **kwargs): - # Set AccountTypeID if it was passed. - self.AccountTypeID = kwargs.get("AccountTypeID") + def __init__(self, Passwd: str = str(), **kwargs): + super().__init__(**kwargs) - account_type = kwargs.get("AccountType") - if account_type: - self.AccountType = account_type - - self.Username = kwargs.get("Username") - - self.ResetKey = kwargs.get("ResetKey") - self.Email = kwargs.get("Email") - self.BackupEmail = kwargs.get("BackupEmail") - self.RealName = kwargs.get("RealName") - self.LangPreference = kwargs.get("LangPreference") - self.Timezone = kwargs.get("Timezone") - self.Homepage = kwargs.get("Homepage") - self.IRCNick = kwargs.get("IRCNick") - self.PGPKey = kwargs.get("PGPKey") - self.RegistrationTS = datetime.utcnow() - self.CommentNotify = kwargs.get("CommentNotify") - self.UpdateNotify = kwargs.get("UpdateNotify") - self.OwnershipNotify = kwargs.get("OwnershipNotify") - self.SSOAccountID = kwargs.get("SSOAccountID") - - self.Salt = None - self.Passwd = str() - - passwd = kwargs.get("Passwd") - if passwd: - self.update_password(passwd) + if Passwd: + self.update_password(Passwd) def update_password(self, password, salt_rounds=12): self.Passwd = bcrypt.hashpw( @@ -154,10 +148,3 @@ class User: def __repr__(self): return "" % ( self.ID, str(self.AccountType), self.Username) - - -# Map schema.Users to User and give it some relationships. -mapper(User, Users, properties={ - "AccountType": relationship(AccountType, - backref=backref("users", lazy="dynamic")) -}) diff --git a/test/test_accepted_term.py b/test/test_accepted_term.py index 4ddf1fc3..8569b021 100644 --- a/test/test_accepted_term.py +++ b/test/test_accepted_term.py @@ -22,7 +22,7 @@ def setup(): AccountType.AccountType == "User").first() user = create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - account_type=account_type) + AccountType=account_type) term = create(Term, Description="Test term", URL="https://test.term") @@ -33,7 +33,7 @@ def test_accepted_term(): # Make sure our AcceptedTerm relationships got initialized properly. assert accepted_term.User == user assert accepted_term in user.accepted_terms - assert accepted_term in term.accepted + assert accepted_term in term.accepted_terms def test_accepted_term_null_user_raises_exception(): diff --git a/test/test_account_type.py b/test/test_account_type.py index 3bd76d1e..fa4bc5ad 100644 --- a/test/test_account_type.py +++ b/test/test_account_type.py @@ -43,6 +43,7 @@ def test_user_account_type_relationship(): AccountType=account_type) assert user.AccountType == account_type - assert account_type.users.filter(User.ID == user.ID).first() + # This must be deleted here to avoid foreign key issues when + # deleting the temporary AccountType in the fixture. delete(User, User.ID == user.ID) diff --git a/test/test_package.py b/test/test_package.py index a994f096..9532823d 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -1,7 +1,7 @@ import pytest from sqlalchemy import and_ -from sqlalchemy.exc import IntegrityError +from sqlalchemy.exc import IntegrityError, OperationalError import aurweb.config @@ -19,7 +19,7 @@ user = pkgbase = package = None def setup(): global user, pkgbase, package - setup_test_db("Users", "PackageBases", "Packages") + setup_test_db("Packages", "PackageBases", "Users") account_type = query(AccountType, AccountType.AccountType == "User").first() @@ -57,17 +57,17 @@ def test_package(): assert record is not None -def test_package_ci(): +def test_package_package_base_cant_change(): """ Test case insensitivity of the database table. """ if aurweb.config.get("database", "backend") == "sqlite": return None # SQLite doesn't seem handle this. from aurweb.db import session - with pytest.raises(IntegrityError): + with pytest.raises(OperationalError): create(Package, PackageBase=pkgbase, - Name="Beautiful-Package") + Name="invalidates-old-package-packagebase-relationship") session.rollback() diff --git a/test/test_package_group.py b/test/test_package_group.py index 28047a7f..0e6e41e3 100644 --- a/test/test_package_group.py +++ b/test/test_package_group.py @@ -25,7 +25,7 @@ def setup(): AccountType.AccountType == "User").first() user = create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - account_type=account_type) + AccountType=account_type) group = create(Group, Name="Test Group") pkgbase = create(PackageBase, Name="test-package", Maintainer=user) diff --git a/test/test_package_license.py b/test/test_package_license.py index 72eb3681..f7654dee 100644 --- a/test/test_package_license.py +++ b/test/test_package_license.py @@ -25,7 +25,7 @@ def setup(): AccountType.AccountType == "User").first() user = create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - account_type=account_type) + AccountType=account_type) license = create(License, Name="Test License") pkgbase = create(PackageBase, Name="test-package", Maintainer=user) diff --git a/test/test_session.py b/test/test_session.py index 1dd82db1..1ba11556 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -10,12 +10,12 @@ from aurweb.models.session import Session, generate_unique_sid from aurweb.models.user import User from aurweb.testing import setup_test_db -user = session = None +account_type = user = session = None @pytest.fixture(autouse=True) def setup(): - global user, session + global account_type, user, session setup_test_db("Users", "Sessions") @@ -35,7 +35,10 @@ def test_session(): def test_session_cs(): """ Test case sensitivity of the database table. """ - session_cs = create(Session, UsersID=user.ID, + user2 = create(User, Username="test2", Email="test2@example.org", + ResetKey="testReset2", Passwd="testPassword", + AccountType=account_type) + session_cs = create(Session, UsersID=user2.ID, SessionID="TESTSESSION", LastUpdateTS=datetime.utcnow().timestamp()) assert session_cs.SessionID == "TESTSESSION" From 5de7ff64df0dc33a20999ae7042ff04a77451819 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 10 Jun 2021 13:55:07 -0700 Subject: [PATCH 0692/1891] add PackageVote SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_vote.py | 53 ++++++++++++++++++++++++++++++++ test/test_package_vote.py | 58 +++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 aurweb/models/package_vote.py create mode 100644 test/test_package_vote.py diff --git a/aurweb/models/package_vote.py b/aurweb/models/package_vote.py new file mode 100644 index 00000000..55a9ecbb --- /dev/null +++ b/aurweb/models/package_vote.py @@ -0,0 +1,53 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.package_base +import aurweb.models.user + +from aurweb.models.declarative import Base + + +class PackageVote(Base): + __tablename__ = "PackageVotes" + + UsersID = Column( + Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + User = relationship( + "User", backref=backref("package_votes", lazy="dynamic"), + foreign_keys=[UsersID]) + + PackageBaseID = Column( + Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False) + PackageBase = relationship( + "PackageBase", backref=backref("package_votes", lazy="dynamic"), + foreign_keys=[PackageBaseID]) + + __mapper_args__ = {"primary_key": [UsersID, PackageBaseID]} + + def __init__(self, + User: aurweb.models.user.User = None, + PackageBase: aurweb.models.package_base.PackageBase = None, + VoteTS: int = None): + self.User = User + if not self.User: + raise IntegrityError( + statement="Foreign key UsersID cannot be null.", + orig="PackageVotes.UsersID", + params=("NULL")) + + self.PackageBase = PackageBase + if not self.PackageBase: + raise IntegrityError( + statement="Foreign key PackageBaseID cannot be null.", + orig="PackageVotes.PackageBaseID", + params=("NULL")) + + self.VoteTS = VoteTS + if not self.VoteTS: + raise IntegrityError( + statement="Column VoteTS cannot be null.", + orig="PackageVotes.VoteTS", + params=("NULL")) diff --git a/test/test_package_vote.py b/test/test_package_vote.py new file mode 100644 index 00000000..b352bf11 --- /dev/null +++ b/test/test_package_vote.py @@ -0,0 +1,58 @@ +from datetime import datetime + +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query, rollback +from aurweb.models.account_type import AccountType +from aurweb.models.package_base import PackageBase +from aurweb.models.package_vote import PackageVote +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase + + setup_test_db("Users", "PackageBases", "PackageVotes") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + print(account_type.ID) + print(account_type.AccountType) + + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + + +def test_package_vote_creation(): + ts = int(datetime.utcnow().timestamp()) + package_vote = create(PackageVote, User=user, PackageBase=pkgbase, + VoteTS=ts) + assert bool(package_vote) + assert package_vote.User == user + assert package_vote.PackageBase == pkgbase + assert package_vote.VoteTS == ts + + +def test_package_vote_null_user_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageVote, PackageBase=pkgbase, VoteTS=1) + rollback() + + +def test_package_vote_null_pkgbase_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageVote, User=user, VoteTS=1) + rollback() + + +def test_package_vote_null_votets_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageVote, User=user, PackageBase=pkgbase) + rollback() From d18cfad63eeaab54fd21d386a769d85067153f8f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 10 Jun 2021 14:18:39 -0700 Subject: [PATCH 0693/1891] use djangos method of wiping sqlite3 tables Django uses a reference graph to determine the order in table deletions that occur. Do the same here. This commit also adds in the `REGEXP` sqlite function, exactly how Django uses it in its reference graphing. Signed-off-by: Kevin Morris --- aurweb/db.py | 24 +++++++++++++++++++++++- aurweb/testing/__init__.py | 36 ++++++++++++++++++++++++++++++++++++ test/test_db.py | 3 +++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/aurweb/db.py b/aurweb/db.py index 9837c746..04c8653a 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,4 +1,8 @@ +import functools import math +import re + +from sqlalchemy import event import aurweb.config import aurweb.util @@ -129,13 +133,31 @@ def get_engine(echo: bool = False): if engine is None: connect_args = dict() - if aurweb.config.get("database", "backend") == "sqlite": + + db_backend = aurweb.config.get("database", "backend") + if db_backend == "sqlite": # check_same_thread is for a SQLite technicality # https://fastapi.tiangolo.com/tutorial/sql-databases/#note connect_args["check_same_thread"] = False + engine = create_engine(get_sqlalchemy_url(), connect_args=connect_args, echo=echo) + + if db_backend == "sqlite": + # For SQLite, we need to add some custom functions as + # they are used in the reference graph method. + def regexp(regex, item): + return bool(re.search(regex, str(item))) + + @event.listens_for(engine, "begin") + def do_begin(conn): + create_deterministic_function = functools.partial( + conn.connection.create_function, + deterministic=True + ) + create_deterministic_function("REGEXP", 2, regexp) + Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) session = Session() diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py index 02c21a4c..90d46720 100644 --- a/aurweb/testing/__init__.py +++ b/aurweb/testing/__init__.py @@ -1,6 +1,28 @@ +from itertools import chain + import aurweb.db +def references_graph(table): + """ Taken from Django's sqlite3/operations.py. """ + query = """ + WITH tables AS ( + SELECT :table name + UNION + SELECT sqlite_master.name + FROM sqlite_master + JOIN tables ON (sql REGEXP :regexp_1 || tables.name || :regexp_2) + ) SELECT name FROM tables; + """ + params = { + "table": table, + "regexp_1": r'(?i)\s+references\s+("|\')?', + "regexp_2": r'("|\')?\s*\(', + } + cursor = aurweb.db.session.execute(query, params=params) + return [row[0] for row in cursor.fetchall()] + + def setup_test_db(*args): """ This function is to be used to setup a test database before using it. It takes a variable number of table strings, and for @@ -25,8 +47,22 @@ def setup_test_db(*args): aurweb.db.get_engine() tables = list(args) + + db_backend = aurweb.config.get("database", "backend") + + if db_backend != "sqlite": + aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 0") + else: + # We're using sqlite, setup tables to be deleted without violating + # foreign key constraints by graphing references. + tables = set(chain.from_iterable( + references_graph(table) for table in tables)) + for table in tables: aurweb.db.session.execute(f"DELETE FROM {table}") + if db_backend != "sqlite": + aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 1") + # Expunge all objects from SQLAlchemy's IdentityMap. aurweb.db.session.expunge_all() diff --git a/test/test_db.py b/test/test_db.py index 3911134f..9298c53d 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -200,6 +200,9 @@ def test_connection_execute_paramstyle_format(): aurweb.db.kill_engine() aurweb.initdb.run(Args()) + # Test SQLite route of clearing tables. + setup_test_db("Users", "Bans") + conn = db.Connection() # First, test ? to %s format replacement. From 11c4926502e0767ee2435a79dd1c8ecaee727086 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 10 Jun 2021 17:46:29 -0700 Subject: [PATCH 0694/1891] add PackageSource SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_source.py | 31 +++++++++++++++++++++++ test/test_package_source.py | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 aurweb/models/package_source.py create mode 100644 test/test_package_source.py diff --git a/aurweb/models/package_source.py b/aurweb/models/package_source.py new file mode 100644 index 00000000..4ffa23df --- /dev/null +++ b/aurweb/models/package_source.py @@ -0,0 +1,31 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.package + +from aurweb.models.declarative import Base + + +class PackageSource(Base): + __tablename__ = "PackageSources" + + PackageID = Column(Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), + nullable=False) + Package = relationship( + "Package", backref=backref("package_sources", lazy="dynamic"), + foreign_keys=[PackageID]) + + __mapper_args__ = {"primary_key": [PackageID]} + + def __init__(self, + Package: aurweb.models.package.Package = None, + **kwargs): + super().__init__(**kwargs) + + self.Package = Package + if not self.Package: + raise IntegrityError( + statement="Foreign key PackageID cannot be null.", + orig="PackageSources.PackageID", + params=("NULL")) diff --git a/test/test_package_source.py b/test/test_package_source.py new file mode 100644 index 00000000..7453f756 --- /dev/null +++ b/test/test_package_source.py @@ -0,0 +1,44 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query, rollback +from aurweb.models.account_type import AccountType +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_source import PackageSource +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = package = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase, package + + setup_test_db("PackageSources", "Packages", "PackageBases", "Users") + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + pkgbase = create(PackageBase, + Name="test-package", + Maintainer=user) + package = create(Package, PackageBase=pkgbase, Name="test-package") + + +def test_package_source(): + pkgsource = create(PackageSource, Package=package) + assert pkgsource.Package == package + # By default, PackageSources.Source assigns the string '/dev/null'. + assert pkgsource.Source == "/dev/null" + assert pkgsource.SourceArch is None + + +def test_package_source_null_package_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageSource) + rollback() From fc28c1e5fd137ab36786eae864a19617bdce90e6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 00:35:18 -0700 Subject: [PATCH 0695/1891] add PackageComment SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_comment.py | 72 ++++++++++++++++++++++++++++++++ test/test_package_comment.py | 63 ++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 aurweb/models/package_comment.py create mode 100644 test/test_package_comment.py diff --git a/aurweb/models/package_comment.py b/aurweb/models/package_comment.py new file mode 100644 index 00000000..42a0661d --- /dev/null +++ b/aurweb/models/package_comment.py @@ -0,0 +1,72 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.package_base +import aurweb.models.user + +from aurweb.models.declarative import Base + + +class PackageComment(Base): + __tablename__ = "PackageComments" + + ID = Column(Integer, primary_key=True) + + PackageBaseID = Column( + Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False) + PackageBase = relationship( + "PackageBase", backref=backref("comments", lazy="dynamic"), + foreign_keys=[PackageBaseID]) + + UsersID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) + User = relationship( + "User", backref=backref("package_comments", lazy="dynamic"), + foreign_keys=[UsersID]) + + EditedUsersID = Column( + Integer, ForeignKey("Users.ID", ondelete="SET NULL")) + Editor = relationship( + "User", backref=backref("edited_comments", lazy="dynamic"), + foreign_keys=[EditedUsersID]) + + DelUsersID = Column( + Integer, ForeignKey("Users.ID", ondelete="SET NULL")) + Deleter = relationship( + "User", backref=backref("deleted_comments", lazy="dynamic"), + foreign_keys=[DelUsersID]) + + __mapper_args__ = {"primary_key": [ID]} + + def __init__(self, + PackageBase: aurweb.models.package_base.PackageBase = None, + User: aurweb.models.user.User = None, + **kwargs): + super().__init__(**kwargs) + + self.PackageBase = PackageBase + if not self.PackageBase: + raise IntegrityError( + statement="Foreign key PackageBaseID cannot be null.", + orig="PackageComments.PackageBaseID", + params=("NULL")) + + self.User = User + if not self.User: + raise IntegrityError( + statement="Foreign key UsersID cannot be null.", + orig="PackageComments.UsersID", + params=("NULL")) + + if self.Comments is None: + raise IntegrityError( + statement="Column Comments cannot be null.", + orig="PackageComments.Comments", + params=("NULL")) + + if self.RenderedComment is None: + raise IntegrityError( + statement="Column RenderedComment cannot be null.", + orig="PackageComments.RenderedComment", + params=("NULL")) diff --git a/test/test_package_comment.py b/test/test_package_comment.py new file mode 100644 index 00000000..fb734071 --- /dev/null +++ b/test/test_package_comment.py @@ -0,0 +1,63 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query, rollback +from aurweb.models.account_type import AccountType +from aurweb.models.package_base import PackageBase +from aurweb.models.package_comment import PackageComment +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = None + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db("PackageBases", "PackageComments", "Users") + + global user, pkgbase + + account_type = query(AccountType, + AccountType.AccountType == "User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + + +def test_package_comment_creation(): + package_comment = create(PackageComment, + PackageBase=pkgbase, + User=user, + Comments="Test comment.", + RenderedComment="Test rendered comment.") + assert bool(package_comment.ID) + + +def test_package_comment_null_package_base_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageComment, User=user, Comments="Test comment.", + RenderedComment="Test rendered comment.") + rollback() + + +def test_package_comment_null_user_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageComment, PackageBase=pkgbase, Comments="Test comment.", + RenderedComment="Test rendered comment.") + rollback() + + +def test_package_comment_null_comments_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageComment, PackageBase=pkgbase, User=user, + RenderedComment="Test rendered comment.") + rollback() + + +def test_package_comment_null_renderedcomment_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageComment, PackageBase=pkgbase, User=user, + Comments="Test comment.") + rollback() From ebd216edfd4f78db864f044fdc10d13cdc7b20b9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 16:52:45 -0700 Subject: [PATCH 0696/1891] add PackageComaintainer SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_comaintainer.py | 53 +++++++++++++++++++++++++++ test/test_package_comaintainer.py | 49 +++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 aurweb/models/package_comaintainer.py create mode 100644 test/test_package_comaintainer.py diff --git a/aurweb/models/package_comaintainer.py b/aurweb/models/package_comaintainer.py new file mode 100644 index 00000000..88fd58ae --- /dev/null +++ b/aurweb/models/package_comaintainer.py @@ -0,0 +1,53 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.package_base +import aurweb.models.user + +from aurweb.models.declarative import Base + + +class PackageComaintainer(Base): + __tablename__ = "PackageComaintainers" + + UsersID = Column( + Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + User = relationship( + "User", backref=backref("comaintained", lazy="dynamic"), + foreign_keys=[UsersID]) + + PackageBaseID = Column( + Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False) + PackageBase = relationship( + "PackageBase", backref=backref("comaintainers", lazy="dynamic"), + foreign_keys=[PackageBaseID]) + + __mapper_args__ = {"primary_key": [UsersID, PackageBaseID]} + + def __init__(self, + User: aurweb.models.user.User = None, + PackageBase: aurweb.models.package_base.PackageBase = None, + Priority: int = None): + self.User = User + if not self.User: + raise IntegrityError( + statement="Foreign key UsersID cannot be null.", + orig="PackageComaintainers.UsersID", + params=("NULL")) + + self.PackageBase = PackageBase + if not self.PackageBase: + raise IntegrityError( + statement="Foreign key PackageBaseID cannot be null.", + orig="PackageComaintainers.PackageBaseID", + params=("NULL")) + + self.Priority = Priority + if not self.Priority: + raise IntegrityError( + statement="Column Priority cannot be null.", + orig="PackageComaintainers.Priority", + params=("NULL")) diff --git a/test/test_package_comaintainer.py b/test/test_package_comaintainer.py new file mode 100644 index 00000000..ac94a9ba --- /dev/null +++ b/test/test_package_comaintainer.py @@ -0,0 +1,49 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, rollback +from aurweb.models.package_base import PackageBase +from aurweb.models.package_comaintainer import PackageComaintainer +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase + + setup_test_db("Users", "PackageBases", "PackageComaintainers") + + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + + +def test_package_comaintainer_creation(): + package_comaintainer = create(PackageComaintainer, User=user, PackageBase=pkgbase, + Priority=5) + assert bool(package_comaintainer) + assert package_comaintainer.User == user + assert package_comaintainer.PackageBase == pkgbase + assert package_comaintainer.Priority == 5 + + +def test_package_comaintainer_null_user_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageComaintainer, PackageBase=pkgbase, Priority=1) + rollback() + + +def test_package_comaintainer_null_pkgbase_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageComaintainer, User=user, Priority=1) + rollback() + + +def test_package_comaintainer_null_priority_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageComaintainer, User=user, PackageBase=pkgbase) + rollback() From 229df1adefb709959e70754845ed1bc65501064c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 16:56:15 -0700 Subject: [PATCH 0697/1891] test_package_vote: remove useless stuff Signed-off-by: Kevin Morris --- test/test_package_vote.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/test_package_vote.py b/test/test_package_vote.py index b352bf11..cb15e217 100644 --- a/test/test_package_vote.py +++ b/test/test_package_vote.py @@ -4,8 +4,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query, rollback -from aurweb.models.account_type import AccountType +from aurweb.db import create, rollback from aurweb.models.package_base import PackageBase from aurweb.models.package_vote import PackageVote from aurweb.models.user import User @@ -20,11 +19,6 @@ def setup(): setup_test_db("Users", "PackageBases", "PackageVotes") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - print(account_type.ID) - print(account_type.AccountType) - user = create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword") pkgbase = create(PackageBase, Name="test-package", Maintainer=user) From 5b856c7af2e023d24ca7ad0208f537aff45239db Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 17:14:28 -0700 Subject: [PATCH 0698/1891] add PackageNotification SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_notification.py | 47 +++++++++++++++++++++++++++ test/test_package_notification.py | 42 ++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 aurweb/models/package_notification.py create mode 100644 test/test_package_notification.py diff --git a/aurweb/models/package_notification.py b/aurweb/models/package_notification.py new file mode 100644 index 00000000..ab23a212 --- /dev/null +++ b/aurweb/models/package_notification.py @@ -0,0 +1,47 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.package_base +import aurweb.models.user + +from aurweb.models.declarative import Base + + +class PackageNotification(Base): + __tablename__ = "PackageNotifications" + + UserID = Column( + Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + User = relationship( + "User", backref=backref("package_notifications", lazy="dynamic"), + foreign_keys=[UserID]) + + PackageBaseID = Column( + Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False) + PackageBase = relationship( + "PackageBase", + backref=backref("package_notifications", lazy="dynamic"), + foreign_keys=[PackageBaseID]) + + __mapper_args__ = {"primary_key": [UserID, PackageBaseID]} + + def __init__(self, + User: aurweb.models.user.User = None, + PackageBase: aurweb.models.package_base.PackageBase = None, + NotificationTS: int = None): + self.User = User + if not self.User: + raise IntegrityError( + statement="Foreign key UserID cannot be null.", + orig="PackageNotifications.UserID", + params=("NULL")) + + self.PackageBase = PackageBase + if not self.PackageBase: + raise IntegrityError( + statement="Foreign key PackageBaseID cannot be null.", + orig="PackageNotifications.PackageBaseID", + params=("NULL")) diff --git a/test/test_package_notification.py b/test/test_package_notification.py new file mode 100644 index 00000000..2898a904 --- /dev/null +++ b/test/test_package_notification.py @@ -0,0 +1,42 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, rollback +from aurweb.models.package_base import PackageBase +from aurweb.models.package_notification import PackageNotification +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase + + setup_test_db("Users", "PackageBases", "PackageNotifications") + + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + + +def test_package_notification_creation(): + package_notification = create(PackageNotification, User=user, + PackageBase=pkgbase) + assert bool(package_notification) + assert package_notification.User == user + assert package_notification.PackageBase == pkgbase + + +def test_package_notification_null_user_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageNotification, PackageBase=pkgbase) + rollback() + + +def test_package_notification_null_pkgbase_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageNotification, User=user) + rollback() From 163e4d738999932fb7e109aba48170c8f2526ca6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 17:15:18 -0700 Subject: [PATCH 0699/1891] test_package_comaintainer: sanitize newlines Signed-off-by: Kevin Morris --- test/test_package_comaintainer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_package_comaintainer.py b/test/test_package_comaintainer.py index ac94a9ba..cba99ba0 100644 --- a/test/test_package_comaintainer.py +++ b/test/test_package_comaintainer.py @@ -23,8 +23,8 @@ def setup(): def test_package_comaintainer_creation(): - package_comaintainer = create(PackageComaintainer, User=user, PackageBase=pkgbase, - Priority=5) + package_comaintainer = create(PackageComaintainer, User=user, + PackageBase=pkgbase, Priority=5) assert bool(package_comaintainer) assert package_comaintainer.User == user assert package_comaintainer.PackageBase == pkgbase From 511f174c8ba704b3cf53ae47fcf56e55c74026f8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 17:28:08 -0700 Subject: [PATCH 0700/1891] add PackageBlacklist SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_blacklist.py | 20 ++++++++++++++++++ test/test_package_blacklist.py | 34 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 aurweb/models/package_blacklist.py create mode 100644 test/test_package_blacklist.py diff --git a/aurweb/models/package_blacklist.py b/aurweb/models/package_blacklist.py new file mode 100644 index 00000000..7702c877 --- /dev/null +++ b/aurweb/models/package_blacklist.py @@ -0,0 +1,20 @@ +from sqlalchemy import Column, Integer +from sqlalchemy.exc import IntegrityError + +from aurweb.models.declarative import Base + + +class PackageBlacklist(Base): + __tablename__ = "PackageBlacklist" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} + + def __init__(self, Name: str = None): + self.Name = Name + if not self.Name: + raise IntegrityError( + statement="Column Name cannot be null.", + orig="PackageBlacklist.Name", + params=("NULL")) diff --git a/test/test_package_blacklist.py b/test/test_package_blacklist.py new file mode 100644 index 00000000..3c64cc21 --- /dev/null +++ b/test/test_package_blacklist.py @@ -0,0 +1,34 @@ +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, rollback +from aurweb.models.package_base import PackageBase +from aurweb.models.package_blacklist import PackageBlacklist +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase + + setup_test_db("PackageBlacklist", "PackageBases", "Users") + + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + + +def test_package_blacklist_creation(): + package_blacklist = create(PackageBlacklist, Name="evil-package") + assert bool(package_blacklist.ID) + assert package_blacklist.Name == "evil-package" + + +def test_package_blacklist_null_name_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageBlacklist) + rollback() From 3bf4b3717a6baed1326168053daf5f374a6e5003 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 17:37:51 -0700 Subject: [PATCH 0701/1891] add RequestType SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/request_type.py | 11 +++++++++++ test/test_request_type.py | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 aurweb/models/request_type.py create mode 100644 test/test_request_type.py diff --git a/aurweb/models/request_type.py b/aurweb/models/request_type.py new file mode 100644 index 00000000..2c8276e8 --- /dev/null +++ b/aurweb/models/request_type.py @@ -0,0 +1,11 @@ +from sqlalchemy import Column, Integer + +from aurweb.models.declarative import Base + + +class RequestType(Base): + __tablename__ = "RequestTypes" + + ID = Column(Integer, primary_key=True) + + __mapper_args__ = {"primary_key": [ID]} diff --git a/test/test_request_type.py b/test/test_request_type.py new file mode 100644 index 00000000..a470a60b --- /dev/null +++ b/test/test_request_type.py @@ -0,0 +1,24 @@ +import pytest + +from aurweb.db import create, delete +from aurweb.models.request_type import RequestType +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db() + + +def test_request_type_creation(): + request_type = create(RequestType, Name="Test Request") + assert bool(request_type.ID) + assert request_type.Name == "Test Request" + delete(RequestType, RequestType.ID == request_type.ID) + + +def test_request_type_null_name_returns_empty_string(): + request_type = create(RequestType) + assert bool(request_type.ID) + assert request_type.Name == str() + delete(RequestType, RequestType.ID == request_type.ID) From 65ff0e76da9ea6cf7ba382e38414424148d7c487 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 19:57:52 -0700 Subject: [PATCH 0702/1891] aurweb.schema: Fix off-by-one String impls of DECIMAL Signed-off-by: Kevin Morris --- aurweb/schema.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/schema.py b/aurweb/schema.py index 9caf6374..fb8f0dee 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -109,7 +109,7 @@ PackageBases = Table( Column('NumVotes', INTEGER(unsigned=True), nullable=False, server_default=text("0")), Column('Popularity', DECIMAL(10, 6, unsigned=True) - if db_backend == "mysql" else String(16), # Stubbed out to test. + if db_backend == "mysql" else String(17), nullable=False, server_default=text("0")), Column('OutOfDateTS', BIGINT(unsigned=True)), Column('FlaggerComment', Text, nullable=False), @@ -388,7 +388,7 @@ TU_VoteInfo = Table( Column('End', BIGINT(unsigned=True), nullable=False), Column('Quorum', DECIMAL(2, 2, unsigned=True) - if db_backend == "mysql" else String(4), + if db_backend == "mysql" else String(5), nullable=False), Column('SubmitterID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('Yes', TINYINT(3, unsigned=True), nullable=False, server_default=text("'0'")), From 809939ab03c5192d9f06d2ffa138d4e064fd0b35 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 20:36:32 -0700 Subject: [PATCH 0703/1891] add TUVoteInfo SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/tu_voteinfo.py | 74 +++++++++++++++++++++++ test/test_tu_voteinfo.py | 111 +++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 aurweb/models/tu_voteinfo.py create mode 100644 test/test_tu_voteinfo.py diff --git a/aurweb/models/tu_voteinfo.py b/aurweb/models/tu_voteinfo.py new file mode 100644 index 00000000..2225b4d7 --- /dev/null +++ b/aurweb/models/tu_voteinfo.py @@ -0,0 +1,74 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.user + +from aurweb.models.declarative import Base + + +class TUVoteInfo(Base): + __tablename__ = "TU_VoteInfo" + + ID = Column(Integer, primary_key=True) + + SubmitterID = Column( + Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + Submitter = relationship( + "User", backref=backref("tu_voteinfo_set", lazy="dynamic"), + foreign_keys=[SubmitterID]) + + __mapper_args__ = {"primary_key": [ID]} + + def __init__(self, + Agenda: str = None, + User: str = None, + Submitted: int = None, + End: int = None, + Quorum: float = None, + Submitter: aurweb.models.user.User = None, + **kwargs): + super().__init__(**kwargs) + + self.Agenda = Agenda + if self.Agenda is None: + raise IntegrityError( + statement="Column Agenda cannot be null.", + orig="TU_VoteInfo.Agenda", + params=("NULL")) + + self.User = User + if self.User is None: + raise IntegrityError( + statement="Column User cannot be null.", + orig="TU_VoteInfo.User", + params=("NULL")) + + self.Submitted = Submitted + if self.Submitted is None: + raise IntegrityError( + statement="Column Submitted cannot be null.", + orig="TU_VoteInfo.Submitted", + params=("NULL")) + + self.End = End + if self.End is None: + raise IntegrityError( + statement="Column End cannot be null.", + orig="TU_VoteInfo.End", + params=("NULL")) + + if Quorum is None: + raise IntegrityError( + statement="Column Quorum cannot be null.", + orig="TU_VoteInfo.Quorum", + params=("NULL")) + self.Quorum = str(Quorum) + + self.Submitter = Submitter + if not self.Submitter: + raise IntegrityError( + statement="Foreign key SubmitterID cannot be null.", + orig="TU_VoteInfo.SubmitterID", + params=("NULL")) diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py new file mode 100644 index 00000000..e95f174b --- /dev/null +++ b/test/test_tu_voteinfo.py @@ -0,0 +1,111 @@ +from datetime import datetime + +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query, rollback +from aurweb.models.account_type import AccountType +from aurweb.models.tu_voteinfo import TUVoteInfo +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = None + + +@pytest.fixture(autouse=True) +def setup(): + global user + + setup_test_db("Users", "PackageBases", "TU_VoteInfo") + + tu_type = query(AccountType, + AccountType.AccountType == "Trusted User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=tu_type) + + +def test_tu_voteinfo_creation(): + ts = int(datetime.utcnow().timestamp()) + tu_voteinfo = create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 5, + Quorum=0.5, + Submitter=user) + assert bool(tu_voteinfo.ID) + assert tu_voteinfo.Agenda == "Blah blah." + assert tu_voteinfo.User == user.Username + assert tu_voteinfo.Submitted == ts + assert tu_voteinfo.End == ts + 5 + assert float(tu_voteinfo.Quorum) == 0.5 + assert tu_voteinfo.Submitter == user + assert tu_voteinfo.Yes == 0 + assert tu_voteinfo.No == 0 + assert tu_voteinfo.Abstain == 0 + assert tu_voteinfo.ActiveTUs == 0 + + assert tu_voteinfo in user.tu_voteinfo_set + + +def test_tu_voteinfo_null_submitter_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, End=0, + Quorum=0.50) + rollback() + + +def test_tu_voteinfo_null_agenda_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVoteInfo, + User=user.Username, + Submitted=0, End=0, + Quorum=0.50, + Submitter=user) + rollback() + + +def test_tu_voteinfo_null_user_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVoteInfo, + Agenda="Blah blah.", + Submitted=0, End=0, + Quorum=0.50, + Submitter=user) + rollback() + + +def test_tu_voteinfo_null_submitted_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + End=0, + Quorum=0.50, + Submitter=user) + rollback() + + +def test_tu_voteinfo_null_end_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, + Quorum=0.50, + Submitter=user) + rollback() + + +def test_tu_voteinfo_null_quorum_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, End=0, + Submitter=user) + rollback() From 541c978ac4a7bdec79e1ce7359c23d0ff42723fd Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 19:14:33 -0700 Subject: [PATCH 0704/1891] add PackageRequest SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/package_request.py | 93 ++++++++++++++++++++++++ test/test_package_request.py | 119 +++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 aurweb/models/package_request.py create mode 100644 test/test_package_request.py diff --git a/aurweb/models/package_request.py b/aurweb/models/package_request.py new file mode 100644 index 00000000..00f46ce2 --- /dev/null +++ b/aurweb/models/package_request.py @@ -0,0 +1,93 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.package_base +import aurweb.models.request_type +import aurweb.models.user + +from aurweb.models.declarative import Base + + +class PackageRequest(Base): + __tablename__ = "PackageRequests" + + ID = Column(Integer, primary_key=True) + + ReqTypeID = Column( + Integer, ForeignKey("RequestTypes.ID", ondelete="NO ACTION"), + nullable=False) + RequestType = relationship( + "RequestType", backref=backref("package_requests", lazy="dynamic"), + foreign_keys=[ReqTypeID]) + + UsersID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) + User = relationship( + "User", backref=backref("package_requests", lazy="dynamic"), + foreign_keys=[UsersID]) + + PackageBaseID = Column( + Integer, ForeignKey("PackageBases.ID", ondelete="SET NULL"), + nullable=False) + PackageBase = relationship( + "PackageBase", backref=backref("requests", lazy="dynamic"), + foreign_keys=[PackageBaseID]) + + ClosedUID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) + Closer = relationship( + "User", backref=backref("closed_requests", lazy="dynamic"), + foreign_keys=[ClosedUID]) + + __mapper_args__ = {"primary_key": [ID]} + + def __init__(self, + RequestType: aurweb.models.request_type.RequestType = None, + PackageBase: aurweb.models.package_base.PackageBase = None, + PackageBaseName: str = None, + User: aurweb.models.user.User = None, + Comments: str = None, + ClosureComment: str = None, + **kwargs): + super().__init__(**kwargs) + + self.RequestType = RequestType + if not self.RequestType: + raise IntegrityError( + statement="Foreign key ReqTypeID cannot be null.", + orig="PackageRequests.ReqTypeID", + params=("NULL")) + + self.PackageBase = PackageBase + if not self.PackageBase: + raise IntegrityError( + statement="Foreign key PackageBaseID cannot be null.", + orig="PackageRequests.PackageBaseID", + params=("NULL")) + + self.PackageBaseName = PackageBaseName + if not self.PackageBaseName: + raise IntegrityError( + statement="Column PackageBaseName cannot be null.", + orig="PackageRequests.PackageBaseName", + params=("NULL")) + + self.User = User + if not self.User: + raise IntegrityError( + statement="Foreign key UsersID cannot be null.", + orig="PackageRequests.UsersID", + params=("NULL")) + + self.Comments = Comments + if self.Comments is None: + raise IntegrityError( + statement="Column Comments cannot be null.", + orig="PackageRequests.Comments", + params=("NULL")) + + self.ClosureComment = ClosureComment + if self.ClosureComment is None: + raise IntegrityError( + statement="Column ClosureComment cannot be null.", + orig="PackageRequests.ClosureComment", + params=("NULL")) diff --git a/test/test_package_request.py b/test/test_package_request.py new file mode 100644 index 00000000..fc839836 --- /dev/null +++ b/test/test_package_request.py @@ -0,0 +1,119 @@ +from datetime import datetime + +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query, rollback +from aurweb.models.package_base import PackageBase +from aurweb.models.package_request import PackageRequest +from aurweb.models.request_type import RequestType +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = pkgbase = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, pkgbase + + setup_test_db("PackageRequests", "PackageBases", "Users") + + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + + +def test_package_request_creation(): + request_type = query(RequestType, RequestType.Name == "merge").first() + assert request_type.Name == "merge" + + package_request = create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) + + assert bool(package_request.ID) + assert package_request.RequestType == request_type + assert package_request.User == user + assert package_request.PackageBase == pkgbase + assert package_request.PackageBaseName == pkgbase.Name + assert package_request.Comments == str() + assert package_request.ClosureComment == str() + + # Make sure that everything is cross-referenced with relationships. + assert package_request in request_type.package_requests + assert package_request in user.package_requests + assert package_request in pkgbase.requests + + +def test_package_request_closed(): + request_type = query(RequestType, RequestType.Name == "merge").first() + assert request_type.Name == "merge" + + ts = int(datetime.utcnow().timestamp()) + package_request = create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Closer=user, ClosedTS=ts, + Comments=str(), ClosureComment=str()) + + assert package_request.Closer == user + assert package_request.ClosedTS == ts + + # Test relationships. + assert package_request in user.closed_requests + + +def test_package_request_null_request_type_raises_exception(): + with pytest.raises(IntegrityError): + create(PackageRequest, User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) + rollback() + + +def test_package_request_null_user_raises_exception(): + request_type = query(RequestType, RequestType.Name == "merge").first() + with pytest.raises(IntegrityError): + create(PackageRequest, RequestType=request_type, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) + rollback() + + +def test_package_request_null_package_base_raises_exception(): + request_type = query(RequestType, RequestType.Name == "merge").first() + with pytest.raises(IntegrityError): + create(PackageRequest, RequestType=request_type, + User=user, PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) + rollback() + + +def test_package_request_null_package_base_name_raises_exception(): + request_type = query(RequestType, RequestType.Name == "merge").first() + with pytest.raises(IntegrityError): + create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + Comments=str(), ClosureComment=str()) + rollback() + + +def test_package_request_null_comments_raises_exception(): + request_type = query(RequestType, RequestType.Name == "merge").first() + with pytest.raises(IntegrityError): + create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + ClosureComment=str()) + rollback() + + +def test_package_request_null_closure_comment_raises_exception(): + request_type = query(RequestType, RequestType.Name == "merge").first() + with pytest.raises(IntegrityError): + create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + Comments=str()) + rollback() From 8c345a04488a07b9836cff9559bb17722b5fc77e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 21:48:39 -0700 Subject: [PATCH 0705/1891] TUVoteInfo: generalize Quorum SQLite does not support native DECIMAL columns, and for that reason, we had to switch to using Strings that can hold the data in the case we are using sqlite. This commit sets the TUVoteInfo model up in a generic way, that it always converts to string when setting Quorum (OK for DECIMAL) and always converts to float when getting Quorum. This way, we can treat TUVoteInfo.Quorum as the same thing everywhere. Signed-off-by: Kevin Morris --- aurweb/models/tu_voteinfo.py | 15 ++++++++++++++- test/test_tu_voteinfo.py | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/aurweb/models/tu_voteinfo.py b/aurweb/models/tu_voteinfo.py index 2225b4d7..a246f132 100644 --- a/aurweb/models/tu_voteinfo.py +++ b/aurweb/models/tu_voteinfo.py @@ -1,3 +1,5 @@ +import typing + from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship @@ -64,7 +66,7 @@ class TUVoteInfo(Base): statement="Column Quorum cannot be null.", orig="TU_VoteInfo.Quorum", params=("NULL")) - self.Quorum = str(Quorum) + self.Quorum = Quorum self.Submitter = Submitter if not self.Submitter: @@ -72,3 +74,14 @@ class TUVoteInfo(Base): statement="Foreign key SubmitterID cannot be null.", orig="TU_VoteInfo.SubmitterID", params=("NULL")) + + def __setattr__(self, key: str, value: typing.Any): + """ Customize setattr to stringify any Quorum keys given. """ + if key == "Quorum": + value = str(value) + return super().__setattr__(key, value) + + def __getattribute__(self, key: str): + """ Customize getattr to floatify any fetched Quorum values. """ + attr = super().__getattribute__(key) + return float(attr) if key == "Quorum" else attr diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py index e95f174b..37609efd 100644 --- a/test/test_tu_voteinfo.py +++ b/test/test_tu_voteinfo.py @@ -39,7 +39,7 @@ def test_tu_voteinfo_creation(): assert tu_voteinfo.User == user.Username assert tu_voteinfo.Submitted == ts assert tu_voteinfo.End == ts + 5 - assert float(tu_voteinfo.Quorum) == 0.5 + assert tu_voteinfo.Quorum == 0.5 assert tu_voteinfo.Submitter == user assert tu_voteinfo.Yes == 0 assert tu_voteinfo.No == 0 From 0c1241f8bbe53b587cb149d0daee32731bffed46 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 22:14:38 -0700 Subject: [PATCH 0706/1891] add TUVote SQLAlchemy ORM model Signed-off-by: Kevin Morris --- aurweb/models/tu_vote.py | 43 ++++++++++++++++++++++++++++++ test/test_tu_vote.py | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 aurweb/models/tu_vote.py create mode 100644 test/test_tu_vote.py diff --git a/aurweb/models/tu_vote.py b/aurweb/models/tu_vote.py new file mode 100644 index 00000000..2b7bf2d0 --- /dev/null +++ b/aurweb/models/tu_vote.py @@ -0,0 +1,43 @@ +from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import backref, relationship + +import aurweb.models.tu_voteinfo +import aurweb.models.user + +from aurweb.models.declarative import Base + + +class TUVote(Base): + __tablename__ = "TU_Votes" + + VoteID = Column(Integer, ForeignKey("TU_VoteInfo.ID", ondelete="CASCADE"), + nullable=False) + VoteInfo = relationship( + "TUVoteInfo", backref=backref("tu_votes", lazy="dynamic"), + foreign_keys=[VoteID]) + + UserID = Column(Integer, ForeignKey("Users.ID", ondelete="CASCADE"), + nullable=False) + User = relationship( + "User", backref=backref("tu_votes", lazy="dynamic"), + foreign_keys=[UserID]) + + __mapper_args__ = {"primary_key": [VoteID, UserID]} + + def __init__(self, + VoteInfo: aurweb.models.tu_voteinfo.TUVoteInfo = None, + User: aurweb.models.user.User = None): + self.VoteInfo = VoteInfo + if self.VoteInfo is None: + raise IntegrityError( + statement="Foreign key VoteID cannot be null.", + orig="TU_Votes.VoteID", + params=("NULL")) + + self.User = User + if self.User is None: + raise IntegrityError( + statement="Foreign key UserID cannot be null.", + orig="TU_Votes.UserID", + params=("NULL")) diff --git a/test/test_tu_vote.py b/test/test_tu_vote.py new file mode 100644 index 00000000..9ff4a8d9 --- /dev/null +++ b/test/test_tu_vote.py @@ -0,0 +1,56 @@ +from datetime import datetime + +import pytest + +from sqlalchemy.exc import IntegrityError + +from aurweb.db import create, query, rollback +from aurweb.models.account_type import AccountType +from aurweb.models.tu_vote import TUVote +from aurweb.models.tu_voteinfo import TUVoteInfo +from aurweb.models.user import User +from aurweb.testing import setup_test_db + +user = tu_voteinfo = None + + +@pytest.fixture(autouse=True) +def setup(): + global user, tu_voteinfo + + setup_test_db("Users", "TU_VoteInfo", "TU_Votes") + + tu_type = query(AccountType, + AccountType.AccountType == "Trusted User").first() + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=tu_type) + + ts = int(datetime.utcnow().timestamp()) + tu_voteinfo = create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 5, + Quorum=0.5, + Submitter=user) + + +def test_tu_vote_creation(): + tu_vote = create(TUVote, User=user, VoteInfo=tu_voteinfo) + assert tu_vote.VoteInfo == tu_voteinfo + assert tu_vote.User == user + + assert tu_vote in user.tu_votes + assert tu_vote in tu_voteinfo.tu_votes + + +def test_tu_vote_null_user_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVote, VoteInfo=tu_voteinfo) + rollback() + + +def test_tu_vote_null_voteinfo_raises_exception(): + with pytest.raises(IntegrityError): + create(TUVote, User=user) + rollback() From 18ec8e3cc8ca3e18f87c1b892b68a0857be39597 Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Fri, 20 Nov 2020 00:19:15 +0100 Subject: [PATCH 0707/1891] RSS: Add ability to specify isPermaLink="false" for GUID --- web/lib/feedcreator.class.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/lib/feedcreator.class.php b/web/lib/feedcreator.class.php index a1fe24c9..bfc29b20 100644 --- a/web/lib/feedcreator.class.php +++ b/web/lib/feedcreator.class.php @@ -183,7 +183,7 @@ class FeedItem extends HtmlDescribable { /** * Optional attributes of an item. */ - var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator; + var $author, $authorEmail, $image, $category, $comments, $guid, $guidIsPermaLink, $source, $creator; /** * Publishing date of an item. May be in one of the following formats: @@ -995,7 +995,11 @@ class RSSCreator091 extends FeedCreator { $feed.= " ".htmlspecialchars($itemDate->rfc822())."\n"; } if ($this->items[$i]->guid!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; + $feed.= " items[$i]->guidIsPermaLink == false) { + $feed.= " isPermaLink=\"false\""; + } + $feed.= ">".htmlspecialchars($this->items[$i]->guid)."\n"; } $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); $feed.= " \n"; From 2bb30f9bf53446189b6079ac349acc82909c3a49 Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Fri, 20 Nov 2020 00:19:54 +0100 Subject: [PATCH 0708/1891] Add RSS feed for modified packages --- web/html/modified-rss.php | 62 +++++++++++++++++++++++++++++++++++++++ web/lib/pkgfuncs.inc.php | 17 +++++++++-- web/lib/routing.inc.php | 1 + 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 web/html/modified-rss.php diff --git a/web/html/modified-rss.php b/web/html/modified-rss.php new file mode 100644 index 00000000..4c5c47e0 --- /dev/null +++ b/web/html/modified-rss.php @@ -0,0 +1,62 @@ +cssStyleSheet = false; +$rss->xslStyleSheet = false; + +# Use UTF-8 (fixes FS#10706). +$rss->encoding = "UTF-8"; + +#All the general RSS setup +$rss->title = "AUR Latest Modified Packages"; +$rss->description = "The latest modified packages in the AUR"; +$rss->link = "${protocol}://{$host}"; +$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); +$image = new FeedImage(); +$image->title = "AUR Latest Modified Packages"; +$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; +$image->link = $rss->link; +$image->description = "AUR Latest Modified Packages Feed"; +$rss->image = $image; + +#Get the latest packages and add items for them +$packages = latest_modified_pkgs(100); + +foreach ($packages as $indx => $row) { + $item = new FeedItem(); + $item->title = $row["Name"]; + $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); + $item->description = $row["Description"]; + $item->date = intval($row["ModifiedTS"]); + $item->source = "{$protocol}://{$host}"; + $item->author = username_from_id($row["MaintainerUID"]); + $item->guidIsPermaLink = true; + $item->guid = $row["Name"] . "-" . $row["ModifiedTS"]; + $rss->addItem($item); +} + +#save it so that useCached() can find it +$feedContent = $rss->createFeed(); +set_cache_value($feed_key, $feedContent, 600); +echo $feedContent; +?> diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index eb3afab6..140c7ec1 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -925,13 +925,13 @@ function sanitize_ids($ids) { * * @return array $packages Package info for the specified number of recent packages */ -function latest_pkgs($numpkgs) { +function latest_pkgs($numpkgs, $orderBy='SubmittedTS') { $dbh = DB::connect(); - $q = "SELECT Packages.*, MaintainerUID, SubmittedTS "; + $q = "SELECT Packages.*, MaintainerUID, SubmittedTS, ModifiedTS "; $q.= "FROM Packages LEFT JOIN PackageBases ON "; $q.= "PackageBases.ID = Packages.PackageBaseID "; - $q.= "ORDER BY SubmittedTS DESC "; + $q.= "ORDER BY " . $orderBy . " DESC "; $q.= "LIMIT " . intval($numpkgs); $result = $dbh->query($q); @@ -944,3 +944,14 @@ function latest_pkgs($numpkgs) { return $packages; } + +/** + * Determine package information for latest modified packages + * + * @param int $numpkgs Number of packages to get information on + * + * @return array $packages Package info for the specified number of recently modified packages + */ +function latest_modified_pkgs($numpkgs) { + return latest_pkgs($numpkgs, 'ModifiedTS'); +} diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php index 7d9750a0..73c667d2 100644 --- a/web/lib/routing.inc.php +++ b/web/lib/routing.inc.php @@ -15,6 +15,7 @@ $ROUTES = array( '/logout' => 'logout.php', '/passreset' => 'passreset.php', '/rpc' => 'rpc.php', + '/rss/modified' => 'modified-rss.php', '/rss' => 'rss.php', '/tos' => 'tos.php', '/tu' => 'tu.php', From 537349e124c158a6537b4026ed3a1394a75a7206 Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Fri, 20 Nov 2020 00:20:26 +0100 Subject: [PATCH 0709/1891] Add modified packages RSS feed to frontend --- web/html/css/archweb.css | 4 ++++ web/template/header.php | 1 + web/template/stats/updates_table.php | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/web/html/css/archweb.css b/web/html/css/archweb.css index f95e3843..b935d7db 100644 --- a/web/html/css/archweb.css +++ b/web/html/css/archweb.css @@ -556,6 +556,10 @@ h3 span.arrow { margin: -2em 0 0 0; } + #pkg-updates .rss-icon.latest { + margin-right: 1em; + } + #pkg-updates table { margin: 0; } diff --git a/web/template/header.php b/web/template/header.php index f7409400..afe7a9b6 100644 --- a/web/template/header.php +++ b/web/template/header.php @@ -9,6 +9,7 @@ ' /> + ' /> diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index b4c6215f..23a86288 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -1,6 +1,7 @@

    ()

    -RSS Feed +RSS Feed +RSS Feed From e7db894eb716132411bd88c094bc8df8b5f378de Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Fri, 20 Nov 2020 00:19:15 +0100 Subject: [PATCH 0710/1891] RSS: Add ability to specify isPermaLink="false" for GUID --- web/lib/feedcreator.class.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/lib/feedcreator.class.php b/web/lib/feedcreator.class.php index a1fe24c9..bfc29b20 100644 --- a/web/lib/feedcreator.class.php +++ b/web/lib/feedcreator.class.php @@ -183,7 +183,7 @@ class FeedItem extends HtmlDescribable { /** * Optional attributes of an item. */ - var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator; + var $author, $authorEmail, $image, $category, $comments, $guid, $guidIsPermaLink, $source, $creator; /** * Publishing date of an item. May be in one of the following formats: @@ -995,7 +995,11 @@ class RSSCreator091 extends FeedCreator { $feed.= " ".htmlspecialchars($itemDate->rfc822())."\n"; } if ($this->items[$i]->guid!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; + $feed.= " items[$i]->guidIsPermaLink == false) { + $feed.= " isPermaLink=\"false\""; + } + $feed.= ">".htmlspecialchars($this->items[$i]->guid)."\n"; } $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); $feed.= " \n"; From 4330fe4f335a2c1b3b68743337576501dc1f6c92 Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Fri, 20 Nov 2020 00:19:54 +0100 Subject: [PATCH 0711/1891] Add RSS feed for modified packages --- web/html/modified-rss.php | 62 +++++++++++++++++++++++++++++++++++++++ web/lib/pkgfuncs.inc.php | 17 +++++++++-- web/lib/routing.inc.php | 1 + 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 web/html/modified-rss.php diff --git a/web/html/modified-rss.php b/web/html/modified-rss.php new file mode 100644 index 00000000..4c5c47e0 --- /dev/null +++ b/web/html/modified-rss.php @@ -0,0 +1,62 @@ +cssStyleSheet = false; +$rss->xslStyleSheet = false; + +# Use UTF-8 (fixes FS#10706). +$rss->encoding = "UTF-8"; + +#All the general RSS setup +$rss->title = "AUR Latest Modified Packages"; +$rss->description = "The latest modified packages in the AUR"; +$rss->link = "${protocol}://{$host}"; +$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); +$image = new FeedImage(); +$image->title = "AUR Latest Modified Packages"; +$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; +$image->link = $rss->link; +$image->description = "AUR Latest Modified Packages Feed"; +$rss->image = $image; + +#Get the latest packages and add items for them +$packages = latest_modified_pkgs(100); + +foreach ($packages as $indx => $row) { + $item = new FeedItem(); + $item->title = $row["Name"]; + $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); + $item->description = $row["Description"]; + $item->date = intval($row["ModifiedTS"]); + $item->source = "{$protocol}://{$host}"; + $item->author = username_from_id($row["MaintainerUID"]); + $item->guidIsPermaLink = true; + $item->guid = $row["Name"] . "-" . $row["ModifiedTS"]; + $rss->addItem($item); +} + +#save it so that useCached() can find it +$feedContent = $rss->createFeed(); +set_cache_value($feed_key, $feedContent, 600); +echo $feedContent; +?> diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index eb3afab6..140c7ec1 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -925,13 +925,13 @@ function sanitize_ids($ids) { * * @return array $packages Package info for the specified number of recent packages */ -function latest_pkgs($numpkgs) { +function latest_pkgs($numpkgs, $orderBy='SubmittedTS') { $dbh = DB::connect(); - $q = "SELECT Packages.*, MaintainerUID, SubmittedTS "; + $q = "SELECT Packages.*, MaintainerUID, SubmittedTS, ModifiedTS "; $q.= "FROM Packages LEFT JOIN PackageBases ON "; $q.= "PackageBases.ID = Packages.PackageBaseID "; - $q.= "ORDER BY SubmittedTS DESC "; + $q.= "ORDER BY " . $orderBy . " DESC "; $q.= "LIMIT " . intval($numpkgs); $result = $dbh->query($q); @@ -944,3 +944,14 @@ function latest_pkgs($numpkgs) { return $packages; } + +/** + * Determine package information for latest modified packages + * + * @param int $numpkgs Number of packages to get information on + * + * @return array $packages Package info for the specified number of recently modified packages + */ +function latest_modified_pkgs($numpkgs) { + return latest_pkgs($numpkgs, 'ModifiedTS'); +} diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php index 7d9750a0..73c667d2 100644 --- a/web/lib/routing.inc.php +++ b/web/lib/routing.inc.php @@ -15,6 +15,7 @@ $ROUTES = array( '/logout' => 'logout.php', '/passreset' => 'passreset.php', '/rpc' => 'rpc.php', + '/rss/modified' => 'modified-rss.php', '/rss' => 'rss.php', '/tos' => 'tos.php', '/tu' => 'tu.php', From 8d9f20939c864800a45fc6f8994ad9af8e8fe837 Mon Sep 17 00:00:00 2001 From: Justin Kromlinger Date: Fri, 20 Nov 2020 00:20:26 +0100 Subject: [PATCH 0712/1891] Add modified packages RSS feed to frontend --- web/html/css/archweb.css | 4 ++++ web/template/header.php | 1 + web/template/stats/updates_table.php | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/web/html/css/archweb.css b/web/html/css/archweb.css index f95e3843..b935d7db 100644 --- a/web/html/css/archweb.css +++ b/web/html/css/archweb.css @@ -556,6 +556,10 @@ h3 span.arrow { margin: -2em 0 0 0; } + #pkg-updates .rss-icon.latest { + margin-right: 1em; + } + #pkg-updates table { margin: 0; } diff --git a/web/template/header.php b/web/template/header.php index f7409400..afe7a9b6 100644 --- a/web/template/header.php +++ b/web/template/header.php @@ -9,6 +9,7 @@ ' /> + ' /> diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php index b4c6215f..23a86288 100644 --- a/web/template/stats/updates_table.php +++ b/web/template/stats/updates_table.php @@ -1,6 +1,7 @@

    ()

    -RSS Feed +RSS Feed +RSS Feed
    From bd8f5280112b2cf1cf6113453977629be2ee92c5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 13 Jun 2021 10:48:31 -0700 Subject: [PATCH 0713/1891] add Base.as_dict() and Base.json() Two utility functions for all of our ORM models that will allow us to easily convert them to Python structures and JSON data. Signed-off-by: Kevin Morris --- aurweb/models/declarative.py | 30 ++++++++++++++++++++++++++++++ aurweb/util.py | 8 ++++++++ test/test_user.py | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/aurweb/models/declarative.py b/aurweb/models/declarative.py index 45a629ce..96ee1829 100644 --- a/aurweb/models/declarative.py +++ b/aurweb/models/declarative.py @@ -1,10 +1,40 @@ +import json + from sqlalchemy.ext.declarative import declarative_base import aurweb.db +from aurweb import util + + +def to_dict(model): + return { + c.name: getattr(model, c.name) + for c in model.__table__.columns + } + + +def to_json(model, indent: int = None): + return json.dumps({ + k: util.jsonify(v) + for k, v in to_dict(model).items() + }, indent=indent) + + Base = declarative_base() + +# Setup __table_args__ applicable to every table. Base.__table_args__ = { "autoload": True, "autoload_with": aurweb.db.get_engine(), "extend_existing": True } + + +# Setup Base.as_dict and Base.json. +# +# With this, declarative models can use .as_dict() or .json() +# at any time to produce a dict and json out of table columns. +# +Base.as_dict = to_dict +Base.json = to_json diff --git a/aurweb/util.py b/aurweb/util.py index 8e4b291d..ad8ac6b7 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -3,6 +3,7 @@ import random import re import string +from datetime import datetime from urllib.parse import urlparse from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email @@ -94,3 +95,10 @@ def account_url(context, user): if request.url.scheme == "http" and request.url.port != 80: base += f":{request.url.port}" return f"{base}/account/{user.Username}" + + +def jsonify(obj): + """ Perform a conversion on obj if it's needed. """ + if isinstance(obj, datetime): + obj = int(obj.timestamp()) + return obj diff --git a/test/test_user.py b/test/test_user.py index 8b4da61e..06585207 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -1,4 +1,5 @@ import hashlib +import json from datetime import datetime, timedelta @@ -198,3 +199,21 @@ def test_user_credential_types(): assert aurweb.auth.trusted_user(user) assert aurweb.auth.developer(user) assert aurweb.auth.trusted_user_or_dev(user) + + +def test_user_json(): + data = json.loads(user.json()) + assert data.get("ID") == user.ID + assert data.get("Username") == user.Username + assert data.get("Email") == user.Email + # .json() converts datetime values to integer timestamps. + assert isinstance(data.get("RegistrationTS"), int) + + +def test_user_as_dict(): + data = user.as_dict() + assert data.get("ID") == user.ID + assert data.get("Username") == user.Username + assert data.get("Email") == user.Email + # .as_dict() does not convert values to json-capable types. + assert isinstance(data.get("RegistrationTS"), datetime) From 40448ccd34d32bcb4c1f5357e6196dc8f5c17dc6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 13 Jun 2021 12:16:13 -0700 Subject: [PATCH 0714/1891] aurweb.db: add commit(), add() and autocommit arg With the addition of these two, some code has been swapped to use these in some of the other db wrappers with an additional autocommit kwarg in create and delete, to control batch transactions. Signed-off-by: Kevin Morris --- aurweb/db.py | 21 ++++++++++++++++----- test/test_db.py | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/aurweb/db.py b/aurweb/db.py index 04c8653a..c0147720 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -59,24 +59,35 @@ def query(model, *args, **kwargs): return session.query(model).filter(*args, **kwargs) -def create(model, *args, **kwargs): +def create(model, autocommit: bool = True, *args, **kwargs): instance = model(*args, **kwargs) - session.add(instance) - session.commit() + add(instance) + if autocommit is True: + commit() return instance -def delete(model, *args, **kwargs): +def delete(model, *args, autocommit: bool = True, **kwargs): instance = session.query(model).filter(*args, **kwargs) for record in instance: session.delete(record) - session.commit() + if autocommit is True: + commit() def rollback(): session.rollback() +def add(model): + session.add(model) + return model + + +def commit(): + session.commit() + + def get_sqlalchemy_url(): """ Build an SQLAlchemy for use with create_engine based on the aurweb configuration. diff --git a/test/test_db.py b/test/test_db.py index 9298c53d..d7a91813 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -273,6 +273,31 @@ def test_create_delete(): record = db.query(AccountType, AccountType.AccountType == "test").first() assert record is None + # Create and delete a record with autocommit=False. + db.create(AccountType, AccountType="test", autocommit=False) + db.commit() + db.delete(AccountType, AccountType.AccountType == "test", autocommit=False) + db.commit() + record = db.query(AccountType, AccountType.AccountType == "test").first() + assert record is None + + +def test_add_commit(): + # Use db.add and db.commit to add a temporary record. + account_type = AccountType(AccountType="test") + db.add(account_type) + db.commit() + + # Assert it got created in the DB. + assert bool(account_type.ID) + + # Query the DB for it and compare the record with our object. + record = db.query(AccountType, AccountType.AccountType == "test").first() + assert record == account_type + + # Remove the record. + db.delete(AccountType, AccountType.ID == account_type.ID) + def test_connection_executor_mysql_paramstyle(): executor = db.ConnectionExecutor(None, backend="mysql") From 7ae95ac90813dc3f521d810ccb95adfc74a64496 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 04:39:58 -0700 Subject: [PATCH 0715/1891] bugfix: removed extra space in " My Account" nav link Signed-off-by: Kevin Morris --- templates/partials/archdev-navbar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index 4d54f6af..c935fd41 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -9,7 +9,7 @@ {% if request.user.is_authenticated() %}
  • - {% trans %} My Account{% endtrans %} + {% trans %}My Account{% endtrans %}
  • From b7d67bf5fcf02d172fce1a290c500f9fb432c49f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 05:06:24 -0700 Subject: [PATCH 0716/1891] render_template: convert HTTPStatus objects This will automate a lot of conversion that happens around the codebase in terms of status_code. As of this commit, we should improve usage and remove int(status_code) casts wherever we can. Signed-off-by: Kevin Morris --- aurweb/templates.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/templates.py b/aurweb/templates.py index c0472b2e..7474da1c 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -65,7 +65,7 @@ async def make_variable_context(request: Request, title: str, next: str = None): def render_template(request: Request, path: str, context: dict, - status_code=int(HTTPStatus.OK)): + status_code: HTTPStatus = HTTPStatus.OK): """ Render a Jinja2 multi-lingual template with some context. """ # Create a deep copy of our jinja2 environment. The environment in @@ -81,7 +81,7 @@ def render_template(request: Request, template = templates.get_template(path) rendered = template.render(context) - response = HTMLResponse(rendered, status_code=status_code) + response = HTMLResponse(rendered, status_code=int(status_code)) response.set_cookie("AURLANG", context.get("language")) response.set_cookie("AURTZ", context.get("timezone")) return response From f89d06d092aa0f20a7b267b6cb274ae175c294df Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 05:20:23 -0700 Subject: [PATCH 0717/1891] setup_test_db: remove mysql-dependent coverage path Signed-off-by: Kevin Morris --- aurweb/testing/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py index 90d46720..65d34253 100644 --- a/aurweb/testing/__init__.py +++ b/aurweb/testing/__init__.py @@ -50,7 +50,7 @@ def setup_test_db(*args): db_backend = aurweb.config.get("database", "backend") - if db_backend != "sqlite": + if db_backend != "sqlite": # pragma: no cover aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 0") else: # We're using sqlite, setup tables to be deleted without violating @@ -61,7 +61,7 @@ def setup_test_db(*args): for table in tables: aurweb.db.session.execute(f"DELETE FROM {table}") - if db_backend != "sqlite": + if db_backend != "sqlite": # pragma: no cover aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 1") # Expunge all objects from SQLAlchemy's IdentityMap. From ac67268a28f02dcdc2fb765c6bd6d76555e0056a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 16:49:41 -0700 Subject: [PATCH 0718/1891] add util.timezone_to_datetime -> `dt` Jinja2 filter Signed-off-by: Kevin Morris --- aurweb/templates.py | 3 +++ aurweb/util.py | 4 ++++ test/test_util.py | 9 +++++++++ 3 files changed, 16 insertions(+) create mode 100644 test/test_util.py diff --git a/aurweb/templates.py b/aurweb/templates.py index 7474da1c..8c6f3294 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -23,6 +23,9 @@ env = jinja2.Environment(loader=loader, autoescape=True, # Add tr translation filter. env.filters["tr"] = l10n.tr +# Utility filters. +env.filters["dt"] = util.timestamp_to_datetime + # Add captcha filters. env.filters["captcha_salt"] = captcha.captcha_salt_filter env.filters["captcha_cmdline"] = captcha.captcha_cmdline_filter diff --git a/aurweb/util.py b/aurweb/util.py index ad8ac6b7..ce18853b 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -97,6 +97,10 @@ def account_url(context, user): return f"{base}/account/{user.Username}" +def timestamp_to_datetime(timestamp: int): + return datetime.utcfromtimestamp(int(timestamp)) + + def jsonify(obj): """ Perform a conversion on obj if it's needed. """ if isinstance(obj, datetime): diff --git a/test/test_util.py b/test/test_util.py new file mode 100644 index 00000000..cd7b7a57 --- /dev/null +++ b/test/test_util.py @@ -0,0 +1,9 @@ +from datetime import datetime + +from aurweb import util + + +def test_timestamp_to_datetime(): + ts = datetime.utcnow().timestamp() + dt = datetime.utcfromtimestamp(int(ts)) + assert util.timestamp_to_datetime(ts) == dt From b1baf769985949bfa496c9d8276dbcd2e101072b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 16:55:01 -0700 Subject: [PATCH 0719/1891] add util.as_timezone -> `as_timezone` Jinja2 filter Signed-off-by: Kevin Morris --- aurweb/templates.py | 1 + aurweb/util.py | 5 +++++ test/test_util.py | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/aurweb/templates.py b/aurweb/templates.py index 8c6f3294..9439f3a3 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -25,6 +25,7 @@ env.filters["tr"] = l10n.tr # Utility filters. env.filters["dt"] = util.timestamp_to_datetime +env.filters["as_timezone"] = util.as_timezone # Add captcha filters. env.filters["captcha_salt"] = captcha.captcha_salt_filter diff --git a/aurweb/util.py b/aurweb/util.py index ce18853b..1615e00a 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -5,6 +5,7 @@ import string from datetime import datetime from urllib.parse import urlparse +from zoneinfo import ZoneInfo from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email from jinja2 import pass_context @@ -101,6 +102,10 @@ def timestamp_to_datetime(timestamp: int): return datetime.utcfromtimestamp(int(timestamp)) +def as_timezone(dt: datetime, timezone: str): + return dt.astimezone(tz=ZoneInfo(timezone)) + + def jsonify(obj): """ Perform a conversion on obj if it's needed. """ if isinstance(obj, datetime): diff --git a/test/test_util.py b/test/test_util.py index cd7b7a57..d58a8ae2 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -1,4 +1,5 @@ from datetime import datetime +from zoneinfo import ZoneInfo from aurweb import util @@ -7,3 +8,9 @@ def test_timestamp_to_datetime(): ts = datetime.utcnow().timestamp() dt = datetime.utcfromtimestamp(int(ts)) assert util.timestamp_to_datetime(ts) == dt + + +def test_as_timezone(): + ts = datetime.utcnow().timestamp() + dt = util.timestamp_to_datetime(ts) + assert util.as_timezone(dt, "UTC") == dt.astimezone(tz=ZoneInfo("UTC")) From d5e650a33930286bae0263e8b0aff12ed94a319e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 16:57:06 -0700 Subject: [PATCH 0720/1891] add util.dedupe_qs -> `dedupe_qs` Jinja2 filter Signed-off-by: Kevin Morris --- aurweb/templates.py | 1 + aurweb/util.py | 26 +++++++++++++++++++++++++- test/test_util.py | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/aurweb/templates.py b/aurweb/templates.py index 9439f3a3..1e09bf61 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -26,6 +26,7 @@ env.filters["tr"] = l10n.tr # Utility filters. env.filters["dt"] = util.timestamp_to_datetime env.filters["as_timezone"] = util.as_timezone +env.filters["dedupe_qs"] = util.dedupe_qs # Add captcha filters. env.filters["captcha_salt"] = captcha.captcha_salt_filter diff --git a/aurweb/util.py b/aurweb/util.py index 1615e00a..0aec6f45 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -3,8 +3,9 @@ import random import re import string +from collections import OrderedDict from datetime import datetime -from urllib.parse import urlparse +from urllib.parse import quote_plus, urlparse from zoneinfo import ZoneInfo from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email @@ -106,6 +107,29 @@ def as_timezone(dt: datetime, timezone: str): return dt.astimezone(tz=ZoneInfo(timezone)) +def dedupe_qs(query_string: str, *additions): + """ Dedupe keys found in a query string by rewriting it without + duplicates found while iterating from the end to the beginning, + using an ordered memo to track keys found and persist locations. + + That is, query string 'a=1&b=1&a=2' will be deduped and converted + to 'b=1&a=2'. + + :param query_string: An HTTP URL query string. + :param *additions: Optional additional fields to add to the query string. + :return: Deduped query string, including *additions at the tail. + """ + for addition in list(additions): + query_string += f"&{addition}" + + qs = OrderedDict() + for item in reversed(query_string.split('&')): + key, value = item.split('=') + if key not in qs: + qs[key] = value + return '&'.join([f"{k}={quote_plus(v)}" for k, v in reversed(qs.items())]) + + def jsonify(obj): """ Perform a conversion on obj if it's needed. """ if isinstance(obj, datetime): diff --git a/test/test_util.py b/test/test_util.py index d58a8ae2..074de494 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -1,3 +1,4 @@ +from collections import OrderedDict from datetime import datetime from zoneinfo import ZoneInfo @@ -14,3 +15,18 @@ def test_as_timezone(): ts = datetime.utcnow().timestamp() dt = util.timestamp_to_datetime(ts) assert util.as_timezone(dt, "UTC") == dt.astimezone(tz=ZoneInfo("UTC")) + + +def test_dedupe_qs(): + items = OrderedDict() + items["key1"] = "test" + items["key2"] = "blah" + items["key3"] = 1 + + # Construct and test our query string. + query_string = '&'.join([f"{k}={v}" for k, v in items.items()]) + assert query_string == "key1=test&key2=blah&key3=1" + + # Add key1=changed and key2=changed to the query and dedupe it. + deduped = util.dedupe_qs(query_string, "key1=changed", "key3=changed") + assert deduped == "key2=blah&key1=changed&key3=changed" From d7941e6bedfed32df0299a5869df40f33b202374 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 16:57:44 -0700 Subject: [PATCH 0721/1891] urllib.parse.quote_plus -> `urlencode` Jinja2 filter Signed-off-by: Kevin Morris --- aurweb/templates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/templates.py b/aurweb/templates.py index 1e09bf61..015f8c9f 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -4,6 +4,7 @@ import zoneinfo from datetime import datetime from http import HTTPStatus +from urllib.parse import quote_plus import jinja2 @@ -27,6 +28,7 @@ env.filters["tr"] = l10n.tr env.filters["dt"] = util.timestamp_to_datetime env.filters["as_timezone"] = util.as_timezone env.filters["dedupe_qs"] = util.dedupe_qs +env.filters["urlencode"] = quote_plus # Add captcha filters. env.filters["captcha_salt"] = captcha.captcha_salt_filter From 8b6f92f9e907267288c9a2d757c7747b22c7bca8 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Tue, 11 May 2021 00:01:13 +0200 Subject: [PATCH 0722/1891] Use the clipboard API for copy paste The Document.execCommand API is deprecated and no longer recommended to be used. It's replacement is the much simpler navigator.clipboard API which is supported in all browsers except internet explorer. Signed-off-by: Eli Schwartz --- web/template/pkg_details.php | 10 +++------- web/template/pkgbase_details.php | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index c6bb32d8..047de9a7 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -308,14 +308,10 @@ endif; diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index a6857c4e..35ad217a 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -137,14 +137,10 @@ endif; From d7603fa4d3d31e8c50b2988730652809ae1f42b7 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 10 May 2021 23:55:36 +0200 Subject: [PATCH 0723/1891] Port package details page to pure JavaScript Use a CSS animation for jQuery.Animate and replace the rest with pure vanilla JavaScript. Signed-off-by: Eli Schwartz --- web/html/css/aurweb.css | 5 +++ web/html/packages.php | 96 +++++++++++++++++++++++++---------------- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 81bf9ab6..bb4e3ad7 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -199,3 +199,8 @@ label.confirmation, .error { color: red; } + +.article-content > div { + overflow: hidden; + transition: height 1s; +} diff --git a/web/html/packages.php b/web/html/packages.php index a989428e..559a8f45 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -46,70 +46,94 @@ if (isset($pkgname)) { html_header($title, $details); ?> - From 06fa8ab5f32061ae1d06abbe1cc502883f3884da Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 14 Jun 2021 22:13:07 +0200 Subject: [PATCH 0724/1891] Convert comment editing to vanilla JavaScript Signed-off-by: Eli Schwartz --- web/template/pkg_comments.php | 90 ++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 3bcf1a38..ffa9e137 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -169,37 +169,71 @@ if ($comment_section == "package") { From af76e660d0f03712901d2d1ddda07d383fafcb08 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 21 Jun 2021 21:35:05 -0700 Subject: [PATCH 0725/1891] auth_required: allow formattable template tuples See docstring for updates. template= has been modified. status_code= has been added as an optional template status_code. Signed-off-by: Kevin Morris --- aurweb/auth.py | 67 +++++++++++++++++++++++++++++++----- aurweb/routers/accounts.py | 16 ++++++--- test/test_accounts_routes.py | 1 - 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 401ed6ae..f57e18bf 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -10,9 +10,10 @@ from starlette.requests import HTTPConnection import aurweb.config +from aurweb import l10n from aurweb.models.session import Session from aurweb.models.user import User -from aurweb.templates import make_context, render_template +from aurweb.templates import make_variable_context, render_template class AnonymousUser: @@ -60,7 +61,8 @@ class BasicAuthBackend(AuthenticationBackend): def auth_required(is_required: bool = True, redirect: str = "/", - template: tuple = None): + template: tuple = None, + status_code: HTTPStatus = HTTPStatus.UNAUTHORIZED): """ Authentication route decorator. If redirect is given, the user will be redirected if the auth state @@ -69,26 +71,73 @@ def auth_required(is_required: bool = True, If template is given, it will be rendered with Unauthorized if is_required does not match and take priority over redirect. + A precondition of this function is that, if template is provided, + it **must** match the following format: + + template=("template.html", ["Some Template For", "{}"], ["username"]) + + Where `username` is a FastAPI request path parameter, fitting + a route like: `/some_route/{username}`. + + If you wish to supply a non-formatted template, just omit any Python + format strings (with the '{}' substring). The third tuple element + will not be used, and so anything can be supplied. + + template=("template.html", ["Some Page"], None) + + All title shards and format parameters will be translated before + applying any format operations. + :param is_required: A boolean indicating whether the function requires auth :param redirect: Path to redirect to if is_required isn't True - :param template: A template tuple: ("template.html", "Template Page") + :param template: A three-element template tuple: + (path, title_iterable, variable_iterable) + :param status_code: An optional status_code for template render. + Redirects are always SEE_OTHER. """ def decorator(func): @functools.wraps(func) async def wrapper(request, *args, **kwargs): if request.user.is_authenticated() != is_required: - status_code = int(HTTPStatus.UNAUTHORIZED) url = "/" if redirect: - status_code = int(HTTPStatus.SEE_OTHER) url = redirect if template: - path, title = template - context = make_context(request, title) + # template=("template.html", + # ["Some Title", "someFormatted {}"], + # ["variable"]) + # => render template.html with title: + # "Some Title someFormatted variables" + path, title_parts, variables = template + _ = l10n.get_translator_for_request(request) + + # Step through title_parts; for each part which contains + # a '{}' in it, apply .format(var) where var = the current + # iteration of variables. + # + # This implies that len(variables) is equal to + # len([part for part in title_parts if '{}' in part]) + # and this must always be true. + # + sanitized = [] + _variables = iter(variables) + for part in title_parts: + if "{}" in part: # If this part is formattable. + key = next(_variables) + var = request.path_params.get(key) + sanitized.append(_(part.format(var))) + else: # Otherwise, just add the translated part. + sanitized.append(_(part)) + + # Glue all title parts together, separated by spaces. + title = " ".join(sanitized) + + context = await make_variable_context(request, title) return render_template(request, path, context, - status_code=int(HTTPStatus.UNAUTHORIZED)) - return RedirectResponse(url=url, status_code=status_code) + status_code=status_code) + return RedirectResponse(url, + status_code=int(HTTPStatus.SEE_OTHER)) return await func(request, *args, **kwargs) return wrapper diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index c7c96003..966f8409 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -555,13 +555,21 @@ async def account_edit_post(request: Request, return util.migrate_cookies(request, response) +account_template = ( + "account/show.html", + ["Account", "{}"], + ["username"] # Query parameters to replace in the title string. +) + + @router.get("/account/{username}") -@auth_required(True, template=("account/show.html", "Accounts")) +@auth_required(True, template=account_template, + status_code=HTTPStatus.UNAUTHORIZED) async def account(request: Request, username: str): + _ = l10n.get_translator_for_request(request) + context = await make_variable_context(request, _("Account") + username) + user = db.query(User, User.Username == username).first() - - context = await make_variable_context(request, "Accounts") - if not user: raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index d5fd089e..bd0d9d4b 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -915,7 +915,6 @@ def test_get_account_not_found(): def test_get_account_unauthenticated(): with client as request: response = request.get("/account/test", allow_redirects=False) - assert response.status_code == int(HTTPStatus.UNAUTHORIZED) content = response.content.decode() From 959e535126bdb6863f62ccf1e4a32482793b1386 Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Wed, 23 Jun 2021 03:09:37 +0200 Subject: [PATCH 0726/1891] Use the real ml email address instead of alias All the arch-x@archlinux.org -> arch-x@lists.archlinux.org aliases will be dropped soon[1]. [1] https://lists.archlinux.org/pipermail/arch-dev-public/2021-June/030462.html --- conf/config.defaults | 2 +- test/setup.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/config.defaults b/conf/config.defaults index e6961520..b7bc0368 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -22,7 +22,7 @@ git_clone_uri_anon = https://aur.archlinux.org/%s.git git_clone_uri_priv = ssh://aur@aur.archlinux.org/%s.git max_rpc_results = 5000 max_depends = 1000 -aur_request_ml = aur-requests@archlinux.org +aur_request_ml = aur-requests@lists.archlinux.org request_idle_time = 1209600 request_archive_time = 15552000 auto_orphan_age = 15552000 diff --git a/test/setup.sh b/test/setup.sh index 4a6eb3b1..589c8c3f 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -26,7 +26,7 @@ name = aur.db [options] aur_location = https://aur.archlinux.org -aur_request_ml = aur-requests@archlinux.org +aur_request_ml = aur-requests@lists.archlinux.org enable-maintenance = 0 maintenance-exceptions = 127.0.0.1 commit_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s&id=%s From ec632a7091df6df3940f62cfee3d9a09641dd4b5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 11 Jun 2021 23:09:34 -0700 Subject: [PATCH 0727/1891] use secure=True when options.disable_http_login is enabled We'll piggyback off of the current existing configuration item, `disable_http_login`, to decide how we should submit cookies to an HTTP response. Previously, in `sso.py`, the http schema was used to make this decision. There is an issue with that, however: We cannot actually test properly if we depend on the https schema. This change allows us to toggle `disable_http_login` to modify the behavior of cookies sent with an http response to be secure. We test this behavior in test/test_auth_routes.py#L81: `test_secure_login(mock)`. Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 5 +++- aurweb/routers/html.py | 6 ++++- aurweb/routers/sso.py | 8 ++++--- aurweb/templates.py | 9 +++++--- aurweb/util.py | 3 ++- test/test_auth_routes.py | 50 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 9 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index e4864424..4aca9304 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -59,7 +59,10 @@ async def login_post(request: Request, response = RedirectResponse(url=next, status_code=int(HTTPStatus.SEE_OTHER)) - response.set_cookie("AURSID", sid, expires=expires_at) + + secure_cookies = aurweb.config.getboolean("options", "disable_http_login") + response.set_cookie("AURSID", sid, expires=expires_at, + secure=secure_cookies, httponly=True) return response diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 890aff88..ed0c039b 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -6,6 +6,8 @@ from http import HTTPStatus from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse +import aurweb.config + from aurweb.templates import make_context, render_template router = APIRouter() @@ -45,7 +47,9 @@ async def language(request: Request, # In any case, set the response's AURLANG cookie that never expires. response = RedirectResponse(url=f"{next}{query_string}", status_code=int(HTTPStatus.SEE_OTHER)) - response.set_cookie("AURLANG", set_lang) + secure_cookies = aurweb.config.getboolean("options", "disable_http_login") + response.set_cookie("AURLANG", set_lang, + secure=secure_cookies, httponly=True) return response diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 4b12b932..093807fe 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -131,13 +131,15 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw elif len(aur_accounts) == 1: sid = open_session(request, conn, aur_accounts[0][Users.c.ID]) response = RedirectResponse(redirect if redirect and is_aur_url(redirect) else "/") + secure_cookies = aurweb.config.getboolean("options", "disable_http_login") response.set_cookie(key="AURSID", value=sid, httponly=True, - secure=request.url.scheme == "https") + secure=secure_cookies) if "id_token" in token: # We save the id_token for the SSO logout. It’s not too important # though, so if we can’t find it, we can live without it. - response.set_cookie(key="SSO_ID_TOKEN", value=token["id_token"], path="/sso/", - httponly=True, secure=request.url.scheme == "https") + response.set_cookie(key="SSO_ID_TOKEN", value=token["id_token"], + path="/sso/", httponly=True, + secure=secure_cookies) return response else: # We’ve got a severe integrity violation. diff --git a/aurweb/templates.py b/aurweb/templates.py index 015f8c9f..640b9447 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -88,7 +88,10 @@ def render_template(request: Request, template = templates.get_template(path) rendered = template.render(context) - response = HTMLResponse(rendered, status_code=int(status_code)) - response.set_cookie("AURLANG", context.get("language")) - response.set_cookie("AURTZ", context.get("timezone")) + response = HTMLResponse(rendered, status_code=status_code) + secure_cookies = aurweb.config.getboolean("options", "disable_http_login") + response.set_cookie("AURLANG", context.get("language"), + secure=secure_cookies, httponly=True) + response.set_cookie("AURTZ", context.get("timezone"), + secure=secure_cookies, httponly=True) return response diff --git a/aurweb/util.py b/aurweb/util.py index 0aec6f45..1da85606 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -85,8 +85,9 @@ def valid_ssh_pubkey(pk): def migrate_cookies(request, response): + secure_cookies = aurweb.config.getboolean("options", "disable_http_login") for k, v in request.cookies.items(): - response.set_cookie(k, v) + response.set_cookie(k, v, secure=secure_cookies, httponly=True) return response diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 360b48cc..a443be72 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -1,5 +1,6 @@ from datetime import datetime from http import HTTPStatus +from unittest import mock import pytest @@ -70,6 +71,55 @@ def test_login_logout(): assert "AURSID" not in response.cookies +def mock_getboolean(a, b): + if a == "options" and b == "disable_http_login": + return True + return bool(aurweb.config.get(a, b)) + + +@mock.patch("aurweb.config.getboolean", side_effect=mock_getboolean) +def test_secure_login(mock): + """ In this test, we check to verify the course of action taken + by starlette when providing secure=True to a response cookie. + This is achieved by mocking aurweb.config.getboolean to return + True (or 1) when looking for `options.disable_http_login`. + When we receive a response with `disable_http_login` enabled, + we check the fields in cookies received for the secure and + httponly fields, in addition to the rest of the fields given + on such a request. """ + + # Create a local TestClient here since we mocked configuration. + client = TestClient(app) + + # Data used for our upcoming http post request. + post_data = { + "user": user.Username, + "passwd": "testPassword", + "next": "/" + } + + # Perform a login request with the data matching our user. + with client as request: + response = request.post("/login", data=post_data, + allow_redirects=False) + + # Make sure we got the expected status out of it. + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + # Let's check what we got in terms of cookies for AURSID. + # Make sure that a secure cookie got passed to us. + cookie = next(c for c in response.cookies if c.name == "AURSID") + assert cookie.secure is True + assert cookie.has_nonstandard_attr("HttpOnly") is True + assert cookie.value is not None and len(cookie.value) > 0 + + # Let's make sure we actually have a session relationship + # with the AURSID we ended up with. + record = query(Session, Session.SessionID == cookie.value).first() + assert record is not None and record.User == user + assert user.session == record + + def test_authenticated_login_forbidden(): post_data = { "user": "test", From 91dc3efc75700fd9c559a908028ff39eeb7d2bfe Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 12 Jun 2021 03:23:58 -0700 Subject: [PATCH 0728/1891] add util.add_samesite_fields(response, value) This function adds f"SameSite={value}" to each cookie's header stored in response. This is needed because starlette does not currently support the `samesite` argument in Response.set_cookie. It is merged, however, and waiting for next release. Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 3 ++- aurweb/routers/html.py | 3 ++- aurweb/routers/sso.py | 3 ++- aurweb/templates.py | 2 +- aurweb/util.py | 15 ++++++++++++++- test/test_auth_routes.py | 2 ++ 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 4aca9304..2b05784b 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -6,6 +6,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse import aurweb.config +from aurweb import util from aurweb.auth import auth_required from aurweb.models.user import User from aurweb.templates import make_context, render_template @@ -63,7 +64,7 @@ async def login_post(request: Request, secure_cookies = aurweb.config.getboolean("options", "disable_http_login") response.set_cookie("AURSID", sid, expires=expires_at, secure=secure_cookies, httponly=True) - return response + return util.add_samesite_fields(response, "strict") @router.get("/logout") diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index ed0c039b..580ee0d4 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -8,6 +8,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse import aurweb.config +from aurweb import util from aurweb.templates import make_context, render_template router = APIRouter() @@ -50,7 +51,7 @@ async def language(request: Request, secure_cookies = aurweb.config.getboolean("options", "disable_http_login") response.set_cookie("AURLANG", set_lang, secure=secure_cookies, httponly=True) - return response + return util.add_samesite_fields(response, "strict") @router.get("/", response_class=HTMLResponse) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index 093807fe..edeb7c6b 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -14,6 +14,7 @@ from starlette.requests import Request import aurweb.config import aurweb.db +from aurweb import util from aurweb.l10n import get_translator_for_request from aurweb.schema import Bans, Sessions, Users @@ -140,7 +141,7 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw response.set_cookie(key="SSO_ID_TOKEN", value=token["id_token"], path="/sso/", httponly=True, secure=secure_cookies) - return response + return util.add_samesite_fields(response, "strict") else: # We’ve got a severe integrity violation. raise Exception("Multiple accounts found for SSO account " + sub) diff --git a/aurweb/templates.py b/aurweb/templates.py index 640b9447..bb4047f4 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -94,4 +94,4 @@ def render_template(request: Request, secure=secure_cookies, httponly=True) response.set_cookie("AURTZ", context.get("timezone"), secure=secure_cookies, httponly=True) - return response + return util.add_samesite_fields(response, "strict") diff --git a/aurweb/util.py b/aurweb/util.py index 1da85606..b34226a2 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -9,6 +9,7 @@ from urllib.parse import quote_plus, urlparse from zoneinfo import ZoneInfo from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email +from fastapi.responses import Response from jinja2 import pass_context import aurweb.config @@ -88,7 +89,7 @@ def migrate_cookies(request, response): secure_cookies = aurweb.config.getboolean("options", "disable_http_login") for k, v in request.cookies.items(): response.set_cookie(k, v, secure=secure_cookies, httponly=True) - return response + return add_samesite_fields(response, "strict") @pass_context @@ -136,3 +137,15 @@ def jsonify(obj): if isinstance(obj, datetime): obj = int(obj.timestamp()) return obj + + +def add_samesite_fields(response: Response, value: str): + """ Set the SameSite field on all cookie headers found. + Taken from https://github.com/tiangolo/fastapi/issues/1099. """ + for idx, header in enumerate(response.raw_headers): + if header[0].decode() == "set-cookie": + cookie = header[1].decode() + if f"SameSite={value}" not in cookie: + cookie += f"; SameSite={value}" + response.raw_headers[idx] = (header[0], cookie.encode()) + return response diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index a443be72..b0dd5648 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -111,6 +111,8 @@ def test_secure_login(mock): cookie = next(c for c in response.cookies if c.name == "AURSID") assert cookie.secure is True assert cookie.has_nonstandard_attr("HttpOnly") is True + assert cookie.has_nonstandard_attr("SameSite") is True + assert cookie.get_nonstandard_attr("SameSite") == "strict" assert cookie.value is not None and len(cookie.value) > 0 # Let's make sure we actually have a session relationship From 13456fea1e6eab4971e4ec9f38456ccaeccda352 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 12 Jun 2021 03:26:05 -0700 Subject: [PATCH 0729/1891] set AURLANG + AURTZ on login Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 2b05784b..8f37fe27 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -64,6 +64,10 @@ async def login_post(request: Request, secure_cookies = aurweb.config.getboolean("options", "disable_http_login") response.set_cookie("AURSID", sid, expires=expires_at, secure=secure_cookies, httponly=True) + response.set_cookie("AURTZ", user.Timezone, + secure=secure_cookies, httponly=True) + response.set_cookie("AURLANG", user.LangPreference, + secure=secure_cookies, httponly=True) return util.add_samesite_fields(response, "strict") From 865c41450466c8392605f7c1aabc5607b77cb5a1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 12 Jun 2021 03:54:41 -0700 Subject: [PATCH 0730/1891] aurweb.asgi: add security headers middleware This commit introduces a middleware function which adds the following security headers to each response: - Content-Security-Policy - This includes a new `nonce`, which is tied to a user via authentication middleware. Both an anonymous user and an authenticated user recieve their own random nonces. - X-Content-Type-Options - Referrer-Policy - X-Frame-Options They are then tested for existence in test/test_routes.py. Note: The overcomplicated-looking asyncio behavior in the middleware function is used to avoid a warning about the old coroutine awaits being deprecated. See https://docs.python.org/3/library/asyncio-task.html#asyncio.wait for more detail. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 43 ++++++++++++++++++++++++++++++- aurweb/auth.py | 10 ++++++- aurweb/models/user.py | 1 + aurweb/util.py | 11 ++++++++ templates/partials/typeahead.html | 2 +- test/test_routes.py | 42 ++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 3 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 861f6056..6c4d457d 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -1,6 +1,8 @@ +import asyncio import http +import typing -from fastapi import FastAPI, HTTPException +from fastapi import FastAPI, HTTPException, Request from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from starlette.middleware.authentication import AuthenticationMiddleware @@ -55,3 +57,42 @@ async def http_exception_handler(request, exc): phrase = http.HTTPStatus(exc.status_code).phrase return HTMLResponse(f"

    {exc.status_code} {phrase}

    {exc.detail}

    ", status_code=exc.status_code) + + +@app.middleware("http") +async def add_security_headers(request: Request, call_next: typing.Callable): + """ This middleware adds the CSP, XCTO, XFO and RP security + headers to the HTTP response associated with request. + + CSP: Content-Security-Policy + XCTO: X-Content-Type-Options + RP: Referrer-Policy + XFO: X-Frame-Options + """ + response = asyncio.create_task(call_next(request)) + await asyncio.wait({response}, return_when=asyncio.FIRST_COMPLETED) + response = response.result() + + # Add CSP header. + nonce = request.user.nonce + csp = "default-src 'self'; " + script_hosts = [ + "ajax.googleapis.com", + "cdn.jsdelivr.net" + ] + csp += f"script-src 'self' 'nonce-{nonce}' " + ' '.join(script_hosts) + response.headers["Content-Security-Policy"] = csp + + # Add XTCO header. + xcto = "nosniff" + response.headers["X-Content-Type-Options"] = xcto + + # Add Referrer Policy header. + rp = "same-origin" + response.headers["Referrer-Policy"] = rp + + # Add X-Frame-Options header. + xfo = "SAMEORIGIN" + response.headers["X-Frame-Options"] = xfo + + return response diff --git a/aurweb/auth.py b/aurweb/auth.py index f57e18bf..ba5f0fea 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -10,7 +10,7 @@ from starlette.requests import HTTPConnection import aurweb.config -from aurweb import l10n +from aurweb import l10n, util from aurweb.models.session import Session from aurweb.models.user import User from aurweb.templates import make_variable_context, render_template @@ -25,6 +25,12 @@ class AnonymousUser: # A stub ssh_pub_key relationship. ssh_pub_key = None + # A nonce attribute, needed for all browser sessions; set in __init__. + nonce = None + + def __init__(self): + self.nonce = util.make_nonce() + @staticmethod def is_authenticated(): return False @@ -55,7 +61,9 @@ class BasicAuthBackend(AuthenticationBackend): # exists, due to ForeignKey constraints in the schema upheld # by mysqlclient. user = session.query(User).filter(User.ID == record.UsersID).first() + user.nonce = util.make_nonce() user.authenticated = True + return AuthCredentials(["authenticated"]), user diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 83cde5f1..9db9add0 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -37,6 +37,7 @@ class User(Base): # High-level variables used to track authentication (not in DB). authenticated = False + nonce = None def __init__(self, Passwd: str = str(), **kwargs): super().__init__(**kwargs) diff --git a/aurweb/util.py b/aurweb/util.py index b34226a2..e5f510ce 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -1,6 +1,8 @@ import base64 +import math import random import re +import secrets import string from collections import OrderedDict @@ -20,6 +22,15 @@ def make_random_string(length): string.digits, k=length)) +def make_nonce(length: int = 8): + """ Generate a single random nonce. Here, token_hex generates a hex + string of 2 hex characters per byte, where the length give is + nbytes. This means that to get our proper string length, we need to + cut it in half and truncate off any remaining (in the case that + length was uneven). """ + return secrets.token_hex(math.ceil(length / 2))[:length] + + def valid_username(username): min_len = aurweb.config.getint("options", "username_min_len") max_len = aurweb.config.getint("options", "username_max_len") diff --git a/templates/partials/typeahead.html b/templates/partials/typeahead.html index d943dbc4..c218b8d1 100644 --- a/templates/partials/typeahead.html +++ b/templates/partials/typeahead.html @@ -1,6 +1,6 @@ - - - + "+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery) \ No newline at end of file diff --git a/web/html/js/typeahead.js b/web/html/js/typeahead.js new file mode 100644 index 00000000..1b7252d7 --- /dev/null +++ b/web/html/js/typeahead.js @@ -0,0 +1,151 @@ +"use strict"; + +const typeahead = (function() { + var input; + var form; + var suggest_type; + var list; + var submit = true; + + function resetResults() { + if (!list) return; + list.style.display = "none"; + list.innerHTML = ""; + } + + function getCompleteList() { + if (!list) { + list = document.createElement("UL"); + list.setAttribute("class", "pkgsearch-typeahead"); + form.appendChild(list); + setListLocation(); + } + return list; + } + + function onListClick(e) { + let target = e.target; + while (!target.getAttribute('data-value')) { + target = target.parentNode; + } + input.value = target.getAttribute('data-value'); + if (submit) { + form.submit(); + } + } + + function setListLocation() { + if (!list) return; + const rects = input.getClientRects()[0]; + list.style.top = (rects.top + rects.height) + "px"; + list.style.left = rects.left + "px"; + } + + function loadData(letter, data) { + const pkgs = data.slice(0, 10); // Show maximum of 10 results + + resetResults(); + + if (pkgs.length === 0) { + return; + } + + const ul = getCompleteList(); + ul.style.display = "block"; + const fragment = document.createDocumentFragment(); + + for (let i = 0; i < pkgs.length; i++) { + const item = document.createElement("li"); + const text = pkgs[i].replace(letter, '' + letter + ''); + item.innerHTML = '' + text + ''; + item.setAttribute('data-value', pkgs[i]); + fragment.appendChild(item); + } + + ul.appendChild(fragment); + ul.addEventListener('click', onListClick); + } + + function fetchData(letter) { + const url = '/rpc?type=' + suggest_type + '&arg=' + letter; + fetch(url).then(function(response) { + return response.json(); + }).then(function(data) { + loadData(letter, data); + }); + } + + function onInputClick() { + if (input.value === "") { + resetResults(); + return; + } + fetchData(input.value); + } + + function onKeyDown(e) { + if (!list) return; + + const elem = document.querySelector(".pkgsearch-typeahead li.active"); + switch(e.keyCode) { + case 13: // enter + if (!submit) { + return; + } + if (elem) { + input.value = elem.getAttribute('data-value'); + form.submit(); + } else { + form.submit(); + } + e.preventDefault(); + break; + case 38: // up + if (elem && elem.previousElementSibling) { + elem.className = ""; + elem.previousElementSibling.className = "active"; + } + e.preventDefault(); + break; + case 40: // down + if (elem && elem.nextElementSibling) { + elem.className = ""; + elem.nextElementSibling.className = "active"; + } else if (!elem && list.childElementCount !== 0) { + list.children[0].className = "active"; + } + e.preventDefault(); + break; + } + } + + // debounce https://davidwalsh.name/javascript-debounce-function + function debounce(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + } + + return { + init: function(type, inputfield, formfield, submitdata = true) { + suggest_type = type; + input = inputfield; + form = formfield; + submit = submitdata; + + input.addEventListener("input", onInputClick); + input.addEventListener("keydown", onKeyDown); + window.addEventListener('resize', debounce(setListLocation, 150)); + document.addEventListener("click", resetResults); + } + } +}()); diff --git a/web/html/pkgmerge.php b/web/html/pkgmerge.php index d583c239..d96562a7 100644 --- a/web/html/pkgmerge.php +++ b/web/html/pkgmerge.php @@ -25,7 +25,7 @@ if (has_credential(CRED_PKGBASE_DELETE)): ?>

    -
    +
    @@ -33,25 +33,17 @@ if (has_credential(CRED_PKGBASE_DELETE)): ?> - - +

    -

    +

    " />

    diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php index d80a422c..9d74093e 100644 --- a/web/template/pkgreq_form.php +++ b/web/template/pkgreq_form.php @@ -9,7 +9,7 @@
  • - +
    @@ -24,44 +24,41 @@

    - - +

    - +

    From c8d88464b1f62154a58d8ee403f3eefb3168aa0f Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Fri, 25 Jun 2021 17:25:24 +0200 Subject: [PATCH 0745/1891] Update mailing list address https://lists.archlinux.org/pipermail/arch-dev-public/2021-June/030462.html --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b9ff466..9c8d747e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -Patches should be sent to the [aur-dev@archlinux.org][1] mailing list. +Patches should be sent to the [aur-dev@lists.archlinux.org][1] mailing list. Before sending patches, you are recommended to run `flake8` and `isort`. From d95e4ec4431ff4e08e409eb1a670f1b0c90035cc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Jun 2021 17:09:21 -0700 Subject: [PATCH 0746/1891] Docker: create missing 'aurweb' DB if needed Signed-off-by: Kevin Morris --- docker/scripts/run-mariadb.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docker/scripts/run-mariadb.sh b/docker/scripts/run-mariadb.sh index 7e908129..d27d8124 100755 --- a/docker/scripts/run-mariadb.sh +++ b/docker/scripts/run-mariadb.sh @@ -8,9 +8,16 @@ done # Create test database. mysql -u root -e "CREATE USER 'aur'@'%' IDENTIFIED BY 'aur'" \ 2>/dev/null || /bin/true + +# Create a brand new 'aurweb_test' DB. mysql -u root -e "DROP DATABASE aurweb_test" 2>/dev/null || /bin/true mysql -u root -e "CREATE DATABASE aurweb_test" mysql -u root -e "GRANT ALL PRIVILEGES ON aurweb_test.* TO 'aur'@'%'" + +# Create the 'aurweb' DB if it does not yet exist. +mysql -u root -e "CREATE DATABASE aurweb" 2>/dev/null || /bin/true +mysql -u root -e "GRANT ALL PRIVILEGES ON aurweb.* TO 'aur'@'%'" + mysql -u root -e "FLUSH PRIVILEGES" # Shutdown mariadb. From 201a04ffb9dddadbd7be2fc587057017426ace2e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Jun 2021 16:17:38 -0700 Subject: [PATCH 0747/1891] gendummydata: employ a salted hash for users As of Python updates, we are no longer considering rows with empty salts to be legacy hashes. Update gendummydata.py to generate salts for the legacy passwords it uses with salt rounds = 4. Signed-off-by: Kevin Morris --- schema/gendummydata.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 35805d6c..11f2838a 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -16,6 +16,8 @@ import random import sys import time +import bcrypt + LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output SEED_FILE = "/usr/share/dict/words" USER_ID = 5 # Users.ID of first bogus user @@ -182,11 +184,17 @@ for u in user_keys: # pass + # For dummy data, we just use 4 salt rounds. + salt = bcrypt.gensalt(rounds=4).decode() + + # "{salt}{username}" + to_hash = f"{salt}{u}" + h = hashlib.new('md5') - h.update(u.encode()) - s = ("INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd)" - " VALUES (%d, %d, '%s', '%s@example.com', '%s');\n") - s = s % (seen_users[u], account_type, u, u, h.hexdigest()) + h.update(to_hash.encode()) + s = ("INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd, Salt)" + " VALUES (%d, %d, '%s', '%s@example.com', '%s', '%s');\n") + s = s % (seen_users[u], account_type, u, u, h.hexdigest(), salt) out.write(s) log.debug("Number of developers: %d" % len(developers)) From eb56305091f13c44716e45746d23fe850c22803c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Jun 2021 17:27:43 -0700 Subject: [PATCH 0748/1891] gendummydata: lower record counts This commit halves MAX_USERS and MAX_PKGS, in addition to setting OPEN_PROPOSALS to 15 and CLOSE_PROPOSALS to 50. A few counts are now configurable via environment variable: - MAX_USERS, default: 38000 - MAX_PKGS, default: 32000 - OPEN_PROPOSALS, default: 15 - CLOSE_PROPOSALS, default: 15 Signed-off-by: Kevin Morris --- schema/gendummydata.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 11f2838a..9224b051 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -22,18 +22,22 @@ LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output SEED_FILE = "/usr/share/dict/words" USER_ID = 5 # Users.ID of first bogus user PKG_ID = 1 # Packages.ID of first package -MAX_USERS = 76000 # how many users to 'register' +# how many users to 'register' +MAX_USERS = int(os.environ.get("MAX_USERS", 38000)) MAX_DEVS = .1 # what percentage of MAX_USERS are Developers MAX_TUS = .2 # what percentage of MAX_USERS are Trusted Users -MAX_PKGS = 64000 # how many packages to load +# how many packages to load +MAX_PKGS = int(os.environ.get("MAX_PKGS", 32000)) PKG_DEPS = (1, 15) # min/max depends a package has PKG_RELS = (1, 5) # min/max relations a package has PKG_SRC = (1, 3) # min/max sources a package has PKG_CMNTS = (1, 5) # min/max number of comments a package has CATEGORIES_COUNT = 17 # the number of categories from aur-schema VOTING = (0, .001) # percentage range for package voting -OPEN_PROPOSALS = 5 # number of open trusted user proposals -CLOSE_PROPOSALS = 15 # number of closed trusted user proposals +# number of open trusted user proposals +OPEN_PROPOSALS = int(os.environ.get("OPEN_PROPOSALS", 15)) +# number of closed trusted user proposals +CLOSE_PROPOSALS = int(os.environ.get("CLOSE_PROPOSALS", 50)) RANDOM_TLDS = ("edu", "com", "org", "net", "tw", "ru", "pl", "de", "es") RANDOM_URL = ("http://www.", "ftp://ftp.", "http://", "ftp://") RANDOM_LOCS = ("pub", "release", "files", "downloads", "src") From d8556b0d868ef4d3696bbe5a3fe1d5d400537ee4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Jun 2021 21:22:54 -0700 Subject: [PATCH 0749/1891] config: add options.salt_rounds During development, the lower this value is (must be >= 4) equals faster User generation. This is particularly useful for running tests. In production, a higher value (like 12 which is used by various popular frameworks) should be used. Signed-off-by: Kevin Morris --- conf/config.defaults | 1 + conf/config.dev | 2 ++ 2 files changed, 3 insertions(+) diff --git a/conf/config.defaults b/conf/config.defaults index 6da4d754..ebc21e51 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -40,6 +40,7 @@ localedir = /srv/http/aurweb/aur.git/web/locale/ cache = none cache_pkginfo_ttl = 86400 memcache_servers = 127.0.0.1:11211 +salt_rounds = 12 [ratelimit] request_limit = 4000 diff --git a/conf/config.dev b/conf/config.dev index 6ef3bb79..fc3bde91 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -26,6 +26,8 @@ aur_location = http://127.0.0.1:8080 disable_http_login = 0 enable-maintenance = 0 localedir = YOUR_AUR_ROOT/web/locale +; In production, salt_rounds should be higher; suggested: 12. +salt_rounds = 4 [notifications] ; For development/testing, use /usr/bin/sendmail From cec07c76b63460865de326e60ab4be8c148b6bc0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Jun 2021 21:24:33 -0700 Subject: [PATCH 0750/1891] User: use aurweb.config options.salt_rounds Signed-off-by: Kevin Morris --- aurweb/config.py | 4 ++-- aurweb/models/user.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 2a6cfc3e..73db58dc 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -44,5 +44,5 @@ def getboolean(section, option): return _get_parser().getboolean(section, option) -def getint(section, option): - return _get_parser().getint(section, option) +def getint(section, option, fallback=None): + return _get_parser().getint(section, option, fallback=fallback) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 9db9add0..bcb47754 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -15,6 +15,8 @@ import aurweb.schema from aurweb.models.ban import is_banned from aurweb.models.declarative import Base +SALT_ROUNDS_DEFAULT = 12 + class User(Base): """ An ORM model of a single Users record. """ @@ -39,16 +41,24 @@ class User(Base): authenticated = False nonce = None + # Make this static to the class just in case SQLAlchemy ever + # does something to bypass our constructor. + salt_rounds = aurweb.config.getint("options", "salt_rounds", + SALT_ROUNDS_DEFAULT) + def __init__(self, Passwd: str = str(), **kwargs): super().__init__(**kwargs) + # Run this again in the constructor in case we rehashed config. + self.salt_rounds = aurweb.config.getint("options", "salt_rounds", + SALT_ROUNDS_DEFAULT) if Passwd: self.update_password(Passwd) - def update_password(self, password, salt_rounds=12): + def update_password(self, password): self.Passwd = bcrypt.hashpw( password.encode(), - bcrypt.gensalt(rounds=salt_rounds)).decode() + bcrypt.gensalt(rounds=self.salt_rounds)).decode() @staticmethod def minimum_passwd_length(): From ff3519ae113dd0f8b19051e9f08ddffefb7adf56 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Jun 2021 22:12:01 -0700 Subject: [PATCH 0751/1891] [alembic] Log db name being used in a migration Signed-off-by: Kevin Morris --- migrations/env.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/migrations/env.py b/migrations/env.py index dfe14804..7130d141 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -1,3 +1,4 @@ +import logging import logging.config import sqlalchemy @@ -19,12 +20,14 @@ target_metadata = aurweb.schema.metadata # my_important_option = config.get_main_option("my_important_option") # ... etc. - # If configure_logger is either True or not specified, # configure the logger via fileConfig. if config.attributes.get("configure_logger", True): logging.config.fileConfig(config.config_file_name) +# This grabs the root logger in env.py. +logger = logging.getLogger(__name__) + def run_migrations_offline(): """Run migrations in 'offline' mode. @@ -38,6 +41,8 @@ def run_migrations_offline(): script output. """ + db_name = aurweb.config.get("database", "name") + logging.info(f"Performing offline migration on database '{db_name}'.") context.configure( url=aurweb.db.get_sqlalchemy_url(), target_metadata=target_metadata, @@ -56,6 +61,8 @@ def run_migrations_online(): and associate a connection with the context. """ + db_name = aurweb.config.get("database", "name") + logging.info(f"Performing online migration on database '{db_name}'.") connectable = sqlalchemy.create_engine( aurweb.db.get_sqlalchemy_url(), poolclass=sqlalchemy.pool.NullPool, From 9ee7be4a1c8299010df384e91c8e56ec25cc925a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Jun 2021 00:33:32 -0700 Subject: [PATCH 0752/1891] Docker: remove web/locale from volume mounts This caused a bug where generated locale would not be used. Also, removed appending to /etc/hosts which was bugging out on Mac OS X. archlinux:base-devel seems to come with a valid /etc/hosts. Additionally, remove AUR_CONFIG from Dockerfile. We don't set it up; just use the defaults during installation. Signed-off-by: Kevin Morris --- Dockerfile | 3 --- docker-compose.yml | 28 +++++++++++++++++++++------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5fd3ec07..da9c8d3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,6 @@ FROM archlinux:base-devel # Setup some default system stuff. -RUN bash -c 'echo "127.0.0.1 localhost" >> /etc/hosts' -RUN bash -c 'echo "::1 localhost" >> /etc/hosts' RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime RUN mkdir -p .pkg-cache @@ -28,6 +26,5 @@ WORKDIR /aurweb COPY . . ENV PYTHONPATH=/aurweb -ENV AUR_CONFIG=conf/config RUN make -C po all install diff --git a/docker-compose.yml b/docker-compose.yml index c2c948f5..795236c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -116,7 +116,9 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web:/aurweb/web + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates fastapi: @@ -148,7 +150,9 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web:/aurweb/web + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates nginx: @@ -180,7 +184,9 @@ services: - git_data:/aurweb/aur.git - ./cache:/cache - ./logs:/var/log/nginx - - ./web:/aurweb/web + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib sharness: image: aurweb:latest @@ -202,7 +208,9 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web:/aurweb/web + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates pytest-mysql: @@ -229,7 +237,9 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web:/aurweb/web + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates pytest-sqlite: @@ -248,7 +258,9 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web:/aurweb/web + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates depends_on: git: @@ -277,7 +289,9 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web:/aurweb/web + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates volumes: From 07c4be0afbfb467d7c09620a6f01c0761dc0ba6e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Jun 2021 00:42:20 -0700 Subject: [PATCH 0753/1891] Docker: add .dockerignore Currently, this ignores compiled translation files. Signed-off-by: Kevin Morris --- .dockerignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..30747517 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +*/*.mo From 4927a61378a15cdd8ab0fe277c4acdc8cfd973d9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 04:40:54 -0700 Subject: [PATCH 0754/1891] add TUVoteInfo.is_running() method Signed-off-by: Kevin Morris --- aurweb/models/tu_voteinfo.py | 5 +++++ test/test_tu_voteinfo.py | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/aurweb/models/tu_voteinfo.py b/aurweb/models/tu_voteinfo.py index a246f132..fd0031a7 100644 --- a/aurweb/models/tu_voteinfo.py +++ b/aurweb/models/tu_voteinfo.py @@ -1,5 +1,7 @@ import typing +from datetime import datetime + from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship @@ -85,3 +87,6 @@ class TUVoteInfo(Base): """ Customize getattr to floatify any fetched Quorum values. """ attr = super().__getattribute__(key) return float(attr) if key == "Quorum" else attr + + def is_running(self): + return self.End > int(datetime.utcnow().timestamp()) diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py index 37609efd..bd5709fb 100644 --- a/test/test_tu_voteinfo.py +++ b/test/test_tu_voteinfo.py @@ -4,7 +4,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query, rollback +from aurweb.db import commit, create, query, rollback from aurweb.models.account_type import AccountType from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User @@ -49,6 +49,21 @@ def test_tu_voteinfo_creation(): assert tu_voteinfo in user.tu_voteinfo_set +def test_tu_voteinfo_is_running(): + ts = int(datetime.utcnow().timestamp()) + tu_voteinfo = create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 1000, + Quorum=0.5, + Submitter=user) + assert tu_voteinfo.is_running() is True + + tu_voteinfo.End = ts - 5 + commit() + assert tu_voteinfo.is_running() is False + + def test_tu_voteinfo_null_submitter_raises_exception(): with pytest.raises(IntegrityError): create(TUVoteInfo, From ef4a7308ee16e0e42b6adff170dccc259807cade Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 24 Jun 2021 19:28:36 -0700 Subject: [PATCH 0755/1891] add AccountType constants New constants (in aurweb.models.account_type): - USER: "User" - USER_ID: USER's ID - TRUSTED_USER: "Trusted User" - TRUSTED_USER_ID: TRUSTED_USER's ID - DEVELOPER: "Developer" - DEVELOPER_ID: DEVELOPER's ID - TRUSTED_USER_AND_DEV: "TRUSTED_USER_AND_DEV" - TRUSTED_USER_AND_DEV_ID: TRUSTED_USER_AND_DEV's ID Signed-off-by: Kevin Morris --- aurweb/models/account_type.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py index 502a86b1..ca302e5b 100644 --- a/aurweb/models/account_type.py +++ b/aurweb/models/account_type.py @@ -1,5 +1,6 @@ from sqlalchemy import Column, Integer +from aurweb import db from aurweb.models.declarative import Base @@ -20,3 +21,30 @@ class AccountType(Base): def __repr__(self): return "" % ( self.ID, str(self)) + + +# Define some AccountType.AccountType constants. +USER = "User" +TRUSTED_USER = "Trusted User" +DEVELOPER = "Developer" +TRUSTED_USER_AND_DEV = "Trusted User & Developer" + +# Fetch account type IDs from the database for constants. +_account_types = db.query(AccountType) +USER_ID = _account_types.filter( + AccountType.AccountType == USER).first().ID +TRUSTED_USER_ID = _account_types.filter( + AccountType.AccountType == TRUSTED_USER).first().ID +DEVELOPER_ID = _account_types.filter( + AccountType.AccountType == DEVELOPER).first().ID +TRUSTED_USER_AND_DEV_ID = _account_types.filter( + AccountType.AccountType == TRUSTED_USER_AND_DEV).first().ID +_account_types = None # Get rid of the query handle. + +# Map string constants to integer constants. +ACCOUNT_TYPE_ID = { + USER: USER_ID, + TRUSTED_USER: TRUSTED_USER_ID, + DEVELOPER: DEVELOPER_ID, + TRUSTED_USER_AND_DEV: TRUSTED_USER_AND_DEV_ID +} From d606ebc0f1c5805d92a2a1dae86d097dde38ab30 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 04:41:28 -0700 Subject: [PATCH 0756/1891] add User.is_trusted_user() and User.is_developer() Signed-off-by: Kevin Morris --- aurweb/models/user.py | 12 ++++++++++++ test/test_user.py | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index bcb47754..1762f004 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -156,6 +156,18 @@ class User(Base): session.delete(self.session) session.commit() + def is_trusted_user(self): + return self.AccountType.ID in { + aurweb.models.account_type.TRUSTED_USER_ID, + aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID + } + + def is_developer(self): + return self.AccountType.ID in { + aurweb.models.account_type.DEVELOPER_ID, + aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID + } + def __repr__(self): return "" % ( self.ID, str(self.AccountType), self.Username) diff --git a/test/test_user.py b/test/test_user.py index 06585207..9ab40801 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -9,7 +9,7 @@ import pytest import aurweb.auth import aurweb.config -from aurweb.db import create, query +from aurweb.db import commit, create, query from aurweb.models.account_type import AccountType from aurweb.models.ban import Ban from aurweb.models.session import Session @@ -217,3 +217,35 @@ def test_user_as_dict(): assert data.get("Email") == user.Email # .as_dict() does not convert values to json-capable types. assert isinstance(data.get("RegistrationTS"), datetime) + + +def test_user_is_trusted_user(): + tu_type = query(AccountType, + AccountType.AccountType == "Trusted User").first() + user.AccountType = tu_type + commit() + assert user.is_trusted_user() is True + + # Do it again with the combined role. + tu_type = query( + AccountType, + AccountType.AccountType == "Trusted User & Developer").first() + user.AccountType = tu_type + commit() + assert user.is_trusted_user() is True + + +def test_user_is_developer(): + dev_type = query(AccountType, + AccountType.AccountType == "Developer").first() + user.AccountType = dev_type + commit() + assert user.is_developer() is True + + # Do it again with the combined role. + dev_type = query( + AccountType, + AccountType.AccountType == "Trusted User & Developer").first() + user.AccountType = dev_type + commit() + assert user.is_developer() is True From a6bba601a98aef9b19a4a2b5114557b21706c1d5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 10:46:44 -0700 Subject: [PATCH 0757/1891] add util.get_vote -> `get_vote` Jinja2 filter This filter gets a vote of a request's user toward a voteinfo. Example: {% set vote = (voteinfo | get_vote(request)) %} Signed-off-by: Kevin Morris --- aurweb/templates.py | 1 + aurweb/util.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/aurweb/templates.py b/aurweb/templates.py index bb4047f4..b8853593 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -29,6 +29,7 @@ env.filters["dt"] = util.timestamp_to_datetime env.filters["as_timezone"] = util.as_timezone env.filters["dedupe_qs"] = util.dedupe_qs env.filters["urlencode"] = quote_plus +env.filters["get_vote"] = util.get_vote # Add captcha filters. env.filters["captcha_salt"] = captcha.captcha_salt_filter diff --git a/aurweb/util.py b/aurweb/util.py index e5f510ce..adbff755 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -10,6 +10,8 @@ from datetime import datetime from urllib.parse import quote_plus, urlparse from zoneinfo import ZoneInfo +import fastapi + from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email from fastapi.responses import Response from jinja2 import pass_context @@ -143,6 +145,11 @@ def dedupe_qs(query_string: str, *additions): return '&'.join([f"{k}={quote_plus(v)}" for k, v in reversed(qs.items())]) +def get_vote(voteinfo, request: fastapi.Request): + from aurweb.models.tu_vote import TUVote + return voteinfo.tu_votes.filter(TUVote.User == request.user).first() + + def jsonify(obj): """ Perform a conversion on obj if it's needed. """ if isinstance(obj, datetime): From d674aaf736383a82d0bc900a5b8bcfc7e41537b9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Jun 2021 04:33:48 -0700 Subject: [PATCH 0758/1891] add /tu/ (get) index This commit implements the '/tu' Trusted User index page. In addition to this functionality, this commit introduces the following jinja2 filters: - dt: util.timestamp_to_datetime - as_timezone: util.as_timezone - dedupe_qs: util.dedupe_qs - urlencode: urllib.parse.quote_plus There's also a new decorator that can be used to enforce permissions: `account_type_required`. If a user does not meet account type requirements, they are redirected to '/'. ``` @auth_required(True) @account_type_required({"Trusted User"}) async def some_route(request: fastapi.Request): return Response("You are a Trusted User!") ``` Routes added: - `GET /tu`: aurweb.routers.trusted_user.trusted_user Signed-off-by: Kevin Morris --- aurweb/asgi.py | 3 +- aurweb/auth.py | 39 +++ aurweb/models/account_type.py | 5 + aurweb/routers/trusted_user.py | 97 ++++++ templates/partials/archdev-navbar.html | 18 + templates/partials/tu/last_votes.html | 33 ++ templates/partials/tu/proposals.html | 120 +++++++ templates/tu/index.html | 35 ++ test/test_auth.py | 18 +- test/test_trusted_user_routes.py | 443 +++++++++++++++++++++++++ 10 files changed, 808 insertions(+), 3 deletions(-) create mode 100644 aurweb/routers/trusted_user.py create mode 100644 templates/partials/tu/last_votes.html create mode 100644 templates/partials/tu/proposals.html create mode 100644 templates/tu/index.html create mode 100644 test/test_trusted_user_routes.py diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 65318907..a674fec6 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -16,7 +16,7 @@ from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine, query from aurweb.models.accepted_term import AcceptedTerm from aurweb.models.term import Term -from aurweb.routers import accounts, auth, errors, html, sso +from aurweb.routers import accounts, auth, errors, html, sso, trusted_user # Setup the FastAPI app. app = FastAPI(exception_handlers=errors.exceptions) @@ -47,6 +47,7 @@ async def app_startup(): app.include_router(html.router) app.include_router(auth.router) app.include_router(accounts.router) + app.include_router(trusted_user.router) # Initialize the database engine and ORM. get_engine() diff --git a/aurweb/auth.py b/aurweb/auth.py index ba5f0fea..316e7293 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -3,6 +3,8 @@ import functools from datetime import datetime from http import HTTPStatus +import fastapi + from fastapi.responses import RedirectResponse from sqlalchemy import and_ from starlette.authentication import AuthCredentials, AuthenticationBackend @@ -11,6 +13,7 @@ from starlette.requests import HTTPConnection import aurweb.config from aurweb import l10n, util +from aurweb.models.account_type import ACCOUNT_TYPE_ID from aurweb.models.session import Session from aurweb.models.user import User from aurweb.templates import make_variable_context, render_template @@ -152,6 +155,42 @@ def auth_required(is_required: bool = True, return decorator +def account_type_required(one_of: set): + """ A decorator that can be used on FastAPI routes to dictate + that a user belongs to one of the types defined in one_of. + + This decorator should be run after an @auth_required(True) is + dictated. + + - Example code: + + @router.get('/some_route') + @auth_required(True) + @account_type_required({"Trusted User", "Trusted User & Developer"}) + async def some_route(request: fastapi.Request): + return Response() + + :param one_of: A set consisting of strings to match against AccountType. + :return: Return the FastAPI function this decorator wraps. + """ + # Convert any account type string constants to their integer IDs. + one_of = { + ACCOUNT_TYPE_ID[atype] + for atype in one_of + if isinstance(atype, str) + } + + def decorator(func): + @functools.wraps(func) + async def wrapper(request: fastapi.Request, *args, **kwargs): + if request.user.AccountType.ID not in one_of: + return RedirectResponse("/", + status_code=int(HTTPStatus.SEE_OTHER)) + return await func(request, *args, **kwargs) + return wrapper + return decorator + + CRED_ACCOUNT_CHANGE_TYPE = 1 CRED_ACCOUNT_EDIT = 2 CRED_ACCOUNT_EDIT_DEV = 3 diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py index ca302e5b..0db37ced 100644 --- a/aurweb/models/account_type.py +++ b/aurweb/models/account_type.py @@ -3,6 +3,11 @@ from sqlalchemy import Column, Integer from aurweb import db from aurweb.models.declarative import Base +USER = "User" +TRUSTED_USER = "Trusted User" +DEVELOPER = "Developer" +TRUSTED_USER_AND_DEV = "Trusted User & Developer" + class AccountType(Base): """ An ORM model of a single AccountTypes record. """ diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py new file mode 100644 index 00000000..c027f67d --- /dev/null +++ b/aurweb/routers/trusted_user.py @@ -0,0 +1,97 @@ +from datetime import datetime +from urllib.parse import quote_plus + +from fastapi import APIRouter, Request +from sqlalchemy import and_, or_ + +from aurweb import db +from aurweb.auth import account_type_required, auth_required +from aurweb.models.account_type import DEVELOPER, TRUSTED_USER, TRUSTED_USER_AND_DEV +from aurweb.models.tu_vote import TUVote +from aurweb.models.tu_voteinfo import TUVoteInfo +from aurweb.models.user import User +from aurweb.templates import make_context, render_template + +router = APIRouter() + +# Some TU route specific constants. +ITEMS_PER_PAGE = 10 # Paged table size. +MAX_AGENDA_LENGTH = 75 # Agenda table column length. + +# A set of account types that will approve a user for TU actions. +REQUIRED_TYPES = { + TRUSTED_USER, + DEVELOPER, + TRUSTED_USER_AND_DEV +} + + +@router.get("/tu") +@auth_required(True, redirect="/") +@account_type_required(REQUIRED_TYPES) +async def trusted_user(request: Request, + coff: int = 0, # current offset + cby: str = "desc", # current by + poff: int = 0, # past offset + pby: str = "desc"): # past by + context = make_context(request, "Trusted User") + + current_by, past_by = cby, pby + current_off, past_off = coff, poff + + context["pp"] = pp = ITEMS_PER_PAGE + context["prev_len"] = MAX_AGENDA_LENGTH + + ts = int(datetime.utcnow().timestamp()) + + if current_by not in {"asc", "desc"}: + # If a malicious by was given, default to desc. + current_by = "desc" + context["current_by"] = current_by + + if past_by not in {"asc", "desc"}: + # If a malicious by was given, default to desc. + past_by = "desc" + context["past_by"] = past_by + + current_votes = db.query(TUVoteInfo, TUVoteInfo.End > ts).order_by( + TUVoteInfo.Submitted.desc()) + context["current_votes_count"] = current_votes.count() + current_votes = current_votes.limit(pp).offset(current_off) + context["current_votes"] = reversed(current_votes.all()) \ + if current_by == "asc" else current_votes.all() + context["current_off"] = current_off + + past_votes = db.query(TUVoteInfo, TUVoteInfo.End <= ts).order_by( + TUVoteInfo.Submitted.desc()) + context["past_votes_count"] = past_votes.count() + past_votes = past_votes.limit(pp).offset(past_off) + context["past_votes"] = reversed(past_votes.all()) \ + if past_by == "asc" else past_votes.all() + context["past_off"] = past_off + + # TODO + # We order last votes by TUVote.VoteID and User.Username. + # This is really bad. We should add a Created column to + # TUVote of type Timestamp and order by that instead. + last_votes_by_tu = db.query(TUVote).filter( + and_(TUVote.VoteID == TUVoteInfo.ID, + TUVoteInfo.End <= ts, + TUVote.UserID == User.ID, + or_(User.AccountTypeID == 2, + User.AccountTypeID == 4)) + ).group_by(User.ID).order_by( + TUVote.VoteID.desc(), User.Username.asc()) + context["last_votes_by_tu"] = last_votes_by_tu.all() + + context["current_by_next"] = "asc" if current_by == "desc" else "desc" + context["past_by_next"] = "asc" if past_by == "desc" else "desc" + + context["q"] = '&'.join([ + f"coff={current_off}", + f"cby={quote_plus(current_by)}", + f"poff={past_off}", + f"pby={quote_plus(past_by)}" + ]) + + return render_template(request, "tu/index.html", context) diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index c935fd41..c6cd3f19 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -7,11 +7,29 @@ {% endif %}

  • {% trans %}Packages{% endtrans %}
  • {% if request.user.is_authenticated() %} + + {% if request.user.is_trusted_user() or request.user.is_developer() %} +
  • + {% trans %}Requests{% endtrans %} +
  • + +
  • + {% trans %}Accounts{% endtrans %} +
  • + {% endif %} +
  • {% trans %}My Account{% endtrans %}
  • + + {% if request.user.is_trusted_user() %} +
  • + {% trans %}Trusted User{% endtrans %} +
  • + {% endif %} +
  • {% trans %}Logout{% endtrans %} diff --git a/templates/partials/tu/last_votes.html b/templates/partials/tu/last_votes.html new file mode 100644 index 00000000..94b9c1e8 --- /dev/null +++ b/templates/partials/tu/last_votes.html @@ -0,0 +1,33 @@ +
    +

    {% trans %}{{ title }}{% endtrans %}

    + +
  • + + + + + + + {% if not votes %} + + + + + {% else %} + {% for vote in votes %} + + + + + {% endfor %} + {% endif %} + +
    {{ "User" | tr }}{{ "Last vote" | tr }}
    + {{ "No results found." | tr }} +
    {{ vote.User.Username }} + + {{ vote.VoteID }} + +
    + + diff --git a/templates/partials/tu/proposals.html b/templates/partials/tu/proposals.html new file mode 100644 index 00000000..13e705fc --- /dev/null +++ b/templates/partials/tu/proposals.html @@ -0,0 +1,120 @@ +
    +

    {% trans %}{{ title }}{% endtrans %}

    + + {% if title == "Current Votes" %} +
    + {% endif %} + + {% if not results %} +

    + {% trans %}No results found.{% endtrans %} +

    + {% else %} + + + + + + + + + {% if title != "Current Votes" %} + + + {% endif %} + + + + + + {% for result in results %} + + + + + {% set submitted = result.Submitted | dt | as_timezone(timezone) %} + + + + {% set end = result.End | dt | as_timezone(timezone) %} + + + + + {% if title != "Current Votes" %} + + + {% endif %} + + {% set vote = (result | get_vote(request)) %} + + + {% endfor %} + +
    {{ "Proposal" | tr }} + {% set off_qs = "%s=%d" | format(off_param, off) %} + {% set by_qs = "%s=%s" | format(by_param, by_next | urlencode) %} + + {{ "Start" | tr }} + + {{ "End" | tr }}{{ "User" | tr }}{{ "Yes" | tr }}{{ "No" | tr }}{{ "Voted" | tr }}
    + + {% set agenda = result.Agenda[:prev_len] %} + {{ agenda }} + {{ submitted.strftime("%Y-%m-%d") }}{{ end.strftime("%Y-%m-%d") }} + {% if not result.User %} + N/A + {% else %} + + {{ result.User }} + + {% endif %} + {{ result.Yes }}{{ result.No }} + {% if vote %} + + {{ "Yes" | tr }} + + {% else %} + + {{ "No" | tr }} + + {% endif %} +
    + +
    +

    + {% if total_votes > pp %} + + {% if off > 0 %} + {% set off_qs = "%s=%d" | format(off_param, off - 10) %} + {% set by_qs = "%s=%s" | format(by_param, by | urlencode) %} + + ‹ Back + + {% endif %} + + {% if off < total_votes - pp %} + {% set off_qs = "%s=%d" | format(off_param, off + 10) %} + {% set by_qs = "%s=%s" | format(by_param, by | urlencode) %} + + Next › + + {% endif %} + + {% endif %} +

    +
    + + {% endif %} + +
    diff --git a/templates/tu/index.html b/templates/tu/index.html new file mode 100644 index 00000000..5060e1f7 --- /dev/null +++ b/templates/tu/index.html @@ -0,0 +1,35 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} + {% + with table_class = "current-votes", + total_votes = current_votes_count, + results = current_votes, + off_param = "coff", + by_param = "cby", + by_next = current_by_next, + title = "Current Votes", + off = current_off, + by = current_by + %} + {% include "partials/tu/proposals.html" %} + {% endwith %} + + {% + with table_class = "past-votes", + total_votes = past_votes_count, + results = past_votes, + off_param = "poff", + by_param = "pby", + by_next = past_by_next, + title = "Past Votes", + off = past_off, + by = past_by + %} + {% include "partials/tu/proposals.html" %} + {% endwith %} + + {% with title = "Last Votes by TU", votes = last_votes_by_tu %} + {% include "partials/tu/last_votes.html" %} + {% endwith %} +{% endblock %} diff --git a/test/test_auth.py b/test/test_auth.py index e5e1de11..b386bea1 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -4,9 +4,9 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.auth import BasicAuthBackend, has_credential +from aurweb.auth import BasicAuthBackend, account_type_required, has_credential from aurweb.db import create, query -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER, USER_ID, AccountType from aurweb.models.session import Session from aurweb.models.user import User from aurweb.testing import setup_test_db @@ -76,3 +76,17 @@ async def test_basic_auth_backend(): def test_has_fake_credential_fails(): # Fake credential 666 does not exist. assert not has_credential(user, 666) + + +def test_account_type_required(): + """ This test merely asserts that a few different paths + do not raise exceptions. """ + # This one shouldn't raise. + account_type_required({USER}) + + # This one also shouldn't raise. + account_type_required({USER_ID}) + + # But this one should! We have no "FAKE" key. + with pytest.raises(KeyError): + account_type_required({'FAKE'}) diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py new file mode 100644 index 00000000..a6527e6f --- /dev/null +++ b/test/test_trusted_user_routes.py @@ -0,0 +1,443 @@ +import re + +from datetime import datetime +from http import HTTPStatus +from io import StringIO + +import lxml.etree +import pytest + +from fastapi.testclient import TestClient + +from aurweb import db +from aurweb.models.account_type import AccountType +from aurweb.models.tu_vote import TUVote +from aurweb.models.tu_voteinfo import TUVoteInfo +from aurweb.models.user import User +from aurweb.testing import setup_test_db +from aurweb.testing.requests import Request + +DATETIME_REGEX = r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$' + + +def parse_root(html): + parser = lxml.etree.HTMLParser(recover=True) + tree = lxml.etree.parse(StringIO(html), parser) + return tree.getroot() + + +def get_table(root, class_name): + table = root.xpath(f'//table[contains(@class, "{class_name}")]')[0] + return table + + +def get_table_rows(table): + tbody = table.xpath("./tbody")[0] + return tbody.xpath("./tr") + + +def get_pkglist_directions(table): + stats = table.getparent().xpath("./div[@class='pkglist-stats']")[0] + nav = stats.xpath("./p[@class='pkglist-nav']")[0] + return nav.xpath("./a") + + +def get_a(node): + return node.xpath('./a')[0].text.strip() + + +def get_span(node): + return node.xpath('./span')[0].text.strip() + + +def assert_current_vote_html(row, expected): + columns = row.xpath("./td") + proposal, start, end, user, voted = columns + p, s, e, u, v = expected # Column expectations. + assert re.match(p, get_a(proposal)) is not None + assert re.match(s, start.text) is not None + assert re.match(e, end.text) is not None + assert re.match(u, get_a(user)) is not None + assert re.match(v, get_span(voted)) is not None + + +def assert_past_vote_html(row, expected): + columns = row.xpath("./td") + proposal, start, end, user, yes, no, voted = columns # Real columns. + p, s, e, u, y, n, v = expected # Column expectations. + assert re.match(p, get_a(proposal)) is not None + assert re.match(s, start.text) is not None + assert re.match(e, end.text) is not None + assert re.match(u, get_a(user)) is not None + assert re.match(y, yes.text) is not None + assert re.match(n, no.text) is not None + assert re.match(v, get_span(voted)) is not None + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db("TU_Votes", "TU_VoteInfo", "Users") + + +@pytest.fixture +def client(): + from aurweb.asgi import app + yield TestClient(app=app) + + +@pytest.fixture +def tu_user(): + tu_type = db.query(AccountType, + AccountType.AccountType == "Trusted User").first() + yield db.create(User, Username="test_tu", Email="test_tu@example.org", + RealName="Test TU", Passwd="testPassword", + AccountType=tu_type) + + +@pytest.fixture +def user(): + user_type = db.query(AccountType, + AccountType.AccountType == "User").first() + yield db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=user_type) + + +def test_tu_index_guest(client): + with client as request: + response = request.get("/tu", allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/" + + +def test_tu_index_unauthorized(client, user): + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + # Login as a normal user, not a TU. + response = request.get("/tu", cookies=cookies, allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/" + + +def test_tu_empty_index(client, tu_user): + """ Check an empty index when we don't create any records. """ + + # Make a default get request to /tu. + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get("/tu", cookies=cookies, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + # Parse lxml root. + root = parse_root(response.text) + + # Check that .current-votes does not exist. + tables = root.xpath('//table[contains(@class, "current-votes")]') + assert len(tables) == 0 + + # Check that .past-votes has does not exist. + tables = root.xpath('//table[contains(@class, "current-votes")]') + assert len(tables) == 0 + + +def test_tu_index(client, tu_user): + ts = int(datetime.utcnow().timestamp()) + + # Create some test votes: (Agenda, Start, End). + votes = [ + ("Test agenda 1", ts - 5, ts + 1000), # Still running. + ("Test agenda 2", ts - 1000, ts - 5) # Not running anymore. + ] + vote_records = [] + for vote in votes: + agenda, start, end = vote + vote_records.append( + db.create(TUVoteInfo, Agenda=agenda, + User=tu_user.Username, + Submitted=start, End=end, + Quorum=0.0, + Submitter=tu_user)) + + # Vote on an ended proposal. + vote_record = vote_records[1] + vote_record.Yes += 1 + vote_record.ActiveTUs += 1 + db.create(TUVote, VoteInfo=vote_record, User=tu_user) + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + # Pass an invalid cby and pby; let them default to "desc". + response = request.get("/tu", cookies=cookies, params={ + "cby": "BAD!", + "pby": "blah" + }, allow_redirects=False) + + assert response.status_code == int(HTTPStatus.OK) + + # Rows we expect to exist in HTML produced by /tu for current votes. + expected_rows = [ + ( + r'Test agenda 1', + DATETIME_REGEX, + DATETIME_REGEX, + tu_user.Username, + r'^(Yes|No)$' + ) + ] + + # Assert that we are matching the number of current votes. + current_votes = [c for c in votes if c[2] > ts] + assert len(current_votes) == len(expected_rows) + + # Parse lxml.etree root. + root = parse_root(response.text) + + table = get_table(root, "current-votes") + rows = get_table_rows(table) + for i, row in enumerate(rows): + assert_current_vote_html(row, expected_rows[i]) + + # Assert that we are matching the number of past votes. + past_votes = [c for c in votes if c[2] <= ts] + assert len(past_votes) == len(expected_rows) + + # Rows we expect to exist in HTML produced by /tu for past votes. + expected_rows = [ + ( + r'Test agenda 2', + DATETIME_REGEX, + DATETIME_REGEX, + tu_user.Username, + r'^\d+$', + r'^\d+$', + r'^(Yes|No)$' + ) + ] + + table = get_table(root, "past-votes") + rows = get_table_rows(table) + for i, row in enumerate(rows): + assert_past_vote_html(row, expected_rows[i]) + + # Get the .last-votes table and check that our vote shows up. + table = get_table(root, "last-votes") + rows = get_table_rows(table) + assert len(rows) == 1 + + # Check to see the rows match up to our user and related vote. + username, vote_id = rows[0] + vote_id = vote_id.xpath("./a")[0] + assert username.text.strip() == tu_user.Username + assert int(vote_id.text.strip()) == vote_records[1].ID + + +def test_tu_index_table_paging(client, tu_user): + ts = int(datetime.utcnow().timestamp()) + + for i in range(25): + # Create 25 current votes. + db.create(TUVoteInfo, Agenda=f"Agenda #{i}", + User=tu_user.Username, + Submitted=(ts - 5), End=(ts + 1000), + Quorum=0.0, + Submitter=tu_user, autocommit=False) + + for i in range(25): + # Create 25 past votes. + db.create(TUVoteInfo, Agenda=f"Agenda #{25 + i}", + User=tu_user.Username, + Submitted=(ts - 1000), End=(ts - 5), + Quorum=0.0, + Submitter=tu_user, autocommit=False) + db.commit() + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get("/tu", cookies=cookies, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + # Parse lxml.etree root. + root = parse_root(response.text) + + table = get_table(root, "current-votes") + rows = get_table_rows(table) + assert len(rows) == 10 + + def make_expectation(offset, i): + return [ + f"Agenda #{offset + i}", + DATETIME_REGEX, + DATETIME_REGEX, + tu_user.Username, + r'^(Yes|No)$' + ] + + for i, row in enumerate(rows): + assert_current_vote_html(row, make_expectation(0, i)) + + # Parse out Back/Next buttons. + directions = get_pkglist_directions(table) + assert len(directions) == 1 + assert "Next" in directions[0].text + + # Now, get the next page of current votes. + offset = 10 # Specify coff=10 + with client as request: + response = request.get("/tu", cookies=cookies, params={ + "coff": offset + }, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + old_rows = rows + root = parse_root(response.text) + + table = get_table(root, "current-votes") + rows = get_table_rows(table) + assert rows != old_rows + + for i, row in enumerate(rows): + assert_current_vote_html(row, make_expectation(offset, i)) + + # Parse out Back/Next buttons. + directions = get_pkglist_directions(table) + assert len(directions) == 2 + assert "Back" in directions[0].text + assert "Next" in directions[1].text + + # Make sure past-votes' Back/Next were not affected. + past_votes = get_table(root, "past-votes") + past_directions = get_pkglist_directions(past_votes) + assert len(past_directions) == 1 + assert "Next" in past_directions[0].text + + offset = 20 # Specify coff=10 + with client as request: + response = request.get("/tu", cookies=cookies, params={ + "coff": offset + }, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + # Do it again, we only have five left. + old_rows = rows + root = parse_root(response.text) + + table = get_table(root, "current-votes") + rows = get_table_rows(table) + assert rows != old_rows + for i, row in enumerate(rows): + assert_current_vote_html(row, make_expectation(offset, i)) + + # Parse out Back/Next buttons. + directions = get_pkglist_directions(table) + assert len(directions) == 1 + assert "Back" in directions[0].text + + # Make sure past-votes' Back/Next were not affected. + past_votes = get_table(root, "past-votes") + past_directions = get_pkglist_directions(past_votes) + assert len(past_directions) == 1 + assert "Next" in past_directions[0].text + + +def test_tu_index_sorting(client, tu_user): + ts = int(datetime.utcnow().timestamp()) + + for i in range(2): + # Create 'Agenda #1' and 'Agenda #2'. + db.create(TUVoteInfo, Agenda=f"Agenda #{i + 1}", + User=tu_user.Username, + Submitted=(ts + 5), End=(ts + 1000), + Quorum=0.0, + Submitter=tu_user, autocommit=False) + + # Let's order each vote one day after the other. + # This will allow us to test the sorting nature + # of the tables. + ts += 86405 + + # Make a default request to /tu. + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get("/tu", cookies=cookies, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + # Get lxml handles of the document. + root = parse_root(response.text) + table = get_table(root, "current-votes") + rows = get_table_rows(table) + + # The latest Agenda is at the top by default. + expected = [ + "Agenda #2", + "Agenda #1" + ] + + assert len(rows) == len(expected) + for i, row in enumerate(rows): + assert_current_vote_html(row, [ + expected[i], + DATETIME_REGEX, + DATETIME_REGEX, + tu_user.Username, + r'^(Yes|No)$' + ]) + + # Make another request; one that sorts the current votes + # in ascending order instead of the default descending order. + with client as request: + response = request.get("/tu", cookies=cookies, params={ + "cby": "asc" + }, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + # Get lxml handles of the document. + root = parse_root(response.text) + table = get_table(root, "current-votes") + rows = get_table_rows(table) + + # Reverse our expectations and assert that the proposals got flipped. + rev_expected = list(reversed(expected)) + assert len(rows) == len(rev_expected) + for i, row in enumerate(rows): + assert_current_vote_html(row, [ + rev_expected[i], + DATETIME_REGEX, + DATETIME_REGEX, + tu_user.Username, + r'^(Yes|No)$' + ]) + + +def test_tu_index_last_votes(client, tu_user, user): + ts = int(datetime.utcnow().timestamp()) + + # Create a proposal which has ended. + voteinfo = db.create(TUVoteInfo, Agenda="Test agenda", + User=user.Username, + Submitted=(ts - 1000), + End=(ts - 5), + Yes=1, + ActiveTUs=1, + Quorum=0.0, + Submitter=tu_user) + + # Create a vote on it from tu_user. + db.create(TUVote, VoteInfo=voteinfo, User=tu_user) + + # Now, check that tu_user got populated in the .last-votes table. + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get("/tu", cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + table = get_table(root, "last-votes") + rows = get_table_rows(table) + assert len(rows) == 1 + + last_vote = rows[0] + user, vote_id = last_vote.xpath("./td") + vote_id = vote_id.xpath("./a")[0] + + assert user.text.strip() == tu_user.Username + assert int(vote_id.text.strip()) == voteinfo.ID From e534704a98ed7d421c04279e0c4f57aa8ea837b1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Jun 2021 01:10:20 -0700 Subject: [PATCH 0759/1891] [FastAPI] remove unused Requests navbar item Signed-off-by: Kevin Morris --- templates/partials/archdev-navbar.html | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index c6cd3f19..13459e1a 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -7,17 +7,13 @@ {% endif %}
  • {% trans %}Packages{% endtrans %}
  • {% if request.user.is_authenticated() %} - {% if request.user.is_trusted_user() or request.user.is_developer() %}
  • - {% trans %}Requests{% endtrans %} -
  • - -
  • - {% trans %}Accounts{% endtrans %} + + {% trans %}Accounts{% endtrans %} +
  • {% endif %} -
  • {% trans %}My Account{% endtrans %} From dc4cc9b604a9085f631c2649909f6767e6f2ce3e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 01:10:53 -0700 Subject: [PATCH 0760/1891] add aurweb.asgi.id_redirect_middleware A new middleware which redirects requests going to '/route?id=some_id' to '/route/some_id'. In the FastAPI application, we'll prefer using restful layouts where possible where resource-based ids are parameters of the request uri: '/route/{resource_id}'. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 22 ++++++++++++++++++++++ test/test_routes.py | 10 ++++++++++ 2 files changed, 32 insertions(+) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index a674fec6..35166c73 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -2,6 +2,8 @@ import asyncio import http import typing +from urllib.parse import quote_plus + from fastapi import FastAPI, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.staticfiles import StaticFiles @@ -120,3 +122,23 @@ async def check_terms_of_service(request: Request, call_next: typing.Callable): task = asyncio.create_task(call_next(request)) await asyncio.wait({task}, return_when=asyncio.FIRST_COMPLETED) return task.result() + + +@app.middleware("http") +async def id_redirect_middleware(request: Request, call_next: typing.Callable): + id = request.query_params.get("id") + + if id is not None: + # Preserve query string. + qs = [] + for k, v in request.query_params.items(): + if k != "id": + qs.append(f"{k}={quote_plus(str(v))}") + qs = str() if not qs else '?' + '&'.join(qs) + + path = request.url.path.rstrip('/') + return RedirectResponse(f"{path}/{id}{qs}") + + task = asyncio.create_task(call_next(request)) + await asyncio.wait({task}, return_when=asyncio.FIRST_COMPLETED) + return task.result() diff --git a/test/test_routes.py b/test/test_routes.py index d67f4a48..a2d1786e 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -148,3 +148,13 @@ def test_nonce_csp(): if not (nonce_verified := (script.get("nonce") == nonce)): break assert nonce_verified is True + + +def test_id_redirect(): + with client as request: + response = request.get("/", params={ + "id": "test", # This param will be rewritten into Location. + "key": "value", # Test that this param persists. + "key2": "value2" # And this one. + }, allow_redirects=False) + assert response.headers.get("location") == "/test?key=value&key2=value2" From ac1779b705d9b0ad87deaa1856e9b5e05d9ae944 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 01:14:10 -0700 Subject: [PATCH 0761/1891] add util.number_format -> `number_format` Jinja2 filter Implement a `number_format` equivalent to PHP's version. Signed-off-by: Kevin Morris --- aurweb/templates.py | 1 + aurweb/util.py | 5 +++++ test/test_util.py | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/aurweb/templates.py b/aurweb/templates.py index b8853593..8b507425 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -30,6 +30,7 @@ env.filters["as_timezone"] = util.as_timezone env.filters["dedupe_qs"] = util.dedupe_qs env.filters["urlencode"] = quote_plus env.filters["get_vote"] = util.get_vote +env.filters["number_format"] = util.number_format # Add captcha filters. env.filters["captcha_salt"] = captcha.captcha_salt_filter diff --git a/aurweb/util.py b/aurweb/util.py index adbff755..539af40e 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -150,6 +150,11 @@ def get_vote(voteinfo, request: fastapi.Request): return voteinfo.tu_votes.filter(TUVote.User == request.user).first() +def number_format(value: float, places: int): + """ A converter function similar to PHP's number_format. """ + return f"{value:.{places}f}" + + def jsonify(obj): """ Perform a conversion on obj if it's needed. """ if isinstance(obj, datetime): diff --git a/test/test_util.py b/test/test_util.py index 074de494..f54a98a0 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -30,3 +30,8 @@ def test_dedupe_qs(): # Add key1=changed and key2=changed to the query and dedupe it. deduped = util.dedupe_qs(query_string, "key1=changed", "key3=changed") assert deduped == "key2=blah&key1=changed&key3=changed" + + +def test_number_format(): + assert util.number_format(0.222, 2) == "0.22" + assert util.number_format(0.226, 2) == "0.23" From 83c038a42ac50a087bff82490b21acc7e55d65b9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 01:18:40 -0700 Subject: [PATCH 0762/1891] add TUVoteInfo.total_votes() Returns the sum of TUVoteInfo.Yes, TUVoteInfo.No and TUVoteInfo.Abstain. Signed-off-by: Kevin Morris --- aurweb/models/tu_voteinfo.py | 3 +++ test/test_tu_voteinfo.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/aurweb/models/tu_voteinfo.py b/aurweb/models/tu_voteinfo.py index fd0031a7..b80073f4 100644 --- a/aurweb/models/tu_voteinfo.py +++ b/aurweb/models/tu_voteinfo.py @@ -90,3 +90,6 @@ class TUVoteInfo(Base): def is_running(self): return self.End > int(datetime.utcnow().timestamp()) + + def total_votes(self): + return self.Yes + self.No + self.Abstain diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py index bd5709fb..494300c5 100644 --- a/test/test_tu_voteinfo.py +++ b/test/test_tu_voteinfo.py @@ -64,6 +64,24 @@ def test_tu_voteinfo_is_running(): assert tu_voteinfo.is_running() is False +def test_tu_voteinfo_total_votes(): + ts = int(datetime.utcnow().timestamp()) + tu_voteinfo = create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 1000, + Quorum=0.5, + Submitter=user) + + tu_voteinfo.Yes = 1 + tu_voteinfo.No = 3 + tu_voteinfo.Abstain = 5 + commit() + + # total_votes() should be the sum of Yes, No and Abstain: 1 + 3 + 5 = 9. + assert tu_voteinfo.total_votes() == 9 + + def test_tu_voteinfo_null_submitter_raises_exception(): with pytest.raises(IntegrityError): create(TUVoteInfo, From 85ba4a33a865ab78cd9e3e1b4e9bd6e410ea8816 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 05:08:25 -0700 Subject: [PATCH 0763/1891] add /tu/{proposal_id} (get, post) routes This commit ports the `/tu/?id={proposal_id}` PHP routes to FastAPI into two individual GET and POST routes. With this port of the single proposal view and POST logic, several things have changed. - The only parameter used is now `decision`, which must contain `Yes`, `No`, or `Abstain` as a string. When an invalid value is given, a BAD_REQUEST response is returned in plaintext: Invalid 'decision' value. - The `doVote` parameter has been removed. - The details section has been rearranged into a set of divs with specific classes that can be used for testing. CSS has been added to persist the layout with the element changes. - Several errors that can be discovered in the POST path now trigger their own non-200 HTTPStatus codes. Signed-off-by: Kevin Morris --- aurweb/routers/trusted_user.py | 127 ++++++++- templates/partials/tu/proposal/details.html | 106 +++++++ templates/partials/tu/proposal/form.html | 14 + templates/partials/tu/proposal/voters.html | 10 + templates/tu/show.html | 20 ++ test/test_trusted_user_routes.py | 288 ++++++++++++++++++++ web/html/css/aurweb.css | 8 + 7 files changed, 571 insertions(+), 2 deletions(-) create mode 100644 templates/partials/tu/proposal/details.html create mode 100644 templates/partials/tu/proposal/form.html create mode 100644 templates/partials/tu/proposal/voters.html create mode 100644 templates/tu/show.html diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index c027f67d..efdcfc73 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -1,7 +1,11 @@ +import typing + from datetime import datetime +from http import HTTPStatus from urllib.parse import quote_plus -from fastapi import APIRouter, Request +from fastapi import APIRouter, Form, HTTPException, Request +from fastapi.responses import Response from sqlalchemy import and_, or_ from aurweb import db @@ -10,7 +14,7 @@ from aurweb.models.account_type import DEVELOPER, TRUSTED_USER, TRUSTED_USER_AND from aurweb.models.tu_vote import TUVote from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User -from aurweb.templates import make_context, render_template +from aurweb.templates import make_context, make_variable_context, render_template router = APIRouter() @@ -95,3 +99,122 @@ async def trusted_user(request: Request, ]) return render_template(request, "tu/index.html", context) + + +def render_proposal(request: Request, + context: dict, + proposal: int, + voteinfo: TUVoteInfo, + voters: typing.Iterable[User], + vote: TUVote, + status_code: HTTPStatus = HTTPStatus.OK): + """ Render a single TU proposal. """ + context["proposal"] = proposal + context["voteinfo"] = voteinfo + context["voters"] = voters + + participation = voteinfo.ActiveTUs / voteinfo.total_votes() \ + if voteinfo.total_votes() else 0 + context["participation"] = participation + + accepted = (voteinfo.Yes > voteinfo.ActiveTUs / 2) or \ + (participation > voteinfo.Quorum and voteinfo.Yes > voteinfo.No) + context["accepted"] = accepted + + can_vote = voters.filter(TUVote.User == request.user).first() is None + context["can_vote"] = can_vote + + if not voteinfo.is_running(): + context["error"] = "Voting is closed for this proposal." + + context["vote"] = vote + context["has_voted"] = vote is not None + + return render_template(request, "tu/show.html", context, + status_code=status_code) + + +@router.get("/tu/{proposal}") +@auth_required(True, redirect="/") +@account_type_required(REQUIRED_TYPES) +async def trusted_user_proposal(request: Request, proposal: int): + context = await make_variable_context(request, "Trusted User") + proposal = int(proposal) + + voteinfo = db.query(TUVoteInfo, TUVoteInfo.ID == proposal).first() + if not voteinfo: + raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) + + voters = db.query(User).join(TUVote).filter(TUVote.VoteID == voteinfo.ID) + vote = db.query(TUVote, and_(TUVote.UserID == request.user.ID, + TUVote.VoteID == voteinfo.ID)).first() + + if not request.user.is_trusted_user(): + context["error"] = "Only Trusted Users are allowed to vote." + elif voteinfo.User == request.user.Username: + context["error"] = "You cannot vote in an proposal about you." + elif vote is not None: + context["error"] = "You've already voted for this proposal." + + context["vote"] = vote + return render_proposal(request, context, proposal, voteinfo, voters, vote) + + +@router.post("/tu/{proposal}") +@auth_required(True, redirect="/") +@account_type_required(REQUIRED_TYPES) +async def trusted_user_proposal_post(request: Request, + proposal: int, + decision: str = Form(...)): + context = await make_variable_context(request, "Trusted User") + proposal = int(proposal) # Make sure it's an int. + + voteinfo = db.query(TUVoteInfo, TUVoteInfo.ID == proposal).first() + if not voteinfo: + raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) + + voters = db.query(User).join(TUVote).filter(TUVote.VoteID == voteinfo.ID) + + # status_code we'll use for responses later. + status_code = HTTPStatus.OK + + if not request.user.is_trusted_user(): + # Test: Create a proposal and view it as a "Developer". It + # should give us this error. + context["error"] = "Only Trusted Users are allowed to vote." + status_code = HTTPStatus.UNAUTHORIZED + elif voteinfo.User == request.user.Username: + context["error"] = "You cannot vote in an proposal about you." + status_code = HTTPStatus.BAD_REQUEST + + vote = db.query(TUVote, and_(TUVote.UserID == request.user.ID, + TUVote.VoteID == voteinfo.ID)).first() + + if status_code != HTTPStatus.OK: + return render_proposal(request, context, proposal, + voteinfo, voters, vote, + status_code=status_code) + + if vote is not None: + context["error"] = "You've already voted for this proposal." + status_code = HTTPStatus.BAD_REQUEST + + if status_code != HTTPStatus.OK: + return render_proposal(request, context, proposal, + voteinfo, voters, vote, + status_code=status_code) + + if decision in {"Yes", "No", "Abstain"}: + # Increment whichever decision was given to us. + setattr(voteinfo, decision, getattr(voteinfo, decision) + 1) + else: + return Response("Invalid 'decision' value.", + status_code=int(HTTPStatus.BAD_REQUEST)) + + vote = db.create(TUVote, User=request.user, VoteInfo=voteinfo, + autocommit=False) + voteinfo.ActiveTUs += 1 + db.commit() + + context["error"] = "You've already voted for this proposal." + return render_proposal(request, context, proposal, voteinfo, voters, vote) diff --git a/templates/partials/tu/proposal/details.html b/templates/partials/tu/proposal/details.html new file mode 100644 index 00000000..3f15a6eb --- /dev/null +++ b/templates/partials/tu/proposal/details.html @@ -0,0 +1,106 @@ +

    {% trans %}Proposal Details{% endtrans %}

    + +{% if voteinfo.is_running() %} +

    + {% trans %}This vote is still running.{% endtrans %} +

    +{% endif %} + + +
    + + + {% set submitted = voteinfo.Submitted | dt | as_timezone(timezone) %} + {% set end = voteinfo.End | dt | as_timezone(timezone) %} + + +
    + {{ "End" | tr }}: + + {{ end.strftime("%Y-%m-%d %H:%M") }} + +
    + + {% if not voteinfo.is_running() %} +
    + {{ "Result" | tr }}: + {% if not voteinfo.ActiveTUs %} + {{ "unknown" | tr }} + {% elif accepted %} + + {{ "Accepted" | tr }} + + {% else %} + + {{ "Rejected" | tr }} + + {% endif %} +
    + {% endif %} +
    + +
    +

    + + {{ voteinfo.Agenda | replace("\n", "
    \n") | safe | e }} +

    +
    + + + + {% if not voteinfo.is_running() %} + + + + {% endif %} + + + + + + + + {% if not voteinfo.is_running() %} + + + + {% endif %} + + + + + +
    {{ "Yes" | tr }}{{ "No" | tr }}{{ "Abstain" | tr }}{{ "Total" | tr }}{{ "Voted" | tr }}{{ "Participation" | tr }}
    {{ voteinfo.Yes }}{{ voteinfo.No }}{{ voteinfo.Abstain }}{{ voteinfo.total_votes() }} + {% if not has_voted %} + + {{ "No" | tr }} + + {% else %} + + {{ "Yes" | tr }} + + {% endif %} + + {% if voteinfo.ActiveTUs %} + {{ (participation * 100) | number_format(2) }}% + {% else %} + {{ "unknown" | tr }} + {% endif %} +
    diff --git a/templates/partials/tu/proposal/form.html b/templates/partials/tu/proposal/form.html new file mode 100644 index 00000000..d783a622 --- /dev/null +++ b/templates/partials/tu/proposal/form.html @@ -0,0 +1,14 @@ + + +
    + + + +
    + diff --git a/templates/partials/tu/proposal/voters.html b/templates/partials/tu/proposal/voters.html new file mode 100644 index 00000000..2fd42bdf --- /dev/null +++ b/templates/partials/tu/proposal/voters.html @@ -0,0 +1,10 @@ +

    {{ "Voters" | tr }}

    + diff --git a/templates/tu/show.html b/templates/tu/show.html new file mode 100644 index 00000000..ca5cbe63 --- /dev/null +++ b/templates/tu/show.html @@ -0,0 +1,20 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    + {% include "partials/tu/proposal/details.html" %} +
    + +
    + {% include "partials/tu/proposal/voters.html" %} +
    + +
    + {% if error %} + {{ error | tr }} + {% else %} + {% include "partials/tu/proposal/form.html" %} + {% endif %} +
    + +{% endblock %} diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index a6527e6f..73cea9bf 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -18,6 +18,7 @@ from aurweb.testing import setup_test_db from aurweb.testing.requests import Request DATETIME_REGEX = r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$' +PARTICIPATION_REGEX = r'^1?[0-9]{2}[%]$' # 0% - 100% def parse_root(html): @@ -103,6 +104,26 @@ def user(): AccountType=user_type) +@pytest.fixture +def proposal(tu_user): + ts = int(datetime.utcnow().timestamp()) + agenda = "Test proposal." + start = ts - 5 + end = ts + 1000 + + user_type = db.query(AccountType, + AccountType.AccountType == "User").first() + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=user_type) + + voteinfo = db.create(TUVoteInfo, + Agenda=agenda, Quorum=0.0, + User=user.Username, Submitter=tu_user, + Submitted=start, End=end) + yield (tu_user, user, voteinfo) + + def test_tu_index_guest(client): with client as request: response = request.get("/tu", allow_redirects=False) @@ -441,3 +462,270 @@ def test_tu_index_last_votes(client, tu_user, user): assert user.text.strip() == tu_user.Username assert int(vote_id.text.strip()) == voteinfo.ID + + +def test_tu_proposal_not_found(client, tu_user): + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get("/tu", params={"id": 1}, cookies=cookies) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_tu_running_proposal(client, proposal): + tu_user, user, voteinfo = proposal + + # Initiate an authenticated GET request to /tu/{proposal_id}. + proposal_id = voteinfo.ID + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get(f"/tu/{proposal_id}", cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + # Alright, now let's continue on to verifying some markup. + # First, let's verify that the proposal details match. + root = parse_root(response.text) + details = root.xpath('//div[@class="proposal details"]')[0] + + vote_running = root.xpath('//p[contains(@class, "vote-running")]')[0] + assert vote_running.text.strip() == "This vote is still running." + + # Verify User field. + username = details.xpath( + './div[contains(@class, "user")]/strong/a/text()')[0] + assert username.strip() == user.Username + + submitted = details.xpath( + './div[contains(@class, "submitted")]/text()')[0] + assert re.match(r'^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} by .+$', + submitted.strip()) is not None + + end = details.xpath('./div[contains(@class, "end")]')[0] + end_label = end.xpath("./text()")[0] + assert end_label.strip() == "End:" + + end_datetime = end.xpath("./strong/text()")[0] + assert re.match(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$', + end_datetime.strip()) is not None + + # We have not voted yet. Assert that our voting form is shown. + form = root.xpath('//form[contains(@class, "action-form")]')[0] + fields = form.xpath("./fieldset")[0] + buttons = fields.xpath('./button[@name="decision"]') + assert len(buttons) == 3 + + # Check the button names and values. + yes, no, abstain = buttons + + # Yes + assert yes.attrib["name"] == "decision" + assert yes.attrib["value"] == "Yes" + + # No + assert no.attrib["name"] == "decision" + assert no.attrib["value"] == "No" + + # Abstain + assert abstain.attrib["name"] == "decision" + assert abstain.attrib["value"] == "Abstain" + + # Create a vote. + db.create(TUVote, VoteInfo=voteinfo, User=tu_user) + voteinfo.ActiveTUs += 1 + voteinfo.Yes += 1 + db.commit() + + # Make another request now that we've voted. + with client as request: + response = request.get( + "/tu", params={"id": voteinfo.ID}, cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + # Parse our new root. + root = parse_root(response.text) + + # Check that we no longer have a voting form. + form = root.xpath('//form[contains(@class, "action-form")]') + assert not form + + # Check that we're told we've voted. + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "You've already voted for this proposal." + + +def test_tu_ended_proposal(client, proposal): + tu_user, user, voteinfo = proposal + + ts = int(datetime.utcnow().timestamp()) + voteinfo.End = ts - 5 # 5 seconds ago. + db.commit() + + # Initiate an authenticated GET request to /tu/{proposal_id}. + proposal_id = voteinfo.ID + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get(f"/tu/{proposal_id}", cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + # Alright, now let's continue on to verifying some markup. + # First, let's verify that the proposal details match. + root = parse_root(response.text) + details = root.xpath('//div[@class="proposal details"]')[0] + + vote_running = root.xpath('//p[contains(@class, "vote-running")]') + assert not vote_running + + result_node = details.xpath('./div[contains(@class, "result")]')[0] + result_label = result_node.xpath("./text()")[0] + assert result_label.strip() == "Result:" + + result = result_node.xpath("./span/text()")[0] + assert result.strip() == "unknown" + + # Check that voting has ended. + form = root.xpath('//form[contains(@class, "action-form")]') + assert not form + + # We should see a status about it. + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "Voting is closed for this proposal." + + +def test_tu_proposal_vote_not_found(client, tu_user): + """ Test POST request to a missing vote. """ + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + data = {"decision": "Yes"} + response = request.post("/tu/1", cookies=cookies, + data=data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_tu_proposal_vote(client, proposal): + tu_user, user, voteinfo = proposal + + # Store the current related values. + yes = voteinfo.Yes + active_tus = voteinfo.ActiveTUs + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + data = {"decision": "Yes"} + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data) + assert response.status_code == int(HTTPStatus.OK) + + # Check that the proposal record got updated. + assert voteinfo.Yes == yes + 1 + assert voteinfo.ActiveTUs == active_tus + 1 + + # Check that the new TUVote exists. + vote = db.query(TUVote, TUVote.VoteInfo == voteinfo, + TUVote.User == tu_user).first() + assert vote is not None + + root = parse_root(response.text) + + # Check that we're told we've voted. + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "You've already voted for this proposal." + + +def test_tu_proposal_vote_unauthorized(client, proposal): + tu_user, user, voteinfo = proposal + + dev_type = db.query(AccountType, + AccountType.AccountType == "Developer").first() + tu_user.AccountType = dev_type + db.commit() + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + data = {"decision": "Yes"} + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.UNAUTHORIZED) + + root = parse_root(response.text) + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "Only Trusted Users are allowed to vote." + + with client as request: + data = {"decision": "Yes"} + response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "Only Trusted Users are allowed to vote." + + +def test_tu_proposal_vote_cant_self_vote(client, proposal): + tu_user, user, voteinfo = proposal + + # Update voteinfo.User. + voteinfo.User = tu_user.Username + db.commit() + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + data = {"decision": "Yes"} + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + root = parse_root(response.text) + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "You cannot vote in an proposal about you." + + with client as request: + data = {"decision": "Yes"} + response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "You cannot vote in an proposal about you." + + +def test_tu_proposal_vote_already_voted(client, proposal): + tu_user, user, voteinfo = proposal + + db.create(TUVote, VoteInfo=voteinfo, User=tu_user) + voteinfo.Yes += 1 + voteinfo.ActiveTUs += 1 + db.commit() + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + data = {"decision": "Yes"} + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + + root = parse_root(response.text) + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "You've already voted for this proposal." + + with client as request: + data = {"decision": "Yes"} + response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + status = root.xpath('//span[contains(@class, "status")]/text()')[0] + assert status == "You've already voted for this proposal." + + +def test_tu_proposal_vote_invalid_decision(client, proposal): + tu_user, user, voteinfo = proposal + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + data = {"decision": "EVIL"} + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, + data=data) + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + assert response.text == "Invalid 'decision' value." diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index bb4e3ad7..2748462f 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -204,3 +204,11 @@ label.confirmation, overflow: hidden; transition: height 1s; } + +.proposal.details { + margin: .33em 0 1em; +} + +button[type="submit"] { + padding: 0 0.6em; +} From bfffdd4d912eb012f947a81ff4c51489015fa2df Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Jun 2021 04:13:28 -0700 Subject: [PATCH 0764/1891] aurweb.asgi: Allow unsafe-inline style-src in CSP Signed-off-by: Kevin Morris --- aurweb/asgi.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 35166c73..26893232 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -88,6 +88,8 @@ async def add_security_headers(request: Request, call_next: typing.Callable): "cdn.jsdelivr.net" ] csp += f"script-src 'self' 'nonce-{nonce}' " + ' '.join(script_hosts) + # It's fine if css is inlined. + csp += f"; style-src 'self' 'unsafe-inline'" response.headers["Content-Security-Policy"] = csp # Add XTCO header. From 04ab98907aa6b7e432bbc3b0bd71462bf9ecd513 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Jun 2021 04:20:55 -0700 Subject: [PATCH 0765/1891] aurweb.asgi: patch invalid f-string Signed-off-by: Kevin Morris --- aurweb/asgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 26893232..228b9a65 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -89,7 +89,7 @@ async def add_security_headers(request: Request, call_next: typing.Callable): ] csp += f"script-src 'self' 'nonce-{nonce}' " + ' '.join(script_hosts) # It's fine if css is inlined. - csp += f"; style-src 'self' 'unsafe-inline'" + csp += "; style-src 'self' 'unsafe-inline'" response.headers["Content-Security-Policy"] = csp # Add XTCO header. From 97c1247b577adb13fac793577d411f0f2be9274a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 26 Jun 2021 04:43:00 -0700 Subject: [PATCH 0766/1891] /tu/{proposal_id}: Do not show voters if there are none This was different than PHP. Signed-off-by: Kevin Morris --- aurweb/routers/trusted_user.py | 2 +- templates/tu/show.html | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index efdcfc73..55f7b7e1 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -111,7 +111,7 @@ def render_proposal(request: Request, """ Render a single TU proposal. """ context["proposal"] = proposal context["voteinfo"] = voteinfo - context["voters"] = voters + context["voters"] = voters.all() participation = voteinfo.ActiveTUs / voteinfo.total_votes() \ if voteinfo.total_votes() else 0 diff --git a/templates/tu/show.html b/templates/tu/show.html index ca5cbe63..ff2d4bb6 100644 --- a/templates/tu/show.html +++ b/templates/tu/show.html @@ -4,10 +4,12 @@
    {% include "partials/tu/proposal/details.html" %}
    - -
    - {% include "partials/tu/proposal/voters.html" %} -
    + + {% if voters %} +
    + {% include "partials/tu/proposal/voters.html" %} +
    + {% endif %}
    {% if error %} From 83f93c8dbb1bc823fa8bcc3966d572255dc742e2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 27 Jun 2021 03:54:13 -0700 Subject: [PATCH 0767/1891] aurweb.routers.accounts: strip host out of ssh pubkeys We must store the paired key, otherwise aurweb-git-auth will fail. Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 3e3469ca..36871595 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -1,4 +1,5 @@ import copy +import logging import typing from datetime import datetime @@ -24,6 +25,7 @@ from aurweb.scripts.notify import ResetKeyNotification from aurweb.templates import make_variable_context, render_template router = APIRouter() +logger = logging.getLogger(__name__) @router.get("/passreset", response_class=HTMLResponse) @@ -402,6 +404,10 @@ async def account_register_post(request: Request, if PK: # Get the second element in the PK, which is the actual key. pubkey = PK.strip().rstrip() + parts = pubkey.split(" ") + if len(parts) == 3: + # Remove the host part. + pubkey = parts[0] + " " + parts[1] fingerprint = get_fingerprint(pubkey) user.ssh_pub_key = SSHPubKey(UserID=user.ID, PubKey=pubkey, @@ -522,15 +528,19 @@ async def account_edit_post(request: Request, if PK: # Get the second token in the public key, which is the actual key. pubkey = PK.strip().rstrip() + parts = pubkey.split(" ") + if len(parts) == 3: + # Remove the host part. + pubkey = parts[0] + " " + parts[1] fingerprint = get_fingerprint(pubkey) if not user.ssh_pub_key: # No public key exists, create one. user.ssh_pub_key = SSHPubKey(UserID=user.ID, - PubKey=PK, + PubKey=pubkey, Fingerprint=fingerprint) - elif user.ssh_pub_key.Fingerprint != fingerprint: + elif user.ssh_pub_key.PubKey != pubkey: # A public key already exists, update it. - user.ssh_pub_key.PubKey = PK + user.ssh_pub_key.PubKey = pubkey user.ssh_pub_key.Fingerprint = fingerprint elif user.ssh_pub_key: # Else, if the user has a public key already, delete it. From 0a3aa40f209e755f4a345ff86015d7a42acdb1f4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 27 Jun 2021 05:16:12 -0700 Subject: [PATCH 0768/1891] Docker: Fix `git` sshd This was completely bugged out. This commit fixes git, provides two separate cgit servers for the different URL bases and also supplies a smartgit service for $AURWEB_URL/repo.git interaction. Docker image needs to be rebuilt with this change: $ docker build -t aurweb:latest . Signed-off-by: Kevin Morris --- Dockerfile | 11 +++-- docker-compose.yml | 72 +++++++++++++++++++++++++----- docker/cgit-entrypoint.sh | 7 ++- docker/fastapi-entrypoint.sh | 3 ++ docker/git-entrypoint.sh | 81 +++++++++++++++++++++++++++------- docker/health/cgit.sh | 2 +- docker/health/smartgit.sh | 2 + docker/health/sshd.sh | 5 ++- docker/nginx-entrypoint.sh | 38 ++++++++++++++-- docker/php-entrypoint.sh | 3 ++ docker/scripts/run-cgit.sh | 4 ++ docker/scripts/run-smartgit.sh | 9 ++++ docker/scripts/run-sshd.sh | 2 +- docker/smartgit-entrypoint.sh | 4 ++ 14 files changed, 202 insertions(+), 41 deletions(-) create mode 100755 docker/health/smartgit.sh create mode 100755 docker/scripts/run-cgit.sh create mode 100755 docker/scripts/run-smartgit.sh create mode 100755 docker/smartgit-entrypoint.sh diff --git a/Dockerfile b/Dockerfile index da9c8d3b..4141a4c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,6 @@ FROM archlinux:base-devel +ENV PYTHONPATH=/aurweb +ENV AUR_CONFIG=conf/config # Setup some default system stuff. RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime @@ -16,7 +18,7 @@ RUN pacman -Syu --noconfirm --noprogressbar \ python-pytest-asyncio python-coverage hypercorn python-bcrypt \ python-email-validator openssh python-lxml mariadb mariadb-libs \ python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ - python-asgiref uvicorn + python-asgiref uvicorn python-pip python-wheel RUN useradd -U -d /aurweb -c 'AUR User' aur @@ -25,6 +27,9 @@ COPY docker /docker WORKDIR /aurweb COPY . . -ENV PYTHONPATH=/aurweb - RUN make -C po all install +RUN pip3 install -t /aurweb/app --upgrade -I . + +# Set permissions on directories and binaries. +RUN bash -c 'find /aurweb/app -type d -exec chmod 755 {} \;' +RUN chmod 755 /aurweb/app/bin/* diff --git a/docker-compose.yml b/docker-compose.yml index 795236c7..6bf36166 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,33 +50,77 @@ services: image: aurweb:latest init: true environment: - - AUR_CONFIG=conf/config + - AUR_CONFIG=/aurweb/conf/config entrypoint: /docker/git-entrypoint.sh command: /docker/scripts/run-sshd.sh ports: - - "2222:22" + - "2222:2222" healthcheck: test: "bash /docker/health/sshd.sh" interval: 2s timeout: 30s + depends_on: + mariadb: + condition: service_healthy + links: + - mariadb volumes: - mariadb_run:/var/run/mysqld - mariadb_data:/var/lib/mysql - git_data:/aurweb/aur.git - ./cache:/cache - cgit: + smartgit: + image: aurweb:latest + init: true + environment: + - AUR_CONFIG=/aurweb/conf/config + entrypoint: /docker/smartgit-entrypoint.sh + command: /docker/scripts/run-smartgit.sh + healthcheck: + test: "bash /docker/health/smartgit.sh" + interval: 2s + timeout: 30s + depends_on: + mariadb: + condition: service_healthy + links: + - mariadb + volumes: + - mariadb_run:/var/run/mysqld + - mariadb_data:/var/lib/mysql + - git_data:/aurweb/aur.git + - ./cache:/cache + - smartgit_run:/var/run/smartgit + + cgit-php: image: aurweb:latest init: true environment: - AUR_CONFIG=/aurweb/conf/config entrypoint: /docker/cgit-entrypoint.sh - command: >- - uwsgi --socket 0.0.0.0:3000 - --plugins cgi - --cgi /usr/share/webapps/cgit/cgit.cgi + command: /docker/scripts/run-cgit.sh 3000 "https://localhost:8443/cgit" healthcheck: - test: "bash /docker/health/cgit.sh" + test: "bash /docker/health/cgit.sh 3000" + interval: 2s + timeout: 30s + depends_on: + git: + condition: service_healthy + links: + - git + volumes: + - git_data:/aurweb/aur.git + + cgit-fastapi: + image: aurweb:latest + init: true + environment: + - AUR_CONFIG=/aurweb/conf/config + entrypoint: /docker/cgit-entrypoint.sh + command: /docker/scripts/run-cgit.sh 3000 "https://localhost:8444/cgit" + healthcheck: + test: "bash /docker/health/cgit.sh 3000" interval: 2s timeout: 30s depends_on: @@ -170,14 +214,20 @@ services: interval: 2s timeout: 30s depends_on: - cgit: + cgit-php: + condition: service_healthy + cgit-fastapi: + condition: service_healthy + smartgit: condition: service_healthy fastapi: condition: service_healthy php-fpm: condition: service_healthy links: - - cgit + - cgit-php + - cgit-fastapi + - smartgit - fastapi - php-fpm volumes: @@ -187,6 +237,7 @@ services: - ./web/html:/aurweb/web/html - ./web/template:/aurweb/web/template - ./web/lib:/aurweb/web/lib + - smartgit_run:/var/run/smartgit sharness: image: aurweb:latest @@ -298,3 +349,4 @@ volumes: mariadb_run: {} # Share /var/run/mysqld/mysqld.sock mariadb_data: {} # Share /var/lib/mysql git_data: {} # Share aurweb/aur.git + smartgit_run: {} diff --git a/docker/cgit-entrypoint.sh b/docker/cgit-entrypoint.sh index e05e1b7a..9abc5091 100755 --- a/docker/cgit-entrypoint.sh +++ b/docker/cgit-entrypoint.sh @@ -1,13 +1,12 @@ #!/bin/bash set -eou pipefail -cp -vf conf/cgitrc.proto /etc/cgitrc +mkdir -p /var/cache/cgit -sed -ri 's|clone-prefix=.*|clone-prefix=https://localhost:8443|' /etc/cgitrc +cp -vf conf/cgitrc.proto /etc/cgitrc +sed -ri "s|clone-prefix=.*|clone-prefix=${2}|" /etc/cgitrc sed -ri 's|header=.*|header=/aurweb/web/template/cgit/header.html|' /etc/cgitrc sed -ri 's|footer=.*|footer=/aurweb/web/template/cgit/footer.html|' /etc/cgitrc sed -ri 's|repo\.path=.*|repo.path=/aurweb/aur.git|' /etc/cgitrc -mkdir -p /var/cache/cgit - exec "$@" diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index 2f04c29f..11b8ac5a 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -7,4 +7,7 @@ bash $dir/test-mysql-entrypoint.sh sed -ri "s;^(aur_location) = .+;\1 = https://localhost:8444;" conf/config sed -ri 's/^(name) = .+/\1 = aurweb/' conf/config +sed -ri "s|^(git_clone_uri_anon) = .+|\1 = https://localhost:8444/cgit/aur.git -b %s|" conf/config.defaults +sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ssh://aur@localhost:2222/%s.git|" conf/config.defaults + exec "$@" diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index d17ceeaf..e6d3ad97 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -2,44 +2,91 @@ set -eou pipefail SSHD_CONFIG=/etc/ssh/sshd_config +AUTH_SCRIPT=/aurweb/app/git-auth.sh -GIT_REPO=aur.git -GIT_KEY=/cache/git.key +GIT_REPO=/aurweb/aur.git +GIT_BRANCH=master # 'Master' branch. -# Setup SSH Keys. -ssh-keygen -A +if ! grep -q 'PYTHONPATH' /etc/environment; then + echo "PYTHONPATH='/aurweb:/aurweb/app'" >> /etc/environment +else + sed -ri "s|^(PYTHONPATH)=.*$|\1='/aurweb:/aurweb/app'|" /etc/environment +fi + +if ! grep -q 'AUR_CONFIG' /etc/environment; then + echo "AUR_CONFIG='/aurweb/conf/config'" >> /etc/environment +else + sed -ri "s|^(AUR_CONFIG)=.*$|\1='/aurweb/conf/config'|" /etc/environment +fi + +if ! grep -q '/aurweb/app/bin' /etc/environment; then + echo "PATH='/aurweb/app/bin:\${PATH}'" >> /etc/environment +fi # Add AUR SSH config. cat >> $SSHD_CONFIG << EOF Match User aur PasswordAuthentication no - AuthorizedKeysCommand /usr/local/bin/aurweb-git-auth "%t" "%k" + AuthorizedKeysCommand $AUTH_SCRIPT "%t" "%k" AuthorizedKeysCommandUser aur AcceptEnv AUR_OVERWRITE - SetEnv AUR_CONFIG=/aurweb/config/config EOF +cat >> $AUTH_SCRIPT << EOF +#!/usr/bin/env bash +export PYTHONPATH="$PYTHONPATH" +export AUR_CONFIG="$AUR_CONFIG" +export PATH="/aurweb/app/bin:\${PATH}" + +exec /aurweb/app/bin/aurweb-git-auth "\$@" +EOF +chmod 755 $AUTH_SCRIPT + +DB_NAME="aurweb" +DB_HOST="mariadb" +DB_USER="aur" +DB_PASS="aur" + +# Setup a config for our mysql db. +cp -vf conf/config.dev $AUR_CONFIG +sed -i "s;YOUR_AUR_ROOT;$(pwd);g" $AUR_CONFIG +sed -ri "s/^(name) = .+/\1 = ${DB_NAME}/" $AUR_CONFIG +sed -ri "s/^(host) = .+/\1 = ${DB_HOST}/" $AUR_CONFIG +sed -ri "s/^(user) = .+/\1 = ${DB_USER}/" $AUR_CONFIG +sed -ri "s/^;?(password) = .+/\1 = ${DB_PASS}/" $AUR_CONFIG +sed -i "s|/usr/local/bin|/aurweb/app/bin|g" $AUR_CONFIG + +AUR_CONFIG_DEFAULTS="${AUR_CONFIG}.defaults" + +if [[ "$AUR_CONFIG_DEFAULTS" != "/aurweb/conf/config.defaults" ]]; then + cp -vf conf/config.defaults $AUR_CONFIG_DEFAULTS +fi + +# Set some defaults needed for pathing and ssh uris. +sed -i "s|/usr/local/bin|/aurweb/app/bin|g" $AUR_CONFIG_DEFAULTS +sed -ri "s|^(repo-path) = .+|\1 = /aurweb/aur.git/|" $AUR_CONFIG_DEFAULTS + +ssh_cmdline='ssh ssh://aur@localhost:2222' +sed -ri "s|^(ssh-cmdline) = .+|\1 = $ssh_cmdline|" $AUR_CONFIG_DEFAULTS + +# Setup SSH Keys. +ssh-keygen -A + # Taken from INSTALL. mkdir -pv $GIT_REPO # Initialize git repository. if [ ! -f $GIT_REPO/config ]; then + curdir="$(pwd)" cd $GIT_REPO + git config --global init.defaultBranch $GIT_BRANCH git init --bare git config --local transfer.hideRefs '^refs/' git config --local --add transfer.hideRefs '!refs/' git config --local --add transfer.hideRefs '!HEAD' - ln -sf /usr/local/bin/aurweb-git-update hooks/update - chown -R aur . - cd .. + ln -sf /aurweb/app/bin/aurweb-git-update hooks/update + cd $curdir + chown -R aur:aur $GIT_REPO fi -if [ ! -f $GIT_KEY ]; then - # Create a DSA ssh private/pubkey at /cache/git.key{.pub,}. - ssh-keygen -f $GIT_KEY -t dsa -N '' -C 'AUR Git Key' -fi - -# Users should modify these permissions on their local machines. -chmod 666 ${GIT_KEY}{.pub,} - exec "$@" diff --git a/docker/health/cgit.sh b/docker/health/cgit.sh index add33031..2f0cfeb1 100755 --- a/docker/health/cgit.sh +++ b/docker/health/cgit.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec printf "" >>/dev/tcp/127.0.0.1/3000 +exec printf "" >>/dev/tcp/127.0.0.1/${1} diff --git a/docker/health/smartgit.sh b/docker/health/smartgit.sh new file mode 100755 index 00000000..b4e7ebd4 --- /dev/null +++ b/docker/health/smartgit.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec pgrep uwsgi diff --git a/docker/health/sshd.sh b/docker/health/sshd.sh index 6befdfb5..d9da9ea1 100755 --- a/docker/health/sshd.sh +++ b/docker/health/sshd.sh @@ -1,2 +1,5 @@ #!/bin/bash -exec printf "" >>/dev/tcp/127.0.0.1/22 +# Opt to just pgrep sshd instead of connecting here. This health +# script is used on a regular interval and it ends up spamming +# the git service's logs with accesses. +exec pgrep sshd diff --git a/docker/nginx-entrypoint.sh b/docker/nginx-entrypoint.sh index 1e442ef7..238cd167 100755 --- a/docker/nginx-entrypoint.sh +++ b/docker/nginx-entrypoint.sh @@ -45,8 +45,16 @@ http { server fastapi:8000; } - upstream cgit { - server cgit:3000; + upstream cgit-php { + server cgit-php:3000; + } + + upstream cgit-fastapi { + server cgit-fastapi:3000; + } + + upstream smartgit { + server unix:/var/run/smartgit/smartgit.sock; } server { @@ -59,12 +67,23 @@ http { root /aurweb/web/html; index index.php; + location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { + include uwsgi_params; + uwsgi_pass smartgit; + uwsgi_modifier1 9; + uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; + uwsgi_param PATH_INFO /aur.git/\$3; + uwsgi_param GIT_HTTP_EXPORT_ALL ""; + uwsgi_param GIT_NAMESPACE \$1; + uwsgi_param GIT_PROJECT_ROOT /aurweb; + } + location ~ ^/cgit { include uwsgi_params; rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=\$1&\$2 last; uwsgi_modifier1 9; uwsgi_param CGIT_CONFIG /etc/cgitrc; - uwsgi_pass uwsgi://cgit; + uwsgi_pass uwsgi://cgit-php; } location ~ ^/[^/]+\.php($|/) { @@ -95,12 +114,23 @@ http { try_files \$uri @proxy_to_app; } + location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { + include uwsgi_params; + uwsgi_pass smartgit; + uwsgi_modifier1 9; + uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; + uwsgi_param PATH_INFO /aur.git/\$3; + uwsgi_param GIT_HTTP_EXPORT_ALL ""; + uwsgi_param GIT_NAMESPACE \$1; + uwsgi_param GIT_PROJECT_ROOT /aurweb; + } + location ~ ^/cgit { include uwsgi_params; rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=\$1&\$2 last; uwsgi_modifier1 9; uwsgi_param CGIT_CONFIG /etc/cgitrc; - uwsgi_pass uwsgi://cgit; + uwsgi_pass uwsgi://cgit-fastapi; } location @proxy_to_app { diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index 19c6d059..4d49ef17 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -7,6 +7,9 @@ bash $dir/test-mysql-entrypoint.sh sed -ri "s;^(aur_location) = .+;\1 = https://localhost:8443;" conf/config sed -ri 's/^(name) = .+/\1 = aurweb/' conf/config +sed -ri "s|^(git_clone_uri_anon) = .+|\1 = https://localhost:8443/cgit/aur.git -b %s|" conf/config.defaults +sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ssh://aur@localhost:2222/%s.git|" conf/config.defaults + sed -ri 's/^(listen).*/\1 = 0.0.0.0:9000/' /etc/php/php-fpm.d/www.conf sed -ri 's/^;?(clear_env).*/\1 = no/' /etc/php/php-fpm.d/www.conf diff --git a/docker/scripts/run-cgit.sh b/docker/scripts/run-cgit.sh new file mode 100755 index 00000000..67bdc079 --- /dev/null +++ b/docker/scripts/run-cgit.sh @@ -0,0 +1,4 @@ +#!/bin/bash +exec uwsgi --socket 0.0.0.0:${1} \ + --plugins cgi \ + --cgi /usr/share/webapps/cgit/cgit.cgi diff --git a/docker/scripts/run-smartgit.sh b/docker/scripts/run-smartgit.sh new file mode 100755 index 00000000..b6869a6c --- /dev/null +++ b/docker/scripts/run-smartgit.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +exec uwsgi \ + --socket /var/run/smartgit/smartgit.sock \ + --uid root \ + --gid http \ + --chmod-socket=666 \ + --plugins cgi \ + --cgi /usr/lib/git-core/git-http-backend diff --git a/docker/scripts/run-sshd.sh b/docker/scripts/run-sshd.sh index a69af7e2..d488e80d 100755 --- a/docker/scripts/run-sshd.sh +++ b/docker/scripts/run-sshd.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec /usr/sbin/sshd -D +exec /usr/sbin/sshd -e -p 2222 -D diff --git a/docker/smartgit-entrypoint.sh b/docker/smartgit-entrypoint.sh new file mode 100755 index 00000000..daa9edeb --- /dev/null +++ b/docker/smartgit-entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eou pipefail + +exec "$@" From 12911a101e8a5adb4097ed503c3923bedaf98fa9 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sun, 27 Jun 2021 13:55:51 +0200 Subject: [PATCH 0769/1891] Port homepage intro to fastapi Port the main home page content to fastapi. --- aurweb/config.py | 6 +++ aurweb/routers/html.py | 2 + aurweb/util.py | 10 +++++ templates/index.html | 92 ++++++++++++++++++++++++++++++++++++++++++ test/test_homepage.py | 36 +++++++++++++++++ 5 files changed, 146 insertions(+) create mode 100644 test/test_homepage.py diff --git a/aurweb/config.py b/aurweb/config.py index 73db58dc..52fadda2 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -46,3 +46,9 @@ def getboolean(section, option): def getint(section, option, fallback=None): return _get_parser().getint(section, option, fallback=fallback) + + +def get_section(section_name): + for section in _get_parser().sections(): + if section == section_name: + return _get_parser()[section] diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 580ee0d4..f6f1a54e 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -58,6 +58,8 @@ async def language(request: Request, async def index(request: Request): """ Homepage route. """ context = make_context(request, "Home") + context['ssh_fingerprints'] = util.get_ssh_fingerprints() + return render_template(request, "index.html", context) diff --git a/aurweb/util.py b/aurweb/util.py index 539af40e..d4a0b221 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -172,3 +172,13 @@ def add_samesite_fields(response: Response, value: str): cookie += f"; SameSite={value}" response.raw_headers[idx] = (header[0], cookie.encode()) return response + + +def get_ssh_fingerprints(): + fingerprints = {} + fingerprint_section = aurweb.config.get_section("fingerprints") + + if fingerprint_section: + fingerprints = {key: fingerprint_section[key] for key in fingerprint_section.keys()} + + return fingerprints diff --git a/templates/index.html b/templates/index.html index 27d3375d..8cd1cc78 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,4 +1,96 @@ {% extends 'partials/layout.html' %} {% block pageContent %} +
    +

    AUR {% trans %}Home{% endtrans %}

    +

    + {{ "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU Guidelines%s for more information." + | tr + | format('', "", + '', "") + | safe + }} + {{ "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s otherwise they will be deleted!" + | tr + | format("", "", + '', + "") + | safe + }} + {% trans %}Remember to vote for your favourite packages!{% endtrans %} + {% trans %}Some packages may be provided as binaries in [community].{% endtrans %} +

    + {% trans %}DISCLAIMER{% endtrans %}: + {% trans %}AUR packages are user produced content. Any use of the provided files is at your own risk.{% endtrans %} +

    +

    {% trans %}Learn more...{% endtrans %}

    +

    +
    +
    +

    {% trans %}Support{% endtrans %}

    +

    {% trans %}Package Requests{% endtrans %}

    +
    +

    + {{ "There are three types of requests that can be filed in the %sPackage Actions%s box on the package details page:" + | tr + | format("", "") + | safe + }} +

    +
      +
    • {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
    • +
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
    • +
    • {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}
    • +
    +

    + {{ "If you want to discuss a request, you can use the %saur-requests%s mailing list. However, please do not use that list to file requests." + | tr + | format('', "") + | safe + }} +

    +
    +

    {% trans %}Submitting Packages{% endtrans %}

    +
    +

    + {{ "Git over SSH is now used to submit packages to the AUR. See the %sSubmitting packages%s section of the Arch User Repository ArchWiki page for more details." + | tr + | format('', "") + | safe + }} +

    + {% if ssh_fingerprints %} +

    + {% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %} +

    +

      + {% for keytype in ssh_fingerprints %} +
    • {{ keytype }}: {{ ssh_fingerprints[keytype] }} + {% endfor %} +
    + {% endif %} +
    +

    {% trans %}Discussion{% endtrans %}

    +
    +

    + {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." + | tr + | format('', "", + '', "") + | safe + }} +

    +

    +

    {% trans %}Bug Reporting{% endtrans %}

    +
    +

    + {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page." + | tr + | format('', "", + "", "") + | safe + }} +

    +
    +
    {% endblock %} diff --git a/test/test_homepage.py b/test/test_homepage.py new file mode 100644 index 00000000..23d7185f --- /dev/null +++ b/test/test_homepage.py @@ -0,0 +1,36 @@ +from http import HTTPStatus +from unittest.mock import patch + +from fastapi.testclient import TestClient + +from aurweb.asgi import app + +client = TestClient(app) + + +def test_homepage(): + with client as request: + response = request.get("/") + assert response.status_code == int(HTTPStatus.OK) + + +@patch('aurweb.util.get_ssh_fingerprints') +def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock): + fingerprints = {'Ed25519': "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"} + get_ssh_fingerprints_mock.return_value = fingerprints + + with client as request: + response = request.get("/") + + assert list(fingerprints.values())[0] in response.content.decode() + assert 'The following SSH fingerprints are used for the AUR' in response.content.decode() + + +@patch('aurweb.util.get_ssh_fingerprints') +def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock): + get_ssh_fingerprints_mock.return_value = {} + + with client as request: + response = request.get("/") + + assert 'The following SSH fingerprints are used for the AUR' not in response.content.decode() From acc100eb5220169b257d33e40818ab9361ecb5e5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 27 Jun 2021 06:26:18 -0700 Subject: [PATCH 0770/1891] Docker: Fix installation, remove pip, simplify sshd Signed-off-by: Kevin Morris --- Dockerfile | 8 ++------ docker/git-entrypoint.sh | 28 +++++++++++----------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4141a4c9..cec36158 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN pacman -Syu --noconfirm --noprogressbar \ python-pytest-asyncio python-coverage hypercorn python-bcrypt \ python-email-validator openssh python-lxml mariadb mariadb-libs \ python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ - python-asgiref uvicorn python-pip python-wheel + python-asgiref uvicorn RUN useradd -U -d /aurweb -c 'AUR User' aur @@ -28,8 +28,4 @@ WORKDIR /aurweb COPY . . RUN make -C po all install -RUN pip3 install -t /aurweb/app --upgrade -I . - -# Set permissions on directories and binaries. -RUN bash -c 'find /aurweb/app -type d -exec chmod 755 {} \;' -RUN chmod 755 /aurweb/app/bin/* +RUN python3 setup.py install --install-scripts=/usr/local/bin diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index e6d3ad97..89537853 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -2,7 +2,7 @@ set -eou pipefail SSHD_CONFIG=/etc/ssh/sshd_config -AUTH_SCRIPT=/aurweb/app/git-auth.sh +AUTH_SCRIPT=/app/git-auth.sh GIT_REPO=/aurweb/aur.git GIT_BRANCH=master # 'Master' branch. @@ -10,7 +10,7 @@ GIT_BRANCH=master # 'Master' branch. if ! grep -q 'PYTHONPATH' /etc/environment; then echo "PYTHONPATH='/aurweb:/aurweb/app'" >> /etc/environment else - sed -ri "s|^(PYTHONPATH)=.*$|\1='/aurweb:/aurweb/app'|" /etc/environment + sed -ri "s|^(PYTHONPATH)=.*$|\1='/aurweb'|" /etc/environment fi if ! grep -q 'AUR_CONFIG' /etc/environment; then @@ -19,9 +19,15 @@ else sed -ri "s|^(AUR_CONFIG)=.*$|\1='/aurweb/conf/config'|" /etc/environment fi -if ! grep -q '/aurweb/app/bin' /etc/environment; then - echo "PATH='/aurweb/app/bin:\${PATH}'" >> /etc/environment -fi +mkdir -p /app +chmod 755 /app + +cat >> $AUTH_SCRIPT << EOF +#!/usr/bin/env bash +export AUR_CONFIG="$AUR_CONFIG" +exec /usr/local/bin/aurweb-git-auth "\$@" +EOF +chmod 755 $AUTH_SCRIPT # Add AUR SSH config. cat >> $SSHD_CONFIG << EOF @@ -32,16 +38,6 @@ Match User aur AcceptEnv AUR_OVERWRITE EOF -cat >> $AUTH_SCRIPT << EOF -#!/usr/bin/env bash -export PYTHONPATH="$PYTHONPATH" -export AUR_CONFIG="$AUR_CONFIG" -export PATH="/aurweb/app/bin:\${PATH}" - -exec /aurweb/app/bin/aurweb-git-auth "\$@" -EOF -chmod 755 $AUTH_SCRIPT - DB_NAME="aurweb" DB_HOST="mariadb" DB_USER="aur" @@ -54,7 +50,6 @@ sed -ri "s/^(name) = .+/\1 = ${DB_NAME}/" $AUR_CONFIG sed -ri "s/^(host) = .+/\1 = ${DB_HOST}/" $AUR_CONFIG sed -ri "s/^(user) = .+/\1 = ${DB_USER}/" $AUR_CONFIG sed -ri "s/^;?(password) = .+/\1 = ${DB_PASS}/" $AUR_CONFIG -sed -i "s|/usr/local/bin|/aurweb/app/bin|g" $AUR_CONFIG AUR_CONFIG_DEFAULTS="${AUR_CONFIG}.defaults" @@ -63,7 +58,6 @@ if [[ "$AUR_CONFIG_DEFAULTS" != "/aurweb/conf/config.defaults" ]]; then fi # Set some defaults needed for pathing and ssh uris. -sed -i "s|/usr/local/bin|/aurweb/app/bin|g" $AUR_CONFIG_DEFAULTS sed -ri "s|^(repo-path) = .+|\1 = /aurweb/aur.git/|" $AUR_CONFIG_DEFAULTS ssh_cmdline='ssh ssh://aur@localhost:2222' From b2491ddc07fefe9612a14fb8ac9ed4bac9da8f79 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sun, 27 Jun 2021 17:25:46 +0200 Subject: [PATCH 0771/1891] Use type=email for email fields Setting the input type gives the use a hint that the field should be an email and also shows an error when a non-email is filled into the email field. --- templates/partials/account_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 5ae18131..6455c351 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -89,7 +89,7 @@ {% trans %}Email Address{% endtrans %}: - ({% trans %}required{% endtrans %})

    @@ -119,7 +119,7 @@ {% trans %}Backup Email Address{% endtrans %}: -

    From 222d995e95ebedab00169be9e44e161d36efc292 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sun, 27 Jun 2021 17:27:44 +0200 Subject: [PATCH 0772/1891] Use backup_email field for backup email The context gives backup_email and not backup for the backup email field. Fixes: #91 --- templates/partials/account_form.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 6455c351..05009594 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -120,7 +120,7 @@ + maxlength="254" name="BE" value="{{ backup_email }}">

    From a26e70334333c99ade535d92c5957fd19f7d796e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 04:04:52 -0700 Subject: [PATCH 0773/1891] bugfix: use empty string if backup_email is None Signed-off-by: Kevin Morris --- templates/partials/account_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 05009594..6374fd5e 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -90,7 +90,7 @@ + size="30" maxlength="254" name="E" value="{{ email or '' }}"> ({% trans %}required{% endtrans %})

    @@ -120,7 +120,7 @@ + maxlength="254" name="BE" value="{{ backup_email or '' }}">

    From 28300ee889f74eaf29fec5dc0bb2f4492375b0d2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 04:12:29 -0700 Subject: [PATCH 0774/1891] bugfix: populate context on invalid password (account edit) Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 36871595..5d798ae8 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -483,15 +483,15 @@ async def account_edit_post(request: Request, context = await make_variable_context(request, "Accounts") context["user"] = user + args = dict(await request.form()) + context = make_account_form_context(context, request, user, args) + ok, errors = process_account_form(request, user, args) + if not passwd: context["errors"] = ["Invalid password."] return render_template(request, "account/edit.html", context, status_code=int(HTTPStatus.BAD_REQUEST)) - args = dict(await request.form()) - context = make_account_form_context(context, request, user, args) - ok, errors = process_account_form(request, user, args) - if not ok: context["errors"] = errors return render_template(request, "account/edit.html", context, From 3c6b2203e92e8359f421aed5f421a8d6424fe8de Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 05:36:12 -0700 Subject: [PATCH 0775/1891] Docker: bugfix: /usr/local/bin instead of /aurweb/app/bin Signed-off-by: Kevin Morris --- docker/git-entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index 89537853..57752ac5 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -78,7 +78,7 @@ if [ ! -f $GIT_REPO/config ]; then git config --local transfer.hideRefs '^refs/' git config --local --add transfer.hideRefs '!refs/' git config --local --add transfer.hideRefs '!HEAD' - ln -sf /aurweb/app/bin/aurweb-git-update hooks/update + ln -sf /usr/local/bin/aurweb-git-update hooks/update cd $curdir chown -R aur:aur $GIT_REPO fi From f8d2d4c82a5fd442e10fa205811548cffea59da7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 08:22:34 -0700 Subject: [PATCH 0776/1891] PackageBase.package -> PackageBase.packages A PackageBase can have more than one package associated with it. Signed-off-by: Kevin Morris --- aurweb/models/package.py | 2 +- test/test_package.py | 18 +----------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/aurweb/models/package.py b/aurweb/models/package.py index ff518f20..e8159d85 100644 --- a/aurweb/models/package.py +++ b/aurweb/models/package.py @@ -17,7 +17,7 @@ class Package(Base): Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), nullable=False) PackageBase = relationship( - "PackageBase", backref=backref("package", uselist=False), + "PackageBase", backref=backref("packages", lazy="dynamic"), foreign_keys=[PackageBaseID]) __mapper_args__ = {"primary_key": [ID]} diff --git a/test/test_package.py b/test/test_package.py index 9532823d..1e940164 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -1,9 +1,7 @@ import pytest from sqlalchemy import and_ -from sqlalchemy.exc import IntegrityError, OperationalError - -import aurweb.config +from sqlalchemy.exc import IntegrityError from aurweb.db import create, query from aurweb.models.account_type import AccountType @@ -57,20 +55,6 @@ def test_package(): assert record is not None -def test_package_package_base_cant_change(): - """ Test case insensitivity of the database table. """ - if aurweb.config.get("database", "backend") == "sqlite": - return None # SQLite doesn't seem handle this. - - from aurweb.db import session - - with pytest.raises(OperationalError): - create(Package, - PackageBase=pkgbase, - Name="invalidates-old-package-packagebase-relationship") - session.rollback() - - def test_package_null_pkgbase_raises_exception(): from aurweb.db import session From 7d695f0c6af4b35688aa53c3602aee09e05eff68 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 08:32:46 -0700 Subject: [PATCH 0777/1891] Update .gitignore Signed-off-by: Kevin Morris --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 5d1a4de7..27ff977a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ fastapi_aw/ .idea /cache/* /logs/* +/build/ +/dist/ +/aurweb.egg-info/ From dbbafc15fae9567deba5fd02b7a4dfdc5969d1ad Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 12:44:55 -0700 Subject: [PATCH 0778/1891] bugfix: PackageKeyword should have two PKs Signed-off-by: Kevin Morris --- aurweb/models/package_keyword.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aurweb/models/package_keyword.py b/aurweb/models/package_keyword.py index 2926740d..803e6bca 100644 --- a/aurweb/models/package_keyword.py +++ b/aurweb/models/package_keyword.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, ForeignKey, Integer +from sqlalchemy import Column, ForeignKey, Integer, String, text from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship @@ -18,7 +18,11 @@ class PackageKeyword(Base): "PackageBase", backref=backref("keywords", lazy="dynamic"), foreign_keys=[PackageBaseID]) - __mapper_args__ = {"primary_key": [PackageBaseID]} + Keyword = Column( + String(255), primary_key=True, nullable=False, + server_default=text("''")) + + __mapper_args__ = {"primary_key": [PackageBaseID, Keyword]} def __init__(self, PackageBase: aurweb.models.package_base.PackageBase = None, From 2f5d9c63c479211aec63a5c29ef5a7dc8c464225 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 28 Jun 2021 22:32:56 +0100 Subject: [PATCH 0779/1891] [php] Support DB mysql backend with port instead of socket Signed-off-by: Leonidas Spyropoulos --- web/lib/DB.class.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/web/lib/DB.class.php b/web/lib/DB.class.php index dfdbbf96..c7b3c745 100644 --- a/web/lib/DB.class.php +++ b/web/lib/DB.class.php @@ -20,15 +20,23 @@ class DB { $backend = config_get('database', 'backend'); $host = config_get('database', 'host'); $socket = config_get('database', 'socket'); + $port = config_get('database', 'port'); $name = config_get('database', 'name'); $user = config_get('database', 'user'); $password = config_get('database', 'password'); if ($backend == "mysql") { - $dsn = $backend . - ':host=' . $host . - ';unix_socket=' . $socket . - ';dbname=' . $name; + if ($port != '') { + $dsn = $backend . + ':host=' . $host . + ';port=' . $port . + ';dbname=' . $name; + } else { + $dsn = $backend . + ':host=' . $host . + ';unix_socket=' . $socket . + ';dbname=' . $name; + } self::$dbh = new PDO($dsn, $user, $password); self::$dbh->exec("SET NAMES 'utf8' COLLATE 'utf8_general_ci';"); From c3a29171cde3b7fa16de82c1f60aa9e3329393bc Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 28 Jun 2021 22:33:51 +0100 Subject: [PATCH 0780/1891] [php] aurweb.spawn avoid permission denied when running as user Signed-off-by: Leonidas Spyropoulos --- aurweb/spawn.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index f7c07dd7..6d553dde 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -58,6 +58,11 @@ def generate_nginx_config(): pid {os.path.join(temporary_dir, "nginx.pid")}; http {{ access_log /dev/stdout; + client_body_temp_path {os.path.join(temporary_dir, "client_body")}; + proxy_temp_path {os.path.join(temporary_dir, "proxy")}; + fastcgi_temp_path {os.path.join(temporary_dir, "fastcgi")}1 2; + uwsgi_temp_path {os.path.join(temporary_dir, "uwsgi")}; + scgi_temp_path {os.path.join(temporary_dir, "scgi")}; server {{ listen {aur_location_parts.netloc}; location / {{ From af96be7d0928172a42f92d9a4a264ca6eb2c4710 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 10:27:45 -0700 Subject: [PATCH 0781/1891] Docker: move nginx config to its own file Signed-off-by: Kevin Morris --- docker/config/nginx.conf | 133 ++++++++++++++++++++++++++++++++++++ docker/nginx-entrypoint.sh | 135 +------------------------------------ 2 files changed, 134 insertions(+), 134 deletions(-) create mode 100644 docker/config/nginx.conf diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf new file mode 100644 index 00000000..c1957d71 --- /dev/null +++ b/docker/config/nginx.conf @@ -0,0 +1,133 @@ +daemon off; +user root; +worker_processes auto; +pid /var/run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 256; +} + +http { + sendfile on; + tcp_nopush on; + types_hash_max_size 4096; + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + gzip on; + + upstream hypercorn { + server fastapi:8000; + } + + upstream cgit-php { + server cgit-php:3000; + } + + upstream cgit-fastapi { + server cgit-fastapi:3000; + } + + upstream smartgit { + server unix:/var/run/smartgit/smartgit.sock; + } + + server { + listen 8443 ssl http2; + server_name localhost default_server; + + ssl_certificate /etc/ssl/certs/localhost.cert.pem; + ssl_certificate_key /etc/ssl/private/localhost.key.pem; + + root /aurweb/web/html; + index index.php; + + location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { + include uwsgi_params; + uwsgi_pass smartgit; + uwsgi_modifier1 9; + uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; + uwsgi_param PATH_INFO /aur.git/$3; + uwsgi_param GIT_HTTP_EXPORT_ALL ""; + uwsgi_param GIT_NAMESPACE $1; + uwsgi_param GIT_PROJECT_ROOT /aurweb; + } + + location ~ ^/cgit { + include uwsgi_params; + rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=$1&$2 last; + uwsgi_modifier1 9; + uwsgi_param CGIT_CONFIG /etc/cgitrc; + uwsgi_pass uwsgi://cgit-php; + } + + location ~ ^/[^/]+\.php($|/) { + fastcgi_pass php-fpm:9000; + fastcgi_index index.php; + fastcgi_split_path_info ^(/[^/]+\.php)(/.*)$; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + include fastcgi_params; + } + + location ~ .* { + rewrite ^/(.*)$ /index.php/$1 last; + } + + } + + server { + listen 8444 ssl http2; + server_name localhost default_server; + + ssl_certificate /etc/ssl/certs/localhost.cert.pem; + ssl_certificate_key /etc/ssl/private/localhost.key.pem; + + root /aurweb/web/html; + + location / { + try_files $uri @proxy_to_app; + } + + location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { + include uwsgi_params; + uwsgi_pass smartgit; + uwsgi_modifier1 9; + uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; + uwsgi_param PATH_INFO /aur.git/$3; + uwsgi_param GIT_HTTP_EXPORT_ALL ""; + uwsgi_param GIT_NAMESPACE $1; + uwsgi_param GIT_PROJECT_ROOT /aurweb; + } + + location ~ ^/cgit { + include uwsgi_params; + rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=$1&$2 last; + uwsgi_modifier1 9; + uwsgi_param CGIT_CONFIG /etc/cgitrc; + uwsgi_pass uwsgi://cgit-fastapi; + } + + location @proxy_to_app { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_redirect off; + proxy_buffering off; + proxy_pass https://hypercorn; + } + } + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } +} + diff --git a/docker/nginx-entrypoint.sh b/docker/nginx-entrypoint.sh index 238cd167..347af50f 100755 --- a/docker/nginx-entrypoint.sh +++ b/docker/nginx-entrypoint.sh @@ -15,139 +15,6 @@ sed -ri 's/^(disable_http_login) = .+/\1 = 1/' conf/config cp -vf /cache/localhost.cert.pem /etc/ssl/certs/localhost.cert.pem cp -vf /cache/localhost.key.pem /etc/ssl/private/localhost.key.pem -cat > /etc/nginx/nginx.conf << EOF -daemon off; -user root; -worker_processes auto; -pid /var/run/nginx.pid; -include /etc/nginx/modules-enabled/*.conf; - -events { - worker_connections 256; -} - -http { - sendfile on; - tcp_nopush on; - types_hash_max_size 4096; - include /etc/nginx/mime.types; - default_type application/octet-stream; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - gzip on; - - upstream hypercorn { - server fastapi:8000; - } - - upstream cgit-php { - server cgit-php:3000; - } - - upstream cgit-fastapi { - server cgit-fastapi:3000; - } - - upstream smartgit { - server unix:/var/run/smartgit/smartgit.sock; - } - - server { - listen 8443 ssl http2; - server_name localhost default_server; - - ssl_certificate /etc/ssl/certs/localhost.cert.pem; - ssl_certificate_key /etc/ssl/private/localhost.key.pem; - - root /aurweb/web/html; - index index.php; - - location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { - include uwsgi_params; - uwsgi_pass smartgit; - uwsgi_modifier1 9; - uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; - uwsgi_param PATH_INFO /aur.git/\$3; - uwsgi_param GIT_HTTP_EXPORT_ALL ""; - uwsgi_param GIT_NAMESPACE \$1; - uwsgi_param GIT_PROJECT_ROOT /aurweb; - } - - location ~ ^/cgit { - include uwsgi_params; - rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=\$1&\$2 last; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG /etc/cgitrc; - uwsgi_pass uwsgi://cgit-php; - } - - location ~ ^/[^/]+\.php($|/) { - fastcgi_pass php-fpm:9000; - fastcgi_index index.php; - fastcgi_split_path_info ^(/[^/]+\.php)(/.*)\$; - fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; - fastcgi_param PATH_INFO \$fastcgi_path_info; - include fastcgi_params; - } - - location ~ .* { - rewrite ^/(.*)$ /index.php/\$1 last; - } - - } - - server { - listen 8444 ssl http2; - server_name localhost default_server; - - ssl_certificate /etc/ssl/certs/localhost.cert.pem; - ssl_certificate_key /etc/ssl/private/localhost.key.pem; - - root /aurweb/web/html; - - location / { - try_files \$uri @proxy_to_app; - } - - location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { - include uwsgi_params; - uwsgi_pass smartgit; - uwsgi_modifier1 9; - uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; - uwsgi_param PATH_INFO /aur.git/\$3; - uwsgi_param GIT_HTTP_EXPORT_ALL ""; - uwsgi_param GIT_NAMESPACE \$1; - uwsgi_param GIT_PROJECT_ROOT /aurweb; - } - - location ~ ^/cgit { - include uwsgi_params; - rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=\$1&\$2 last; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG /etc/cgitrc; - uwsgi_pass uwsgi://cgit-fastapi; - } - - location @proxy_to_app { - proxy_set_header Host \$http_host; - proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto \$scheme; - proxy_redirect off; - proxy_buffering off; - proxy_pass https://hypercorn; - } - } - - map \$http_upgrade \$connection_upgrade { - default upgrade; - '' close; - } -} -EOF +cp -vf /docker/config/nginx.conf /etc/nginx/nginx.conf exec "$@" From 3bacfe6cd97049926893a37595bbb40158be7a48 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 10:29:24 -0700 Subject: [PATCH 0782/1891] Docker: increase nginx and php-fpm logging Log toward stdout/stderr which is accessible via `docker-compose logs `. Examples: - `docker-compose logs nginx` - `docker-compose logs php-fpm` Signed-off-by: Kevin Morris --- docker/config/nginx.conf | 4 ++-- docker/php-entrypoint.sh | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index c1957d71..d7c0196a 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -18,8 +18,8 @@ http { ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; + access_log /dev/stdout; + error_log /dev/stderr; gzip on; diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index 4d49ef17..350871d6 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -13,6 +13,11 @@ sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ssh://aur@localhost:2222/%s.git|" con sed -ri 's/^(listen).*/\1 = 0.0.0.0:9000/' /etc/php/php-fpm.d/www.conf sed -ri 's/^;?(clear_env).*/\1 = no/' /etc/php/php-fpm.d/www.conf +# Log to stderr. View logs via `docker-compose logs php-fpm`. +sed -ri 's|^(error_log) = .*$|\1 = /proc/self/fd/2|g' /etc/php/php-fpm.conf +sed -ri 's|^;?(access\.log) = .*$|\1 = /proc/self/fd/2|g' \ + /etc/php/php-fpm.d/www.conf + sed -ri 's/^;?(extension=pdo_mysql)/\1/' /etc/php/php.ini sed -ri 's/^;?(open_basedir).*$/\1 = \//' /etc/php/php.ini From a120af5a005450b348dd260ac4c9b92e979d95e7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 10:30:26 -0700 Subject: [PATCH 0783/1891] Docker: remove asset forward to index.php This makes logging look a little better for development purposes. Now, `docker-compose logs php-fpm` will only show details about PHP accesses, while `docker-compose logs nginx` will show accesses regarding PHP assets. Signed-off-by: Kevin Morris --- docker/config/nginx.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index d7c0196a..3a8de801 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -77,6 +77,10 @@ http { include fastcgi_params; } + location ~ .+\.(css|js?|jpe?g|png|svg|ico)/?$ { + try_files $uri =404; + } + location ~ .* { rewrite ^/(.*)$ /index.php/$1 last; } From 4442ba6703de42b1cba568f582ea4f668629ac14 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 10:41:54 -0700 Subject: [PATCH 0784/1891] bugfix: return null if config key doesn't exist This was previously causing a PHP warning due to returning a missing key. Signed-off-by: Kevin Morris --- web/lib/confparser.inc.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php index 1152e132..fdd2b78e 100644 --- a/web/lib/confparser.inc.php +++ b/web/lib/confparser.inc.php @@ -30,7 +30,9 @@ function config_get($section, $key) { global $AUR_CONFIG; config_load(); - return $AUR_CONFIG[$section][$key]; + return isset($AUR_CONFIG[$section][$key]) + ? $AUR_CONFIG[$section][$key] + : null; } function config_get_int($section, $key) { From 6c7bb04b93161580946c2ee96d0002f3bd7858d1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 21:33:47 -0700 Subject: [PATCH 0785/1891] Docker: Improve mariadb init Signed-off-by: Kevin Morris --- docker-compose.yml | 8 +++++++- docker/mariadb-entrypoint.sh | 29 ++++++++++++++++++++++++++++- docker/scripts/run-mariadb.sh | 26 -------------------------- docker/scripts/run-pytests.sh | 3 ++- docker/test-mysql-entrypoint.sh | 3 ++- 5 files changed, 39 insertions(+), 30 deletions(-) delete mode 100755 docker/scripts/run-mariadb.sh diff --git a/docker-compose.yml b/docker-compose.yml index 6bf36166..40d9bc5b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,8 +32,10 @@ services: mariadb: image: aurweb:latest init: true + environment: + - DB_HOST="%" entrypoint: /docker/mariadb-entrypoint.sh - command: /docker/scripts/run-mariadb.sh mysqld_safe --datadir=/var/lib/mysql + command: /usr/bin/mysqld_safe --datadir=/var/lib/mysql ports: # This will expose mariadbd on 127.0.0.1:13306 in the host. # Ex: `mysql -uaur -paur -h 127.0.0.1 -P 13306 aurweb` @@ -136,6 +138,7 @@ services: init: true environment: - AUR_CONFIG=/aurweb/conf/config + - DB_HOST=mariadb entrypoint: /docker/php-entrypoint.sh command: /docker/scripts/run-php.sh healthcheck: @@ -170,6 +173,7 @@ services: init: true environment: - AUR_CONFIG=conf/config + - DB_HOST=mariadb entrypoint: /docker/fastapi-entrypoint.sh command: /docker/scripts/run-fastapi.sh "${FASTAPI_BACKEND}" healthcheck: @@ -269,6 +273,7 @@ services: init: true environment: - AUR_CONFIG=conf/config + - DB_HOST=mariadb entrypoint: /docker/test-mysql-entrypoint.sh command: /docker/scripts/run-pytests.sh clean stdin_open: true @@ -324,6 +329,7 @@ services: init: true environment: - AUR_CONFIG=conf/config + - DB_HOST=mariadb entrypoint: /docker/tests-entrypoint.sh command: /docker/scripts/run-tests.sh stdin_open: true diff --git a/docker/mariadb-entrypoint.sh b/docker/mariadb-entrypoint.sh index e33c61c7..48e87045 100755 --- a/docker/mariadb-entrypoint.sh +++ b/docker/mariadb-entrypoint.sh @@ -1,6 +1,33 @@ #!/bin/bash set -eou pipefail -mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql +MYSQL_DATA=/var/lib/mysql +DB_HOST="localhost" + +mariadb-install-db --user=mysql --basedir=/usr --datadir=$MYSQL_DATA + +# Start it up. +mysqld_safe --datadir=$MYSQL_DATA --skip-networking & +while ! mysqladmin ping 2>/dev/null; do + sleep 1s +done + +# Configure databases. +DATABASE="aurweb" # Persistent database for fastapi/php-fpm. +TEST_DB="aurweb_test" # Test database (ephemereal). + +echo "Taking care of primary database '${DATABASE}'..." +mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'$DB_HOST' IDENTIFIED BY 'aur';" +mysql -u root -e "CREATE DATABASE IF NOT EXISTS $DATABASE;" +mysql -u root -e "GRANT ALL ON ${DATABASE}.* TO 'aur'@'$DB_HOST';" + +# Drop and create our test database. +echo "Dropping test database '$TEST_DB'..." +mysql -u root -e "DROP DATABASE IF EXISTS $TEST_DB;" +mysql -u root -e "CREATE DATABASE $TEST_DB;" +mysql -u root -e "GRANT ALL ON ${TEST_DB}.* TO 'aur'@'$DB_HOST';" +echo "Created new '$TEST_DB'!" + +mysqladmin -uroot shutdown exec "$@" diff --git a/docker/scripts/run-mariadb.sh b/docker/scripts/run-mariadb.sh deleted file mode 100755 index d27d8124..00000000 --- a/docker/scripts/run-mariadb.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -mysqld_safe --datadir=/var/lib/mysql --skip-networking & -until mysqladmin ping --silent; do - sleep 1s -done - -# Create test database. -mysql -u root -e "CREATE USER 'aur'@'%' IDENTIFIED BY 'aur'" \ - 2>/dev/null || /bin/true - -# Create a brand new 'aurweb_test' DB. -mysql -u root -e "DROP DATABASE aurweb_test" 2>/dev/null || /bin/true -mysql -u root -e "CREATE DATABASE aurweb_test" -mysql -u root -e "GRANT ALL PRIVILEGES ON aurweb_test.* TO 'aur'@'%'" - -# Create the 'aurweb' DB if it does not yet exist. -mysql -u root -e "CREATE DATABASE aurweb" 2>/dev/null || /bin/true -mysql -u root -e "GRANT ALL PRIVILEGES ON aurweb.* TO 'aur'@'%'" - -mysql -u root -e "FLUSH PRIVILEGES" - -# Shutdown mariadb. -mysqladmin -uroot shutdown - -exec "$@" diff --git a/docker/scripts/run-pytests.sh b/docker/scripts/run-pytests.sh index 021603b1..c6baa939 100755 --- a/docker/scripts/run-pytests.sh +++ b/docker/scripts/run-pytests.sh @@ -23,7 +23,8 @@ while [ $# -ne 0 ]; do done # Initialize the new database; ignore errors. -python -m aurweb.initdb 2>/dev/null || /bin/true +python -m aurweb.initdb 2>/dev/null || \ + (echo "Error: aurweb.initdb failed; already initialized?" && /bin/true) # Run pytest with optional targets in front of it. make -C test "${PARAMS[@]}" pytest diff --git a/docker/test-mysql-entrypoint.sh b/docker/test-mysql-entrypoint.sh index ea4df868..9594318f 100755 --- a/docker/test-mysql-entrypoint.sh +++ b/docker/test-mysql-entrypoint.sh @@ -1,8 +1,9 @@ #!/bin/bash set -eou pipefail +[[ -z "$DB_HOST" ]] && echo 'Error: $DB_HOST required but missing.' && exit 1 + DB_NAME="aurweb_test" -DB_HOST="mariadb" DB_USER="aur" DB_PASS="aur" From f4406ccf5cc27806843d7bb8a216c5aa6ad1a214 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 21:28:12 -0700 Subject: [PATCH 0786/1891] Docker: Centralize repo dependencies Now, we have `docker/scripts/install-deps.sh`, a script used by both Docker and .gitlab-ci.yml. We can now focus on changing deps in this script along as well as documentation going forward. Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 47 +++++++++++----------------------- Dockerfile | 37 +++++++++++++------------- docker/scripts/install-deps.sh | 19 ++++++++++++++ 3 files changed, 52 insertions(+), 51 deletions(-) create mode 100755 docker/scripts/install-deps.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6a9d80cb..7b8da2ae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: archlinux +image: archlinux:base-devel cache: key: system-v1 @@ -7,45 +7,28 @@ cache: - .pkg-cache variables: - AUR_CONFIG: conf/config + AUR_CONFIG: conf/config # Default MySQL config setup in before_script. + DB_HOST: localhost before_script: - - pacman -Syu --noconfirm --noprogressbar --needed --cachedir .pkg-cache - base-devel git gpgme protobuf pyalpm python-mysqlclient - python-pygit2 python-srcinfo python-bleach python-markdown - python-sqlalchemy python-alembic python-pytest python-werkzeug - python-pytest-tap python-fastapi hypercorn nginx python-authlib - python-itsdangerous python-httpx python-jinja python-pytest-cov - python-requests python-aiofiles python-python-multipart - python-pytest-asyncio python-coverage python-bcrypt - python-email-validator openssh python-lxml mariadb - python-isort flake8 - - bash -c "echo '127.0.0.1 localhost' > /etc/hosts" - - bash -c "echo '::1 localhost' >> /etc/hosts" - - mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + - ./docker/scripts/install-deps.sh + - useradd -U -d /aurweb -c 'AUR User' aur + - ./docker/mariadb-entrypoint.sh - (cd '/usr' && /usr/bin/mysqld_safe --datadir='/var/lib/mysql') & - 'until : > /dev/tcp/127.0.0.1/3306; do sleep 1s; done' - - mysql -u root -e "CREATE USER 'aur'@'localhost' IDENTIFIED BY 'aur';" - - mysql -u root -e "CREATE DATABASE aurweb_test;" - - mysql -u root -e "GRANT ALL ON aurweb_test.* TO 'aur'@'localhost';" - - mysql -u root -e "FLUSH PRIVILEGES;" - - sed -r "s;YOUR_AUR_ROOT;$(pwd);g" conf/config.dev > conf/config - - cp conf/config conf/config.sqlite - - cp conf/config.defaults conf/config.sqlite.defaults - - sed -i -r 's;backend = .*;backend = sqlite;' conf/config.sqlite - - sed -i -r "s;name = .*;name = $(pwd)/aurweb.sqlite3;" conf/config.sqlite + - ./docker/test-mysql-entrypoint.sh # Create mysql AUR_CONFIG. + - ./docker/test-sqlite-entrypoint.sh # Create sqlite AUR_CONFIG. + - make -C po all install + - python setup.py install --install-scripts=/usr/local/bin + - python -m aurweb.initdb # Initialize MySQL tables. - AUR_CONFIG=conf/config.sqlite python -m aurweb.initdb + - make -C test clean test: script: - - python setup.py install - - make -C po all install - - python -m aurweb.initdb - - make -C test sh # sharness tests use sqlite. - - make -C test pytest # pytest with mysql. - - AUR_CONFIG=conf/config.sqlite make -C test pytest # pytest with sqlite. - - coverage report --include='aurweb/*' - - coverage xml --include='aurweb/*' + - make -C test sh pytest # sharness tests use sqlite & pytest w/ mysql. + - AUR_CONFIG=conf/config.sqlite make -C test pytest + - make -C test coverage # Produce coverage reports. - flake8 --count aurweb # Assert no flake8 violations in aurweb. - flake8 --count test # Assert no flake8 violations in test. - flake8 --count migrations # Assert no flake8 violations in migrations. diff --git a/Dockerfile b/Dockerfile index cec36158..2843fa1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,30 @@ FROM archlinux:base-devel + ENV PYTHONPATH=/aurweb ENV AUR_CONFIG=conf/config +# Copy our single bootstrap script. +COPY docker/scripts/install-deps.sh /install-deps.sh +RUN /install-deps.sh + +# Add our aur user. +RUN useradd -U -d /aurweb -c 'AUR User' aur + # Setup some default system stuff. RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime -RUN mkdir -p .pkg-cache +# Copy the rest of docker. +COPY ./docker /docker +COPY ./docker/scripts/*.sh /usr/local/bin/ -# Install dependencies. -RUN pacman -Syu --noconfirm --noprogressbar \ - --cachedir .pkg-cache git gpgme protobuf pyalpm \ - python-mysqlclient python-pygit2 python-srcinfo python-bleach \ - python-markdown python-sqlalchemy python-alembic python-pytest \ - python-werkzeug python-pytest-tap python-fastapi nginx python-authlib \ - python-itsdangerous python-httpx python-jinja python-pytest-cov \ - python-requests python-aiofiles python-python-multipart \ - python-pytest-asyncio python-coverage hypercorn python-bcrypt \ - python-email-validator openssh python-lxml mariadb mariadb-libs \ - python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ - python-asgiref uvicorn - -RUN useradd -U -d /aurweb -c 'AUR User' aur - -COPY docker /docker +# Copy from host to container. +COPY . /aurweb +# Working directory is aurweb root @ /aurweb. WORKDIR /aurweb -COPY . . +# Install translations. RUN make -C po all install -RUN python3 setup.py install --install-scripts=/usr/local/bin + +# Install package and scripts. +RUN python setup.py install --install-scripts=/usr/local/bin diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh new file mode 100755 index 00000000..fc15313f --- /dev/null +++ b/docker/scripts/install-deps.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Install Arch Linux dependencies. This is centralized here +# for CI and Docker usage and should always reflect the most +# robust development ecosystem. +set -eou pipefail + +pacman -Syu --noconfirm --noprogressbar \ + --cachedir .pkg-cache git gpgme protobuf pyalpm \ + python-mysqlclient python-pygit2 python-srcinfo python-bleach \ + python-markdown python-sqlalchemy python-alembic python-pytest \ + python-werkzeug python-pytest-tap python-fastapi nginx python-authlib \ + python-itsdangerous python-httpx python-jinja python-pytest-cov \ + python-requests python-aiofiles python-python-multipart \ + python-pytest-asyncio python-coverage hypercorn python-bcrypt \ + python-email-validator openssh python-lxml mariadb mariadb-libs \ + python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ + python-asgiref uvicorn + +exec "$@" From 3f60f5048e210f5248bb2b56fcfbe346e5ebac2a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 21:35:00 -0700 Subject: [PATCH 0787/1891] Docker: add scripts/setup-sqlite.sh This script purely removes any existing sqlite and is used before tests are run. This causes the test flow to run `aurweb.initdb` again (if ever). Signed-off-by: Kevin Morris --- docker-compose.yml | 4 ++-- docker/scripts/setup-sqlite.sh | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100755 docker/scripts/setup-sqlite.sh diff --git a/docker-compose.yml b/docker-compose.yml index 40d9bc5b..22495a95 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -304,7 +304,7 @@ services: environment: - AUR_CONFIG=conf/config.sqlite entrypoint: /docker/test-sqlite-entrypoint.sh - command: /docker/scripts/run-pytests.sh clean + command: setup-sqlite.sh run-pytests.sh clean stdin_open: true tty: true volumes: @@ -331,7 +331,7 @@ services: - AUR_CONFIG=conf/config - DB_HOST=mariadb entrypoint: /docker/tests-entrypoint.sh - command: /docker/scripts/run-tests.sh + command: setup-sqlite.sh run-tests.sh stdin_open: true tty: true depends_on: diff --git a/docker/scripts/setup-sqlite.sh b/docker/scripts/setup-sqlite.sh new file mode 100755 index 00000000..e0b8de50 --- /dev/null +++ b/docker/scripts/setup-sqlite.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# Run an sqlite test. This script really just prepares sqlite +# tests by deleting any existing databases so the test can +# initialize cleanly. +DB_NAME="$(grep 'name =' conf/config.sqlite | sed -r 's/^name = (.+)$/\1/')" +rm -vf $DB_NAME +exec "$@" From 427a30ef8adb9ff92c9ee6745c3d2985929f3a7a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 21:37:45 -0700 Subject: [PATCH 0788/1891] Docker: Remove deprecated `links` In addition, remove some unneeded dependencies on tests. Though, in the future we _should_ craft tests that use these. Signed-off-by: Kevin Morris --- docker-compose.yml | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 22495a95..ab8d7c41 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -64,8 +64,6 @@ services: depends_on: mariadb: condition: service_healthy - links: - - mariadb volumes: - mariadb_run:/var/run/mysqld - mariadb_data:/var/lib/mysql @@ -86,8 +84,6 @@ services: depends_on: mariadb: condition: service_healthy - links: - - mariadb volumes: - mariadb_run:/var/run/mysqld - mariadb_data:/var/lib/mysql @@ -109,8 +105,6 @@ services: depends_on: git: condition: service_healthy - links: - - git volumes: - git_data:/aurweb/aur.git @@ -128,8 +122,6 @@ services: depends_on: git: condition: service_healthy - links: - - git volumes: - git_data:/aurweb/aur.git @@ -152,10 +144,6 @@ services: condition: service_healthy mariadb: condition: service_healthy - links: - - ca - - git - - mariadb volumes: - mariadb_run:/var/run/mysqld # Bind socket in this volume. - mariadb_data:/var/lib/mysql @@ -187,10 +175,6 @@ services: condition: service_healthy mariadb: condition: service_healthy - links: - - ca - - git - - mariadb volumes: - mariadb_run:/var/run/mysqld # Bind socket in this volume. - mariadb_data:/var/lib/mysql @@ -228,12 +212,6 @@ services: condition: service_healthy php-fpm: condition: service_healthy - links: - - cgit-php - - cgit-fastapi - - smartgit - - fastapi - - php-fpm volumes: - git_data:/aurweb/aur.git - ./cache:/cache @@ -255,8 +233,6 @@ services: depends_on: git: condition: service_healthy - links: - - git volumes: - git_data:/aurweb/aur.git - ./cache:/cache @@ -281,11 +257,6 @@ services: depends_on: mariadb: condition: service_healthy - git: - condition: service_healthy - links: - - mariadb - - git volumes: - mariadb_run:/var/run/mysqld - git_data:/aurweb/aur.git @@ -318,11 +289,6 @@ services: - ./web/template:/aurweb/web/template - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates - depends_on: - git: - condition: service_healthy - links: - - git test: image: aurweb:latest @@ -337,8 +303,6 @@ services: depends_on: mariadb: condition: service_healthy - links: - - mariadb volumes: - mariadb_run:/var/run/mysqld - git_data:/aurweb/aur.git From 3a74f76ff9835dd03b4709a585195611f6a20e38 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 29 Jun 2021 22:44:41 -0700 Subject: [PATCH 0789/1891] FastAPI: use internal typeahead and remove jquery Awesome! Signed-off-by: Kevin Morris --- aurweb/asgi.py | 5 +---- templates/index.html | 10 ++++++++++ templates/partials/head.html | 3 +++ templates/partials/layout.html | 1 - templates/partials/typeahead.html | 30 ------------------------------ web/html/js/typeahead-home.js | 6 ++++++ 6 files changed, 20 insertions(+), 35 deletions(-) delete mode 100644 templates/partials/typeahead.html create mode 100644 web/html/js/typeahead-home.js diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 228b9a65..5f0ad01d 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -83,10 +83,7 @@ async def add_security_headers(request: Request, call_next: typing.Callable): # Add CSP header. nonce = request.user.nonce csp = "default-src 'self'; " - script_hosts = [ - "ajax.googleapis.com", - "cdn.jsdelivr.net" - ] + script_hosts = [] csp += f"script-src 'self' 'nonce-{nonce}' " + ' '.join(script_hosts) # It's fine if css is inlined. csp += "; style-src 'self' 'unsafe-inline'" diff --git a/templates/index.html b/templates/index.html index 8cd1cc78..f8745f33 100644 --- a/templates/index.html +++ b/templates/index.html @@ -93,4 +93,14 @@

    + + + + + + + {% endblock %} diff --git a/templates/partials/head.html b/templates/partials/head.html index 0351fd6e..9b438255 100644 --- a/templates/partials/head.html +++ b/templates/partials/head.html @@ -12,5 +12,8 @@ + + + AUR ({{ language }}) - {{ title | tr }} diff --git a/templates/partials/layout.html b/templates/partials/layout.html index 019ebff7..68637ed7 100644 --- a/templates/partials/layout.html +++ b/templates/partials/layout.html @@ -6,6 +6,5 @@ {% include 'partials/navbar.html' %} {% extends 'partials/body.html' %} - {% include 'partials/typeahead.html' %} diff --git a/templates/partials/typeahead.html b/templates/partials/typeahead.html deleted file mode 100644 index c218b8d1..00000000 --- a/templates/partials/typeahead.html +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/web/html/js/typeahead-home.js b/web/html/js/typeahead-home.js new file mode 100644 index 00000000..5af51c53 --- /dev/null +++ b/web/html/js/typeahead-home.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + const input = document.getElementById('pkgsearch-field'); + const form = document.getElementById('pkgsearch-form'); + const type = 'suggest'; + typeahead.init(type, input, form); +}); From 450469e3d66059d2002a68c4ad8d435793a7bfe4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Jun 2021 08:54:22 -0700 Subject: [PATCH 0790/1891] add /addvote/ (get, post) routes Another part of the "Trusted User" collection of routes. This allows a Trusted User to create a proposal. New Routes: - get `/addvote/` - post `/addvote/` Signed-off-by: Kevin Morris --- aurweb/routers/trusted_user.py | 119 ++++++++++++++++++++++++++----- templates/addvote.html | 68 ++++++++++++++++++ test/test_trusted_user_routes.py | 93 ++++++++++++++++++++++++ 3 files changed, 264 insertions(+), 16 deletions(-) create mode 100644 templates/addvote.html diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 55f7b7e1..fd5ebb04 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -1,3 +1,6 @@ +import html +import logging +import re import typing from datetime import datetime @@ -5,10 +8,10 @@ from http import HTTPStatus from urllib.parse import quote_plus from fastapi import APIRouter, Form, HTTPException, Request -from fastapi.responses import Response +from fastapi.responses import RedirectResponse, Response from sqlalchemy import and_, or_ -from aurweb import db +from aurweb import db, l10n from aurweb.auth import account_type_required, auth_required from aurweb.models.account_type import DEVELOPER, TRUSTED_USER, TRUSTED_USER_AND_DEV from aurweb.models.tu_vote import TUVote @@ -17,6 +20,7 @@ from aurweb.models.user import User from aurweb.templates import make_context, make_variable_context, render_template router = APIRouter() +logger = logging.getLogger(__name__) # Some TU route specific constants. ITEMS_PER_PAGE = 10 # Paged table size. @@ -29,6 +33,17 @@ REQUIRED_TYPES = { TRUSTED_USER_AND_DEV } +ADDVOTE_SPECIFICS = { + # This dict stores a vote duration and quorum for a proposal. + # When a proposal is added, duration is added to the current + # timestamp. + # "addvote_type": (duration, quorum) + "add_tu": (7 * 24 * 60 * 60, 0.66), + "remove_tu": (7 * 24 * 60 * 60, 0.75), + "remove_inactive_tu": (5 * 24 * 60 * 60, 0.66), + "bylaws": (7 * 24 * 60 * 60, 0.75) +} + @router.get("/tu") @auth_required(True, redirect="/") @@ -174,28 +189,17 @@ async def trusted_user_proposal_post(request: Request, raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) voters = db.query(User).join(TUVote).filter(TUVote.VoteID == voteinfo.ID) + vote = db.query(TUVote, and_(TUVote.UserID == request.user.ID, + TUVote.VoteID == voteinfo.ID)).first() - # status_code we'll use for responses later. status_code = HTTPStatus.OK - if not request.user.is_trusted_user(): - # Test: Create a proposal and view it as a "Developer". It - # should give us this error. context["error"] = "Only Trusted Users are allowed to vote." status_code = HTTPStatus.UNAUTHORIZED elif voteinfo.User == request.user.Username: context["error"] = "You cannot vote in an proposal about you." status_code = HTTPStatus.BAD_REQUEST - - vote = db.query(TUVote, and_(TUVote.UserID == request.user.ID, - TUVote.VoteID == voteinfo.ID)).first() - - if status_code != HTTPStatus.OK: - return render_proposal(request, context, proposal, - voteinfo, voters, vote, - status_code=status_code) - - if vote is not None: + elif vote is not None: context["error"] = "You've already voted for this proposal." status_code = HTTPStatus.BAD_REQUEST @@ -218,3 +222,86 @@ async def trusted_user_proposal_post(request: Request, context["error"] = "You've already voted for this proposal." return render_proposal(request, context, proposal, voteinfo, voters, vote) + + +@router.get("/addvote") +@auth_required(True) +@account_type_required({"Trusted User", "Trusted User & Developer"}) +async def trusted_user_addvote(request: Request, + user: str = str(), + type: str = "add_tu", + agenda: str = str()): + context = await make_variable_context(request, "Add Proposal") + + if type not in ADDVOTE_SPECIFICS: + context["error"] = "Invalid type." + type = "add_tu" # Default it. + + context["user"] = user + context["type"] = type + context["agenda"] = agenda + + return render_template(request, "addvote.html", context) + + +@router.post("/addvote") +@auth_required(True) +@account_type_required({TRUSTED_USER, TRUSTED_USER_AND_DEV}) +async def trusted_user_addvote_post(request: Request, + user: str = Form(default=str()), + type: str = Form(default=str()), + agenda: str = Form(default=str())): + # Build a context. + context = await make_variable_context(request, "Add Proposal") + + context["type"] = type + context["user"] = user + context["agenda"] = agenda + + def render_addvote(context, status_code): + """ Simplify render_template a bit for this test. """ + return render_template(request, "addvote.html", context, status_code) + + # Alright, get some database records, if we can. + if type != "bylaws": + user_record = db.query(User, User.Username == user).first() + if user_record is None: + context["error"] = "Username does not exist." + return render_addvote(context, HTTPStatus.NOT_FOUND) + + voteinfo = db.query(TUVoteInfo, TUVoteInfo.User == user).count() + if voteinfo: + _ = l10n.get_translator_for_request(request) + context["error"] = _( + "%s already has proposal running for them.") % ( + html.escape(user),) + return render_addvote(context, HTTPStatus.BAD_REQUEST) + + if type not in ADDVOTE_SPECIFICS: + context["error"] = "Invalid type." + context["type"] = type = "add_tu" # Default for rendering. + return render_addvote(context, HTTPStatus.BAD_REQUEST) + + if not agenda: + context["error"] = "Proposal cannot be empty." + return render_addvote(context, HTTPStatus.BAD_REQUEST) + + # Gather some mapped constants and the current timestamp. + duration, quorum = ADDVOTE_SPECIFICS.get(type) + timestamp = int(datetime.utcnow().timestamp()) + + # Remove diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html new file mode 100644 index 00000000..a25e9c9e --- /dev/null +++ b/templates/partials/packages/details.html @@ -0,0 +1,145 @@ + + + + + + {% if show_package_details | default(False) %} + + + + + + + + + + + + + {% endif %} + {% if pkgbase.keywords.count() %} + + + {% if is_maintainer %} + + {% else %} + + {% endif %} + + {% endif %} + {% if licenses and licenses.count() and show_package_details | default(False) %} + + + + + {% endif %} + {% if show_package_details | default(False) %} + + + + + {% endif %} + + + + + + + + + + + + + + + {% if not is_maintainer %} + + {% else %} + + {% endif %} + + + + + + + {% set submitted = pkgbase.SubmittedTS | dt | as_timezone(timezone) %} + + + + + + {% set updated = pkgbase.ModifiedTS | dt | as_timezone(timezone) %} + + +
    {{ "Git Clone URL" | tr }}: + {{ git_clone_uri_anon | format(pkgbase.Name) }} ({{ "read-only" | tr }}, {{ "click to copy" | tr }}) + {% if is_maintainer %} +
    {{ git_clone_uri_priv | format(pkgbase.Name) }} ({{ "click to copy" | tr }}) + {% endif %} +
    {{ "Package Base" | tr }}: + + {{ pkgbase.Name }} + +
    {{ "Description" | tr }}:{{ pkgbase.packages.first().Description }}
    {{ "Upstream URL" | tr }}: + {% set pkg = pkgbase.packages.first() %} + {% if pkg.URL %} + {{ pkg.URL }} + {% else %} + {{ "None" | tr }} + {% endif %} +
    {{ "Keywords" | tr }}: +
    +
    + + +
    +
    +
    + {% for keyword in pkgbase.keywords %} + + {{ keyword.Keyword }} + + {% endfor %} +
    {{ "Licenses" | tr }}:{{ licenses | join(', ', attribute='Name') | default('None' | tr) }}
    {{ "Conflicts" | tr }}: + {{ conflicts | join(', ', attribute='RelName') }} +
    {{ "Submitter" | tr }}: + {% if request.user.is_authenticated() %} + + {{ pkgbase.Submitter.Username | default("None" | tr) }} + + {% else %} + {{ pkgbase.Submitter.Username | default("None" | tr) }} + {% endif %} +
    {{ "Maintainer" | tr }}: + {% if request.user.is_authenticated() %} + + {{ pkgbase.Maintainer.Username | default("None" | tr) }} + + {% else %} + {{ pkgbase.Maintainer.Username | default("None" | tr) }} + {% endif %} +
    {{ "Last Packager" | tr }}: + {% if request.user.is_authenticated() %} + + {{ pkgbase.Packager.Username | default("None" | tr) }} + + {% else %} + {{ pkgbase.Packager.Username | default("None" | tr) }} + {% endif %} +
    {{ "Votes" | tr }}:{{ pkgbase.package_votes.count() }} + + {{ pkgbase.package_votes.count() }} + +
    {{ "Popularity" | tr }}:{{ pkgbase.Popularity | number_format(6 if pkgbase.Popularity <= 0.2 else 2) }}
    {{ "First Submitted" | tr }}:{{ "%s" | format(submitted.strftime("%Y-%m-%d %H:%M")) }}
    {{ "Last Updated" | tr }}:{{ "%s" | format(updated.strftime("%Y-%m-%d %H:%M")) }}
    + + + diff --git a/templates/partials/packages/package_actions.html b/templates/partials/packages/package_actions.html deleted file mode 100644 index 4e7da882..00000000 --- a/templates/partials/packages/package_actions.html +++ /dev/null @@ -1,87 +0,0 @@ - - diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html new file mode 100644 index 00000000..767e25a9 --- /dev/null +++ b/templates/partials/packages/package_metadata.html @@ -0,0 +1,54 @@ +
    +

    Dependencies ({{ dependencies.count() }})

    +
      + {% for dep in dependencies.all() %} +
    • + {% set broken = not dep.is_package() %} + {% if broken %} + + {% else %} + + {% endif %} + {{ dep.DepName }} + {% if broken %} + + {% else %} + + {% endif %} + {{ dep.Package | provides_list(dep.DepName) | safe }} + {% set extra = dep | dep_extra %} + {% if extra %} + {{ dep | dep_extra_desc }} + {% endif %} +
    • + {% endfor %} +
    +
    + +
    +

    Required by ({{ required_by.count() }})

    + +
    + +
    +

    Sources ({{ sources.count() }})

    +
    + +
    + +
    diff --git a/templates/pkgbase.html b/templates/pkgbase.html deleted file mode 100644 index d608fa2e..00000000 --- a/templates/pkgbase.html +++ /dev/null @@ -1,95 +0,0 @@ -{% extends "partials/layout.html" %} - -{% block pageContent %} - {% include "partials/packages/search.html" %} -
    -

    Package Details: {{ pkgbase.Name }}

    - - {% set result = pkgbase %} - {% set pkgname = "result.Name" %} - {% include "partials/packages/package_actions.html" %} - - - - - - - - - {% if is_maintainer %} - - {% else %} - - {% endif %} - - - - - - - - - - - - - - - - - - - - - - - {% set submitted = pkgbase.SubmittedTS | dt | as_timezone(timezone) %} - - - - - - {% set updated = pkgbase.ModifiedTS | dt | as_timezone(timezone) %} - - -
    {{ "Git Clone URL" | tr }}: - {{ git_clone_uri_anon | format(pkgbase.Name) }} ({{ "read-only" | tr }}, {{ "click to copy" | tr }}) - {% if is_maintainer %} -
    {{ git_clone_uri_priv | format(pkgbase.Name) }} ({{ "click to copy" | tr }}) - {% endif %} -
    {{ "Keywords" | tr }}: -
    -
    - - - -
    -
    -
    - {% for item in pkgbase.keywords %} - {{ item.Keyword }} - {% endfor %} -
    {{ "Submitter" | tr }}:{{ pkgbase.Submitter.Username | default("None") }}
    {{ "Maintainer" | tr }}:{{ pkgbase.Maintainer.Username | default("None") }}
    {{ "Last Packager" | tr }}:{{ pkgbase.Packager.Username | default("None") }}
    {{ "Votes" | tr }}:{{ pkgbase.NumVotes }}
    {{ "Popularity" | tr }}:{{ '%0.2f' % pkgbase.Popularity | float }}
    {{ "First Submitted" | tr }}:{{ "%s" | tr | format(submitted.strftime("%Y-%m-%d %H:%M")) }}
    {{ "Last Updated" | tr }}:{{ "%s" | tr | format(updated.strftime("%Y-%m-%d %H:%M")) }}
    - -
    -
    - -

    Packages ({{ packages_count }})

    - -
    -
    -
    - {% set pkgname = result.Name %} - {% set pkgbase_id = result.ID %} - {% set comments = comments %} - {% include "partials/packages/comments.html" %} -{% endblock %} diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py index d39091aa..e28f1781 100644 --- a/test/test_package_dependency.py +++ b/test/test_package_dependency.py @@ -77,6 +77,13 @@ def test_package_dependencies(): assert pkgdep in optdepends.package_dependencies assert pkgdep in package.package_dependencies + assert not pkgdep.is_package() + + base = create(PackageBase, Name=pkgdep.DepName, Maintainer=user) + create(Package, PackageBase=base, Name=pkgdep.DepName) + + assert pkgdep.is_package() + def test_package_dependencies_null_package_raises_exception(): from aurweb.db import session diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py new file mode 100644 index 00000000..f9592238 --- /dev/null +++ b/test/test_packages_routes.py @@ -0,0 +1,283 @@ +from datetime import datetime +from http import HTTPStatus + +import pytest + +from fastapi.testclient import TestClient + +from aurweb import asgi, db +from aurweb.models.account_type import USER_ID, AccountType +from aurweb.models.dependency_type import DependencyType +from aurweb.models.official_provider import OfficialProvider +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_comment import PackageComment +from aurweb.models.package_dependency import PackageDependency +from aurweb.models.package_keyword import PackageKeyword +from aurweb.models.package_relation import PackageRelation +from aurweb.models.relation_type import PROVIDES_ID, RelationType +from aurweb.models.user import User +from aurweb.testing import setup_test_db +from aurweb.testing.html import parse_root +from aurweb.testing.requests import Request + + +def package_endpoint(package: Package) -> str: + return f"/packages/{package.Name}" + + +def create_package(pkgname: str, maintainer: User, + autocommit: bool = True) -> Package: + pkgbase = db.create(PackageBase, + Name=pkgname, + Maintainer=maintainer, + autocommit=False) + return db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase, + autocommit=autocommit) + + +def create_package_dep(package: Package, depname: str, + dep_type_name: str = "depends", + autocommit: bool = True) -> PackageDependency: + dep_type = db.query(DependencyType, + DependencyType.Name == dep_type_name).first() + return db.create(PackageDependency, + DependencyType=dep_type, + Package=package, + DepName=depname, + autocommit=autocommit) + + +def create_package_rel(package: Package, + relname: str, + autocommit: bool = True) -> PackageRelation: + rel_type = db.query(RelationType, + RelationType.ID == PROVIDES_ID).first() + return db.create(PackageRelation, + RelationType=rel_type, + Package=package, + RelName=relname) + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db( + User.__tablename__, + Package.__tablename__, + PackageBase.__tablename__, + PackageDependency.__tablename__, + PackageRelation.__tablename__, + PackageKeyword.__tablename__, + OfficialProvider.__tablename__ + ) + + +@pytest.fixture +def client() -> TestClient: + """ Yield a FastAPI TestClient. """ + yield TestClient(app=asgi.app) + + +@pytest.fixture +def user() -> User: + """ Yield a user. """ + account_type = db.query(AccountType, AccountType.ID == USER_ID).first() + yield db.create(User, Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountType=account_type) + + +@pytest.fixture +def maintainer() -> User: + """ Yield a specific User used to maintain packages. """ + account_type = db.query(AccountType, AccountType.ID == USER_ID).first() + yield db.create(User, Username="test_maintainer", + Email="test_maintainer@example.org", + Passwd="testPassword", + AccountType=account_type) + + +@pytest.fixture +def package(maintainer: User) -> Package: + """ Yield a Package created by user. """ + pkgbase = db.create(PackageBase, + Name="test-package", + Maintainer=maintainer) + yield db.create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name) + + +def test_package_not_found(client: TestClient): + with client as request: + resp = request.get("/packages/not_found") + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_package_official_not_found(client: TestClient, package: Package): + """ When a Package has a matching OfficialProvider record, it is not + hosted on AUR, but in the official repositories. Getting a package + with this kind of record should return a status code 404. """ + db.create(OfficialProvider, + Name=package.Name, + Repo="core", + Provides=package.Name) + + with client as request: + resp = request.get(package_endpoint(package)) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_package(client: TestClient, package: Package): + """ Test a single /packages/{name} route. """ + with client as request: + + resp = request.get(package_endpoint(package)) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + h2 = root.find('.//div[@id="pkgdetails"]/h2') + + sections = h2.text.split(":") + assert sections[0] == "Package Details" + + name, version = sections[1].lstrip().split(" ") + assert name == package.Name + version == package.Version + + rows = root.findall('.//table[@id="pkginfo"]//tr') + row = rows[1] # Second row is our target. + + pkgbase = row.find("./td/a") + assert pkgbase.text.strip() == package.PackageBase.Name + + +def test_package_comments(client: TestClient, user: User, package: Package): + now = (datetime.utcnow().timestamp()) + comment = db.create(PackageComment, PackageBase=package.PackageBase, + User=user, Comments="Test comment", CommentTS=now) + + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get(package_endpoint(package), cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + expected = [ + comment.Comments + ] + comments = root.xpath('.//div[contains(@class, "package-comments")]' + '/div[@class="article-content"]/div/text()') + for i, row in enumerate(expected): + assert comments[i].strip() == row + + +def test_package_authenticated(client: TestClient, user: User, + package: Package): + """ We get the same here for either authenticated or not + authenticated. Form inputs are presented to maintainers. + This process also occurs when pkgbase.html is rendered. """ + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get(package_endpoint(package), cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + expected = [ + "View PKGBUILD", + "View Changes", + "Download snapshot", + "Search wiki", + "Flag package out-of-date", + "Vote for this package", + "Enable notifications", + "Submit Request" + ] + for expected_text in expected: + assert expected_text in resp.text + + +def test_package_authenticated_maintainer(client: TestClient, + maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + resp = request.get(package_endpoint(package), cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + expected = [ + "View PKGBUILD", + "View Changes", + "Download snapshot", + "Search wiki", + "Flag package out-of-date", + "Vote for this package", + "Enable notifications", + "Manage Co-Maintainers", + "Submit Request", + "Delete Package", + "Merge Package", + "Disown Package" + ] + for expected_text in expected: + assert expected_text in resp.text + + +def test_package_dependencies(client: TestClient, maintainer: User, + package: Package): + # Create a normal dependency of type depends. + dep_pkg = create_package("test-dep-1", maintainer, autocommit=False) + dep = create_package_dep(package, dep_pkg.Name, autocommit=False) + + # Also, create a makedepends. + make_dep_pkg = create_package("test-dep-2", maintainer, autocommit=False) + make_dep = create_package_dep(package, make_dep_pkg.Name, + dep_type_name="makedepends", + autocommit=False) + + # And... a checkdepends! + check_dep_pkg = create_package("test-dep-3", maintainer, autocommit=False) + check_dep = create_package_dep(package, check_dep_pkg.Name, + dep_type_name="checkdepends", + autocommit=False) + + # Geez. Just stop. This is optdepends. + opt_dep_pkg = create_package("test-dep-4", maintainer, autocommit=False) + opt_dep = create_package_dep(package, opt_dep_pkg.Name, + dep_type_name="optdepends", + autocommit=False) + + broken_dep = create_package_dep(package, "test-dep-5", + dep_type_name="depends", + autocommit=False) + + # Create an official provider record. + db.create(OfficialProvider, Name="test-dep-99", + Repo="core", Provides="test-dep-99", + autocommit=False) + official_dep = create_package_dep(package, "test-dep-99", + autocommit=False) + + # Also, create a provider who provides our test-dep-99. + provider = create_package("test-provider", maintainer, autocommit=False) + create_package_rel(provider, dep.DepName) + + with client as request: + resp = request.get(package_endpoint(package)) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + + expected = [ + dep.DepName, + make_dep.DepName, + check_dep.DepName, + opt_dep.DepName, + official_dep.DepName + ] + pkgdeps = root.findall('.//ul[@id="pkgdepslist"]/li/a') + for i, expectation in enumerate(expected): + assert pkgdeps[i].text.strip() == expectation + + broken_node = root.find('.//ul[@id="pkgdepslist"]/li/span') + assert broken_node.text.strip() == broken_dep.DepName diff --git a/test/test_packages_util.py b/test/test_packages_util.py new file mode 100644 index 00000000..17978490 --- /dev/null +++ b/test/test_packages_util.py @@ -0,0 +1,51 @@ +import pytest + +from fastapi.testclient import TestClient + +from aurweb import asgi, db +from aurweb.models.account_type import USER_ID, AccountType +from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.user import User +from aurweb.packages import util +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db( + User.__tablename__, + Package.__tablename__, + PackageBase.__tablename__, + OfficialProvider.__tablename__ + ) + + +@pytest.fixture +def maintainer() -> User: + account_type = db.query(AccountType, AccountType.ID == USER_ID).first() + yield db.create(User, Username="test_maintainer", + Email="test_maintainer@examepl.org", + Passwd="testPassword", + AccountType=account_type) + + +@pytest.fixture +def package(maintainer: User) -> Package: + pkgbase = db.create(PackageBase, Name="test-pkg", Maintainer=maintainer) + yield db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) + + +@pytest.fixture +def client() -> TestClient: + yield TestClient(app=asgi.app) + + +def test_package_link(client: TestClient, maintainer: User, package: Package): + db.create(OfficialProvider, + Name=package.Name, + Repo="core", + Provides=package.Name) + expected = f"{OFFICIAL_BASE}/packages/?q={package.Name}" + assert util.package_link(package) == expected diff --git a/test/test_templates.py b/test/test_templates.py new file mode 100644 index 00000000..8e3017b4 --- /dev/null +++ b/test/test_templates.py @@ -0,0 +1,15 @@ +import pytest + +from aurweb.templates import register_filter + + +@register_filter("func") +def func(): pass + + +def test_register_filter_exists_key_error(): + """ Most instances of register_filter are tested through module + imports or template renders, so we only test failures here. """ + with pytest.raises(KeyError): + @register_filter("func") + def some_func(): pass diff --git a/web/html/js/copy.js b/web/html/js/copy.js new file mode 100644 index 00000000..f46299b3 --- /dev/null +++ b/web/html/js/copy.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + document.querySelector('.copy').addEventListener('click', function(e) { + e.preventDefault(); + navigator.clipboard.writeText(event.target.text); + }); +}); From 88569b6d0987dd58e11198964e7bf597ed75d311 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 15 Jul 2021 22:54:41 -0700 Subject: [PATCH 0813/1891] add /pkgbase/{name} route Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 17 +++++++++ .../partials/packages/pkgbase_metadata.html | 13 +++++++ templates/pkgbase.html | 21 +++++++++++ test/test_packages_routes.py | 37 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 templates/partials/packages/pkgbase_metadata.html create mode 100644 templates/pkgbase.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 9650df85..cb7f4a18 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -96,3 +96,20 @@ async def package(request: Request, name: str) -> Response: context["conflicts"] = conflicts return render_template(request, "packages/show.html", context) + + +@router.get("/pkgbase/{name}") +async def package_base(request: Request, name: str) -> Response: + # Get the PackageBase. + pkgbase = get_pkgbase(name) + + # If this is not a split package, redirect to /packages/{name}. + if pkgbase.packages.count() == 1: + return RedirectResponse(f"/packages/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + # Add our base information. + context = await make_single_context(request, pkgbase) + context["packages"] = pkgbase.packages.all() # Doesn't need to be here. + + return render_template(request, "pkgbase.html", context) diff --git a/templates/partials/packages/pkgbase_metadata.html b/templates/partials/packages/pkgbase_metadata.html new file mode 100644 index 00000000..ba27fda5 --- /dev/null +++ b/templates/partials/packages/pkgbase_metadata.html @@ -0,0 +1,13 @@ +
    +

    Packages ({{ packages_count }})

    + +
    diff --git a/templates/pkgbase.html b/templates/pkgbase.html new file mode 100644 index 00000000..315cdf67 --- /dev/null +++ b/templates/pkgbase.html @@ -0,0 +1,21 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} + {% include "partials/packages/search.html" %} +
    +

    {{ 'Package Base Details' | tr }}: {{ pkgbase.Name }}

    + + {% set result = pkgbase %} + {% include "partials/packages/actions.html" %} + {% include "partials/packages/details.html" %} + +
    + {% include "partials/packages/pkgbase_metadata.html" %} +
    +
    + + {% set pkgname = result.Name %} + {% set pkgbase_id = result.ID %} + {% set comments = comments %} + {% include "partials/packages/comments.html" %} +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index f9592238..44ef7fcd 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -281,3 +281,40 @@ def test_package_dependencies(client: TestClient, maintainer: User, broken_node = root.find('.//ul[@id="pkgdepslist"]/li/span') assert broken_node.text.strip() == broken_dep.DepName + + +def test_pkgbase_not_found(client: TestClient): + with client as request: + resp = request.get("/pkgbase/not_found") + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_redirect(client: TestClient, package: Package): + with client as request: + resp = request.get(f"/pkgbase/{package.Name}", + allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/packages/{package.Name}" + + +def test_pkgbase(client: TestClient, package: Package): + second = db.create(Package, Name="second-pkg", + PackageBase=package.PackageBase) + + expected = [package.Name, second.Name] + with client as request: + resp = request.get(f"/pkgbase/{package.Name}", + allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + + # Check the details box title. + title = root.find('.//div[@id="pkgdetails"]/h2') + title, pkgname = title.text.split(": ") + assert title == "Package Base Details" + assert pkgname == package.Name + + pkgs = root.findall('.//div[@id="pkgs"]/ul/li/a') + for i, name in enumerate(expected): + assert pkgs[i].text.strip() == name From 04d1c81d3dc3af59749ca3555a9fd45f4a9fcb78 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 27 Jul 2021 22:03:38 -0700 Subject: [PATCH 0814/1891] bugfix: fix extra dependency annotations These were being displayed regardless of the dep type and state of DepDesc. This is fixed with this commit. Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 2 ++ templates/partials/packages/package_metadata.html | 6 ++++-- test/test_packages_routes.py | 11 ++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 6681d479..698ae1af 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -46,6 +46,8 @@ def dep_extra(dep: PackageDependency) -> str: @register_filter("dep_extra_desc") def dep_extra_desc(dep: PackageDependency) -> str: extra = dep_extra(dep) + if not dep.DepDesc: + return extra return extra + f" – {dep.DepDesc}" diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html index 767e25a9..7ec95699 100644 --- a/templates/partials/packages/package_metadata.html +++ b/templates/partials/packages/package_metadata.html @@ -16,9 +16,11 @@ {% endif %} {{ dep.Package | provides_list(dep.DepName) | safe }} - {% set extra = dep | dep_extra %} - {% if extra %} + + {% if dep.DepTypeID == 4 %} {{ dep | dep_extra_desc }} + {% else %} + {{ dep | dep_extra }} {% endif %}
  • {% endfor %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 44ef7fcd..82fbba40 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -247,7 +247,15 @@ def test_package_dependencies(client: TestClient, maintainer: User, dep_type_name="optdepends", autocommit=False) - broken_dep = create_package_dep(package, "test-dep-5", + # Heh. Another optdepends to test one with a description. + opt_desc_dep_pkg = create_package("test-dep-5", maintainer, + autocommit=False) + opt_desc_dep = create_package_dep(package, opt_desc_dep_pkg.Name, + dep_type_name="optdepends", + autocommit=False) + opt_desc_dep.DepDesc = "Test description." + + broken_dep = create_package_dep(package, "test-dep-6", dep_type_name="depends", autocommit=False) @@ -273,6 +281,7 @@ def test_package_dependencies(client: TestClient, maintainer: User, make_dep.DepName, check_dep.DepName, opt_dep.DepName, + opt_desc_dep.DepName, official_dep.DepName ] pkgdeps = root.findall('.//ul[@id="pkgdepslist"]/li/a') From bace345da4c6ff4f89e6cda0f916d8789ea5dba8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 8 Aug 2021 18:32:35 -0700 Subject: [PATCH 0815/1891] Docker: support both '%' and 'localhost' in mariadb This is needed to be able to reach the mysql service from other hosts or through localhost. Handling both cases here means that we can support both localhost access and host access. Signed-off-by: Kevin Morris --- docker/mariadb-entrypoint.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docker/mariadb-entrypoint.sh b/docker/mariadb-entrypoint.sh index e38900c8..945a4b82 100755 --- a/docker/mariadb-entrypoint.sh +++ b/docker/mariadb-entrypoint.sh @@ -18,15 +18,19 @@ DATABASE="aurweb" # Persistent database for fastapi/php-fpm. TEST_DB="aurweb_test" # Test database (ephemereal). echo "Taking care of primary database '${DATABASE}'..." -mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'$DB_HOST' IDENTIFIED BY 'aur';" +mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'localhost' IDENTIFIED BY 'aur';" +mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'%' IDENTIFIED BY 'aur';" mysql -u root -e "CREATE DATABASE IF NOT EXISTS $DATABASE;" -mysql -u root -e "GRANT ALL ON ${DATABASE}.* TO 'aur'@'$DB_HOST';" +mysql -u root -e "GRANT ALL ON ${DATABASE}.* TO 'aur'@'localhost';" +mysql -u root -e "GRANT ALL ON ${DATABASE}.* TO 'aur'@'%';" # Drop and create our test database. echo "Dropping test database '$TEST_DB'..." mysql -u root -e "DROP DATABASE IF EXISTS $TEST_DB;" mysql -u root -e "CREATE DATABASE $TEST_DB;" -mysql -u root -e "GRANT ALL ON ${TEST_DB}.* TO 'aur'@'$DB_HOST';" +mysql -u root -e "GRANT ALL ON ${TEST_DB}.* TO 'aur'@'localhost';" +mysql -u root -e "GRANT ALL ON ${TEST_DB}.* TO 'aur'@'%';" + echo "Created new '$TEST_DB'!" mysqladmin -uroot shutdown From 4ade8b053992663242df361477ca26282cadfc20 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 6 Aug 2021 00:59:38 -0700 Subject: [PATCH 0816/1891] routers.packages: Simplify some existence checks Signed-off-by: Kevin Morris --- aurweb/auth.py | 15 ++++++++ aurweb/models/package_dependency.py | 2 +- aurweb/packages/util.py | 18 ++++------ aurweb/routers/packages.py | 44 +++++++++++------------ templates/partials/packages/comments.html | 2 +- templates/partials/packages/details.html | 10 +++--- 6 files changed, 48 insertions(+), 43 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 316e7293..26e4073d 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -19,6 +19,17 @@ from aurweb.models.user import User from aurweb.templates import make_variable_context, render_template +class StubQuery: + """ Acts as a stubbed version of an orm.Query. Typically used + to masquerade fake records for an AnonymousUser. """ + + def filter(self, *args): + return StubQuery() + + def scalar(self): + return 0 + + class AnonymousUser: # Stub attributes used to mimic a real user. ID = 0 @@ -28,6 +39,10 @@ class AnonymousUser: # A stub ssh_pub_key relationship. ssh_pub_key = None + # Add stubbed relationship backrefs. + package_notifications = StubQuery() + package_votes = StubQuery() + # A nonce attribute, needed for all browser sessions; set in __init__. nonce = None diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index 0e5b028b..9ce0b019 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -69,4 +69,4 @@ class PackageDependency(Base): pkg = db.query(Package, Package.Name == self.DepName) official = db.query(OfficialProvider, OfficialProvider.Name == self.DepName) - return pkg.count() > 0 or official.count() > 0 + return pkg.scalar() or official.scalar() diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 698ae1af..60db2962 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -54,10 +54,9 @@ def dep_extra_desc(dep: PackageDependency) -> str: @register_filter("pkgname_link") def pkgname_link(pkgname: str) -> str: base = "/".join([OFFICIAL_BASE, "packages"]) - pkg = db.query(Package).filter(Package.Name == pkgname) official = db.query(OfficialProvider).filter( OfficialProvider.Name == pkgname) - if not pkg.count() or official.count(): + if official.scalar(): return f"{base}/?q={pkgname}" return f"/packages/{pkgname}" @@ -67,7 +66,7 @@ def package_link(package: Package) -> str: base = "/".join([OFFICIAL_BASE, "packages"]) official = db.query(OfficialProvider).filter( OfficialProvider.Name == package.Name) - if official.count(): + if official.scalar(): return f"{base}/?q={package.Name}" return f"/packages/{package.Name}" @@ -82,19 +81,14 @@ def provides_list(package: Package, depname: str) -> list: ) ) - string = str() - has_providers = providers.count() > 0 - - if has_providers: - string += "(" - - string += ", ".join([ + string = ", ".join([ f'{pkg.Name}' for pkg in providers ]) - if has_providers: - string += ")" + if string: + # If we actually constructed a string, wrap it. + string = f"({string})" return string diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index cb7f4a18..0ffcbfb9 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -19,9 +19,9 @@ from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote -from aurweb.models.relation_type import CONFLICTS_ID, RelationType +from aurweb.models.relation_type import CONFLICTS_ID from aurweb.packages.util import get_pkgbase -from aurweb.templates import make_variable_context, render_template +from aurweb.templates import make_context, render_template router = APIRouter() @@ -34,7 +34,7 @@ async def make_single_context(request: Request, :param pkgbase: PackageBase instance :return: A pkgbase context without specific differences """ - context = await make_variable_context(request, pkgbase.Name) + context = make_context(request, pkgbase.Name) context["git_clone_uri_anon"] = aurweb.config.get("options", "git_clone_uri_anon") context["git_clone_uri_priv"] = aurweb.config.get("options", @@ -44,20 +44,15 @@ async def make_single_context(request: Request, context["keywords"] = pkgbase.keywords context["comments"] = pkgbase.comments context["is_maintainer"] = (request.user.is_authenticated() - and request.user == pkgbase.Maintainer) - context["notified"] = db.query( - PackageNotification).join(PackageBase).filter( - and_(PackageBase.ID == pkgbase.ID, - PackageNotification.UserID == request.user.ID)).count() > 0 + and request.user.ID == pkgbase.MaintainerUID) + context["notified"] = request.user.package_notifications.filter( + PackageNotification.PackageBaseID == pkgbase.ID + ).scalar() context["out_of_date"] = bool(pkgbase.OutOfDateTS) - context["voted"] = pkgbase.package_votes.filter( - PackageVote.UsersID == request.user.ID).count() > 0 - - context["notifications_enabled"] = db.query( - PackageNotification).join(PackageBase).filter( - PackageBase.ID == pkgbase.ID).count() > 0 + context["voted"] = request.user.package_votes.filter( + PackageVote.PackageBaseID == pkgbase.ID).scalar() return context @@ -71,13 +66,12 @@ async def package(request: Request, name: str) -> Response: context = await make_single_context(request, pkgbase) # Package sources. - sources = db.query(PackageSource).join(Package).filter( - Package.PackageBaseID == pkgbase.ID) - context["sources"] = sources + context["sources"] = db.query(PackageSource).join(Package).join( + PackageBase).filter(PackageBase.ID == pkgbase.ID) # Package dependencies. - dependencies = db.query(PackageDependency).join(Package).filter( - Package.PackageBaseID == pkgbase.ID) + dependencies = db.query(PackageDependency).join(Package).join( + PackageBase).filter(PackageBase.ID == pkgbase.ID) context["dependencies"] = dependencies # Package requirements (other packages depend on this one). @@ -86,13 +80,15 @@ async def package(request: Request, name: str) -> Response: Package.Name.asc()) context["required_by"] = required_by - licenses = db.query(License).join(PackageLicense).join(Package).filter( - PackageLicense.PackageID == pkgbase.packages.first().ID) + licenses = db.query(License).join(PackageLicense).join(Package).join( + PackageBase).filter(PackageBase.ID == pkgbase.ID) context["licenses"] = licenses - conflicts = db.query(PackageRelation).join(RelationType).join(Package).join(PackageBase).filter( - and_(RelationType.ID == CONFLICTS_ID, - PackageBase.ID == pkgbase.ID)) + conflicts = db.query(PackageRelation).join(Package).join( + PackageBase).filter( + and_(PackageRelation.RelTypeID == CONFLICTS_ID, + PackageBase.ID == pkgbase.ID) + ) context["conflicts"] = conflicts return render_template(request, "packages/show.html", context) diff --git a/templates/partials/packages/comments.html b/templates/partials/packages/comments.html index f1bc020d..051849b0 100644 --- a/templates/partials/packages/comments.html +++ b/templates/partials/packages/comments.html @@ -49,7 +49,7 @@ {% endif %} -{% if comments.count() %} +{% if comments.scalar() %}

    diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index a25e9c9e..83c6d53b 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -1,3 +1,4 @@ +{% set pkg = pkgbase.packages.first() %} @@ -19,12 +20,11 @@ - + {% endif %} - {% if pkgbase.keywords.count() %} + {% if pkgbase.keywords.scalar() %} {% if is_maintainer %} @@ -63,13 +63,13 @@ {% endif %} {% endif %} - {% if licenses and licenses.count() and show_package_details | default(False) %} + {% if licenses and licenses.scalar() and show_package_details %} {% endif %} - {% if show_package_details | default(False) %} + {% if show_package_details %} - - + {% if request.user.is_authenticated() %} + + + {% endif %} @@ -21,33 +23,33 @@ {{ pkg.Name }} - {% if flagged %} - - {% else %} - - {% endif %} + {{ pkg.Version }} - - - + + {% if request.user.is_authenticated() %} + + + {% endif %} {% endfor %} From f147ef34767a91c0171b6d69ca2a2749ea0f4994 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 18 Aug 2021 22:14:35 -0700 Subject: [PATCH 0832/1891] models.account_type: remove duplicated constants Clearly made in mistake, removing to keep things organized. Signed-off-by: Kevin Morris --- aurweb/models/account_type.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py index 0db37ced..2e3dde06 100644 --- a/aurweb/models/account_type.py +++ b/aurweb/models/account_type.py @@ -28,12 +28,6 @@ class AccountType(Base): self.ID, str(self)) -# Define some AccountType.AccountType constants. -USER = "User" -TRUSTED_USER = "Trusted User" -DEVELOPER = "Developer" -TRUSTED_USER_AND_DEV = "Trusted User & Developer" - # Fetch account type IDs from the database for constants. _account_types = db.query(AccountType) USER_ID = _account_types.filter( From fb908189b61cce6241d8b4afdb4010ea279dfeea Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sat, 28 Aug 2021 17:18:32 -0500 Subject: [PATCH 0833/1891] Began port of dependencies to pip Adds Python dependencies to requirements list to allow installation via pip --- requirements.txt | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..1c760057 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,40 @@ +# Arch Linux +pyalpm==0.10.6 +srcinfo==0.0.8 + +# Generic +authlib==0.15.2 +aiofiles==0.7.0 +asgiref==3.4.1 +bcrypt==3.2.0 +bleach==3.3.1 +coverage==5.5 +email-validator==1.1.3 +fakeredis==1.6.0 +fastapi==0.66.0 +feedgen==0.9.0 +flake8==3.9.2 +httpx==0.18.2 +hypercorn==0.11.2 +isort==5.9.3 +itsdangerous==2.0.1 +jinja2==3.0.1 +lxml==4.6.3 +markdown==3.3.4 +orjson==3.6.3 +protobuf==3.17.3 +pygit2==1.6.1 +pytest==6.2.4 +pytest-asyncio==0.15.1 +pytest-cov==2.12.1 +pytest-tap==3.2 +python-multipart==0.0.5 +redis==3.5.3 +requests==2.26.0 +uvicorn==0.15.0 +werkzeug==2.0.1 + +# SQL +alembic==1.6.5 +sqlalchemy==1.3.23 +mysqlclient==2.0.3 From b88fa8386ae9359fbf0d7cabf6efd008bd4d760b Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sat, 28 Aug 2021 19:25:51 -0500 Subject: [PATCH 0834/1891] Removed pyalpm and srcinfo from pip requirements; Changed section title Changed 'Generic' to 'General' --- requirements.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1c760057..37a12f61 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,4 @@ -# Arch Linux -pyalpm==0.10.6 -srcinfo==0.0.8 - -# Generic +# General authlib==0.15.2 aiofiles==0.7.0 asgiref==3.4.1 From 0075ba3c33c18831e277ddfceac53d8653a9dcc6 Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sat, 28 Aug 2021 19:27:36 -0500 Subject: [PATCH 0835/1891] Added .python-version from Pyenv --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 4fdfa790..885d9c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ doc/rpc.html # Ignore any user-configured .envrc files at the root. /.envrc + +# Ignore .python-version file from Pyenv +.python-version From e69004bc4a135551fc89581147947fb8c8f0e68c Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sat, 28 Aug 2021 19:29:44 -0500 Subject: [PATCH 0836/1891] Alphabetized .gitignore file so it looks prettier --- .gitignore | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 885d9c2f..f7ec5a95 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,5 @@ -dummy-data.sql* -po/*.mo -po/*.po~ -po/POTFILES -web/locale/*/ -aur.git/ __pycache__/ *.py[cod] -test/test-results/ -test/trash directory* -schema/aur-schema-sqlite.sql -data.sql -aurweb.sqlite3 -conf/config -conf/config.sqlite -conf/config.sqlite.defaults -conf/docker -conf/docker.defaults -htmlcov/ -fastapi_aw/ .vim/ .pylintrc .coverage @@ -28,6 +10,24 @@ fastapi_aw/ /dist/ /aurweb.egg-info/ /pyrightconfig.json +aur.git/ +aurweb.sqlite3 +conf/config +conf/config.sqlite +conf/config.sqlite.defaults +conf/docker +conf/docker.defaults +data.sql +dummy-data.sql* +fastapi_aw/ +htmlcov/ +po/*.mo +po/*.po~ +po/POTFILES +schema/aur-schema-sqlite.sql +test/test-results/ +test/trash directory* +web/locale/*/ # Do not stage compiled asciidoc: make -C doc doc/rpc.html From e61050adcf41141d43a2018265b1c38b0c4031e4 Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sat, 28 Aug 2021 19:31:11 -0500 Subject: [PATCH 0837/1891] Added env/ to .gitignore Folder will be used under virtualenv for pip dependencies --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f7ec5a95..581d5c17 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ conf/docker conf/docker.defaults data.sql dummy-data.sql* +env/ fastapi_aw/ htmlcov/ po/*.mo From 85b1a05d0138888e2f06c8fc5b474314abd090e9 Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sat, 28 Aug 2021 19:51:05 -0500 Subject: [PATCH 0838/1891] Removed pip dependencies from docker/scripts/install-deps.sh --- docker/scripts/install-deps.sh | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index a532a6b2..d22fd460 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -5,16 +5,12 @@ set -eou pipefail pacman -Syu --noconfirm --noprogressbar \ - --cachedir .pkg-cache git gpgme protobuf pyalpm \ - python-mysqlclient python-pygit2 python-srcinfo python-bleach \ - python-markdown python-sqlalchemy python-alembic python-pytest \ - python-werkzeug python-pytest-tap python-fastapi nginx python-authlib \ - python-itsdangerous python-httpx python-jinja python-pytest-cov \ - python-requests python-aiofiles python-python-multipart \ - python-pytest-asyncio python-coverage hypercorn python-bcrypt \ - python-email-validator openssh python-lxml mariadb mariadb-libs \ - python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ - python-asgiref uvicorn python-feedgen memcached php-memcached \ - python-redis redis python-fakeredis python-orjson + --cachedir .pkg-cache git gpgme \ + nginx redis openssh \ + mariadb mariadb-libs \ + cgit uwsgi uwsgi-plugin-cgi \ + php php-fpm \ + memcached php-memcached \ + pyalpm python-srcinfo exec "$@" From eff7d478ab29d541c7a486cccd27c23d0e803e5d Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sat, 28 Aug 2021 20:12:35 -0500 Subject: [PATCH 0839/1891] Updated CI tests for pip dependencies; Changed styling in install-deps.sh --- .gitlab-ci.yml | 1 + Dockerfile | 26 +++++++++++++------------- docker/scripts/install-deps.sh | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7b8da2ae..d360d483 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,7 @@ variables: before_script: - ./docker/scripts/install-deps.sh + - pip install -r requirements.txt - useradd -U -d /aurweb -c 'AUR User' aur - ./docker/mariadb-entrypoint.sh - (cd '/usr' && /usr/bin/mysqld_safe --datadir='/var/lib/mysql') & diff --git a/Dockerfile b/Dockerfile index 2843fa1b..b610b8c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,19 @@ FROM archlinux:base-devel ENV PYTHONPATH=/aurweb ENV AUR_CONFIG=conf/config -# Copy our single bootstrap script. -COPY docker/scripts/install-deps.sh /install-deps.sh -RUN /install-deps.sh +# Copy Docker scripts +COPY ./docker /docker +COPY ./docker/scripts/*.sh /usr/local/bin/ + +# Copy over all aurweb files. +COPY . /aurweb + +# Working directory is aurweb root @ /aurweb. +WORKDIR /aurweb + +# Install dependencies +RUN docker/scripts/install-deps.sh +RUN pip install -r requirements.txt # Add our aur user. RUN useradd -U -d /aurweb -c 'AUR User' aur @@ -13,16 +23,6 @@ RUN useradd -U -d /aurweb -c 'AUR User' aur # Setup some default system stuff. RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime -# Copy the rest of docker. -COPY ./docker /docker -COPY ./docker/scripts/*.sh /usr/local/bin/ - -# Copy from host to container. -COPY . /aurweb - -# Working directory is aurweb root @ /aurweb. -WORKDIR /aurweb - # Install translations. RUN make -C po all install diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index d22fd460..4985fe85 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -11,6 +11,6 @@ pacman -Syu --noconfirm --noprogressbar \ cgit uwsgi uwsgi-plugin-cgi \ php php-fpm \ memcached php-memcached \ - pyalpm python-srcinfo + python-pip pyalpm python-srcinfo exec "$@" From a0be0185475e38adcb628b776f440efc5685c23d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 28 Aug 2021 21:30:36 -0700 Subject: [PATCH 0840/1891] Docker: Reorder dependency installation for cache purposes Signed-off-by: Kevin Morris --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b610b8c1..6539bd94 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,14 +7,16 @@ ENV AUR_CONFIG=conf/config COPY ./docker /docker COPY ./docker/scripts/*.sh /usr/local/bin/ +# Install system-wide dependencies. +RUN /docker/scripts/install-deps.sh + # Copy over all aurweb files. COPY . /aurweb # Working directory is aurweb root @ /aurweb. WORKDIR /aurweb -# Install dependencies -RUN docker/scripts/install-deps.sh +# Install pip directories now that we have access to /aurweb. RUN pip install -r requirements.txt # Add our aur user. From 1c26ce52a5e83abe99d5bea055aac8231b97428f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 30 Aug 2021 18:17:14 -0700 Subject: [PATCH 0841/1891] [FastAPI] include DepArch in dependency list Signed-off-by: Kevin Morris --- templates/partials/packages/package_metadata.html | 3 +++ test/test_packages_routes.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html index 7ec95699..e7b1aefb 100644 --- a/templates/partials/packages/package_metadata.html +++ b/templates/partials/packages/package_metadata.html @@ -16,6 +16,9 @@ {% endif %} {{ dep.Package | provides_list(dep.DepName) | safe }} + {% if dep.DepArch %} + ({{ dep.DepArch }}) + {% endif %} {% if dep.DepTypeID == 4 %} {{ dep | dep_extra_desc }} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 82fbba40..0c9d80e8 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -228,6 +228,7 @@ def test_package_dependencies(client: TestClient, maintainer: User, # Create a normal dependency of type depends. dep_pkg = create_package("test-dep-1", maintainer, autocommit=False) dep = create_package_dep(package, dep_pkg.Name, autocommit=False) + dep.DepArch = "x86_64" # Also, create a makedepends. make_dep_pkg = create_package("test-dep-2", maintainer, autocommit=False) @@ -288,6 +289,11 @@ def test_package_dependencies(client: TestClient, maintainer: User, for i, expectation in enumerate(expected): assert pkgdeps[i].text.strip() == expectation + # Let's make sure the DepArch was displayed for our first dep. + arch = root.findall('.//ul[@id="pkgdepslist"]/li')[0] + arch = arch.xpath('./em')[1] + assert arch.text.strip() == "(x86_64)" + broken_node = root.find('.//ul[@id="pkgdepslist"]/li/span') assert broken_node.text.strip() == broken_dep.DepName From 45fbf214b46fd5e3f90157ee2aaf94cdf62e62f4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 20 Aug 2021 16:29:04 -0700 Subject: [PATCH 0842/1891] jinja2: add 'tn' filter, a numerical translation The possibly plural version of `tr`, `tn` provides a way to translate strings into singular or plural form based on a given integer being 1 or not 1. Example use: ``` {{ 1 | tn("%d package found.", "%d packages found.") | format(1) }} ``` Signed-off-by: Kevin Morris --- aurweb/l10n.py | 18 ++++++++++++++++++ aurweb/templates.py | 3 ++- test/test_l10n.py | 12 ++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/aurweb/l10n.py b/aurweb/l10n.py index 9270f3ce..c4938d64 100644 --- a/aurweb/l10n.py +++ b/aurweb/l10n.py @@ -93,3 +93,21 @@ def tr(context: typing.Any, value: str): """ A translation filter; example: {{ "Hello" | tr("de") }}. """ _ = get_translator_for_request(context.get("request")) return _(value) + + +@pass_context +def tn(context: typing.Dict[str, typing.Any], count: int, + singular: str, plural: str) -> str: + """ A singular and plural translation filter. + + Example: + {{ some_integer | tn("singular %d", "plural %d") }} + + :param context: Response context + :param count: The number used to decide singular or plural state + :param singular: The singular translation + :param plural: The plural translation + :return: Translated string + """ + gettext = get_raw_translator_for_request(context.get("request")) + return gettext.ngettext(singular, plural, count) diff --git a/aurweb/templates.py b/aurweb/templates.py index fa7aa039..7530472f 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -23,8 +23,9 @@ loader = jinja2.FileSystemLoader(os.path.join( env = jinja2.Environment(loader=loader, autoescape=True, extensions=["jinja2.ext.i18n"]) -# Add tr translation filter. +# Add t{r,n} translation filters. env.filters["tr"] = l10n.tr +env.filters["tn"] = l10n.tn # Utility filters. env.filters["dt"] = util.timestamp_to_datetime diff --git a/test/test_l10n.py b/test/test_l10n.py index e833cd44..1c2ae95a 100644 --- a/test/test_l10n.py +++ b/test/test_l10n.py @@ -36,3 +36,15 @@ def test_get_translator_for_request(): translate = l10n.get_translator_for_request(request) assert translate("Home") == "Startseite" + + +def test_tn_filter(): + request = Request() + request.cookies["AURLANG"] = "en" + context = {"language": "en", "request": request} + + translated = l10n.tn(context, 1, "%d package found.", "%d packages found.") + assert translated == "%d package found." + + translated = l10n.tn(context, 2, "%d package found.", "%d packages found.") + assert translated == "%d packages found." From 55c29c4519c200f32ad2463a63f5a46f7a850f2c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 30 Aug 2021 18:27:17 -0700 Subject: [PATCH 0843/1891] partials/packages/details.html: Add package request count This was missed during the original implementation merge. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 5 +++ templates/partials/packages/actions.html | 8 ++++- test/test_packages_routes.py | 45 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 0ffcbfb9..0873bd9f 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -17,6 +17,7 @@ from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_license import PackageLicense from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation +from aurweb.models.package_request import PackageRequest from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID @@ -54,6 +55,10 @@ async def make_single_context(request: Request, context["voted"] = request.user.package_votes.filter( PackageVote.PackageBaseID == pkgbase.ID).scalar() + context["requests"] = pkgbase.requests.filter( + PackageRequest.ClosedTS.is_(None) + ).count() + return context diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 87db3a3f..346537be 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -124,7 +124,13 @@ {% endif %} -
  • + {% if requests %} +
  • + + {{ requests | tn("%d pending request", "%d pending requests") | format(requests) }} + +
  • + {% endif %}
  • {% if not request.user.is_authenticated() %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 0c9d80e8..ad07ec17 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -15,7 +15,9 @@ from aurweb.models.package_comment import PackageComment from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_keyword import PackageKeyword from aurweb.models.package_relation import PackageRelation +from aurweb.models.package_request import PackageRequest from aurweb.models.relation_type import PROVIDES_ID, RelationType +from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User from aurweb.testing import setup_test_db from aurweb.testing.html import parse_root @@ -173,6 +175,43 @@ def test_package_comments(client: TestClient, user: User, package: Package): assert comments[i].strip() == row +def test_package_requests_display(client: TestClient, user: User, + package: Package): + type_ = db.query(RequestType, RequestType.ID == DELETION_ID).first() + db.create(PackageRequest, PackageBase=package.PackageBase, + PackageBaseName=package.PackageBase.Name, + User=user, RequestType=type_, + Comments="Test comment.", + ClosureComment=str()) + + # Test that a single request displays "1 pending request". + with client as request: + resp = request.get(package_endpoint(package)) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + selector = '//div[@id="actionlist"]/ul/li/span[@class="flagged"]' + target = root.xpath(selector)[0] + assert target.text.strip() == "1 pending request" + + type_ = db.query(RequestType, RequestType.ID == DELETION_ID).first() + db.create(PackageRequest, PackageBase=package.PackageBase, + PackageBaseName=package.PackageBase.Name, + User=user, RequestType=type_, + Comments="Test comment2.", + ClosureComment=str()) + + # Test that a two requests display "2 pending requests". + with client as request: + resp = request.get(package_endpoint(package)) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + selector = '//div[@id="actionlist"]/ul/li/span[@class="flagged"]' + target = root.xpath(selector)[0] + assert target.text.strip() == "2 pending requests" + + def test_package_authenticated(client: TestClient, user: User, package: Package): """ We get the same here for either authenticated or not @@ -196,6 +235,12 @@ def test_package_authenticated(client: TestClient, user: User, for expected_text in expected: assert expected_text in resp.text + # When no requests are up, make sure we don't see the display for them. + root = parse_root(resp.text) + selector = '//div[@id="actionlist"]/ul/li/span[@class="flagged"]' + target = root.xpath(selector) + assert len(target) == 0 + def test_package_authenticated_maintainer(client: TestClient, maintainer: User, From 718ae1acba880d6ecf7488e88c3ac90bd357d493 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 30 Aug 2021 22:14:31 -0700 Subject: [PATCH 0844/1891] aurweb.templates: loader -> _loader, env -> _env These are module local globals and we don't want to expose global functionality to users, so privatize them with a leading `_` prefix. These things should **really** not be accessible by users. --- aurweb/templates.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/aurweb/templates.py b/aurweb/templates.py index 7530472f..48391b4a 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -18,29 +18,29 @@ import aurweb.config from aurweb import captcha, l10n, time, util # Prepare jinja2 objects. -loader = jinja2.FileSystemLoader(os.path.join( +_loader = jinja2.FileSystemLoader(os.path.join( aurweb.config.get("options", "aurwebdir"), "templates")) -env = jinja2.Environment(loader=loader, autoescape=True, - extensions=["jinja2.ext.i18n"]) +_env = jinja2.Environment(loader=_loader, autoescape=True, + extensions=["jinja2.ext.i18n"]) # Add t{r,n} translation filters. -env.filters["tr"] = l10n.tr -env.filters["tn"] = l10n.tn +_env.filters["tr"] = l10n.tr +_env.filters["tn"] = l10n.tn # Utility filters. -env.filters["dt"] = util.timestamp_to_datetime -env.filters["as_timezone"] = util.as_timezone -env.filters["dedupe_qs"] = util.dedupe_qs -env.filters["urlencode"] = quote_plus -env.filters["get_vote"] = util.get_vote -env.filters["number_format"] = util.number_format +_env.filters["dt"] = util.timestamp_to_datetime +_env.filters["as_timezone"] = util.as_timezone +_env.filters["dedupe_qs"] = util.dedupe_qs +_env.filters["urlencode"] = quote_plus +_env.filters["get_vote"] = util.get_vote +_env.filters["number_format"] = util.number_format # Add captcha filters. -env.filters["captcha_salt"] = captcha.captcha_salt_filter -env.filters["captcha_cmdline"] = captcha.captcha_cmdline_filter +_env.filters["captcha_salt"] = captcha.captcha_salt_filter +_env.filters["captcha_cmdline"] = captcha.captcha_cmdline_filter # Add account utility filters. -env.filters["account_url"] = util.account_url +_env.filters["account_url"] = util.account_url def register_filter(name: str) -> Callable: @@ -61,9 +61,9 @@ def register_filter(name: str) -> Callable: @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) - if name in env.filters: + if name in _env.filters: raise KeyError(f"Jinja already has a filter named '{name}'") - env.filters[name] = wrapper + _env.filters[name] = wrapper return wrapper return decorator @@ -105,12 +105,12 @@ def render_template(request: Request, status_code: HTTPStatus = HTTPStatus.OK): """ Render a Jinja2 multi-lingual template with some context. """ - # Create a deep copy of our jinja2 environment. The environment in + # Create a deep copy of our jinja2 _environment. The _environment in # total by itself is 48 bytes large (according to sys.getsizeof). # This is done so we can install gettext translations on the template - # environment being rendered without installing them into a global + # _environment being rendered without installing them into a global # which is reused in this function. - templates = copy.copy(env) + templates = copy.copy(_env) translator = l10n.get_raw_translator_for_request(context.get("request")) templates.install_gettext_translations(translator) From e15a18e9fb05afac2ddc1fdc12965b80eafa5435 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 30 Aug 2021 23:04:55 -0700 Subject: [PATCH 0845/1891] remove unneeded comment Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 0873bd9f..a20c97b1 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -111,6 +111,6 @@ async def package_base(request: Request, name: str) -> Response: # Add our base information. context = await make_single_context(request, pkgbase) - context["packages"] = pkgbase.packages.all() # Doesn't need to be here. + context["packages"] = pkgbase.packages.all() return render_template(request, "pkgbase.html", context) From 49cc12f99dbe2bc69edd09db39692ad2135473af Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 20 Aug 2021 14:44:36 -0700 Subject: [PATCH 0846/1891] jinja2: rename filter 'urlencode' to 'quote_plus' urlencode does more than just a quote_plus. Using urlencode was not sensible, so this commit addresses that. Signed-off-by: Kevin Morris --- aurweb/templates.py | 2 +- aurweb/util.py | 3 +++ templates/partials/packages/actions.html | 6 +++--- templates/partials/tu/proposal/voters.html | 2 +- templates/partials/tu/proposals.html | 6 +++--- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/aurweb/templates.py b/aurweb/templates.py index 48391b4a..a648d5a1 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -31,7 +31,7 @@ _env.filters["tn"] = l10n.tn _env.filters["dt"] = util.timestamp_to_datetime _env.filters["as_timezone"] = util.as_timezone _env.filters["dedupe_qs"] = util.dedupe_qs -_env.filters["urlencode"] = quote_plus +_env.filters["quote_plus"] = quote_plus _env.filters["get_vote"] = util.get_vote _env.filters["number_format"] = util.number_format diff --git a/aurweb/util.py b/aurweb/util.py index 860bdd12..494a988d 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -1,4 +1,5 @@ import base64 +import logging import math import random import re @@ -18,6 +19,8 @@ from jinja2 import pass_context import aurweb.config +logger = logging.getLogger(__name__) + def make_random_string(length): return ''.join(random.choices(string.ascii_lowercase diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 346537be..d552f2dd 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -42,12 +42,12 @@
  • {% endif %}
  • - + {{ "Vote for this package" | tr }}
  • - + {{ "Enable notifications" | tr }}
  • @@ -133,7 +133,7 @@ {% endif %}
  • {% if not request.user.is_authenticated() %} - + {{ "Submit Request" | tr }} {% else %} diff --git a/templates/partials/tu/proposal/voters.html b/templates/partials/tu/proposal/voters.html index 2fd42bdf..6069f97d 100644 --- a/templates/partials/tu/proposal/voters.html +++ b/templates/partials/tu/proposal/voters.html @@ -2,7 +2,7 @@
      {% for voter in voters %}
    • - + {{ voter.Username | e }}
    • diff --git a/templates/partials/tu/proposals.html b/templates/partials/tu/proposals.html index 13e705fc..ab90444e 100644 --- a/templates/partials/tu/proposals.html +++ b/templates/partials/tu/proposals.html @@ -23,7 +23,7 @@
  • @@ -97,7 +97,7 @@ {% set off_qs = "%s=%d" | format(off_param, off - 10) %} {% set by_qs = "%s=%s" | format(by_param, by | quote_plus) %} + href="?{{ q | extend_query([off_param, ([off - 10, 0] | max)], [by_param, by]) | urlencode }}"> ‹ Back {% endif %} @@ -106,7 +106,7 @@ {% set off_qs = "%s=%d" | format(off_param, off + 10) %} {% set by_qs = "%s=%s" | format(by_param, by | quote_plus) %} + href="?{{ q | extend_query([off_param, off + pp], [by_param, by]) | urlencode }}"> Next › {% endif %} diff --git a/test/test_util.py b/test/test_util.py index 06fc08d3..0cc45409 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -1,4 +1,3 @@ -from collections import OrderedDict from datetime import datetime from zoneinfo import ZoneInfo @@ -17,21 +16,6 @@ def test_as_timezone(): assert util.as_timezone(dt, "UTC") == dt.astimezone(tz=ZoneInfo("UTC")) -def test_dedupe_qs(): - items = OrderedDict() - items["key1"] = "test" - items["key2"] = "blah" - items["key3"] = 1 - - # Construct and test our query string. - query_string = '&'.join([f"{k}={v}" for k, v in items.items()]) - assert query_string == "key1=test&key2=blah&key3=1" - - # Add key1=changed and key2=changed to the query and dedupe it. - deduped = util.dedupe_qs(query_string, "key1=changed", "key3=changed") - assert deduped == "key2=blah&key1=changed&key3=changed" - - def test_number_format(): assert util.number_format(0.222, 2) == "0.22" assert util.number_format(0.226, 2) == "0.23" From b52059d43758e56729e475e01039b4ed19a64fab Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 31 Aug 2021 17:13:10 -0700 Subject: [PATCH 0850/1891] RPC: add deprecation warning for v1-v4 usage With FastAPI starting to come closer to a close, we've got to advertise this deprecation so that users have some time to adjust before making the changes. We have not specified a specific time here, but we'd like this message to reach users of the RPC API for at least a month before any modifications are made to the interface. Signed-off-by: Kevin Morris --- web/lib/aurjson.class.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 86eae22b..e7bc7f97 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -272,6 +272,15 @@ class AurJSON { 'results' => $data ); + if ($this->version != 5) { + $json_array['warning'] = 'The use of versions lower than 5 is ' + . 'now deprecated and will soon be unsupported. To ensure ' + . 'your API client supports the change without issue, it ' + . 'should use version 5 and adjust for any changes in the ' + . 'API interface. See https://aur.archlinux.org/rpc for ' + . 'documentation related to v5.'; + } + if ($error) { $json_array['error'] = $error; } From cfa95ef80ad758f1804896f582c73a8f907d9686 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 31 Aug 2021 17:13:10 -0700 Subject: [PATCH 0851/1891] RPC: add deprecation warning for v1-v4 usage With FastAPI starting to come closer to a close, we've got to advertise this deprecation so that users have some time to adjust before making the changes. We have not specified a specific time here, but we'd like this message to reach users of the RPC API for at least a month before any modifications are made to the interface. Signed-off-by: Kevin Morris --- web/lib/aurjson.class.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php index 86eae22b..e7bc7f97 100644 --- a/web/lib/aurjson.class.php +++ b/web/lib/aurjson.class.php @@ -272,6 +272,15 @@ class AurJSON { 'results' => $data ); + if ($this->version != 5) { + $json_array['warning'] = 'The use of versions lower than 5 is ' + . 'now deprecated and will soon be unsupported. To ensure ' + . 'your API client supports the change without issue, it ' + . 'should use version 5 and adjust for any changes in the ' + . 'API interface. See https://aur.archlinux.org/rpc for ' + . 'documentation related to v5.'; + } + if ($error) { $json_array['error'] = $error; } From a5943bf2add0231925d7836e2e0b587a4f5c7f05 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 2 Sep 2021 16:26:48 -0700 Subject: [PATCH 0852/1891] [FastAPI] Refactor db modifications For SQLAlchemy to automatically understand updates from the external world, it must use an `autocommit=True` in its session. This change breaks how we were using commit previously, as `autocommit=True` causes SQLAlchemy to commit when a SessionTransaction context hits __exit__. So, a refactoring was required of our tests: All usage of any `db.{create,delete}` must be called **within** a SessionTransaction context, created via new `db.begin()`. From this point forward, we're going to require: ``` with db.begin(): db.create(...) db.delete(...) db.session.delete(object) ``` With this, we now get external DB modifications automatically without reloading or restarting the FastAPI server, which we absolutely need for production. Signed-off-by: Kevin Morris --- aurweb/db.py | 44 +++++--- aurweb/models/user.py | 42 ++++---- aurweb/routers/accounts.py | 145 +++++++++++++-------------- aurweb/routers/html.py | 6 +- aurweb/routers/trusted_user.py | 20 ++-- test/test_account_type.py | 18 ++-- test/test_accounts_routes.py | 166 ++++++++++++++++--------------- test/test_api_rate_limit.py | 19 ++-- test/test_auth.py | 22 ++-- test/test_auth_routes.py | 9 +- test/test_ban.py | 10 +- test/test_db.py | 22 ++-- test/test_dependency_type.py | 14 ++- test/test_group.py | 11 +- test/test_homepage.py | 49 ++++----- test/test_license.py | 11 +- test/test_official_provider.py | 59 +++++------ test/test_package.py | 68 ++++++------- test/test_package_base.py | 61 ++++++------ test/test_package_blacklist.py | 16 +-- test/test_package_comment.py | 47 +++++---- test/test_package_dependency.py | 84 ++++++++-------- test/test_package_relation.py | 75 +++++++------- test/test_package_request.py | 99 ++++++++++-------- test/test_package_source.py | 23 +++-- test/test_packages_routes.py | 160 +++++++++++++++-------------- test/test_packages_util.py | 27 +++-- test/test_relation_type.py | 15 +-- test/test_request_type.py | 24 +++-- test/test_routes.py | 14 +-- test/test_rss.py | 15 ++- test/test_session.py | 34 ++++--- test/test_ssh_pub_key.py | 32 +++--- test/test_term.py | 19 ++-- test/test_trusted_user_routes.py | 166 ++++++++++++++++--------------- test/test_tu_voteinfo.py | 130 +++++++++++++----------- test/test_user.py | 124 ++++++++++++----------- 37 files changed, 998 insertions(+), 902 deletions(-) diff --git a/aurweb/db.py b/aurweb/db.py index c0147720..ea6b6918 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -59,20 +59,15 @@ def query(model, *args, **kwargs): return session.query(model).filter(*args, **kwargs) -def create(model, autocommit: bool = True, *args, **kwargs): +def create(model, *args, **kwargs): instance = model(*args, **kwargs) - add(instance) - if autocommit is True: - commit() - return instance + return add(instance) -def delete(model, *args, autocommit: bool = True, **kwargs): +def delete(model, *args, **kwargs): instance = session.query(model).filter(*args, **kwargs) for record in instance: session.delete(record) - if autocommit is True: - commit() def rollback(): @@ -84,8 +79,25 @@ def add(model): return model -def commit(): - session.commit() +def begin(): + """ Begin an SQLAlchemy SessionTransaction. + + This context is **required** to perform an modifications to the + database. + + Example: + + with db.begin(): + object = db.create(...) + # On __exit__, db.commit() is run. + + with db.begin(): + object = db.delete(...) + # On __exit__, db.commit() is run. + + :return: A new SessionTransaction based on session + """ + return session.begin() def get_sqlalchemy_url(): @@ -155,23 +167,23 @@ def get_engine(echo: bool = False): connect_args=connect_args, echo=echo) + Session = sessionmaker(autocommit=True, autoflush=False, bind=engine) + session = Session() + if db_backend == "sqlite": # For SQLite, we need to add some custom functions as # they are used in the reference graph method. def regexp(regex, item): return bool(re.search(regex, str(item))) - @event.listens_for(engine, "begin") - def do_begin(conn): + @event.listens_for(engine, "connect") + def do_begin(conn, record): create_deterministic_function = functools.partial( - conn.connection.create_function, + conn.create_function, deterministic=True ) create_deterministic_function("REGEXP", 2, regexp) - Session = sessionmaker(autocommit=False, autoflush=False, bind=engine) - session = Session() - return engine diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 0ccf7329..70d15f88 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -102,7 +102,7 @@ class User(Base): def login(self, request: Request, password: str, session_time=0): """ Login and authenticate a request. """ - from aurweb.db import session + from aurweb import db from aurweb.models.session import Session, generate_unique_sid if not self._login_approved(request): @@ -112,10 +112,7 @@ class User(Base): if not self.authenticated: return None - self.LastLogin = now_ts = datetime.utcnow().timestamp() - self.LastLoginIPAddress = request.client.host - session.commit() - + now_ts = datetime.utcnow().timestamp() session_ts = now_ts + ( session_time if session_time else aurweb.config.getint("options", "login_timeout") @@ -123,22 +120,23 @@ class User(Base): sid = None - if not self.session: - sid = generate_unique_sid() - self.session = Session(UsersID=self.ID, SessionID=sid, - LastUpdateTS=session_ts) - session.add(self.session) - else: - last_updated = self.session.LastUpdateTS - if last_updated and last_updated < now_ts: - self.session.SessionID = sid = generate_unique_sid() + with db.begin(): + self.LastLogin = now_ts + self.LastLoginIPAddress = request.client.host + if not self.session: + sid = generate_unique_sid() + self.session = Session(UsersID=self.ID, SessionID=sid, + LastUpdateTS=session_ts) + db.add(self.session) else: - # Session is still valid; retrieve the current SID. - sid = self.session.SessionID + last_updated = self.session.LastUpdateTS + if last_updated and last_updated < now_ts: + self.session.SessionID = sid = generate_unique_sid() + else: + # Session is still valid; retrieve the current SID. + sid = self.session.SessionID - self.session.LastUpdateTS = session_ts - - session.commit() + self.session.LastUpdateTS = session_ts request.cookies["AURSID"] = self.session.SessionID return self.session.SessionID @@ -149,13 +147,11 @@ class User(Base): return aurweb.auth.has_credential(self, cred, approved) def logout(self, request): - from aurweb.db import session - del request.cookies["AURSID"] self.authenticated = False if self.session: - session.delete(self.session) - session.commit() + with db.begin(): + db.session.delete(self.session) def is_trusted_user(self): return self.AccountType.ID in { diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 466d129d..ef4b99af 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -43,8 +43,6 @@ async def passreset_post(request: Request, resetkey: str = Form(default=None), password: str = Form(default=None), confirm: str = Form(default=None)): - from aurweb.db import session - context = await make_variable_context(request, "Password Reset") # The user parameter being required, we can match against @@ -86,12 +84,11 @@ async def passreset_post(request: Request, # We got to this point; everything matched up. Update the password # and remove the ResetKey. - user.ResetKey = str() - user.update_password(password) - - if user.session: - session.delete(user.session) - session.commit() + with db.begin(): + user.ResetKey = str() + if user.session: + db.session.delete(user.session) + user.update_password(password) # Render ?step=complete. return RedirectResponse(url="/passreset?step=complete", @@ -99,8 +96,8 @@ async def passreset_post(request: Request, # If we got here, we continue with issuing a resetkey for the user. resetkey = db.make_random_value(User, User.ResetKey) - user.ResetKey = resetkey - session.commit() + with db.begin(): + user.ResetKey = resetkey executor = db.ConnectionExecutor(db.get_engine().raw_connection()) ResetKeyNotification(executor, user.ID).send() @@ -364,8 +361,6 @@ async def account_register_post(request: Request, ON: bool = Form(default=False), captcha: str = Form(default=None), captcha_salt: str = Form(...)): - from aurweb.db import session - context = await make_variable_context(request, "Register") args = dict(await request.form()) @@ -394,11 +389,13 @@ async def account_register_post(request: Request, AccountType.AccountType == "User").first() # Create a user given all parameters available. - user = db.create(User, Username=U, Email=E, HideEmail=H, BackupEmail=BE, - RealName=R, Homepage=HP, IRCNick=I, PGPKey=K, - LangPreference=L, Timezone=TZ, CommentNotify=CN, - UpdateNotify=UN, OwnershipNotify=ON, ResetKey=resetkey, - AccountType=account_type) + with db.begin(): + user = db.create(User, Username=U, + Email=E, HideEmail=H, BackupEmail=BE, + RealName=R, Homepage=HP, IRCNick=I, PGPKey=K, + LangPreference=L, Timezone=TZ, CommentNotify=CN, + UpdateNotify=UN, OwnershipNotify=ON, + ResetKey=resetkey, AccountType=account_type) # If a PK was given and either one does not exist or the given # PK mismatches the existing user's SSHPubKey.PubKey. @@ -410,10 +407,10 @@ async def account_register_post(request: Request, # Remove the host part. pubkey = parts[0] + " " + parts[1] fingerprint = get_fingerprint(pubkey) - user.ssh_pub_key = SSHPubKey(UserID=user.ID, - PubKey=pubkey, - Fingerprint=fingerprint) - session.commit() + with db.begin(): + user.ssh_pub_key = SSHPubKey(UserID=user.ID, + PubKey=pubkey, + Fingerprint=fingerprint) # Send a reset key notification to the new user. executor = db.ConnectionExecutor(db.get_engine().raw_connection()) @@ -499,63 +496,67 @@ async def account_edit_post(request: Request, status_code=int(HTTPStatus.BAD_REQUEST)) # Set all updated fields as needed. - user.Username = U or user.Username - user.Email = E or user.Email - user.HideEmail = bool(H) - user.BackupEmail = BE or user.BackupEmail - user.RealName = R or user.RealName - user.Homepage = HP or user.Homepage - user.IRCNick = I or user.IRCNick - user.PGPKey = K or user.PGPKey - user.InactivityTS = datetime.utcnow().timestamp() if J else 0 + with db.begin(): + user.Username = U or user.Username + user.Email = E or user.Email + user.HideEmail = bool(H) + user.BackupEmail = BE or user.BackupEmail + user.RealName = R or user.RealName + user.Homepage = HP or user.Homepage + user.IRCNick = I or user.IRCNick + user.PGPKey = K or user.PGPKey + user.InactivityTS = datetime.utcnow().timestamp() if J else 0 # If we update the language, update the cookie as well. if L and L != user.LangPreference: request.cookies["AURLANG"] = L - user.LangPreference = L + with db.begin(): + user.LangPreference = L context["language"] = L # If we update the timezone, also update the cookie. if TZ and TZ != user.Timezone: - user.Timezone = TZ + with db.begin(): + user.Timezone = TZ request.cookies["AURTZ"] = TZ context["timezone"] = TZ - user.CommentNotify = bool(CN) - user.UpdateNotify = bool(UN) - user.OwnershipNotify = bool(ON) + with db.begin(): + user.CommentNotify = bool(CN) + user.UpdateNotify = bool(UN) + user.OwnershipNotify = bool(ON) # If a PK is given, compare it against the target user's PK. - if PK: - # Get the second token in the public key, which is the actual key. - pubkey = PK.strip().rstrip() - parts = pubkey.split(" ") - if len(parts) == 3: - # Remove the host part. - pubkey = parts[0] + " " + parts[1] - fingerprint = get_fingerprint(pubkey) - if not user.ssh_pub_key: - # No public key exists, create one. - user.ssh_pub_key = SSHPubKey(UserID=user.ID, - PubKey=pubkey, - Fingerprint=fingerprint) - elif user.ssh_pub_key.PubKey != pubkey: - # A public key already exists, update it. - user.ssh_pub_key.PubKey = pubkey - user.ssh_pub_key.Fingerprint = fingerprint - elif user.ssh_pub_key: - # Else, if the user has a public key already, delete it. - session.delete(user.ssh_pub_key) - - # Commit changes, if any. - session.commit() + with db.begin(): + if PK: + # Get the second token in the public key, which is the actual key. + pubkey = PK.strip().rstrip() + parts = pubkey.split(" ") + if len(parts) == 3: + # Remove the host part. + pubkey = parts[0] + " " + parts[1] + fingerprint = get_fingerprint(pubkey) + if not user.ssh_pub_key: + # No public key exists, create one. + user.ssh_pub_key = SSHPubKey(UserID=user.ID, + PubKey=pubkey, + Fingerprint=fingerprint) + elif user.ssh_pub_key.PubKey != pubkey: + # A public key already exists, update it. + user.ssh_pub_key.PubKey = pubkey + user.ssh_pub_key.Fingerprint = fingerprint + elif user.ssh_pub_key: + # Else, if the user has a public key already, delete it. + session.delete(user.ssh_pub_key) if P and not user.valid_password(P): # Remove the fields we consumed for passwords. context["P"] = context["C"] = str() # If a password was given and it doesn't match the user's, update it. - user.update_password(P) + with db.begin(): + user.update_password(P) + if user == request.user: # If the target user is the request user, login with # the updated password and update AURSID. @@ -731,21 +732,17 @@ async def terms_of_service_post(request: Request, accept_needed = sorted(unaccepted + diffs) return render_terms_of_service(request, context, accept_needed) - # For each term we found, query for the matching accepted term - # and update its Revision to the term's current Revision. - for term in diffs: - accepted_term = request.user.accepted_terms.filter( - AcceptedTerm.TermsID == term.ID).first() - accepted_term.Revision = term.Revision + with db.begin(): + # For each term we found, query for the matching accepted term + # and update its Revision to the term's current Revision. + for term in diffs: + accepted_term = request.user.accepted_terms.filter( + AcceptedTerm.TermsID == term.ID).first() + accepted_term.Revision = term.Revision - # For each term that was never accepted, accept it! - for term in unaccepted: - db.create(AcceptedTerm, User=request.user, - Term=term, Revision=term.Revision, - autocommit=False) - - if diffs or unaccepted: - # If we had any terms to update, commit the changes. - db.commit() + # For each term that was never accepted, accept it! + for term in unaccepted: + db.create(AcceptedTerm, User=request.user, + Term=term, Revision=term.Revision) return RedirectResponse("/", status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index c2375f69..c3fd3db1 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -44,8 +44,6 @@ async def language(request: Request, setting the language on any page, we want to preserve query parameters across the redirect. """ - from aurweb.db import session - if next[0] != '/': return HTMLResponse(b"Invalid 'next' parameter.", status_code=400) @@ -53,8 +51,8 @@ async def language(request: Request, # If the user is authenticated, update the user's LangPreference. if request.user.is_authenticated(): - request.user.LangPreference = set_lang - session.commit() + with db.begin(): + request.user.LangPreference = set_lang # In any case, set the response's AURLANG cookie that never expires. response = RedirectResponse(url=f"{next}{query_string}", diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 61cfec6c..a977b31a 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -214,10 +214,9 @@ async def trusted_user_proposal_post(request: Request, return Response("Invalid 'decision' value.", status_code=int(HTTPStatus.BAD_REQUEST)) - vote = db.create(TUVote, User=request.user, VoteInfo=voteinfo, - autocommit=False) - voteinfo.ActiveTUs += 1 - db.commit() + with db.begin(): + vote = db.create(TUVote, User=request.user, VoteInfo=voteinfo) + voteinfo.ActiveTUs += 1 context["error"] = "You've already voted for this proposal." return render_proposal(request, context, proposal, voteinfo, voters, vote) @@ -294,12 +293,13 @@ async def trusted_user_addvote_post(request: Request, agenda = re.sub(r'<[/]?style.*>', '', agenda) # Create a new TUVoteInfo (proposal)! - voteinfo = db.create(TUVoteInfo, - User=user, - Agenda=agenda, - Submitted=timestamp, End=timestamp + duration, - Quorum=quorum, - Submitter=request.user) + with db.begin(): + voteinfo = db.create(TUVoteInfo, + User=user, + Agenda=agenda, + Submitted=timestamp, End=timestamp + duration, + Quorum=quorum, + Submitter=request.user) # Redirect to the new proposal. return RedirectResponse(f"/tu/{voteinfo.ID}", diff --git a/test/test_account_type.py b/test/test_account_type.py index fa4bc5ad..86e68253 100644 --- a/test/test_account_type.py +++ b/test/test_account_type.py @@ -1,6 +1,6 @@ import pytest -from aurweb.db import create, delete, query +from aurweb.db import begin, create, delete, query from aurweb.models.account_type import AccountType from aurweb.models.user import User from aurweb.testing import setup_test_db @@ -14,11 +14,13 @@ def setup(): global account_type - account_type = create(AccountType, AccountType="TestUser") + with begin(): + account_type = create(AccountType, AccountType="TestUser") yield account_type - delete(AccountType, AccountType.ID == account_type.ID) + with begin(): + delete(AccountType, AccountType.ID == account_type.ID) def test_account_type(): @@ -38,12 +40,14 @@ def test_account_type(): def test_user_account_type_relationship(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + with begin(): + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) assert user.AccountType == account_type # This must be deleted here to avoid foreign key issues when # deleting the temporary AccountType in the fixture. - delete(User, User.ID == user.ID) + with begin(): + delete(User, User.ID == user.ID) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 567b3426..9120f23f 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -11,9 +11,9 @@ import pytest from fastapi.testclient import TestClient -from aurweb import captcha +from aurweb import captcha, db from aurweb.asgi import app -from aurweb.db import commit, create, query +from aurweb.db import create, query from aurweb.models.accepted_term import AcceptedTerm from aurweb.models.account_type import DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, AccountType from aurweb.models.ban import Ban @@ -57,9 +57,11 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, - RealName="Test UserZ", Passwd="testPassword", - IRCNick="testZ", AccountType=account_type) + + with db.begin(): + user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, + RealName="Test UserZ", Passwd="testPassword", + IRCNick="testZ", AccountType=account_type) yield user @@ -70,9 +72,10 @@ def setup(): @pytest.fixture def tu_user(): - user.AccountType = query(AccountType, - AccountType.ID == TRUSTED_USER_AND_DEV_ID).first() - commit() + with db.begin(): + user.AccountType = query(AccountType).filter( + AccountType.ID == TRUSTED_USER_AND_DEV_ID + ).first() yield user @@ -149,11 +152,9 @@ def test_post_passreset_user(): def test_post_passreset_resetkey(): - from aurweb.db import session - - user.session = Session(UsersID=user.ID, SessionID="blah", - LastUpdateTS=datetime.utcnow().timestamp()) - session.commit() + with db.begin(): + user.session = Session(UsersID=user.ID, SessionID="blah", + LastUpdateTS=datetime.utcnow().timestamp()) # Prepare a password reset. with client as request: @@ -357,7 +358,8 @@ def test_post_register_error_invalid_captcha(): def test_post_register_error_ip_banned(): # 'testclient' is used as request.client.host via FastAPI TestClient. - create(Ban, IPAddress="testclient", BanTS=datetime.utcnow()) + with db.begin(): + create(Ban, IPAddress="testclient", BanTS=datetime.utcnow()) with client as request: response = post_register(request) @@ -576,7 +578,8 @@ def test_post_register_error_ssh_pubkey_taken(): # Take the sha256 fingerprint of the ssh public key, create it. fp = get_fingerprint(pk) - create(SSHPubKey, UserID=user.ID, PubKey=pk, Fingerprint=fp) + with db.begin(): + create(SSHPubKey, UserID=user.ID, PubKey=pk, Fingerprint=fp) with client as request: response = post_register(request, PK=pk) @@ -660,13 +663,11 @@ def test_post_account_edit(): def test_post_account_edit_dev(): - from aurweb.db import session - # Modify our user to be a "Trusted User & Developer" name = "Trusted User & Developer" tu_or_dev = query(AccountType, AccountType.AccountType == name).first() - user.AccountType = tu_or_dev - session.commit() + with db.begin(): + user.AccountType = tu_or_dev request = Request() sid = user.login(request, "testPassword") @@ -1001,21 +1002,19 @@ def get_rows(html): def test_post_accounts(tu_user): # Set a PGPKey. - user.PGPKey = "5F18B20346188419750745D7335F2CB41F253D30" + with db.begin(): + user.PGPKey = "5F18B20346188419750745D7335F2CB41F253D30" # Create a few more users. users = [user] - for i in range(10): - _user = create(User, Username=f"test_{i}", - Email=f"test_{i}@example.org", - RealName=f"Test #{i}", - Passwd="testPassword", - IRCNick=f"test_#{i}", - autocommit=False) - users.append(_user) - - # Commit everything to the database. - commit() + with db.begin(): + for i in range(10): + _user = create(User, Username=f"test_{i}", + Email=f"test_{i}@example.org", + RealName=f"Test #{i}", + Passwd="testPassword", + IRCNick=f"test_#{i}") + users.append(_user) sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1085,11 +1084,12 @@ def test_post_accounts_account_type(tu_user): # test the `u` parameter. account_type = query(AccountType, AccountType.AccountType == "User").first() - create(User, Username="test_2", - Email="test_2@example.org", - RealName="Test User 2", - Passwd="testPassword", - AccountType=account_type) + with db.begin(): + create(User, Username="test_2", + Email="test_2@example.org", + RealName="Test User 2", + Passwd="testPassword", + AccountType=account_type) # Expect no entries; we marked our only user as a User type. with client as request: @@ -1113,9 +1113,10 @@ def test_post_accounts_account_type(tu_user): assert type.text.strip() == "User" # Set our only user to a Trusted User. - user.AccountType = query(AccountType, - AccountType.ID == TRUSTED_USER_ID).first() - commit() + with db.begin(): + user.AccountType = query(AccountType).filter( + AccountType.ID == TRUSTED_USER_ID + ).first() with client as request: response = request.post("/accounts/", cookies=cookies, @@ -1130,9 +1131,10 @@ def test_post_accounts_account_type(tu_user): assert type.text.strip() == "Trusted User" - user.AccountType = query(AccountType, - AccountType.ID == DEVELOPER_ID).first() - commit() + with db.begin(): + user.AccountType = query(AccountType).filter( + AccountType.ID == DEVELOPER_ID + ).first() with client as request: response = request.post("/accounts/", cookies=cookies, @@ -1147,10 +1149,10 @@ def test_post_accounts_account_type(tu_user): assert type.text.strip() == "Developer" - user.AccountType = query(AccountType, - AccountType.ID == TRUSTED_USER_AND_DEV_ID - ).first() - commit() + with db.begin(): + user.AccountType = query(AccountType).filter( + AccountType.ID == TRUSTED_USER_AND_DEV_ID + ).first() with client as request: response = request.post("/accounts/", cookies=cookies, @@ -1182,8 +1184,8 @@ def test_post_accounts_status(tu_user): username, type, status, realname, irc, pgp_key, edit = row assert status.text.strip() == "Active" - user.Suspended = True - commit() + with db.begin(): + user.Suspended = True with client as request: response = request.post("/accounts/", cookies=cookies, @@ -1244,12 +1246,13 @@ def test_post_accounts_sortby(tu_user): # Create a second user so we can compare sorts. account_type = query(AccountType, AccountType.ID == DEVELOPER_ID).first() - create(User, Username="test2", - Email="test2@example.org", - RealName="Test User 2", - Passwd="testPassword", - IRCNick="test2", - AccountType=account_type) + with db.begin(): + create(User, Username="test2", + Email="test2@example.org", + RealName="Test User 2", + Passwd="testPassword", + IRCNick="test2", + AccountType=account_type) sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1297,9 +1300,10 @@ def test_post_accounts_sortby(tu_user): # Test the rows are reversed when ordering by RealName. assert compare_text_values(4, first_rows, reversed(rows)) is True - user.AccountType = query(AccountType, - AccountType.ID == TRUSTED_USER_AND_DEV_ID).first() - commit() + with db.begin(): + user.AccountType = query(AccountType).filter( + AccountType.ID == TRUSTED_USER_AND_DEV_ID + ).first() # Fetch first_rows again with our new AccountType ordering. with client as request: @@ -1322,8 +1326,8 @@ def test_post_accounts_sortby(tu_user): def test_post_accounts_pgp_key(tu_user): - user.PGPKey = "5F18B20346188419750745D7335F2CB41F253D30" - commit() + with db.begin(): + user.PGPKey = "5F18B20346188419750745D7335F2CB41F253D30" sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1343,15 +1347,14 @@ def test_post_accounts_paged(tu_user): users = [user] account_type = query(AccountType, AccountType.AccountType == "User").first() - for i in range(150): - _user = create(User, Username=f"test_#{i}", - Email=f"test_#{i}@example.org", - RealName=f"Test User #{i}", - Passwd="testPassword", - AccountType=account_type, - autocommit=False) - users.append(_user) - commit() + with db.begin(): + for i in range(150): + _user = create(User, Username=f"test_#{i}", + Email=f"test_#{i}@example.org", + RealName=f"Test User #{i}", + Passwd="testPassword", + AccountType=account_type) + users.append(_user) sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1414,8 +1417,9 @@ def test_post_accounts_paged(tu_user): def test_get_terms_of_service(): - term = create(Term, Description="Test term.", - URL="http://localhost", Revision=1) + with db.begin(): + term = create(Term, Description="Test term.", + URL="http://localhost", Revision=1) with client as request: response = request.get("/tos", allow_redirects=False) @@ -1436,8 +1440,9 @@ def test_get_terms_of_service(): response = request.get("/tos", cookies=cookies, allow_redirects=False) assert response.status_code == int(HTTPStatus.OK) - accepted_term = create(AcceptedTerm, User=user, - Term=term, Revision=term.Revision) + with db.begin(): + accepted_term = create(AcceptedTerm, User=user, + Term=term, Revision=term.Revision) with client as request: response = request.get("/tos", cookies=cookies, allow_redirects=False) @@ -1445,8 +1450,8 @@ def test_get_terms_of_service(): assert response.status_code == int(HTTPStatus.SEE_OTHER) # Bump the term's revision. - term.Revision = 2 - commit() + with db.begin(): + term.Revision = 2 with client as request: response = request.get("/tos", cookies=cookies, allow_redirects=False) @@ -1454,8 +1459,8 @@ def test_get_terms_of_service(): # yet been agreed to via AcceptedTerm update. assert response.status_code == int(HTTPStatus.OK) - accepted_term.Revision = term.Revision - commit() + with db.begin(): + accepted_term.Revision = term.Revision with client as request: response = request.get("/tos", cookies=cookies, allow_redirects=False) @@ -1471,8 +1476,9 @@ def test_post_terms_of_service(): cookies = {"AURSID": sid} # Auth cookie. # Create a fresh Term. - term = create(Term, Description="Test term.", - URL="http://localhost", Revision=1) + with db.begin(): + term = create(Term, Description="Test term.", + URL="http://localhost", Revision=1) # Test that the term we just created is listed. with client as request: @@ -1497,8 +1503,8 @@ def test_post_terms_of_service(): assert accepted_term.Term == term # Update the term to revision 2. - term.Revision = 2 - commit() + with db.begin(): + term.Revision = 2 # A GET request gives us the new revision to accept. with client as request: diff --git a/test/test_api_rate_limit.py b/test/test_api_rate_limit.py index 536e3841..25cb3e0f 100644 --- a/test/test_api_rate_limit.py +++ b/test/test_api_rate_limit.py @@ -2,6 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError +from aurweb import db from aurweb.db import create from aurweb.models.api_rate_limit import ApiRateLimit from aurweb.testing import setup_test_db @@ -13,26 +14,28 @@ def setup(): def test_api_rate_key_creation(): - rate = create(ApiRateLimit, IP="127.0.0.1", Requests=10, WindowStart=1) + with db.begin(): + rate = create(ApiRateLimit, IP="127.0.0.1", Requests=10, WindowStart=1) assert rate.IP == "127.0.0.1" assert rate.Requests == 10 assert rate.WindowStart == 1 def test_api_rate_key_ip_default(): - api_rate_limit = create(ApiRateLimit, Requests=10, WindowStart=1) + with db.begin(): + api_rate_limit = create(ApiRateLimit, Requests=10, WindowStart=1) assert api_rate_limit.IP == str() def test_api_rate_key_null_requests_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(ApiRateLimit, IP="127.0.0.1", WindowStart=1) - session.rollback() + with db.begin(): + create(ApiRateLimit, IP="127.0.0.1", WindowStart=1) + db.rollback() def test_api_rate_key_null_window_start_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(ApiRateLimit, IP="127.0.0.1", Requests=1) - session.rollback() + with db.begin(): + create(ApiRateLimit, IP="127.0.0.1", Requests=1) + db.rollback() diff --git a/test/test_auth.py b/test/test_auth.py index b386bea1..caa39468 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -4,6 +4,7 @@ import pytest from sqlalchemy.exc import IntegrityError +from aurweb import db from aurweb.auth import BasicAuthBackend, account_type_required, has_credential from aurweb.db import create, query from aurweb.models.account_type import USER, USER_ID, AccountType @@ -23,9 +24,10 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.com", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + with db.begin(): + user = create(User, Username="test", Email="test@example.com", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) backend = BasicAuthBackend() request = Request() @@ -51,14 +53,13 @@ async def test_auth_backend_invalid_sid(): @pytest.mark.asyncio async def test_auth_backend_invalid_user_id(): - from aurweb.db import session - # Create a new session with a fake user id. now_ts = datetime.utcnow().timestamp() with pytest.raises(IntegrityError): - create(Session, UsersID=666, SessionID="realSession", - LastUpdateTS=now_ts + 5) - session.rollback() + with db.begin(): + create(Session, UsersID=666, SessionID="realSession", + LastUpdateTS=now_ts + 5) + db.rollback() @pytest.mark.asyncio @@ -66,8 +67,9 @@ async def test_basic_auth_backend(): # This time, everything matches up. We expect the user to # equal the real_user. now_ts = datetime.utcnow().timestamp() - create(Session, UsersID=user.ID, SessionID="realSession", - LastUpdateTS=now_ts + 5) + with db.begin(): + create(Session, UsersID=user.ID, SessionID="realSession", + LastUpdateTS=now_ts + 5) request.cookies["AURSID"] = "realSession" _, result = await backend.authenticate(request) assert result == user diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index b0dd5648..1d8f9cbe 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -9,7 +9,7 @@ from fastapi.testclient import TestClient import aurweb.config from aurweb.asgi import app -from aurweb.db import create, query +from aurweb.db import begin, create, query from aurweb.models.account_type import AccountType from aurweb.models.session import Session from aurweb.models.user import User @@ -32,9 +32,10 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + with begin(): + user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, + RealName="Test User", Passwd="testPassword", + AccountType=account_type) client = TestClient(app) diff --git a/test/test_ban.py b/test/test_ban.py index b728644b..f96e9d14 100644 --- a/test/test_ban.py +++ b/test/test_ban.py @@ -6,6 +6,7 @@ import pytest from sqlalchemy import exc as sa_exc +from aurweb import db from aurweb.db import create from aurweb.models.ban import Ban, is_banned from aurweb.testing import setup_test_db @@ -21,7 +22,8 @@ def setup(): setup_test_db("Bans") ts = datetime.utcnow() + timedelta(seconds=30) - ban = create(Ban, IPAddress="127.0.0.1", BanTS=ts) + with db.begin(): + ban = create(Ban, IPAddress="127.0.0.1", BanTS=ts) request = Request() @@ -35,17 +37,17 @@ def test_invalid_ban(): with pytest.raises(sa_exc.IntegrityError): bad_ban = Ban(BanTS=datetime.utcnow()) - session.add(bad_ban) # We're adding a ban with no primary key; this causes an # SQLAlchemy warnings when committing to the DB. # Ignore them. with warnings.catch_warnings(): warnings.simplefilter("ignore", sa_exc.SAWarning) - session.commit() + with db.begin(): + session.add(bad_ban) # Since we got a transaction failure, we need to rollback. - session.rollback() + db.rollback() def test_banned(): diff --git a/test/test_db.py b/test/test_db.py index 9ece25ea..7798d2f6 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -278,18 +278,15 @@ def test_connection_execute_paramstyle_unsupported(): def test_create_delete(): - db.create(AccountType, AccountType="test") + with db.begin(): + db.create(AccountType, AccountType="test") + record = db.query(AccountType, AccountType.AccountType == "test").first() assert record is not None - db.delete(AccountType, AccountType.AccountType == "test") - record = db.query(AccountType, AccountType.AccountType == "test").first() - assert record is None - # Create and delete a record with autocommit=False. - db.create(AccountType, AccountType="test", autocommit=False) - db.commit() - db.delete(AccountType, AccountType.AccountType == "test", autocommit=False) - db.commit() + with db.begin(): + db.delete(AccountType, AccountType.AccountType == "test") + record = db.query(AccountType, AccountType.AccountType == "test").first() assert record is None @@ -297,8 +294,8 @@ def test_create_delete(): def test_add_commit(): # Use db.add and db.commit to add a temporary record. account_type = AccountType(AccountType="test") - db.add(account_type) - db.commit() + with db.begin(): + db.add(account_type) # Assert it got created in the DB. assert bool(account_type.ID) @@ -308,7 +305,8 @@ def test_add_commit(): assert record == account_type # Remove the record. - db.delete(AccountType, AccountType.ID == account_type.ID) + with db.begin(): + db.delete(AccountType, AccountType.ID == account_type.ID) def test_connection_executor_mysql_paramstyle(): diff --git a/test/test_dependency_type.py b/test/test_dependency_type.py index 6c37cc58..4d555123 100644 --- a/test/test_dependency_type.py +++ b/test/test_dependency_type.py @@ -1,6 +1,6 @@ import pytest -from aurweb.db import create, delete, query +from aurweb.db import begin, create, delete, query from aurweb.models.dependency_type import DependencyType from aurweb.testing import setup_test_db @@ -19,13 +19,17 @@ def test_dependency_types(): def test_dependency_type_creation(): - dependency_type = create(DependencyType, Name="Test Type") + with begin(): + dependency_type = create(DependencyType, Name="Test Type") assert bool(dependency_type.ID) assert dependency_type.Name == "Test Type" - delete(DependencyType, DependencyType.ID == dependency_type.ID) + with begin(): + delete(DependencyType, DependencyType.ID == dependency_type.ID) def test_dependency_type_null_name_uses_default(): - dependency_type = create(DependencyType) + with begin(): + dependency_type = create(DependencyType) assert dependency_type.Name == str() - delete(DependencyType, DependencyType.ID == dependency_type.ID) + with begin(): + delete(DependencyType, DependencyType.ID == dependency_type.ID) diff --git a/test/test_group.py b/test/test_group.py index da017a96..cea69b68 100644 --- a/test/test_group.py +++ b/test/test_group.py @@ -2,7 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create +from aurweb import db from aurweb.models.group import Group from aurweb.testing import setup_test_db @@ -13,13 +13,14 @@ def setup(): def test_group_creation(): - group = create(Group, Name="Test Group") + with db.begin(): + group = db.create(Group, Name="Test Group") assert bool(group.ID) assert group.Name == "Test Group" def test_group_null_name_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(Group) - session.rollback() + with db.begin(): + db.create(Group) + db.rollback() diff --git a/test/test_homepage.py b/test/test_homepage.py index 2cd6682f..fef3532d 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -38,8 +38,10 @@ def setup(): @pytest.fixture def user(): - yield db.create(User, Username="test", Email="test@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + Passwd="testPassword", AccountTypeID=USER_ID) + yield user @pytest.fixture @@ -68,17 +70,14 @@ def packages(user): # For i..num_packages, create a package named pkg_{i}. pkgs = [] now = int(datetime.utcnow().timestamp()) - for i in range(num_packages): - pkgbase = db.create(PackageBase, Name=f"pkg_{i}", - Maintainer=user, Packager=user, - autocommit=False, SubmittedTS=now, - ModifiedTS=now) - pkg = db.create(Package, PackageBase=pkgbase, - Name=pkgbase.Name, autocommit=False) - pkgs.append(pkg) - now += 1 - - db.commit() + with db.begin(): + for i in range(num_packages): + pkgbase = db.create(PackageBase, Name=f"pkg_{i}", + Maintainer=user, Packager=user, + SubmittedTS=now, ModifiedTS=now) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + pkgs.append(pkg) + now += 1 yield pkgs @@ -159,10 +158,11 @@ def test_homepage_updates(redis, packages): def test_homepage_dashboard(redis, packages, user): # Create Comaintainer records for all of the packages. - for pkg in packages: - db.create(PackageComaintainer, PackageBase=pkg.PackageBase, - User=user, Priority=1, autocommit=False) - db.commit() + with db.begin(): + for pkg in packages: + db.create(PackageComaintainer, + PackageBase=pkg.PackageBase, + User=user, Priority=1) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -193,11 +193,12 @@ def test_homepage_dashboard_requests(redis, packages, user): pkg = packages[0] reqtype = db.query(RequestType, RequestType.ID == DELETION_ID).first() - pkgreq = db.create(PackageRequest, PackageBase=pkg.PackageBase, - PackageBaseName=pkg.PackageBase.Name, - User=user, Comments=str(), - ClosureComment=str(), RequestTS=now, - RequestType=reqtype) + with db.begin(): + pkgreq = db.create(PackageRequest, PackageBase=pkg.PackageBase, + PackageBaseName=pkg.PackageBase.Name, + User=user, Comments=str(), + ClosureComment=str(), RequestTS=now, + RequestType=reqtype) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -213,8 +214,8 @@ def test_homepage_dashboard_requests(redis, packages, user): def test_homepage_dashboard_flagged_packages(redis, packages, user): # Set the first Package flagged by setting its OutOfDateTS column. pkg = packages[0] - pkg.PackageBase.OutOfDateTS = int(datetime.utcnow().timestamp()) - db.commit() + with db.begin(): + pkg.PackageBase.OutOfDateTS = int(datetime.utcnow().timestamp()) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: diff --git a/test/test_license.py b/test/test_license.py index feb7a396..2c52f058 100644 --- a/test/test_license.py +++ b/test/test_license.py @@ -2,7 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create +from aurweb import db from aurweb.models.license import License from aurweb.testing import setup_test_db @@ -13,13 +13,14 @@ def setup(): def test_license_creation(): - license = create(License, Name="Test License") + with db.begin(): + license = db.create(License, Name="Test License") assert bool(license.ID) assert license.Name == "Test License" def test_license_null_name_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(License) - session.rollback() + with db.begin(): + db.create(License) + db.rollback() diff --git a/test/test_official_provider.py b/test/test_official_provider.py index a1d3d54a..0aa4f1d1 100644 --- a/test/test_official_provider.py +++ b/test/test_official_provider.py @@ -2,7 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create +from aurweb import db from aurweb.models.official_provider import OfficialProvider from aurweb.testing import setup_test_db @@ -13,10 +13,11 @@ def setup(): def test_official_provider_creation(): - oprovider = create(OfficialProvider, - Name="some-name", - Repo="some-repo", - Provides="some-provides") + with db.begin(): + oprovider = db.create(OfficialProvider, + Name="some-name", + Repo="some-repo", + Provides="some-provides") assert bool(oprovider.ID) assert oprovider.Name == "some-name" assert oprovider.Repo == "some-repo" @@ -25,16 +26,18 @@ def test_official_provider_creation(): def test_official_provider_cs(): """ Test case sensitivity of the database table. """ - oprovider = create(OfficialProvider, - Name="some-name", - Repo="some-repo", - Provides="some-provides") + with db.begin(): + oprovider = db.create(OfficialProvider, + Name="some-name", + Repo="some-repo", + Provides="some-provides") assert bool(oprovider.ID) - oprovider_cs = create(OfficialProvider, - Name="SOME-NAME", - Repo="SOME-REPO", - Provides="SOME-PROVIDES") + with db.begin(): + oprovider_cs = db.create(OfficialProvider, + Name="SOME-NAME", + Repo="SOME-REPO", + Provides="SOME-PROVIDES") assert bool(oprovider_cs.ID) assert oprovider.ID != oprovider_cs.ID @@ -49,27 +52,27 @@ def test_official_provider_cs(): def test_official_provider_null_name_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(OfficialProvider, - Repo="some-repo", - Provides="some-provides") - session.rollback() + with db.begin(): + db.create(OfficialProvider, + Repo="some-repo", + Provides="some-provides") + db.rollback() def test_official_provider_null_repo_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(OfficialProvider, - Name="some-name", - Provides="some-provides") - session.rollback() + with db.begin(): + db.create(OfficialProvider, + Name="some-name", + Provides="some-provides") + db.rollback() def test_official_provider_null_provides_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(OfficialProvider, - Name="some-name", - Repo="some-repo") - session.rollback() + with db.begin(): + db.create(OfficialProvider, + Name="some-name", + Repo="some-repo") + db.rollback() diff --git a/test/test_package.py b/test/test_package.py index 1e940164..112ca9b4 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -3,7 +3,7 @@ import pytest from sqlalchemy import and_ from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query +from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -19,25 +19,25 @@ def setup(): setup_test_db("Packages", "PackageBases", "Users") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + account_type = db.query(AccountType, + AccountType.AccountType == "User").first() - pkgbase = create(PackageBase, - Name="beautiful-package", - Maintainer=user) - package = create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + + pkgbase = db.create(PackageBase, + Name="beautiful-package", + Maintainer=user) + package = db.create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") def test_package(): - from aurweb.db import session - assert pkgbase == package.PackageBase assert package.Name == "beautiful-package" assert package.Description == "Test description." @@ -45,33 +45,31 @@ def test_package(): assert package.URL == "https://test.package" # Update package Version. - package.Version = "1.2.3" - session.commit() + with db.begin(): + package.Version = "1.2.3" # Make sure it got updated in the database. - record = query(Package, - and_(Package.ID == package.ID, - Package.Version == "1.2.3")).first() + record = db.query(Package, + and_(Package.ID == package.ID, + Package.Version == "1.2.3")).first() assert record is not None def test_package_null_pkgbase_raises_exception(): - from aurweb.db import session - with pytest.raises(IntegrityError): - create(Package, - Name="some-package", - Description="Some description.", - URL="https://some.package") - session.rollback() + with db.begin(): + db.create(Package, + Name="some-package", + Description="Some description.", + URL="https://some.package") + db.rollback() def test_package_null_name_raises_exception(): - from aurweb.db import session - with pytest.raises(IntegrityError): - create(Package, - PackageBase=pkgbase, - Description="Some description.", - URL="https://some.package") - session.rollback() + with db.begin(): + db.create(Package, + PackageBase=pkgbase, + Description="Some description.", + URL="https://some.package") + db.rollback() diff --git a/test/test_package_base.py b/test/test_package_base.py index 0c0d0526..2bc6278f 100644 --- a/test/test_package_base.py +++ b/test/test_package_base.py @@ -4,7 +4,7 @@ from sqlalchemy.exc import IntegrityError import aurweb.config -from aurweb.db import create, query +from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.package_base import PackageBase from aurweb.models.user import User @@ -19,17 +19,19 @@ def setup(): setup_test_db("Users", "PackageBases") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + account_type = db.query(AccountType, + AccountType.AccountType == "User").first() + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) def test_package_base(): - pkgbase = create(PackageBase, - Name="beautiful-package", - Maintainer=user) + with db.begin(): + pkgbase = db.create(PackageBase, + Name="beautiful-package", + Maintainer=user) assert pkgbase in user.maintained_bases assert not pkgbase.OutOfDateTS @@ -38,7 +40,8 @@ def test_package_base(): # Set Popularity to a string, then get it by attribute to # exercise the string -> float conversion path. - pkgbase.Popularity = "0.0" + with db.begin(): + pkgbase.Popularity = "0.0" assert pkgbase.Popularity == 0.0 @@ -47,27 +50,28 @@ def test_package_base_ci(): if aurweb.config.get("database", "backend") == "sqlite": return None # SQLite doesn't seem handle this. - from aurweb.db import session - - pkgbase = create(PackageBase, - Name="beautiful-package", - Maintainer=user) + with db.begin(): + pkgbase = db.create(PackageBase, + Name="beautiful-package", + Maintainer=user) assert bool(pkgbase.ID) with pytest.raises(IntegrityError): - create(PackageBase, - Name="Beautiful-Package", - Maintainer=user) - session.rollback() + with db.begin(): + db.create(PackageBase, + Name="Beautiful-Package", + Maintainer=user) + db.rollback() def test_package_base_relationships(): - pkgbase = create(PackageBase, - Name="beautiful-package", - Flagger=user, - Maintainer=user, - Submitter=user, - Packager=user) + with db.begin(): + pkgbase = db.create(PackageBase, + Name="beautiful-package", + Flagger=user, + Maintainer=user, + Submitter=user, + Packager=user) assert pkgbase in user.flagged_bases assert pkgbase in user.maintained_bases assert pkgbase in user.submitted_bases @@ -75,8 +79,7 @@ def test_package_base_relationships(): def test_package_base_null_name_raises_exception(): - from aurweb.db import session - with pytest.raises(IntegrityError): - create(PackageBase) - session.rollback() + with db.begin(): + db.create(PackageBase) + db.rollback() diff --git a/test/test_package_blacklist.py b/test/test_package_blacklist.py index 3c64cc21..93f15de7 100644 --- a/test/test_package_blacklist.py +++ b/test/test_package_blacklist.py @@ -2,7 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, rollback +from aurweb import db from aurweb.models.package_base import PackageBase from aurweb.models.package_blacklist import PackageBlacklist from aurweb.models.user import User @@ -17,18 +17,20 @@ def setup(): setup_test_db("PackageBlacklist", "PackageBases", "Users") - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) def test_package_blacklist_creation(): - package_blacklist = create(PackageBlacklist, Name="evil-package") + with db.begin(): + package_blacklist = db.create(PackageBlacklist, Name="evil-package") assert bool(package_blacklist.ID) assert package_blacklist.Name == "evil-package" def test_package_blacklist_null_name_raises_exception(): with pytest.raises(IntegrityError): - create(PackageBlacklist) - rollback() + with db.begin(): + db.create(PackageBlacklist) + db.rollback() diff --git a/test/test_package_comment.py b/test/test_package_comment.py index ca77b511..60f0333d 100644 --- a/test/test_package_comment.py +++ b/test/test_package_comment.py @@ -2,7 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query, rollback +from aurweb.db import begin, create, query, rollback from aurweb.models.account_type import AccountType from aurweb.models.package_base import PackageBase from aurweb.models.package_comment import PackageComment @@ -20,45 +20,52 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + with begin(): + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) def test_package_comment_creation(): - package_comment = create(PackageComment, - PackageBase=pkgbase, - User=user, - Comments="Test comment.", - RenderedComment="Test rendered comment.") + with begin(): + package_comment = create(PackageComment, + PackageBase=pkgbase, + User=user, + Comments="Test comment.", + RenderedComment="Test rendered comment.") assert bool(package_comment.ID) def test_package_comment_null_package_base_raises_exception(): with pytest.raises(IntegrityError): - create(PackageComment, User=user, Comments="Test comment.", - RenderedComment="Test rendered comment.") + with begin(): + create(PackageComment, User=user, Comments="Test comment.", + RenderedComment="Test rendered comment.") rollback() def test_package_comment_null_user_raises_exception(): with pytest.raises(IntegrityError): - create(PackageComment, PackageBase=pkgbase, Comments="Test comment.", - RenderedComment="Test rendered comment.") + with begin(): + create(PackageComment, PackageBase=pkgbase, + Comments="Test comment.", + RenderedComment="Test rendered comment.") rollback() def test_package_comment_null_comments_raises_exception(): with pytest.raises(IntegrityError): - create(PackageComment, PackageBase=pkgbase, User=user, - RenderedComment="Test rendered comment.") + with begin(): + create(PackageComment, PackageBase=pkgbase, User=user, + RenderedComment="Test rendered comment.") rollback() def test_package_comment_null_renderedcomment_defaults(): - record = create(PackageComment, - PackageBase=pkgbase, - User=user, - Comments="Test comment.") + with begin(): + record = create(PackageComment, + PackageBase=pkgbase, + User=user, + Comments="Test comment.") assert record.RenderedComment == str() diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py index e28f1781..2ddef68e 100644 --- a/test/test_package_dependency.py +++ b/test/test_package_dependency.py @@ -2,7 +2,8 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import commit, create, query +from aurweb import db +from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.dependency_type import DependencyType from aurweb.models.package import Package @@ -22,25 +23,28 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, - Name="test-package", - Maintainer=user) - package = create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + with db.begin(): + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + pkgbase = create(PackageBase, + Name="test-package", + Maintainer=user) + package = create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") def test_package_dependencies(): depends = query(DependencyType, DependencyType.Name == "depends").first() - pkgdep = create(PackageDependency, Package=package, - DependencyType=depends, - DepName="test-dep") + + with db.begin(): + pkgdep = create(PackageDependency, Package=package, + DependencyType=depends, + DepName="test-dep") assert pkgdep.DepName == "test-dep" assert pkgdep.Package == package assert pkgdep.DependencyType == depends @@ -49,8 +53,8 @@ def test_package_dependencies(): makedepends = query(DependencyType, DependencyType.Name == "makedepends").first() - pkgdep.DependencyType = makedepends - commit() + with db.begin(): + pkgdep.DependencyType = makedepends assert pkgdep.DepName == "test-dep" assert pkgdep.Package == package assert pkgdep.DependencyType == makedepends @@ -59,8 +63,8 @@ def test_package_dependencies(): checkdepends = query(DependencyType, DependencyType.Name == "checkdepends").first() - pkgdep.DependencyType = checkdepends - commit() + with db.begin(): + pkgdep.DependencyType = checkdepends assert pkgdep.DepName == "test-dep" assert pkgdep.Package == package assert pkgdep.DependencyType == checkdepends @@ -69,8 +73,8 @@ def test_package_dependencies(): optdepends = query(DependencyType, DependencyType.Name == "optdepends").first() - pkgdep.DependencyType = optdepends - commit() + with db.begin(): + pkgdep.DependencyType = optdepends assert pkgdep.DepName == "test-dep" assert pkgdep.Package == package assert pkgdep.DependencyType == optdepends @@ -79,39 +83,37 @@ def test_package_dependencies(): assert not pkgdep.is_package() - base = create(PackageBase, Name=pkgdep.DepName, Maintainer=user) - create(Package, PackageBase=base, Name=pkgdep.DepName) + with db.begin(): + base = create(PackageBase, Name=pkgdep.DepName, Maintainer=user) + create(Package, PackageBase=base, Name=pkgdep.DepName) assert pkgdep.is_package() def test_package_dependencies_null_package_raises_exception(): - from aurweb.db import session - depends = query(DependencyType, DependencyType.Name == "depends").first() with pytest.raises(IntegrityError): - create(PackageDependency, - DependencyType=depends, - DepName="test-dep") - session.rollback() + with db.begin(): + create(PackageDependency, + DependencyType=depends, + DepName="test-dep") + db.rollback() def test_package_dependencies_null_dependency_type_raises_exception(): - from aurweb.db import session - with pytest.raises(IntegrityError): - create(PackageDependency, - Package=package, - DepName="test-dep") - session.rollback() + with db.begin(): + create(PackageDependency, + Package=package, + DepName="test-dep") + db.rollback() def test_package_dependencies_null_depname_raises_exception(): - from aurweb.db import session - depends = query(DependencyType, DependencyType.Name == "depends").first() with pytest.raises(IntegrityError): - create(PackageDependency, - Package=package, - DependencyType=depends) - session.rollback() + with db.begin(): + create(PackageDependency, + Package=package, + DependencyType=depends) + db.rollback() diff --git a/test/test_package_relation.py b/test/test_package_relation.py index 766d0017..edb67078 100644 --- a/test/test_package_relation.py +++ b/test/test_package_relation.py @@ -2,7 +2,8 @@ import pytest from sqlalchemy.exc import IntegrityError, OperationalError -from aurweb.db import commit, create, query +from aurweb import db +from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -22,25 +23,28 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, - Name="test-package", - Maintainer=user) - package = create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + with db.begin(): + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + pkgbase = create(PackageBase, + Name="test-package", + Maintainer=user) + package = create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") def test_package_relation(): conflicts = query(RelationType, RelationType.Name == "conflicts").first() - pkgrel = create(PackageRelation, Package=package, - RelationType=conflicts, - RelName="test-relation") + + with db.begin(): + pkgrel = create(PackageRelation, Package=package, + RelationType=conflicts, + RelName="test-relation") assert pkgrel.RelName == "test-relation" assert pkgrel.Package == package assert pkgrel.RelationType == conflicts @@ -48,8 +52,8 @@ def test_package_relation(): assert pkgrel in package.package_relations provides = query(RelationType, RelationType.Name == "provides").first() - pkgrel.RelationType = provides - commit() + with db.begin(): + pkgrel.RelationType = provides assert pkgrel.RelName == "test-relation" assert pkgrel.Package == package assert pkgrel.RelationType == provides @@ -57,8 +61,8 @@ def test_package_relation(): assert pkgrel in package.package_relations replaces = query(RelationType, RelationType.Name == "replaces").first() - pkgrel.RelationType = replaces - commit() + with db.begin(): + pkgrel.RelationType = replaces assert pkgrel.RelName == "test-relation" assert pkgrel.Package == package assert pkgrel.RelationType == replaces @@ -67,36 +71,33 @@ def test_package_relation(): def test_package_relation_null_package_raises_exception(): - from aurweb.db import session - conflicts = query(RelationType, RelationType.Name == "conflicts").first() assert conflicts is not None with pytest.raises(IntegrityError): - create(PackageRelation, - RelationType=conflicts, - RelName="test-relation") - session.rollback() + with db.begin(): + create(PackageRelation, + RelationType=conflicts, + RelName="test-relation") + db.rollback() def test_package_relation_null_relation_type_raises_exception(): - from aurweb.db import session - with pytest.raises(IntegrityError): - create(PackageRelation, - Package=package, - RelName="test-relation") - session.rollback() + with db.begin(): + create(PackageRelation, + Package=package, + RelName="test-relation") + db.rollback() def test_package_relation_null_relname_raises_exception(): - from aurweb.db import session - depends = query(RelationType, RelationType.Name == "conflicts").first() assert depends is not None with pytest.raises((OperationalError, IntegrityError)): - create(PackageRelation, - Package=package, - RelationType=depends) - session.rollback() + with db.begin(): + create(PackageRelation, + Package=package, + RelationType=depends) + db.rollback() diff --git a/test/test_package_request.py b/test/test_package_request.py index c28af6bd..1589ffc2 100644 --- a/test/test_package_request.py +++ b/test/test_package_request.py @@ -4,7 +4,8 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import commit, create, query, rollback +from aurweb import db +from aurweb.db import create, query, rollback from aurweb.models.package_base import PackageBase from aurweb.models.package_request import (ACCEPTED, ACCEPTED_ID, CLOSED, CLOSED_ID, PENDING, PENDING_ID, REJECTED, REJECTED_ID, PackageRequest) @@ -21,19 +22,21 @@ def setup(): setup_test_db("PackageRequests", "PackageBases", "Users") - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + with db.begin(): + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = create(PackageBase, Name="test-package", Maintainer=user) def test_package_request_creation(): request_type = query(RequestType, RequestType.Name == "merge").first() assert request_type.Name == "merge" - package_request = create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + with db.begin(): + package_request = create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) assert bool(package_request.ID) assert package_request.RequestType == request_type @@ -54,11 +57,12 @@ def test_package_request_closed(): assert request_type.Name == "merge" ts = int(datetime.utcnow().timestamp()) - package_request = create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Closer=user, ClosedTS=ts, - Comments=str(), ClosureComment=str()) + with db.begin(): + package_request = create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Closer=user, ClosedTS=ts, + Comments=str(), ClosureComment=str()) assert package_request.Closer == user assert package_request.ClosedTS == ts @@ -69,54 +73,60 @@ def test_package_request_closed(): def test_package_request_null_request_type_raises_exception(): with pytest.raises(IntegrityError): - create(PackageRequest, User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + with db.begin(): + create(PackageRequest, User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) rollback() def test_package_request_null_user_raises_exception(): request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - create(PackageRequest, RequestType=request_type, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + with db.begin(): + create(PackageRequest, RequestType=request_type, + PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) rollback() def test_package_request_null_package_base_raises_exception(): request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - create(PackageRequest, RequestType=request_type, - User=user, PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + with db.begin(): + create(PackageRequest, RequestType=request_type, + User=user, PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) rollback() def test_package_request_null_package_base_name_raises_exception(): request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - Comments=str(), ClosureComment=str()) + with db.begin(): + create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + Comments=str(), ClosureComment=str()) rollback() def test_package_request_null_comments_raises_exception(): request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - ClosureComment=str()) + with db.begin(): + create(PackageRequest, RequestType=request_type, User=user, + PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + ClosureComment=str()) rollback() def test_package_request_null_closure_comment_raises_exception(): request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - Comments=str()) + with db.begin(): + create(PackageRequest, RequestType=request_type, User=user, + PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + Comments=str()) rollback() @@ -124,26 +134,27 @@ def test_package_request_status_display(): """ Test status_display() based on the Status column value. """ request_type = query(RequestType, RequestType.Name == "merge").first() - pkgreq = create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str(), - Status=PENDING_ID) + with db.begin(): + pkgreq = create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str(), + Status=PENDING_ID) assert pkgreq.status_display() == PENDING - pkgreq.Status = CLOSED_ID - commit() + with db.begin(): + pkgreq.Status = CLOSED_ID assert pkgreq.status_display() == CLOSED - pkgreq.Status = ACCEPTED_ID - commit() + with db.begin(): + pkgreq.Status = ACCEPTED_ID assert pkgreq.status_display() == ACCEPTED - pkgreq.Status = REJECTED_ID - commit() + with db.begin(): + pkgreq.Status = REJECTED_ID assert pkgreq.status_display() == REJECTED - pkgreq.Status = 124 - commit() + with db.begin(): + pkgreq.Status = 124 with pytest.raises(KeyError): pkgreq.status_display() diff --git a/test/test_package_source.py b/test/test_package_source.py index 7453f756..d1adcf9c 100644 --- a/test/test_package_source.py +++ b/test/test_package_source.py @@ -2,7 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query, rollback +from aurweb.db import begin, create, query, rollback from aurweb.models.account_type import AccountType from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -21,17 +21,19 @@ def setup(): account_type = query(AccountType, AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, - Name="test-package", - Maintainer=user) - package = create(Package, PackageBase=pkgbase, Name="test-package") + with begin(): + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) + pkgbase = create(PackageBase, + Name="test-package", + Maintainer=user) + package = create(Package, PackageBase=pkgbase, Name="test-package") def test_package_source(): - pkgsource = create(PackageSource, Package=package) + with begin(): + pkgsource = create(PackageSource, Package=package) assert pkgsource.Package == package # By default, PackageSources.Source assigns the string '/dev/null'. assert pkgsource.Source == "/dev/null" @@ -40,5 +42,6 @@ def test_package_source(): def test_package_source_null_package_raises_exception(): with pytest.raises(IntegrityError): - create(PackageSource) + with begin(): + create(PackageSource) rollback() diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index ad07ec17..8a468c15 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -28,31 +28,25 @@ def package_endpoint(package: Package) -> str: return f"/packages/{package.Name}" -def create_package(pkgname: str, maintainer: User, - autocommit: bool = True) -> Package: +def create_package(pkgname: str, maintainer: User) -> Package: pkgbase = db.create(PackageBase, Name=pkgname, - Maintainer=maintainer, - autocommit=False) - return db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase, - autocommit=autocommit) + Maintainer=maintainer) + return db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) def create_package_dep(package: Package, depname: str, - dep_type_name: str = "depends", - autocommit: bool = True) -> PackageDependency: + dep_type_name: str = "depends") -> PackageDependency: dep_type = db.query(DependencyType, DependencyType.Name == dep_type_name).first() return db.create(PackageDependency, DependencyType=dep_type, Package=package, - DepName=depname, - autocommit=autocommit) + DepName=depname) def create_package_rel(package: Package, - relname: str, - autocommit: bool = True) -> PackageRelation: + relname: str) -> PackageRelation: rel_type = db.query(RelationType, RelationType.ID == PROVIDES_ID).first() return db.create(PackageRelation, @@ -84,31 +78,37 @@ def client() -> TestClient: def user() -> User: """ Yield a user. """ account_type = db.query(AccountType, AccountType.ID == USER_ID).first() - yield db.create(User, Username="test", - Email="test@example.org", - Passwd="testPassword", - AccountType=account_type) + with db.begin(): + user = db.create(User, Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountType=account_type) + yield user @pytest.fixture def maintainer() -> User: """ Yield a specific User used to maintain packages. """ account_type = db.query(AccountType, AccountType.ID == USER_ID).first() - yield db.create(User, Username="test_maintainer", - Email="test_maintainer@example.org", - Passwd="testPassword", - AccountType=account_type) + with db.begin(): + maintainer = db.create(User, Username="test_maintainer", + Email="test_maintainer@example.org", + Passwd="testPassword", + AccountType=account_type) + yield maintainer @pytest.fixture def package(maintainer: User) -> Package: """ Yield a Package created by user. """ - pkgbase = db.create(PackageBase, - Name="test-package", - Maintainer=maintainer) - yield db.create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name) + with db.begin(): + pkgbase = db.create(PackageBase, + Name="test-package", + Maintainer=maintainer) + package = db.create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name) + yield package def test_package_not_found(client: TestClient): @@ -121,10 +121,11 @@ def test_package_official_not_found(client: TestClient, package: Package): """ When a Package has a matching OfficialProvider record, it is not hosted on AUR, but in the official repositories. Getting a package with this kind of record should return a status code 404. """ - db.create(OfficialProvider, - Name=package.Name, - Repo="core", - Provides=package.Name) + with db.begin(): + db.create(OfficialProvider, + Name=package.Name, + Repo="core", + Provides=package.Name) with client as request: resp = request.get(package_endpoint(package)) @@ -157,8 +158,9 @@ def test_package(client: TestClient, package: Package): def test_package_comments(client: TestClient, user: User, package: Package): now = (datetime.utcnow().timestamp()) - comment = db.create(PackageComment, PackageBase=package.PackageBase, - User=user, Comments="Test comment", CommentTS=now) + with db.begin(): + comment = db.create(PackageComment, PackageBase=package.PackageBase, + User=user, Comments="Test comment", CommentTS=now) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -178,11 +180,12 @@ def test_package_comments(client: TestClient, user: User, package: Package): def test_package_requests_display(client: TestClient, user: User, package: Package): type_ = db.query(RequestType, RequestType.ID == DELETION_ID).first() - db.create(PackageRequest, PackageBase=package.PackageBase, - PackageBaseName=package.PackageBase.Name, - User=user, RequestType=type_, - Comments="Test comment.", - ClosureComment=str()) + with db.begin(): + db.create(PackageRequest, PackageBase=package.PackageBase, + PackageBaseName=package.PackageBase.Name, + User=user, RequestType=type_, + Comments="Test comment.", + ClosureComment=str()) # Test that a single request displays "1 pending request". with client as request: @@ -195,11 +198,12 @@ def test_package_requests_display(client: TestClient, user: User, assert target.text.strip() == "1 pending request" type_ = db.query(RequestType, RequestType.ID == DELETION_ID).first() - db.create(PackageRequest, PackageBase=package.PackageBase, - PackageBaseName=package.PackageBase.Name, - User=user, RequestType=type_, - Comments="Test comment2.", - ClosureComment=str()) + with db.begin(): + db.create(PackageRequest, PackageBase=package.PackageBase, + PackageBaseName=package.PackageBase.Name, + User=user, RequestType=type_, + Comments="Test comment2.", + ClosureComment=str()) # Test that a two requests display "2 pending requests". with client as request: @@ -271,50 +275,43 @@ def test_package_authenticated_maintainer(client: TestClient, def test_package_dependencies(client: TestClient, maintainer: User, package: Package): # Create a normal dependency of type depends. - dep_pkg = create_package("test-dep-1", maintainer, autocommit=False) - dep = create_package_dep(package, dep_pkg.Name, autocommit=False) - dep.DepArch = "x86_64" + with db.begin(): + dep_pkg = create_package("test-dep-1", maintainer) + dep = create_package_dep(package, dep_pkg.Name) + dep.DepArch = "x86_64" - # Also, create a makedepends. - make_dep_pkg = create_package("test-dep-2", maintainer, autocommit=False) - make_dep = create_package_dep(package, make_dep_pkg.Name, - dep_type_name="makedepends", - autocommit=False) + # Also, create a makedepends. + make_dep_pkg = create_package("test-dep-2", maintainer) + make_dep = create_package_dep(package, make_dep_pkg.Name, + dep_type_name="makedepends") - # And... a checkdepends! - check_dep_pkg = create_package("test-dep-3", maintainer, autocommit=False) - check_dep = create_package_dep(package, check_dep_pkg.Name, - dep_type_name="checkdepends", - autocommit=False) + # And... a checkdepends! + check_dep_pkg = create_package("test-dep-3", maintainer) + check_dep = create_package_dep(package, check_dep_pkg.Name, + dep_type_name="checkdepends") - # Geez. Just stop. This is optdepends. - opt_dep_pkg = create_package("test-dep-4", maintainer, autocommit=False) - opt_dep = create_package_dep(package, opt_dep_pkg.Name, - dep_type_name="optdepends", - autocommit=False) + # Geez. Just stop. This is optdepends. + opt_dep_pkg = create_package("test-dep-4", maintainer) + opt_dep = create_package_dep(package, opt_dep_pkg.Name, + dep_type_name="optdepends") - # Heh. Another optdepends to test one with a description. - opt_desc_dep_pkg = create_package("test-dep-5", maintainer, - autocommit=False) - opt_desc_dep = create_package_dep(package, opt_desc_dep_pkg.Name, - dep_type_name="optdepends", - autocommit=False) - opt_desc_dep.DepDesc = "Test description." + # Heh. Another optdepends to test one with a description. + opt_desc_dep_pkg = create_package("test-dep-5", maintainer) + opt_desc_dep = create_package_dep(package, opt_desc_dep_pkg.Name, + dep_type_name="optdepends") + opt_desc_dep.DepDesc = "Test description." - broken_dep = create_package_dep(package, "test-dep-6", - dep_type_name="depends", - autocommit=False) + broken_dep = create_package_dep(package, "test-dep-6", + dep_type_name="depends") - # Create an official provider record. - db.create(OfficialProvider, Name="test-dep-99", - Repo="core", Provides="test-dep-99", - autocommit=False) - official_dep = create_package_dep(package, "test-dep-99", - autocommit=False) + # Create an official provider record. + db.create(OfficialProvider, Name="test-dep-99", + Repo="core", Provides="test-dep-99") + official_dep = create_package_dep(package, "test-dep-99") - # Also, create a provider who provides our test-dep-99. - provider = create_package("test-provider", maintainer, autocommit=False) - create_package_rel(provider, dep.DepName) + # Also, create a provider who provides our test-dep-99. + provider = create_package("test-provider", maintainer) + create_package_rel(provider, dep.DepName) with client as request: resp = request.get(package_endpoint(package)) @@ -358,8 +355,9 @@ def test_pkgbase_redirect(client: TestClient, package: Package): def test_pkgbase(client: TestClient, package: Package): - second = db.create(Package, Name="second-pkg", - PackageBase=package.PackageBase) + with db.begin(): + second = db.create(Package, Name="second-pkg", + PackageBase=package.PackageBase) expected = [package.Name, second.Name] with client as request: diff --git a/test/test_packages_util.py b/test/test_packages_util.py index bc6a941c..754e3b8d 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -26,17 +26,21 @@ def setup(): @pytest.fixture def maintainer() -> User: account_type = db.query(AccountType, AccountType.ID == USER_ID).first() - yield db.create(User, Username="test_maintainer", - Email="test_maintainer@examepl.org", - Passwd="testPassword", - AccountType=account_type) + with db.begin(): + maintainer = db.create(User, Username="test_maintainer", + Email="test_maintainer@examepl.org", + Passwd="testPassword", + AccountType=account_type) + yield maintainer @pytest.fixture def package(maintainer: User) -> Package: - pkgbase = db.create(PackageBase, Name="test-pkg", - Packager=maintainer, Maintainer=maintainer) - yield db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) + with db.begin(): + pkgbase = db.create(PackageBase, Name="test-pkg", + Packager=maintainer, Maintainer=maintainer) + package = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) + yield package @pytest.fixture @@ -45,10 +49,11 @@ def client() -> TestClient: def test_package_link(client: TestClient, maintainer: User, package: Package): - db.create(OfficialProvider, - Name=package.Name, - Repo="core", - Provides=package.Name) + with db.begin(): + db.create(OfficialProvider, + Name=package.Name, + Repo="core", + Provides=package.Name) expected = f"{OFFICIAL_BASE}/packages/?q={package.Name}" assert util.package_link(package) == expected diff --git a/test/test_relation_type.py b/test/test_relation_type.py index bf23505c..fbc22c71 100644 --- a/test/test_relation_type.py +++ b/test/test_relation_type.py @@ -1,6 +1,6 @@ import pytest -from aurweb.db import create, delete, query +from aurweb import db from aurweb.models.relation_type import RelationType from aurweb.testing import setup_test_db @@ -11,22 +11,25 @@ def setup(): def test_relation_type_creation(): - relation_type = create(RelationType, Name="test-relation") + with db.begin(): + relation_type = db.create(RelationType, Name="test-relation") + assert bool(relation_type.ID) assert relation_type.Name == "test-relation" - delete(RelationType, RelationType.ID == relation_type.ID) + with db.begin(): + db.delete(RelationType, RelationType.ID == relation_type.ID) def test_relation_types(): - conflicts = query(RelationType, RelationType.Name == "conflicts").first() + conflicts = db.query(RelationType, RelationType.Name == "conflicts").first() assert conflicts is not None assert conflicts.Name == "conflicts" - provides = query(RelationType, RelationType.Name == "provides").first() + provides = db.query(RelationType, RelationType.Name == "provides").first() assert provides is not None assert provides.Name == "provides" - replaces = query(RelationType, RelationType.Name == "replaces").first() + replaces = db.query(RelationType, RelationType.Name == "replaces").first() assert replaces is not None assert replaces.Name == "replaces" diff --git a/test/test_request_type.py b/test/test_request_type.py index a3b3ccb8..8d21c2d9 100644 --- a/test/test_request_type.py +++ b/test/test_request_type.py @@ -1,6 +1,6 @@ import pytest -from aurweb.db import create, delete, query +from aurweb import db from aurweb.models.request_type import DELETION_ID, MERGE_ID, ORPHAN_ID, RequestType from aurweb.testing import setup_test_db @@ -11,25 +11,33 @@ def setup(): def test_request_type_creation(): - request_type = create(RequestType, Name="Test Request") + with db.begin(): + request_type = db.create(RequestType, Name="Test Request") + assert bool(request_type.ID) assert request_type.Name == "Test Request" - delete(RequestType, RequestType.ID == request_type.ID) + + with db.begin(): + db.delete(RequestType, RequestType.ID == request_type.ID) def test_request_type_null_name_returns_empty_string(): - request_type = create(RequestType) + with db.begin(): + request_type = db.create(RequestType) + assert bool(request_type.ID) assert request_type.Name == str() - delete(RequestType, RequestType.ID == request_type.ID) + + with db.begin(): + db.delete(RequestType, RequestType.ID == request_type.ID) def test_request_type_name_display(): - deletion = query(RequestType, RequestType.ID == DELETION_ID).first() + deletion = db.query(RequestType, RequestType.ID == DELETION_ID).first() assert deletion.name_display() == "Deletion" - orphan = query(RequestType, RequestType.ID == ORPHAN_ID).first() + orphan = db.query(RequestType, RequestType.ID == ORPHAN_ID).first() assert orphan.name_display() == "Orphan" - merge = query(RequestType, RequestType.ID == MERGE_ID).first() + merge = db.query(RequestType, RequestType.ID == MERGE_ID).first() assert merge.name_display() == "Merge" diff --git a/test/test_routes.py b/test/test_routes.py index a2d1786e..e3f69d7a 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -8,8 +8,8 @@ import pytest from fastapi.testclient import TestClient +from aurweb import db from aurweb.asgi import app -from aurweb.db import create, query from aurweb.models.account_type import AccountType from aurweb.models.user import User from aurweb.testing import setup_test_db @@ -24,11 +24,13 @@ def setup(): setup_test_db("Users", "Sessions") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + account_type = db.query(AccountType, + AccountType.AccountType == "User").first() + + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) client = TestClient(app) diff --git a/test/test_rss.py b/test/test_rss.py index 7dd5bb47..ce3bc71f 100644 --- a/test/test_rss.py +++ b/test/test_rss.py @@ -49,14 +49,13 @@ def packages(user): now = int(datetime.utcnow().timestamp()) # Create 101 packages; we limit 100 on RSS feeds. - for i in range(101): - pkgbase = db.create( - PackageBase, Maintainer=user, Name=f"test-package-{i}", - SubmittedTS=(now + i), ModifiedTS=(now + i), autocommit=False) - pkg = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase, - autocommit=False) - pkgs.append(pkg) - db.commit() + with db.begin(): + for i in range(101): + pkgbase = db.create( + PackageBase, Maintainer=user, Name=f"test-package-{i}", + SubmittedTS=(now + i), ModifiedTS=(now + i)) + pkg = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) + pkgs.append(pkg) yield pkgs diff --git a/test/test_session.py b/test/test_session.py index 1ba11556..4e6f4db4 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -4,7 +4,7 @@ from unittest import mock import pytest -from aurweb.db import create, query +from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.session import Session, generate_unique_sid from aurweb.models.user import User @@ -19,13 +19,16 @@ def setup(): setup_test_db("Users", "Sessions") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - ResetKey="testReset", Passwd="testPassword", - AccountType=account_type) - session = create(Session, UsersID=user.ID, SessionID="testSession", - LastUpdateTS=datetime.utcnow().timestamp()) + account_type = db.query(AccountType, + AccountType.AccountType == "User").first() + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + ResetKey="testReset", Passwd="testPassword", + AccountType=account_type) + + with db.begin(): + session = db.create(Session, UsersID=user.ID, SessionID="testSession", + LastUpdateTS=datetime.utcnow().timestamp()) def test_session(): @@ -35,12 +38,15 @@ def test_session(): def test_session_cs(): """ Test case sensitivity of the database table. """ - user2 = create(User, Username="test2", Email="test2@example.org", - ResetKey="testReset2", Passwd="testPassword", - AccountType=account_type) - session_cs = create(Session, UsersID=user2.ID, - SessionID="TESTSESSION", - LastUpdateTS=datetime.utcnow().timestamp()) + with db.begin(): + user2 = db.create(User, Username="test2", Email="test2@example.org", + ResetKey="testReset2", Passwd="testPassword", + AccountType=account_type) + + with db.begin(): + session_cs = db.create(Session, UsersID=user2.ID, + SessionID="TESTSESSION", + LastUpdateTS=datetime.utcnow().timestamp()) assert session_cs.SessionID == "TESTSESSION" assert session.SessionID == "testSession" diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py index 0793199a..12a3e1ce 100644 --- a/test/test_ssh_pub_key.py +++ b/test/test_ssh_pub_key.py @@ -1,6 +1,6 @@ import pytest -from aurweb.db import create, query +from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.user import User @@ -19,19 +19,18 @@ def setup(): setup_test_db("Users", "SSHPubKeys") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + account_type = db.query(AccountType, + AccountType.AccountType == "User").first() + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) - assert account_type == user.AccountType - assert account_type.ID == user.AccountTypeID - - ssh_pub_key = create(SSHPubKey, - UserID=user.ID, - Fingerprint="testFingerprint", - PubKey="testPubKey") + with db.begin(): + ssh_pub_key = db.create(SSHPubKey, + UserID=user.ID, + Fingerprint="testFingerprint", + PubKey="testPubKey") def test_ssh_pub_key(): @@ -43,9 +42,10 @@ def test_ssh_pub_key(): def test_ssh_pub_key_cs(): """ Test case sensitivity of the database table. """ - ssh_pub_key_cs = create(SSHPubKey, UserID=user.ID, - Fingerprint="TESTFINGERPRINT", - PubKey="TESTPUBKEY") + with db.begin(): + ssh_pub_key_cs = db.create(SSHPubKey, UserID=user.ID, + Fingerprint="TESTFINGERPRINT", + PubKey="TESTPUBKEY") assert ssh_pub_key_cs.Fingerprint == "TESTFINGERPRINT" assert ssh_pub_key_cs.PubKey == "TESTPUBKEY" diff --git a/test/test_term.py b/test/test_term.py index 25108419..3f28311f 100644 --- a/test/test_term.py +++ b/test/test_term.py @@ -2,7 +2,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create +from aurweb import db from aurweb.models.term import Term from aurweb.testing import setup_test_db @@ -18,8 +18,9 @@ def setup(): def test_term_creation(): - term = create(Term, Description="Term description", - URL="https://fake_url.io") + with db.begin(): + term = db.create(Term, Description="Term description", + URL="https://fake_url.io") assert bool(term.ID) assert term.Description == "Term description" assert term.URL == "https://fake_url.io" @@ -27,14 +28,14 @@ def test_term_creation(): def test_term_null_description_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(Term, URL="https://fake_url.io") - session.rollback() + with db.begin(): + db.create(Term, URL="https://fake_url.io") + db.rollback() def test_term_null_url_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(Term, Description="Term description") - session.rollback() + with db.begin(): + db.create(Term, Description="Term description") + db.rollback() diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index 0c33f958..67181db3 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -90,37 +90,37 @@ def client(): def tu_user(): tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first() - yield db.create(User, Username="test_tu", Email="test_tu@example.org", - RealName="Test TU", Passwd="testPassword", - AccountType=tu_type) + with db.begin(): + tu_user = db.create(User, Username="test_tu", + Email="test_tu@example.org", + RealName="Test TU", Passwd="testPassword", + AccountType=tu_type) + yield tu_user @pytest.fixture def user(): user_type = db.query(AccountType, AccountType.AccountType == "User").first() - yield db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=user_type) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=user_type) + yield user @pytest.fixture -def proposal(tu_user): +def proposal(user, tu_user): ts = int(datetime.utcnow().timestamp()) agenda = "Test proposal." start = ts - 5 end = ts + 1000 - user_type = db.query(AccountType, - AccountType.AccountType == "User").first() - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=user_type) - - voteinfo = db.create(TUVoteInfo, - Agenda=agenda, Quorum=0.0, - User=user.Username, Submitter=tu_user, - Submitted=start, End=end) + with db.begin(): + voteinfo = db.create(TUVoteInfo, + Agenda=agenda, Quorum=0.0, + User=user.Username, Submitter=tu_user, + Submitted=start, End=end) yield (tu_user, user, voteinfo) @@ -170,20 +170,22 @@ def test_tu_index(client, tu_user): ("Test agenda 2", ts - 1000, ts - 5) # Not running anymore. ] vote_records = [] - for vote in votes: - agenda, start, end = vote - vote_records.append( - db.create(TUVoteInfo, Agenda=agenda, - User=tu_user.Username, - Submitted=start, End=end, - Quorum=0.0, - Submitter=tu_user)) + with db.begin(): + for vote in votes: + agenda, start, end = vote + vote_records.append( + db.create(TUVoteInfo, Agenda=agenda, + User=tu_user.Username, + Submitted=start, End=end, + Quorum=0.0, + Submitter=tu_user)) - # Vote on an ended proposal. - vote_record = vote_records[1] - vote_record.Yes += 1 - vote_record.ActiveTUs += 1 - db.create(TUVote, VoteInfo=vote_record, User=tu_user) + with db.begin(): + # Vote on an ended proposal. + vote_record = vote_records[1] + vote_record.Yes += 1 + vote_record.ActiveTUs += 1 + db.create(TUVote, VoteInfo=vote_record, User=tu_user) cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: @@ -255,22 +257,22 @@ def test_tu_index(client, tu_user): def test_tu_index_table_paging(client, tu_user): ts = int(datetime.utcnow().timestamp()) - for i in range(25): - # Create 25 current votes. - db.create(TUVoteInfo, Agenda=f"Agenda #{i}", - User=tu_user.Username, - Submitted=(ts - 5), End=(ts + 1000), - Quorum=0.0, - Submitter=tu_user, autocommit=False) + with db.begin(): + for i in range(25): + # Create 25 current votes. + db.create(TUVoteInfo, Agenda=f"Agenda #{i}", + User=tu_user.Username, + Submitted=(ts - 5), End=(ts + 1000), + Quorum=0.0, + Submitter=tu_user) - for i in range(25): - # Create 25 past votes. - db.create(TUVoteInfo, Agenda=f"Agenda #{25 + i}", - User=tu_user.Username, - Submitted=(ts - 1000), End=(ts - 5), - Quorum=0.0, - Submitter=tu_user, autocommit=False) - db.commit() + for i in range(25): + # Create 25 past votes. + db.create(TUVoteInfo, Agenda=f"Agenda #{25 + i}", + User=tu_user.Username, + Submitted=(ts - 1000), End=(ts - 5), + Quorum=0.0, + Submitter=tu_user) cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: @@ -363,18 +365,19 @@ def test_tu_index_table_paging(client, tu_user): def test_tu_index_sorting(client, tu_user): ts = int(datetime.utcnow().timestamp()) - for i in range(2): - # Create 'Agenda #1' and 'Agenda #2'. - db.create(TUVoteInfo, Agenda=f"Agenda #{i + 1}", - User=tu_user.Username, - Submitted=(ts + 5), End=(ts + 1000), - Quorum=0.0, - Submitter=tu_user, autocommit=False) + with db.begin(): + for i in range(2): + # Create 'Agenda #1' and 'Agenda #2'. + db.create(TUVoteInfo, Agenda=f"Agenda #{i + 1}", + User=tu_user.Username, + Submitted=(ts + 5), End=(ts + 1000), + Quorum=0.0, + Submitter=tu_user) - # Let's order each vote one day after the other. - # This will allow us to test the sorting nature - # of the tables. - ts += 86405 + # Let's order each vote one day after the other. + # This will allow us to test the sorting nature + # of the tables. + ts += 86405 # Make a default request to /tu. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} @@ -432,18 +435,19 @@ def test_tu_index_sorting(client, tu_user): def test_tu_index_last_votes(client, tu_user, user): ts = int(datetime.utcnow().timestamp()) - # Create a proposal which has ended. - voteinfo = db.create(TUVoteInfo, Agenda="Test agenda", - User=user.Username, - Submitted=(ts - 1000), - End=(ts - 5), - Yes=1, - ActiveTUs=1, - Quorum=0.0, - Submitter=tu_user) + with db.begin(): + # Create a proposal which has ended. + voteinfo = db.create(TUVoteInfo, Agenda="Test agenda", + User=user.Username, + Submitted=(ts - 1000), + End=(ts - 5), + Yes=1, + ActiveTUs=1, + Quorum=0.0, + Submitter=tu_user) - # Create a vote on it from tu_user. - db.create(TUVote, VoteInfo=voteinfo, User=tu_user) + # Create a vote on it from tu_user. + db.create(TUVote, VoteInfo=voteinfo, User=tu_user) # Now, check that tu_user got populated in the .last-votes table. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} @@ -529,10 +533,10 @@ def test_tu_running_proposal(client, proposal): assert abstain.attrib["value"] == "Abstain" # Create a vote. - db.create(TUVote, VoteInfo=voteinfo, User=tu_user) - voteinfo.ActiveTUs += 1 - voteinfo.Yes += 1 - db.commit() + with db.begin(): + db.create(TUVote, VoteInfo=voteinfo, User=tu_user) + voteinfo.ActiveTUs += 1 + voteinfo.Yes += 1 # Make another request now that we've voted. with client as request: @@ -556,8 +560,8 @@ def test_tu_ended_proposal(client, proposal): tu_user, user, voteinfo = proposal ts = int(datetime.utcnow().timestamp()) - voteinfo.End = ts - 5 # 5 seconds ago. - db.commit() + with db.begin(): + voteinfo.End = ts - 5 # 5 seconds ago. # Initiate an authenticated GET request to /tu/{proposal_id}. proposal_id = voteinfo.ID @@ -635,8 +639,8 @@ def test_tu_proposal_vote_unauthorized(client, proposal): dev_type = db.query(AccountType, AccountType.AccountType == "Developer").first() - tu_user.AccountType = dev_type - db.commit() + with db.begin(): + tu_user.AccountType = dev_type cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: @@ -664,8 +668,8 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): tu_user, user, voteinfo = proposal # Update voteinfo.User. - voteinfo.User = tu_user.Username - db.commit() + with db.begin(): + voteinfo.User = tu_user.Username cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: @@ -692,10 +696,10 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): def test_tu_proposal_vote_already_voted(client, proposal): tu_user, user, voteinfo = proposal - db.create(TUVote, VoteInfo=voteinfo, User=tu_user) - voteinfo.Yes += 1 - voteinfo.ActiveTUs += 1 - db.commit() + with db.begin(): + db.create(TUVote, VoteInfo=voteinfo, User=tu_user) + voteinfo.Yes += 1 + voteinfo.ActiveTUs += 1 cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py index 494300c5..b60e2e6a 100644 --- a/test/test_tu_voteinfo.py +++ b/test/test_tu_voteinfo.py @@ -4,7 +4,8 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import commit, create, query, rollback +from aurweb import db +from aurweb.db import create, query, rollback from aurweb.models.account_type import AccountType from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User @@ -21,19 +22,21 @@ def setup(): tu_type = query(AccountType, AccountType.AccountType == "Trusted User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=tu_type) + with db.begin(): + user = create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=tu_type) def test_tu_voteinfo_creation(): ts = int(datetime.utcnow().timestamp()) - tu_voteinfo = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 5, - Quorum=0.5, - Submitter=user) + with db.begin(): + tu_voteinfo = create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 5, + Quorum=0.5, + Submitter=user) assert bool(tu_voteinfo.ID) assert tu_voteinfo.Agenda == "Blah blah." assert tu_voteinfo.User == user.Username @@ -51,32 +54,33 @@ def test_tu_voteinfo_creation(): def test_tu_voteinfo_is_running(): ts = int(datetime.utcnow().timestamp()) - tu_voteinfo = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 1000, - Quorum=0.5, - Submitter=user) + with db.begin(): + tu_voteinfo = create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 1000, + Quorum=0.5, + Submitter=user) assert tu_voteinfo.is_running() is True - tu_voteinfo.End = ts - 5 - commit() + with db.begin(): + tu_voteinfo.End = ts - 5 assert tu_voteinfo.is_running() is False def test_tu_voteinfo_total_votes(): ts = int(datetime.utcnow().timestamp()) - tu_voteinfo = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 1000, - Quorum=0.5, - Submitter=user) + with db.begin(): + tu_voteinfo = create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 1000, + Quorum=0.5, + Submitter=user) - tu_voteinfo.Yes = 1 - tu_voteinfo.No = 3 - tu_voteinfo.Abstain = 5 - commit() + tu_voteinfo.Yes = 1 + tu_voteinfo.No = 3 + tu_voteinfo.Abstain = 5 # total_votes() should be the sum of Yes, No and Abstain: 1 + 3 + 5 = 9. assert tu_voteinfo.total_votes() == 9 @@ -84,61 +88,67 @@ def test_tu_voteinfo_total_votes(): def test_tu_voteinfo_null_submitter_raises_exception(): with pytest.raises(IntegrityError): - create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=0, End=0, - Quorum=0.50) + with db.begin(): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, End=0, + Quorum=0.50) rollback() def test_tu_voteinfo_null_agenda_raises_exception(): with pytest.raises(IntegrityError): - create(TUVoteInfo, - User=user.Username, - Submitted=0, End=0, - Quorum=0.50, - Submitter=user) + with db.begin(): + create(TUVoteInfo, + User=user.Username, + Submitted=0, End=0, + Quorum=0.50, + Submitter=user) rollback() def test_tu_voteinfo_null_user_raises_exception(): with pytest.raises(IntegrityError): - create(TUVoteInfo, - Agenda="Blah blah.", - Submitted=0, End=0, - Quorum=0.50, - Submitter=user) + with db.begin(): + create(TUVoteInfo, + Agenda="Blah blah.", + Submitted=0, End=0, + Quorum=0.50, + Submitter=user) rollback() def test_tu_voteinfo_null_submitted_raises_exception(): with pytest.raises(IntegrityError): - create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - End=0, - Quorum=0.50, - Submitter=user) + with db.begin(): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + End=0, + Quorum=0.50, + Submitter=user) rollback() def test_tu_voteinfo_null_end_raises_exception(): with pytest.raises(IntegrityError): - create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=0, - Quorum=0.50, - Submitter=user) + with db.begin(): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, + Quorum=0.50, + Submitter=user) rollback() def test_tu_voteinfo_null_quorum_raises_exception(): with pytest.raises(IntegrityError): - create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=0, End=0, - Submitter=user) + with db.begin(): + create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, End=0, + Submitter=user) rollback() diff --git a/test/test_user.py b/test/test_user.py index 7756cff3..70eac079 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -9,7 +9,7 @@ import pytest import aurweb.auth import aurweb.config -from aurweb.db import commit, create, query +from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.ban import Ban from aurweb.models.package import Package @@ -40,12 +40,13 @@ def setup(): PackageNotification.__tablename__ ) - account_type = query(AccountType, - AccountType.AccountType == "User").first() + account_type = db.query(AccountType, + AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) def test_user_login_logout(): @@ -70,14 +71,14 @@ def test_user_login_logout(): assert "AURSID" in request.cookies # Expect that User session relationships work right. - user_session = query(Session, - Session.UsersID == user.ID).first() + user_session = db.query(Session, + Session.UsersID == user.ID).first() assert user_session == user.session assert user.session.SessionID == sid assert user.session.User == user # Search for the user via query API. - result = query(User, User.ID == user.ID).first() + result = db.query(User, User.ID == user.ID).first() # Compare the result and our original user. assert result == user @@ -114,7 +115,8 @@ def test_user_login_twice(): def test_user_login_banned(): # Add ban for the next 30 seconds. banned_timestamp = datetime.utcnow() + timedelta(seconds=30) - create(Ban, IPAddress="127.0.0.1", BanTS=banned_timestamp) + with db.begin(): + db.create(Ban, IPAddress="127.0.0.1", BanTS=banned_timestamp) request = Request() request.client.host = "127.0.0.1" @@ -122,18 +124,17 @@ def test_user_login_banned(): def test_user_login_suspended(): - from aurweb.db import session - user.Suspended = True - session.commit() + with db.begin(): + user.Suspended = True assert not user.login(Request(), "testPassword") def test_legacy_user_authentication(): - from aurweb.db import session - - user.Salt = bcrypt.gensalt().decode() - user.Passwd = hashlib.md5(f"{user.Salt}testPassword".encode()).hexdigest() - session.commit() + with db.begin(): + user.Salt = bcrypt.gensalt().decode() + user.Passwd = hashlib.md5( + f"{user.Salt}testPassword".encode() + ).hexdigest() assert not user.valid_password("badPassword") assert user.valid_password("testPassword") @@ -145,8 +146,9 @@ def test_legacy_user_authentication(): def test_user_login_with_outdated_sid(): # Make a session with a LastUpdateTS 5 seconds ago, causing # user.login to update it with a new sid. - create(Session, UsersID=user.ID, SessionID="stub", - LastUpdateTS=datetime.utcnow().timestamp() - 5) + with db.begin(): + db.create(Session, UsersID=user.ID, SessionID="stub", + LastUpdateTS=datetime.utcnow().timestamp() - 5) sid = user.login(Request(), "testPassword") assert sid and user.is_authenticated() assert sid != "stub" @@ -171,43 +173,42 @@ def test_user_has_credential(): def test_user_ssh_pub_key(): assert user.ssh_pub_key is None - ssh_pub_key = create(SSHPubKey, UserID=user.ID, - Fingerprint="testFingerprint", - PubKey="testPubKey") + with db.begin(): + ssh_pub_key = db.create(SSHPubKey, UserID=user.ID, + Fingerprint="testFingerprint", + PubKey="testPubKey") assert user.ssh_pub_key == ssh_pub_key def test_user_credential_types(): - from aurweb.db import session - assert aurweb.auth.user_developer_or_trusted_user(user) assert not aurweb.auth.trusted_user(user) assert not aurweb.auth.developer(user) assert not aurweb.auth.trusted_user_or_dev(user) - trusted_user_type = query(AccountType, - AccountType.AccountType == "Trusted User")\ - .first() - user.AccountType = trusted_user_type - session.commit() + trusted_user_type = db.query(AccountType).filter( + AccountType.AccountType == "Trusted User" + ).first() + with db.begin(): + user.AccountType = trusted_user_type assert aurweb.auth.trusted_user(user) assert aurweb.auth.trusted_user_or_dev(user) - developer_type = query(AccountType, - AccountType.AccountType == "Developer").first() - user.AccountType = developer_type - session.commit() + developer_type = db.query(AccountType, + AccountType.AccountType == "Developer").first() + with db.begin(): + user.AccountType = developer_type assert aurweb.auth.developer(user) assert aurweb.auth.trusted_user_or_dev(user) type_str = "Trusted User & Developer" - elevated_type = query(AccountType, - AccountType.AccountType == type_str).first() - user.AccountType = elevated_type - session.commit() + elevated_type = db.query(AccountType, + AccountType.AccountType == type_str).first() + with db.begin(): + user.AccountType = elevated_type assert aurweb.auth.trusted_user(user) assert aurweb.auth.developer(user) @@ -233,53 +234,56 @@ def test_user_as_dict(): def test_user_is_trusted_user(): - tu_type = query(AccountType, - AccountType.AccountType == "Trusted User").first() - user.AccountType = tu_type - commit() + tu_type = db.query(AccountType, + AccountType.AccountType == "Trusted User").first() + with db.begin(): + user.AccountType = tu_type assert user.is_trusted_user() is True # Do it again with the combined role. - tu_type = query( + tu_type = db.query( AccountType, AccountType.AccountType == "Trusted User & Developer").first() - user.AccountType = tu_type - commit() + with db.begin(): + user.AccountType = tu_type assert user.is_trusted_user() is True def test_user_is_developer(): - dev_type = query(AccountType, - AccountType.AccountType == "Developer").first() - user.AccountType = dev_type - commit() + dev_type = db.query(AccountType, + AccountType.AccountType == "Developer").first() + with db.begin(): + user.AccountType = dev_type assert user.is_developer() is True # Do it again with the combined role. - dev_type = query( + dev_type = db.query( AccountType, AccountType.AccountType == "Trusted User & Developer").first() - user.AccountType = dev_type - commit() + with db.begin(): + user.AccountType = dev_type assert user.is_developer() is True def test_user_voted_for(): now = int(datetime.utcnow().timestamp()) - pkgbase = create(PackageBase, Name="pkg1", Maintainer=user) - pkg = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) - create(PackageVote, PackageBase=pkgbase, User=user, VoteTS=now) + with db.begin(): + pkgbase = db.create(PackageBase, Name="pkg1", Maintainer=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + db.create(PackageVote, PackageBase=pkgbase, User=user, VoteTS=now) assert user.voted_for(pkg) def test_user_notified(): - pkgbase = create(PackageBase, Name="pkg1", Maintainer=user) - pkg = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) - create(PackageNotification, PackageBase=pkgbase, User=user) + with db.begin(): + pkgbase = db.create(PackageBase, Name="pkg1", Maintainer=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + db.create(PackageNotification, PackageBase=pkgbase, User=user) assert user.notified(pkg) def test_user_packages(): - pkgbase = create(PackageBase, Name="pkg1", Maintainer=user) - pkg = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + with db.begin(): + pkgbase = db.create(PackageBase, Name="pkg1", Maintainer=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) assert pkg in user.packages() From 1b452d126471df269605ed4e39edcdd38f9e59d8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 3 Sep 2021 21:02:35 -0700 Subject: [PATCH 0853/1891] Add GPL 2.0 LICENSE file This was missing from the project and really needs to be here. Closes #107 Signed-off-by: Kevin Morris --- LICENSE | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. From 5c7e76ef891af78dbe4e3cacb42675b86d9f3a35 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 3 Sep 2021 21:02:35 -0700 Subject: [PATCH 0854/1891] Add GPL 2.0 LICENSE file This was missing from the project and really needs to be here. Closes #107 Signed-off-by: Kevin Morris --- LICENSE | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. From 5e6f0cb8d71266d8ba29ea24db267914b1e33973 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Sep 2021 10:02:40 -0700 Subject: [PATCH 0855/1891] Revert "Add GPL 2.0 LICENSE file" This was already in the repository in ./COPYING This reverts commit 1b452d126471df269605ed4e39edcdd38f9e59d8. --- LICENSE | 339 -------------------------------------------------------- 1 file changed, 339 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d511905c..00000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. From 4e5b67f0a6164a237bbab17f56db9c037cc365f0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Sep 2021 10:02:40 -0700 Subject: [PATCH 0856/1891] Revert "Add GPL 2.0 LICENSE file" This was already in the repository in ./COPYING This reverts commit 1b452d126471df269605ed4e39edcdd38f9e59d8. --- LICENSE | 339 -------------------------------------------------------- 1 file changed, 339 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d511905c..00000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. From 2f9994807becf152cc6617e5e0e6d6ba24b2c363 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Sep 2021 10:02:13 -0700 Subject: [PATCH 0857/1891] use Poetry to deal with deps and package install As the new-age Python package manager, Poetry brings a lot of good additions to the table. It allows us to more easily deal with virtualenvs for the project and resolve dependencies. As of this commit, `requirements.txt` is replaced by Poetry, configured at `pyproject.toml`. In Docker and GitLab, we currently use Poetry in a root fashion. We should work toward purely using virtualenvs in Docker, but, for now we'd like to move forward with other things. The project can still be installed to a virtualenv and used on a user's system through Poetry; it is just not yet doing so in Docker. Modifications: * docker/scripts/install-deps.sh * Remove python dependencies. * conf/config.defaults * Script paths have been updated to use '/usr/bin'. * docker/git-entrypoint.sh * Use '/usr/bin/aurweb-git-auth' instead of '/usr/local/bin/aurweb-git-auth'. Additions: * docker/scripts/install-python-deps.sh * A script used purely to install Python dependencies with Poetry. This has to be used within the aurweb project directory and requires system-wide dependencies are installed beforehand. * Also upgrades system-wide pip. Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 4 +- Dockerfile | 15 +- INSTALL | 54 +- conf/config.defaults | 10 +- docker/git-entrypoint.sh | 2 +- docker/scripts/install-deps.sh | 14 +- docker/scripts/install-python-deps.sh | 14 + poetry.lock | 1577 +++++++++++++++++++++++++ pyproject.toml | 100 ++ requirements.txt | 36 - setup.py | 36 - 11 files changed, 1756 insertions(+), 106 deletions(-) create mode 100755 docker/scripts/install-python-deps.sh create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d360d483..ffea5308 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,8 +11,9 @@ variables: DB_HOST: localhost before_script: + - export PATH="$HOME/.poetry/bin:${PATH}" - ./docker/scripts/install-deps.sh - - pip install -r requirements.txt + - ./docker/scripts/install-python-deps.sh - useradd -U -d /aurweb -c 'AUR User' aur - ./docker/mariadb-entrypoint.sh - (cd '/usr' && /usr/bin/mysqld_safe --datadir='/var/lib/mysql') & @@ -20,7 +21,6 @@ before_script: - ./docker/test-mysql-entrypoint.sh # Create mysql AUR_CONFIG. - ./docker/test-sqlite-entrypoint.sh # Create sqlite AUR_CONFIG. - make -C po all install - - python setup.py install --install-scripts=/usr/local/bin - python -m aurweb.initdb # Initialize MySQL tables. - AUR_CONFIG=conf/config.sqlite python -m aurweb.initdb - make -C test clean diff --git a/Dockerfile b/Dockerfile index 6539bd94..76da62f7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,25 @@ FROM archlinux:base-devel +ENV PATH="$HOME/.poetry/bin:${PATH}" ENV PYTHONPATH=/aurweb ENV AUR_CONFIG=conf/config +# Install system-wide dependencies. +COPY ./docker/scripts/install-deps.sh /install-deps.sh +RUN /install-deps.sh + # Copy Docker scripts COPY ./docker /docker COPY ./docker/scripts/*.sh /usr/local/bin/ -# Install system-wide dependencies. -RUN /docker/scripts/install-deps.sh - # Copy over all aurweb files. COPY . /aurweb # Working directory is aurweb root @ /aurweb. WORKDIR /aurweb -# Install pip directories now that we have access to /aurweb. -RUN pip install -r requirements.txt +# Install Python dependencies. +RUN /docker/scripts/install-python-deps.sh # Add our aur user. RUN useradd -U -d /aurweb -c 'AUR User' aur @@ -27,6 +29,3 @@ RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime # Install translations. RUN make -C po all install - -# Install package and scripts. -RUN python setup.py install --install-scripts=/usr/local/bin diff --git a/INSTALL b/INSTALL index 4df59bd2..e14b9f31 100644 --- a/INSTALL +++ b/INSTALL @@ -45,22 +45,54 @@ read the instructions below. if the defaults file does not exist) and adjust the configuration (pay attention to disable_http_login, enable_maintenance and aur_location). -4) Install Python modules and dependencies: +4) Install dependencies. - # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy \ - python-bleach python-markdown python-alembic hypercorn \ - python-itsdangerous python-authlib python-httpx \ - python-jinja python-aiofiles python-python-multipart \ - python-requests hypercorn python-bcrypt python-email-validator \ - python-lxml python-feedgen - # python3 setup.py install +4a) Install system-wide dependencies: -(FastAPI-Specific) + # pacman -S git gpgme cgit pyalpm python-srcinfo curl openssh \ + uwsgi uwsgi-plugin-cgi php php-fpm - # pacman -S redis python-redis python-fakeredis python-orjson +4b) Install Python dependencies via poetry (required): + +**NOTE** Users do not need to install pip or poetry dependencies system-wide. +You may take advantage of Poetry's virtualenv integration to manage +dependencies. This is merely a demonstration to show users how to without +a virtualenv. In Docker and CI, we don't yet use a virtualenv. + + ## Install Poetry dependencies system-wide, if not using a virtualenv. + # pacman -S python-pip + + ## Ensure pip is upgraded. Poetry depends on it being up to date. + # pip install --upgrade pip + + ## Install Poetry. + # curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + # export PATH="$HOME/.poetry/bin:${PATH}" + + ## Use Poetry to install dependencies and the aurweb package. + # poetry lock # Resolve dependencies + # poetry update # Install/update dependencies + # poetry build # Build the aurweb package + # poetry install # Install the aurweb package and scripts + +When installing in a virtualenv, config.defaults must contain the correct +absolute paths to aurweb scripts, which requires modification. + +4c) Setup FastAPI Redis cache (optional). + +First, install Redis and start its service. + + # pacman -S redis # systemctl enable --now redis -5) Create a new MySQL database and a user and import the aurweb SQL schema: +Now that Redis is running, ensure that you configure aurweb to use +the Redis cache by setting `cache = redis` in your AUR config. + +In `conf/config.defaults`, the `redis_address` configuration is set +to `redis://localhost`. This can be set to point to any Redis server +and will be used as long as `cache = redis`. + +5) Create a new database and a user and import the aurweb SQL schema: $ python -m aurweb.initdb diff --git a/conf/config.defaults b/conf/config.defaults index 1b4c3a74..1c96a55d 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -34,8 +34,8 @@ commit_uri = /cgit/aur.git/commit/?h=%s&id=%s snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 -render-comment-cmd = /usr/local/bin/aurweb-rendercomment -localedir = /srv/http/aurweb/aur.git/web/locale/ +render-comment-cmd = /usr/bin/aurweb-rendercomment +localedir = /srv/http/aurweb/web/locale/ ; memcache, apc, or redis ; memcache/apc are supported in PHP, redis is supported in Python. cache = none @@ -49,7 +49,7 @@ request_limit = 4000 window_length = 86400 [notifications] -notify-cmd = /usr/local/bin/aurweb-notify +notify-cmd = /usr/bin/aurweb-notify sendmail = smtp-server = localhost smtp-port = 25 @@ -68,7 +68,7 @@ RSA = SHA256:Ju+yWiMb/2O+gKQ9RJCDqvRg7l+Q95KFAeqM5sr6l2s [auth] valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 sk-ssh-ecdsa@openssh.com sk-ssh-ed25519@openssh.com username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ -git-serve-cmd = /usr/local/bin/aurweb-git-serve +git-serve-cmd = /usr/bin/aurweb-git-serve ssh-options = restrict [sso] @@ -83,7 +83,7 @@ session_secret = repo-path = /srv/http/aurweb/aur.git/ repo-regex = [a-z0-9][a-z0-9.+_-]*$ git-shell-cmd = /usr/bin/git-shell -git-update-cmd = /usr/local/bin/aurweb-git-update +git-update-cmd = /usr/bin/aurweb-git-update ssh-cmdline = ssh aur@aur.archlinux.org [update] diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index 57752ac5..cfd159c9 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -25,7 +25,7 @@ chmod 755 /app cat >> $AUTH_SCRIPT << EOF #!/usr/bin/env bash export AUR_CONFIG="$AUR_CONFIG" -exec /usr/local/bin/aurweb-git-auth "\$@" +exec /usr/bin/aurweb-git-auth "\$@" EOF chmod 755 $AUTH_SCRIPT diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 4985fe85..f8881d05 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -5,12 +5,12 @@ set -eou pipefail pacman -Syu --noconfirm --noprogressbar \ - --cachedir .pkg-cache git gpgme \ - nginx redis openssh \ - mariadb mariadb-libs \ - cgit uwsgi uwsgi-plugin-cgi \ - php php-fpm \ - memcached php-memcached \ - python-pip pyalpm python-srcinfo + --cachedir .pkg-cache git gpgme nginx redis openssh \ + mariadb mariadb-libs cgit uwsgi uwsgi-plugin-cgi \ + php php-fpm memcached php-memcached python-pip pyalpm \ + python-srcinfo curl + +# https://python-poetry.org/docs/ Installation section. +curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - exec "$@" diff --git a/docker/scripts/install-python-deps.sh b/docker/scripts/install-python-deps.sh new file mode 100755 index 00000000..df9b5997 --- /dev/null +++ b/docker/scripts/install-python-deps.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -eou pipefail + +# Upgrade PIP; Arch Linux's version of pip is outdated for Poetry. +pip install --upgrade pip + +# Install the aurweb package and deps system-wide via poetry. +poetry config virtualenvs.create false +poetry lock +poetry update +poetry build +poetry install --no-interaction --no-ansi + +exec "$@" diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..3cc84361 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1577 @@ +[[package]] +name = "aiofiles" +version = "0.7.0" +description = "File support for asyncio." +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[[package]] +name = "alembic" +version = "1.6.5" +description = "A database migration tool for SQLAlchemy." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" + +[package.dependencies] +Mako = "*" +python-dateutil = "*" +python-editor = ">=0.3" +SQLAlchemy = ">=1.3.0" + +[[package]] +name = "anyio" +version = "3.3.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +trio = ["trio (>=0.16)"] + +[[package]] +name = "asgiref" +version = "3.4.1" +description = "ASGI specs, helper code, and adapters" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] + +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] + +[[package]] +name = "authlib" +version = "0.15.2" +description = "The ultimate Python library in building OAuth and OpenID Connect servers." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +cryptography = "*" + +[package.extras] +client = ["requests"] + +[[package]] +name = "bcrypt" +version = "3.2.0" +description = "Modern password hashing for your software and your servers" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.1" +six = ">=1.4.1" + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + +[[package]] +name = "bleach" +version = "3.3.1" +description = "An easy safelist-based HTML-sanitizing tool." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +packaging = "*" +six = ">=1.9.0" +webencodings = "*" + +[[package]] +name = "certifi" +version = "2021.5.30" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "cffi" +version = "1.14.6" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.4" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "click" +version = "8.0.1" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "coverage" +version = "5.5" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +toml = ["toml"] + +[[package]] +name = "cryptography" +version = "3.4.8" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools-rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] + +[[package]] +name = "dnspython" +version = "2.1.0" +description = "DNS toolkit" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +dnssec = ["cryptography (>=2.6)"] +doh = ["requests", "requests-toolbelt"] +idna = ["idna (>=2.1)"] +curio = ["curio (>=1.2)", "sniffio (>=1.1)"] +trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"] + +[[package]] +name = "dunamai" +version = "1.6.0" +description = "Dynamic version generation" +category = "main" +optional = false +python-versions = ">=3.5,<4.0" + +[[package]] +name = "email-validator" +version = "1.1.3" +description = "A robust email syntax and deliverability validation library for Python 2.x/3.x." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +dnspython = ">=1.15.0" +idna = ">=2.0.0" + +[[package]] +name = "fakeredis" +version = "1.6.0" +description = "Fake implementation of redis API for testing purposes." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +redis = "<3.6.0" +six = ">=1.12" +sortedcontainers = "*" + +[package.extras] +aioredis = ["aioredis"] +lua = ["lupa"] + +[[package]] +name = "fastapi" +version = "0.66.0" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" +starlette = "0.14.2" + +[package.extras] +all = ["requests (>=2.24.0,<3.0.0)", "aiofiles (>=0.5.0,<0.6.0)", "jinja2 (>=2.11.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<2.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "graphene (>=2.1.8,<3.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)"] +dev = ["python-jose[cryptography] (>=3.1.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "graphene (>=2.1.8,<3.0.0)"] +doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "markdown-include (>=0.6.0,<0.7.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.2.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] +test = ["pytest (==5.4.3)", "pytest-cov (==2.10.0)", "pytest-asyncio (>=0.14.0,<0.15.0)", "mypy (==0.812)", "flake8 (>=3.8.3,<4.0.0)", "black (==20.8b1)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.15.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.4.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.4.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "aiofiles (>=0.5.0,<0.6.0)", "flask (>=1.1.2,<2.0.0)"] + +[[package]] +name = "feedgen" +version = "0.9.0" +description = "Feed Generator (ATOM, RSS, Podcasts)" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +lxml = "*" +python-dateutil = "*" + +[[package]] +name = "flake8" +version = "3.9.2" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" + +[[package]] +name = "h11" +version = "0.12.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "h2" +version = "4.0.0" +description = "HTTP/2 State-Machine based protocol implementation" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +hpack = ">=4.0,<5" +hyperframe = ">=6.0,<7" + +[[package]] +name = "hpack" +version = "4.0.0" +description = "Pure-Python HPACK header compression" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[[package]] +name = "httpcore" +version = "0.13.6" +description = "A minimal low-level HTTP client." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +anyio = ">=3.0.0,<4.0.0" +h11 = ">=0.11,<0.13" +sniffio = ">=1.0.0,<2.0.0" + +[package.extras] +http2 = ["h2 (>=3,<5)"] + +[[package]] +name = "httpx" +version = "0.18.2" +description = "The next generation HTTP client." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +certifi = "*" +httpcore = ">=0.13.3,<0.14.0" +rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +sniffio = "*" + +[package.extras] +brotli = ["brotlicffi (>=1.0.0,<2.0.0)"] +http2 = ["h2 (>=3.0.0,<4.0.0)"] + +[[package]] +name = "hypercorn" +version = "0.11.2" +description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +h11 = "*" +h2 = ">=3.1.0" +priority = "*" +toml = "*" +wsproto = ">=0.14.0" + +[package.extras] +h3 = ["aioquic (>=0.9.0,<1.0)"] +tests = ["hypothesis", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-trio", "trio"] +trio = ["trio (>=0.11.0)"] +uvloop = ["uvloop"] + +[[package]] +name = "hyperframe" +version = "6.0.1" +description = "HTTP/2 framing layer for Python" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[[package]] +name = "idna" +version = "3.2" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "isort" +version = "5.9.3" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.6.1,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] + +[[package]] +name = "itsdangerous" +version = "2.0.1" +description = "Safely pass data to untrusted environments and back." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "jinja2" +version = "3.0.1" +description = "A very fast and expressive template engine." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "lxml" +version = "4.6.3" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["beautifulsoup4"] +source = ["Cython (>=0.29.7)"] + +[[package]] +name = "mako" +version = "1.1.5" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["babel"] +lingua = ["lingua"] + +[[package]] +name = "markdown" +version = "3.3.4" +description = "Python implementation of Markdown." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "2.0.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "mysqlclient" +version = "2.0.3" +description = "Python interface to MySQL" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "orjson" +version = "3.6.3" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pluggy" +version = "0.13.1" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +dev = ["pre-commit", "tox"] + +[[package]] +name = "poetry-dynamic-versioning" +version = "0.13.1" +description = "Plugin for Poetry to enable dynamic versioning based on VCS tags" +category = "main" +optional = false +python-versions = ">=3.5,<4.0" + +[package.dependencies] +dunamai = ">=1.5,<2.0" +jinja2 = {version = ">=2.11.1,<4", markers = "python_version >= \"3.6\" and python_version < \"4.0\""} +tomlkit = ">=0.4" + +[[package]] +name = "priority" +version = "2.0.0" +description = "A pure-Python implementation of the HTTP/2 priority tree" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[[package]] +name = "protobuf" +version = "3.17.3" +description = "Protocol Buffers" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.9" + +[[package]] +name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pycodestyle" +version = "2.7.0" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pycparser" +version = "2.20" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pydantic" +version = "1.8.2" +description = "Data validation and settings management using python 3.6 type hinting" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +typing-extensions = ">=3.7.4.3" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pyflakes" +version = "2.3.1" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pygit2" +version = "1.6.1" +description = "Python bindings for libgit2." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +cffi = ">=1.4.0" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "pytest" +version = "6.2.4" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<1.0.0a1" +py = ">=1.8.2" +toml = "*" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.15.1" +description = "Pytest support for asyncio." +category = "dev" +optional = false +python-versions = ">= 3.6" + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +testing = ["coverage", "hypothesis (>=5.7.1)"] + +[[package]] +name = "pytest-cov" +version = "2.12.1" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +coverage = ">=5.2.1" +pytest = ">=4.6" +toml = "*" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-tap" +version = "3.2" +description = "Test Anything Protocol (TAP) reporting plugin for pytest" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +pytest = ">=3.0" +"tap.py" = ">=3.0,<4.0" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-editor" +version = "1.0.4" +description = "Programmatically open an editor, capture the result." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "python-multipart" +version = "0.0.5" +description = "A streaming multipart parser for Python" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.4.0" + +[[package]] +name = "redis" +version = "3.5.3" +description = "Python client for Redis key-value store" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +hiredis = ["hiredis (>=0.1.3)"] + +[[package]] +name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "rfc3986" +version = "1.5.0" +description = "Validating URI References per RFC 3986" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "sniffio" +version = "1.2.0" +description = "Sniff out which async library your code is running under" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "sqlalchemy" +version = "1.3.23" +description = "Database Abstraction Library" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +mssql = ["pyodbc"] +mssql_pymssql = ["pymssql"] +mssql_pyodbc = ["pyodbc"] +mysql = ["mysqlclient"] +oracle = ["cx-oracle"] +postgresql = ["psycopg2"] +postgresql_pg8000 = ["pg8000 (<1.16.6)"] +postgresql_psycopg2binary = ["psycopg2-binary"] +postgresql_psycopg2cffi = ["psycopg2cffi"] +pymysql = ["pymysql (<1)", "pymysql"] + +[[package]] +name = "starlette" +version = "0.14.2" +description = "The little ASGI library that shines." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] + +[[package]] +name = "tap.py" +version = "3.0" +description = "Test Anything Protocol (TAP) tools" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +yaml = ["more-itertools", "PyYAML (>=5.1)"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tomlkit" +version = "0.7.2" +description = "Style preserving TOML library" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +typing = {version = ">=3.6,<4.0", markers = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"3.5\""} + +[[package]] +name = "typing" +version = "3.7.4.3" +description = "Type Hints for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "typing-extensions" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "urllib3" +version = "1.26.6" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "uvicorn" +version = "0.15.0" +description = "The lightning-fast ASGI server." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +asgiref = ">=3.4.0" +click = ">=7.0" +h11 = ">=0.8" + +[package.extras] +standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "werkzeug" +version = "2.0.1" +description = "The comprehensive WSGI web application library." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +watchdog = ["watchdog"] + +[[package]] +name = "wsproto" +version = "1.0.0" +description = "WebSockets state-machine based protocol implementation" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +h11 = ">=0.9.0,<1" + +[metadata] +lock-version = "1.1" +python-versions = "*" +content-hash = "96112731ca21a6ff5d0657c6c40979642bb992ae660ba8d6135421718737c6b0" + +[metadata.files] +aiofiles = [ + {file = "aiofiles-0.7.0-py3-none-any.whl", hash = "sha256:c67a6823b5f23fcab0a2595a289cec7d8c863ffcb4322fb8cd6b90400aedfdbc"}, + {file = "aiofiles-0.7.0.tar.gz", hash = "sha256:a1c4fc9b2ff81568c83e21392a82f344ea9d23da906e4f6a52662764545e19d4"}, +] +alembic = [ + {file = "alembic-1.6.5-py2.py3-none-any.whl", hash = "sha256:e78be5b919f5bb184e3e0e2dd1ca986f2362e29a2bc933c446fe89f39dbe4e9c"}, + {file = "alembic-1.6.5.tar.gz", hash = "sha256:a21fedebb3fb8f6bbbba51a11114f08c78709377051384c9c5ead5705ee93a51"}, +] +anyio = [ + {file = "anyio-3.3.0-py3-none-any.whl", hash = "sha256:929a6852074397afe1d989002aa96d457e3e1e5441357c60d03e7eea0e65e1b0"}, + {file = "anyio-3.3.0.tar.gz", hash = "sha256:ae57a67583e5ff8b4af47666ff5651c3732d45fd26c929253748e796af860374"}, +] +asgiref = [ + {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, + {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] +authlib = [ + {file = "Authlib-0.15.2-py2.py3-none-any.whl", hash = "sha256:078b900fa9fbebf9f8dae1d5dc1ca857b6a742493093ef9b0b36ad926f36e41f"}, + {file = "Authlib-0.15.2.tar.gz", hash = "sha256:21b34625c83ca48150684bbeca8f7c884cd281913c72d146dbf0e9d2fbfdec4e"}, +] +bcrypt = [ + {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, + {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, + {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, + {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, +] +bleach = [ + {file = "bleach-3.3.1-py2.py3-none-any.whl", hash = "sha256:ae976d7174bba988c0b632def82fdc94235756edfb14e6558a9c5be555c9fb78"}, + {file = "bleach-3.3.1.tar.gz", hash = "sha256:306483a5a9795474160ad57fce3ddd1b50551e981eed8e15a582d34cef28aafa"}, +] +certifi = [ + {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, + {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, +] +cffi = [ + {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, + {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, + {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, + {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"}, + {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"}, + {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"}, + {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, + {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, + {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, + {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, + {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, + {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, + {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, + {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, + {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, + {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, + {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, + {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, + {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"}, + {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"}, +] +click = [ + {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, + {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +coverage = [ + {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, + {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, + {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, + {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, + {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, + {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, + {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, + {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, + {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, + {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, + {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, + {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, + {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, + {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, + {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, + {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, + {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, + {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, + {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, + {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, + {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, +] +cryptography = [ + {file = "cryptography-3.4.8-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14"}, + {file = "cryptography-3.4.8-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb"}, + {file = "cryptography-3.4.8-cp36-abi3-win32.whl", hash = "sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7"}, + {file = "cryptography-3.4.8-cp36-abi3-win_amd64.whl", hash = "sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e"}, + {file = "cryptography-3.4.8.tar.gz", hash = "sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c"}, +] +dnspython = [ + {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"}, + {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"}, +] +dunamai = [ + {file = "dunamai-1.6.0-py3-none-any.whl", hash = "sha256:44a94a4edebb145bb6198a2f26de957b12b77d43b7c9c0646be814c60cf5d8df"}, + {file = "dunamai-1.6.0.tar.gz", hash = "sha256:6f1111f47e869ed58d44a7d37f112e3e7c761dce3c71f2c5464526928d7e9896"}, +] +email-validator = [ + {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, + {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"}, +] +fakeredis = [ + {file = "fakeredis-1.6.0-py3-none-any.whl", hash = "sha256:3449b306f3a85102b28f8180c24722ef966fcb1e3c744758b6f635ec80321a5c"}, + {file = "fakeredis-1.6.0.tar.gz", hash = "sha256:11ccfc9769d718d37e45b382e64a6ba02586b622afa0371a6bd85766d72255f3"}, +] +fastapi = [ + {file = "fastapi-0.66.0-py3-none-any.whl", hash = "sha256:85d8aee8c3c46171f4cb7bb3651425a42c07cb9183345d100ef55d88ca2ce15f"}, + {file = "fastapi-0.66.0.tar.gz", hash = "sha256:6ea4225448786f3d6fae737713789f87631a7455f65580de0a4a2e50471060d9"}, +] +feedgen = [ + {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, +] +flake8 = [ + {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, + {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, +] +h11 = [ + {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, + {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, +] +h2 = [ + {file = "h2-4.0.0-py3-none-any.whl", hash = "sha256:ac9e293a1990b339d5d71b19c5fe630e3dd4d768c620d1730d355485323f1b25"}, + {file = "h2-4.0.0.tar.gz", hash = "sha256:bb7ac7099dd67a857ed52c815a6192b6b1f5ba6b516237fc24a085341340593d"}, +] +hpack = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] +httpcore = [ + {file = "httpcore-0.13.6-py3-none-any.whl", hash = "sha256:db4c0dcb8323494d01b8c6d812d80091a31e520033e7b0120883d6f52da649ff"}, + {file = "httpcore-0.13.6.tar.gz", hash = "sha256:b0d16f0012ec88d8cc848f5a55f8a03158405f4bca02ee49bc4ca2c1fda49f3e"}, +] +httpx = [ + {file = "httpx-0.18.2-py3-none-any.whl", hash = "sha256:979afafecb7d22a1d10340bafb403cf2cb75aff214426ff206521fc79d26408c"}, + {file = "httpx-0.18.2.tar.gz", hash = "sha256:9f99c15d33642d38bce8405df088c1c4cfd940284b4290cacbfb02e64f4877c6"}, +] +hypercorn = [ + {file = "Hypercorn-0.11.2-py3-none-any.whl", hash = "sha256:8007c10f81566920f8ae12c0e26e146f94ca70506da964b5a727ad610aa1d821"}, + {file = "Hypercorn-0.11.2.tar.gz", hash = "sha256:5ba1e719c521080abd698ff5781a2331e34ef50fc1c89a50960538115a896a9a"}, +] +hyperframe = [ + {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, + {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, +] +idna = [ + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] +isort = [ + {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, + {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, +] +itsdangerous = [ + {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, + {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"}, +] +jinja2 = [ + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, +] +lxml = [ + {file = "lxml-4.6.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2"}, + {file = "lxml-4.6.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1b7584d421d254ab86d4f0b13ec662a9014397678a7c4265a02a6d7c2b18a75f"}, + {file = "lxml-4.6.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d"}, + {file = "lxml-4.6.3-cp27-cp27m-win32.whl", hash = "sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106"}, + {file = "lxml-4.6.3-cp27-cp27m-win_amd64.whl", hash = "sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee"}, + {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f"}, + {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4"}, + {file = "lxml-4.6.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:64812391546a18896adaa86c77c59a4998f33c24788cadc35789e55b727a37f4"}, + {file = "lxml-4.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c1a40c06fd5ba37ad39caa0b3144eb3772e813b5fb5b084198a985431c2f1e8d"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16"}, + {file = "lxml-4.6.3-cp35-cp35m-win32.whl", hash = "sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2"}, + {file = "lxml-4.6.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4"}, + {file = "lxml-4.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d916d31fd85b2f78c76400d625076d9124de3e4bda8b016d25a050cc7d603f24"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617"}, + {file = "lxml-4.6.3-cp36-cp36m-win32.whl", hash = "sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04"}, + {file = "lxml-4.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a"}, + {file = "lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:36108c73739985979bf302006527cf8a20515ce444ba916281d1c43938b8bb96"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92"}, + {file = "lxml-4.6.3-cp37-cp37m-win32.whl", hash = "sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade"}, + {file = "lxml-4.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b"}, + {file = "lxml-4.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:e1cbd3f19a61e27e011e02f9600837b921ac661f0c40560eefb366e4e4fb275e"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1b38116b6e628118dea5b2186ee6820ab138dbb1e24a13e478490c7db2f326ae"}, + {file = "lxml-4.6.3-cp38-cp38-win32.whl", hash = "sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28"}, + {file = "lxml-4.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7"}, + {file = "lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3082c518be8e97324390614dacd041bb1358c882d77108ca1957ba47738d9d59"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a"}, + {file = "lxml-4.6.3-cp39-cp39-win32.whl", hash = "sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f"}, + {file = "lxml-4.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83"}, + {file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"}, +] +mako = [ + {file = "Mako-1.1.5-py2.py3-none-any.whl", hash = "sha256:6804ee66a7f6a6416910463b00d76a7b25194cd27f1918500c5bd7be2a088a23"}, + {file = "Mako-1.1.5.tar.gz", hash = "sha256:169fa52af22a91900d852e937400e79f535496191c63712e3b9fda5a9bed6fc3"}, +] +markdown = [ + {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, + {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, +] +markupsafe = [ + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +mysqlclient = [ + {file = "mysqlclient-2.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3"}, + {file = "mysqlclient-2.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7"}, + {file = "mysqlclient-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5"}, + {file = "mysqlclient-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6"}, + {file = "mysqlclient-2.0.3.tar.gz", hash = "sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432"}, +] +orjson = [ + {file = "orjson-3.6.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:5f78ed46b179585272a5670537f2203dbb7b3e2f8e4db1be72839cc423e2daef"}, + {file = "orjson-3.6.3-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:a99f310960e3acdda72ba1e98df8bf8c9145d90a0f72719786f43f4ea6937846"}, + {file = "orjson-3.6.3-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:8a5e46418f51f03060f91d743b59aed70c8d02a5012428365cfa20b7f670e903"}, + {file = "orjson-3.6.3-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:084de43ca9b19ad58c618c9f1ff93784e0190df2d88a02ae24c3cdebe9f2e9f7"}, + {file = "orjson-3.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b68a601f49c0328bf16498309e56ab87c1d6c2bb0287abf70329eb958d565c62"}, + {file = "orjson-3.6.3-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:9e4a26212851ea8ff81dee7e4e0da7e1e63b5b4f4330a8b4f27e99f1ba3f758b"}, + {file = "orjson-3.6.3-cp37-cp37m-manylinux_2_24_x86_64.whl", hash = "sha256:5eb9d7f2f45e12cbc7500da4176f2d3221a73891b4be505fe79c52cbb800e872"}, + {file = "orjson-3.6.3-cp37-none-win_amd64.whl", hash = "sha256:39aa7d42c9760fba36c37adb1d9c6752696ce9443c5dcb65222dd0994b5735e1"}, + {file = "orjson-3.6.3-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:8d4430e0cc390c1d745aea3827fd0c6fd7aa5f0690de30a2fe25c406aa5efa20"}, + {file = "orjson-3.6.3-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:be79e0ddea7f3a47332ec9573365c0b8a8cce4357e9682050f53c1bc75c1571f"}, + {file = "orjson-3.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fce5ada0f8dd7c9e16c675626a29dfc5cc766e1eb67d8021b1e77d0861e4e850"}, + {file = "orjson-3.6.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:1014a6f514b39dc414fce60568c9e7f635de97a1f1f5972ebc38f88a6160944a"}, + {file = "orjson-3.6.3-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:c3beff02a339f194274ec1fcf03e2c1563e84f297b568eb3d45751722454a52e"}, + {file = "orjson-3.6.3-cp38-none-win_amd64.whl", hash = "sha256:8f105e9290f901a618a0ced87f785fce2fcf6ab753699de081d82ee05c90f038"}, + {file = "orjson-3.6.3-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7936bef5589c9955ebee3423df51709d5f3b37ef54b830239bddb9fa5ead99f4"}, + {file = "orjson-3.6.3-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:82e3afbf404cb91774f894ed7bf52fd83bb1cc6bd72221711f4ce4e7774f0560"}, + {file = "orjson-3.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c702c78c33416fc8a138c5ec36eef5166ecfe8990c8f99c97551cd37c396e4d"}, + {file = "orjson-3.6.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:4606907b9aaec9fea6159ac14f838dbd2851f18b05fb414c4b3143bff9f2bb0d"}, + {file = "orjson-3.6.3-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:4ebb464b8b557a1401a03da6f41761544886db95b52280e60d25549da7427453"}, + {file = "orjson-3.6.3-cp39-none-win_amd64.whl", hash = "sha256:720a7d7ba1dcf32bbd8fb380370b1fdd06ed916caea48403edd64f2ccf7883c1"}, + {file = "orjson-3.6.3.tar.gz", hash = "sha256:353cc079cedfe990ea2d2186306f766e0d47bba63acd072e22d6df96c67be993"}, +] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] +pluggy = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] +poetry-dynamic-versioning = [ + {file = "poetry-dynamic-versioning-0.13.1.tar.gz", hash = "sha256:5c0e7b22560db76812057ef95dadad662ecc63eb270145787eabe73da7c222f9"}, + {file = "poetry_dynamic_versioning-0.13.1-py3-none-any.whl", hash = "sha256:6d79f76436c624653fc06eb9bb54fb4f39b1d54362bc366ad2496855711d3a78"}, +] +priority = [ + {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, + {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, +] +protobuf = [ + {file = "protobuf-3.17.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ab6bb0e270c6c58e7ff4345b3a803cc59dbee19ddf77a4719c5b635f1d547aa8"}, + {file = "protobuf-3.17.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:13ee7be3c2d9a5d2b42a1030976f760f28755fcf5863c55b1460fd205e6cd637"}, + {file = "protobuf-3.17.3-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:1556a1049ccec58c7855a78d27e5c6e70e95103b32de9142bae0576e9200a1b0"}, + {file = "protobuf-3.17.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f0e59430ee953184a703a324b8ec52f571c6c4259d496a19d1cabcdc19dabc62"}, + {file = "protobuf-3.17.3-cp35-cp35m-win32.whl", hash = "sha256:a981222367fb4210a10a929ad5983ae93bd5a050a0824fc35d6371c07b78caf6"}, + {file = "protobuf-3.17.3-cp35-cp35m-win_amd64.whl", hash = "sha256:6d847c59963c03fd7a0cd7c488cadfa10cda4fff34d8bc8cba92935a91b7a037"}, + {file = "protobuf-3.17.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:145ce0af55c4259ca74993ddab3479c78af064002ec8227beb3d944405123c71"}, + {file = "protobuf-3.17.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ce4d8bf0321e7b2d4395e253f8002a1a5ffbcfd7bcc0a6ba46712c07d47d0b4"}, + {file = "protobuf-3.17.3-cp36-cp36m-win32.whl", hash = "sha256:7a4c97961e9e5b03a56f9a6c82742ed55375c4a25f2692b625d4087d02ed31b9"}, + {file = "protobuf-3.17.3-cp36-cp36m-win_amd64.whl", hash = "sha256:a22b3a0dbac6544dacbafd4c5f6a29e389a50e3b193e2c70dae6bbf7930f651d"}, + {file = "protobuf-3.17.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ffea251f5cd3c0b9b43c7a7a912777e0bc86263436a87c2555242a348817221b"}, + {file = "protobuf-3.17.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:9b7a5c1022e0fa0dbde7fd03682d07d14624ad870ae52054849d8960f04bc764"}, + {file = "protobuf-3.17.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8727ee027157516e2c311f218ebf2260a18088ffb2d29473e82add217d196b1c"}, + {file = "protobuf-3.17.3-cp37-cp37m-win32.whl", hash = "sha256:14c1c9377a7ffbeaccd4722ab0aa900091f52b516ad89c4b0c3bb0a4af903ba5"}, + {file = "protobuf-3.17.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c56c050a947186ba51de4f94ab441d7f04fcd44c56df6e922369cc2e1a92d683"}, + {file = "protobuf-3.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87"}, + {file = "protobuf-3.17.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1"}, + {file = "protobuf-3.17.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d"}, + {file = "protobuf-3.17.3-cp38-cp38-win32.whl", hash = "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1"}, + {file = "protobuf-3.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2"}, + {file = "protobuf-3.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde"}, + {file = "protobuf-3.17.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:26010f693b675ff5a1d0e1bdb17689b8b716a18709113288fead438703d45539"}, + {file = "protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47"}, + {file = "protobuf-3.17.3-cp39-cp39-win32.whl", hash = "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554"}, + {file = "protobuf-3.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d"}, + {file = "protobuf-3.17.3-py2.py3-none-any.whl", hash = "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e"}, + {file = "protobuf-3.17.3.tar.gz", hash = "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b"}, +] +py = [ + {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, + {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +] +pycodestyle = [ + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, +] +pycparser = [ + {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, + {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, +] +pydantic = [ + {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, + {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, + {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, + {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, + {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, + {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, + {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, + {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, + {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, + {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, +] +pyflakes = [ + {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, + {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, +] +pygit2 = [ + {file = "pygit2-1.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:547429774c11f5bc9d20a49aa86e4bd13c90a55140504ef05f55cf424470ee34"}, + {file = "pygit2-1.6.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e75865d7b6fc161d93b16f10365eaad353cd546e302a98f2de2097ddea1066b"}, + {file = "pygit2-1.6.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4a64b6090308ffd1c82e2dd4316cb79483715387b13818156d516134a5b17c"}, + {file = "pygit2-1.6.1-cp36-cp36m-win32.whl", hash = "sha256:2666a3970b2ea1222a9f0463b466f98c8d564f29ec84cf0a58d9b0d3865dbaaf"}, + {file = "pygit2-1.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2de12ca2d3b7eb86106223b40b2edc0c61103c71e7962e53092c6ddef71a194"}, + {file = "pygit2-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9c1d96c66fb6e69ec710078a73c19edff420bc1db430caa9e03a825eede3f25c"}, + {file = "pygit2-1.6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:454d42550fa6a6cd0e6a6ad9ab3f3262135fd157f57bad245ce156c36ee93370"}, + {file = "pygit2-1.6.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce0827b77dd2f8a3465bdc181c4e65f27dd12dbd92635c038e58030cc90c2de0"}, + {file = "pygit2-1.6.1-cp37-cp37m-win32.whl", hash = "sha256:b0161a141888d450eb821472fdcdadd14a072ddeda841fee9984956d34d3e19d"}, + {file = "pygit2-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:af2fa259b6f7899227611ab978c600695724e85965836cb607d8b1e70cfea9b3"}, + {file = "pygit2-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0e1e02c28983ddc004c0f54063f3e46fca388225d468e32e16689cfb750e0bd6"}, + {file = "pygit2-1.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5dadc4844feb76cde5cc9a37656326a361dd8b5c8e8f8674dcd4a5ecf395db3"}, + {file = "pygit2-1.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef07458e4172a31318663295083b43f957d611145738ff56aa76db593542a6e8"}, + {file = "pygit2-1.6.1-cp38-cp38-win32.whl", hash = "sha256:7a0c0a1f11fd41f57e8c6c64d903cc7fa4ec95d15592270be3217ed7f78eb023"}, + {file = "pygit2-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:2fd5c1b2d84dc6084f1bda836607afe37e95186a53a5a827a69083415e57fe4f"}, + {file = "pygit2-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b9b88b7e9a5286a71be0b6c307f0523c9606aeedff6b61eb9c440e18817fa641"}, + {file = "pygit2-1.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac12d32b714c3383ebccffee5eb6aff0b69a2542a40a664fd5ad370afcb28ee7"}, + {file = "pygit2-1.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe682ed6afd2ab31127f6a502cf3e002dc1cc8d26c36a5d49dfd180250351eb6"}, + {file = "pygit2-1.6.1-cp39-cp39-win32.whl", hash = "sha256:dbbf66a23860aa899949068ac9b503b4bc21e6063e8f53870440adbdc909405e"}, + {file = "pygit2-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:f90775afb11f69376e2af21ab56fcfbb52f6bc84117059ddf0355f81e5e36352"}, + {file = "pygit2-1.6.1.tar.gz", hash = "sha256:c3303776f774d3e0115c1c4f6e1fc35470d15f113a7ae9401a0b90acfa1661ac"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pytest = [ + {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, + {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, +] +pytest-asyncio = [ + {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"}, + {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"}, +] +pytest-cov = [ + {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, + {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, +] +pytest-tap = [ + {file = "pytest-tap-3.2.tar.gz", hash = "sha256:1b585c4a636458dbd958d136381bbabb1752c5877d05fac7d6a6001a8a9ddc29"}, + {file = "pytest_tap-3.2-py3-none-any.whl", hash = "sha256:18f59047f8bc68247d37f807fae7f2f8897d2c7397aea2fd2870f0421dc566cb"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +python-editor = [ + {file = "python-editor-1.0.4.tar.gz", hash = "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b"}, + {file = "python_editor-1.0.4-py2-none-any.whl", hash = "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8"}, + {file = "python_editor-1.0.4-py2.7.egg", hash = "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522"}, + {file = "python_editor-1.0.4-py3-none-any.whl", hash = "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d"}, + {file = "python_editor-1.0.4-py3.5.egg", hash = "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77"}, +] +python-multipart = [ + {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, +] +redis = [ + {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, + {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, +] +requests = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] +rfc3986 = [ + {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +sniffio = [ + {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, + {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, +] +sortedcontainers = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] +sqlalchemy = [ + {file = "SQLAlchemy-1.3.23-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:fd3b96f8c705af8e938eaa99cbd8fd1450f632d38cad55e7367c33b263bf98ec"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:29cccc9606750fe10c5d0e8bd847f17a97f3850b8682aef1f56f5d5e1a5a64b1"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:927ce09e49bff3104459e1451ce82983b0a3062437a07d883a4c66f0b344c9b5"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-win32.whl", hash = "sha256:b4b0e44d586cd64b65b507fa116a3814a1a53d55dce4836d7c1a6eb2823ff8d1"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-win_amd64.whl", hash = "sha256:6b8b8c80c7f384f06825612dd078e4a31f0185e8f1f6b8c19e188ff246334205"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9e9c25522933e569e8b53ccc644dc993cab87e922fb7e142894653880fdd419d"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a0e306e9bb76fd93b29ae3a5155298e4c1b504c7cbc620c09c20858d32d16234"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:6c9e6cc9237de5660bcddea63f332428bb83c8e2015c26777281f7ffbd2efb84"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:94f667d86be82dd4cb17d08de0c3622e77ca865320e0b95eae6153faa7b4ecaf"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:751934967f5336a3e26fc5993ccad1e4fee982029f9317eb6153bc0bc3d2d2da"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:63677d0c08524af4c5893c18dbe42141de7178001360b3de0b86217502ed3601"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-win32.whl", hash = "sha256:ddfb511e76d016c3a160910642d57f4587dc542ce5ee823b0d415134790eeeb9"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-win_amd64.whl", hash = "sha256:040bdfc1d76a9074717a3f43455685f781c581f94472b010cd6c4754754e1862"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d1a85dfc5dee741bf49cb9b6b6b8d2725a268e4992507cf151cba26b17d97c37"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:639940bbe1108ac667dcffc79925db2966826c270112e9159439ab6bb14f8d80"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e8a1750b44ad6422ace82bf3466638f1aa0862dbb9689690d5f2f48cce3476c8"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e5bb3463df697279e5459a7316ad5a60b04b0107f9392e88674d0ece70e9cf70"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-win32.whl", hash = "sha256:e273367f4076bd7b9a8dc2e771978ef2bfd6b82526e80775a7db52bff8ca01dd"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-win_amd64.whl", hash = "sha256:ac2244e64485c3778f012951fdc869969a736cd61375fde6096d08850d8be729"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:23927c3981d1ec6b4ea71eb99d28424b874d9c696a21e5fbd9fa322718be3708"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d90010304abb4102123d10cbad2cdf2c25a9f2e66a50974199b24b468509bad5"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a8bfc1e1afe523e94974132d7230b82ca7fa2511aedde1f537ec54db0399541a"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:269990b3ab53cb035d662dcde51df0943c1417bdab707dc4a7e4114a710504b4"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-win32.whl", hash = "sha256:fdd2ed7395df8ac2dbb10cefc44737b66c6a5cd7755c92524733d7a443e5b7e2"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-win_amd64.whl", hash = "sha256:6a939a868fdaa4b504e8b9d4a61f21aac11e3fecc8a8214455e144939e3d2aea"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:24f9569e82a009a09ce2d263559acb3466eba2617203170e4a0af91e75b4f075"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2578dbdbe4dbb0e5126fb37ffcd9793a25dcad769a95f171a2161030bea850ff"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1fe5d8d39118c2b018c215c37b73fd6893c3e1d4895be745ca8ff6eb83333ed3"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c7dc052432cd5d060d7437e217dd33c97025287f99a69a50e2dc1478dd610d64"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-win32.whl", hash = "sha256:ecce8c021894a77d89808222b1ff9687ad84db54d18e4bd0500ca766737faaf6"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-win_amd64.whl", hash = "sha256:37b83bf81b4b85dda273aaaed5f35ea20ad80606f672d94d2218afc565fb0173"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8be835aac18ec85351385e17b8665bd4d63083a7160a017bef3d640e8e65cadb"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6ec1044908414013ebfe363450c22f14698803ce97fbb47e53284d55c5165848"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eab063a70cca4a587c28824e18be41d8ecc4457f8f15b2933584c6c6cccd30f0"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:baeb451ee23e264de3f577fee5283c73d9bbaa8cb921d0305c0bbf700094b65b"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-win32.whl", hash = "sha256:94208867f34e60f54a33a37f1c117251be91a47e3bfdb9ab8a7847f20886ad06"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-win_amd64.whl", hash = "sha256:f4d972139d5000105fcda9539a76452039434013570d6059993120dc2a65e447"}, + {file = "SQLAlchemy-1.3.23.tar.gz", hash = "sha256:6fca33672578666f657c131552c4ef8979c1606e494f78cd5199742dfb26918b"}, +] +starlette = [ + {file = "starlette-0.14.2-py3-none-any.whl", hash = "sha256:3c8e48e52736b3161e34c9f0e8153b4f32ec5d8995a3ee1d59410d92f75162ed"}, + {file = "starlette-0.14.2.tar.gz", hash = "sha256:7d49f4a27f8742262ef1470608c59ddbc66baf37c148e938c7038e6bc7a998aa"}, +] +"tap.py" = [ + {file = "tap.py-3.0-py2.py3-none-any.whl", hash = "sha256:a598bfaa2e224d71f2e86147c2ef822c18ff2e1b8ef006397e5056b08f92f699"}, + {file = "tap.py-3.0.tar.gz", hash = "sha256:f5eeeeebfd64e53d32661752bb4c288589a3babbb96db3f391a4ec29f1359c70"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +tomlkit = [ + {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, + {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, +] +typing = [ + {file = "typing-3.7.4.3-py2-none-any.whl", hash = "sha256:283d868f5071ab9ad873e5e52268d611e851c870a2ba354193026f2dfb29d8b5"}, + {file = "typing-3.7.4.3.tar.gz", hash = "sha256:1187fb9c82fd670d10aa07bbb6cfcfe4bdda42d6fab8d5134f04e8c4d0b71cc9"}, +] +typing-extensions = [ + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, +] +urllib3 = [ + {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, + {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, +] +uvicorn = [ + {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, + {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, +] +webencodings = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] +werkzeug = [ + {file = "Werkzeug-2.0.1-py3-none-any.whl", hash = "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"}, + {file = "Werkzeug-2.0.1.tar.gz", hash = "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42"}, +] +wsproto = [ + {file = "wsproto-1.0.0-py3-none-any.whl", hash = "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f"}, + {file = "wsproto-1.0.0.tar.gz", hash = "sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..8cb276ce --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,100 @@ +# Poetry build configuration for the aurweb project. +# +# Dependencies: +# * python >= 3.9 +# * pip +# * poetry +# * poetry-dynamic-versioning +# +[tool.poetry] +name = "aurweb" +version = "5.0.0" # Updated via poetry-dynamic-versioning +license = "GPL-2.0-only" +description = "Source code for the Arch User Repository's website" +homepage = "https://aur.archlinux.org" +repository = "https://gitlab.archlinux.org/archlinux/aurweb" +documentation = "https://gitlab.archlinux.org/archlinux/aurweb/-/blob/master/README.md" +keywords = ["aurweb", "aur", "Arch", "Linux"] +authors = [ + "Lucas Fleischer ", + "Eli Schwartz ", + "Kevin Morris " +] +maintainers = [ + "Eli Schwartz " +] +packages = [ + { include = "aurweb" } +] + +[tool.poetry-dynamic-versioning] +enable = true +vcs = "git" + +[build-system] +requires = ["poetry>=1.1.8", "poetry-dynamic-versioning"] +build-backend = "poetry.masonry.api" + +[tool.poetry.urls] +"Repository" = "https://gitlab.archlinux.org/archlinux/aurweb" +"Bug Tracker" = "https://gitlab.archlinux.org/archlinux/aurweb/-/issues" +"Development Mailing List" = "https://lists.archlinux.org/listinfo/aur-dev" +"General Mailing List" = "https://lists.archlinux.org/listinfo/aur-general" +"Request Mailing List" = "https://lists.archlinux.org/listinfo/aur-requests" + +[tool.poetry.dependencies] +# poetry-dynamic-versioning is used to produce tool.poetry.version +# based on git tags. +poetry-dynamic-versioning = { version = "0.13.1", python = "^3.9" } + +# General +authlib = { version = "0.15.2", python = "^3.9" } +aiofiles = { version = "0.7.0", python = "^3.9" } +asgiref = { version = "3.4.1", python = "^3.9" } +bcrypt = { version = "3.2.0", python = "^3.9" } +bleach = { version = "3.3.1", python = "^3.9" } +email-validator = { version = "1.1.3", python = "^3.9" } +fakeredis = { version = "1.6.0", python = "^3.9" } +fastapi = { version = "0.66.0", python = "^3.9" } +feedgen = { version = "0.9.0", python = "^3.9" } +httpx = { version = "0.18.2", python = "^3.9" } +hypercorn = { version = "0.11.2", python = "^3.9" } +itsdangerous = { version = "2.0.1", python = "^3.9" } +jinja2 = { version = "3.0.1", python = "^3.9" } +lxml = { version = "4.6.3", python = "^3.9" } +markdown = { version = "3.3.4", python = "^3.9" } +orjson = { version = "3.6.3", python = "^3.9" } +protobuf = { version = "3.17.3", python = "^3.9" } +pygit2 = { version = "1.6.1", python = "^3.9" } +python-multipart = { version = "0.0.5", python = "^3.9" } +redis = { version = "3.5.3", python = "^3.9" } +requests = { version = "2.26.0", python = "^3.9" } +werkzeug = { version = "2.0.1", python = "^3.9" } + +# SQL +alembic = { version = "1.6.5", python = "^3.9" } +sqlalchemy = { version = "1.3.23", python = "^3.9" } +mysqlclient = { version = "2.0.3", python = "^3.9" } + +[tool.poetry.dev-dependencies] +flake8 = { version = "3.9.2", python = "^3.9" } +isort = { version = "5.9.3", python = "^3.9" } +coverage = { version = "5.5", python = "^3.9" } +pytest = { version = "6.2.4", python = "^3.9" } +pytest-asyncio = { version = "0.15.1", python = "^3.9" } +pytest-cov = { version = "2.12.1", python = "^3.9" } +pytest-tap = { version = "3.2", python = "^3.9" } +uvicorn = { version = "0.15.0", python = "^3.9" } + +[tool.poetry.scripts] +aurweb-git-auth = "aurweb.git.auth:main" +aurweb-git-serve = "aurweb.git.serve:main" +aurweb-git-update = "aurweb.git.update:main" +aurweb-aurblup = "aurweb.scripts.aurblup:main" +aurweb-mkpkglists = "aurweb.scripts.mkpkglists:main" +aurweb-notify = "aurweb.scripts.notify:main" +aurweb-pkgmaint = "aurweb.scripts.pkgmaint:main" +aurweb-popupdate = "aurweb.scripts.popupdate:main" +aurweb-rendercomment = "aurweb.scripts.rendercomment:main" +aurweb-tuvotereminder = "aurweb.scripts.tuvotereminder:main" +aurweb-usermaint = "aurweb.scripts.usermaint:main" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 37a12f61..00000000 --- a/requirements.txt +++ /dev/null @@ -1,36 +0,0 @@ -# General -authlib==0.15.2 -aiofiles==0.7.0 -asgiref==3.4.1 -bcrypt==3.2.0 -bleach==3.3.1 -coverage==5.5 -email-validator==1.1.3 -fakeredis==1.6.0 -fastapi==0.66.0 -feedgen==0.9.0 -flake8==3.9.2 -httpx==0.18.2 -hypercorn==0.11.2 -isort==5.9.3 -itsdangerous==2.0.1 -jinja2==3.0.1 -lxml==4.6.3 -markdown==3.3.4 -orjson==3.6.3 -protobuf==3.17.3 -pygit2==1.6.1 -pytest==6.2.4 -pytest-asyncio==0.15.1 -pytest-cov==2.12.1 -pytest-tap==3.2 -python-multipart==0.0.5 -redis==3.5.3 -requests==2.26.0 -uvicorn==0.15.0 -werkzeug==2.0.1 - -# SQL -alembic==1.6.5 -sqlalchemy==1.3.23 -mysqlclient==2.0.3 diff --git a/setup.py b/setup.py deleted file mode 100644 index cf88488c..00000000 --- a/setup.py +++ /dev/null @@ -1,36 +0,0 @@ -import re -import sys - -from setuptools import find_packages, setup - -version = None -with open('web/lib/version.inc.php', 'r') as f: - for line in f.readlines(): - match = re.match(r'^define\("AURWEB_VERSION", "v([0-9.]+)"\);$', line) - if match: - version = match.group(1) - -if not version: - sys.stderr.write('error: Failed to parse version file!') - sys.exit(1) - -setup( - name="aurweb", - version=version, - packages=find_packages(), - entry_points={ - 'console_scripts': [ - 'aurweb-git-auth = aurweb.git.auth:main', - 'aurweb-git-serve = aurweb.git.serve:main', - 'aurweb-git-update = aurweb.git.update:main', - 'aurweb-aurblup = aurweb.scripts.aurblup:main', - 'aurweb-mkpkglists = aurweb.scripts.mkpkglists:main', - 'aurweb-notify = aurweb.scripts.notify:main', - 'aurweb-pkgmaint = aurweb.scripts.pkgmaint:main', - 'aurweb-popupdate = aurweb.scripts.popupdate:main', - 'aurweb-rendercomment = aurweb.scripts.rendercomment:main', - 'aurweb-tuvotereminder = aurweb.scripts.tuvotereminder:main', - 'aurweb-usermaint = aurweb.scripts.usermaint:main', - ], - }, -) From 3f034ac1287ec7533589807e23240d0d136aaeca Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Sep 2021 18:59:24 -0700 Subject: [PATCH 0858/1891] Docker: Fix incorrect ENV PATH specification As root, seems that $HOME doesn't work like I expected it to. Tested this before, but I apparently had some cache still holding on. Fixing the issue in this commit here. Signed-off-by: Kevin Morris --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 76da62f7..b490d2fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM archlinux:base-devel -ENV PATH="$HOME/.poetry/bin:${PATH}" +ENV PATH="/root/.poetry/bin:${PATH}" ENV PYTHONPATH=/aurweb ENV AUR_CONFIG=conf/config From fa07f940514fd30886acf3d47c3a37d79940adfa Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Sep 2021 19:08:10 -0700 Subject: [PATCH 0859/1891] Docker: Fix FastAPI db initialization PHP was doing this correctly, but FastAPI was doing this in it's exec script @ docker/scripts/run-fastapi.sh. Modify the fastapi service so that it does the same thing as PHP, and the existing "fastapi restart quirk" is no more. Signed-off-by: Kevin Morris --- docker/fastapi-entrypoint.sh | 3 +++ docker/scripts/run-fastapi.sh | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index 41a88206..83a2cda8 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -14,4 +14,7 @@ sed -ri 's|^(redis_address) = .+|\1 = redis://redis|' conf/config sed -ri "s|^(git_clone_uri_anon) = .+|\1 = https://localhost:8444/%s.git|" conf/config.defaults sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ssh://aur@localhost:2222/%s.git|" conf/config.defaults +# Initialize the new database; ignore errors. +python -m aurweb.initdb 2>/dev/null || /bin/true + exec "$@" diff --git a/docker/scripts/run-fastapi.sh b/docker/scripts/run-fastapi.sh index 1db4c505..bb1a01a7 100755 --- a/docker/scripts/run-fastapi.sh +++ b/docker/scripts/run-fastapi.sh @@ -1,8 +1,5 @@ #!/bin/bash -# Initialize the new database; ignore errors. -python -m aurweb.initdb 2>/dev/null || /bin/true - if [ "$1" == "uvicorn" ] || [ "$1" == "" ]; then exec uvicorn --reload \ --ssl-certfile /cache/localhost.cert.pem \ From e93b0a9b452da9db9b28b1c734fb323e367c991d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 5 Sep 2021 00:08:47 -0700 Subject: [PATCH 0860/1891] Docker: expose fastapi (18000) and php-fpm (19000) Signed-off-by: Kevin Morris --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 0e91d6eb..e4eccb12 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -166,6 +166,8 @@ services: - ./web/template:/aurweb/web/template - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates + ports: + - "19000:9000" fastapi: image: aurweb:latest @@ -197,6 +199,8 @@ services: - ./web/template:/aurweb/web/template - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates + ports: + - "18000:8000" nginx: image: aurweb:latest From 95357687f9e0a6c9519e7dc2475059a3506abcd3 Mon Sep 17 00:00:00 2001 From: Hunter Wittenborn Date: Sun, 5 Sep 2021 16:13:45 -0500 Subject: [PATCH 0861/1891] Added ability to specify fortune file via an environment variable --- schema/gendummydata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 9224b051..275b3601 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -41,7 +41,7 @@ CLOSE_PROPOSALS = int(os.environ.get("CLOSE_PROPOSALS", 50)) RANDOM_TLDS = ("edu", "com", "org", "net", "tw", "ru", "pl", "de", "es") RANDOM_URL = ("http://www.", "ftp://ftp.", "http://", "ftp://") RANDOM_LOCS = ("pub", "release", "files", "downloads", "src") -FORTUNE_FILE = "/usr/share/fortune/cookie" +FORTUNE_FILE = os.environ.get("FORTUNE_FILE", "/usr/share/fortune/cookie") # setup logging logformat = "%(levelname)s: %(message)s" From 2e3f69ab126e6ac6ffa92b4e149faab61bfa3374 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 8 Sep 2021 17:10:14 -0700 Subject: [PATCH 0862/1891] fix(docker): Fix git service's update hook The update hook was incorrectly linked to /usr/local/bin/aurweb-git-update, which was neglected during the original patch regarding dependency conversion to `poetry`. Signed-off-by: Kevin Morris --- docker/git-entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index cfd159c9..f07a5577 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -78,7 +78,7 @@ if [ ! -f $GIT_REPO/config ]; then git config --local transfer.hideRefs '^refs/' git config --local --add transfer.hideRefs '!refs/' git config --local --add transfer.hideRefs '!HEAD' - ln -sf /usr/local/bin/aurweb-git-update hooks/update + ln -sf /usr/bin/aurweb-git-update hooks/update cd $curdir chown -R aur:aur $GIT_REPO fi From 0fd31b8d368a4e4a267b5e83d608bc088bb13b4d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 8 Sep 2021 17:14:55 -0700 Subject: [PATCH 0863/1891] refactor(docker): New mariadb_init service Provides a single source of truth for mariadb database initialization. Previously, php-fpm and fastapi were racing against each other; while this wasn't an issue, it was very messy. Signed-off-by: Kevin Morris --- docker-compose.yml | 45 +++++++++++++------------------ docker/fastapi-entrypoint.sh | 19 ++++++++----- docker/mariadb-entrypoint.sh | 2 -- docker/mariadb-init-entrypoint.sh | 20 ++++++++++++++ docker/php-entrypoint.sh | 18 +++++++++---- 5 files changed, 64 insertions(+), 40 deletions(-) create mode 100755 docker/mariadb-init-entrypoint.sh diff --git a/docker-compose.yml b/docker-compose.yml index e4eccb12..309e95fe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,8 +49,6 @@ services: mariadb: image: aurweb:latest init: true - environment: - - DB_HOST="%" entrypoint: /docker/mariadb-entrypoint.sh command: /usr/bin/mysqld_safe --datadir=/var/lib/mysql ports: @@ -63,11 +61,23 @@ services: healthcheck: test: "bash /docker/health/mariadb.sh" + mariadb_init: + image: aurweb:latest + init: true + environment: + - DB_HOST=mariadb + entrypoint: /docker/mariadb-init-entrypoint.sh + command: echo "MariaDB tables initialized." + depends_on: + mariadb: + condition: service_healthy + git: image: aurweb:latest init: true environment: - AUR_CONFIG=/aurweb/conf/config + - DB_HOST=mariadb entrypoint: /docker/git-entrypoint.sh command: /docker/scripts/run-sshd.sh ports: @@ -75,11 +85,9 @@ services: healthcheck: test: "bash /docker/health/sshd.sh" depends_on: - mariadb: - condition: service_healthy + mariadb_init: + condition: service_started volumes: - - mariadb_run:/var/run/mysqld - - mariadb_data:/var/lib/mysql - git_data:/aurweb/aur.git - ./cache:/cache @@ -96,8 +104,6 @@ services: mariadb: condition: service_healthy volumes: - - mariadb_run:/var/run/mysqld - - mariadb_data:/var/lib/mysql - git_data:/aurweb/aur.git - ./cache:/cache - smartgit_run:/var/run/smartgit @@ -114,8 +120,6 @@ services: depends_on: git: condition: service_healthy - php-fpm: - condition: service_healthy volumes: - git_data:/aurweb/aur.git @@ -131,8 +135,6 @@ services: depends_on: git: condition: service_healthy - fastapi: - condition: service_healthy volumes: - git_data:/aurweb/aur.git @@ -151,13 +153,9 @@ services: condition: service_started git: condition: service_healthy - mariadb: - condition: service_healthy memcached: condition: service_healthy volumes: - - mariadb_run:/var/run/mysqld # Bind socket in this volume. - - mariadb_data:/var/lib/mysql - ./cache:/cache - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations @@ -186,11 +184,7 @@ services: condition: service_healthy redis: condition: service_healthy - mariadb: - condition: service_healthy volumes: - - mariadb_run:/var/run/mysqld # Bind socket in this volume. - - mariadb_data:/var/lib/mysql - ./cache:/cache - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations @@ -268,10 +262,9 @@ services: stdin_open: true tty: true depends_on: - mariadb: - condition: service_healthy + mariadb_init: + condition: service_started volumes: - - mariadb_run:/var/run/mysqld - git_data:/aurweb/aur.git - ./cache:/cache - ./aurweb:/aurweb/aurweb @@ -292,7 +285,6 @@ services: stdin_open: true tty: true volumes: - - mariadb_run:/var/run/mysqld - git_data:/aurweb/aur.git - ./cache:/cache - ./aurweb:/aurweb/aurweb @@ -314,10 +306,9 @@ services: stdin_open: true tty: true depends_on: - mariadb: - condition: service_healthy + mariadb_init: + condition: service_started volumes: - - mariadb_run:/var/run/mysqld - git_data:/aurweb/aur.git - ./cache:/cache - ./aurweb:/aurweb/aurweb diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index 83a2cda8..3829b0bf 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -1,11 +1,21 @@ #!/bin/bash set -eou pipefail -dir="$(dirname $0)" -bash $dir/test-mysql-entrypoint.sh +[[ -z "$DB_HOST" ]] && echo 'Error: $DB_HOST required but missing.' && exit 1 + +DB_NAME="aurweb" +DB_USER="aur" +DB_PASS="aur" + +# Setup a config for our mysql db. +cp -vf conf/config.dev conf/config +sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config +sed -ri "s/^(name) = .+/\1 = ${DB_NAME}/" conf/config +sed -ri "s/^(host) = .+/\1 = ${DB_HOST}/" conf/config +sed -ri "s/^(user) = .+/\1 = ${DB_USER}/" conf/config +sed -ri "s/^;?(password) = .+/\1 = ${DB_PASS}/" conf/config sed -ri "s;^(aur_location) = .+;\1 = https://localhost:8444;" conf/config -sed -ri 's/^(name) = .+/\1 = aurweb/' conf/config # Setup Redis for FastAPI. sed -ri 's/^(cache) = .+/\1 = redis/' conf/config @@ -14,7 +24,4 @@ sed -ri 's|^(redis_address) = .+|\1 = redis://redis|' conf/config sed -ri "s|^(git_clone_uri_anon) = .+|\1 = https://localhost:8444/%s.git|" conf/config.defaults sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ssh://aur@localhost:2222/%s.git|" conf/config.defaults -# Initialize the new database; ignore errors. -python -m aurweb.initdb 2>/dev/null || /bin/true - exec "$@" diff --git a/docker/mariadb-entrypoint.sh b/docker/mariadb-entrypoint.sh index 945a4b82..e1ebfa6a 100755 --- a/docker/mariadb-entrypoint.sh +++ b/docker/mariadb-entrypoint.sh @@ -3,8 +3,6 @@ set -eou pipefail MYSQL_DATA=/var/lib/mysql -[[ -z "$DB_HOST" ]] && DB_HOST="localhost" - mariadb-install-db --user=mysql --basedir=/usr --datadir=$MYSQL_DATA # Start it up. diff --git a/docker/mariadb-init-entrypoint.sh b/docker/mariadb-init-entrypoint.sh new file mode 100755 index 00000000..4cd6f46c --- /dev/null +++ b/docker/mariadb-init-entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -eou pipefail + +[[ -z "$DB_HOST" ]] && echo 'Error: $DB_HOST required but missing.' && exit 1 + +DB_NAME="aurweb" +DB_USER="aur" +DB_PASS="aur" + +# Setup a config for our mysql db. +cp -vf conf/config.dev conf/config +sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config +sed -ri "s/^(name) = .+/\1 = ${DB_NAME}/" conf/config +sed -ri "s/^(host) = .+/\1 = ${DB_HOST}/" conf/config +sed -ri "s/^(user) = .+/\1 = ${DB_USER}/" conf/config +sed -ri "s/^;?(password) = .+/\1 = ${DB_PASS}/" conf/config + +python -m aurweb.initdb 2>/dev/null || /bin/true + +exec "$@" diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index 1f3ed82b..8fda1830 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -1,11 +1,21 @@ #!/bin/bash set -eou pipefail -dir="$(dirname $0)" -bash $dir/test-mysql-entrypoint.sh +[[ -z "$DB_HOST" ]] && echo 'Error: $DB_HOST required but missing.' && exit 1 + +DB_NAME="aurweb" +DB_USER="aur" +DB_PASS="aur" + +# Setup a config for our mysql db. +cp -vf conf/config.dev conf/config +sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config +sed -ri "s/^(name) = .+/\1 = ${DB_NAME}/" conf/config +sed -ri "s/^(host) = .+/\1 = ${DB_HOST}/" conf/config +sed -ri "s/^(user) = .+/\1 = ${DB_USER}/" conf/config +sed -ri "s/^;?(password) = .+/\1 = ${DB_PASS}/" conf/config sed -ri "s;^(aur_location) = .+;\1 = https://localhost:8443;" conf/config -sed -ri 's/^(name) = .+/\1 = aurweb/' conf/config # Enable memcached. sed -ri 's/^(cache) = .+$/\1 = memcache/' conf/config @@ -27,6 +37,4 @@ sed -ri 's/^;?(open_basedir).*$/\1 = \//' /etc/php/php.ini # Use the sqlite3 extension line for memcached. sed -ri 's/^;(extension)=sqlite3$/\1=memcached/' /etc/php/php.ini -python -m aurweb.initdb 2>/dev/null || /bin/true - exec "$@" From ad3016ef4f98a3131af2680d8d7a80cf0ce6ac74 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 8 Sep 2021 17:36:37 -0700 Subject: [PATCH 0864/1891] fix: /account/{name}/edit Account Type selection The "Account Type" selection was not properly being rendered due to an incorrect equality. This has been fixed in templates/partials/account_form.html. Signed-off-by: Kevin Morris --- templates/partials/account_form.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 6374fd5e..f166c230 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -59,7 +59,7 @@ {% if request.user.is_authenticated() %} diff --git a/test/test_packages_util.py b/test/test_packages_util.py index 754e3b8d..1396734b 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -1,3 +1,5 @@ +from datetime import datetime + import pytest from fastapi.testclient import TestClient @@ -7,6 +9,8 @@ from aurweb.models.account_type import USER_ID, AccountType from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_notification import PackageNotification +from aurweb.models.package_vote import PackageVote from aurweb.models.user import User from aurweb.packages import util from aurweb.redis import kill_redis @@ -19,6 +23,8 @@ def setup(): User.__tablename__, Package.__tablename__, PackageBase.__tablename__, + PackageVote.__tablename__, + PackageNotification.__tablename__, OfficialProvider.__tablename__ ) @@ -71,3 +77,24 @@ def test_updated_packages(maintainer: User, package: Package): assert util.updated_packages(1, 0) == [expected] assert util.updated_packages(1, 600) == [expected] kill_redis() # Kill it again, in case other tests use a real instance. + + +def test_query_voted(maintainer: User, package: Package): + now = int(datetime.utcnow().timestamp()) + with db.begin(): + db.create(PackageVote, User=maintainer, VoteTS=now, + PackageBase=package.PackageBase) + + query = db.query(Package).filter(Package.ID == package.ID).all() + query_voted = util.query_voted(query, maintainer) + assert query_voted[package.PackageBase.ID] + + +def test_query_notified(maintainer: User, package: Package): + with db.begin(): + db.create(PackageNotification, User=maintainer, + PackageBase=package.PackageBase) + + query = db.query(Package).filter(Package.ID == package.ID).all() + query_notified = util.query_notified(query, maintainer) + assert query_notified[package.PackageBase.ID] From aee1390e2c0aab59b2008d575c5f1750ca664733 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 19 Sep 2021 11:48:19 -0700 Subject: [PATCH 0877/1891] fix(FastAPI): registration sends WelcomeNotification Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index ef4b99af..3c799938 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -22,7 +22,7 @@ from aurweb.models.ban import Ban from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.term import Term from aurweb.models.user import User -from aurweb.scripts.notify import ResetKeyNotification +from aurweb.scripts.notify import ResetKeyNotification, WelcomeNotification from aurweb.templates import make_context, make_variable_context, render_template router = APIRouter() @@ -414,7 +414,7 @@ async def account_register_post(request: Request, # Send a reset key notification to the new user. executor = db.ConnectionExecutor(db.get_engine().raw_connection()) - ResetKeyNotification(executor, user.ID).send() + WelcomeNotification(executor, user.ID).send() context["complete"] = True context["user"] = user From b59601a8b7af137c0f31cd92dbff10f52afe82f6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Sep 2021 19:14:47 -0700 Subject: [PATCH 0878/1891] feat(poetry): add paginate==0.5.6 With upstream at https://github.com/Pylons/paginate, this module helps us deal with pagination without reinventing the wheel. Signed-off-by: Kevin Morris --- poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 3cc84361..322e250f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -513,6 +513,14 @@ python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2" +[[package]] +name = "paginate" +version = "0.5.6" +description = "Divides large result sets into pages for easier browsing" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "pluggy" version = "0.13.1" @@ -921,7 +929,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = "*" -content-hash = "96112731ca21a6ff5d0657c6c40979642bb992ae660ba8d6135421718737c6b0" +content-hash = "c262ac1160b83593377fb7520d35c4b8ad81e5acff9d0a2060b2b048e3865b78" [metadata.files] aiofiles = [ @@ -1328,6 +1336,9 @@ packaging = [ {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, ] +paginate = [ + {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, +] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, diff --git a/pyproject.toml b/pyproject.toml index 8cb276ce..4b530493 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ python-multipart = { version = "0.0.5", python = "^3.9" } redis = { version = "3.5.3", python = "^3.9" } requests = { version = "2.26.0", python = "^3.9" } werkzeug = { version = "2.0.1", python = "^3.9" } +paginate = { version = "0.5.6", python = "^3.9" } # SQL alembic = { version = "1.6.5", python = "^3.9" } From c006386079b3f1dff893ba359eb978132800627c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 28 Aug 2021 16:14:07 -0700 Subject: [PATCH 0879/1891] add User.is_elevated() This one returns true if the user is either a Trusted User or a Developer. Signed-off-by: Kevin Morris --- aurweb/models/user.py | 9 +++++++++ test/test_user.py | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 70d15f88..28aa613e 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -165,6 +165,15 @@ class User(Base): aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID } + def is_elevated(self): + """ A User is 'elevated' when they have either a + Trusted User or Developer AccountType. """ + return self.AccountType.ID in { + aurweb.models.account_type.TRUSTED_USER_ID, + aurweb.models.account_type.DEVELOPER_ID, + aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID, + } + def can_edit_user(self, user): """ Can this account record edit the target user? It must either be the target user or a user with enough permissions to do so. diff --git a/test/test_user.py b/test/test_user.py index 70eac079..43cbf58a 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -214,6 +214,11 @@ def test_user_credential_types(): assert aurweb.auth.developer(user) assert aurweb.auth.trusted_user_or_dev(user) + # Some model authorization checks. + assert user.is_elevated() + assert user.is_trusted_user() + assert user.is_developer() + def test_user_json(): data = json.loads(user.json()) From 741cbfaa4e4d08dc02544140faf7bd1470ca7692 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 28 Aug 2021 16:15:48 -0700 Subject: [PATCH 0880/1891] auth: add several AnonymousUser method stubs We'll need to use these, so this commit implements them here with tests for coverage. Signed-off-by: Kevin Morris --- aurweb/auth.py | 20 ++++++++++++++++++++ test/test_auth.py | 27 ++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 26e4073d..2e6674b0 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -53,10 +53,30 @@ class AnonymousUser: def is_authenticated(): return False + @staticmethod + def is_trusted_user(): + return False + + @staticmethod + def is_developer(): + return False + + @staticmethod + def is_elevated(): + return False + @staticmethod def has_credential(credential): return False + @staticmethod + def voted_for(package): + return False + + @staticmethod + def notified(package): + return False + class BasicAuthBackend(AuthenticationBackend): async def authenticate(self, conn: HTTPConnection): diff --git a/test/test_auth.py b/test/test_auth.py index caa39468..ced64064 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -5,7 +5,7 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.auth import BasicAuthBackend, account_type_required, has_credential +from aurweb.auth import AnonymousUser, BasicAuthBackend, account_type_required, has_credential from aurweb.db import create, query from aurweb.models.account_type import USER, USER_ID, AccountType from aurweb.models.session import Session @@ -92,3 +92,28 @@ def test_account_type_required(): # But this one should! We have no "FAKE" key. with pytest.raises(KeyError): account_type_required({'FAKE'}) + + +def test_is_trusted_user(): + user_ = AnonymousUser() + assert not user_.is_trusted_user() + + +def test_is_developer(): + user_ = AnonymousUser() + assert not user_.is_developer() + + +def test_is_elevated(): + user_ = AnonymousUser() + assert not user_.is_elevated() + + +def test_voted_for(): + user_ = AnonymousUser() + assert not user_.voted_for(None) + + +def test_notified(): + user_ = AnonymousUser() + assert not user_.notified(None) From 6298b1228a7313de4375a567d79a7ab046bc2a26 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 15 Sep 2021 11:31:55 -0700 Subject: [PATCH 0881/1891] feat(FastAPI): add templates/partials/widgets/pager.html A pager that can be used for paginated result tables. Signed-off-by: Kevin Morris --- aurweb/filters.py | 50 +++++++++++++++++++++++++++ templates/partials/widgets/pager.html | 26 ++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 aurweb/filters.py create mode 100644 templates/partials/widgets/pager.html diff --git a/aurweb/filters.py b/aurweb/filters.py new file mode 100644 index 00000000..bb56c656 --- /dev/null +++ b/aurweb/filters.py @@ -0,0 +1,50 @@ +from typing import Any, Dict + +import paginate + +from jinja2 import pass_context + +from aurweb import util +from aurweb.templates import register_filter + + +@register_filter("pager_nav") +@pass_context +def pager_nav(context: Dict[str, Any], + page: int, total: int, prefix: str) -> str: + page = int(page) # Make sure this is an int. + + pp = context.get("PP", 50) + + # Setup a local query string dict, optionally passed by caller. + q = context.get("q", dict()) + + search_by = context.get("SeB", None) + if search_by: + q["SeB"] = search_by + + sort_by = context.get("SB", None) + if sort_by: + q["SB"] = sort_by + + def create_url(page: int): + nonlocal q + offset = max(page * pp - pp, 0) + qs = util.to_qs(util.extend_query(q, ["O", offset])) + return f"{prefix}?{qs}" + + # Use the paginate module to produce our linkage. + pager = paginate.Page([], page=page + 1, + items_per_page=pp, + item_count=total, + url_maker=create_url) + + return pager.pager( + link_attr={"class": "page"}, + curpage_attr={"class": "page"}, + separator=" ", + format="$link_first $link_previous ~5~ $link_next $link_last", + symbol_first="« First", + symbol_previous="‹ Previous", + symbol_next="Next ›", + symbol_last="Last »") diff --git a/templates/partials/widgets/pager.html b/templates/partials/widgets/pager.html new file mode 100644 index 00000000..4809accf --- /dev/null +++ b/templates/partials/widgets/pager.html @@ -0,0 +1,26 @@ +{# A pager widget that can be used for navigation of a number of results. + +Inputs required: + + prefix: Request URI prefix used to produce navigation offsets + singular: Singular sentence to be translated via tn + plural: Plural sentence to be translated via tn + PP: The number of results per page + O: The current offset value + total: The total number of results +#} + +{% set page = ((O / PP) | int) %} +{% set pages = ((total / PP) | ceil) %} + +
    +

    + {{ total | tn(singular, plural) | format(total) }} + {{ "Page %d of %d." | tr | format(page + 1, pages) }} +

    + {% if pages > 1 %} +

    + {{ page | pager_nav(total, prefix) | safe }} +

    + {% endif %} +

    From 5cf70620921848050ed3ac92dff7f84df1dbf979 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 29 Aug 2021 22:21:39 -0700 Subject: [PATCH 0882/1891] feat(FastAPI): add /packages (get) search In terms of performance, most queries on this page win over PHP in query times, with the exception of sorting by Voted or Notify (https://gitlab.archlinux.org/archlinux/aurweb/-/issues/102). Otherwise, there are a few modifications: described below. * Pagination * The `paginate` Python module has been used in the FastAPI project here to implement paging on the packages search page. This changes how pagination is displayed, however it serves the same purpose. We'll take advantage of this module in other places as well. * Form action * The form action for actions now use `POST /packages` to perform. This is currently implemented and will be addressed in a follow-up commit. * Input names and values * Input names and values have been modified to satisfy the snake_case naming convention we'd like to use as much as possible. * Some input names and values were modified to comply with FastAPI Forms: (IDs[]) -> (IDs, ). Signed-off-by: Kevin Morris --- aurweb/packages/search.py | 195 +++++++ aurweb/routers/packages.py | 83 ++- aurweb/templates.py | 2 + conf/config.defaults | 1 + setup.cfg | 2 + templates/packages.html | 84 +++ templates/partials/packages/search.html | 58 +- .../partials/packages/search_actions.html | 25 + .../partials/packages/search_results.html | 114 ++++ test/test_packages_routes.py | 540 +++++++++++++++++- web/html/css/aurweb.css | 7 + 11 files changed, 1081 insertions(+), 30 deletions(-) create mode 100644 aurweb/packages/search.py create mode 100644 templates/packages.html create mode 100644 templates/partials/packages/search_actions.html create mode 100644 templates/partials/packages/search_results.html diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py new file mode 100644 index 00000000..854834ee --- /dev/null +++ b/aurweb/packages/search.py @@ -0,0 +1,195 @@ +from sqlalchemy import and_, case, or_, orm + +from aurweb import config, db +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_comaintainer import PackageComaintainer +from aurweb.models.package_keyword import PackageKeyword +from aurweb.models.package_notification import PackageNotification +from aurweb.models.package_vote import PackageVote +from aurweb.models.user import User + +DEFAULT_MAX_RESULTS = 2500 + + +class PackageSearch: + """ A Package search query builder. """ + + # A constant mapping of short to full name sort orderings. + FULL_SORT_ORDER = {"d": "desc", "a": "asc"} + + def __init__(self, user: User): + """ Construct an instance of PackageSearch. + + This constructors performs several steps during initialization: + 1. Setup self.query: an ORM query of Package joined by PackageBase. + """ + self.user = user + self.query = db.query(Package).join(PackageBase).join( + PackageVote, + and_(PackageVote.PackageBaseID == PackageBase.ID, + PackageVote.UsersID == self.user.ID), + isouter=True + ).join( + PackageNotification, + and_(PackageNotification.PackageBaseID == PackageBase.ID, + PackageNotification.UserID == self.user.ID), + isouter=True + ) + self.ordering = "d" + + # Setup SeB (Search By) callbacks. + self.search_by_cb = { + "nd": self._search_by_namedesc, + "n": self._search_by_name, + "b": self._search_by_pkgbase, + "N": self._search_by_exact_name, + "B": self._search_by_exact_pkgbase, + "k": self._search_by_keywords, + "m": self._search_by_maintainer, + "c": self._search_by_comaintainer, + "M": self._search_by_co_or_maintainer, + "s": self._search_by_submitter + } + + # Setup SB (Sort By) callbacks. + self.sort_by_cb = { + "n": self._sort_by_name, + "v": self._sort_by_votes, + "p": self._sort_by_popularity, + "w": self._sort_by_voted, + "o": self._sort_by_notify, + "m": self._sort_by_maintainer, + "l": self._sort_by_last_modified + } + + def _search_by_namedesc(self, keywords: str) -> orm.Query: + self.query = self.query.filter( + or_(Package.Name.like(f"%{keywords}%"), + Package.Description.like(f"%{keywords}%")) + ) + return self + + def _search_by_name(self, keywords: str) -> orm.Query: + self.query = self.query.filter(Package.Name.like(f"%{keywords}%")) + return self + + def _search_by_exact_name(self, keywords: str) -> orm.Query: + self.query = self.query.filter(Package.Name == keywords) + return self + + def _search_by_pkgbase(self, keywords: str) -> orm.Query: + self.query = self.query.filter(PackageBase.Name.like(f"%{keywords}%")) + return self + + def _search_by_exact_pkgbase(self, keywords: str) -> orm.Query: + self.query = self.query.filter(PackageBase.Name == keywords) + return self + + def _search_by_keywords(self, keywords: str) -> orm.Query: + self.query = self.query.join(PackageKeyword).filter( + PackageKeyword.Keyword == keywords + ) + return self + + def _search_by_maintainer(self, keywords: str) -> orm.Query: + self.query = self.query.join( + User, User.ID == PackageBase.MaintainerUID + ).filter(User.Username == keywords) + return self + + def _search_by_comaintainer(self, keywords: str) -> orm.Query: + self.query = self.query.join(PackageComaintainer).join( + User, User.ID == PackageComaintainer.UsersID + ).filter(User.Username == keywords) + return self + + def _search_by_co_or_maintainer(self, keywords: str) -> orm.Query: + self.query = self.query.join( + PackageComaintainer, + isouter=True + ).join( + User, or_(User.ID == PackageBase.MaintainerUID, + User.ID == PackageComaintainer.UsersID) + ).filter(User.Username == keywords) + return self + + def _search_by_submitter(self, keywords: str) -> orm.Query: + self.query = self.query.join( + User, User.ID == PackageBase.SubmitterUID + ).filter(User.Username == keywords) + return self + + def search_by(self, search_by: str, keywords: str) -> orm.Query: + if search_by not in self.search_by_cb: + search_by = "nd" # Default: Name, Description + callback = self.search_by_cb.get(search_by) + result = callback(keywords) + return result + + def _sort_by_name(self, order: str): + column = getattr(Package.Name, order) + self.query = self.query.order_by(column()) + return self + + def _sort_by_votes(self, order: str): + column = getattr(PackageBase.NumVotes, order) + self.query = self.query.order_by(column()) + return self + + def _sort_by_popularity(self, order: str): + column = getattr(PackageBase.Popularity, order) + self.query = self.query.order_by(column()) + return self + + def _sort_by_voted(self, order: str): + # FIXME: Currently, PHP is destroying this implementation + # in terms of performance. We should improve this; there's no + # reason it should take _longer_. + column = getattr( + case([(PackageVote.UsersID == self.user.ID, 1)], else_=0), + order + ) + self.query = self.query.order_by(column(), Package.Name.desc()) + return self + + def _sort_by_notify(self, order: str): + # FIXME: Currently, PHP is destroying this implementation + # in terms of performance. We should improve this; there's no + # reason it should take _longer_. + column = getattr( + case([(PackageNotification.UserID == self.user.ID, 1)], else_=0), + order + ) + self.query = self.query.order_by(column(), Package.Name.desc()) + return self + + def _sort_by_maintainer(self, order: str): + column = getattr(User.Username, order) + self.query = self.query.join( + User, User.ID == PackageBase.MaintainerUID, isouter=True + ).order_by(column()) + return self + + def _sort_by_last_modified(self, order: str): + column = getattr(PackageBase.ModifiedTS, order) + self.query = self.query.order_by(column()) + return self + + def sort_by(self, sort_by: str, ordering: str = "d") -> orm.Query: + if sort_by not in self.sort_by_cb: + sort_by = "n" # Default: Name. + callback = self.sort_by_cb.get(sort_by) + if ordering not in self.FULL_SORT_ORDER: + ordering = "d" # Default: Descending. + ordering = self.FULL_SORT_ORDER.get(ordering) + return callback(ordering) + + def results(self) -> orm.Query: + # Store the total count of all records found up to limit. + limit = (config.getint("options", "max_search_results") + or DEFAULT_MAX_RESULTS) + self.total_count = self.query.limit(limit).count() + + # Return the query to the user. + return self.query diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index a20c97b1..3eda2539 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -5,6 +5,7 @@ from fastapi import APIRouter, Request, Response from fastapi.responses import RedirectResponse from sqlalchemy import and_ +import aurweb.filters import aurweb.models.package_comment import aurweb.models.package_keyword import aurweb.packages.util @@ -21,12 +22,92 @@ from aurweb.models.package_request import PackageRequest from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID -from aurweb.packages.util import get_pkgbase +from aurweb.packages.search import PackageSearch +from aurweb.packages.util import get_pkgbase, query_notified, query_voted from aurweb.templates import make_context, render_template router = APIRouter() +async def packages_get(request: Request, context: Dict[str, Any]): + # Query parameters used in this request. + context["q"] = dict(request.query_params) + + # Per page and offset. + per_page = context["PP"] = int(request.query_params.get("PP", 50)) + offset = context["O"] = int(request.query_params.get("O", 0)) + + # Query search by. + search_by = context["SeB"] = request.query_params.get("SeB", "nd") + + # Query sort by. + sort_by = context["SB"] = request.query_params.get("SB", "n") + + # Query sort order. + sort_order = request.query_params.get("SO", None) + + # Apply ordering, limit and offset. + search = PackageSearch(request.user) + + # For each keyword found in K, apply a search_by filter. + # This means that for any sentences separated by spaces, + # they are used as if they were ANDed. + keywords = context["K"] = request.query_params.get("K", str()) + keywords = keywords.split(" ") + for keyword in keywords: + search.search_by(search_by, keyword) + + flagged = request.query_params.get("outdated", None) + if flagged: + # If outdated was given, set it up in the context. + context["outdated"] = flagged + + # When outdated is set to "on," we filter records which do have + # an OutOfDateTS. When it's set to "off," we filter out any which + # do **not** have OutOfDateTS. + criteria = None + if flagged == "on": + criteria = PackageBase.OutOfDateTS.isnot + else: + criteria = PackageBase.OutOfDateTS.is_ + + # Apply the flag criteria to our PackageSearch.query. + search.query = search.query.filter(criteria(None)) + + submit = request.query_params.get("submit", "Go") + if submit == "Orphans": + # If the user clicked the "Orphans" button, we only want + # orphaned packages. + search.query = search.query.filter(PackageBase.MaintainerUID.is_(None)) + + # Apply user-specified specified sort column and ordering. + search.sort_by(sort_by, sort_order) + + # If no SO was given, default the context SO to 'a' (Ascending). + # By default, if no SO is given, the search should sort by 'd' + # (Descending), but display "Ascending" for the Sort order select. + if sort_order is None: + sort_order = "a" + context["SO"] = sort_order + + # Insert search results into the context. + results = search.results() + context["packages"] = results.limit(per_page).offset(offset) + context["packages_voted"] = query_voted( + context.get("packages"), request.user) + context["packages_notified"] = query_notified( + context.get("packages"), request.user) + context["packages_count"] = search.total_count + + return render_template(request, "packages.html", context) + + +@router.get("/packages") +async def packages(request: Request) -> Response: + context = make_context(request, "Packages") + return await packages_get(request, context) + + async def make_single_context(request: Request, pkgbase: PackageBase) -> Dict[str, Any]: """ Make a basic context for package or pkgbase. diff --git a/aurweb/templates.py b/aurweb/templates.py index 6a1b6a1c..09be049c 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -1,5 +1,6 @@ import copy import functools +import math import os import zoneinfo @@ -35,6 +36,7 @@ _env.filters["urlencode"] = util.to_qs _env.filters["quote_plus"] = quote_plus _env.filters["get_vote"] = util.get_vote _env.filters["number_format"] = util.number_format +_env.filters["ceil"] = math.ceil # Add captcha filters. _env.filters["captcha_salt"] = captcha.captcha_salt_filter diff --git a/conf/config.defaults b/conf/config.defaults index 1c96a55d..988859a0 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -22,6 +22,7 @@ aur_location = https://aur.archlinux.org git_clone_uri_anon = https://aur.archlinux.org/%s.git git_clone_uri_priv = ssh://aur@aur.archlinux.org/%s.git max_rpc_results = 5000 +max_search_results = 2500 max_depends = 1000 aur_request_ml = aur-requests@lists.archlinux.org request_idle_time = 1209600 diff --git a/setup.cfg b/setup.cfg index 1d67ca96..4f2bdf7d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,6 @@ [pycodestyle] max-line-length = 127 +ignore = E741, W503 [flake8] max-line-length = 127 @@ -25,6 +26,7 @@ max-complexity = 10 per-file-ignores = aurweb/routers/accounts.py:E741,C901 test/test_ssh_pub_key.py:E501 + aurweb/routers/packages.py:E741 [isort] line_length = 127 diff --git a/templates/packages.html b/templates/packages.html new file mode 100644 index 00000000..8b5b06d1 --- /dev/null +++ b/templates/packages.html @@ -0,0 +1,84 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} + {% if errors %} + +
      + {% for error in errors %} +
    • {{ error | tr }}
    • + {% endfor %} +
    + {% include "partials/packages/search.html" %} + + {% else %} + + {% set pages = (packages_count / PP) | ceil %} + {% set page = O / PP %} + + {% if success %} +
      + {% for message in success %} +
    • {{ message | tr }}
    • + {% endfor %} +
    + {% endif %} + + {# Search form #} + {% include "partials/packages/search.html" %} +
    + + {# /packages does things a bit roundabout-wise: + + If SeB is not given, "nd" is the default. + If SB is not given, "n" is the default. + If SO is not given, "d" is the default. + + However, we depend on flipping SO for column sorting. + + This section sets those defaults for the context if + they are not already setup. #} + {% if not SeB %} + {% set SeB = "nd" %} + {% endif %} + {% if not SB %} + {% set SB = "n" %} + {% endif %} + {% if not SO %} + {% set SO = "d" %} + {% endif %} + + {# Pagination widget #} + {% with total = packages_count, + singular = "%d package found.", + plural = "%d packages found.", + prefix = "/packages" %} + {% include "partials/widgets/pager.html" %} + {% endwith %} + + {# Package action form #} +
    + + {# Search results #} + {% with voted = packages_voted, notified = packages_notified %} + {% include "partials/packages/search_results.html" %} + {% endwith %} + + {# Pagination widget #} + {% with total = packages_count, + singular = "%d package found.", + plural = "%d packages found.", + prefix = "/packages" %} + {% include "partials/widgets/pager.html" %} + {% endwith %} + + {% if request.user.is_authenticated() %} + {# Package actions #} + {% include "partials/packages/search_actions.html" %} + {% endif %} + +
    + + {% endif %} +{% endblock %} diff --git a/templates/partials/packages/search.html b/templates/partials/packages/search.html index c4488b95..bb6fdb50 100644 --- a/templates/partials/packages/search.html +++ b/templates/partials/packages/search.html @@ -8,61 +8,65 @@
    - +
    - - + +
    diff --git a/templates/partials/packages/search_actions.html b/templates/partials/packages/search_actions.html new file mode 100644 index 00000000..2f5fe2e7 --- /dev/null +++ b/templates/partials/packages/search_actions.html @@ -0,0 +1,25 @@ +

    + + + {% if request.user.is_trusted_user() or request.user.is_developer() %} + + + {% endif %} + + + + +

    diff --git a/templates/partials/packages/search_results.html b/templates/partials/packages/search_results.html new file mode 100644 index 00000000..28cf0b48 --- /dev/null +++ b/templates/partials/packages/search_results.html @@ -0,0 +1,114 @@ +
    {{ "Git Clone URL" | tr }}:
    {{ "Description" | tr }}:{{ pkgbase.packages.first().Description }}{{ pkg.Description }}
    {{ "Upstream URL" | tr }}: - {% set pkg = pkgbase.packages.first() %} {% if pkg.URL %} {{ pkg.URL }} {% else %} @@ -33,7 +33,7 @@
    {{ "Keywords" | tr }}:
    {{ "Licenses" | tr }}: {{ licenses | join(', ', attribute='Name') | default('None' | tr) }}
    {{ "Conflicts" | tr }}: From ae0f69a5e463b5cdb502aa3777eb5da011112eba Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 16 Aug 2021 17:18:29 -0700 Subject: [PATCH 0817/1891] Docker: remove intervals and timeouts These weren't needed at all and provided false negatives in general. Removed them to let Docker deal with them. Additionally. 'exit 0' -> 'echo' for ca's command; 'exit 0' happens to depend on the shell running Docker (it seems). echo is quite a bit more agnostic. Moreso, added mariadb deps to php-fpm and fastapi. Signed-off-by: Kevin Morris --- docker-compose.yml | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ab8d7c41..3500b8e9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ services: image: aurweb:latest init: true entrypoint: /docker/ca-entrypoint.sh - command: exit 0 + command: echo volumes: - ./cache:/cache @@ -45,8 +45,6 @@ services: - mariadb_data:/var/lib/mysql healthcheck: test: "bash /docker/health/mariadb.sh" - interval: 2s - timeout: 60s git: image: aurweb:latest @@ -59,8 +57,6 @@ services: - "2222:2222" healthcheck: test: "bash /docker/health/sshd.sh" - interval: 2s - timeout: 30s depends_on: mariadb: condition: service_healthy @@ -79,8 +75,6 @@ services: command: /docker/scripts/run-smartgit.sh healthcheck: test: "bash /docker/health/smartgit.sh" - interval: 2s - timeout: 30s depends_on: mariadb: condition: service_healthy @@ -100,11 +94,11 @@ services: command: /docker/scripts/run-cgit.sh 3000 "https://localhost:8443/cgit" healthcheck: test: "bash /docker/health/cgit.sh 3000" - interval: 2s - timeout: 30s depends_on: git: condition: service_healthy + php-fpm: + condition: service_healthy volumes: - git_data:/aurweb/aur.git @@ -117,11 +111,11 @@ services: command: /docker/scripts/run-cgit.sh 3000 "https://localhost:8444/cgit" healthcheck: test: "bash /docker/health/cgit.sh 3000" - interval: 2s - timeout: 30s depends_on: git: condition: service_healthy + fastapi: + condition: service_healthy volumes: - git_data:/aurweb/aur.git @@ -135,8 +129,6 @@ services: command: /docker/scripts/run-php.sh healthcheck: test: "bash /docker/health/php.sh" - interval: 2s - timeout: 30s depends_on: ca: condition: service_started @@ -166,8 +158,6 @@ services: command: /docker/scripts/run-fastapi.sh "${FASTAPI_BACKEND}" healthcheck: test: "bash /docker/health/fastapi.sh ${FASTAPI_BACKEND}" - interval: 2s - timeout: 30s depends_on: ca: condition: service_started @@ -199,8 +189,6 @@ services: - "8444:8444" # FastAPI healthcheck: test: "bash /docker/health/nginx.sh" - interval: 2s - timeout: 30s depends_on: cgit-php: condition: service_healthy From 35851d553348383903c17d98cd049ac1f07bfaab Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 8 Aug 2021 18:35:49 -0700 Subject: [PATCH 0818/1891] Docker: add service 'memcached' Additionally, setup memcached for php-fpm. Signed-off-by: Kevin Morris --- conf/config.dev | 4 ++++ docker-compose.yml | 9 +++++++++ docker/health/memcached.sh | 2 ++ docker/php-entrypoint.sh | 6 ++++++ docker/scripts/install-deps.sh | 2 +- docker/scripts/run-memcached.sh | 2 ++ 6 files changed, 24 insertions(+), 1 deletion(-) create mode 100755 docker/health/memcached.sh create mode 100755 docker/scripts/run-memcached.sh diff --git a/conf/config.dev b/conf/config.dev index fc3bde91..566b655e 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -28,6 +28,10 @@ enable-maintenance = 0 localedir = YOUR_AUR_ROOT/web/locale ; In production, salt_rounds should be higher; suggested: 12. salt_rounds = 4 +cache = none +; In docker, the memcached host is available. On a user's system, +; this should be set to localhost (most likely). +memcache_servers = memcached:11211 [notifications] ; For development/testing, use /usr/bin/sendmail diff --git a/docker-compose.yml b/docker-compose.yml index 3500b8e9..56eff570 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,13 @@ services: volumes: - ./cache:/cache + memcached: + image: aurweb:latest + init: true + command: /docker/scripts/run-memcached.sh + healthcheck: + test: "bash /docker/health/memcached.sh" + mariadb: image: aurweb:latest init: true @@ -136,6 +143,8 @@ services: condition: service_healthy mariadb: condition: service_healthy + memcached: + condition: service_healthy volumes: - mariadb_run:/var/run/mysqld # Bind socket in this volume. - mariadb_data:/var/lib/mysql diff --git a/docker/health/memcached.sh b/docker/health/memcached.sh new file mode 100755 index 00000000..00f8cd98 --- /dev/null +++ b/docker/health/memcached.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec pgrep memcached diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index b4f6c631..1f3ed82b 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -7,6 +7,9 @@ bash $dir/test-mysql-entrypoint.sh sed -ri "s;^(aur_location) = .+;\1 = https://localhost:8443;" conf/config sed -ri 's/^(name) = .+/\1 = aurweb/' conf/config +# Enable memcached. +sed -ri 's/^(cache) = .+$/\1 = memcache/' conf/config + sed -ri "s|^(git_clone_uri_anon) = .+|\1 = https://localhost:8443/%s.git|" conf/config.defaults sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ssh://aur@localhost:2222/%s.git|" conf/config.defaults @@ -21,6 +24,9 @@ sed -ri 's|^;?(access\.log) = .*$|\1 = /proc/self/fd/2|g' \ sed -ri 's/^;?(extension=pdo_mysql)/\1/' /etc/php/php.ini sed -ri 's/^;?(open_basedir).*$/\1 = \//' /etc/php/php.ini +# Use the sqlite3 extension line for memcached. +sed -ri 's/^;(extension)=sqlite3$/\1=memcached/' /etc/php/php.ini + python -m aurweb.initdb 2>/dev/null || /bin/true exec "$@" diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 8d4525de..6edbff5a 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -14,6 +14,6 @@ pacman -Syu --noconfirm --noprogressbar \ python-pytest-asyncio python-coverage hypercorn python-bcrypt \ python-email-validator openssh python-lxml mariadb mariadb-libs \ python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ - python-asgiref uvicorn python-feedgen + python-asgiref uvicorn python-feedgen memcached php-memcached exec "$@" diff --git a/docker/scripts/run-memcached.sh b/docker/scripts/run-memcached.sh new file mode 100755 index 00000000..90784b0f --- /dev/null +++ b/docker/scripts/run-memcached.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec /usr/bin/memcached -u memcached -m 64 -c 1024 -l 0.0.0.0 From 96d1af936381a959090d5362ee2ee49b4c91eced Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 08:30:12 -0700 Subject: [PATCH 0819/1891] docker-compose: add redis service Now, the fastapi docker-compose service uses the new redis service for a cache option. Signed-off-by: Kevin Morris --- INSTALL | 5 +++++ docker-compose.yml | 12 ++++++++++++ docker/fastapi-entrypoint.sh | 4 ++++ docker/health/redis.sh | 2 ++ docker/redis-entrypoint.sh | 6 ++++++ docker/scripts/install-deps.sh | 3 ++- docker/scripts/run-redis.sh | 2 ++ 7 files changed, 33 insertions(+), 1 deletion(-) create mode 100755 docker/health/redis.sh create mode 100755 docker/redis-entrypoint.sh create mode 100755 docker/scripts/run-redis.sh diff --git a/INSTALL b/INSTALL index f192f9f5..c41a5c8e 100644 --- a/INSTALL +++ b/INSTALL @@ -55,6 +55,11 @@ read the instructions below. python-lxml python-feedgen # python3 setup.py install +(FastAPI-Specific) + + # pacman -S redis python-redis + # systemctl enable --now redis + 5) Create a new MySQL database and a user and import the aurweb SQL schema: $ python -m aurweb.initdb diff --git a/docker-compose.yml b/docker-compose.yml index 56eff570..0e91d6eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,6 +36,16 @@ services: healthcheck: test: "bash /docker/health/memcached.sh" + redis: + image: aurweb:latest + init: true + entrypoint: /docker/redis-entrypoint.sh + command: /docker/scripts/run-redis.sh + healthcheck: + test: "bash /docker/health/redis.sh" + ports: + - "16379:6379" + mariadb: image: aurweb:latest init: true @@ -172,6 +182,8 @@ services: condition: service_started git: condition: service_healthy + redis: + condition: service_healthy mariadb: condition: service_healthy volumes: diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index c46a33eb..41a88206 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -7,6 +7,10 @@ bash $dir/test-mysql-entrypoint.sh sed -ri "s;^(aur_location) = .+;\1 = https://localhost:8444;" conf/config sed -ri 's/^(name) = .+/\1 = aurweb/' conf/config +# Setup Redis for FastAPI. +sed -ri 's/^(cache) = .+/\1 = redis/' conf/config +sed -ri 's|^(redis_address) = .+|\1 = redis://redis|' conf/config + sed -ri "s|^(git_clone_uri_anon) = .+|\1 = https://localhost:8444/%s.git|" conf/config.defaults sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ssh://aur@localhost:2222/%s.git|" conf/config.defaults diff --git a/docker/health/redis.sh b/docker/health/redis.sh new file mode 100755 index 00000000..b5b442e8 --- /dev/null +++ b/docker/health/redis.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec pgrep redis-server diff --git a/docker/redis-entrypoint.sh b/docker/redis-entrypoint.sh new file mode 100755 index 00000000..e92be6c5 --- /dev/null +++ b/docker/redis-entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -eou pipefail + +sed -ri 's/^bind .*$/bind 0.0.0.0 -::1/g' /etc/redis/redis.conf + +exec "$@" diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 6edbff5a..6b0ec48b 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -14,6 +14,7 @@ pacman -Syu --noconfirm --noprogressbar \ python-pytest-asyncio python-coverage hypercorn python-bcrypt \ python-email-validator openssh python-lxml mariadb mariadb-libs \ python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ - python-asgiref uvicorn python-feedgen memcached php-memcached + python-asgiref uvicorn python-feedgen memcached php-memcached \ + python-redis redis exec "$@" diff --git a/docker/scripts/run-redis.sh b/docker/scripts/run-redis.sh new file mode 100755 index 00000000..8dc98b10 --- /dev/null +++ b/docker/scripts/run-redis.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec /usr/bin/redis-server /etc/redis/redis.conf From 91e769f6033867daaa951334ff51380275de5c84 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 28 Jun 2021 08:49:02 -0700 Subject: [PATCH 0820/1891] FastAPI: add redis integration This includes the addition of the python-fakeredis package, used for stubbing python-redis when a user does not have a configured cache. Signed-off-by: Kevin Morris --- INSTALL | 2 +- aurweb/redis.py | 57 ++++++++++++++++++++++++++++++++++ conf/config.defaults | 4 ++- conf/config.dev | 3 ++ docker/scripts/install-deps.sh | 2 +- test/test_asgi.py | 18 +++++++++++ test/test_redis.py | 40 ++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 aurweb/redis.py create mode 100644 test/test_redis.py diff --git a/INSTALL b/INSTALL index c41a5c8e..fdeb64ca 100644 --- a/INSTALL +++ b/INSTALL @@ -57,7 +57,7 @@ read the instructions below. (FastAPI-Specific) - # pacman -S redis python-redis + # pacman -S redis python-redis python-fakeredis # systemctl enable --now redis 5) Create a new MySQL database and a user and import the aurweb SQL schema: diff --git a/aurweb/redis.py b/aurweb/redis.py new file mode 100644 index 00000000..6b8dede4 --- /dev/null +++ b/aurweb/redis.py @@ -0,0 +1,57 @@ +import logging + +import fakeredis + +from redis import ConnectionPool, Redis + +import aurweb.config + +logger = logging.getLogger(__name__) +pool = None + + +class FakeConnectionPool: + """ A fake ConnectionPool class which holds an internal reference + to a fakeredis handle. + + We normally deal with Redis by keeping its ConnectionPool globally + referenced so we can persist connection state through different calls + to redis_connection(), and since FakeRedis does not offer a ConnectionPool, + we craft one up here to hang onto the same handle instance as long as the + same instance is alive; this allows us to use a similar flow from the + redis_connection() user's perspective. + """ + + def __init__(self): + self.handle = fakeredis.FakeStrictRedis() + + def disconnect(self): + pass + + +def redis_connection(): # pragma: no cover + global pool + + disabled = aurweb.config.get("options", "cache") != "redis" + + # If we haven't initialized redis yet, construct a pool. + if disabled: + logger.debug("Initializing fake Redis instance.") + if pool is None: + pool = FakeConnectionPool() + return pool.handle + else: + logger.debug("Initializing real Redis instance.") + if pool is None: + redis_addr = aurweb.config.get("options", "redis_address") + pool = ConnectionPool.from_url(redis_addr) + + # Create a connection to the pool. + return Redis(connection_pool=pool) + + +def kill_redis(): + global pool + if pool: + pool.disconnect() + pool = None diff --git a/conf/config.defaults b/conf/config.defaults index ebc21e51..1b4c3a74 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -36,11 +36,13 @@ enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 render-comment-cmd = /usr/local/bin/aurweb-rendercomment localedir = /srv/http/aurweb/aur.git/web/locale/ -# memcache or apc +; memcache, apc, or redis +; memcache/apc are supported in PHP, redis is supported in Python. cache = none cache_pkginfo_ttl = 86400 memcache_servers = 127.0.0.1:11211 salt_rounds = 12 +redis_address = redis://localhost [ratelimit] request_limit = 4000 diff --git a/conf/config.dev b/conf/config.dev index 566b655e..94a9630b 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -28,10 +28,13 @@ enable-maintenance = 0 localedir = YOUR_AUR_ROOT/web/locale ; In production, salt_rounds should be higher; suggested: 12. salt_rounds = 4 +; See config.defaults comment about cache. cache = none ; In docker, the memcached host is available. On a user's system, ; this should be set to localhost (most likely). memcache_servers = memcached:11211 +; If cache = 'redis' this address is used to connect to Redis. +redis_address = redis://127.0.0.1 [notifications] ; For development/testing, use /usr/bin/sendmail diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 6b0ec48b..0405f29b 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -15,6 +15,6 @@ pacman -Syu --noconfirm --noprogressbar \ python-email-validator openssh python-lxml mariadb mariadb-libs \ python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ python-asgiref uvicorn python-feedgen memcached php-memcached \ - python-redis redis + python-redis redis python-fakeredis exec "$@" diff --git a/test/test_asgi.py b/test/test_asgi.py index 79b34daf..b8856741 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -9,6 +9,24 @@ from fastapi import HTTPException import aurweb.asgi import aurweb.config +import aurweb.redis + + +@pytest.mark.asyncio +async def test_asgi_startup_session_secret_exception(monkeypatch): + """ Test that we get an IOError on app_startup when we cannot + connect to options.redis_address. """ + + redis_addr = aurweb.config.get("options", "redis_address") + + def mock_get(section: str, key: str): + if section == "fastapi" and key == "session_secret": + return None + return redis_addr + + with mock.patch("aurweb.config.get", side_effect=mock_get): + with pytest.raises(Exception): + await aurweb.asgi.app_startup() @pytest.mark.asyncio diff --git a/test/test_redis.py b/test/test_redis.py new file mode 100644 index 00000000..82aebb57 --- /dev/null +++ b/test/test_redis.py @@ -0,0 +1,40 @@ +from unittest import mock + +import pytest + +import aurweb.config + +from aurweb.redis import redis_connection + + +@pytest.fixture +def rediss(): + """ Create a RedisStub. """ + def mock_get(section, key): + return "none" + + with mock.patch("aurweb.config.get", side_effect=mock_get): + aurweb.config.rehash() + redis = redis_connection() + aurweb.config.rehash() + + yield redis + + +def test_redis_stub(rediss): + # We don't yet have a test key set. + assert rediss.get("test") is None + + # Set the test key to abc. + rediss.set("test", "abc") + assert rediss.get("test").decode() == "abc" + + # Test expire. + rediss.expire("test", 0) + assert rediss.get("test") is None + + # Now, set the test key again and use delete() on it. + rediss.set("test", "abc") + assert rediss.get("test").decode() == "abc" + rediss.delete("test") + assert rediss.get("test") is None From 968ed736c16f92de6ebca1a77fe1e7b2d78ec4e5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 8 Aug 2021 20:42:00 -0700 Subject: [PATCH 0821/1891] add python-orjson dependency python-orjson speeds up a lot of JSON serialization steps, so we choose to use it over the standard library json module. Signed-off-by: Kevin Morris --- INSTALL | 2 +- docker/scripts/install-deps.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/INSTALL b/INSTALL index fdeb64ca..4df59bd2 100644 --- a/INSTALL +++ b/INSTALL @@ -57,7 +57,7 @@ read the instructions below. (FastAPI-Specific) - # pacman -S redis python-redis python-fakeredis + # pacman -S redis python-redis python-fakeredis python-orjson # systemctl enable --now redis 5) Create a new MySQL database and a user and import the aurweb SQL schema: diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 0405f29b..a532a6b2 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -15,6 +15,6 @@ pacman -Syu --noconfirm --noprogressbar \ python-email-validator openssh python-lxml mariadb mariadb-libs \ python-isort flake8 cgit uwsgi uwsgi-plugin-cgi php php-fpm \ python-asgiref uvicorn python-feedgen memcached php-memcached \ - python-redis redis python-fakeredis + python-redis redis python-fakeredis python-orjson exec "$@" From 9e73936c4e52a862f392947005d6ed29668969de Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 6 Aug 2021 22:44:19 -0700 Subject: [PATCH 0822/1891] add aurweb.cache, a redis caching utility module Signed-off-by: Kevin Morris --- aurweb/cache.py | 20 +++++++++++++ test/test_cache.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 aurweb/cache.py create mode 100644 test/test_cache.py diff --git a/aurweb/cache.py b/aurweb/cache.py new file mode 100644 index 00000000..697473b8 --- /dev/null +++ b/aurweb/cache.py @@ -0,0 +1,20 @@ +from redis import Redis +from sqlalchemy import orm + + +async def db_count_cache(redis: Redis, key: str, query: orm.Query, + expire: int = None) -> int: + """ Store and retrieve a query.count() via redis cache. + + :param redis: Redis handle + :param key: Redis key + :param query: SQLAlchemy ORM query + :param expire: Optional expiration in seconds + :return: query.count() + """ + result = redis.get(key) + if result is None: + redis.set(key, (result := int(query.count()))) + if expire: + redis.expire(key, expire) + return int(result) diff --git a/test/test_cache.py b/test/test_cache.py new file mode 100644 index 00000000..35346e52 --- /dev/null +++ b/test/test_cache.py @@ -0,0 +1,74 @@ +import pytest + +from aurweb import cache, db +from aurweb.models.account_type import USER_ID +from aurweb.models.user import User +from aurweb.testing import setup_test_db + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db( + User.__tablename__ + ) + + +class StubRedis: + """ A class which acts as a RedisConnection without using Redis. """ + + cache = dict() + expires = dict() + + def get(self, key, *args): + if "key" not in self.cache: + self.cache[key] = None + return self.cache[key] + + def set(self, key, *args): + self.cache[key] = list(args)[0] + + def expire(self, key, *args): + self.expires[key] = list(args)[0] + + async def execute(self, command, key, *args): + f = getattr(self, command) + return f(key, *args) + + +@pytest.fixture +def redis(): + yield StubRedis() + + +@pytest.mark.asyncio +async def test_db_count_cache(redis): + db.create(User, Username="user1", + Email="user1@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID) + + query = db.query(User) + + # Now, perform several checks that db_count_cache matches query.count(). + + # We have no cached value yet. + assert await cache.db_count_cache(redis, "key1", query) == query.count() + + # It's cached now. + assert await cache.db_count_cache(redis, "key1", query) == query.count() + + +@pytest.mark.asyncio +async def test_db_count_cache_expires(redis): + db.create(User, Username="user1", + Email="user1@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID) + + query = db.query(User) + + # Cache a query with an expire. + value = await cache.db_count_cache(redis, "key1", query, 100) + assert value == query.count() + + assert redis.expires["key1"] == 100 From d9cdd5faeff608f4191872cc808be5c3ce0ce4b4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 28 Jul 2021 13:28:17 -0700 Subject: [PATCH 0823/1891] [FastAPI] Modularize homepage and add side panel This puts one more toward completion of the homepage overall; we'll need to still implement the authenticated user dashboard after this. Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 55 ++++++++- aurweb/routers/html.py | 74 ++++++++++- templates/home.html | 101 +++++++++++++++ templates/index.html | 107 ++-------------- .../partials/packages/widgets/search.html | 14 +++ .../partials/packages/widgets/statistics.html | 55 +++++++++ .../partials/packages/widgets/updates.html | 35 ++++++ templates/partials/widgets/statistics.html | 27 ++++ test/test_homepage.py | 115 ++++++++++++++++++ test/test_packages_util.py | 19 ++- 10 files changed, 500 insertions(+), 102 deletions(-) create mode 100644 templates/home.html create mode 100644 templates/partials/packages/widgets/search.html create mode 100644 templates/partials/packages/widgets/statistics.html create mode 100644 templates/partials/packages/widgets/updates.html create mode 100644 templates/partials/widgets/statistics.html diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 60db2962..036e3441 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -1,7 +1,10 @@ from http import HTTPStatus +from typing import List + +import orjson from fastapi import HTTPException -from sqlalchemy import and_ +from sqlalchemy import and_, orm from aurweb import db from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider @@ -10,6 +13,7 @@ from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_relation import PackageRelation from aurweb.models.relation_type import PROVIDES_ID, RelationType +from aurweb.redis import redis_connection from aurweb.templates import register_filter @@ -111,3 +115,52 @@ def get_pkgbase(name: str) -> PackageBase: raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) return pkgbase + + +@register_filter("out_of_date") +def out_of_date(packages: orm.Query) -> orm.Query: + return packages.filter(PackageBase.OutOfDateTS.isnot(None)) + + +def updated_packages(limit: int = 0, cache_ttl: int = 600) -> List[Package]: + """ Return a list of valid Package objects ordered by their + ModifiedTS column in descending order from cache, after setting + the cache when no key yet exists. + + :param limit: Optional record limit + :param cache_ttl: Cache expiration time (in seconds) + :return: A list of Packages + """ + redis = redis_connection() + packages = redis.get("package_updates") + if packages: + # If we already have a cache, deserialize it and return. + return orjson.loads(packages) + + query = db.query(Package).join(PackageBase).filter( + PackageBase.PackagerUID.isnot(None) + ).order_by( + PackageBase.ModifiedTS.desc() + ) + + if limit: + query = query.limit(limit) + + packages = [] + for pkg in query: + # For each Package returned by the query, append a dict + # containing Package columns we're interested in. + packages.append({ + "Name": pkg.Name, + "Version": pkg.Version, + "PackageBase": { + "ModifiedTS": pkg.PackageBase.ModifiedTS + } + }) + + # Store the JSON serialization of the package_updates key into Redis. + redis.set("package_updates", orjson.dumps(packages)) + redis.expire("package_updates", cache_ttl) + + # Return the deserialized list of packages. + return packages diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index f6f1a54e..ae012901 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -1,14 +1,21 @@ """ AURWeb's primary routing module. Define all routes via @app.app.{get,post} decorators in some way; more complex routes should be defined in their own modules and imported here. """ +from datetime import datetime from http import HTTPStatus from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse +from sqlalchemy import and_, or_ import aurweb.config -from aurweb import util +from aurweb import db, util +from aurweb.cache import db_count_cache +from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID +from aurweb.models.package_base import PackageBase +from aurweb.models.user import User +from aurweb.packages.util import updated_packages from aurweb.templates import make_context, render_template router = APIRouter() @@ -60,6 +67,71 @@ async def index(request: Request): context = make_context(request, "Home") context['ssh_fingerprints'] = util.get_ssh_fingerprints() + bases = db.query(PackageBase) + + redis = aurweb.redis.redis_connection() + stats_expire = 300 # Five minutes. + updates_expire = 600 # Ten minutes. + + # Package statistics. + query = bases.filter(PackageBase.PackagerUID.isnot(None)) + context["package_count"] = await db_count_cache( + redis, "package_count", query, expire=stats_expire) + + query = bases.filter( + and_(PackageBase.MaintainerUID.is_(None), + PackageBase.PackagerUID.isnot(None)) + ) + context["orphan_count"] = await db_count_cache( + redis, "orphan_count", query, expire=stats_expire) + + query = db.query(User) + context["user_count"] = await db_count_cache( + redis, "user_count", query, expire=stats_expire) + + query = query.filter( + or_(User.AccountTypeID == TRUSTED_USER_ID, + User.AccountTypeID == TRUSTED_USER_AND_DEV_ID)) + context["trusted_user_count"] = await db_count_cache( + redis, "trusted_user_count", query, expire=stats_expire) + + # Current timestamp. + now = int(datetime.utcnow().timestamp()) + + seven_days = 86400 * 7 # Seven days worth of seconds. + seven_days_ago = now - seven_days + + one_hour = 3600 + updated = bases.filter( + and_(PackageBase.ModifiedTS - PackageBase.SubmittedTS >= one_hour, + PackageBase.PackagerUID.isnot(None)) + ) + + query = bases.filter( + and_(PackageBase.SubmittedTS >= seven_days_ago, + PackageBase.PackagerUID.isnot(None)) + ) + context["seven_days_old_added"] = await db_count_cache( + redis, "seven_days_old_added", query, expire=stats_expire) + + query = updated.filter(PackageBase.ModifiedTS >= seven_days_ago) + context["seven_days_old_updated"] = await db_count_cache( + redis, "seven_days_old_updated", query, expire=stats_expire) + + year = seven_days * 52 # Fifty two weeks worth: one year. + year_ago = now - year + query = updated.filter(PackageBase.ModifiedTS >= year_ago) + context["year_old_updated"] = await db_count_cache( + redis, "year_old_updated", query, expire=stats_expire) + + query = bases.filter( + PackageBase.ModifiedTS - PackageBase.SubmittedTS < 3600) + context["never_updated"] = await db_count_cache( + redis, "never_updated", query, expire=stats_expire) + + # Get the 15 most recently updated packages. + context["package_updates"] = updated_packages(15, updates_expire) + return render_template(request, "index.html", context) diff --git a/templates/home.html b/templates/home.html new file mode 100644 index 00000000..a8cae5b8 --- /dev/null +++ b/templates/home.html @@ -0,0 +1,101 @@ +
    +

    AUR {% trans %}Home{% endtrans %}

    +

    + {{ "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU Guidelines%s for more information." + | tr + | format('', "", + '', "") + | safe + }} + {{ "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s otherwise they will be deleted!" + | tr + | format("", "", + '', + "") + | safe + }} + {% trans %}Remember to vote for your favourite packages!{% endtrans %} + {% trans %}Some packages may be provided as binaries in [community].{% endtrans %} +

    +

    + {% trans %}DISCLAIMER{% endtrans %}: + {% trans %}AUR packages are user produced content. Any use of the provided files is at your own risk.{% endtrans %} +

    +

    {% trans %}Learn more...{% endtrans %}

    +
    +
    +

    {% trans %}Support{% endtrans %}

    +

    {% trans %}Package Requests{% endtrans %}

    +
    +

    + {{ "There are three types of requests that can be filed in the %sPackage Actions%s box on the package details page:" + | tr + | format("", "") + | safe + }} +

    +
      +
    • {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
    • +
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
    • +
    • {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}
    • +
    +

    + {{ "If you want to discuss a request, you can use the %saur-requests%s mailing list. However, please do not use that list to file requests." + | tr + | format('', "") + | safe + }} +

    +
    +

    {% trans %}Submitting Packages{% endtrans %}

    +
    +

    + {{ "Git over SSH is now used to submit packages to the AUR. See the %sSubmitting packages%s section of the Arch User Repository ArchWiki page for more details." + | tr + | format('', "") + | safe + }} +

    + {% if ssh_fingerprints %} +

    + {% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %} +

    +

      + {% for keytype in ssh_fingerprints %} +
    • {{ keytype }}: {{ ssh_fingerprints[keytype] }} + {% endfor %} +
    + {% endif %} +
    +

    {% trans %}Discussion{% endtrans %}

    +
    +

    + {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." + | tr + | format('', "", + '', "") + | safe + }} +

    +

    +

    {% trans %}Bug Reporting{% endtrans %}

    +
    +

    + {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page." + | tr + | format('', "", + "", "") + | safe + }} +

    +
    +
    + + + + + + diff --git a/templates/index.html b/templates/index.html index f8745f33..e50a99cd 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,106 +1,15 @@ {% extends 'partials/layout.html' %} {% block pageContent %} -
    -

    AUR {% trans %}Home{% endtrans %}

    -

    - {{ "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU Guidelines%s for more information." - | tr - | format('', "", - '', "") - | safe - }} - {{ "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s otherwise they will be deleted!" - | tr - | format("", "", - '', - "") - | safe - }} - {% trans %}Remember to vote for your favourite packages!{% endtrans %} - {% trans %}Some packages may be provided as binaries in [community].{% endtrans %} -

    - {% trans %}DISCLAIMER{% endtrans %}: - {% trans %}AUR packages are user produced content. Any use of the provided files is at your own risk.{% endtrans %} -

    -

    {% trans %}Learn more...{% endtrans %}

    -

    -
    -
    -

    {% trans %}Support{% endtrans %}

    -

    {% trans %}Package Requests{% endtrans %}

    -
    -

    - {{ "There are three types of requests that can be filed in the %sPackage Actions%s box on the package details page:" - | tr - | format("", "") - | safe - }} -

    -
      -
    • {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
    • -
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
    • -
    • {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}
    • -
    -

    - {{ "If you want to discuss a request, you can use the %saur-requests%s mailing list. However, please do not use that list to file requests." - | tr - | format('', "") - | safe - }} -

    +
    +
    + {% include 'home.html' %} +
    -

    {% trans %}Submitting Packages{% endtrans %}

    -
    -

    - {{ "Git over SSH is now used to submit packages to the AUR. See the %sSubmitting packages%s section of the Arch User Repository ArchWiki page for more details." - | tr - | format('', "") - | safe - }} -

    - {% if ssh_fingerprints %} -

    - {% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %} -

    -

      - {% for keytype in ssh_fingerprints %} -
    • {{ keytype }}: {{ ssh_fingerprints[keytype] }} - {% endfor %} -
    - {% endif %} +
    + {% include 'partials/packages/widgets/search.html' %} + {% include 'partials/packages/widgets/updates.html' %} + {% include 'partials/packages/widgets/statistics.html' %}
    -

    {% trans %}Discussion{% endtrans %}

    -
    -

    - {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." - | tr - | format('', "", - '', "") - | safe - }} -

    -

    -

    {% trans %}Bug Reporting{% endtrans %}

    -
    -

    - {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page." - | tr - | format('', "", - "", "") - | safe - }} -

    -
    -
    - - - - - - {% endblock %} diff --git a/templates/partials/packages/widgets/search.html b/templates/partials/packages/widgets/search.html new file mode 100644 index 00000000..106b93ea --- /dev/null +++ b/templates/partials/packages/widgets/search.html @@ -0,0 +1,14 @@ +
    +
    +
    + + + +
    +
    +
    diff --git a/templates/partials/packages/widgets/statistics.html b/templates/partials/packages/widgets/statistics.html new file mode 100644 index 00000000..f841ae0e --- /dev/null +++ b/templates/partials/packages/widgets/statistics.html @@ -0,0 +1,55 @@ +
    +

    {{ "Statistics" | tr }}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{ "Packages" | tr }}{{ package_count }}
    {{ "Orphan Packages" | tr }}{{ orphan_count }}
    + {{ "Packages added in the past 7 days" | tr }} + {{ seven_days_old_added }}
    + {{ "Packages updated in the past 7 days" | tr }} + {{ seven_days_old_updated }}
    + {{ "Packages updated in the past year" | tr }} + {{ year_old_updated }}
    + {{ "Packages never updated" | tr }} + {{ never_updated }}
    + {{ "Registered Users" | tr }} + {{ user_count }}
    + {{ "Trusted Users" | tr }} + {{ trusted_user_count }}
    +
    + +{% if request.user.is_authenticated() %} + + {% include 'partials/widgets/statistics.html' %} +{% endif %} diff --git a/templates/partials/packages/widgets/updates.html b/templates/partials/packages/widgets/updates.html new file mode 100644 index 00000000..3ee1b98e --- /dev/null +++ b/templates/partials/packages/widgets/updates.html @@ -0,0 +1,35 @@ +
    +

    + {{ "Recent Updates" | tr }} + + ({{ "more" | tr }}) + +

    + + RSS Feed + + + RSS Feed + + + + + {% for pkg in package_updates %} + + + + + {% endfor %} + +
    + + {{ pkg.Name }} {{ pkg.Version }} + + + {% set modified = pkg.PackageBase.ModifiedTS | dt | as_timezone(timezone) %} + {{ modified.strftime("%Y-%m-%d %H:%M") }} +
    + +
    diff --git a/templates/partials/widgets/statistics.html b/templates/partials/widgets/statistics.html new file mode 100644 index 00000000..0bf844b6 --- /dev/null +++ b/templates/partials/widgets/statistics.html @@ -0,0 +1,27 @@ +
    +

    {{ "My Statistics" | tr }}

    + + {% set bases = request.user.maintained_bases %} + + + + + + + {% set out_of_date_packages = bases | out_of_date %} + + + + + +
    + + {{ "Packages" | tr }} + + {{ bases.count() }}
    + + {{ "Out of Date" | tr }} + + {{ out_of_date_packages.count() }}
    + +
    diff --git a/test/test_homepage.py b/test/test_homepage.py index 23d7185f..a629b98c 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -1,13 +1,82 @@ +import re + +from datetime import datetime from http import HTTPStatus from unittest.mock import patch +import pytest + from fastapi.testclient import TestClient +from aurweb import db from aurweb.asgi import app +from aurweb.models.account_type import USER_ID +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.user import User +from aurweb.redis import redis_connection +from aurweb.testing import setup_test_db +from aurweb.testing.html import parse_root client = TestClient(app) +@pytest.fixture(autouse=True) +def setup(): + yield setup_test_db( + User.__tablename__, + Package.__tablename__, + PackageBase.__tablename__ + ) + + +@pytest.fixture +def user(): + yield db.create(User, Username="test", Email="test@example.org", + Passwd="testPassword", AccountTypeID=USER_ID) + + +@pytest.fixture +def redis(): + redis = redis_connection() + + def delete_keys(): + # Cleanup keys if they exist. + for key in ("package_count", "orphan_count", "user_count", + "trusted_user_count", "seven_days_old_added", + "seven_days_old_updated", "year_old_updated", + "never_updated", "package_updates"): + if redis.get(key) is not None: + redis.delete(key) + + delete_keys() + yield redis + delete_keys() + + +@pytest.fixture +def packages(user): + """ Yield a list of num_packages Package objects maintained by user. """ + num_packages = 50 # Tunable + + # For i..num_packages, create a package named pkg_{i}. + pkgs = [] + now = int(datetime.utcnow().timestamp()) + for i in range(num_packages): + pkgbase = db.create(PackageBase, Name=f"pkg_{i}", + Maintainer=user, Packager=user, + autocommit=False, SubmittedTS=now, + ModifiedTS=now) + pkg = db.create(Package, PackageBase=pkgbase, + Name=pkgbase.Name, autocommit=False) + pkgs.append(pkg) + now += 1 + + db.commit() + + yield pkgs + + def test_homepage(): with client as request: response = request.get("/") @@ -34,3 +103,49 @@ def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock): response = request.get("/") assert 'The following SSH fingerprints are used for the AUR' not in response.content.decode() + + +def test_homepage_stats(redis, packages): + with client as request: + response = request.get("/") + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + + expectations = [ + ("Packages", r'\d+'), + ("Orphan Packages", r'\d+'), + ("Packages added in the past 7 days", r'\d+'), + ("Packages updated in the past 7 days", r'\d+'), + ("Packages updated in the past year", r'\d+'), + ("Packages never updated", r'\d+'), + ("Registered Users", r'\d+'), + ("Trusted Users", r'\d+') + ] + + stats = root.xpath('//div[@id="pkg-stats"]//tr') + for i, expected in enumerate(expectations): + expected_key, expected_regex = expected + key, value = stats[i].xpath('./td') + assert key.text.strip() == expected_key + assert re.match(expected_regex, value.text.strip()) + + +def test_homepage_updates(redis, packages): + with client as request: + response = request.get("/") + assert response.status_code == int(HTTPStatus.OK) + # Run the request a second time to exercise the Redis path. + response = request.get("/") + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + + # We expect to see the latest 15 packages, which happens to be + # pkg_49 .. pkg_34. So, create a list of expectations using a range + # starting at 49, stepping down to 49 - 15, -1 step at a time. + expectations = [f"pkg_{i}" for i in range(50 - 1, 50 - 1 - 15, -1)] + updates = root.xpath('//div[@id="pkg-updates"]/table/tbody/tr') + for i, expected in enumerate(expectations): + pkgname = updates[i].xpath('./td/a').pop(0) + assert pkgname.text.strip() == expected diff --git a/test/test_packages_util.py b/test/test_packages_util.py index 17978490..bc6a941c 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -9,6 +9,7 @@ from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.user import User from aurweb.packages import util +from aurweb.redis import kill_redis from aurweb.testing import setup_test_db @@ -33,7 +34,8 @@ def maintainer() -> User: @pytest.fixture def package(maintainer: User) -> Package: - pkgbase = db.create(PackageBase, Name="test-pkg", Maintainer=maintainer) + pkgbase = db.create(PackageBase, Name="test-pkg", + Packager=maintainer, Maintainer=maintainer) yield db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) @@ -49,3 +51,18 @@ def test_package_link(client: TestClient, maintainer: User, package: Package): Provides=package.Name) expected = f"{OFFICIAL_BASE}/packages/?q={package.Name}" assert util.package_link(package) == expected + + +def test_updated_packages(maintainer: User, package: Package): + expected = { + "Name": package.Name, + "Version": package.Version, + "PackageBase": { + "ModifiedTS": package.PackageBase.ModifiedTS + } + } + + kill_redis() # Kill it here to ensure we're on a fake instance. + assert util.updated_packages(1, 0) == [expected] + assert util.updated_packages(1, 600) == [expected] + kill_redis() # Kill it again, in case other tests use a real instance. From 469c141f6b541ea4b6d6aadbbd32fdb9822f6975 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 17 Aug 2021 20:58:41 -0700 Subject: [PATCH 0824/1891] [FastAPI] bugfix: remove use of scalar() in plural context Anything where we can have more than one of something, scalar() cannot be used. Signed-off-by: Kevin Morris --- templates/partials/packages/comments.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/partials/packages/comments.html b/templates/partials/packages/comments.html index 051849b0..39cfb363 100644 --- a/templates/partials/packages/comments.html +++ b/templates/partials/packages/comments.html @@ -49,7 +49,7 @@
    {% endif %} -{% if comments.scalar() %} +{% if comments %}

    From eb8ea53a4483d3a9d42b9b5cb0bfcfcc87d2cb4e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 7 Aug 2021 14:57:24 -0700 Subject: [PATCH 0825/1891] PackageRequest: add status_display() A helper function which provides a textual string conversion of a particular Status column. In a PackageRequest, Status is split up into four different types: - PENDING : "Pending", PENDING_ID: 0 - CLOSED : "Closed", CLOSED_ID: 1 - ACCEPTED : "Accepted", ACCEPTED_ID: 2 - REJECTED : "Rejected", REJECTED_ID: 3 This commit adds constants for the textual strings and the IDs. It also adds a PackageRequest.status_display() function which grabs the proper display string for a particular Status ID. Signed-off-by: Kevin Morris --- aurweb/models/package_request.py | 22 +++++++++++++++++++++ test/test_package_request.py | 34 ++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/aurweb/models/package_request.py b/aurweb/models/package_request.py index 00f46ce2..a5125cee 100644 --- a/aurweb/models/package_request.py +++ b/aurweb/models/package_request.py @@ -8,6 +8,17 @@ import aurweb.models.user from aurweb.models.declarative import Base +PENDING = "Pending" +CLOSED = "Closed" +ACCEPTED = "Accepted" +REJECTED = "Rejected" + +# Integer values used for the Status column of PackageRequest. +PENDING_ID = 0 +CLOSED_ID = 1 +ACCEPTED_ID = 2 +REJECTED_ID = 3 + class PackageRequest(Base): __tablename__ = "PackageRequests" @@ -40,6 +51,13 @@ class PackageRequest(Base): __mapper_args__ = {"primary_key": [ID]} + STATUS_DISPLAY = { + PENDING_ID: PENDING, + CLOSED_ID: CLOSED, + ACCEPTED_ID: ACCEPTED, + REJECTED_ID: REJECTED + } + def __init__(self, RequestType: aurweb.models.request_type.RequestType = None, PackageBase: aurweb.models.package_base.PackageBase = None, @@ -91,3 +109,7 @@ class PackageRequest(Base): statement="Column ClosureComment cannot be null.", orig="PackageRequests.ClosureComment", params=("NULL")) + + def status_display(self) -> str: + """ Return a display string for the Status column. """ + return self.STATUS_DISPLAY[self.Status] diff --git a/test/test_package_request.py b/test/test_package_request.py index fc839836..c28af6bd 100644 --- a/test/test_package_request.py +++ b/test/test_package_request.py @@ -4,9 +4,10 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query, rollback +from aurweb.db import commit, create, query, rollback from aurweb.models.package_base import PackageBase -from aurweb.models.package_request import PackageRequest +from aurweb.models.package_request import (ACCEPTED, ACCEPTED_ID, CLOSED, CLOSED_ID, PENDING, PENDING_ID, REJECTED, + REJECTED_ID, PackageRequest) from aurweb.models.request_type import RequestType from aurweb.models.user import User from aurweb.testing import setup_test_db @@ -117,3 +118,32 @@ def test_package_request_null_closure_comment_raises_exception(): User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, Comments=str()) rollback() + + +def test_package_request_status_display(): + """ Test status_display() based on the Status column value. """ + request_type = query(RequestType, RequestType.Name == "merge").first() + + pkgreq = create(PackageRequest, RequestType=request_type, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str(), + Status=PENDING_ID) + assert pkgreq.status_display() == PENDING + + pkgreq.Status = CLOSED_ID + commit() + assert pkgreq.status_display() == CLOSED + + pkgreq.Status = ACCEPTED_ID + commit() + assert pkgreq.status_display() == ACCEPTED + + pkgreq.Status = REJECTED_ID + commit() + assert pkgreq.status_display() == REJECTED + + pkgreq.Status = 124 + commit() + with pytest.raises(KeyError): + pkgreq.status_display() From 5bd3a7bbabd06bf846991a9dd4c74d61c9a8d0a0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 7 Aug 2021 15:43:44 -0700 Subject: [PATCH 0826/1891] RequestType: add name_display() and record constants Just like some of the other tables, we have some constant records that we use to denote types of things. This commit adds constants which correlate with these record constants. Signed-off-by: Kevin Morris --- aurweb/models/request_type.py | 15 +++++++++++++++ test/test_request_type.py | 15 +++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/aurweb/models/request_type.py b/aurweb/models/request_type.py index 2c8276e8..a26dcf9a 100644 --- a/aurweb/models/request_type.py +++ b/aurweb/models/request_type.py @@ -1,7 +1,12 @@ from sqlalchemy import Column, Integer +from aurweb import db from aurweb.models.declarative import Base +DELETION = "deletion" +ORPHAN = "orphan" +MERGE = "merge" + class RequestType(Base): __tablename__ = "RequestTypes" @@ -9,3 +14,13 @@ class RequestType(Base): ID = Column(Integer, primary_key=True) __mapper_args__ = {"primary_key": [ID]} + + def name_display(self) -> str: + """ Return the Name column with its first char capitalized. """ + name = self.Name + return name[0].upper() + name[1:] + + +DELETION_ID = db.query(RequestType, RequestType.Name == DELETION).first().ID +ORPHAN_ID = db.query(RequestType, RequestType.Name == ORPHAN).first().ID +MERGE_ID = db.query(RequestType, RequestType.Name == MERGE).first().ID diff --git a/test/test_request_type.py b/test/test_request_type.py index a470a60b..a3b3ccb8 100644 --- a/test/test_request_type.py +++ b/test/test_request_type.py @@ -1,7 +1,7 @@ import pytest -from aurweb.db import create, delete -from aurweb.models.request_type import RequestType +from aurweb.db import create, delete, query +from aurweb.models.request_type import DELETION_ID, MERGE_ID, ORPHAN_ID, RequestType from aurweb.testing import setup_test_db @@ -22,3 +22,14 @@ def test_request_type_null_name_returns_empty_string(): assert bool(request_type.ID) assert request_type.Name == str() delete(RequestType, RequestType.ID == request_type.ID) + + +def test_request_type_name_display(): + deletion = query(RequestType, RequestType.ID == DELETION_ID).first() + assert deletion.name_display() == "Deletion" + + orphan = query(RequestType, RequestType.ID == ORPHAN_ID).first() + assert orphan.name_display() == "Orphan" + + merge = query(RequestType, RequestType.ID == MERGE_ID).first() + assert merge.name_display() == "Merge" From af51b5c4604636408d78d015b49bfbc0e8d7de27 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 7 Aug 2021 19:35:50 -0700 Subject: [PATCH 0827/1891] User: add several utility methods Added: - User.voted_for(package) - Has a user voted for a particular package? - User.notified(package) - Is a user being notified about a particular package? - User.packages() - Entire collection of Package objects related to User. Signed-off-by: Kevin Morris --- aurweb/models/user.py | 36 +++++++++++++++++++++++++++++++++++- test/test_user.py | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 4705c050..0ccf7329 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -5,13 +5,14 @@ from datetime import datetime import bcrypt from fastapi import Request -from sqlalchemy import Column, ForeignKey, Integer, String, text +from sqlalchemy import Column, ForeignKey, Integer, String, or_, text from sqlalchemy.orm import backref, relationship import aurweb.config import aurweb.models.account_type import aurweb.schema +from aurweb import db from aurweb.models.ban import is_banned from aurweb.models.declarative import Base @@ -177,6 +178,39 @@ class User(Base): """ return self == user or self.is_trusted_user() or self.is_developer() + def voted_for(self, package) -> bool: + """ Has this User voted for package? """ + from aurweb.models.package_vote import PackageVote + return bool(package.PackageBase.package_votes.filter( + PackageVote.UsersID == self.ID + ).scalar()) + + def notified(self, package) -> bool: + """ Is this User being notified about package? """ + from aurweb.models.package_notification import PackageNotification + return bool(package.PackageBase.package_notifications.filter( + PackageNotification.UserID == self.ID + ).scalar()) + + def packages(self): + """ Returns an ORM query to Package objects owned by this user. + + This should really be replaced with an internal ORM join + configured for the User model. This has not been done yet + due to issues I've been encountering in the process, so + sticking with this function until we can properly implement it. + + :return: ORM query of User-packaged or maintained Package objects + """ + from aurweb.models.package import Package + from aurweb.models.package_base import PackageBase + return db.query(Package).join(PackageBase).filter( + or_( + PackageBase.PackagerUID == self.ID, + PackageBase.MaintainerUID == self.ID + ) + ) + def __repr__(self): return "" % ( self.ID, str(self.AccountType), self.Username) diff --git a/test/test_user.py b/test/test_user.py index 9ab40801..7756cff3 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -12,6 +12,10 @@ import aurweb.config from aurweb.db import commit, create, query from aurweb.models.account_type import AccountType from aurweb.models.ban import Ban +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.package_notification import PackageNotification +from aurweb.models.package_vote import PackageVote from aurweb.models.session import Session from aurweb.models.ssh_pub_key import SSHPubKey from aurweb.models.user import User @@ -25,7 +29,16 @@ account_type = user = None def setup(): global account_type, user - setup_test_db("Users", "Sessions", "Bans", "SSHPubKeys") + setup_test_db( + User.__tablename__, + Session.__tablename__, + Ban.__tablename__, + SSHPubKey.__tablename__, + Package.__tablename__, + PackageBase.__tablename__, + PackageVote.__tablename__, + PackageNotification.__tablename__ + ) account_type = query(AccountType, AccountType.AccountType == "User").first() @@ -249,3 +262,24 @@ def test_user_is_developer(): user.AccountType = dev_type commit() assert user.is_developer() is True + + +def test_user_voted_for(): + now = int(datetime.utcnow().timestamp()) + pkgbase = create(PackageBase, Name="pkg1", Maintainer=user) + pkg = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + create(PackageVote, PackageBase=pkgbase, User=user, VoteTS=now) + assert user.voted_for(pkg) + + +def test_user_notified(): + pkgbase = create(PackageBase, Name="pkg1", Maintainer=user) + pkg = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + create(PackageNotification, PackageBase=pkgbase, User=user) + assert user.notified(pkg) + + +def test_user_packages(): + pkgbase = create(PackageBase, Name="pkg1", Maintainer=user) + pkg = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + assert pkg in user.packages() From 5a175bd92a791b45ad1d224cca133645abfcaa0d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 9 Aug 2021 23:43:48 -0700 Subject: [PATCH 0828/1891] routers.html: add authenticated dashboard to homepage Signed-off-by: Kevin Morris --- aurweb/routers/html.py | 39 +++++++++++ templates/dashboard.html | 54 ++++++++++++++++ templates/index.html | 6 +- templates/partials/packages/requests.html | 38 +++++++++++ templates/partials/packages/results.html | 55 ++++++++++++++++ test/test_homepage.py | 79 ++++++++++++++++++++++- 6 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 templates/dashboard.html create mode 100644 templates/partials/packages/requests.html create mode 100644 templates/partials/packages/results.html diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index ae012901..c2375f69 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -9,11 +9,15 @@ from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, or_ import aurweb.config +import aurweb.models.package_request from aurweb import db, util from aurweb.cache import db_count_cache from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID +from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_comaintainer import PackageComaintainer +from aurweb.models.package_request import PackageRequest from aurweb.models.user import User from aurweb.packages.util import updated_packages from aurweb.templates import make_context, render_template @@ -132,6 +136,41 @@ async def index(request: Request): # Get the 15 most recently updated packages. context["package_updates"] = updated_packages(15, updates_expire) + if request.user.is_authenticated(): + # Authenticated users get a few extra pieces of data for + # the dashboard display. + packages = db.query(Package).join(PackageBase) + + maintained = packages.join( + User, PackageBase.MaintainerUID == User.ID + ).filter( + PackageBase.MaintainerUID == request.user.ID + ) + + context["flagged_packages"] = maintained.filter( + PackageBase.OutOfDateTS.isnot(None) + ).order_by( + PackageBase.ModifiedTS.desc(), Package.Name.asc() + ).limit(50).all() + + archive_time = aurweb.config.getint('options', 'request_archive_time') + start = now - archive_time + context["package_requests"] = request.user.package_requests.filter( + PackageRequest.RequestTS >= start + ).limit(50).all() + + # Packages that the request user maintains or comaintains. + context["packages"] = maintained.order_by( + PackageBase.ModifiedTS.desc(), Package.Name.desc() + ).limit(50).all() + + # Any packages that the request user comaintains. + context["comaintained"] = packages.join( + PackageComaintainer).filter( + PackageComaintainer.UsersID == request.user.ID).order_by( + PackageBase.ModifiedTS.desc(), Package.Name.desc() + ).limit(50).all() + return render_template(request, "index.html", context) diff --git a/templates/dashboard.html b/templates/dashboard.html new file mode 100644 index 00000000..5ad89992 --- /dev/null +++ b/templates/dashboard.html @@ -0,0 +1,54 @@ +
    +

    {{ "Dashboard" | tr }}

    + +

    {{ "My Flagged Packages" | tr }}

    + {% if not flagged_packages %} +

    {{ "No packages matched your search criteria." | tr }}

    + {% else %} + {% with table_id = "flagged-packages", packages = flagged_packages %} + {% include 'partials/packages/results.html' %} + {% endwith %} + {% endif %} + +

    {{ "My Requests" | tr }}

    + {% if not package_requests %} +

    {{ "No requests matched your search criteria." | tr }}

    + {% else %} + {% with requests = package_requests %} + {% include 'partials/packages/requests.html' %} + {% endwith %} + {% endif %} +
    + +
    +

    {{ "My Packages" | tr }}

    +

    + + {{ "Search for packages I maintain" | tr }} + +

    + {% if not packages %} +

    {{ "No packages matched your search criteria." | tr }}

    + {% else %} + {% with table_id = "my-packages" %} + {% include 'partials/packages/results.html' %} + {% endwith %} + {% endif %} +
    + +
    +

    {{ "Co-Maintained Packages" | tr }}

    +

    + + {{ "Search for packages I co-maintain" | tr }} + +

    + {% if not comaintained %} +

    {{ "No packages matched your search criteria." | tr }}

    + {% else %} + {% with table_id = "comaintained-packages", packages = comaintained %} + {% include 'partials/packages/results.html' %} + {% endwith %} + {% endif %} +
    + diff --git a/templates/index.html b/templates/index.html index e50a99cd..0b6eda50 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,7 +3,11 @@ {% block pageContent %}
    - {% include 'home.html' %} + {% if request.user.is_authenticated() %} + {% include 'dashboard.html' %} + {% else %} + {% include 'home.html' %} + {% endif %}
    diff --git a/templates/partials/packages/requests.html b/templates/partials/packages/requests.html new file mode 100644 index 00000000..5239ca72 --- /dev/null +++ b/templates/partials/packages/requests.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + {% for request in requests %} + {% set requested = request.RequestTS | dt | as_timezone(timezone) %} + + + + + + + + + {% endfor %} + + + +
    {{ "Package" | tr }}{{ "Type" | tr }}{{ "Comments" | tr }}{{ "Filed by" | tr }}{{ "Date" | tr }}{{ "Status" | tr }}
    + + {{ request.PackageBase.Name }} + + {{ request.RequestType.name_display() | tr }}{{ request.Comments }} + + {{ request.User.Username }} + + {{ requested.strftime("%Y-%m-%d %H:%M") }}{{ request.status_display() | tr }}
    diff --git a/templates/partials/packages/results.html b/templates/partials/packages/results.html new file mode 100644 index 00000000..005bd5a9 --- /dev/null +++ b/templates/partials/packages/results.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + {% for pkg in packages %} + {% set flagged = pkg.PackageBase.OutOfDateTS %} + + + {% if flagged %} + + {% else %} + + {% endif %} + + + + + + + + {% endfor %} + +
    {{ "Name" | tr }}{{ "Version" | tr }}{{ "Votes" | tr }}{{ "Popularity" | tr }}{{ "Voted" | tr }}{{ "Notify" | tr }}{{ "Description" | tr }}{{ "Maintainer" | tr }}
    + + {{ pkg.Name }} + + {{ pkg.Version }}{{ pkg.Version }}{{ pkg.PackageBase.NumVotes }} + {{ pkg.PackageBase.Popularity | number_format(2) }} + + + {% if request.user.voted_for(pkg) %} + {{ "Yes" | tr }} + {% endif %} + + + {% if request.user.notified(pkg) %} + {{ "Yes" | tr }} + {% endif %} + {{ pkg.Description or '' }} + {% set maintainer = pkg.PackageBase.Maintainer %} + + {{ maintainer.Username }} + +
    diff --git a/test/test_homepage.py b/test/test_homepage.py index a629b98c..2cd6682f 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -13,10 +13,14 @@ from aurweb.asgi import app from aurweb.models.account_type import USER_ID from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_comaintainer import PackageComaintainer +from aurweb.models.package_request import PackageRequest +from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User from aurweb.redis import redis_connection from aurweb.testing import setup_test_db from aurweb.testing.html import parse_root +from aurweb.testing.requests import Request client = TestClient(app) @@ -26,7 +30,9 @@ def setup(): yield setup_test_db( User.__tablename__, Package.__tablename__, - PackageBase.__tablename__ + PackageBase.__tablename__, + PackageComaintainer.__tablename__, + PackageRequest.__tablename__ ) @@ -149,3 +155,74 @@ def test_homepage_updates(redis, packages): for i, expected in enumerate(expectations): pkgname = updates[i].xpath('./td/a').pop(0) assert pkgname.text.strip() == expected + + +def test_homepage_dashboard(redis, packages, user): + # Create Comaintainer records for all of the packages. + for pkg in packages: + db.create(PackageComaintainer, PackageBase=pkg.PackageBase, + User=user, Priority=1, autocommit=False) + db.commit() + + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + response = request.get("/", cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + + # Assert some expectations that we end up getting all fifty + # packages in the "My Packages" table. + expectations = [f"pkg_{i}" for i in range(50 - 1, 0, -1)] + my_packages = root.xpath('//table[@id="my-packages"]/tbody/tr') + for i, expected in enumerate(expectations): + name, version, votes, pop, voted, notify, desc, maint \ + = my_packages[i].xpath('./td') + assert name.xpath('./a').pop(0).text.strip() == expected + + # Do the same for the Comaintained Packages table. + my_packages = root.xpath('//table[@id="comaintained-packages"]/tbody/tr') + for i, expected in enumerate(expectations): + name, version, votes, pop, voted, notify, desc, maint \ + = my_packages[i].xpath('./td') + assert name.xpath('./a').pop(0).text.strip() == expected + + +def test_homepage_dashboard_requests(redis, packages, user): + now = int(datetime.utcnow().timestamp()) + + pkg = packages[0] + reqtype = db.query(RequestType, RequestType.ID == DELETION_ID).first() + pkgreq = db.create(PackageRequest, PackageBase=pkg.PackageBase, + PackageBaseName=pkg.PackageBase.Name, + User=user, Comments=str(), + ClosureComment=str(), RequestTS=now, + RequestType=reqtype) + + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + response = request.get("/", cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + request = root.xpath('//table[@id="pkgreq-results"]/tbody/tr').pop(0) + pkgname = request.xpath('./td/a').pop(0) + assert pkgname.text.strip() == pkgreq.PackageBaseName + + +def test_homepage_dashboard_flagged_packages(redis, packages, user): + # Set the first Package flagged by setting its OutOfDateTS column. + pkg = packages[0] + pkg.PackageBase.OutOfDateTS = int(datetime.utcnow().timestamp()) + db.commit() + + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + response = request.get("/", cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + # Check to see that the package showed up in the Flagged Packages table. + root = parse_root(response.text) + flagged_pkg = root.xpath('//table[@id="flagged-packages"]/tbody/tr').pop(0) + flagged_name = flagged_pkg.xpath('./td/a').pop(0) + assert flagged_name.text.strip() == pkg.Name From f086457741574867f30109dc58ae656684968e2e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 17 Aug 2021 21:52:59 -0700 Subject: [PATCH 0829/1891] aurweb.redis: Reduce logging Signed-off-by: Kevin Morris --- aurweb/redis.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/redis.py b/aurweb/redis.py index 6b8dede4..6d3cff38 100644 --- a/aurweb/redis.py +++ b/aurweb/redis.py @@ -36,13 +36,13 @@ def redis_connection(): # pragma: no cover # If we haven't initialized redis yet, construct a pool. if disabled: - logger.debug("Initializing fake Redis instance.") if pool is None: + logger.debug("Initializing fake Redis instance.") pool = FakeConnectionPool() return pool.handle else: - logger.debug("Initializing real Redis instance.") if pool is None: + logger.debug("Initializing real Redis instance.") redis_addr = aurweb.config.get("options", "redis_address") pool = ConnectionPool.from_url(redis_addr) From 6eafb457ec18cefd9341e27d84b7be76abbcca29 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 20 Aug 2021 16:36:10 -0700 Subject: [PATCH 0830/1891] aurweb.util: fix code style violation Signed-off-by: Kevin Morris --- aurweb/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index d4a0b221..860bdd12 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -20,8 +20,8 @@ import aurweb.config def make_random_string(length): - return ''.join(random.choices(string.ascii_lowercase + - string.digits, k=length)) + return ''.join(random.choices(string.ascii_lowercase + + string.digits, k=length)) def make_nonce(length: int = 8): From a72ab61902961562048f487c2e102249b4a33964 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 25 Aug 2021 16:34:37 -0700 Subject: [PATCH 0831/1891] [FastAPI] fix dashboard template Some columns should only be shown when a user is authenticated. Signed-off-by: Kevin Morris --- templates/partials/packages/results.html | 52 ++++++++++++------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/templates/partials/packages/results.html b/templates/partials/packages/results.html index 005bd5a9..80029d10 100644 --- a/templates/partials/packages/results.html +++ b/templates/partials/packages/results.html @@ -6,8 +6,10 @@

    {{ "Version" | tr }} {{ "Votes" | tr }} {{ "Popularity" | tr }}{{ "Voted" | tr }}{{ "Notify" | tr }}{{ "Voted" | tr }}{{ "Notify" | tr }}{{ "Description" | tr }} {{ "Maintainer" | tr }}
    {{ pkg.Version }}{{ pkg.Version }}{{ pkg.PackageBase.NumVotes }} - {{ pkg.PackageBase.Popularity | number_format(2) }} - - - {% if request.user.voted_for(pkg) %} - {{ "Yes" | tr }} - {% endif %} - - - {% if request.user.notified(pkg) %} - {{ "Yes" | tr }} - {% endif %} - {{ pkg.PackageBase.Popularity | number_format(2) }} + + {% if request.user.voted_for(pkg) %} + {{ "Yes" | tr }} + {% endif %} + + + {% if request.user.notified(pkg) %} + {{ "Yes" | tr }} + {% endif %} + {{ pkg.Description or '' }} {% set maintainer = pkg.PackageBase.Maintainer %} - - {{ maintainer.Username }} - + {% if maintainer %} + + {{ maintainer.Username }} + + {% else %} + {{ "orphan" | tr }} + {% endif %}
    {{ "Proposal" | tr }} {% set off_qs = "%s=%d" | format(off_param, off) %} - {% set by_qs = "%s=%s" | format(by_param, by_next | urlencode) %} + {% set by_qs = "%s=%s" | format(by_param, by_next | quote_plus) %} {{ "Start" | tr }} @@ -95,7 +95,7 @@ {% if off > 0 %} {% set off_qs = "%s=%d" | format(off_param, off - 10) %} - {% set by_qs = "%s=%s" | format(by_param, by | urlencode) %} + {% set by_qs = "%s=%s" | format(by_param, by | quote_plus) %} ‹ Back @@ -104,7 +104,7 @@ {% if off < total_votes - pp %} {% set off_qs = "%s=%d" | format(off_param, off + 10) %} - {% set by_qs = "%s=%s" | format(by_param, by | urlencode) %} + {% set by_qs = "%s=%s" | format(by_param, by | quote_plus) %} Next › From a114bd3e16e5df00cc2542e37cedb82bf99e9a84 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 28 Aug 2021 16:33:33 -0700 Subject: [PATCH 0847/1891] aurweb.util: add extend_query and to_qs helpers The first addition, extend_query, can be used to take an existing query parameter dictionary and inject an *additions as replacement key/value pairs. The second, to_qs, converts a query parameter dictionary to a query string in the form "a=b&c=d". These two functions simplify and make dedupe_qs and quote_plus more efficient in terms of constructing custom query string overrides. Signed-off-by: Kevin Morris --- aurweb/util.py | 14 +++++++++++++- test/test_util.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/aurweb/util.py b/aurweb/util.py index 494a988d..e993c440 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -8,7 +8,8 @@ import string from collections import OrderedDict from datetime import datetime -from urllib.parse import quote_plus, urlparse +from typing import Any, Dict +from urllib.parse import quote_plus, urlencode, urlparse from zoneinfo import ZoneInfo import fastapi @@ -148,6 +149,17 @@ def dedupe_qs(query_string: str, *additions): return '&'.join([f"{k}={quote_plus(v)}" for k, v in reversed(qs.items())]) +def extend_query(query: Dict[str, Any], *additions) -> Dict[str, Any]: + """ Add additionally key value pairs to query. """ + for k, v in list(additions): + query[k] = v + return query + + +def to_qs(query: Dict[str, Any]) -> str: + return urlencode(query, doseq=True) + + def get_vote(voteinfo, request: fastapi.Request): from aurweb.models.tu_vote import TUVote return voteinfo.tu_votes.filter(TUVote.User == request.user).first() diff --git a/test/test_util.py b/test/test_util.py index f54a98a0..06fc08d3 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -35,3 +35,18 @@ def test_dedupe_qs(): def test_number_format(): assert util.number_format(0.222, 2) == "0.22" assert util.number_format(0.226, 2) == "0.23" + + +def test_extend_query(): + """ Test extension of a query via extend_query. """ + query = {"a": "b"} + extended = util.extend_query(query, ("a", "c"), ("b", "d")) + assert extended.get("a") == "c" + assert extended.get("b") == "d" + + +def test_to_qs(): + """ Test conversion from a query dictionary to a query string. """ + query = {"a": "b", "c": [1, 2, 3]} + qs = util.to_qs(query) + assert qs == "a=b&c=1&c=2&c=3" From c9374732c013ba336cd1b3d6b3991fece9b2c934 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 31 Aug 2021 14:25:58 -0700 Subject: [PATCH 0848/1891] add filters for extend_query, to_qs New jinja2 filters: * `extend_query` -> `aurweb.util.extend_query` * `urlencode` -> `aurweb.util.to_qs` Signed-off-by: Kevin Morris --- aurweb/templates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/templates.py b/aurweb/templates.py index a648d5a1..4a9927fb 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -31,6 +31,8 @@ _env.filters["tn"] = l10n.tn _env.filters["dt"] = util.timestamp_to_datetime _env.filters["as_timezone"] = util.as_timezone _env.filters["dedupe_qs"] = util.dedupe_qs +_env.filters["extend_query"] = util.extend_query +_env.filters["urlencode"] = util.to_qs _env.filters["quote_plus"] = quote_plus _env.filters["get_vote"] = util.get_vote _env.filters["number_format"] = util.number_format From 210e459ba90e274e585a6928585aa2362d168944 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 31 Aug 2021 14:27:16 -0700 Subject: [PATCH 0849/1891] Eradicate the `dedupe_qs` filter The new `extend_query` and `urlencode` filters are way cleaner ways to achieve what we did with `dedupe_qs`. Signed-off-by: Kevin Morris --- aurweb/routers/trusted_user.py | 13 ++++++------- aurweb/templates.py | 1 - aurweb/util.py | 28 ++-------------------------- templates/partials/tu/proposals.html | 6 +++--- test/test_util.py | 16 ---------------- 5 files changed, 11 insertions(+), 53 deletions(-) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index fd5ebb04..61cfec6c 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -5,7 +5,6 @@ import typing from datetime import datetime from http import HTTPStatus -from urllib.parse import quote_plus from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import RedirectResponse, Response @@ -106,12 +105,12 @@ async def trusted_user(request: Request, context["current_by_next"] = "asc" if current_by == "desc" else "desc" context["past_by_next"] = "asc" if past_by == "desc" else "desc" - context["q"] = '&'.join([ - f"coff={current_off}", - f"cby={quote_plus(current_by)}", - f"poff={past_off}", - f"pby={quote_plus(past_by)}" - ]) + context["q"] = { + "coff": current_off, + "cby": current_by, + "poff": past_off, + "pby": past_by + } return render_template(request, "tu/index.html", context) diff --git a/aurweb/templates.py b/aurweb/templates.py index 4a9927fb..6a1b6a1c 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -30,7 +30,6 @@ _env.filters["tn"] = l10n.tn # Utility filters. _env.filters["dt"] = util.timestamp_to_datetime _env.filters["as_timezone"] = util.as_timezone -_env.filters["dedupe_qs"] = util.dedupe_qs _env.filters["extend_query"] = util.extend_query _env.filters["urlencode"] = util.to_qs _env.filters["quote_plus"] = quote_plus diff --git a/aurweb/util.py b/aurweb/util.py index e993c440..f9181811 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -6,10 +6,9 @@ import re import secrets import string -from collections import OrderedDict from datetime import datetime from typing import Any, Dict -from urllib.parse import quote_plus, urlencode, urlparse +from urllib.parse import urlencode, urlparse from zoneinfo import ZoneInfo import fastapi @@ -126,31 +125,8 @@ def as_timezone(dt: datetime, timezone: str): return dt.astimezone(tz=ZoneInfo(timezone)) -def dedupe_qs(query_string: str, *additions): - """ Dedupe keys found in a query string by rewriting it without - duplicates found while iterating from the end to the beginning, - using an ordered memo to track keys found and persist locations. - - That is, query string 'a=1&b=1&a=2' will be deduped and converted - to 'b=1&a=2'. - - :param query_string: An HTTP URL query string. - :param *additions: Optional additional fields to add to the query string. - :return: Deduped query string, including *additions at the tail. - """ - for addition in list(additions): - query_string += f"&{addition}" - - qs = OrderedDict() - for item in reversed(query_string.split('&')): - key, value = item.split('=') - if key not in qs: - qs[key] = value - return '&'.join([f"{k}={quote_plus(v)}" for k, v in reversed(qs.items())]) - - def extend_query(query: Dict[str, Any], *additions) -> Dict[str, Any]: - """ Add additionally key value pairs to query. """ + """ Add additional key value pairs to query. """ for k, v in list(additions): query[k] = v return query diff --git a/templates/partials/tu/proposals.html b/templates/partials/tu/proposals.html index ab90444e..40eba22b 100644 --- a/templates/partials/tu/proposals.html +++ b/templates/partials/tu/proposals.html @@ -24,7 +24,7 @@ {% set off_qs = "%s=%d" | format(off_param, off) %} {% set by_qs = "%s=%s" | format(by_param, by_next | quote_plus) %} - + {{ "Start" | tr }} {{ pkg.PackageBase.Popularity | number_format(2) }} - - {% if request.user.voted_for(pkg) %} + {# If I voted, display "Yes". #} + {% if pkg.PackageBase.ID in votes %} {{ "Yes" | tr }} {% endif %} - - {% if request.user.notified(pkg) %} + {# If I'm being notified, display "Yes". #} + {% if pkg.PackageBase.ID in notified %} {{ "Yes" | tr }} {% endif %}
    + + + {% if request.user.is_authenticated() %} + + {% endif %} + + + + + {% if request.user.is_authenticated() %} + + + {% endif %} + + + + + + {% for pkg in packages %} + {% set flagged = pkg.PackageBase.OutOfDateTS %} + + {% if request.user.is_authenticated() %} + + {% endif %} + + {% if flagged %} + + {% else %} + + {% endif %} + + + {% if request.user.is_authenticated() %} + + + {% endif %} + + + + {% endfor %} + +
    + {% set order = SO %} + {% if SB == "n" %} + {% set order = "d" if order == "a" else "a" %} + {% endif %} + + {{ "Name" | tr }} + + {{ "Version" | tr }} + {% set order = SO %} + {% if SB == "v" %} + {% set order = "d" if order == "a" else "a" %} + {% endif %} + + {{ "Votes" | tr }} + + + {% set order = SO %} + {% if SB == "p" %} + {% set order = "d" if order == "a" else "a" %} + {% endif %} + {{ "Popularity" | tr }}? + + {% set order = SO %} + {% if SB == "w" %} + {% set order = "d" if order == "a" else "a" %} + {% endif %} + + {{ "Voted" | tr }} + + + {% set order = SO %} + {% if SB == "o" %} + {% set order = "d" if order == "a" else "a" %} + {% endif %} + + {{ "Notify" | tr }} + + {{ "Description" | tr }} + {% set order = SO %} + {% if SB == "m" %} + {% set order = "d" if order == "a" else "a" %} + {% endif %} + + {{ "Maintainer" | tr }} + +
    + + + + {{ pkg.Name }} + + {{ pkg.Version }}{{ pkg.Version }}{{ pkg.PackageBase.NumVotes }} + {{ pkg.PackageBase.Popularity | number_format(2) }} + + {% if pkg.PackageBase.ID in voted %} + {{ "Yes" | tr }} + {% endif %} + + {% if pkg.PackageBase.ID in notified %} + {{ "Yes" | tr }} + {% endif %} + {{ pkg.Description or '' }} + {% set maintainer = pkg.PackageBase.Maintainer %} + {% if maintainer %} + + {{ maintainer.Username }} + + {% else %} + {{ "orphan" | tr }} + {% endif %} +
    diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 8a468c15..fb45af88 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1,5 +1,8 @@ +import re + from datetime import datetime from http import HTTPStatus +from typing import List import pytest @@ -11,11 +14,14 @@ from aurweb.models.dependency_type import DependencyType from aurweb.models.official_provider import OfficialProvider from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_comment import PackageComment from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_keyword import PackageKeyword +from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation from aurweb.models.package_request import PackageRequest +from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import PROVIDES_ID, RelationType from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User @@ -64,6 +70,9 @@ def setup(): PackageDependency.__tablename__, PackageRelation.__tablename__, PackageKeyword.__tablename__, + PackageVote.__tablename__, + PackageNotification.__tablename__, + PackageComaintainer.__tablename__, OfficialProvider.__tablename__ ) @@ -101,16 +110,41 @@ def maintainer() -> User: @pytest.fixture def package(maintainer: User) -> Package: """ Yield a Package created by user. """ + now = int(datetime.utcnow().timestamp()) with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", - Maintainer=maintainer) + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now) package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) yield package +@pytest.fixture +def packages(maintainer: User) -> List[Package]: + """ Yield 55 packages named pkg_0 .. pkg_54. """ + packages_ = [] + now = int(datetime.utcnow().timestamp()) + with db.begin(): + for i in range(55): + pkgbase = db.create(PackageBase, + Name=f"pkg_{i}", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now) + package = db.create(Package, + PackageBase=pkgbase, + Name=f"pkg_{i}") + packages_.append(package) + + yield packages_ + + def test_package_not_found(client: TestClient): with client as request: resp = request.get("/packages/not_found") @@ -133,7 +167,7 @@ def test_package_official_not_found(client: TestClient, package: Package): def test_package(client: TestClient, package: Package): - """ Test a single /packages/{name} route. """ + """ Test a single / packages / {name} route. """ with client as request: resp = request.get(package_endpoint(package)) @@ -376,3 +410,505 @@ def test_pkgbase(client: TestClient, package: Package): pkgs = root.findall('.//div[@id="pkgs"]/ul/li/a') for i, name in enumerate(expected): assert pkgs[i].text.strip() == name + + +def test_packages(client: TestClient, packages: List[Package]): + """ Test the / packages route with defaults. + + Defaults: + 50 results per page + offset of 0 + """ + with client as request: + response = request.get("/packages", params={ + "SeB": "X" # "X" isn't valid, defaults to "nd" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + stats = root.xpath('//div[@class="pkglist-stats"]/p')[0] + pager_text = re.sub(r'\s+', " ", stats.text.replace("\n", "").strip()) + assert pager_text == "55 packages found. Page 1 of 2." + + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 50 # Default per-page + + +def test_packages_search_by_name(client: TestClient, packages: List[Package]): + with client as request: + response = request.get("/packages", params={ + "SeB": "n", + "K": "pkg_" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 50 # Default per-page + + +def test_packages_search_by_exact_name(client: TestClient, + packages: List[Package]): + with client as request: + response = request.get("/packages", params={ + "SeB": "N", + "K": "pkg_" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + + # There is no package named exactly 'pkg_', we get 0 results. + assert len(rows) == 0 + + with client as request: + response = request.get("/packages", params={ + "SeB": "N", + "K": "pkg_1" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + + # There's just one package named 'pkg_1', we get 1 result. + assert len(rows) == 1 + + +def test_packages_search_by_pkgbase(client: TestClient, + packages: List[Package]): + with client as request: + response = request.get("/packages", params={ + "SeB": "b", + "K": "pkg_" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 50 + + +def test_packages_search_by_exact_pkgbase(client: TestClient, + packages: List[Package]): + with client as request: + response = request.get("/packages", params={ + "SeB": "B", + "K": "pkg_" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 0 + + with client as request: + response = request.get("/packages", params={ + "SeB": "B", + "K": "pkg_1" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + +def test_packages_search_by_keywords(client: TestClient, + packages: List[Package]): + # None of our packages have keywords, so this query should return nothing. + with client as request: + response = request.get("/packages", params={ + "SeB": "k", + "K": "testKeyword" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 0 + + # But now, let's create the keyword for the first package. + package = packages[0] + with db.begin(): + db.create(PackageKeyword, + PackageBase=package.PackageBase, + Keyword="testKeyword") + + # And request packages with that keyword, we should get 1 result. + with client as request: + response = request.get("/packages", params={ + "SeB": "k", + "K": "testKeyword" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + +def test_packages_search_by_maintainer(client: TestClient, + maintainer: User, + package: Package): + with client as request: + response = request.get("/packages", params={ + "SeB": "m", + "K": maintainer.Username + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + +def test_packages_search_by_comaintainer(client: TestClient, + maintainer: User, + package: Package): + # Nobody's a comaintainer yet. + with client as request: + response = request.get("/packages", params={ + "SeB": "c", + "K": maintainer.Username + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 0 + + # Now, we create a comaintainer. + with db.begin(): + db.create(PackageComaintainer, + PackageBase=package.PackageBase, + User=maintainer, + Priority=1) + + # Then test that it's returned by our search. + with client as request: + response = request.get("/packages", params={ + "SeB": "c", + "K": maintainer.Username + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + +def test_packages_search_by_co_or_maintainer(client: TestClient, + maintainer: User, + package: Package): + with client as request: + response = request.get("/packages", params={ + "SeB": "M", + "SB": "BLAH", # Invalid SB; gets reset to default "n". + "K": maintainer.Username + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + with db.begin(): + user = db.create(User, Username="comaintainer", + Email="comaintainer@example.org", + Passwd="testPassword") + db.create(PackageComaintainer, + PackageBase=package.PackageBase, + User=user, + Priority=1) + + with client as request: + response = request.get("/packages", params={ + "SeB": "M", + "K": user.Username + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + +def test_packages_search_by_submitter(client: TestClient, + maintainer: User, + package: Package): + with client as request: + response = request.get("/packages", params={ + "SeB": "s", + "K": maintainer.Username + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + +def test_packages_sort_by_votes(client: TestClient, + maintainer: User, + packages: List[Package]): + # Set the first package's NumVotes to 1. + with db.begin(): + packages[0].PackageBase.NumVotes = 1 + + # Test that, by default, the first result is what we just set above. + with client as request: + response = request.get("/packages", params={ + "SB": "v" # Votes. + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + votes = rows[0].xpath('./td')[2] # The third column of the first row. + assert votes.text.strip() == "1" + + # Now, test that with an ascending order, the last result is + # the one we set, since the default (above) is descending. + with client as request: + response = request.get("/packages", params={ + "SB": "v", # Votes. + "SO": "a", # Ascending. + "O": "50" # Second page. + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + votes = rows[-1].xpath('./td')[2] # The third column of the last row. + assert votes.text.strip() == "1" + + +def test_packages_sort_by_popularity(client: TestClient, + maintainer: User, + packages: List[Package]): + # Set the first package's Popularity to 0.50. + with db.begin(): + packages[0].PackageBase.Popularity = "0.50" + + # Test that, by default, the first result is what we just set above. + with client as request: + response = request.get("/packages", params={ + "SB": "p" # Popularity + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + pop = rows[0].xpath('./td')[3] # The fourth column of the first row. + assert pop.text.strip() == "0.50" + + +def test_packages_sort_by_voted(client: TestClient, + maintainer: User, + packages: List[Package]): + now = int(datetime.utcnow().timestamp()) + with db.begin(): + db.create(PackageVote, PackageBase=packages[0].PackageBase, + User=maintainer, VoteTS=now) + + # Test that, by default, the first result is what we just set above. + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + response = request.get("/packages", params={ + "SB": "w", # Voted + "SO": "d" # Descending, Voted first. + }, cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + voted = rows[0].xpath('./td')[5] # The sixth column of the first row. + assert voted.text.strip() == "Yes" + + # Conversely, everything else was not voted on. + voted = rows[1].xpath('./td')[5] # The sixth column of the second row. + assert voted.text.strip() == str() # Empty. + + +def test_packages_sort_by_notify(client: TestClient, + maintainer: User, + packages: List[Package]): + db.create(PackageNotification, + PackageBase=packages[0].PackageBase, + User=maintainer) + + # Test that, by default, the first result is what we just set above. + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + response = request.get("/packages", params={ + "SB": "o", # Voted + "SO": "d" # Descending, Voted first. + }, cookies=cookies) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + notify = rows[0].xpath('./td')[6] # The sixth column of the first row. + assert notify.text.strip() == "Yes" + + # Conversely, everything else was not voted on. + notify = rows[1].xpath('./td')[6] # The sixth column of the second row. + assert notify.text.strip() == str() # Empty. + + +def test_packages_sort_by_maintainer(client: TestClient, + maintainer: User, + package: Package): + """ Sort a package search by the maintainer column. """ + + # Create a second package, so the two can be ordered and checked. + with db.begin(): + maintainer2 = db.create(User, Username="maintainer2", + Email="maintainer2@example.org", + Passwd="testPassword") + base2 = db.create(PackageBase, Name="pkg_2", Maintainer=maintainer2, + Submitter=maintainer2, Packager=maintainer2) + db.create(Package, Name="pkg_2", PackageBase=base2) + + # Check the descending order route. + with client as request: + response = request.get("/packages", params={ + "SB": "m", + "SO": "d" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + col = rows[0].xpath('./td')[5].xpath('./a')[0] # Last column. + + assert col.text.strip() == maintainer.Username + + # On the other hand, with ascending, we should get reverse ordering. + with client as request: + response = request.get("/packages", params={ + "SB": "m", + "SO": "a" + }) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + col = rows[0].xpath('./td')[5].xpath('./a')[0] # Last column. + + assert col.text.strip() == maintainer2.Username + + +def test_packages_sort_by_last_modified(client: TestClient, + packages: List[Package]): + now = int(datetime.utcnow().timestamp()) + # Set the first package's ModifiedTS to be 1000 seconds before now. + package = packages[0] + with db.begin(): + package.PackageBase.ModifiedTS = now - 1000 + + with client as request: + response = request.get("/packages", params={ + "SB": "l", + "SO": "a" # Ascending; oldest modification first. + }) + assert response.status_code == int(HTTPStatus.OK) + + # We should have 50 (default per page) results. + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 50 + + # Let's assert that the first item returned was the one we modified above. + row = rows[0] + col = row.xpath('./td')[0].xpath('./a')[0] + assert col.text.strip() == package.Name + + +def test_packages_flagged(client: TestClient, maintainer: User, + packages: List[Package]): + package = packages[0] + + now = int(datetime.utcnow().timestamp()) + + with db.begin(): + package.PackageBase.OutOfDateTS = now + package.PackageBase.Flagger = maintainer + + with client as request: + response = request.get("/packages", params={ + "outdated": "on" + }) + assert response.status_code == int(HTTPStatus.OK) + + # We should only get one result from this query; the package we flagged. + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + with client as request: + response = request.get("/packages", params={ + "outdated": "off" + }) + assert response.status_code == int(HTTPStatus.OK) + + # In this case, we should get 54 results, which means that the first + # page will have 50 results (55 packages - 1 outdated = 54 not outdated). + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 50 + + +def test_packages_orphans(client: TestClient, packages: List[Package]): + package = packages[0] + with db.begin(): + package.PackageBase.Maintainer = None + + with client as request: + response = request.get("/packages", params={"submit": "Orphans"}) + assert response.status_code == int(HTTPStatus.OK) + + # We only have one orphan. Let's make sure that's what is returned. + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + +def test_packages_per_page(client: TestClient, maintainer: User): + """ Test the ability for /packages to deal with the PP query + argument specifications (50, 100, 250; default: 50). """ + with db.begin(): + for i in range(255): + base = db.create(PackageBase, Name=f"pkg_{i}", + Maintainer=maintainer, + Submitter=maintainer, + Packager=maintainer) + db.create(Package, PackageBase=base, Name=base.Name) + + # Test default case, PP of 50. + with client as request: + response = request.get("/packages", params={"PP": 50}) + assert response.status_code == int(HTTPStatus.OK) + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 50 + + # Alright, test the next case, PP of 100. + with client as request: + response = request.get("/packages", params={"PP": 100}) + assert response.status_code == int(HTTPStatus.OK) + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 100 + + # And finally, the last case, a PP of 250. + with client as request: + response = request.get("/packages", params={"PP": 250}) + assert response.status_code == int(HTTPStatus.OK) + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 250 diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index b36dbd4d..62179769 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -222,3 +222,10 @@ button[type="reset"] { text-align: right; } +input#search-action-submit { + width: 80px; +} + +.success { + color: green; +} From 7e589863561a0777f8feb9f4b11f505715d80841 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 20 Sep 2021 01:30:12 -0700 Subject: [PATCH 0883/1891] feat: add util/adduser.py database tooling script We'll need to add tests for these things at some point. However, I'd like to include this script in here immediately for ease of testing or administration in general. Signed-off-by: Kevin Morris --- util/adduser.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 util/adduser.py diff --git a/util/adduser.py b/util/adduser.py new file mode 100644 index 00000000..7e35d13d --- /dev/null +++ b/util/adduser.py @@ -0,0 +1,67 @@ +import argparse +import sys +import traceback + +from aurweb import db +from aurweb.models.account_type import AccountType +from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint +from aurweb.models.user import User + + +def parse_args(): + parser = argparse.ArgumentParser(description="aurweb-adduser options") + + parser.add_argument("-u", "--username", help="Username", required=True) + parser.add_argument("-e", "--email", help="Email", required=True) + parser.add_argument("-p", "--password", help="Password", required=True) + parser.add_argument("-r", "--realname", help="Real Name") + parser.add_argument("-i", "--ircnick", help="IRC Nick") + parser.add_argument("--pgp-key", help="PGP Key Fingerprint") + parser.add_argument("--ssh-pubkey", help="SSH PubKey") + + parser.add_argument("-t", "--type", help="Account Type", + choices=[ + "User", + "Trusted User", + "Developer", + "Trusted User & Developer" + ], default="User") + + return parser.parse_args() + + +def main(): + args = parse_args() + + type = db.query(AccountType, + AccountType.AccountType == args.type).first() + with db.begin(): + user = db.create(User, Username=args.username, + Email=args.email, Passwd=args.password, + RealName=args.realname, IRCNick=args.ircnick, + PGPKey=args.pgp_key, AccountType=type) + + if args.ssh_pubkey: + pubkey = args.ssh_pubkey.strip() + + # Remove host from the pubkey if it's there. + pubkey = ' '.join(pubkey.split(' ')[:2]) + + with db.begin(): + db.create(SSHPubKey, + User=user, + PubKey=pubkey, + Fingerprint=get_fingerprint(pubkey)) + + print(user.json()) + return 0 + + +if __name__ == "__main__": + e = 1 + try: + e = main() + except Exception: + traceback.print_exc() + e = 1 + sys.exit(e) From dc5dc233ec120ace46e870a057b632b4d5c8149c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 21 Sep 2021 00:01:39 -0700 Subject: [PATCH 0884/1891] .gitlab-ci.yml: add coverage regex This was required for the GitLab coverage badge to get the % of coverage. Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ffea5308..a8ddf08f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,6 +36,7 @@ test: - isort --check-only aurweb # Assert no isort violations in aurweb. - isort --check-only test # Assert no flake8 violations in test. - isort --check-only migrations # Assert no flake8 violations in migrations. + coverage: '/TOTAL.*\s+(\d+\%)/' artifacts: reports: cobertura: coverage.xml From fbd91f346a69e41f44407fc568343c469ea59460 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 22 Sep 2021 18:33:58 -0700 Subject: [PATCH 0885/1891] feat(FastAPI): add /pkgbase/{name}/voters (get) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 9 +++++++++ templates/pkgbase/voters.html | 27 +++++++++++++++++++++++++++ test/test_packages_routes.py | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 templates/pkgbase/voters.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 3eda2539..72cd8c99 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -195,3 +195,12 @@ async def package_base(request: Request, name: str) -> Response: context["packages"] = pkgbase.packages.all() return render_template(request, "pkgbase.html", context) + + +@router.get("/pkgbase/{name}/voters") +async def package_base_voters(request: Request, name: str) -> Response: + # Get the PackageBase. + pkgbase = get_pkgbase(name) + context = make_context(request, "Voters") + context["pkgbase"] = pkgbase + return render_template(request, "pkgbase/voters.html", context) diff --git a/templates/pkgbase/voters.html b/templates/pkgbase/voters.html new file mode 100644 index 00000000..be86f01f --- /dev/null +++ b/templates/pkgbase/voters.html @@ -0,0 +1,27 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    + {{ "Votes" | tr }} for + + {{ pkgbase.Name }} + +

    + +
    +
      + {% for pkg_vote in pkgbase.package_votes %} +
    • + + {{ pkg_vote.User.Username }} + + + {% set voted_at = pkg_vote.VoteTS | dt | as_timezone(timezone) %} + ({{ voted_at.strftime("%Y-%m-%d %H:%M") }}) +
    • + {% endfor %} +
    +
    +
    +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index fb45af88..2190dc18 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -912,3 +912,21 @@ def test_packages_per_page(client: TestClient, maintainer: User): root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') assert len(rows) == 250 + + +def test_pkgbase_voters(client: TestClient, maintainer: User, package: Package): + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/voters" + + now = int(datetime.utcnow().timestamp()) + with db.begin(): + db.create(PackageVote, User=maintainer, PackageBase=pkgbase, + VoteTS=now) + + with client as request: + resp = request.get(endpoint) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//div[@class="box"]//ul/li') + assert len(rows) == 1 From ad9997c48ff39d4412e888470b980330ea28e3ea Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 2 Oct 2021 12:59:49 -0700 Subject: [PATCH 0886/1891] feat(Docker): build aurweb:latest via docker-compose build Users can now build the required image by running (in the aurweb root): $ docker-compose build Signed-off-by: Kevin Morris --- docker-compose.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 309e95fe..8e2d91d8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,6 +22,7 @@ version: "3.8" services: ca: + build: . image: aurweb:latest init: true entrypoint: /docker/ca-entrypoint.sh @@ -30,6 +31,7 @@ services: - ./cache:/cache memcached: + build: . image: aurweb:latest init: true command: /docker/scripts/run-memcached.sh @@ -37,6 +39,7 @@ services: test: "bash /docker/health/memcached.sh" redis: + build: . image: aurweb:latest init: true entrypoint: /docker/redis-entrypoint.sh @@ -47,6 +50,7 @@ services: - "16379:6379" mariadb: + build: . image: aurweb:latest init: true entrypoint: /docker/mariadb-entrypoint.sh @@ -62,6 +66,7 @@ services: test: "bash /docker/health/mariadb.sh" mariadb_init: + build: . image: aurweb:latest init: true environment: @@ -73,6 +78,7 @@ services: condition: service_healthy git: + build: . image: aurweb:latest init: true environment: @@ -92,6 +98,7 @@ services: - ./cache:/cache smartgit: + build: . image: aurweb:latest init: true environment: @@ -109,6 +116,7 @@ services: - smartgit_run:/var/run/smartgit cgit-php: + build: . image: aurweb:latest init: true environment: @@ -124,6 +132,7 @@ services: - git_data:/aurweb/aur.git cgit-fastapi: + build: . image: aurweb:latest init: true environment: @@ -139,6 +148,7 @@ services: - git_data:/aurweb/aur.git php-fpm: + build: . image: aurweb:latest init: true environment: @@ -168,6 +178,7 @@ services: - "19000:9000" fastapi: + build: . image: aurweb:latest init: true environment: @@ -197,6 +208,7 @@ services: - "18000:8000" nginx: + build: . image: aurweb:latest init: true environment: @@ -229,6 +241,7 @@ services: - smartgit_run:/var/run/smartgit sharness: + build: . image: aurweb:latest init: true environment: @@ -252,6 +265,7 @@ services: - ./templates:/aurweb/templates pytest-mysql: + build: . image: aurweb:latest init: true environment: @@ -276,6 +290,7 @@ services: - ./templates:/aurweb/templates pytest-sqlite: + build: . image: aurweb:latest init: true environment: @@ -296,6 +311,7 @@ services: - ./templates:/aurweb/templates test: + build: . image: aurweb:latest init: true environment: From 3b1809e2ea8d7adcafaff09664569c75c35791e3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 2 Oct 2021 13:26:05 -0700 Subject: [PATCH 0887/1891] feat(Docker): allow custom certificates for fastapi/nginx Now, when a `./cache/production.{cert,key}.pem` pair is found, it is used in place of any certificates generated by the `ca` service. This allows users to customize the certificate that the FastAPI ASGI server uses as well as the front-end nginx certificates. Optional: - ./cache/production.cert.pem - ./cache/production.key.pem Fallback: - ./cache/localhost.cert.pem + ./cache/root.ca.pem (chain) - ./cache/localhost.key.pem Signed-off-by: Kevin Morris --- docker/config/nginx.conf | 8 ++++---- docker/nginx-entrypoint.sh | 20 +++++++++++++++++--- docker/scripts/run-fastapi.sh | 20 ++++++++++++++++---- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index 3a8de801..4288a57d 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -43,8 +43,8 @@ http { listen 8443 ssl http2; server_name localhost default_server; - ssl_certificate /etc/ssl/certs/localhost.cert.pem; - ssl_certificate_key /etc/ssl/private/localhost.key.pem; + ssl_certificate /etc/ssl/certs/web.cert.pem; + ssl_certificate_key /etc/ssl/private/web.key.pem; root /aurweb/web/html; index index.php; @@ -91,8 +91,8 @@ http { listen 8444 ssl http2; server_name localhost default_server; - ssl_certificate /etc/ssl/certs/localhost.cert.pem; - ssl_certificate_key /etc/ssl/private/localhost.key.pem; + ssl_certificate /etc/ssl/certs/web.cert.pem; + ssl_certificate_key /etc/ssl/private/web.key.pem; root /aurweb/web/html; diff --git a/docker/nginx-entrypoint.sh b/docker/nginx-entrypoint.sh index 226ded8f..63307948 100755 --- a/docker/nginx-entrypoint.sh +++ b/docker/nginx-entrypoint.sh @@ -1,6 +1,16 @@ #!/bin/bash set -eou pipefail +# If production.{cert,key}.pem exists, prefer them. This allows +# user customization of the certificates that FastAPI uses. +# Otherwise, fallback to localhost.{cert,key}.pem, generated by `ca`. + +CERT=/cache/production.cert.pem +KEY=/cache/production.key.pem + +DEST_CERT=/etc/ssl/certs/web.cert.pem +DEST_KEY=/etc/ssl/private/web.key.pem + # Setup a config for our mysql db. cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config @@ -12,9 +22,13 @@ sed -ri 's/^;?(password) = .+/\1 = aur/' conf/config sed -ri "s|^(aur_location) = .+|\1 = https://localhost:8444|" conf/config sed -ri 's/^(disable_http_login) = .+/\1 = 1/' conf/config -cat /cache/localhost.cert.pem /cache/ca.root.pem \ - > /etc/ssl/certs/localhost.cert.pem -cp -vf /cache/localhost.key.pem /etc/ssl/private/localhost.key.pem +if [ -f "$CERT" ]; then + cp -vf "$CERT" "$DEST_CERT" + cp -vf "$KEY" "$DEST_KEY" +else + cat /cache/localhost.cert.pem /cache/ca.root.pem > "$DEST_CERT" + cp -vf /cache/localhost.key.pem "$DEST_KEY" +fi cp -vf /docker/config/nginx.conf /etc/nginx/nginx.conf diff --git a/docker/scripts/run-fastapi.sh b/docker/scripts/run-fastapi.sh index bb1a01a7..4dcc1d96 100755 --- a/docker/scripts/run-fastapi.sh +++ b/docker/scripts/run-fastapi.sh @@ -1,17 +1,29 @@ #!/bin/bash +CERT=/cache/localhost.cert.pem +KEY=/cache/localhost.key.pem + +# If production.{cert,key}.pem exists, prefer them. This allows +# user customization of the certificates that FastAPI uses. +if [ -f /cache/production.cert.pem ]; then + CERT=/cache/production.cert.pem +fi +if [ -f /cache/production.key.pem ]; then + KEY=/cache/production.key.pem +fi + if [ "$1" == "uvicorn" ] || [ "$1" == "" ]; then exec uvicorn --reload \ - --ssl-certfile /cache/localhost.cert.pem \ - --ssl-keyfile /cache/localhost.key.pem \ + --ssl-certfile "$CERT" \ + --ssl-keyfile "$KEY" \ --log-config /docker/logging.conf \ --host "0.0.0.0" \ --port 8000 \ aurweb.asgi:app else exec hypercorn --reload \ - --certfile /cache/localhost.cert.pem \ - --keyfile /cache/localhost.key.pem \ + --certfile "$CERT" \ + --keyfile "$KEY" \ --log-config /docker/logging.conf \ -b "0.0.0.0:8000" \ aurweb.asgi:app From ef0c2d5a285f185143ec8d5c0632f53f28c230a6 Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Sat, 2 Oct 2021 23:54:10 +0200 Subject: [PATCH 0888/1891] magic --- docker-compose.override.yml | 47 +++++++++++++++++++++++++++++++++++++ docker-compose.prod.yml | 40 +++++++++++++++++++++++++++++++ docker-compose.yml | 39 ++++-------------------------- 3 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 docker-compose.override.yml create mode 100644 docker-compose.prod.yml diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 00000000..c0bee88c --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,47 @@ +services: + ca: + volumes: + - ./cache:/cache + + git: + volumes: + - git_data:/aurweb/aur.git + - ./cache:/cache + + smartgit: + volumes: + - git_data:/aurweb/aur.git + - ./cache:/cache + - smartgit_run:/var/run/smartgit + + php-fpm: + volumes: + - ./cache:/cache + - ./aurweb:/aurweb/aurweb + - ./migrations:/aurweb/migrations + - ./test:/aurweb/test + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib + - ./templates:/aurweb/templates + + fastapi: + volumes: + - ./cache:/cache + - ./aurweb:/aurweb/aurweb + - ./migrations:/aurweb/migrations + - ./test:/aurweb/test + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib + - ./templates:/aurweb/templates + + nginx: + volumes: + - git_data:/aurweb/aur.git + - ./cache:/cache + - ./logs:/var/log/nginx + - ./web/html:/aurweb/web/html + - ./web/template:/aurweb/web/template + - ./web/lib:/aurweb/web/lib + - smartgit_run:/var/run/smartgit diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 00000000..1addecb2 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,40 @@ +version: "3.8" + +services: + ca: + volumes: + - cache:/cache + + git: + volumes: + - git_data:/aurweb/aur.git + - cache:/cache + + smartgit: + volumes: + - git_data:/aurweb/aur.git + - cache:/cache + - smartgit_run:/var/run/smartgit + + php-fpm: + volumes: + - cache:/cache + + fastapi: + volumes: + - cache:/cache + + nginx: + volumes: + - git_data:/aurweb/aur.git + - cache:/cache + - logs:/var/log/nginx + - smartgit_run:/var/run/smartgit + +volumes: + mariadb_run: {} # Share /var/run/mysqld/mysqld.sock + mariadb_data: {} # Share /var/lib/mysql + git_data: {} # Share aurweb/aur.git + smartgit_run: {} + cache: {} + logs: {} diff --git a/docker-compose.yml b/docker-compose.yml index 8e2d91d8..f19485e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,8 +27,6 @@ services: init: true entrypoint: /docker/ca-entrypoint.sh command: echo - volumes: - - ./cache:/cache memcached: build: . @@ -93,9 +91,6 @@ services: depends_on: mariadb_init: condition: service_started - volumes: - - git_data:/aurweb/aur.git - - ./cache:/cache smartgit: build: . @@ -110,10 +105,6 @@ services: depends_on: mariadb: condition: service_healthy - volumes: - - git_data:/aurweb/aur.git - - ./cache:/cache - - smartgit_run:/var/run/smartgit cgit-php: build: . @@ -165,15 +156,6 @@ services: condition: service_healthy memcached: condition: service_healthy - volumes: - - ./cache:/cache - - ./aurweb:/aurweb/aurweb - - ./migrations:/aurweb/migrations - - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - ./templates:/aurweb/templates ports: - "19000:9000" @@ -195,15 +177,6 @@ services: condition: service_healthy redis: condition: service_healthy - volumes: - - ./cache:/cache - - ./aurweb:/aurweb/aurweb - - ./migrations:/aurweb/migrations - - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - ./templates:/aurweb/templates ports: - "18000:8000" @@ -231,18 +204,11 @@ services: condition: service_healthy php-fpm: condition: service_healthy - volumes: - - git_data:/aurweb/aur.git - - ./cache:/cache - - ./logs:/var/log/nginx - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - smartgit_run:/var/run/smartgit sharness: build: . image: aurweb:latest + profiles: ["dev"] init: true environment: - AUR_CONFIG=conf/config.sqlite @@ -267,6 +233,7 @@ services: pytest-mysql: build: . image: aurweb:latest + profiles: ["dev"] init: true environment: - AUR_CONFIG=conf/config @@ -292,6 +259,7 @@ services: pytest-sqlite: build: . image: aurweb:latest + profiles: ["dev"] init: true environment: - AUR_CONFIG=conf/config.sqlite @@ -313,6 +281,7 @@ services: test: build: . image: aurweb:latest + profiles: ["dev"] init: true environment: - AUR_CONFIG=conf/config From 438080827ab7e3700ad982b91d177ec6cf20dcc9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 2 Oct 2021 15:13:14 -0700 Subject: [PATCH 0889/1891] fix(Docker): add production config overrides Additionally, `up -d` will no longer run tests unless `--profile dev` is specified by the Docker user. People should now be running docker with two files: $ docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d nginx $ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run test Contributed by @klausenbusk. Thanks! From a3cb81962f6ad29e28f15102cff4aaba4f4b21db Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 2 Oct 2021 16:18:18 -0700 Subject: [PATCH 0890/1891] add: added aur_request_ml setting to config.dev For the dev environment, we use a no-op address. We don't want to be spamming aur-requests with development notifications. Signed-off-by: Kevin Morris --- conf/config.dev | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/config.dev b/conf/config.dev index 94a9630b..9f837171 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -35,6 +35,7 @@ cache = none memcache_servers = memcached:11211 ; If cache = 'redis' this address is used to connect to Redis. redis_address = redis://127.0.0.1 +aur_request_ml = aur-requests@example-noop.org [notifications] ; For development/testing, use /usr/bin/sendmail From 4abbf9a917a381141d7adce142df5f158325354c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 2 Oct 2021 16:34:34 -0700 Subject: [PATCH 0891/1891] fix: use @localhost for dev email addresses Signed-off-by: Kevin Morris --- conf/config.dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.dev b/conf/config.dev index 9f837171..ec0b33dc 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -35,7 +35,7 @@ cache = none memcache_servers = memcached:11211 ; If cache = 'redis' this address is used to connect to Redis. redis_address = redis://127.0.0.1 -aur_request_ml = aur-requests@example-noop.org +aur_request_ml = aur-requests@localhost [notifications] ; For development/testing, use /usr/bin/sendmail From f849e8b696416933282185df2d7581890e748f5a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 27 Sep 2021 13:49:33 -0700 Subject: [PATCH 0892/1891] change(FastAPI): allow User.notified to accept a Package OR PackageBase In addition, shorten the `package_notifications` relationship to `notifications`. Signed-off-by: Kevin Morris --- aurweb/auth.py | 2 +- aurweb/models/package_notification.py | 4 ++-- aurweb/models/user.py | 22 +++++++++++++++++++--- aurweb/routers/packages.py | 4 +--- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 2e6674b0..19c3a276 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -40,7 +40,7 @@ class AnonymousUser: ssh_pub_key = None # Add stubbed relationship backrefs. - package_notifications = StubQuery() + notifications = StubQuery() package_votes = StubQuery() # A nonce attribute, needed for all browser sessions; set in __init__. diff --git a/aurweb/models/package_notification.py b/aurweb/models/package_notification.py index ab23a212..803c0496 100644 --- a/aurweb/models/package_notification.py +++ b/aurweb/models/package_notification.py @@ -15,7 +15,7 @@ class PackageNotification(Base): Integer, ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False) User = relationship( - "User", backref=backref("package_notifications", lazy="dynamic"), + "User", backref=backref("notifications", lazy="dynamic"), foreign_keys=[UserID]) PackageBaseID = Column( @@ -23,7 +23,7 @@ class PackageNotification(Base): nullable=False) PackageBase = relationship( "PackageBase", - backref=backref("package_notifications", lazy="dynamic"), + backref=backref("notifications", lazy="dynamic"), foreign_keys=[PackageBaseID]) __mapper_args__ = {"primary_key": [UserID, PackageBaseID]} diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 28aa613e..5f848304 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -191,10 +191,26 @@ class User(Base): ).scalar()) def notified(self, package) -> bool: - """ Is this User being notified about package? """ + """ Is this User being notified about package (or package base)? + + :param package: Package or PackageBase instance + :return: Boolean indicating state of package notification + in relation to this User + """ + from aurweb.models.package import Package + from aurweb.models.package_base import PackageBase from aurweb.models.package_notification import PackageNotification - return bool(package.PackageBase.package_notifications.filter( - PackageNotification.UserID == self.ID + + query = None + if isinstance(package, Package): + query = package.PackageBase.notifications + elif isinstance(package, PackageBase): + query = package.notifications + + # Run an exists() query where a pkgbase-related + # PackageNotification exists for self (a user). + return bool(db.query( + query.filter(PackageNotification.UserID == self.ID).exists() ).scalar()) def packages(self): diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 72cd8c99..aa20e5fa 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -127,9 +127,7 @@ async def make_single_context(request: Request, context["comments"] = pkgbase.comments context["is_maintainer"] = (request.user.is_authenticated() and request.user.ID == pkgbase.MaintainerUID) - context["notified"] = request.user.package_notifications.filter( - PackageNotification.PackageBaseID == pkgbase.ID - ).scalar() + context["notified"] = request.user.notified(pkgbase) context["out_of_date"] = bool(pkgbase.OutOfDateTS) From 5e95cfbc8a844c11682db57186ac01d9732e631d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 27 Sep 2021 14:58:07 -0700 Subject: [PATCH 0893/1891] fix(FastAPI): get_pkgbase -> get_pkg_or_base `get_pkgbase` has been replaced with `get_pkg_or_base`, which is quite similar, but it does take a new `cls` keyword argument which is to be the model class which we search for via its `Name` column. Additionally, this change fixes a bug in the `/packages/{name}` route by supplying the Package object in question to the context and modifying the template to use it instead of a hacky through-base workaround. Examples: pkgbase = get_pkg_or_base("some_pkgbase_name", PackageBase) pkg = get_pkg_or_base("some_package_name", Package) Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 22 +++++++++++----------- aurweb/routers/packages.py | 11 +++++++---- templates/packages/show.html | 2 +- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 18ac7a5a..696c158f 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -1,6 +1,6 @@ from collections import defaultdict from http import HTTPStatus -from typing import Dict, List +from typing import Dict, List, Union import orjson @@ -101,24 +101,24 @@ def provides_list(package: Package, depname: str) -> list: return string -def get_pkgbase(name: str) -> PackageBase: +def get_pkg_or_base(name: str, cls: Union[Package, PackageBase] = PackageBase): """ Get a PackageBase instance by its name or raise a 404 if - it can't be foudn in the database. + it can't be found in the database. - :param name: PackageBase.Name - :raises HTTPException: With status code 404 if PackageBase doesn't exist - :return: PackageBase instance + :param name: {Package,PackageBase}.Name + :raises HTTPException: With status code 404 if record doesn't exist + :return: {Package,PackageBase} instance """ - pkgbase = db.query(PackageBase).filter(PackageBase.Name == name).first() - if not pkgbase: - raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) - provider = db.query(OfficialProvider).filter( OfficialProvider.Name == name).first() if provider: raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) - return pkgbase + instance = db.query(cls).filter(cls.Name == name).first() + if cls == PackageBase and not instance: + raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) + + return instance @register_filter("out_of_date") diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index aa20e5fa..8fd7717b 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -23,7 +23,7 @@ from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID from aurweb.packages.search import PackageSearch -from aurweb.packages.util import get_pkgbase, query_notified, query_voted +from aurweb.packages.util import get_pkg_or_base, query_notified, query_voted from aurweb.templates import make_context, render_template router = APIRouter() @@ -143,11 +143,14 @@ async def make_single_context(request: Request, @router.get("/packages/{name}") async def package(request: Request, name: str) -> Response: - # Get the PackageBase. - pkgbase = get_pkgbase(name) + # Get the Package. + pkg = get_pkg_or_base(name, Package) + pkgbase = (get_pkg_or_base(name, PackageBase) + if not pkg else pkg.PackageBase) # Add our base information. context = await make_single_context(request, pkgbase) + context["package"] = pkg # Package sources. context["sources"] = db.query(PackageSource).join(Package).join( @@ -181,7 +184,7 @@ async def package(request: Request, name: str) -> Response: @router.get("/pkgbase/{name}") async def package_base(request: Request, name: str) -> Response: # Get the PackageBase. - pkgbase = get_pkgbase(name) + pkgbase = get_pkg_or_base(name, PackageBase) # If this is not a split package, redirect to /packages/{name}. if pkgbase.packages.count() == 1: diff --git a/templates/packages/show.html b/templates/packages/show.html index 7480f573..0bf8d9fd 100644 --- a/templates/packages/show.html +++ b/templates/packages/show.html @@ -3,7 +3,7 @@ {% block pageContent %} {% include "partials/packages/search.html" %}
    -

    {{ 'Package Details' | tr }}: {{ pkgbase.Name }} {{ pkgbase.packages.first().Version }}

    +

    {{ 'Package Details' | tr }}: {{ package.Name }} {{ package.Version }}

    {% set result = pkgbase %} {% include "partials/packages/actions.html" %} From 7961fa932a92b3743411a3b5307e5ee6636d6904 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 27 Sep 2021 15:01:45 -0700 Subject: [PATCH 0894/1891] feat(FastAPI): add templates.render_raw_template This function is now used as `render_template`'s underlying implementation of rendering a template, and uses that render in its HTMLResponse path. This separation allows users to directly render a template without producing a Response object. Signed-off-by: Kevin Morris --- aurweb/templates.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/aurweb/templates.py b/aurweb/templates.py index 09be049c..ef020bdf 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -102,12 +102,8 @@ async def make_variable_context(request: Request, title: str, next: str = None): return context -def render_template(request: Request, - path: str, - context: dict, - status_code: HTTPStatus = HTTPStatus.OK): +def render_raw_template(request: Request, path: str, context: dict): """ Render a Jinja2 multi-lingual template with some context. """ - # Create a deep copy of our jinja2 _environment. The _environment in # total by itself is 48 bytes large (according to sys.getsizeof). # This is done so we can install gettext translations on the template @@ -119,8 +115,15 @@ def render_template(request: Request, templates.install_gettext_translations(translator) template = templates.get_template(path) - rendered = template.render(context) + return template.render(context) + +def render_template(request: Request, + path: str, + context: dict, + status_code: HTTPStatus = HTTPStatus.OK): + """ Render a template as an HTMLResponse. """ + rendered = render_raw_template(request, path, context) response = HTMLResponse(rendered, status_code=status_code) secure_cookies = aurweb.config.getboolean("options", "disable_http_login") response.set_cookie("AURLANG", context.get("language"), From 0d8216e8eabc96faa48d855a596597a510145cd7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 1 Oct 2021 17:50:23 -0700 Subject: [PATCH 0895/1891] change(FastAPI): decouple rendercomment logic from main This commit decouples most of the rendercomment.py logic into a function, `update_comment_render`, which can be used by other Python modules to perform comment rendering. In addition, we silence some deprecation warnings from python-markdown by removing `md_globals` parameters from python-markdown callbacks. Signed-off-by: Kevin Morris --- aurweb/scripts/rendercomment.py | 43 +++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index f6dfd058..dd5da4f9 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import logging import sys import bleach @@ -9,6 +10,7 @@ import pygit2 import aurweb.config import aurweb.db +logger = logging.getLogger(__name__) repo_path = aurweb.config.get('serve', 'repo-path') commit_uri = aurweb.config.get('options', 'commit_uri') @@ -24,7 +26,7 @@ class LinkifyExtension(markdown.extensions.Extension): _urlre = (r'(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' r'(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))') - def extendMarkdown(self, md, md_globals): + def extendMarkdown(self, md): processor = markdown.inlinepatterns.AutolinkInlineProcessor(self._urlre, md) # Register it right after the default <>-link processor (priority 120). md.inlinePatterns.register(processor, 'linkify', 119) @@ -46,7 +48,7 @@ class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): class FlysprayLinksExtension(markdown.extensions.Extension): - def extendMarkdown(self, md, md_globals): + def extendMarkdown(self, md): processor = FlysprayLinksInlineProcessor(r'\bFS#(\d+)\b', md) md.inlinePatterns.register(processor, 'flyspray-links', 118) @@ -90,9 +92,12 @@ class GitCommitsExtension(markdown.extensions.Extension): self._head = head super(markdown.extensions.Extension, self).__init__() - def extendMarkdown(self, md, md_globals): - processor = GitCommitsInlineProcessor(md, self._head) - md.inlinePatterns.register(processor, 'git-commits', 117) + def extendMarkdown(self, md): + try: + processor = GitCommitsInlineProcessor(md, self._head) + md.inlinePatterns.register(processor, 'git-commits', 117) + except pygit2.GitError: + logger.error(f"No git repository found for '{self._head}'.") class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor): @@ -105,7 +110,7 @@ class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor): class HeadingExtension(markdown.extensions.Extension): - def extendMarkdown(self, md, md_globals): + def extendMarkdown(self, md): # Priority doesn't matter since we don't conflict with other processors. md.treeprocessors.register(HeadingTreeprocessor(md), 'heading', 30) @@ -123,19 +128,20 @@ def save_rendered_comment(conn, commentid, html): [html, commentid]) -def main(): - commentid = int(sys.argv[1]) - +def update_comment_render(commentid): conn = aurweb.db.Connection() text, pkgbase = get_comment(conn, commentid) - html = markdown.markdown(text, extensions=['fenced_code', - LinkifyExtension(), - FlysprayLinksExtension(), - GitCommitsExtension(pkgbase), - HeadingExtension()]) - allowed_tags = (bleach.sanitizer.ALLOWED_TAGS + - ['p', 'pre', 'h4', 'h5', 'h6', 'br', 'hr']) + html = markdown.markdown(text, extensions=[ + 'fenced_code', + LinkifyExtension(), + FlysprayLinksExtension(), + GitCommitsExtension(pkgbase), + HeadingExtension() + ]) + + allowed_tags = (bleach.sanitizer.ALLOWED_TAGS + + ['p', 'pre', 'h4', 'h5', 'h6', 'br', 'hr']) html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(conn, commentid, html) @@ -143,5 +149,10 @@ def main(): conn.close() +def main(): + commentid = int(sys.argv[1]) + update_comment_render(commentid) + + if __name__ == '__main__': main() From fc28aad245a0350ec3190fc484543bae4612883d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 27 Sep 2021 18:46:20 -0700 Subject: [PATCH 0896/1891] feat(FastAPI): add pkgbase comments (new, edit) In PHP, this was implemented using an /rpc type 'get-comment-form'. With FastAPI, we've decided to reorganize this into a non-RPC route: `/pkgbase/{name}/comments/{id}/form`, rendered via the new `templates/partials/packages/comment_form.html` template. When the comment_form.html template is provided a `comment` object, it will produce an edit comment form. Otherwise, it will produce a new comment form. A few new FastAPI routes have been introduced: - GET `/pkgbase/{name}/comments/{id}/form` - Produces a JSON response based on {"form": ""}. - POST `/pkgbase/{name}/comments' - Creates a new comment. - POST `/pkgbase/{name}/comments/{id}` - Edits an existing comment. In addition, some Javascript has been modified for our new routes. Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 8 ++ aurweb/routers/packages.py | 105 +++++++++++++- templates/partials/packages/comment.html | 50 ++++--- templates/partials/packages/comment_form.html | 46 ++++++ templates/partials/packages/comments.html | 70 +++------ test/test_packages_routes.py | 133 ++++++++++++++++++ 6 files changed, 333 insertions(+), 79 deletions(-) create mode 100644 templates/partials/packages/comment_form.html diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 696c158f..55149127 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -11,6 +11,7 @@ from aurweb import db from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_comment import PackageComment from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation @@ -121,6 +122,13 @@ def get_pkg_or_base(name: str, cls: Union[Package, PackageBase] = PackageBase): return instance +def get_pkgbase_comment(pkgbase: PackageBase, id: int) -> PackageComment: + comment = pkgbase.comments.filter(PackageComment.ID == id).first() + if not comment: + raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) + return comment + + @register_filter("out_of_date") def out_of_date(packages: orm.Query) -> orm.Query: return packages.filter(PackageBase.OutOfDateTS.isnot(None)) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 8fd7717b..d5c99e8d 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -1,8 +1,9 @@ +from datetime import datetime from http import HTTPStatus from typing import Any, Dict -from fastapi import APIRouter, Request, Response -from fastapi.responses import RedirectResponse +from fastapi import APIRouter, Form, HTTPException, Request, Response +from fastapi.responses import JSONResponse, RedirectResponse from sqlalchemy import and_ import aurweb.filters @@ -11,9 +12,11 @@ import aurweb.models.package_keyword import aurweb.packages.util from aurweb import db +from aurweb.auth import auth_required from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_comment import PackageComment from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_license import PackageLicense from aurweb.models.package_notification import PackageNotification @@ -23,8 +26,9 @@ from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID from aurweb.packages.search import PackageSearch -from aurweb.packages.util import get_pkg_or_base, query_notified, query_voted -from aurweb.templates import make_context, render_template +from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted +from aurweb.scripts.rendercomment import update_comment_render +from aurweb.templates import make_context, render_raw_template, render_template router = APIRouter() @@ -124,7 +128,9 @@ async def make_single_context(request: Request, context["pkgbase"] = pkgbase context["packages_count"] = pkgbase.packages.count() context["keywords"] = pkgbase.keywords - context["comments"] = pkgbase.comments + context["comments"] = pkgbase.comments.order_by( + PackageComment.CommentTS.desc() + ) context["is_maintainer"] = (request.user.is_authenticated() and request.user.ID == pkgbase.MaintainerUID) context["notified"] = request.user.notified(pkgbase) @@ -201,7 +207,94 @@ async def package_base(request: Request, name: str) -> Response: @router.get("/pkgbase/{name}/voters") async def package_base_voters(request: Request, name: str) -> Response: # Get the PackageBase. - pkgbase = get_pkgbase(name) + pkgbase = get_pkg_or_base(name, PackageBase) context = make_context(request, "Voters") context["pkgbase"] = pkgbase return render_template(request, "pkgbase/voters.html", context) + + +@router.post("/pkgbase/{name}/comments") +@auth_required(True) +async def pkgbase_comments_post( + request: Request, name: str, + comment: str = Form(default=str()), + enable_notifications: bool = Form(default=False)): + """ Add a new comment. """ + pkgbase = get_pkg_or_base(name, PackageBase) + + if not comment: + raise HTTPException(status_code=int(HTTPStatus.EXPECTATION_FAILED)) + + # If the provided comment is different than the record's version, + # update the db record. + now = int(datetime.utcnow().timestamp()) + with db.begin(): + comment = db.create(PackageComment, User=request.user, + PackageBase=pkgbase, + Comments=comment, RenderedComment=str(), + CommentTS=now) + + if enable_notifications and not request.user.notified(pkgbase): + db.create(PackageNotification, + User=request.user, + PackageBase=pkgbase) + update_comment_render(comment.ID) + + # Redirect to the pkgbase page. + return RedirectResponse(f"/pkgbase/{pkgbase.Name}#comment-{comment.ID}", + status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.get("/pkgbase/{name}/comments/{id}/form") +@auth_required(True) +async def pkgbase_comment_form(request: Request, name: str, id: int): + """ Produce a comment form for comment {id}. """ + pkgbase = get_pkg_or_base(name, PackageBase) + comment = pkgbase.comments.filter(PackageComment.ID == id).first() + if not comment: + return JSONResponse({}, status_code=int(HTTPStatus.NOT_FOUND)) + + if not request.user.is_elevated() and request.user != comment.User: + return JSONResponse({}, status_code=int(HTTPStatus.UNAUTHORIZED)) + + context = await make_single_context(request, pkgbase) + context["comment"] = comment + + form = render_raw_template( + request, "partials/packages/comment_form.html", context) + return JSONResponse({"form": form}) + + +@router.post("/pkgbase/{name}/comments/{id}") +@auth_required(True) +async def pkgbase_comment_post( + request: Request, name: str, id: int, + comment: str = Form(default=str()), + enable_notifications: bool = Form(default=False)): + pkgbase = get_pkg_or_base(name, PackageBase) + db_comment = get_pkgbase_comment(pkgbase, id) + + if not comment: + raise HTTPException(status_code=int(HTTPStatus.EXPECTATION_FAILED)) + + # If the provided comment is different than the record's version, + # update the db record. + now = int(datetime.utcnow().timestamp()) + if db_comment.Comments != comment: + with db.begin(): + db_comment.Comments = comment + db_comment.Editor = request.user + db_comment.EditedTS = now + + db_notif = request.user.notifications.filter( + PackageNotification.PackageBaseID == pkgbase.ID + ).first() + if enable_notifications and not db_notif: + db.create(PackageNotification, + User=request.user, + PackageBase=pkgbase) + update_comment_render(db_comment.ID) + + # Redirect to the pkgbase page anchored to the updated comment. + return RedirectResponse(f"/pkgbase/{pkgbase.Name}#comment-{db_comment.ID}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index 6cf5f319..36696215 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -16,26 +16,38 @@ ) | safe }} - {% if is_maintainer %} -
    -
    - - - - -
    -
    - Edit comment + {% if comment.Editor %} + {% set edited_on = comment.EditedTS | dt | as_timezone(timezone) %} + + ({{ "edited on %s by %s" | tr + | format(edited_on.strftime('%Y-%m-%d %H:%M'), + '%s' | format( + comment.Editor.Username, comment.Editor.Username)) + | safe + }}) + + {% endif %} + {% if request.user.is_elevated() or pkgbase.Maintainer == request.user %} +
    +
    + + + + +
    +
    + Edit comment + +
    +
    + + + + + +
    +
    {% endif %} -
    -
    - - - - - -
    -

    diff --git a/templates/partials/packages/comment_form.html b/templates/partials/packages/comment_form.html new file mode 100644 index 00000000..c1c25f87 --- /dev/null +++ b/templates/partials/packages/comment_form.html @@ -0,0 +1,46 @@ +{# `action` is assigned the proper route to use for the form action. +When `comment` is provided (PackageComment), we display an edit form +for the comment. Otherwise, we display a new form. + +Routes: + new comment - /pkgbase/{name}/comments + edit comment - /pkgbase/{name}/comments/{id} +#} +{% set action = "/pkgbase/%s/comments" | format(pkgbase.Name) %} +{% if comment %} + {% set action = "/pkgbase/%s/comments/%d" | format(pkgbase.Name, comment.ID) %} +{% endif %} + +
    +
    +

    + {{ "Git commit identifiers referencing commits in the AUR package " + "repository and URLs are converted to links automatically." | tr }} + {{ "%sMarkdown syntax%s is partially supported." | tr + | format('', + "") + | safe }} +

    +

    + +

    +

    + + {% if comment and not request.user.notified(pkgbase) %} + + + + + {% endif %} +

    +
    +
    diff --git a/templates/partials/packages/comments.html b/templates/partials/packages/comments.html index 39cfb363..7c8a32e5 100644 --- a/templates/partials/packages/comments.html +++ b/templates/partials/packages/comments.html @@ -8,44 +8,7 @@ {% if request.user.is_authenticated() %}

    Add Comment

    -
    -
    -
    - - -
    -

    - {{ - "Git commit identifiers referencing commits in the AUR package" - " repository and URLs are converted to links automatically." - | tr - }} - {{ - "%sMarkdown Syntax%s is partially supported." - | tr - | format('', '') - | safe - }} -

    -

    - -

    -

    - - {% if not notifications_enabled %} - - - - - {% endif %} -

    -
    -
    + {% include "partials/packages/comment_form.html" %}
    {% endif %} @@ -99,29 +62,28 @@ function handleEditCommentClick(event) { // The div class="article-content" which contains the comment const edit_form = parent_element.nextElementSibling; - const params = new URLSearchParams({ - type: "get-comment-form", - arg: comment_id, - base_id: {{ pkgbase.ID }}, - pkgbase_name: {{ pkgbase.Name }} - }); - - const url = '/rpc?' + params.toString(); + const url = "/pkgbase/{{ pkgbase.Name }}/comments/" + comment_id + "/form"; add_busy_indicator(event.target); fetch(url, { - method: 'GET' + method: 'GET', + credentials: 'same-origin' + }) + .then(function(response) { + if (!response.ok) { + throw Error(response.statusText); + } + return response.json(); }) - .then(function(response) { return response.json(); }) .then(function(data) { remove_busy_indicator(event.target); - if (data.success) { - edit_form.innerHTML = data.form; - edit_form.querySelector('textarea').focus(); - } else { - alert(data.error); - } + edit_form.innerHTML = data.form; + edit_form.querySelector('textarea').focus(); + }) + .catch(function(error) { + remove_busy_indicator(event.target); + console.error(error); }); } diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 2190dc18..1bfa5fc0 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -73,6 +73,7 @@ def setup(): PackageVote.__tablename__, PackageNotification.__tablename__, PackageComaintainer.__tablename__, + PackageComment.__tablename__, OfficialProvider.__tablename__ ) @@ -930,3 +931,135 @@ def test_pkgbase_voters(client: TestClient, maintainer: User, package: Package): root = parse_root(resp.text) rows = root.xpath('//div[@class="box"]//ul/li') assert len(rows) == 1 + + +def test_pkgbase_comment_not_found(client: TestClient, maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + comment_id = 12345 # A non-existing comment. + endpoint = f"/pkgbase/{package.PackageBase.Name}/comments/{comment_id}" + with client as request: + resp = request.post(endpoint, data={ + "comment": "Failure" + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_comment_form_unauthorized(client: TestClient, user: User, + maintainer: User, package: Package): + now = int(datetime.utcnow().timestamp()) + with db.begin(): + comment = db.create(PackageComment, PackageBase=package.PackageBase, + User=maintainer, Comments="Test", + RenderedComment=str(), CommentTS=now) + + cookies = {"AURSID": user.login(Request(), "testPassword")} + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/form" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) + + +def test_pkgbase_comment_form_not_found(client: TestClient, maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + comment_id = 12345 # A non-existing comment. + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/form" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_comments_missing_comment(client: TestClient, maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{package.PackageBase.Name}/comments" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.EXPECTATION_FAILED) + + +def test_pkgbase_comments(client: TestClient, maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments" + with client as request: + resp = request.post(endpoint, data={ + "comment": "Test comment.", + "enable_notifications": True + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + expected_prefix = f"/pkgbase/{pkgbasename}" + prefix_len = len(expected_prefix) + assert resp.headers.get("location")[:prefix_len] == expected_prefix + + with client as request: + resp = request.get(resp.headers.get("location")) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + headers = root.xpath('//h4[@class="comment-header"]') + bodies = root.xpath('//div[@class="article-content"]/div/p') + + assert len(headers) == 1 + assert len(bodies) == 1 + + assert bodies[0].text.strip() == "Test comment." + + # Clear up the PackageNotification. This doubles as testing + # that the notification was created and clears it up so we can + # test enabling it during edit. + pkgbase = package.PackageBase + db_notif = pkgbase.notifications.filter( + PackageNotification.UserID == maintainer.ID + ).first() + with db.begin(): + db.session.delete(db_notif) + + # Now, let's edit the comment we just created. + comment_id = int(headers[0].attrib["id"].split("-")[-1]) + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}" + with client as request: + resp = request.post(endpoint, data={ + "comment": "Edited comment.", + "enable_notifications": True + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + with client as request: + resp = request.get(resp.headers.get("location")) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + headers = root.xpath('//h4[@class="comment-header"]') + bodies = root.xpath('//div[@class="article-content"]/div/p') + + assert len(headers) == 1 + assert len(bodies) == 1 + + assert bodies[0].text.strip() == "Edited comment." + + # Ensure that a notification was created. + db_notif = pkgbase.notifications.filter( + PackageNotification.UserID == maintainer.ID + ).first() + assert db_notif is not None + + # Don't supply a comment; should return EXPECTATION_FAILED. + with client as request: + fail_resp = request.post(endpoint, cookies=cookies) + assert fail_resp.status_code == int(HTTPStatus.EXPECTATION_FAILED) + + # Now, test the form route, which should return form markup + # via JSON. + endpoint = f"{endpoint}/form" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + data = resp.json() + assert "form" in data From 59d04d6e0c50d3b0443dae29715de63f197be890 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 30 Sep 2021 13:53:31 -0700 Subject: [PATCH 0897/1891] fix(FastAPI): comment.html template rendering Deleters and edits were not previously taken into account. This fix addresses that issue using User.has_credential. Signed-off-by: Kevin Morris --- templates/partials/packages/comment.html | 148 ++++++++++++++--------- 1 file changed, 89 insertions(+), 59 deletions(-) diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index 36696215..6af5cd9e 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -1,60 +1,90 @@ -

    - {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} - {% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %} - {{ - "%s commented on %s" | tr | format( - ('%s' | format( - comment.User.Username, - view_account_info, - comment.User.Username - )) if request.user.is_authenticated() else - (comment.User.Username), - '%s' | format( - comment.ID, - commented_at.strftime("%Y-%m-%d %H:%M") - ) - ) - | safe - }} - {% if comment.Editor %} - {% set edited_on = comment.EditedTS | dt | as_timezone(timezone) %} - - ({{ "edited on %s by %s" | tr - | format(edited_on.strftime('%Y-%m-%d %H:%M'), - '%s' | format( - comment.Editor.Username, comment.Editor.Username)) - | safe - }}) - - {% endif %} - {% if request.user.is_elevated() or pkgbase.Maintainer == request.user %} -
    -
    - - - - -
    -
    - Edit comment +{% set header_cls = "comment-header" %} +{% set article_cls = "article-content" %} +{% if comment.Deleter %} + {% set header_cls = "%s %s" | format(header_cls, "comment-deleted") %} + {% set article_cls = "%s %s" | format(article_cls, "comment-deleted") %} +{% endif %} -
    -
    - - - - - -
    -
    - {% endif %} -

    -
    -
    - {% if comment.RenderedComment %} - {{ comment.RenderedComment | safe }} - {% else %} - {{ comment.Comments }} - {% endif %} -
    -
    +{% if not comment.Deleter or request.user.has_credential("CRED_COMMENT_VIEW_DELETED", approved=[comment.Deleter]) %} +

    + {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} + {% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %} + {{ + "%s commented on %s" | tr | format( + ('%s' | format( + comment.User.Username, + view_account_info, + comment.User.Username + )) if request.user.is_authenticated() else + (comment.User.Username), + '%s' | format( + comment.ID, + commented_at.strftime("%Y-%m-%d %H:%M") + ) + ) + | safe + }} + {% if comment.Editor %} + {% set edited_on = comment.EditedTS | dt | as_timezone(timezone) %} + + ({{ "edited on %s by %s" | tr + | format(edited_on.strftime('%Y-%m-%d %H:%M'), + '%s' | format( + comment.Editor.Username, comment.Editor.Username)) + | safe + }}) + + {% endif %} + {% if not comment.Deleter %} + {% if request.user.has_credential('CRED_COMMENT_DELETE', approved=[comment.User]) %} +
    +
    + +
    +
    + {% endif %} + + {% if request.user.has_credential('CRED_COMMENT_EDIT', approved=[comment.User]) %} + Edit comment + {% endif %} + + {% if request.user.has_credential("CRED_COMMENT_PIN", approved=[pkgbase.Maintainer]) %} +
    +
    + + + + + +
    +
    + {% endif %} + {% else %} + {% if request.user.has_credential("CRED_COMMENT_UNDELETE", approved=[comment.User]) %} +
    +
    + +
    +
    + {% endif %} + {% endif %} +

    +
    +
    + {% if comment.RenderedComment %} + {{ comment.RenderedComment | safe }} + {% else %} + {{ comment.Comments }} + {% endif %} +
    +
    +{% endif %} From 6644c42922ad4645104bef114e1685973ea1a92d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 30 Sep 2021 13:56:14 -0700 Subject: [PATCH 0898/1891] fix(FastAPI): AnonymousUser.has_credential also takes kwargs Signed-off-by: Kevin Morris --- aurweb/auth.py | 2 +- test/test_auth.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 19c3a276..d1a9d9cb 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -66,7 +66,7 @@ class AnonymousUser: return False @staticmethod - def has_credential(credential): + def has_credential(credential, **kwargs): return False @staticmethod diff --git a/test/test_auth.py b/test/test_auth.py index ced64064..7aea17a0 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -117,3 +117,8 @@ def test_voted_for(): def test_notified(): user_ = AnonymousUser() assert not user_.notified(None) + + +def test_has_credential(): + user_ = AnonymousUser() + assert not user_.has_credential("FAKE_CREDENTIAL") From d3be30744ccfe6556f0299d08a1bf8bc63b2ae44 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 1 Oct 2021 15:44:24 -0700 Subject: [PATCH 0899/1891] add(FeatAPI): comment pytest.fixture Signed-off-by: Kevin Morris --- test/test_packages_routes.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 1bfa5fc0..93a7f524 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -125,6 +125,20 @@ def package(maintainer: User) -> Package: yield package +@pytest.fixture +def comment(user: User, package: Package) -> PackageComment: + pkgbase = package.PackageBase + now = int(datetime.utcnow().timestamp()) + with db.begin(): + comment = db.create(PackageComment, + User=user, + PackageBase=pkgbase, + Comments="Test comment.", + RenderedComment=str(), + CommentTS=now) + yield comment + + @pytest.fixture def packages(maintainer: User) -> List[Package]: """ Yield 55 packages named pkg_0 .. pkg_54. """ From 40cd1b9029cc50e41c21d69e502947996862b7b4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 30 Sep 2021 13:58:37 -0700 Subject: [PATCH 0900/1891] feat(FastAPI): add /pkgbase/{name}/comments/{id}/delete (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 25 ++++++++++++++++++++- test/test_packages_routes.py | 43 +++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index d5c99e8d..3a5ca047 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -11,7 +11,7 @@ import aurweb.models.package_comment import aurweb.models.package_keyword import aurweb.packages.util -from aurweb import db +from aurweb import db, l10n from aurweb.auth import auth_required from aurweb.models.license import License from aurweb.models.package import Package @@ -298,3 +298,26 @@ async def pkgbase_comment_post( # Redirect to the pkgbase page anchored to the updated comment. return RedirectResponse(f"/pkgbase/{pkgbase.Name}#comment-{db_comment.ID}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/comments/{id}/delete") +@auth_required(True) +async def pkgbase_comment_delete(request: Request, name: str, id: int): + pkgbase = get_pkg_or_base(name, PackageBase) + comment = get_pkgbase_comment(pkgbase, id) + + authorized = request.user.has_credential("CRED_COMMENT_DELETE", + [comment.User]) + if not authorized: + _ = l10n.get_translator_for_request(request) + raise HTTPException( + status_code=int(HTTPStatus.UNAUTHORIZED), + detail=_("You are not allowed to delete this comment.")) + + now = int(datetime.utcnow().timestamp()) + with db.begin(): + comment.Deleter = request.user + comment.DelTS = now + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 93a7f524..eb3da41a 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -995,7 +995,7 @@ def test_pkgbase_comments_missing_comment(client: TestClient, maintainer: User, assert resp.status_code == int(HTTPStatus.EXPECTATION_FAILED) -def test_pkgbase_comments(client: TestClient, maintainer: User, +def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, package: Package): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} pkgbasename = package.PackageBase.Name @@ -1077,3 +1077,44 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, data = resp.json() assert "form" in data + + +def test_pkgbase_comment_delete(client: TestClient, + user: User, + package: Package, + comment: PackageComment): + # Test the unauthorized case of comment deletion. + cookies = {"AURSID": user.login(Request(), "testPassword")} + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/delete" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + expected = f"/pkgbase/{pkgbasename}" + assert resp.headers.get("location") == expected + + +def test_pkgbase_comment_delete_unauthorized(client: TestClient, + maintainer: User, + package: Package, + comment: PackageComment): + # Test the unauthorized case of comment deletion. + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/delete" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) + + +def test_pkgbase_comment_delete_not_found(client: TestClient, + maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + comment_id = 12345 # Non-existing comment. + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/delete" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) From bb45ae7ac3f8da424c51051981bc6af91742e70e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 30 Sep 2021 19:48:25 -0700 Subject: [PATCH 0901/1891] feat(FastAPI): add /pkgbase/{name}/comments/{id}/undelete (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 22 ++++++++++++++++++++++ test/test_packages_routes.py | 25 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 3a5ca047..92fc9361 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -321,3 +321,25 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int): return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/comments/{id}/undelete") +@auth_required(True) +async def pkgbase_comment_undelete(request: Request, name: str, id: int): + pkgbase = get_pkg_or_base(name, PackageBase) + comment = get_pkgbase_comment(pkgbase, id) + + has_cred = request.user.has_credential("CRED_COMMENT_UNDELETE", + approved=[comment.User]) + if not has_cred: + _ = l10n.get_translator_for_request(request) + raise HTTPException( + status_code=int(HTTPStatus.UNAUTHORIZED), + detail=_("You are not allowed to undelete this comment.")) + + with db.begin(): + comment.Deleter = None + comment.DelTS = None + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index eb3da41a..47b5ed81 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1080,6 +1080,7 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, def test_pkgbase_comment_delete(client: TestClient, + maintainer: User, user: User, package: Package, comment: PackageComment): @@ -1094,6 +1095,18 @@ def test_pkgbase_comment_delete(client: TestClient, expected = f"/pkgbase/{pkgbasename}" assert resp.headers.get("location") == expected + # Test the unauthorized case of comment undeletion. + maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/undelete" + with client as request: + resp = request.post(endpoint, cookies=maint_cookies) + assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) + + # And move on to undeleting it. + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + def test_pkgbase_comment_delete_unauthorized(client: TestClient, maintainer: User, @@ -1118,3 +1131,15 @@ def test_pkgbase_comment_delete_not_found(client: TestClient, with client as request: resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_comment_undelete_not_found(client: TestClient, + maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + comment_id = 12345 # Non-existing comment. + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/undelete" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) From 0895dd07ee621d24007a30b4f3d076d7b55c23f0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 1 Oct 2021 15:47:16 -0700 Subject: [PATCH 0902/1891] feat(FastAPI): add /pkgbase/{name}/comments/{id}/pin (post) In addition, fix up some templates to display pinned comments, and include the unpin form input for pinned comments, which is not yet implemented. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 26 ++++++++++++++ templates/packages/show.html | 4 +-- templates/partials/packages/comment.html | 42 +++++++++++++++++------ templates/partials/packages/comments.html | 16 ++++++++- test/test_packages_routes.py | 26 ++++++++++++++ 5 files changed, 100 insertions(+), 14 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 92fc9361..681cde4f 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -131,6 +131,10 @@ async def make_single_context(request: Request, context["comments"] = pkgbase.comments.order_by( PackageComment.CommentTS.desc() ) + context["pinned_comments"] = pkgbase.comments.filter( + PackageComment.PinnedTS != 0 + ).order_by(PackageComment.CommentTS.desc()) + context["is_maintainer"] = (request.user.is_authenticated() and request.user.ID == pkgbase.MaintainerUID) context["notified"] = request.user.notified(pkgbase) @@ -343,3 +347,25 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int): return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/comments/{id}/pin") +@auth_required(True) +async def pkgbase_comment_pin(request: Request, name: str, id: int): + pkgbase = get_pkg_or_base(name, PackageBase) + comment = get_pkgbase_comment(pkgbase, id) + + has_cred = request.user.has_credential("CRED_COMMENT_PIN", + approved=[pkgbase.Maintainer]) + if not has_cred: + _ = l10n.get_translator_for_request(request) + raise HTTPException( + status_code=int(HTTPStatus.UNAUTHORIZED), + detail=_("You are not allowed to pin this comment.")) + + now = int(datetime.utcnow().timestamp()) + with db.begin(): + comment.PinnedTS = now + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/packages/show.html b/templates/packages/show.html index 0bf8d9fd..ba531fc8 100644 --- a/templates/packages/show.html +++ b/templates/packages/show.html @@ -18,7 +18,5 @@ {% set pkgname = result.Name %} {% set pkgbase_id = result.ID %} - {% if comments.count() %} - {% include "partials/packages/comments.html" %} - {% endif %} + {% include "partials/packages/comments.html" %} {% endblock %} diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index 6af5cd9e..97f11723 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -49,16 +49,38 @@ Edit comment {% endif %} - {% if request.user.has_credential("CRED_COMMENT_PIN", approved=[pkgbase.Maintainer]) %} -
    -
    - - - - - -
    -
    + {% if request.user.has_credential("CRED_COMMENT_PIN", approved=[pkgbase.Maintainer]) %} + {% if comment.PinnedTS %} +
    +
    + +
    +
    + {% else %} +
    +
    + +
    +
    + {% endif %} {% endif %} {% else %} {% if request.user.has_credential("CRED_COMMENT_UNDELETE", approved=[comment.User]) %} diff --git a/templates/partials/packages/comments.html b/templates/partials/packages/comments.html index 7c8a32e5..56b5ab03 100644 --- a/templates/partials/packages/comments.html +++ b/templates/partials/packages/comments.html @@ -12,7 +12,21 @@
    {% endif %} -{% if comments %} +{% if pinned_comments.count() %} +
    +
    +

    + {{ "Pinned Comments" | tr }} + +

    +
    + {% for comment in pinned_comments.all() %} + {% include "partials/packages/comment.html" %} + {% endfor %} +
    +{% endif %} + +{% if comments.count() %}

    diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 47b5ed81..6bf4b975 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1143,3 +1143,29 @@ def test_pkgbase_comment_undelete_not_found(client: TestClient, with client as request: resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_comment_pin(client: TestClient, + maintainer: User, + package: Package, + comment: PackageComment): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + comment_id = comment.ID + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/pin" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_pkgbase_comment_pin_unauthorized(client: TestClient, + user: User, + package: Package, + comment: PackageComment): + cookies = {"AURSID": user.login(Request(), "testPassword")} + comment_id = comment.ID + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/pin" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) From 2efd254974fd2db0253ebc4aec725a08ba525d67 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 1 Oct 2021 17:51:39 -0700 Subject: [PATCH 0903/1891] feat(FastAPI): add /pkgbase/{name}/comments/{id}/unpin (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 21 +++++++++++++++++++++ test/test_packages_routes.py | 27 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 681cde4f..5ae19d07 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -369,3 +369,24 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int): return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/comments/{id}/unpin") +@auth_required(True) +async def pkgbase_comment_unpin(request: Request, name: str, id: int): + pkgbase = get_pkg_or_base(name, PackageBase) + comment = get_pkgbase_comment(pkgbase, id) + + has_cred = request.user.has_credential("CRED_COMMENT_PIN", + approved=[pkgbase.Maintainer]) + if not has_cred: + _ = l10n.get_translator_for_request(request) + raise HTTPException( + status_code=int(HTTPStatus.UNAUTHORIZED), + detail=_("You are not allowed to unpin this comment.")) + + with db.begin(): + comment.PinnedTS = 0 + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 6bf4b975..1c7d5d3e 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1152,11 +1152,25 @@ def test_pkgbase_comment_pin(client: TestClient, cookies = {"AURSID": maintainer.login(Request(), "testPassword")} comment_id = comment.ID pkgbasename = package.PackageBase.Name + + # Pin the comment. endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/pin" with client as request: resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) + # Assert that PinnedTS got set. + assert comment.PinnedTS > 0 + + # Unpin the comment we just pinned. + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/unpin" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + # Let's assert that PinnedTS was unset. + assert comment.PinnedTS == 0 + def test_pkgbase_comment_pin_unauthorized(client: TestClient, user: User, @@ -1169,3 +1183,16 @@ def test_pkgbase_comment_pin_unauthorized(client: TestClient, with client as request: resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) + + +def test_pkgbase_comment_unpin_unauthorized(client: TestClient, + user: User, + package: Package, + comment: PackageComment): + cookies = {"AURSID": user.login(Request(), "testPassword")} + comment_id = comment.ID + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/unpin" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) From 986fa9ee305ed113172f7f214d451a7af071ecc2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 26 Sep 2021 20:26:24 -0700 Subject: [PATCH 0904/1891] feat(PHP): add aurweb Prometheus metrics Along with this initial requests metric implementation, we also now serve the `/metrics` route, which grabs request metrics out of cache and renders them properly for Prometheus. **NOTE** Metrics are only enabled when the aurweb system admin has enabled caching by configuring `options.cache` correctly in `$AUR_CONFIG`. Otherwise, an error is logged about no cache being configured. New dependencies have been added which require the use of `composer`. See `INSTALL` for the dependency section in regards to composer dependencies and how to install them properly for aurweb. Metrics are in the following forms: aurweb_http_requests_count(method="GET",route="/some_route") aurweb_api_requests_count(method="GET",route="/rpc",type="search") This should allow us to search through the requests for specific routes and queries. Signed-off-by: Kevin Morris --- INSTALL | 8 ++- web/html/index.php | 29 ++++++++ web/html/metrics.php | 16 +++++ web/lib/metricfuncs.inc.php | 129 ++++++++++++++++++++++++++++++++++++ web/lib/routing.inc.php | 3 +- 5 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 web/html/metrics.php create mode 100644 web/lib/metricfuncs.inc.php diff --git a/INSTALL b/INSTALL index 9bcd0759..b161edd2 100644 --- a/INSTALL +++ b/INSTALL @@ -49,9 +49,15 @@ read the instructions below. # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy \ python-bleach python-markdown python-alembic python-jinja \ - python-itsdangerous python-authlib python-httpx hypercorn + python-itsdangerous python-authlib python-httpx hypercorn \ + composer # python3 setup.py install +4a) Install `composer` dependencies while inside of aurweb's root: + + $ cd /path/to/aurweb + /path/to/aurweb $ composer require promphp/prometheus_client_php + 5) Create a new MySQL database and a user and import the aurweb SQL schema: $ python -m aurweb.initdb diff --git a/web/html/index.php b/web/html/index.php index e57e7708..82a44c55 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -3,10 +3,39 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgfuncs.inc.php"); +include_once("cachefuncs.inc.php"); +include_once("metricfuncs.inc.php"); $path = $_SERVER['PATH_INFO']; $tokens = explode('/', $path); +$query_string = $_SERVER['QUERY_STRING']; + +// If no options.cache is configured, we no-op metric storage operations. +$is_cached = defined('EXTENSION_LOADED_APC') || defined('EXTENSION_LOADED_MEMCACHE'); +if ($is_cached) { + $method = $_SERVER['REQUEST_METHOD']; + // We'll always add +1 to our total request count to this $path, + // unless this path == /metrics. + if ($path !== "/metrics") + add_metric("http_requests_count", $method, $path); + + // Extract $type out of $query_string, if we can. + $type = null; + $query = array(); + if ($query_string) + parse_str($query_string, $query); + $type = $query['type']; + + // Only store RPC metrics for valid types. + $good_types = [ + "info", "multiinfo", "search", "msearch", + "suggest", "suggest-pkgbase", "get-comment-form" + ]; + if ($path === "/rpc" && in_array($type, $good_types)) + add_metric("api_requests_count", $method, $path, $type); +} + if (config_get_bool('options', 'enable-maintenance') && (empty($tokens[1]) || ($tokens[1] != "css" && $tokens[1] != "images"))) { if (!in_array($_SERVER['REMOTE_ADDR'], explode(" ", config_get('options', 'maintenance-exceptions')))) { header("HTTP/1.0 503 Service Unavailable"); diff --git a/web/html/metrics.php b/web/html/metrics.php new file mode 100644 index 00000000..dfa860ed --- /dev/null +++ b/web/html/metrics.php @@ -0,0 +1,16 @@ + diff --git a/web/lib/metricfuncs.inc.php b/web/lib/metricfuncs.inc.php new file mode 100644 index 00000000..acfc30d7 --- /dev/null +++ b/web/lib/metricfuncs.inc.php @@ -0,0 +1,129 @@ +, 'query_string': }. + $metrics = get_cache_value("prometheus_metrics"); + $metrics = $metrics ? json_decode($metrics) : array(); + + $key = "$path:$type"; + + // If the current request $path isn't yet in $metrics create + // a new assoc array for it and push it into $metrics. + if (!in_array($key, $metrics)) { + $data = array( + 'anchor' => $anchor, + 'method' => $method, + 'path' => $path, + 'type' => $type + ); + array_push($metrics, json_encode($data)); + } + + // Cache-wise, we also store the count values of each route + // through the "prometheus:" key. Grab the cache value + // representing the current $path we're on (defaulted to 1). + $count = get_cache_value("prometheus:$key"); + $count = $count ? $count + 1 : 1; + + $labels = ["method", "route"]; + if ($type) + array_push($labels, "type"); + + $gauge = $registry->getOrRegisterGauge( + 'aurweb', + $anchor, + 'A metric count for the aurweb platform.', + $labels + ); + + $label_values = [$data['method'], $data['path']]; + if ($type) + array_push($label_values, $type); + + $gauge->set($count, $label_values); + + // Update cache values. + set_cache_value("prometheus:$key", $count, 0); + set_cache_value("prometheus_metrics", json_encode($metrics), 0); + +} + +function render_metrics() { + if (!defined('EXTENSION_LOADED_APC') && !defined('EXTENSION_LOADED_MEMCACHE')) { + error_log("The /metrics route requires a valid 'options.cache' " + . "configuration; no cache is configured."); + return http_response_code(417); // EXPECTATION_FAILED + } + + global $registry; + + // First, we grab the set of metrics we're interested in in the + // form of a cached JSON list, if we can. + $metrics = get_cache_value("prometheus_metrics"); + if (!$metrics) + $metrics = array(); + else + $metrics = json_decode($metrics); + + // Now, we walk through each of those list values one by one, + // which happen to be JSON-serialized associative arrays, + // and process each metric via its associative array's contents: + // The route path and the query string. + // See web/html/index.php for the creation of such metrics. + foreach ($metrics as $metric) { + $data = json_decode($metric, true); + + $anchor = $data['anchor']; + $path = $data['path']; + $type = $data['type']; + $key = "$path:$type"; + + $labels = ["method", "route"]; + if ($type) + array_push($labels, "type"); + + $count = get_cache_value("prometheus:$key"); + $gauge = $registry->getOrRegisterGauge( + 'aurweb', + $anchor, + 'A metric count for the aurweb platform.', + $labels + ); + + $label_values = [$data['method'], $data['path']]; + if ($type) + array_push($label_values, $type); + + $gauge->set($count, $label_values); + } + + // Construct the results from RenderTextFormat renderer and + // registry's samples. + $renderer = new RenderTextFormat(); + $result = $renderer->render($registry->getMetricFamilySamples()); + + // Output the results with the right content type header. + http_response_code(200); // OK + header('Content-Type: ' . RenderTextFormat::MIME_TYPE); + echo $result; +} + +?> diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php index 73c667d2..0f452f22 100644 --- a/web/lib/routing.inc.php +++ b/web/lib/routing.inc.php @@ -19,7 +19,8 @@ $ROUTES = array( '/rss' => 'rss.php', '/tos' => 'tos.php', '/tu' => 'tu.php', - '/addvote' => 'addvote.php', + '/addvote' => 'addvote.php', + '/metrics' => 'metrics.php' // Prometheus Metrics ); $PKG_PATH = '/packages'; From 4d191b51f9d5b9a4d365c2b2f806c257f0a720e3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 16 Sep 2021 19:42:09 -0700 Subject: [PATCH 0905/1891] feat(FastAPI): add /pkgbase/{name}/comaintainers (get, post) Changes from PHP: - Form action now points to `/pkgbase/{name}/comaintainers`. - When an error occurs, users are sent back to `/pkgbase/{name}/comaintainers` with an error at the top of the page. (PHP used to send people to /pkgbase/, which ended up at a blank search page). Closes: https://gitlab.archlinux.org/archlinux/aurweb/-/issues/51 Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 145 +++++++++++++++++++++++ templates/partials/packages/actions.html | 4 +- templates/pkgbase/comaintainers.html | 40 +++++++ test/test_packages_routes.py | 108 +++++++++++++++++ 4 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 templates/pkgbase/comaintainers.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 5ae19d07..385d91db 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -16,6 +16,7 @@ from aurweb.auth import auth_required from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_comment import PackageComment from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_license import PackageLicense @@ -25,8 +26,10 @@ from aurweb.models.package_request import PackageRequest from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID +from aurweb.models.user import User from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted +from aurweb.scripts import notify from aurweb.scripts.rendercomment import update_comment_render from aurweb.templates import make_context, render_raw_template, render_template @@ -390,3 +393,145 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int): return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.get("/pkgbase/{name}/comaintainers") +@auth_required(True) +async def package_base_comaintainers(request: Request, name: str) -> Response: + # Get the PackageBase. + pkgbase = get_pkg_or_base(name, PackageBase) + + # Unauthorized users (Non-TU/Dev and not the pkgbase maintainer) + # get redirected to the package base's page. + has_creds = request.user.has_credential("CRED_PKGBASE_EDIT_COMAINTAINERS", + approved=[pkgbase.Maintainer]) + if not has_creds: + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + # Add our base information. + context = make_context(request, "Manage Co-maintainers") + context["pkgbase"] = pkgbase + + context["comaintainers"] = [ + c.User.Username for c in pkgbase.comaintainers + ] + + return render_template(request, "pkgbase/comaintainers.html", context) + + +def remove_users(pkgbase, usernames): + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + notifications = [] + with db.begin(): + for username in usernames: + # We know that the users we passed here are in the DB. + # No need to check for their existence. + comaintainer = pkgbase.comaintainers.join(User).filter( + User.Username == username + ).first() + notifications.append( + notify.ComaintainerRemoveNotification( + conn, comaintainer.User.ID, pkgbase.ID + ) + ) + db.session.delete(comaintainer) + + # Send out notifications if need be. + for notify_ in notifications: + notify_.send() + + +@router.post("/pkgbase/{name}/comaintainers") +@auth_required(True) +async def package_base_comaintainers_post( + request: Request, name: str, + users: str = Form(default=str())) -> Response: + # Get the PackageBase. + pkgbase = get_pkg_or_base(name, PackageBase) + + # Unauthorized users (Non-TU/Dev and not the pkgbase maintainer) + # get redirected to the package base's page. + has_creds = request.user.has_credential("CRED_PKGBASE_EDIT_COMAINTAINERS", + approved=[pkgbase.Maintainer]) + if not has_creds: + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + users = set(users.split("\n")) + users.remove(str()) # Remove any empty strings from the set. + records = {c.User.Username for c in pkgbase.comaintainers} + + remove_users(pkgbase, records.difference(users)) + + # Default priority (lowest value; most preferred). + priority = 1 + + # Get the highest priority in the comaintainer set. + last_priority = pkgbase.comaintainers.order_by( + PackageComaintainer.Priority.desc() + ).limit(1).first() + + # If that record exists, we use a priority which is 1 higher. + # TODO: This needs to ensure that it wraps around and preserves + # ordering in the case where we hit the max number allowed by + # the Priority column type. + if last_priority: + priority = last_priority.Priority + 1 + + def add_users(usernames): + """ Add users as comaintainers to pkgbase. + + :param usernames: An iterable of username strings + :return: None on success, an error string on failure. """ + nonlocal request, pkgbase, priority + + # First, perform a check against all usernames given; for each + # username, add its related User object to memo. + _ = l10n.get_translator_for_request(request) + memo = {} + for username in usernames: + user = db.query(User).filter(User.Username == username).first() + if not user: + return _("Invalid user name: %s") % username + memo[username] = user + + # Alright, now that we got past the check, add them all to the DB. + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + notifications = [] + with db.begin(): + for username in usernames: + user = memo.get(username) + if pkgbase.Maintainer == user: + # Already a maintainer. Move along. + continue + + # If we get here, our user model object is in the memo. + comaintainer = db.create( + PackageComaintainer, + PackageBase=pkgbase, + User=user, + Priority=priority) + priority += 1 + + notifications.append( + notify.ComaintainerAddNotification( + conn, comaintainer.User.ID, pkgbase.ID) + ) + + # Send out notifications. + for notify_ in notifications: + notify_.send() + + error = add_users(users.difference(records)) + if error: + context = make_context(request, "Manage Co-maintainers") + context["pkgbase"] = pkgbase + context["comaintainers"] = [ + c.User.Username for c in pkgbase.comaintainers + ] + context["errors"] = [error] + return render_template(request, "pkgbase/comaintainers.html", context) + + return RedirectResponse(f"/pkgbase/{pkgbase.Name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index d552f2dd..6c30153c 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -117,9 +117,9 @@ {% endif %} - {% if is_maintainer %} + {% if request.user.has_credential('CRED_PKGBASE_EDIT_COMAINTAINERS', approved=[pkgbase.Maintainer]) %}
  • - + {{ "Manage Co-Maintainers" | tr }}
  • diff --git a/templates/pkgbase/comaintainers.html b/templates/pkgbase/comaintainers.html new file mode 100644 index 00000000..06e8b9d7 --- /dev/null +++ b/templates/pkgbase/comaintainers.html @@ -0,0 +1,40 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} + {% if errors %} +
      + {% for error in errors %} +
    • {{ error | tr }}
    • + {% endfor %} +
    + {% endif %} + +
    +

    {{ "Manage Co-maintainers" | tr }}:

    +

    + {{ + "Use this form to add co-maintainers for %s%s%s " + "(one user name per line):" + | tr | format("", pkgbase.Name, "") + | safe + }} +

    + +
    +
    +

    + + +

    + +

    + +

    +
    +
    + +
    +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 1c7d5d3e..f1c20067 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1196,3 +1196,111 @@ def test_pkgbase_comment_unpin_unauthorized(client: TestClient, with client as request: resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) + + +def test_pkgbase_comaintainers_not_found(client: TestClient, maintainer: User): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + endpoint = "/pkgbase/fake/comaintainers" + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_comaintainers_post_not_found(client: TestClient, + maintainer: User): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + endpoint = "/pkgbase/fake/comaintainers" + with client as request: + resp = request.post(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_comaintainers_unauthorized(client: TestClient, user: User, + package: Package): + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + +def test_pkgbase_comaintainers_post_unauthorized(client: TestClient, + user: User, + package: Package): + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + +def test_pkgbase_comaintainers_post_invalid_user(client: TestClient, + maintainer: User, + package: Package): + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "users": "\nfake\n" + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + error = root.xpath('//ul[@class="errorlist"]/li')[0] + assert error.text.strip() == "Invalid user name: fake" + + +def test_pkgbase_comaintainers(client: TestClient, user: User, + maintainer: User, package: Package): + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + + # Start off by adding user as a comaintainer to package. + # The maintainer username given should be ignored. + with client as request: + resp = request.post(endpoint, data={ + "users": f"\n{user.Username}\n{maintainer.Username}\n" + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + # Do it again to exercise the last_priority bump path. + with client as request: + resp = request.post(endpoint, data={ + "users": f"\n{user.Username}\n{maintainer.Username}\n" + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + # Now that we've added a comaintainer to the pkgbase, + # let's perform a GET request to make sure that the backend produces + # the user we added in the users textarea. + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + users = root.xpath('//textarea[@id="id_users"]')[0] + assert users.text.strip() == user.Username + + # Finish off by removing all the comaintainers. + with client as request: + resp = request.post(endpoint, data={ + "users": str() + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + users = root.xpath('//textarea[@id="id_users"]')[0] + assert users is not None and users.text is None From c164abe256e2c1ee71be1ab3815b365fcb3f80de Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 1 Sep 2021 13:55:41 -0700 Subject: [PATCH 0906/1891] feat(FastAPI): add Requests navigation item Along with this, created a new test suite at test/test_html.py, which has the responsibility of testing various HTML things that are not suitable for another test suite. Signed-off-by: Kevin Morris --- templates/partials/archdev-navbar.html | 5 ++ test/test_html.py | 99 ++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 test/test_html.py diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index 13459e1a..9a3ba780 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -7,6 +7,11 @@ {% endif %}
  • {% trans %}Packages{% endtrans %}
  • {% if request.user.is_authenticated() %} +
  • + + {% trans %}Requests{% endtrans %} + +
  • {% if request.user.is_trusted_user() or request.user.is_developer() %}
  • diff --git a/test/test_html.py b/test/test_html.py new file mode 100644 index 00000000..562d6a63 --- /dev/null +++ b/test/test_html.py @@ -0,0 +1,99 @@ +""" A test suite used to test HTML renders in different cases. """ +from http import HTTPStatus + +import pytest + +from fastapi.testclient import TestClient + +from aurweb import asgi, db +from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID, AccountType +from aurweb.models.user import User +from aurweb.testing import setup_test_db +from aurweb.testing.html import parse_root +from aurweb.testing.requests import Request + + +@pytest.fixture(autouse=True) +def setup(): + setup_test_db(User.__tablename__) + + +@pytest.fixture +def client() -> TestClient: + yield TestClient(app=asgi.app) + + +@pytest.fixture +def user() -> User: + user_type = db.query(AccountType, AccountType.ID == USER_ID).first() + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + Passwd="testPassword", AccountType=user_type) + yield user + + +@pytest.fixture +def trusted_user(user: User) -> User: + tu_type = db.query(AccountType, + AccountType.ID == TRUSTED_USER_ID).first() + with db.begin(): + user.AccountType = tu_type + yield user + + +def test_archdev_navbar(client: TestClient): + expected = [ + "AUR Home", + "Packages", + "Register", + "Login" + ] + with client as request: + resp = request.get("/") + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + items = root.xpath('//div[@id="archdev-navbar"]/ul/li/a') + for i, item in enumerate(items): + assert item.text.strip() == expected[i] + + +def test_archdev_navbar_authenticated(client: TestClient, user: User): + expected = [ + "Dashboard", + "Packages", + "Requests", + "My Account", + "Logout" + ] + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get("/", cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + items = root.xpath('//div[@id="archdev-navbar"]/ul/li/a') + for i, item in enumerate(items): + assert item.text.strip() == expected[i] + + +def test_archdev_navbar_authenticated_tu(client: TestClient, + trusted_user: User): + expected = [ + "Dashboard", + "Packages", + "Requests", + "Accounts", + "My Account", + "Trusted User", + "Logout" + ] + cookies = {"AURSID": trusted_user.login(Request(), "testPassword")} + with client as request: + resp = request.get("/", cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + items = root.xpath('//div[@id="archdev-navbar"]/ul/li/a') + for i, item in enumerate(items): + assert item.text.strip() == expected[i] From 99482f9962de96de0d5b248f0ee99cdd15a6a740 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 10 Sep 2021 13:28:11 -0700 Subject: [PATCH 0907/1891] feat(FastAPI): added /requests (get) route Introduces `aurweb.defaults` and `aurweb.filters`. `aurweb.filters` is a location developers can put their additional Jinja2 filters and/or functions. We should slowly move all of our filters over here, where it makes sense. `aurweb.defaults` is a new module which hosts some default constants and utility functions, starting with offsets (O) and per page values (PP). As far as the new GET /requests is concerned, we match up here to PHP's implementation, with some minor improvements: Improvements: * PP on this page is now configurable: 50 (default), 100, or 250. * Example: `https://localhost:8444/requests?PP=250` Modifications: * The pagination is a bit different, but serves the exact same purpose. * "Last" no longer goes to an empty page. * Closes: https://gitlab.archlinux.org/archlinux/aurweb/-/issues/14 Signed-off-by: Kevin Morris --- aurweb/auth.py | 15 +++++ aurweb/defaults.py | 18 ++++++ aurweb/filters.py | 14 ++++- aurweb/routers/packages.py | 40 ++++++++++-- aurweb/templates.py | 15 +++++ setup.cfg | 19 +++--- templates/requests.html | 115 +++++++++++++++++++++++++++++++++++ test/test_defaults.py | 14 +++++ test/test_packages_routes.py | 84 ++++++++++++++++++++++++- test/test_templates.py | 16 ++++- test/test_util.py | 8 ++- 11 files changed, 341 insertions(+), 17 deletions(-) create mode 100644 aurweb/defaults.py create mode 100644 templates/requests.html create mode 100644 test/test_defaults.py diff --git a/aurweb/auth.py b/aurweb/auth.py index d1a9d9cb..21d31081 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -31,8 +31,23 @@ class StubQuery: class AnonymousUser: + """ A stubbed User class used when an unauthenticated User + makes a request against FastAPI. """ # Stub attributes used to mimic a real user. ID = 0 + + class AccountType: + """ A stubbed AccountType static class. In here, we use an ID + and AccountType which do not exist in our constant records. + All records primary keys (AccountType.ID) should be non-zero, + so using a zero here means that we'll never match against a + real AccountType. """ + ID = 0 + AccountType = "Anonymous" + + # AccountTypeID == AccountType.ID; assign a stubbed column. + AccountTypeID = AccountType.ID + LangPreference = aurweb.config.get("options", "default_lang") Timezone = aurweb.config.get("options", "default_timezone") diff --git a/aurweb/defaults.py b/aurweb/defaults.py new file mode 100644 index 00000000..c2568d05 --- /dev/null +++ b/aurweb/defaults.py @@ -0,0 +1,18 @@ +""" Constant default values centralized in one place. """ + +# Default [O]ffset +O = 0 + +# Default [P]er [P]age +PP = 50 + +# A whitelist of valid PP values +PP_WHITELIST = {50, 100, 250} + + +def fallback_pp(per_page: int) -> int: + """ If `per_page` is a valid value in PP_WHITELIST, return it. + Otherwise, return defaults.PP. """ + if per_page not in PP_WHITELIST: + return PP + return per_page diff --git a/aurweb/filters.py b/aurweb/filters.py index bb56c656..f9f56b5d 100644 --- a/aurweb/filters.py +++ b/aurweb/filters.py @@ -4,8 +4,8 @@ import paginate from jinja2 import pass_context -from aurweb import util -from aurweb.templates import register_filter +from aurweb import config, util +from aurweb.templates import register_filter, register_function @register_filter("pager_nav") @@ -48,3 +48,13 @@ def pager_nav(context: Dict[str, Any], symbol_previous="‹ Previous", symbol_next="Next ›", symbol_last="Last »") + + +@register_function("config_getint") +def config_getint(section: str, key: str) -> int: + return config.getint(section, key) + + +@register_function("round") +def do_round(f: float) -> int: + return round(f) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 385d91db..5751a3ee 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -2,17 +2,18 @@ from datetime import datetime from http import HTTPStatus from typing import Any, Dict -from fastapi import APIRouter, Form, HTTPException, Request, Response +from fastapi import APIRouter, Form, HTTPException, Query, Request, Response from fastapi.responses import JSONResponse, RedirectResponse -from sqlalchemy import and_ +from sqlalchemy import and_, case import aurweb.filters import aurweb.models.package_comment import aurweb.models.package_keyword import aurweb.packages.util -from aurweb import db, l10n -from aurweb.auth import auth_required +from aurweb import db, defaults, l10n +from aurweb.auth import account_type_required, auth_required +from aurweb.models.account_type import DEVELOPER, TRUSTED_USER, TRUSTED_USER_AND_DEV from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -22,10 +23,11 @@ from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_license import PackageLicense from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation -from aurweb.models.package_request import PackageRequest +from aurweb.models.package_request import PENDING_ID, PackageRequest from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID +from aurweb.models.request_type import RequestType from aurweb.models.user import User from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted @@ -535,3 +537,31 @@ async def package_base_comaintainers_post( return RedirectResponse(f"/pkgbase/{pkgbase.Name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.get("/requests") +@account_type_required({TRUSTED_USER, DEVELOPER, TRUSTED_USER_AND_DEV}) +@auth_required(True, redirect="/") +async def requests(request: Request, + O: int = Query(default=defaults.O), + PP: int = Query(default=defaults.PP)): + context = make_context(request, "Requests") + + context["q"] = dict(request.query_params) + context["O"] = O + context["PP"] = PP + + # A PackageRequest query, with left inner joined User and RequestType. + query = db.query(PackageRequest).join( + User, PackageRequest.UsersID == User.ID + ).join(RequestType) + + context["total"] = query.count() + context["results"] = query.order_by( + # Order primarily by the Status column being PENDING_ID, + # and secondarily by RequestTS; both in descending order. + case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), + PackageRequest.RequestTS.desc() + ).limit(PP).offset(O).all() + + return render_template(request, "requests.html", context) diff --git a/aurweb/templates.py b/aurweb/templates.py index ef020bdf..2301cfe2 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -71,6 +71,20 @@ def register_filter(name: str) -> Callable: return decorator +def register_function(name: str) -> Callable: + """ A decorator that can be used to register a function. + """ + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + if name in _env.globals: + raise KeyError(f"Jinja already has a function named '{name}'") + _env.globals[name] = wrapper + return wrapper + return decorator + + def make_context(request: Request, title: str, next: str = None): """ Create a context for a jinja2 TemplateResponse. """ @@ -83,6 +97,7 @@ def make_context(request: Request, title: str, next: str = None): "timezones": time.SUPPORTED_TIMEZONES, "title": title, "now": datetime.now(tz=zoneinfo.ZoneInfo(timezone)), + "utcnow": int(datetime.utcnow().timestamp()), "config": aurweb.config, "next": next if next else request.url.path } diff --git a/setup.cfg b/setup.cfg index 4f2bdf7d..cec1bcf5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,17 +6,22 @@ ignore = E741, W503 max-line-length = 127 max-complexity = 10 -# aurweb/routers/accounts.py # Ignore some unavoidable flake8 warnings; we know this is against -# pycodestyle, but some of the existing codebase uses `I` variables, +# PEP8, but some of the existing codebase uses `I` variables, # so specifically silence warnings about it in pre-defined files. +# # In E741, the 'I', 'O', 'l' are ambiguous variable names. # Our current implementation uses these variables through HTTP # and the FastAPI form specification wants them named as such. -# In C901's case, our process_account_form function is way too -# complex for PEP (too many if statements). However, we need to -# process these anyways, and making it any more complex would -# just add confusion to the implementation. +# +# With {W503,W504}, PEP8 does not want us to break lines before +# or after a binary operator. We have many scripts that already +# do this, so we're ignoring it here. +ignore = E741, W503, W504 + +# aurweb/routers/accounts.py +# Ignore over-reaching complexity. +# TODO: This should actually be addressed so we do not ignore C901. # # test/test_ssh_pub_key.py # E501 is detected due to our >127 width test constant. Ignore it. @@ -24,7 +29,7 @@ max-complexity = 10 # Anything like this should be questioned. # per-file-ignores = - aurweb/routers/accounts.py:E741,C901 + aurweb/routers/accounts.py:C901 test/test_ssh_pub_key.py:E501 aurweb/routers/packages.py:E741 diff --git a/templates/requests.html b/templates/requests.html new file mode 100644 index 00000000..a9017e2f --- /dev/null +++ b/templates/requests.html @@ -0,0 +1,115 @@ +{% extends "partials/layout.html" %} + +{% set singular = "%d package request found." %} +{% set plural = "%d package requests found." %} + +{% block pageContent %} +
    + {% if not total %} +

    {{ "No requests matched your search criteria." | tr }}

    + {% else %} + {% include "partials/widgets/pager.html" %} + + + + + + + + + + + + + {% for result in results %} + + + {# Type #} + + {# Comments #} + + + {% set idle_time = config_getint("options", "request_idle_time") %} + {% set time_delta = (utcnow - result.RequestTS) | int %} + + {% set due = result.Status == 0 and time_delta > idle_time %} + + + + {% endfor %} + +
    {{ "Package" | tr }}{{ "Type" | tr }}{{ "Comments" | tr }}{{ "Filed by" | tr }}{{ "Date" | tr }}{{ "Status" | tr }}
    + {# Package #} + + {{ result.PackageBaseName }} + + + {{ result.RequestType.name_display() }} + {# If the RequestType is a merge and request.MergeBaseName is valid... #} + {% if result.RequestType.ID == 3 and result.MergeBaseName %} + ({{ result.MergeBaseName }}) + {% endif %} + {{ result.Comments }} + {# Filed by #} + + {{ result.User.Username }} + + + {# Date #} + {% set date = result.RequestTS | dt | as_timezone(timezone) %} + {{ date.strftime("%Y-%m-%d %H:%M") }} + + {# Status #} + {% if result.Status == 0 %} + {% set temp_q = { "next": "/requests" } %} + + {% if result.RequestType.ID == 1 %} + {% set action = "delete" %} + {% elif result.RequestType.ID == 2 %} + {% set action = "disown" %} + {% elif result.RequestType.ID == 3 %} + {% set action = "merge" %} + {# Add the 'via' url query parameter. #} + {% set temp_q = temp_q | extend_query( + ["via", result.ID], + ["into", result.MergeBaseName] + ) %} + {% endif %} + + {% if request.user.is_elevated() %} + {% if result.RequestType.ID == 2 and not due %} + {% set time_left = idle_time - time_delta %} + {% if time_left > 48 * 3600 %} + {% set n = round(time_left / (24 * 3600)) %} + {% set time_left_fmt = (n | tn("~%d day left", "~%d days left") | format(n)) %} + {% elif time_left > 3600 %} + {% set n = round(time_left / 3600) %} + {% set time_left_fmt = (n | tn("~%d hour left", "~%d hours left") | format(n)) %} + {% else %} + {% set time_left_fmt = ("<1 hour left" | tr) %} + {% endif %} + {{ "Locked" | tr }} + ({{ time_left_fmt }}) + {% else %} + {# Only elevated users (TU or Dev) are allowed to accept requests. #} + + {{ "Accept" | tr }} + + {% endif %} +
    + {% endif %} + + {{ "Close" | tr }} + + {% else %} + {{ result.status_display() }} + {% endif %} +
    + {% include "partials/widgets/pager.html" %} + {% endif %} +
    +{% endblock %} diff --git a/test/test_defaults.py b/test/test_defaults.py new file mode 100644 index 00000000..4803fb5a --- /dev/null +++ b/test/test_defaults.py @@ -0,0 +1,14 @@ +from aurweb import defaults + + +def test_fallback_pp(): + assert defaults.fallback_pp(75) == defaults.PP + assert defaults.fallback_pp(100) == 100 + + +def test_pp(): + assert defaults.PP == 50 + + +def test_o(): + assert defaults.O == 0 diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index f1c20067..a25fcb7e 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -8,7 +8,7 @@ import pytest from fastapi.testclient import TestClient -from aurweb import asgi, db +from aurweb import asgi, db, defaults from aurweb.models.account_type import USER_ID, AccountType from aurweb.models.dependency_type import DependencyType from aurweb.models.official_provider import OfficialProvider @@ -74,6 +74,7 @@ def setup(): PackageNotification.__tablename__, PackageComaintainer.__tablename__, PackageComment.__tablename__, + PackageRequest.__tablename__, OfficialProvider.__tablename__ ) @@ -108,6 +109,18 @@ def maintainer() -> User: yield maintainer +@pytest.fixture +def tu_user(): + tu_type = db.query(AccountType, + AccountType.AccountType == "Trusted User").first() + with db.begin(): + tu_user = db.create(User, Username="test_tu", + Email="test_tu@example.org", + RealName="Test TU", Passwd="testPassword", + AccountType=tu_type) + yield tu_user + + @pytest.fixture def package(maintainer: User) -> Package: """ Yield a Package created by user. """ @@ -160,6 +173,25 @@ def packages(maintainer: User) -> List[Package]: yield packages_ +@pytest.fixture +def requests(user: User, packages: List[Package]) -> List[PackageRequest]: + pkgreqs = [] + deletion_type = db.query(RequestType).filter( + RequestType.ID == DELETION_ID + ).first() + with db.begin(): + for i in range(55): + pkgreq = db.create(PackageRequest, + RequestType=deletion_type, + User=user, + PackageBase=packages[i].PackageBase, + PackageBaseName=packages[i].Name, + Comments=f"Deletion request for pkg_{i}", + ClosureComment=str()) + pkgreqs.append(pkgreq) + yield pkgreqs + + def test_package_not_found(client: TestClient): with client as request: resp = request.get("/packages/not_found") @@ -1304,3 +1336,53 @@ def test_pkgbase_comaintainers(client: TestClient, user: User, root = parse_root(resp.text) users = root.xpath('//textarea[@id="id_users"]')[0] assert users is not None and users.text is None + + +def test_requests_unauthorized(client: TestClient, + maintainer: User, + tu_user: User, + packages: List[Package], + requests: List[PackageRequest]): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + resp = request.get("/requests", cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_requests(client: TestClient, + maintainer: User, + tu_user: User, + packages: List[Package], + requests: List[PackageRequest]): + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + resp = request.get("/requests", params={ + # Pass in url query parameters O, SeB and SB to exercise + # their paths inside of the pager_nav used in this request. + "O": 0, # Page 1 + "SeB": "nd", + "SB": "n" + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + assert "Next ›" in resp.text + assert "Last »" in resp.text + + root = parse_root(resp.text) + # We have 55 requests, our defaults.PP is 50, so expect we have 50 rows. + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == defaults.PP + + # Request page 2 of the requests page. + with client as request: + resp = request.get("/requests", params={ + "O": 50 # Page 2 + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + assert "‹ Previous" in resp.text + assert "« First" in resp.text + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 5 # There are five records left on the second page. diff --git a/test/test_templates.py b/test/test_templates.py index b6aa2055..86fbf611 100644 --- a/test/test_templates.py +++ b/test/test_templates.py @@ -1,6 +1,6 @@ import pytest -from aurweb.templates import register_filter +from aurweb.templates import register_filter, register_function @register_filter("func") @@ -8,6 +8,11 @@ def func(): pass +@register_function("function") +def function(): + pass + + def test_register_filter_exists_key_error(): """ Most instances of register_filter are tested through module imports or template renders, so we only test failures here. """ @@ -15,3 +20,12 @@ def test_register_filter_exists_key_error(): @register_filter("func") def some_func(): pass + + +def test_register_function_exists_key_error(): + """ Most instances of register_filter are tested through module + imports or template renders, so we only test failures here. """ + with pytest.raises(KeyError): + @register_function("function") + def some_func(): + pass diff --git a/test/test_util.py b/test/test_util.py index 0cc45409..99b77a78 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -1,7 +1,7 @@ from datetime import datetime from zoneinfo import ZoneInfo -from aurweb import util +from aurweb import filters, util def test_timestamp_to_datetime(): @@ -34,3 +34,9 @@ def test_to_qs(): query = {"a": "b", "c": [1, 2, 3]} qs = util.to_qs(query) assert qs == "a=b&c=1&c=2&c=3" + + +def test_round(): + assert filters.do_round(1.3) == 1 + assert filters.do_round(1.5) == 2 + assert filters.do_round(2.0) == 2 From 1cf9420997bc6788b4ae3264d8e019fd0ec13d56 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 12 Sep 2021 20:05:49 -0700 Subject: [PATCH 0908/1891] feat(FastAPI): allow reporters to cancel their own requests (1/2) This change required a slight modification of how we handle the Requests page. It is now available to all users. This commit provides 1/2 of the implementation which actually satisfies this feature. 2/2 will contain the actual implementation of closures of requests, which will also allow users who created the request to decide to close it. Issue: https://gitlab.archlinux.org/archlinux/aurweb/-/issues/20 Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 9 ++++++--- test/test_packages_routes.py | 28 +++++++++++++++++++++------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 5751a3ee..2b350478 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -12,8 +12,7 @@ import aurweb.models.package_keyword import aurweb.packages.util from aurweb import db, defaults, l10n -from aurweb.auth import account_type_required, auth_required -from aurweb.models.account_type import DEVELOPER, TRUSTED_USER, TRUSTED_USER_AND_DEV +from aurweb.auth import auth_required from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -540,7 +539,6 @@ async def package_base_comaintainers_post( @router.get("/requests") -@account_type_required({TRUSTED_USER, DEVELOPER, TRUSTED_USER_AND_DEV}) @auth_required(True, redirect="/") async def requests(request: Request, O: int = Query(default=defaults.O), @@ -556,6 +554,11 @@ async def requests(request: Request, User, PackageRequest.UsersID == User.ID ).join(RequestType) + # If the request user is not elevated (TU or Dev), then + # filter PackageRequests which are owned by the request user. + if not request.user.is_elevated(): + query = query.filter(PackageRequest.UsersID == request.user.ID) + context["total"] = query.count() context["results"] = query.order_by( # Order primarily by the Status column being PENDING_ID, diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index a25fcb7e..9867ce42 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1338,14 +1338,9 @@ def test_pkgbase_comaintainers(client: TestClient, user: User, assert users is not None and users.text is None -def test_requests_unauthorized(client: TestClient, - maintainer: User, - tu_user: User, - packages: List[Package], - requests: List[PackageRequest]): - cookies = {"AURSID": maintainer.login(Request(), "testPassword")} +def test_requests_unauthorized(client: TestClient): with client as request: - resp = request.get("/requests", cookies=cookies, allow_redirects=False) + resp = request.get("/requests", allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -1386,3 +1381,22 @@ def test_requests(client: TestClient, root = parse_root(resp.text) rows = root.xpath('//table[@class="results"]/tbody/tr') assert len(rows) == 5 # There are five records left on the second page. + + +def test_requests_selfmade(client: TestClient, user: User, + requests: List[PackageRequest]): + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get("/requests", cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # As the user who creates all of the requests, we should see all of them. + # However, we are not allowed to accept any of them ourselves. + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == defaults.PP + + # Our first and only link in the last row should be "Close". + for row in rows: + last_row = row.xpath('./td')[-1].xpath('./a')[0] + assert last_row.text.strip() == "Close" From ad8369395e323d99bd4b3cae430269ac8dd19491 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 12 Sep 2021 21:51:20 -0700 Subject: [PATCH 0909/1891] feat(FastAPI): add /pkgbase/{name}/request (get) This change brings in the package base request form for new submissions. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 14 ++++ templates/pkgbase/request.html | 87 ++++++++++++++++++++++++ test/test_packages_routes.py | 20 ++++++ web/html/js/typeahead-pkgbase-request.js | 36 ++++++++++ 4 files changed, 157 insertions(+) create mode 100644 templates/pkgbase/request.html create mode 100644 web/html/js/typeahead-pkgbase-request.js diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 2b350478..9c9a41e3 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -568,3 +568,17 @@ async def requests(request: Request, ).limit(PP).offset(O).all() return render_template(request, "requests.html", context) + + +@router.get("/pkgbase/{name}/request") +@auth_required(True) +async def package_request(request: Request, name: str): + context = make_context(request, "Submit Request") + + pkgbase = db.query(PackageBase).filter(PackageBase.Name == name).first() + + if not pkgbase: + raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) + + context["pkgbase"] = pkgbase + return render_template(request, "pkgbase/request.html", context) diff --git a/templates/pkgbase/request.html b/templates/pkgbase/request.html new file mode 100644 index 00000000..66d69f07 --- /dev/null +++ b/templates/pkgbase/request.html @@ -0,0 +1,87 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {{ "Submit Request" | tr }}: {{ pkgbase.Name }}

    +

    + {{ "Use this form to file a request against package base " + "%s%s%s which includes the following packages:" + | tr | format("", pkgbase.Name, "") | safe }} +

    +
      + {% for package in pkgbase.packages %} +
    • {{ package.Name }}
    • + {% endfor %} +
    + + {# Request form #} +
    +
    +

    + + +

    + + {# Javascript included for HTML-changing triggers depending + on the selected type (above). #} + + + + +

    + + +

    + +

    + {{ + "By submitting a deletion request, you ask a Trusted " + "User to delete the package base. This type of " + "request should be used for duplicates, software " + "abandoned by upstream, as well as illegal and " + "irreparably broken packages." | tr + }} +

    + + + + + +

    + +

    + +
    +
    + +
    +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 9867ce42..8704d702 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1400,3 +1400,23 @@ def test_requests_selfmade(client: TestClient, user: User, for row in rows: last_row = row.xpath('./td')[-1].xpath('./a')[0] assert last_row.text.strip() == "Close" + + +def test_pkgbase_request_not_found(client: TestClient, user: User): + pkgbase_name = "fake" + endpoint = f"/pkgbase/{pkgbase_name}/request" + + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_request(client: TestClient, user: User, package: Package): + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/request" + + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) diff --git a/web/html/js/typeahead-pkgbase-request.js b/web/html/js/typeahead-pkgbase-request.js new file mode 100644 index 00000000..e012d55f --- /dev/null +++ b/web/html/js/typeahead-pkgbase-request.js @@ -0,0 +1,36 @@ +function showHideMergeSection() { + const elem = document.getElementById('id_type'); + const merge_section = document.getElementById('merge_section'); + if (elem.value == 'merge') { + merge_section.style.display = ''; + } else { + merge_section.style.display = 'none'; + } +} + +function showHideRequestHints() { + document.getElementById('deletion_hint').style.display = 'none'; + document.getElementById('merge_hint').style.display = 'none'; + document.getElementById('orphan_hint').style.display = 'none'; + + const elem = document.getElementById('id_type'); + document.getElementById(elem.value + '_hint').style.display = ''; +} + +document.addEventListener('DOMContentLoaded', function() { + showHideMergeSection(); + showHideRequestHints(); + + const input = document.getElementById('id_merge_into'); + const form = document.getElementById('request-form'); + const type = "suggest-pkgbase"; + + typeahead.init(type, input, form, false); +}); + +// Bind the change event here, otherwise we have to inline javascript, +// which angers CSP (Content Security Policy). +document.getElementById("id_type").addEventListener("change", function() { + showHideMergeSection(); + showHideRequestHints(); +}); From 1c031638c65588ef5c219adffdaf1a7b695d0d02 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 13 Sep 2021 17:26:25 -0700 Subject: [PATCH 0910/1891] feat(FastAPI): add /pkgbase/{name}/request (post) This change implements the FastAPI version of the /pkgbase/{name}/request form's action. Changes from PHP: - Additional errors are now displayed for the **merge_into** field, which are only displayed when the Merge type is selected. - If the **merge_into** field is empty, a new error is displayed: 'The "Merge into" field must not be empty.' - If the **merge_into** field is given the name of a package base which does not exist, a new error is displayed: "The package base you want to merge into does not exist." - If the **merge_into** field is given the name of the package base that a request is being created for, a new error is displayed: "You cannot merge a package base into itself." - When an error is encountered, users are now brought back to the request form which they submitted and an error is displayed at the top of the page. - If an invalid type is provided, users are returned to a BAD_REQUEST status rendering of the request form. Signed-off-by: Kevin Morris --- aurweb/models/request_type.py | 6 ++ aurweb/routers/packages.py | 69 ++++++++++++++ templates/pkgbase/request.html | 12 ++- test/test_packages_routes.py | 161 +++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+), 1 deletion(-) diff --git a/aurweb/models/request_type.py b/aurweb/models/request_type.py index a26dcf9a..48ace3a3 100644 --- a/aurweb/models/request_type.py +++ b/aurweb/models/request_type.py @@ -20,6 +20,12 @@ class RequestType(Base): name = self.Name return name[0].upper() + name[1:] + def title(self) -> str: + return self.name_display() + + def __getitem__(self, n: int) -> str: + return self.Name[n] + DELETION_ID = db.query(RequestType, RequestType.Name == DELETION).first().ID ORPHAN_ID = db.query(RequestType, RequestType.Name == ORPHAN).first().ID diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 9c9a41e3..231f953b 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -582,3 +582,72 @@ async def package_request(request: Request, name: str): context["pkgbase"] = pkgbase return render_template(request, "pkgbase/request.html", context) + + +@router.post("/pkgbase/{name}/request") +@auth_required(True) +async def pkgbase_request_post(request: Request, name: str, + type: str = Form(...), + merge_into: str = Form(default=None), + comments: str = Form(default=str())): + pkgbase = get_pkg_or_base(name, PackageBase) + + # Create our render context. + context = make_context(request, "Submit Request") + context["pkgbase"] = pkgbase + if type not in {"deletion", "merge", "orphan"}: + # In the case that someone crafted a POST request with an invalid + # type, just return them to the request form with BAD_REQUEST status. + return render_template(request, "pkgbase/request.html", context, + status_code=HTTPStatus.BAD_REQUEST) + + if not comments: + context["errors"] = ["The comment field must not be empty."] + return render_template(request, "pkgbase/request.html", context) + + if type == "merge": + # Perform merge-related checks. + if not merge_into: + # TODO: This error needs to be translated. + context["errors"] = ['The "Merge into" field must not be empty.'] + return render_template(request, "pkgbase/request.html", context) + + target = db.query(PackageBase).filter( + PackageBase.Name == merge_into + ).first() + if not target: + # TODO: This error needs to be translated. + context["errors"] = [ + "The package base you want to merge into does not exist." + ] + return render_template(request, "pkgbase/request.html", context) + + if target.ID == pkgbase.ID: + # TODO: This error needs to be translated. + context["errors"] = [ + "You cannot merge a package base into itself." + ] + return render_template(request, "pkgbase/request.html", context) + + # All good. Create a new PackageRequest based on the given type. + now = int(datetime.utcnow().timestamp()) + reqtype = db.query(RequestType, RequestType.Name == type).first() + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + notify_ = None + with db.begin(): + pkgreq = db.create(PackageRequest, RequestType=reqtype, RequestTS=now, + PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + MergeBaseName=merge_into, User=request.user, + Comments=comments, ClosureComment=str()) + + # Prepare notification object. + notify_ = notify.RequestOpenNotification( + conn, request.user.ID, pkgreq.ID, reqtype, + pkgreq.PackageBase.ID, merge_into=merge_into or None) + + # Send the notification now that we're out of the DB scope. + notify_.send() + + # Redirect the submitting user to /packages. + return RedirectResponse("/packages", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/pkgbase/request.html b/templates/pkgbase/request.html index 66d69f07..bb9b5aba 100644 --- a/templates/pkgbase/request.html +++ b/templates/pkgbase/request.html @@ -1,8 +1,17 @@ {% extends "partials/layout.html" %} {% block pageContent %} + {% if errors %} +
      + {% for error in errors %} +
    • {{ error | tr }}
    • + {% endfor %} +
    + {% endif %} +

    {{ "Submit Request" | tr }}: {{ pkgbase.Name }}

    +

    {{ "Use this form to file a request against package base " "%s%s%s which includes the following packages:" @@ -15,7 +24,8 @@ {# Request form #} -

    +

    diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 8704d702..5353d3bf 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1420,3 +1420,164 @@ def test_pkgbase_request(client: TestClient, user: User, package: Package): with client as request: resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) + + +def test_pkgbase_request_post_deletion(client: TestClient, user: User, + package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "deletion", + "comments": "We want to delete this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + pkgreq = db.query(PackageRequest).filter( + PackageRequest.PackageBaseID == package.PackageBase.ID + ).first() + assert pkgreq is not None + assert pkgreq.RequestType.Name == "deletion" + assert pkgreq.PackageBaseName == package.PackageBase.Name + assert pkgreq.Comments == "We want to delete this." + + +def test_pkgbase_request_post_orphan(client: TestClient, user: User, + package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "orphan", + "comments": "We want to disown this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + pkgreq = db.query(PackageRequest).filter( + PackageRequest.PackageBaseID == package.PackageBase.ID + ).first() + assert pkgreq is not None + assert pkgreq.RequestType.Name == "orphan" + assert pkgreq.PackageBaseName == package.PackageBase.Name + assert pkgreq.Comments == "We want to disown this." + + +def test_pkgbase_request_post_merge(client: TestClient, user: User, + package: Package): + with db.begin(): + pkgbase2 = db.create(PackageBase, Name="new-pkgbase", + Submitter=user, Maintainer=user, Packager=user) + target = db.create(Package, PackageBase=pkgbase2, + Name=pkgbase2.Name, Version="1.0.0") + + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "merge", + "merge_into": target.PackageBase.Name, + "comments": "We want to merge this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + pkgreq = db.query(PackageRequest).filter( + PackageRequest.PackageBaseID == package.PackageBase.ID + ).first() + assert pkgreq is not None + assert pkgreq.RequestType.Name == "merge" + assert pkgreq.PackageBaseName == package.PackageBase.Name + assert pkgreq.MergeBaseName == target.PackageBase.Name + assert pkgreq.Comments == "We want to merge this." + + +def test_pkgbase_request_post_not_found(client: TestClient, user: User): + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post("/pkgbase/fake/request", data={ + "type": "fake" + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.NOT_FOUND) + + +def test_pkgbase_request_post_invalid_type(client: TestClient, + user: User, + package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={"type": "fake"}, cookies=cookies) + assert resp.status_code == int(HTTPStatus.BAD_REQUEST) + + +def test_pkgbase_request_post_no_comment_error(client: TestClient, + user: User, + package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "deletion", + "comments": "" # An empty comment field causes an error. + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + error = root.xpath('//ul[@class="errorlist"]/li')[0] + expected = "The comment field must not be empty." + assert error.text.strip() == expected + + +def test_pkgbase_request_post_merge_not_found_error(client: TestClient, + user: User, + package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "merge", + "merge_into": "fake", # There is no PackageBase.Name "fake" + "comments": "We want to merge this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + error = root.xpath('//ul[@class="errorlist"]/li')[0] + expected = "The package base you want to merge into does not exist." + assert error.text.strip() == expected + + +def test_pkgbase_request_post_merge_no_merge_into_error(client: TestClient, + user: User, + package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "merge", + "merge_into": "", # There is no PackageBase.Name "fake" + "comments": "We want to merge this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + error = root.xpath('//ul[@class="errorlist"]/li')[0] + expected = 'The "Merge into" field must not be empty.' + assert error.text.strip() == expected + + +def test_pkgbase_request_post_merge_self_error(client: TestClient, user: User, + package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "merge", + "merge_into": package.PackageBase.Name, + "comments": "We want to merge this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + error = root.xpath('//ul[@class="errorlist"]/li')[0] + expected = "You cannot merge a package base into itself." + assert error.text.strip() == expected From f6141ff1778e8d1376a0db3b92e7a7d7fa2f9097 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 14 Sep 2021 21:37:35 -0700 Subject: [PATCH 0911/1891] feat(FastAPI): add /requests/{id}/close (get, post) Changes from PHP: - If a user submits a POST request with an invalid reason, they are returned back to the closure form with a BAD_REQUEST status. - Now, users which created a PackageRequest have the ability to close their own. - Form action has been changed to `/requests/{id}/close`. Closes https://gitlab.archlinux.org/archlinux/aurweb/-/issues/20 Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 52 ++++++++++++++++++++- templates/requests/close.html | 60 ++++++++++++++++++++++++ test/test_packages_routes.py | 86 ++++++++++++++++++++++++++++++++++- 3 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 templates/requests/close.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 231f953b..a3effb36 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -22,7 +22,7 @@ from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_license import PackageLicense from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation -from aurweb.models.package_request import PENDING_ID, PackageRequest +from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID, PackageRequest from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID @@ -651,3 +651,53 @@ async def pkgbase_request_post(request: Request, name: str, # Redirect the submitting user to /packages. return RedirectResponse("/packages", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.get("/requests/{id}/close") +@auth_required(True) +async def requests_close(request: Request, id: int): + pkgreq = db.query(PackageRequest).filter(PackageRequest.ID == id).first() + if not request.user.is_elevated() and request.user != pkgreq.User: + # Request user doesn't have permission here: redirect to '/'. + return RedirectResponse("/", status_code=int(HTTPStatus.SEE_OTHER)) + + context = make_context(request, "Close Request") + context["pkgreq"] = pkgreq + return render_template(request, "requests/close.html", context) + + +@router.post("/requests/{id}/close") +@auth_required(True) +async def requests_close_post(request: Request, id: int, + reason: int = Form(default=0), + comments: str = Form(default=str())): + pkgreq = db.query(PackageRequest).filter(PackageRequest.ID == id).first() + if not request.user.is_elevated() and request.user != pkgreq.User: + # Request user doesn't have permission here: redirect to '/'. + return RedirectResponse("/", status_code=int(HTTPStatus.SEE_OTHER)) + + context = make_context(request, "Close Request") + context["pkgreq"] = pkgreq + + if reason not in {ACCEPTED_ID, REJECTED_ID}: + # If the provided reason is not valid, send the user back to + # the closure form with a BAD_REQUEST status. + return render_template(request, "requests/close.html", context, + status_code=HTTPStatus.BAD_REQUEST) + + if not request.user.is_elevated(): + # If we're closing the request as the user who created it, + # the reason should just be a REJECTION. + reason = REJECTED_ID + + with db.begin(): + pkgreq.Closer = request.user + pkgreq.Status = reason + pkgreq.ClosureComment = comments + + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + notify_ = notify.RequestCloseNotification( + conn, request.user.ID, pkgreq.ID, pkgreq.status_display()) + notify_.send() + + return RedirectResponse("/requests", status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/requests/close.html b/templates/requests/close.html new file mode 100644 index 00000000..7862064a --- /dev/null +++ b/templates/requests/close.html @@ -0,0 +1,60 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +

    +

    {{ "Close Request" | tr }}: {{ pkgreq.PackageBaseName }}

    + +

    + {{ + "Use this form to close the request for package base %s%s%s." + | tr | format("", pkgreq.PackageBaseName, "") + | safe + }} +

    + +

    + {{ "Note" | tr }}: + {{ + "The comments field can be left empty. However, it is highly " + "recommended to add a comment when rejecting a request." + | tr + }} +

    + + +
    +

    + + +

    + +

    + + +

    + +

    + +

    + +
    + + +
    +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 5353d3bf..5afe011a 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -20,7 +20,7 @@ from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_keyword import PackageKeyword from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation -from aurweb.models.package_request import PackageRequest +from aurweb.models.package_request import ACCEPTED_ID, REJECTED_ID, PackageRequest from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import PROVIDES_ID, RelationType from aurweb.models.request_type import DELETION_ID, RequestType @@ -1581,3 +1581,87 @@ def test_pkgbase_request_post_merge_self_error(client: TestClient, user: User, error = root.xpath('//ul[@class="errorlist"]/li')[0] expected = "You cannot merge a package base into itself." assert error.text.strip() == expected + + +@pytest.fixture +def pkgreq(user: User, package: Package) -> PackageRequest: + reqtype = db.query(RequestType).filter( + RequestType.ID == DELETION_ID + ).first() + with db.begin(): + pkgreq = db.create(PackageRequest, + RequestType=reqtype, + User=user, + PackageBase=package.PackageBase, + PackageBaseName=package.PackageBase.Name, + Comments=str(), + ClosureComment=str()) + yield pkgreq + + +def test_requests_close(client: TestClient, user: User, + pkgreq: PackageRequest): + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies, + allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + + +def test_requests_close_unauthorized(client: TestClient, maintainer: User, + pkgreq: PackageRequest): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies, + allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == "/" + + +def test_requests_close_post_invalid_reason(client: TestClient, user: User, + pkgreq: PackageRequest): + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(f"/requests/{pkgreq.ID}/close", data={ + "reason": 0 + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.BAD_REQUEST) + + +def test_requests_close_post_unauthorized(client: TestClient, maintainer: User, + pkgreq: PackageRequest): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + resp = request.post(f"/requests/{pkgreq.ID}/close", data={ + "reason": ACCEPTED_ID + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == "/" + + +def test_requests_close_post(client: TestClient, user: User, + pkgreq: PackageRequest): + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(f"/requests/{pkgreq.ID}/close", data={ + "reason": REJECTED_ID + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + assert pkgreq.Status == REJECTED_ID + assert pkgreq.Closer == user + assert pkgreq.ClosureComment == str() + + +def test_requests_close_post_rejected(client: TestClient, user: User, + pkgreq: PackageRequest): + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(f"/requests/{pkgreq.ID}/close", data={ + "reason": REJECTED_ID + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + assert pkgreq.Status == REJECTED_ID + assert pkgreq.Closer == user + assert pkgreq.ClosureComment == str() From b5f8e69b8aaefc093eabb3163eb0dd6445682a8b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 3 Oct 2021 10:22:34 -0700 Subject: [PATCH 0912/1891] feat(FastAPI): use SQLAlchemy's scoped_session Closes #113 Signed-off-by: Kevin Morris --- aurweb/db.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aurweb/db.py b/aurweb/db.py index ea6b6918..2b934300 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -3,6 +3,7 @@ import math import re from sqlalchemy import event +from sqlalchemy.orm import scoped_session import aurweb.config import aurweb.util @@ -167,7 +168,8 @@ def get_engine(echo: bool = False): connect_args=connect_args, echo=echo) - Session = sessionmaker(autocommit=True, autoflush=False, bind=engine) + Session = scoped_session( + sessionmaker(autocommit=True, autoflush=False, bind=engine)) session = Session() if db_backend == "sqlite": From 7bfc2bf9b44ba13526b20160531aea208f694c89 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 3 Oct 2021 15:11:42 -0700 Subject: [PATCH 0913/1891] fix(FastAPI): Improve sqlite testing speed This commit adds a new Arch dependency: `libeatmydata`, which provides the `eatmydata` executable that stubs out fsync() operations. We use `eatmydata` to run our sharness and pytests in Docker now. With `autocommit=True`, required by SQLAlchemy to keep the session up to date with external DB modifications, many fsync calls are used in the SQLite backend; especially because we're wiping and creating records in every DB-bound test. **Before:** - mysql: 1m42s (elapsed during pytest run) - sqlite: 3m06s (elapsed during pytest run) **After:** - mysql: 1m40s (elapsed during pytest run) - sqlite: 1m50s (elapsed during pytest run) Shout out to @klausenbusk, who suggested this as a possible fix, and it was. Thanks, Kristian! Closes #120 Signed-off-by: Kevin Morris --- docker/scripts/install-deps.sh | 2 +- docker/scripts/run-pytests.sh | 2 +- docker/scripts/run-sharness.sh | 2 +- test/README.md | 10 ++++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index f8881d05..fc068b06 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -8,7 +8,7 @@ pacman -Syu --noconfirm --noprogressbar \ --cachedir .pkg-cache git gpgme nginx redis openssh \ mariadb mariadb-libs cgit uwsgi uwsgi-plugin-cgi \ php php-fpm memcached php-memcached python-pip pyalpm \ - python-srcinfo curl + python-srcinfo curl libeatmydata # https://python-poetry.org/docs/ Installation section. curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - diff --git a/docker/scripts/run-pytests.sh b/docker/scripts/run-pytests.sh index c6baa939..ef8a2318 100755 --- a/docker/scripts/run-pytests.sh +++ b/docker/scripts/run-pytests.sh @@ -27,7 +27,7 @@ python -m aurweb.initdb 2>/dev/null || \ (echo "Error: aurweb.initdb failed; already initialized?" && /bin/true) # Run pytest with optional targets in front of it. -make -C test "${PARAMS[@]}" pytest +eatmydata -- make -C test "${PARAMS[@]}" pytest # By default, report coverage and move it into cache. if [ $COVERAGE -eq 1 ]; then diff --git a/docker/scripts/run-sharness.sh b/docker/scripts/run-sharness.sh index 8e928b3f..fe16751c 100755 --- a/docker/scripts/run-sharness.sh +++ b/docker/scripts/run-sharness.sh @@ -4,4 +4,4 @@ set -eou pipefail # Initialize the new database; ignore errors. python -m aurweb.initdb 2>/dev/null || /bin/true -make -C test sh +eatmydata -- make -C test sh diff --git a/test/README.md b/test/README.md index ef8a08f4..13fb0a0c 100644 --- a/test/README.md +++ b/test/README.md @@ -31,6 +31,10 @@ For all the test to run, the following Arch packages should be installed: - postfix - openssh +Optional (faster testing) + +- libeatmydata + Test Configuration ------------------ @@ -115,6 +119,12 @@ To run `pytest` Python test suites: $ make -C test pytest +**Note:** For SQLite tests, users may want to use `eatmydata` +to improve speed: + + $ eatmydata -- make -C test sh + $ eatmydata -- make -C test pytest + To produce coverage reports related to Python when running tests manually, use the following method: From 08068e0a5c70ef8d5ef94c20952d9aa15ba6c8dc Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Mon, 4 Oct 2021 13:30:25 -0400 Subject: [PATCH 0914/1891] fix(FastAPI): use configured letter case for SSH fingerprints Currently, the config parser converts all keys to lowercase which is inconsistent with the old PHP behavior. This has been fixed and relevant fingerprint-getting functions have been simplified without changes in behavior. Signed-off-by: Steven Guikal --- aurweb/config.py | 8 ++++---- aurweb/util.py | 8 +------- test/test_homepage.py | 4 +++- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 52fadda2..aa111f15 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -17,6 +17,7 @@ def _get_parser(): defaults = os.environ.get('AUR_CONFIG_DEFAULTS', path + '.defaults') _parser = configparser.RawConfigParser() + _parser.optionxform = lambda option: option if os.path.isfile(defaults): with open(defaults) as f: _parser.read_file(f) @@ -48,7 +49,6 @@ def getint(section, option, fallback=None): return _get_parser().getint(section, option, fallback=fallback) -def get_section(section_name): - for section in _get_parser().sections(): - if section == section_name: - return _get_parser()[section] +def get_section(section): + if section in _get_parser().sections(): + return _get_parser()[section] diff --git a/aurweb/util.py b/aurweb/util.py index f9181811..08e6d7c6 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -166,10 +166,4 @@ def add_samesite_fields(response: Response, value: str): def get_ssh_fingerprints(): - fingerprints = {} - fingerprint_section = aurweb.config.get_section("fingerprints") - - if fingerprint_section: - fingerprints = {key: fingerprint_section[key] for key in fingerprint_section.keys()} - - return fingerprints + return aurweb.config.get_section("fingerprints") or {} diff --git a/test/test_homepage.py b/test/test_homepage.py index fef3532d..5c678b71 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -96,7 +96,9 @@ def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock): with client as request: response = request.get("/") - assert list(fingerprints.values())[0] in response.content.decode() + for key, value in fingerprints.items(): + assert key in response.content.decode() + assert value in response.content.decode() assert 'The following SSH fingerprints are used for the AUR' in response.content.decode() From 5c179dc4d35b8c2bbacce61d0664fc7285d99e56 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Mon, 4 Oct 2021 17:04:23 -0400 Subject: [PATCH 0915/1891] fix(FastAPI): use consistent ordering on dashboard and request page Signed-off-by: Steven Guikal --- aurweb/routers/html.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 3d44cf87..6e7697e4 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -6,7 +6,7 @@ from http import HTTPStatus from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse -from sqlalchemy import and_, or_ +from sqlalchemy import and_, case, or_ import aurweb.config import aurweb.models.package_request @@ -17,7 +17,7 @@ from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_comaintainer import PackageComaintainer -from aurweb.models.package_request import PackageRequest +from aurweb.models.package_request import PENDING_ID, PackageRequest from aurweb.models.user import User from aurweb.packages.util import query_notified, query_voted, updated_packages from aurweb.templates import make_context, render_template @@ -166,6 +166,11 @@ async def index(request: Request): # Package requests created by request.user. context["package_requests"] = request.user.package_requests.filter( PackageRequest.RequestTS >= start + ).order_by( + # Order primarily by the Status column being PENDING_ID, + # and secondarily by RequestTS; both in descending order. + case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), + PackageRequest.RequestTS.desc() ).limit(50).all() # Packages that the request user maintains or comaintains. From 9af76a73a331b889815e42866e3df4bbe8ddc5d0 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Mon, 4 Oct 2021 16:32:10 -0400 Subject: [PATCH 0916/1891] fix(FastAPI): include MergeBaseName in merge request type This was done on the dedicated requests page, but missed on the dashboard. Signed-off-by: Steven Guikal --- templates/partials/packages/requests.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/templates/partials/packages/requests.html b/templates/partials/packages/requests.html index 5239ca72..5188a476 100644 --- a/templates/partials/packages/requests.html +++ b/templates/partials/packages/requests.html @@ -20,7 +20,13 @@ {{ request.PackageBase.Name }}
    - {{ request.RequestType.name_display() | tr }} + + {{ request.RequestType.name_display() | tr }} + {# If the RequestType is a merge and request.MergeBaseName is valid... #} + {% if request.RequestType.ID == 3 and request.MergeBaseName %} + ({{ request.MergeBaseName }}) + {% endif %} + {{ request.Comments }} Date: Mon, 4 Oct 2021 17:37:25 -0400 Subject: [PATCH 0917/1891] fix(FastAPI): add missing translation filter for request type Signed-off-by: Steven Guikal --- templates/requests.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/requests.html b/templates/requests.html index a9017e2f..74ea6416 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -31,7 +31,7 @@ {# Type #} - {{ result.RequestType.name_display() }} + {{ result.RequestType.name_display() | tr }} {# If the RequestType is a merge and request.MergeBaseName is valid... #} {% if result.RequestType.ID == 3 and result.MergeBaseName %} ({{ result.MergeBaseName }}) From 1956be0f469e5870d957a8dec2fa48100a247273 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Tue, 5 Oct 2021 14:00:12 -0400 Subject: [PATCH 0918/1891] fix(FastAPI): prefill login fields with entered data --- aurweb/routers/auth.py | 16 ++++++++-------- templates/login.html | 9 +++++++-- test/test_auth_routes.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 8f37fe27..a985281e 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -9,14 +9,14 @@ import aurweb.config from aurweb import util from aurweb.auth import auth_required from aurweb.models.user import User -from aurweb.templates import make_context, render_template +from aurweb.templates import make_variable_context, render_template router = APIRouter() -def login_template(request: Request, next: str, errors: list = None): +async def login_template(request: Request, next: str, errors: list = None): """ Provide login-specific template context to render_template. """ - context = make_context(request, "Login", next) + context = await make_variable_context(request, "Login", next) context["errors"] = errors context["url_base"] = f"{request.url.scheme}://{request.url.netloc}" return render_template(request, "login.html", context) @@ -25,7 +25,7 @@ def login_template(request: Request, next: str, errors: list = None): @router.get("/login", response_class=HTMLResponse) @auth_required(False) async def login_get(request: Request, next: str = "/"): - return login_template(request, next) + return await login_template(request, next) @router.post("/login", response_class=HTMLResponse) @@ -39,8 +39,8 @@ async def login_post(request: Request, user = session.query(User).filter(User.Username == user).first() if not user: - return login_template(request, next, - errors=["Bad username or password."]) + return await login_template(request, next, + errors=["Bad username or password."]) cookie_timeout = 0 @@ -50,8 +50,8 @@ async def login_post(request: Request, sid = user.login(request, passwd, cookie_timeout) if not sid: - return login_template(request, next, - errors=["Bad username or password."]) + return await login_template(request, next, + errors=["Bad username or password."]) login_timeout = aurweb.config.getint("options", "login_timeout") diff --git a/templates/login.html b/templates/login.html index da7bd722..3c4f945f 100644 --- a/templates/login.html +++ b/templates/login.html @@ -45,7 +45,8 @@ + maxlength="254" autofocus="autofocus" + value="{{ user or '' }}">

    @@ -57,7 +58,11 @@

    - + diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 1d8f9cbe..313f9927 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -160,6 +160,11 @@ def test_login_missing_username(): response = request.post("/login", data=post_data) assert "AURSID" not in response.cookies + # Make sure password isn't prefilled and remember_me isn't checked. + content = response.content.decode() + assert post_data["passwd"] not in content + assert "checked" not in content + def test_login_remember_me(): post_data = { @@ -188,6 +193,26 @@ def test_login_remember_me(): assert _session.LastUpdateTS < expected_ts + 5 +def test_login_incorrect_password_remember_me(): + post_data = { + "user": "test", + "passwd": "badPassword", + "next": "/", + "remember_me": "on" + } + + with client as request: + response = request.post("/login", data=post_data) + assert "AURSID" not in response.cookies + + # Make sure username is prefilled, password isn't prefilled, and remember_me + # is checked. + content = response.content.decode() + assert post_data["user"] in content + assert post_data["passwd"] not in content + assert "checked" in content + + def test_login_missing_password(): post_data = { "user": "test", @@ -198,6 +223,11 @@ def test_login_missing_password(): response = request.post("/login", data=post_data) assert "AURSID" not in response.cookies + # Make sure username is prefilled and remember_me isn't checked. + content = response.content.decode() + assert post_data["user"] in content + assert "checked" not in content + def test_login_incorrect_password(): post_data = { @@ -209,3 +239,10 @@ def test_login_incorrect_password(): with client as request: response = request.post("/login", data=post_data) assert "AURSID" not in response.cookies + + # Make sure username is prefilled, password isn't prefilled and remember_me + # isn't checked. + content = response.content.decode() + assert post_data["user"] in content + assert post_data["passwd"] not in content + assert "checked" not in content From 1bce53bbb7343fc861f253e97be171403bb930f4 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Tue, 5 Oct 2021 14:36:46 -0400 Subject: [PATCH 0919/1891] fix(FastAPI): mark user and passwd as required fields --- templates/login.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/login.html b/templates/login.html index 3c4f945f..45fc1645 100644 --- a/templates/login.html +++ b/templates/login.html @@ -46,7 +46,7 @@ + required="required" value="{{ user or '' }}">

    @@ -54,7 +54,7 @@ {% trans %}Password{% endtrans %}: + size="30" required="required">

    From a54a09f61d0495789b22724c5f83bf883af83b45 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Tue, 5 Oct 2021 12:38:31 -0400 Subject: [PATCH 0920/1891] fix(FastAPI): fix padding on email inputs Signed-off-by: Steven Guikal --- web/html/css/archweb.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web/html/css/archweb.css b/web/html/css/archweb.css index b935d7db..45b9bff0 100644 --- a/web/html/css/archweb.css +++ b/web/html/css/archweb.css @@ -329,6 +329,7 @@ label { input[type=text], input[type=password], +input[type=email], textarea { padding: 0.10em; } From 889c5b1e21788a1f3126dfa121b6253ea9497501 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 6 Oct 2021 22:08:17 -0700 Subject: [PATCH 0921/1891] fix(FastAPI): pkgbase actions template Display Delete, Merge and Disown actions based on user credentials. Signed-off-by: Kevin Morris --- templates/partials/packages/actions.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 6c30153c..a54d4c90 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -142,17 +142,21 @@ {% endif %}

  • - {% if is_maintainer %} + {% if request.user.has_credential("CRED_PKGBASE_DELETE") %}
  • {{ "Delete Package" | tr }}
  • + {% endif %} + {% if request.user.has_credential("CRED_PKGBASE_MERGE") %}
  • {{ "Merge Package" | tr }}
  • + {% endif %} + {% if request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %}
  • Date: Wed, 6 Oct 2021 22:29:53 -0700 Subject: [PATCH 0922/1891] feat(FastAPI): add CRED_PKGBASE_MERGE Signed-off-by: Kevin Morris --- aurweb/auth.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/auth.py b/aurweb/auth.py index 21d31081..fb062eab 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -268,6 +268,7 @@ CRED_PKGREQ_LIST = 18 CRED_TU_ADD_VOTE = 19 CRED_TU_LIST_VOTES = 20 CRED_TU_VOTE = 21 +CRED_PKGBASE_MERGE = 29 def has_any(user, *account_types): @@ -321,6 +322,7 @@ cred_filters = { CRED_TU_LIST_VOTES: trusted_user, CRED_TU_VOTE: trusted_user, CRED_ACCOUNT_EDIT_DEV: developer, + CRED_PKGBASE_MERGE: trusted_user_or_dev, } From e5299b5ed4c9c9041217f196f5721d8b49bfbf00 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 6 Oct 2021 23:17:08 -0700 Subject: [PATCH 0923/1891] fix(FastAPI): pkgbase/package tests Signed-off-by: Kevin Morris --- test/test_packages_routes.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 5afe011a..4118744a 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -335,6 +335,30 @@ def test_package_authenticated_maintainer(client: TestClient, resp = request.get(package_endpoint(package), cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) + expected = [ + "View PKGBUILD", + "View Changes", + "Download snapshot", + "Search wiki", + "Flag package out-of-date", + "Vote for this package", + "Enable notifications", + "Manage Co-Maintainers", + "Submit Request", + "Disown Package" + ] + for expected_text in expected: + assert expected_text in resp.text + + +def test_package_authenticated_tu(client: TestClient, + tu_user: User, + package: Package): + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + resp = request.get(package_endpoint(package), cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + expected = [ "View PKGBUILD", "View Changes", From 75c49e4f8ada4cae1c5c5fd02ddd3ce73e7ac06a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 00:03:24 -0700 Subject: [PATCH 0924/1891] feat(FastAPI): support {named} fmt in auth_required redirect Signed-off-by: Kevin Morris --- aurweb/auth.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index fb062eab..d44d4ded 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -1,4 +1,5 @@ import functools +import re from datetime import datetime from http import HTTPStatus @@ -121,6 +122,7 @@ class BasicAuthBackend(AuthenticationBackend): def auth_required(is_required: bool = True, + login: bool = False, redirect: str = "/", template: tuple = None, status_code: HTTPStatus = HTTPStatus.UNAUTHORIZED): @@ -162,8 +164,16 @@ def auth_required(is_required: bool = True, async def wrapper(request, *args, **kwargs): if request.user.is_authenticated() != is_required: url = "/" + if redirect: - url = redirect + path_params_expr = re.compile(r'\{(\w+)\}') + match = re.findall(path_params_expr, redirect) + args = {k: request.path_params.get(k) for k in match} + url = redirect.format(**args) + + if login: + url = "/login?" + util.urlencode({"next": url}) + if template: # template=("template.html", # ["Some Title", "someFormatted {}"], From 8bc1fab74df9f14a47ad1923a718633702ae82eb Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 00:26:57 -0700 Subject: [PATCH 0925/1891] change(FastAPI): automate request login requirement Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 2 +- templates/partials/packages/actions.html | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index a3effb36..539f9526 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -571,7 +571,7 @@ async def requests(request: Request, @router.get("/pkgbase/{name}/request") -@auth_required(True) +@auth_required(True, login=True, redirect="/pkgbase/{name}") async def package_request(request: Request, name: str): context = make_context(request, "Submit Request") diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index a54d4c90..7355420c 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -132,15 +132,9 @@
  • {% endif %}
  • - {% if not request.user.is_authenticated() %} - - {{ "Submit Request" | tr }} - - {% else %} {{ "Submit Request" | tr }} - {% endif %}
  • {% if request.user.has_credential("CRED_PKGBASE_DELETE") %}
  • From dc11a88ed35f9cfc8c253e23f5814867448f3ac0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 00:39:25 -0700 Subject: [PATCH 0926/1891] change(FastAPI): depend on auth_required redirect for pkgbase actions Signed-off-by: Kevin Morris --- templates/partials/packages/actions.html | 133 +++++++++-------------- 1 file changed, 51 insertions(+), 82 deletions(-) diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 7355420c..f1863663 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -23,99 +23,68 @@ {{ "Search wiki" | tr }}
  • - {% if not request.user.is_authenticated() %} - {% if not out_of_date %} + {% if not out_of_date %}
  • {{ "Flag package out-of-date" | tr }}
  • - {% else %} -
  • - - {% set ood_ts = result.OutOfDateTS | dt | as_timezone(timezone) %} - {{ - "Flagged out-of-date (%s)" - | tr | format(ood_ts.strftime("%Y-%m-%d")) - }} - -
  • - {% endif %} -
  • - - {{ "Vote for this package" | tr }} - -
  • -
  • - - {{ "Enable notifications" | tr }} - -
  • {% else %} - {% if not out_of_date %} -
  • - - {{ "Flag package out-of-date" | tr }} - -
  • - {% else %} -
  • - - {% set ood_ts = result.OutOfDateTS | dt | as_timezone(timezone) %} - {{ - "Flagged out-of-date (%s)" - | tr | format(ood_ts.strftime("%Y-%m-%d")) - }} - -
  • -
  • - - + + {% set ood_ts = result.OutOfDateTS | dt | as_timezone(timezone) %} + {{ + "Flagged out-of-date (%s)" + | tr | format(ood_ts.strftime("%Y-%m-%d")) + }} + +
  • +
  • + + + +
  • + {% endif %} +
  • + {% if not voted %} +
    + +
    + {% else %} +
    + +
    + {% endif %} +
  • +
  • + {% if notified %} +
    +
    -
  • - {% endif %} -
  • - {% if not voted %} -
    + {% else %} + + name="do_Notify" + value="{{ 'Enable notifications' | tr }}" + />
    - {% else %} -
    - -
    - {% endif %} -
  • -
  • - {% if notified %} -
    - -
    - {% else %} -
    - -
    - {% endif %} -
  • - - {% endif %} + {% endif %} + {% if request.user.has_credential('CRED_PKGBASE_EDIT_COMAINTAINERS', approved=[pkgbase.Maintainer]) %}
  • From a756691d08408b2098557ebc6a50cf205ffe0084 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 10:00:46 -0700 Subject: [PATCH 0927/1891] change(FastAPI): user_developer_or_trusted_user always True Signed-off-by: Kevin Morris --- aurweb/auth.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index fb062eab..9f56f90f 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -276,8 +276,7 @@ def has_any(user, *account_types): def user_developer_or_trusted_user(user): - return has_any(user, "User", "Trusted User", "Developer", - "Trusted User & Developer") + return True def trusted_user(user): From 2e6f8cb9f40869198bd6aaba34597467a5951476 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 09:43:47 -0700 Subject: [PATCH 0928/1891] change(FastAPI): @auth_required login kwarg defaulted to True We pretty much want @auth_required to send users to login if we enforce auth requirements but don't otherwise specify a way to deal with it. Signed-off-by: Kevin Morris --- aurweb/auth.py | 3 ++- aurweb/routers/accounts.py | 20 ++++++++++---------- aurweb/routers/packages.py | 28 ++++++++++++++-------------- aurweb/routers/trusted_user.py | 10 +++++----- test/test_trusted_user_routes.py | 6 ++++-- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index d44d4ded..fb52fade 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -122,7 +122,7 @@ class BasicAuthBackend(AuthenticationBackend): def auth_required(is_required: bool = True, - login: bool = False, + login: bool = True, redirect: str = "/", template: tuple = None, status_code: HTTPStatus = HTTPStatus.UNAUTHORIZED): @@ -152,6 +152,7 @@ def auth_required(is_required: bool = True, applying any format operations. :param is_required: A boolean indicating whether the function requires auth + :param login: Redirect to `/login`, passing `next=` :param redirect: Path to redirect to if is_required isn't True :param template: A three-element template tuple: (path, title_iterable, variable_iterable) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 3c799938..fc1c5242 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -30,14 +30,14 @@ logger = logging.getLogger(__name__) @router.get("/passreset", response_class=HTMLResponse) -@auth_required(False) +@auth_required(False, login=False) async def passreset(request: Request): context = await make_variable_context(request, "Password Reset") return render_template(request, "passreset.html", context) @router.post("/passreset", response_class=HTMLResponse) -@auth_required(False) +@auth_required(False, login=False) async def passreset_post(request: Request, user: str = Form(...), resetkey: str = Form(default=None), @@ -315,7 +315,7 @@ def make_account_form_context(context: dict, @router.get("/register", response_class=HTMLResponse) -@auth_required(False) +@auth_required(False, login=False) async def account_register(request: Request, U: str = Form(default=str()), # Username E: str = Form(default=str()), # Email @@ -341,7 +341,7 @@ async def account_register(request: Request, @router.post("/register", response_class=HTMLResponse) -@auth_required(False) +@auth_required(False, login=False) async def account_register_post(request: Request, U: str = Form(default=str()), # Username E: str = Form(default=str()), # Email @@ -432,7 +432,7 @@ def cannot_edit(request, user): @router.get("/account/{username}/edit", response_class=HTMLResponse) -@auth_required(True) +@auth_required(True, redirect="/account/{username}") async def account_edit(request: Request, username: str): user = db.query(User, User.Username == username).first() @@ -448,7 +448,7 @@ async def account_edit(request: Request, @router.post("/account/{username}/edit", response_class=HTMLResponse) -@auth_required(True) +@auth_required(True, redirect="/account/{username}") async def account_edit_post(request: Request, username: str, U: str = Form(default=str()), # Username @@ -594,7 +594,7 @@ async def account(request: Request, username: str): @router.get("/accounts/") -@auth_required(True) +@auth_required(True, redirect="/accounts/") @account_type_required({TRUSTED_USER, DEVELOPER, TRUSTED_USER_AND_DEV}) async def accounts(request: Request): context = make_context(request, "Accounts") @@ -602,7 +602,7 @@ async def accounts(request: Request): @router.post("/accounts/") -@auth_required(True) +@auth_required(True, redirect="/accounts/") @account_type_required({TRUSTED_USER, DEVELOPER, TRUSTED_USER_AND_DEV}) async def accounts_post(request: Request, O: int = Form(default=0), # Offset @@ -688,7 +688,7 @@ def render_terms_of_service(request: Request, @router.get("/tos") -@auth_required(True, redirect="/") +@auth_required(True, redirect="/tos") async def terms_of_service(request: Request): # Query the database for terms that were previously accepted, # but now have a bumped Revision that needs to be accepted. @@ -709,7 +709,7 @@ async def terms_of_service(request: Request): @router.post("/tos") -@auth_required(True, redirect="/") +@auth_required(True, redirect="/tos") async def terms_of_service_post(request: Request, accept: bool = Form(default=False)): # Query the database for terms that were previously accepted, diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 539f9526..ee6d71ba 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -222,7 +222,7 @@ async def package_base_voters(request: Request, name: str) -> Response: @router.post("/pkgbase/{name}/comments") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comments") async def pkgbase_comments_post( request: Request, name: str, comment: str = Form(default=str()), @@ -254,7 +254,7 @@ async def pkgbase_comments_post( @router.get("/pkgbase/{name}/comments/{id}/form") -@auth_required(True) +@auth_required(True, login=False) async def pkgbase_comment_form(request: Request, name: str, id: int): """ Produce a comment form for comment {id}. """ pkgbase = get_pkg_or_base(name, PackageBase) @@ -274,7 +274,7 @@ async def pkgbase_comment_form(request: Request, name: str, id: int): @router.post("/pkgbase/{name}/comments/{id}") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comments/{id}") async def pkgbase_comment_post( request: Request, name: str, id: int, comment: str = Form(default=str()), @@ -309,7 +309,7 @@ async def pkgbase_comment_post( @router.post("/pkgbase/{name}/comments/{id}/delete") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/delete") async def pkgbase_comment_delete(request: Request, name: str, id: int): pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) @@ -332,7 +332,7 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int): @router.post("/pkgbase/{name}/comments/{id}/undelete") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/undelete") async def pkgbase_comment_undelete(request: Request, name: str, id: int): pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) @@ -354,7 +354,7 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int): @router.post("/pkgbase/{name}/comments/{id}/pin") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/pin") async def pkgbase_comment_pin(request: Request, name: str, id: int): pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) @@ -376,7 +376,7 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int): @router.post("/pkgbase/{name}/comments/{id}/unpin") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/unpin") async def pkgbase_comment_unpin(request: Request, name: str, id: int): pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) @@ -397,7 +397,7 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int): @router.get("/pkgbase/{name}/comaintainers") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comaintainers") async def package_base_comaintainers(request: Request, name: str) -> Response: # Get the PackageBase. pkgbase = get_pkg_or_base(name, PackageBase) @@ -444,7 +444,7 @@ def remove_users(pkgbase, usernames): @router.post("/pkgbase/{name}/comaintainers") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/comaintainers") async def package_base_comaintainers_post( request: Request, name: str, users: str = Form(default=str())) -> Response: @@ -539,7 +539,7 @@ async def package_base_comaintainers_post( @router.get("/requests") -@auth_required(True, redirect="/") +@auth_required(True, redirect="/requests") async def requests(request: Request, O: int = Query(default=defaults.O), PP: int = Query(default=defaults.PP)): @@ -571,7 +571,7 @@ async def requests(request: Request, @router.get("/pkgbase/{name}/request") -@auth_required(True, login=True, redirect="/pkgbase/{name}") +@auth_required(True, redirect="/pkgbase/{name}") async def package_request(request: Request, name: str): context = make_context(request, "Submit Request") @@ -585,7 +585,7 @@ async def package_request(request: Request, name: str): @router.post("/pkgbase/{name}/request") -@auth_required(True) +@auth_required(True, redirect="/pkgbase/{name}/request") async def pkgbase_request_post(request: Request, name: str, type: str = Form(...), merge_into: str = Form(default=None), @@ -654,7 +654,7 @@ async def pkgbase_request_post(request: Request, name: str, @router.get("/requests/{id}/close") -@auth_required(True) +@auth_required(True, redirect="/requests/{id}/close") async def requests_close(request: Request, id: int): pkgreq = db.query(PackageRequest).filter(PackageRequest.ID == id).first() if not request.user.is_elevated() and request.user != pkgreq.User: @@ -667,7 +667,7 @@ async def requests_close(request: Request, id: int): @router.post("/requests/{id}/close") -@auth_required(True) +@auth_required(True, redirect="/requests/{id}/close") async def requests_close_post(request: Request, id: int, reason: int = Form(default=0), comments: str = Form(default=str())): diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index a977b31a..b897a635 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -45,7 +45,7 @@ ADDVOTE_SPECIFICS = { @router.get("/tu") -@auth_required(True, redirect="/") +@auth_required(True, redirect="/tu") @account_type_required(REQUIRED_TYPES) async def trusted_user(request: Request, coff: int = 0, # current offset @@ -149,7 +149,7 @@ def render_proposal(request: Request, @router.get("/tu/{proposal}") -@auth_required(True, redirect="/") +@auth_required(True, redirect="/tu/{proposal}") @account_type_required(REQUIRED_TYPES) async def trusted_user_proposal(request: Request, proposal: int): context = await make_variable_context(request, "Trusted User") @@ -175,7 +175,7 @@ async def trusted_user_proposal(request: Request, proposal: int): @router.post("/tu/{proposal}") -@auth_required(True, redirect="/") +@auth_required(True, redirect="/tu/{proposal}") @account_type_required(REQUIRED_TYPES) async def trusted_user_proposal_post(request: Request, proposal: int, @@ -223,7 +223,7 @@ async def trusted_user_proposal_post(request: Request, @router.get("/addvote") -@auth_required(True) +@auth_required(True, redirect="/addvote") @account_type_required({"Trusted User", "Trusted User & Developer"}) async def trusted_user_addvote(request: Request, user: str = str(), @@ -243,7 +243,7 @@ async def trusted_user_addvote(request: Request, @router.post("/addvote") -@auth_required(True) +@auth_required(True, redirect="/addvote") @account_type_required({TRUSTED_USER, TRUSTED_USER_AND_DEV}) async def trusted_user_addvote_post(request: Request, user: str = Form(default=str()), diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index 67181db3..0579247e 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -9,7 +9,7 @@ import pytest from fastapi.testclient import TestClient -from aurweb import db +from aurweb import db, util from aurweb.models.account_type import AccountType from aurweb.models.tu_vote import TUVote from aurweb.models.tu_voteinfo import TUVoteInfo @@ -128,7 +128,9 @@ def test_tu_index_guest(client): with client as request: response = request.get("/tu", allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) - assert response.headers.get("location") == "/" + + params = util.urlencode({"next": "/tu"}) + assert response.headers.get("location") == f"/login?{params}" def test_tu_index_unauthorized(client, user): From 8eadb4251da6029cb4edb528b222eebb0d3b821c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 5 Oct 2021 16:04:19 -0700 Subject: [PATCH 0929/1891] feat(FastAPI): add /pkgbase/{name}/[un]flag (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 32 ++++++++++++++++++++++++++++++++ test/test_packages_routes.py | 31 +++++++++++++++++++++++++++++++ test/test_user.py | 1 - 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index ee6d71ba..8790327f 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -701,3 +701,35 @@ async def requests_close_post(request: Request, id: int, notify_.send() return RedirectResponse("/requests", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/flag") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_flag(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + has_cred = request.user.has_credential("CRED_PKGBASE_FLAG") + if has_cred and not pkgbase.Flagger: + now = int(datetime.utcnow().timestamp()) + with db.begin(): + pkgbase.OutOfDateTS = now + pkgbase.Flagger = request.user + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/unflag") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_unflag(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + has_cred = request.user.has_credential( + "CRED_PKGBASE_UNFLAG", approved=[pkgbase.Flagger]) + if has_cred: + with db.begin(): + pkgbase.OutOfDateTS = None + pkgbase.Flagger = None + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 4118744a..db36d1a9 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1689,3 +1689,34 @@ def test_requests_close_post_rejected(client: TestClient, user: User, assert pkgreq.Status == REJECTED_ID assert pkgreq.Closer == user assert pkgreq.ClosureComment == str() + + +def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, + package: Package): + pkgbase = package.PackageBase + + # We shouldn't have flagged the package yet; assert so. + assert pkgbase.Flagger is None + + # Flag it. + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/flag" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert pkgbase.Flagger == user + + # Now, test that the 'maintainer' user can't unflag it, because they + # didn't flag it to begin with. + maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/unflag" + with client as request: + resp = request.post(endpoint, cookies=maint_cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert pkgbase.Flagger == user + + # Now, unflag it for real. + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert pkgbase.Flagger is None diff --git a/test/test_user.py b/test/test_user.py index 43cbf58a..771611d8 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -166,7 +166,6 @@ def test_user_minimum_passwd_length(): def test_user_has_credential(): - assert user.has_credential("CRED_PKGBASE_FLAG") assert not user.has_credential("CRED_ACCOUNT_CHANGE_TYPE") From 0dfff2bcb24d8915f5fd317c79f5e750f0897e5a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 5 Oct 2021 21:13:51 -0700 Subject: [PATCH 0930/1891] feat(FastAPI): add /pkgbase/{name}/[un]notify (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 36 ++++++++++++++++++++++++++++++++++++ test/test_packages_routes.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 8790327f..ced9ea3d 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -733,3 +733,39 @@ async def pkgbase_unflag(request: Request, name: str): return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/notify") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_notify(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + notif = db.query(pkgbase.notifications.filter( + PackageNotification.UserID == request.user.ID + ).exists()).scalar() + has_cred = request.user.has_credential("CRED_PKGBASE_NOTIFY") + if has_cred and not notif: + with db.begin(): + db.create(PackageNotification, + PackageBase=pkgbase, + User=request.user) + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/unnotify") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_unnotify(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + notif = pkgbase.notifications.filter( + PackageNotification.UserID == request.user.ID + ).first() + has_cred = request.user.has_credential("CRED_PKGBASE_NOTIFY") + if has_cred and notif: + with db.begin(): + db.session.delete(notif) + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index db36d1a9..1d7fe17c 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1720,3 +1720,36 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger is None + + +def test_pkgbase_notify(client: TestClient, user: User, package: Package): + pkgbase = package.PackageBase + + # We have no notif record yet; assert that. + notif = pkgbase.notifications.filter( + PackageNotification.UserID == user.ID + ).first() + assert notif is None + + # Enable notifications. + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/notify" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + notif = pkgbase.notifications.filter( + PackageNotification.UserID == user.ID + ).first() + assert notif is not None + + # Disable notifications. + endpoint = f"/pkgbase/{pkgbase.Name}/unnotify" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + notif = pkgbase.notifications.filter( + PackageNotification.UserID == user.ID + ).first() + assert notif is None From 0a02df363a80e7571c9a0bbb9829b84f18cf7f4c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 5 Oct 2021 21:32:12 -0700 Subject: [PATCH 0931/1891] feat(FastAPI): add /pkgbase/{name}/[un]vote (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 38 ++++++++++++++++++++++++++++++++++++ test/test_packages_routes.py | 27 +++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index ced9ea3d..8bfb680e 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -769,3 +769,41 @@ async def pkgbase_unnotify(request: Request, name: str): return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/vote") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_vote(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + vote = pkgbase.package_votes.filter( + PackageVote.UsersID == request.user.ID + ).first() + has_cred = request.user.has_credential("CRED_PKGBASE_VOTE") + if has_cred and not vote: + now = int(datetime.utcnow().timestamp()) + with db.begin(): + db.create(PackageVote, + User=request.user, + PackageBase=pkgbase, + VoteTS=now) + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.post("/pkgbase/{name}/unvote") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_unvote(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + vote = pkgbase.package_votes.filter( + PackageVote.UsersID == request.user.ID + ).first() + has_cred = request.user.has_credential("CRED_PKGBASE_VOTE") + if has_cred and vote: + with db.begin(): + db.session.delete(vote) + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 1d7fe17c..a03c5920 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1753,3 +1753,30 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package): PackageNotification.UserID == user.ID ).first() assert notif is None + + +def test_pkgbase_vote(client: TestClient, user: User, package: Package): + pkgbase = package.PackageBase + + # We haven't voted yet. + vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() + assert vote is None + + # Vote for the package. + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/vote" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() + assert vote is not None + + # Remove vote. + endpoint = f"/pkgbase/{pkgbase.Name}/unvote" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() + assert vote is None From 16d516c221112d36ead6ce36b5beb6a54015c8a2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 6 Oct 2021 22:07:20 -0700 Subject: [PATCH 0932/1891] feat(FastAPI): add /pkgbase/{name}/disown (get, post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 63 +++++++++++++++++++++++ templates/packages/disown.html | 55 ++++++++++++++++++++ templates/partials/packages/actions.html | 10 ++-- test/test_packages_routes.py | 65 ++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 templates/packages/disown.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 8bfb680e..af1ebe46 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -807,3 +807,66 @@ async def pkgbase_unvote(request: Request, name: str): return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +def disown_pkgbase(pkgbase: PackageBase, disowner: User): + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + notif = notify.DisownNotification(conn, disowner.ID, pkgbase.ID) + + if disowner != pkgbase.Maintainer: + with db.begin(): + pkgbase.Maintainer = None + else: + co = pkgbase.comaintainers.order_by( + PackageComaintainer.Priority.asc() + ).limit(1).first() + + if co: + with db.begin(): + pkgbase.Maintainer = co.User + db.session.delete(co) + else: + pkgbase.Maintainer = None + + notif.send() + + +@router.get("/pkgbase/{name}/disown") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_disown_get(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + has_cred = request.user.has_credential("CRED_PKGBASE_DISOWN", + approved=[pkgbase.Maintainer]) + if not has_cred: + return RedirectResponse(f"/pkgbase/{name}", + int(HTTPStatus.SEE_OTHER)) + + context = make_context(request, "Disown Package") + context["pkgbase"] = pkgbase + return render_template(request, "packages/disown.html", context) + + +@router.post("/pkgbase/{name}/disown") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_disown_post(request: Request, name: str, + confirm: bool = Form(default=False)): + pkgbase = get_pkg_or_base(name, PackageBase) + + has_cred = request.user.has_credential("CRED_PKGBASE_DISOWN", + approved=[pkgbase.Maintainer]) + if not has_cred: + return RedirectResponse(f"/pkgbase/{name}", + int(HTTPStatus.SEE_OTHER)) + + if not confirm: + context = make_context(request, "Disown Package") + context["pkgbase"] = pkgbase + context["errors"] = [("The selected packages have not been disowned, " + "check the confirmation checkbox.")] + return render_template(request, "packages/disown.html", context, + status_code=int(HTTPStatus.EXPECTATION_FAILED)) + + disown_pkgbase(pkgbase, request.user) + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/packages/disown.html b/templates/packages/disown.html new file mode 100644 index 00000000..8d5a8574 --- /dev/null +++ b/templates/packages/disown.html @@ -0,0 +1,55 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} + + {% if errors %} +
      + {% for error in errors %} +
    • {{ error | tr }}
    • + {% endfor %} +
    + {% endif %} + +
    +

    {{ "Disown Package" | tr }}: {{ pkgbase.Name }}

    + +

    + {{ + "Use this form to disown the package base %s%s%s which " + "includes the following packages: " + | tr | format("", pkgbase.Name, "") | safe + }} +

    + +
      + {% for package in pkgbase.packages.all() %} +
    • {{ package.Name }}
    • + {% endfor %} +
    + +

    + {{ + "By selecting the checkbox, you confirm that you want to " + "disown the package." | tr + }} +

    + +
    +
    +

    + +

    +

    + +

    +
    +
    + +
    +{% endblock %} diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index f1863663..2b26144e 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -121,13 +121,9 @@ {% endif %} {% if request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %}
  • -
    - -
    + + {{ "Disown Package" | tr }} +
  • {% endif %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index a03c5920..c9622431 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1780,3 +1780,68 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package): vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() assert vote is None + + +def test_pkgbase_disown_as_tu(client: TestClient, tu_user: User, + package: Package): + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/disown" + + # But we do here. + with client as request: + resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_pkgbase_disown_as_sole_maintainer(client: TestClient, + maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/disown" + + # But we do here. + with client as request: + resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_pkgbase_disown(client: TestClient, user: User, maintainer: User, + package: Package): + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + user_cookies = {"AURSID": user.login(Request(), "testPassword")} + pkgbase = package.PackageBase + endpoint = f"/pkgbase/{pkgbase.Name}/disown" + + with db.begin(): + db.create(PackageComaintainer, + User=user, + PackageBase=pkgbase, + Priority=1) + + # GET as a normal user, which is rejected for lack of credentials. + with client as request: + resp = request.get(endpoint, cookies=user_cookies, + allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + # GET as the maintainer. + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # POST as a normal user, which is rejected for lack of credentials. + with client as request: + resp = request.post(endpoint, cookies=user_cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + # POST as the maintainer without "confirm". + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.EXPECTATION_FAILED) + + # POST as the maintainer with "confirm". + with client as request: + resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) From c8d01cc5e8083a6586ae61a6c3371d7ed2428f6a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 19 Sep 2021 19:27:29 -0700 Subject: [PATCH 0933/1891] feat(FastAPI): add aurweb.util.apply_all(iterable, fn) A helper which allows us to apply a specific function to each item in an iterable. Signed-off-by: Kevin Morris --- aurweb/util.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aurweb/util.py b/aurweb/util.py index 08e6d7c6..44f711f1 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -7,7 +7,7 @@ import secrets import string from datetime import datetime -from typing import Any, Dict +from typing import Any, Callable, Dict, Iterable from urllib.parse import urlencode, urlparse from zoneinfo import ZoneInfo @@ -167,3 +167,8 @@ def add_samesite_fields(response: Response, value: str): def get_ssh_fingerprints(): return aurweb.config.get_section("fingerprints") or {} + + +def apply_all(iterable: Iterable, fn: Callable): + for item in iterable: + fn(item) From ed68fa2b57f7f4cf916fd2e40312e1f64da2c71e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 19 Sep 2021 19:27:03 -0700 Subject: [PATCH 0934/1891] feat(FastAPI): add aurweb.db.delete_all(iterable) Signed-off-by: Kevin Morris --- aurweb/db.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aurweb/db.py b/aurweb/db.py index 2b934300..c1e80751 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -2,6 +2,8 @@ import functools import math import re +from typing import Iterable + from sqlalchemy import event from sqlalchemy.orm import scoped_session @@ -71,6 +73,12 @@ def delete(model, *args, **kwargs): session.delete(record) +def delete_all(iterable: Iterable): + with begin(): + for obj in iterable: + session.delete(obj) + + def rollback(): session.rollback() From 0ddc969bdcd07fe0181e05a8e2abdb2e23301212 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 6 Oct 2021 15:33:23 -0700 Subject: [PATCH 0935/1891] feat(FastAPI-dev): add package_delete helper Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 76 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index af1ebe46..40322785 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -1,6 +1,6 @@ from datetime import datetime from http import HTTPStatus -from typing import Any, Dict +from typing import Any, Dict, List from fastapi import APIRouter, Form, HTTPException, Query, Request, Response from fastapi.responses import JSONResponse, RedirectResponse @@ -11,7 +11,7 @@ import aurweb.models.package_comment import aurweb.models.package_keyword import aurweb.packages.util -from aurweb import db, defaults, l10n +from aurweb import db, defaults, l10n, util from aurweb.auth import auth_required from aurweb.models.license import License from aurweb.models.package import Package @@ -26,7 +26,7 @@ from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID, from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID -from aurweb.models.request_type import RequestType +from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted @@ -116,6 +116,76 @@ async def packages(request: Request) -> Response: return await packages_get(request, context) +def create_request_if_missing(requests: List[PackageRequest], + reqtype: RequestType, + user: User, + package: Package): + now = int(datetime.utcnow().timestamp()) + pkgreq = db.query(PackageRequest).filter( + PackageRequest.PackageBaseName == package.PackageBase.Name + ).first() + if not pkgreq: + # No PackageRequest existed. Create one. + comments = "Automatically generated by aurweb." + closure_comment = "Deleted by aurweb." + pkgreq = db.create(PackageRequest, + RequestType=reqtype, + PackageBase=package.PackageBase, + PackageBaseName=package.PackageBase.Name, + User=user, + Status=ACCEPTED_ID, + Comments=comments, + ClosureComment=closure_comment, + ClosedTS=now, + Closer=user) + requests.append(pkgreq) + + +def delete_package(deleter: User, + package: Package): + notifications = [] + requests = [] + bases_to_delete = [] + + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + # In all cases, though, just delete the Package in question. + if package.PackageBase.packages.count() == 1: + reqtype = db.query(RequestType).filter( + RequestType.ID == DELETION_ID + ).first() + + with db.begin(): + create_request_if_missing( + requests, reqtype, deleter, package) + + bases_to_delete.append(package.PackageBase) + + # Prepare DeleteNotification. + notifications.append( + notify.DeleteNotification(conn, deleter.ID, package.PackageBase.ID) + ) + + # For each PackageRequest created, mock up an open and close notification. + basename = package.PackageBase.Name + for pkgreq in requests: + notifications.append( + notify.RequestOpenNotification( + conn, deleter.ID, pkgreq.ID, reqtype.Name, + pkgreq.PackageBase.ID, merge_into=basename or None) + ) + notifications.append( + notify.RequestCloseNotification( + conn, deleter.ID, pkgreq.ID, pkgreq.status_display()) + ) + + # Perform all the deletions. + db.delete_all([package]) + db.delete_all(bases_to_delete) + + # Send out all the notifications. + util.apply_all(notifications, lambda n: n.send()) + + async def make_single_context(request: Request, pkgbase: PackageBase) -> Dict[str, Any]: """ Make a basic context for package or pkgbase. From 4e7d2295da657ece2dc0fd1422ecd0e75e4facb7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 6 Oct 2021 20:17:58 -0700 Subject: [PATCH 0936/1891] fix(FastAPI): add package-related missing backref cascades Signed-off-by: Kevin Morris --- aurweb/models/package_comment.py | 3 ++- aurweb/models/package_dependency.py | 3 ++- aurweb/models/package_relation.py | 3 ++- aurweb/models/package_source.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/aurweb/models/package_comment.py b/aurweb/models/package_comment.py index c52ee270..92ae8911 100644 --- a/aurweb/models/package_comment.py +++ b/aurweb/models/package_comment.py @@ -17,7 +17,8 @@ class PackageComment(Base): Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), nullable=False) PackageBase = relationship( - "PackageBase", backref=backref("comments", lazy="dynamic"), + "PackageBase", backref=backref("comments", lazy="dynamic", + cascade="all,delete"), foreign_keys=[PackageBaseID]) UsersID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index 9ce0b019..fb66c6f2 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -15,7 +15,8 @@ class PackageDependency(Base): Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False) Package = relationship( - "Package", backref=backref("package_dependencies", lazy="dynamic"), + "Package", backref=backref("package_dependencies", lazy="dynamic", + cascade="all,delete"), foreign_keys=[PackageID]) DepTypeID = Column( diff --git a/aurweb/models/package_relation.py b/aurweb/models/package_relation.py index 1e6c146c..d4921859 100644 --- a/aurweb/models/package_relation.py +++ b/aurweb/models/package_relation.py @@ -16,7 +16,8 @@ class PackageRelation(Base): Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False) Package = relationship( - "Package", backref=backref("package_relations", lazy="dynamic"), + "Package", backref=backref("package_relations", lazy="dynamic", + cascade="all,delete"), foreign_keys=[PackageID]) RelTypeID = Column( diff --git a/aurweb/models/package_source.py b/aurweb/models/package_source.py index 4ffa23df..f016bee0 100644 --- a/aurweb/models/package_source.py +++ b/aurweb/models/package_source.py @@ -13,7 +13,8 @@ class PackageSource(Base): PackageID = Column(Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False) Package = relationship( - "Package", backref=backref("package_sources", lazy="dynamic"), + "Package", backref=backref("package_sources", lazy="dynamic", + cascade="all,delete"), foreign_keys=[PackageID]) __mapper_args__ = {"primary_key": [PackageID]} From d38abd783250d13f93294944f3897a38e1209d31 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 6 Oct 2021 13:54:14 -0700 Subject: [PATCH 0937/1891] feat(FastAPI): add /pkgbase/{name}/delete (get, post) In addition, we've had to add cascade arguments to backref so sqlalchemy treats the relationships as proper cascades. Furthermore, our pkgbase actions template was not rendering actions properly based on TU credentials. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 37 ++++++++++++++++++++++ templates/packages/delete.html | 56 ++++++++++++++++++++++++++++++++++ test/test_packages_routes.py | 46 ++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 templates/packages/delete.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 40322785..4426d0be 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -940,3 +940,40 @@ async def pkgbase_disown_post(request: Request, name: str, disown_pkgbase(pkgbase, request.user) return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) + + +@router.get("/pkgbase/{name}/delete") +@auth_required(True) +async def pkgbase_delete_get(request: Request, name: str): + if not request.user.has_credential("CRED_PKGBASE_DELETE"): + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + context = make_context(request, "Package Deletion") + context["pkgbase"] = get_pkg_or_base(name, PackageBase) + return render_template(request, "packages/delete.html", context) + + +@router.post("/pkgbase/{name}/delete") +@auth_required(True) +async def pkgbase_delete_post(request: Request, name: str, + confirm: bool = Form(default=False)): + pkgbase = get_pkg_or_base(name, PackageBase) + + if not request.user.has_credential("CRED_PKGBASE_DELETE"): + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + if not confirm: + context = make_context(request, "Package Deletion") + context["pkgbase"] = pkgbase + context["errors"] = [("The selected packages have not been deleted, " + "check the confirmation checkbox.")] + return render_template(request, "packages/delete.html", context, + status_code=int(HTTPStatus.EXPECTATION_FAILED)) + + packages = pkgbase.packages.all() + for package in packages: + delete_package(request.user, package) + + return RedirectResponse("/packages", status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/packages/delete.html b/templates/packages/delete.html new file mode 100644 index 00000000..6e882d05 --- /dev/null +++ b/templates/packages/delete.html @@ -0,0 +1,56 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} + + {% if errors %} +
      + {% for error in errors %} +
    • {{ error | tr }}
    • + {% endfor %} +
    + {% endif %} + +
    +

    {{ "Delete Package" | tr }}: {{ pkgbase.Name }}

    + +

    + {{ + "Use this form to delete the package base %s%s%s and " + "the following packages from the AUR: " + | tr | format("", pkgbase.Name, "") | safe + }} +

    + +
      + {% for package in pkgbase.packages.all() %} +
    • {{ package.Name }}
    • + {% endfor %} +
    + +

    + {{ + "Deletion of a package is permanent. " + "Select the checkbox to confirm action." | tr + }} +

    + +
    +
    +

    + +

    + +

    + +

    +
    +
    + +
    +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index c9622431..1f258497 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1845,3 +1845,49 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User, with client as request: resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + +def test_pkgbase_delete_unauthorized(client: TestClient, user: User, + package: Package): + pkgbase = package.PackageBase + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/delete" + + # Test GET. + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + # Test POST. + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" + + +def test_pkgbase_delete(client: TestClient, tu_user: User, package: Package): + pkgbase = package.PackageBase + + # Test that the GET request works. + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbase.Name}/delete" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # Test that POST works and denies us because we haven't confirmed. + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.EXPECTATION_FAILED) + + # Test that we can actually delete the pkgbase. + with client as request: + resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + # Let's assert that the package base record got removed. + record = db.query(PackageBase).filter( + PackageBase.Name == pkgbase.Name + ).first() + assert record is None From 01fb42c5d97fe930b63ef8b71d4b2a2b62f32a5e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 22:44:54 -0700 Subject: [PATCH 0938/1891] fix(scripts.popupdate): use forced-utc timestamp Additionally, clean up some controversial PEP-8 warnings by removing the '+' string concatenation. Signed-off-by: Kevin Morris --- aurweb/scripts/popupdate.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index b1e70403..96155eef 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -1,21 +1,21 @@ #!/usr/bin/env python3 -import time +from datetime import datetime import aurweb.db def main(): conn = aurweb.db.Connection() - conn.execute("UPDATE PackageBases SET NumVotes = (" + - "SELECT COUNT(*) FROM PackageVotes " + - "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") + conn.execute(("UPDATE PackageBases SET NumVotes = (" + "SELECT COUNT(*) FROM PackageVotes " + "WHERE PackageVotes.PackageBaseID = PackageBases.ID)")) - now = int(time.time()) - conn.execute("UPDATE PackageBases SET Popularity = (" + - "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " + - "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + - "PackageBases.ID AND NOT VoteTS IS NULL)", [now]) + now = int(datetime.utcnow().timestamp()) + conn.execute(("UPDATE PackageBases SET Popularity = (" + "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " + "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + "PackageBases.ID AND NOT VoteTS IS NULL)"), [now]) conn.commit() conn.close() From 63498f5edde58d231eba34359ac231ea217a34d9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 22:48:31 -0700 Subject: [PATCH 0939/1891] fix(FastAPI): use popupdate when [un]voting The `aurweb.scripts.popupdate` script is used to maintain the NumVotes and Popularity field. We could do the NumVotes change more simply; however, since this is already a long-term implementation, we're going to use it until we move scripts over to ORM. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 10 +++++++- aurweb/scripts/popupdate.py | 45 ++++++++++++++++++++++++++++-------- test/test_packages_routes.py | 2 ++ 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 4426d0be..f806f054 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -30,7 +30,7 @@ from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted -from aurweb.scripts import notify +from aurweb.scripts import notify, popupdate from aurweb.scripts.rendercomment import update_comment_render from aurweb.templates import make_context, render_raw_template, render_template @@ -858,6 +858,10 @@ async def pkgbase_vote(request: Request, name: str): PackageBase=pkgbase, VoteTS=now) + # Update NumVotes/Popularity. + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + popupdate.run_single(conn, pkgbase) + return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) @@ -875,6 +879,10 @@ async def pkgbase_unvote(request: Request, name: str): with db.begin(): db.session.delete(vote) + # Update NumVotes/Popularity. + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + popupdate.run_single(conn, pkgbase) + return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index 96155eef..fa82208d 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -5,17 +5,44 @@ from datetime import datetime import aurweb.db -def main(): - conn = aurweb.db.Connection() - conn.execute(("UPDATE PackageBases SET NumVotes = (" - "SELECT COUNT(*) FROM PackageVotes " - "WHERE PackageVotes.PackageBaseID = PackageBases.ID)")) +def run_single(conn, pkgbase): + """ A single popupdate. The given pkgbase instance will be + refreshed after the database update is done. + + NOTE: This function is compatible only with aurweb FastAPI. + + :param conn: db.Connection[Executor] + :param pkgbase: Instance of db.PackageBase + """ + + conn.execute("UPDATE PackageBases SET NumVotes = (" + "SELECT COUNT(*) FROM PackageVotes " + "WHERE PackageVotes.PackageBaseID = PackageBases.ID) " + "WHERE PackageBases.ID = ?", [pkgbase.ID]) now = int(datetime.utcnow().timestamp()) - conn.execute(("UPDATE PackageBases SET Popularity = (" - "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " - "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " - "PackageBases.ID AND NOT VoteTS IS NULL)"), [now]) + conn.execute("UPDATE PackageBases SET Popularity = (" + "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " + "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + "PackageBases.ID AND NOT VoteTS IS NULL) WHERE " + "PackageBases.ID = ?", [now, pkgbase.ID]) + + conn.commit() + conn.close() + aurweb.db.session.refresh(pkgbase) + + +def main(): + conn = aurweb.db.Connection() + conn.execute("UPDATE PackageBases SET NumVotes = (" + "SELECT COUNT(*) FROM PackageVotes " + "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") + + now = int(datetime.utcnow().timestamp()) + conn.execute("UPDATE PackageBases SET Popularity = (" + "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " + "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " + "PackageBases.ID AND NOT VoteTS IS NULL)", [now]) conn.commit() conn.close() diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 1f258497..7b9c520c 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1771,6 +1771,7 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package): vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() assert vote is not None + assert pkgbase.NumVotes == 1 # Remove vote. endpoint = f"/pkgbase/{pkgbase.Name}/unvote" @@ -1780,6 +1781,7 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package): vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() assert vote is None + assert pkgbase.NumVotes == 0 def test_pkgbase_disown_as_tu(client: TestClient, tu_user: User, From 305d07797371087b5e04bb49827d619c793a2d63 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 7 Oct 2021 22:01:04 -0700 Subject: [PATCH 0940/1891] feat(FastAPI): add /pkgbase/{name}/adopt (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 17 ++++++++++++ templates/partials/packages/actions.html | 19 +++++++++++--- test/test_packages_routes.py | 33 ++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index f806f054..b623ca10 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -950,6 +950,23 @@ async def pkgbase_disown_post(request: Request, name: str, status_code=int(HTTPStatus.SEE_OTHER)) +@router.post("/pkgbase/{name}/adopt") +@auth_required(True) +async def pkgbase_adopt_post(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + has_cred = request.user.has_credential("CRED_PKGBASE_ADOPT") + if has_cred or not pkgbase.Maintainer: + # If the user has credentials, they'll adopt the package regardless + # of maintainership. Otherwise, we'll promote the user to maintainer + # if no maintainer currently exists. + with db.begin(): + pkgbase.Maintainer = request.user + + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + @router.get("/pkgbase/{name}/delete") @auth_required(True) async def pkgbase_delete_get(request: Request, name: str): diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 2b26144e..dd83c84d 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -119,12 +119,23 @@ {% endif %} - {% if request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %} + {% if not result.Maintainer %}
  • - - {{ "Disown Package" | tr }} - +
    + +
  • + {% else %} + {% if request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %} +
  • + + {{ "Disown Package" | tr }} + +
  • + {% endif %} {% endif %}

    diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 7b9c520c..86949996 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1849,6 +1849,39 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User, assert resp.status_code == int(HTTPStatus.SEE_OTHER) +def test_pkgbase_adopt(client: TestClient, user: User, tu_user: User, + maintainer: User, package: Package): + # Unset the maintainer as if package is orphaned. + with db.begin(): + package.PackageBase.Maintainer = None + + pkgbasename = package.PackageBase.Name + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + endpoint = f"/pkgbase/{pkgbasename}/adopt" + + # Adopt the package base. + with client as request: + resp = request.post(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert package.PackageBase.Maintainer == maintainer + + # Try to adopt it when it already has a maintainer; nothing changes. + user_cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, cookies=user_cookies, + allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert package.PackageBase.Maintainer == maintainer + + # Steal the package as a TU. + tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, cookies=tu_cookies, + allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert package.PackageBase.Maintainer == tu_user + + def test_pkgbase_delete_unauthorized(client: TestClient, user: User, package: Package): pkgbase = package.PackageBase From 5bbc94f2ef333bbe5d33ee1893067e2864de5eb1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 9 Oct 2021 18:41:32 -0700 Subject: [PATCH 0941/1891] fix(FastAPI): add /pkgbase/{name}/flag (get) This was missed in the [un]flag (post) commit. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 28 +++++++++++++++++- templates/packages/flag.html | 57 ++++++++++++++++++++++++++++++++++++ test/test_packages_routes.py | 20 ++++++++++++- 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 templates/packages/flag.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index b623ca10..8f4a7e1f 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -773,17 +773,42 @@ async def requests_close_post(request: Request, id: int, return RedirectResponse("/requests", status_code=int(HTTPStatus.SEE_OTHER)) +@router.get("/pkgbase/{name}/flag") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_flag_get(request: Request, name: str): + pkgbase = get_pkg_or_base(name, PackageBase) + + has_cred = request.user.has_credential("CRED_PKGBASE_FLAG") + if not has_cred or pkgbase.Flagger is not None: + return RedirectResponse(f"/pkgbase/{name}", + status_code=int(HTTPStatus.SEE_OTHER)) + + context = make_context(request, "Flag Package Out-Of-Date") + context["pkgbase"] = pkgbase + return render_template(request, "packages/flag.html", context) + + @router.post("/pkgbase/{name}/flag") @auth_required(True, redirect="/pkgbase/{name}") -async def pkgbase_flag(request: Request, name: str): +async def pkgbase_flag_post(request: Request, name: str, + comments: str = Form(default=str())): pkgbase = get_pkg_or_base(name, PackageBase) + if not comments: + context = make_context(request, "Flag Package Out-Of-Date") + context["pkgbase"] = pkgbase + context["errors"] = ["The selected packages have not been flagged, " + "please enter a comment."] + return render_template(request, "packages/flag.html", context, + status_code=int(HTTPStatus.BAD_REQUEST)) + has_cred = request.user.has_credential("CRED_PKGBASE_FLAG") if has_cred and not pkgbase.Flagger: now = int(datetime.utcnow().timestamp()) with db.begin(): pkgbase.OutOfDateTS = now pkgbase.Flagger = request.user + pkgbase.FlaggerComment = comments return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) @@ -800,6 +825,7 @@ async def pkgbase_unflag(request: Request, name: str): with db.begin(): pkgbase.OutOfDateTS = None pkgbase.Flagger = None + pkgbase.FlaggerComment = str() return RedirectResponse(f"/pkgbase/{name}", status_code=int(HTTPStatus.SEE_OTHER)) diff --git a/templates/packages/flag.html b/templates/packages/flag.html new file mode 100644 index 00000000..4e133acb --- /dev/null +++ b/templates/packages/flag.html @@ -0,0 +1,57 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {{ "Flag Package Out-Of-Date" | tr }}: {{ pkgbase.Name }}

    + +

    + {{ + "Use this form to flag the package base %s%s%s and " + "the following packages out-of-date: " + | tr | format("", pkgbase.Name, "") | safe + }} +

    + +
      + {% for package in pkgbase.packages.all() %} +
    • {{ package.Name }}
    • + {% endfor %} +
    + +

    + {{ + "Please do %snot%s use this form to report bugs. " + "Use the package comments instead." + | tr | format("", "") | safe + }} + {{ + "Enter details on why the package is out-of-date below, " + "preferably including links to the release announcement " + "or the new release tarball." | tr + }} +

    + + {% if errors %} +
      + {% for error in errors %} +
    • {{ error | tr }}
    • + {% endfor %} +
    + {% endif %} + +
    +
    +

    + + +

    +

    + +

    +
    +
    +
    +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 86949996..12d7e33e 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1698,13 +1698,31 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, # We shouldn't have flagged the package yet; assert so. assert pkgbase.Flagger is None - # Flag it. cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/flag" + + # Get the flag page. + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # Try to flag it without a comment. with client as request: resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.BAD_REQUEST) + + # Flag it with a valid comment. + with client as request: + resp = request.post(endpoint, {"comments": "Test"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger == user + assert pkgbase.FlaggerComment == "Test" + + # Now try to perform a get; we should be redirected because + # it's already flagged. + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Now, test that the 'maintainer' user can't unflag it, because they # didn't flag it to begin with. From d9ab65cb6f2e0f0985f2463c352acc52621e1026 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 9 Oct 2021 20:46:52 -0700 Subject: [PATCH 0942/1891] add Feedback.md GitLab issue template Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Feedback.md | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .gitlab/issue_templates/Feedback.md diff --git a/.gitlab/issue_templates/Feedback.md b/.gitlab/issue_templates/Feedback.md new file mode 100644 index 00000000..e32120aa --- /dev/null +++ b/.gitlab/issue_templates/Feedback.md @@ -0,0 +1,56 @@ +**NOTE:** This issue template is only applicable to FastAPI implementations +in the code-base, which only exists within the `pu` branch. If you wish to +file an issue for the current PHP implementation of aurweb, please file a +standard issue prefixed with `[Bug]` or `[Feature]`. + + +**Checklist** + +- [ ] I have prefixed the issue title with `[Feedback]` along with a message + pointing to the route or feature tested. + - Example: `[Feedback] /packages/{name}` +- [ ] I have completed the [Changes](#changes) section. +- [ ] I have completed the [Bugs](#bugs) section. +- [ ] I have completed the [Improvements](#improvements) section. +- [ ] I have completed the [Summary](#summary) section. + +### Changes + +Please describe changes in user experience when compared to the PHP +implementation. This section can actually hold a lot of info if you +are up for it -- changes in routes, HTML rendering, back-end behavior, +etc. + +If you cannot see any changes from your standpoint, include a short +statement about that fact. + +### Bugs + +Please describe any bugs you've experienced while testing the route +pertaining to this issue. A "perfect" bug report would include your +specific experience, what you expected to occur, and what happened +otherwise. If you can, please include output of `docker-compose logs fastapi` +with your report; especially if any unintended exceptions occurred. + +### Improvements + +If you've experienced improvements in the route when compared to PHP, +please do include those here. We'd like to know if users are noticing +these improvements and how they feel about them. + +There are multiple routes with no improvements. For these, just include +a short sentence about the fact that you've experienced none. + +### Summary + +First: If you've gotten here and completed the [Changes](#changes), +[Bugs](#bugs), and [Improvements](#improvements) sections, we'd like +to thank you very much for your contribution and willingness to test. +We are not a company, and we are not a large team; any bit of assistance +here helps the project astronomically and moves us closer toward a +new release. + +That being said: please include an overall summary of your experience +and how you felt about the current implementation which you're testing +in comparison with PHP (current aur.archlinux.org, or https://localhost:8443 +through docker). From 34c96ed81b017b1b8273e14d98d69a69f9029e37 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 9 Oct 2021 20:46:52 -0700 Subject: [PATCH 0943/1891] add Feedback.md GitLab issue template Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Feedback.md | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .gitlab/issue_templates/Feedback.md diff --git a/.gitlab/issue_templates/Feedback.md b/.gitlab/issue_templates/Feedback.md new file mode 100644 index 00000000..e32120aa --- /dev/null +++ b/.gitlab/issue_templates/Feedback.md @@ -0,0 +1,56 @@ +**NOTE:** This issue template is only applicable to FastAPI implementations +in the code-base, which only exists within the `pu` branch. If you wish to +file an issue for the current PHP implementation of aurweb, please file a +standard issue prefixed with `[Bug]` or `[Feature]`. + + +**Checklist** + +- [ ] I have prefixed the issue title with `[Feedback]` along with a message + pointing to the route or feature tested. + - Example: `[Feedback] /packages/{name}` +- [ ] I have completed the [Changes](#changes) section. +- [ ] I have completed the [Bugs](#bugs) section. +- [ ] I have completed the [Improvements](#improvements) section. +- [ ] I have completed the [Summary](#summary) section. + +### Changes + +Please describe changes in user experience when compared to the PHP +implementation. This section can actually hold a lot of info if you +are up for it -- changes in routes, HTML rendering, back-end behavior, +etc. + +If you cannot see any changes from your standpoint, include a short +statement about that fact. + +### Bugs + +Please describe any bugs you've experienced while testing the route +pertaining to this issue. A "perfect" bug report would include your +specific experience, what you expected to occur, and what happened +otherwise. If you can, please include output of `docker-compose logs fastapi` +with your report; especially if any unintended exceptions occurred. + +### Improvements + +If you've experienced improvements in the route when compared to PHP, +please do include those here. We'd like to know if users are noticing +these improvements and how they feel about them. + +There are multiple routes with no improvements. For these, just include +a short sentence about the fact that you've experienced none. + +### Summary + +First: If you've gotten here and completed the [Changes](#changes), +[Bugs](#bugs), and [Improvements](#improvements) sections, we'd like +to thank you very much for your contribution and willingness to test. +We are not a company, and we are not a large team; any bit of assistance +here helps the project astronomically and moves us closer toward a +new release. + +That being said: please include an overall summary of your experience +and how you felt about the current implementation which you're testing +in comparison with PHP (current aur.archlinux.org, or https://localhost:8443 +through docker). From 27fbda5e7ba21a43c64ca0324c24f42a484196c0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 9 Oct 2021 22:00:18 -0700 Subject: [PATCH 0944/1891] feat(FastAPI): add get_(errors|successes) testing HTML helpers These functions will allow us to more easily check errors or success messages when testing routes. Signed-off-by: Kevin Morris --- aurweb/testing/html.py | 11 +++++++++++ test/test_html.py | 22 +++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/aurweb/testing/html.py b/aurweb/testing/html.py index d5f0c256..f01aaf3d 100644 --- a/aurweb/testing/html.py +++ b/aurweb/testing/html.py @@ -1,4 +1,5 @@ from io import StringIO +from typing import List from lxml import etree @@ -12,3 +13,13 @@ def parse_root(html: str) -> etree.Element: :return: etree.Element """ return etree.parse(StringIO(html), parser) + + +def get_errors(content: str) -> List[etree._Element]: + root = parse_root(content) + return root.xpath('//ul[@class="errorlist"]/li') + + +def get_successes(content: str) -> List[etree._Element]: + root = parse_root(content) + return root.xpath('//ul[@class="success"]/li') diff --git a/test/test_html.py b/test/test_html.py index 562d6a63..2018840b 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -9,7 +9,7 @@ from aurweb import asgi, db from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID, AccountType from aurweb.models.user import User from aurweb.testing import setup_test_db -from aurweb.testing.html import parse_root +from aurweb.testing.html import get_errors, get_successes, parse_root from aurweb.testing.requests import Request @@ -97,3 +97,23 @@ def test_archdev_navbar_authenticated_tu(client: TestClient, items = root.xpath('//div[@id="archdev-navbar"]/ul/li/a') for i, item in enumerate(items): assert item.text.strip() == expected[i] + + +def test_get_errors(): + html = """ +
      +
    • Test
    • +
    +""" + errors = get_errors(html) + assert errors[0].text.strip() == "Test" + + +def test_get_successes(): + html = """ +
      +
    • Test
    • +
    +""" + successes = get_successes(html) + assert successes[0].text.strip() == "Test" From 4525a11d923f3669e46204626b7c1115927d4703 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 10 Oct 2021 00:59:08 -0700 Subject: [PATCH 0945/1891] fix(FastAPI): change a deep copy instead of original This was updating offsets and causing unintended behavior. We should be a bit more functional anyway. Signed-off-by: Kevin Morris --- aurweb/util.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index 44f711f1..61ed5cfb 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -1,4 +1,5 @@ import base64 +import copy import logging import math import random @@ -127,9 +128,10 @@ def as_timezone(dt: datetime, timezone: str): def extend_query(query: Dict[str, Any], *additions) -> Dict[str, Any]: """ Add additional key value pairs to query. """ + q = copy.copy(query) for k, v in list(additions): - query[k] = v - return query + q[k] = v + return q def to_qs(query: Dict[str, Any]) -> str: From 68383b79e24b645c0079627149187c06b3dda734 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 11 Oct 2021 14:13:29 -0700 Subject: [PATCH 0946/1891] add Feature.md GitLab issue template Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Feature.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .gitlab/issue_templates/Feature.md diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md new file mode 100644 index 00000000..5b1524b1 --- /dev/null +++ b/.gitlab/issue_templates/Feature.md @@ -0,0 +1,30 @@ +- [ ] I have summed up the feature in concise words in the [Summary](#summary) section. +- [ ] I have completely described the feature in the [Description](#description) section. +- [ ] I have completed the [Blockers](#blockers) section. + +### Summary + +Fill this section out with a concise wording about the feature being +requested. + +Example: _A new `Tyrant` account type for users_. + +### Description + +Describe your feature in full detail. + +Example: _The `Tyrant` account type should be used to allow a user to be +tyrannical. When a user is a `Tyrant`, they should be able to assassinate +users due to not complying with their laws. Laws can be configured by updating +the Tyrant laws page at https://aur.archlinux.org/account/{username}/laws. +More specifics about laws._ + +### Blockers + +Include any blockers in a list. If there are no blockers, this section +should be omitted from the issue. + +Example: + +- [Feature] Do not allow users to be Tyrants + - \<(issue|merge_request)_link\> From 3d971bfc8d70c48f69090b7ec0b0b1899178c03d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 11 Oct 2021 14:48:00 -0700 Subject: [PATCH 0947/1891] add Bug.md GitLab issue template Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Bug.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .gitlab/issue_templates/Bug.md diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md new file mode 100644 index 00000000..d84a5181 --- /dev/null +++ b/.gitlab/issue_templates/Bug.md @@ -0,0 +1,34 @@ +- [ ] I have described the bug in complete detail in the + [Description](#description) section. +- [ ] I have specified steps in the [Reproduction](#reproduction) section. +- [ ] I have included any logs related to the bug in the + [Logs](#logs) section. +- [ ] I have included the versions which are affected in the + [Version(s)](#versions) section. + +### Description + +Describe the bug in full detail. + +### Reproduction + +Describe a specific set of actions that can be used to reproduce +this bug. + +### Logs + +If you have any logs relevent to the bug, include them here in +quoted or code blocks. + +### Version(s) + +In this section, please include a list of versions you have found +to be affected by this program. This can either come in the form +of `major.minor.patch` (if it affects a release tarball), or a +commit hash if the bug does not directly affect a release version. + +All development is done without modifying version displays in +aurweb's HTML render output. If you're testing locally, use the +commit on which you are experiencing the bug. If you have found +a bug which exists on live aur.archlinux.org, include the version +located at the bottom of the webpage. From 748faca87d314e23557a1e20223db939d8b19192 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 12 Oct 2021 17:55:03 -0700 Subject: [PATCH 0948/1891] fix(FastAPI): translate some untranslated strings Affects: templates/partials/packages/search_actions.html Signed-off-by: Kevin Morris --- templates/partials/packages/search_actions.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/partials/packages/search_actions.html b/templates/partials/packages/search_actions.html index 2f5fe2e7..221189fb 100644 --- a/templates/partials/packages/search_actions.html +++ b/templates/partials/packages/search_actions.html @@ -18,8 +18,8 @@ - +

    From 22b3af61b568732861be17e9759be68715a709fb Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 13 Oct 2021 17:10:16 -0700 Subject: [PATCH 0949/1891] fix(PHP): sanitize and produce metrics at shutdown This change now requires that PHP routes do not return HTTP 404 to be considered for the /metrics population. Additionally, we make a small sanitization here to avoid trailing '/' characters, unless we're on the homepage route. Signed-off-by: Kevin Morris --- web/html/index.php | 24 ++--------------------- web/lib/metricfuncs.inc.php | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/web/html/index.php b/web/html/index.php index 82a44c55..99046930 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -13,28 +13,8 @@ $query_string = $_SERVER['QUERY_STRING']; // If no options.cache is configured, we no-op metric storage operations. $is_cached = defined('EXTENSION_LOADED_APC') || defined('EXTENSION_LOADED_MEMCACHE'); -if ($is_cached) { - $method = $_SERVER['REQUEST_METHOD']; - // We'll always add +1 to our total request count to this $path, - // unless this path == /metrics. - if ($path !== "/metrics") - add_metric("http_requests_count", $method, $path); - - // Extract $type out of $query_string, if we can. - $type = null; - $query = array(); - if ($query_string) - parse_str($query_string, $query); - $type = $query['type']; - - // Only store RPC metrics for valid types. - $good_types = [ - "info", "multiinfo", "search", "msearch", - "suggest", "suggest-pkgbase", "get-comment-form" - ]; - if ($path === "/rpc" && in_array($type, $good_types)) - add_metric("api_requests_count", $method, $path, $type); -} +if ($is_cached) + register_shutdown_function('update_metrics'); if (config_get_bool('options', 'enable-maintenance') && (empty($tokens[1]) || ($tokens[1] != "css" && $tokens[1] != "images"))) { if (!in_array($_SERVER['REMOTE_ADDR'], explode(" ", config_get('options', 'maintenance-exceptions')))) { diff --git a/web/lib/metricfuncs.inc.php b/web/lib/metricfuncs.inc.php index acfc30d7..7ebb59be 100644 --- a/web/lib/metricfuncs.inc.php +++ b/web/lib/metricfuncs.inc.php @@ -13,6 +13,44 @@ use \Prometheus\RenderTextFormat; // and will start again at 0 if it's restarted. $registry = new CollectorRegistry(new InMemory()); +function update_metrics() { + // With no code given to http_response_code, it gets the current + // response code set (via http_response_code or header). + if(http_response_code() == 404) + return; + + $path = $_SERVER['PATH_INFO']; + $method = $_SERVER['REQUEST_METHOD']; + $query_string = $_SERVER['QUERY_STRING']; + + // If $path is at least 1 character, strip / off the end. + // This turns $paths like '/packages/' into '/packages'. + if (strlen($path) > 1) + $path = rtrim($path, "/"); + + // We'll always add +1 to our total request count to this $path, + // unless this path == /metrics. + if ($path !== "/metrics") + add_metric("http_requests_count", $method, $path); + + // Extract $type out of $query_string, if we can. + $type = null; + $query = array(); + if ($query_string) + parse_str($query_string, $query); + + if (array_key_exists("type", $query)) + $type = $query["type"]; + + // Only store RPC metrics for valid types. + $good_types = [ + "info", "multiinfo", "search", "msearch", + "suggest", "suggest-pkgbase", "get-comment-form" + ]; + if ($path === "/rpc" && in_array($type, $good_types)) + add_metric("api_requests_count", $method, $path, $type); +} + function add_metric($anchor, $method, $path, $type = null) { global $registry; From 5bfc1e9094e2a67bad534f7380b1b6b20fe13ef9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 15 Oct 2021 13:18:58 -0700 Subject: [PATCH 0950/1891] Revert "fix(PHP): sanitize and produce metrics at shutdown" This reverts commit 22b3af61b568732861be17e9759be68715a709fb. --- web/html/index.php | 24 +++++++++++++++++++++-- web/lib/metricfuncs.inc.php | 38 ------------------------------------- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/web/html/index.php b/web/html/index.php index 99046930..82a44c55 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -13,8 +13,28 @@ $query_string = $_SERVER['QUERY_STRING']; // If no options.cache is configured, we no-op metric storage operations. $is_cached = defined('EXTENSION_LOADED_APC') || defined('EXTENSION_LOADED_MEMCACHE'); -if ($is_cached) - register_shutdown_function('update_metrics'); +if ($is_cached) { + $method = $_SERVER['REQUEST_METHOD']; + // We'll always add +1 to our total request count to this $path, + // unless this path == /metrics. + if ($path !== "/metrics") + add_metric("http_requests_count", $method, $path); + + // Extract $type out of $query_string, if we can. + $type = null; + $query = array(); + if ($query_string) + parse_str($query_string, $query); + $type = $query['type']; + + // Only store RPC metrics for valid types. + $good_types = [ + "info", "multiinfo", "search", "msearch", + "suggest", "suggest-pkgbase", "get-comment-form" + ]; + if ($path === "/rpc" && in_array($type, $good_types)) + add_metric("api_requests_count", $method, $path, $type); +} if (config_get_bool('options', 'enable-maintenance') && (empty($tokens[1]) || ($tokens[1] != "css" && $tokens[1] != "images"))) { if (!in_array($_SERVER['REMOTE_ADDR'], explode(" ", config_get('options', 'maintenance-exceptions')))) { diff --git a/web/lib/metricfuncs.inc.php b/web/lib/metricfuncs.inc.php index 7ebb59be..acfc30d7 100644 --- a/web/lib/metricfuncs.inc.php +++ b/web/lib/metricfuncs.inc.php @@ -13,44 +13,6 @@ use \Prometheus\RenderTextFormat; // and will start again at 0 if it's restarted. $registry = new CollectorRegistry(new InMemory()); -function update_metrics() { - // With no code given to http_response_code, it gets the current - // response code set (via http_response_code or header). - if(http_response_code() == 404) - return; - - $path = $_SERVER['PATH_INFO']; - $method = $_SERVER['REQUEST_METHOD']; - $query_string = $_SERVER['QUERY_STRING']; - - // If $path is at least 1 character, strip / off the end. - // This turns $paths like '/packages/' into '/packages'. - if (strlen($path) > 1) - $path = rtrim($path, "/"); - - // We'll always add +1 to our total request count to this $path, - // unless this path == /metrics. - if ($path !== "/metrics") - add_metric("http_requests_count", $method, $path); - - // Extract $type out of $query_string, if we can. - $type = null; - $query = array(); - if ($query_string) - parse_str($query_string, $query); - - if (array_key_exists("type", $query)) - $type = $query["type"]; - - // Only store RPC metrics for valid types. - $good_types = [ - "info", "multiinfo", "search", "msearch", - "suggest", "suggest-pkgbase", "get-comment-form" - ]; - if ($path === "/rpc" && in_array($type, $good_types)) - add_metric("api_requests_count", $method, $path, $type); -} - function add_metric($anchor, $method, $path, $type = null) { global $registry; From 040bb0d7f4d43af66126abdc677fcea05afa058a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 15 Oct 2021 13:19:07 -0700 Subject: [PATCH 0951/1891] Revert "feat(PHP): add aurweb Prometheus metrics" This reverts commit 986fa9ee305ed113172f7f214d451a7af071ecc2. --- INSTALL | 8 +-- web/html/index.php | 29 -------- web/html/metrics.php | 16 ----- web/lib/metricfuncs.inc.php | 129 ------------------------------------ web/lib/routing.inc.php | 3 +- 5 files changed, 2 insertions(+), 183 deletions(-) delete mode 100644 web/html/metrics.php delete mode 100644 web/lib/metricfuncs.inc.php diff --git a/INSTALL b/INSTALL index b161edd2..9bcd0759 100644 --- a/INSTALL +++ b/INSTALL @@ -49,15 +49,9 @@ read the instructions below. # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy \ python-bleach python-markdown python-alembic python-jinja \ - python-itsdangerous python-authlib python-httpx hypercorn \ - composer + python-itsdangerous python-authlib python-httpx hypercorn # python3 setup.py install -4a) Install `composer` dependencies while inside of aurweb's root: - - $ cd /path/to/aurweb - /path/to/aurweb $ composer require promphp/prometheus_client_php - 5) Create a new MySQL database and a user and import the aurweb SQL schema: $ python -m aurweb.initdb diff --git a/web/html/index.php b/web/html/index.php index 82a44c55..e57e7708 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -3,39 +3,10 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); include_once("pkgfuncs.inc.php"); -include_once("cachefuncs.inc.php"); -include_once("metricfuncs.inc.php"); $path = $_SERVER['PATH_INFO']; $tokens = explode('/', $path); -$query_string = $_SERVER['QUERY_STRING']; - -// If no options.cache is configured, we no-op metric storage operations. -$is_cached = defined('EXTENSION_LOADED_APC') || defined('EXTENSION_LOADED_MEMCACHE'); -if ($is_cached) { - $method = $_SERVER['REQUEST_METHOD']; - // We'll always add +1 to our total request count to this $path, - // unless this path == /metrics. - if ($path !== "/metrics") - add_metric("http_requests_count", $method, $path); - - // Extract $type out of $query_string, if we can. - $type = null; - $query = array(); - if ($query_string) - parse_str($query_string, $query); - $type = $query['type']; - - // Only store RPC metrics for valid types. - $good_types = [ - "info", "multiinfo", "search", "msearch", - "suggest", "suggest-pkgbase", "get-comment-form" - ]; - if ($path === "/rpc" && in_array($type, $good_types)) - add_metric("api_requests_count", $method, $path, $type); -} - if (config_get_bool('options', 'enable-maintenance') && (empty($tokens[1]) || ($tokens[1] != "css" && $tokens[1] != "images"))) { if (!in_array($_SERVER['REMOTE_ADDR'], explode(" ", config_get('options', 'maintenance-exceptions')))) { header("HTTP/1.0 503 Service Unavailable"); diff --git a/web/html/metrics.php b/web/html/metrics.php deleted file mode 100644 index dfa860ed..00000000 --- a/web/html/metrics.php +++ /dev/null @@ -1,16 +0,0 @@ - diff --git a/web/lib/metricfuncs.inc.php b/web/lib/metricfuncs.inc.php deleted file mode 100644 index acfc30d7..00000000 --- a/web/lib/metricfuncs.inc.php +++ /dev/null @@ -1,129 +0,0 @@ -, 'query_string': }. - $metrics = get_cache_value("prometheus_metrics"); - $metrics = $metrics ? json_decode($metrics) : array(); - - $key = "$path:$type"; - - // If the current request $path isn't yet in $metrics create - // a new assoc array for it and push it into $metrics. - if (!in_array($key, $metrics)) { - $data = array( - 'anchor' => $anchor, - 'method' => $method, - 'path' => $path, - 'type' => $type - ); - array_push($metrics, json_encode($data)); - } - - // Cache-wise, we also store the count values of each route - // through the "prometheus:" key. Grab the cache value - // representing the current $path we're on (defaulted to 1). - $count = get_cache_value("prometheus:$key"); - $count = $count ? $count + 1 : 1; - - $labels = ["method", "route"]; - if ($type) - array_push($labels, "type"); - - $gauge = $registry->getOrRegisterGauge( - 'aurweb', - $anchor, - 'A metric count for the aurweb platform.', - $labels - ); - - $label_values = [$data['method'], $data['path']]; - if ($type) - array_push($label_values, $type); - - $gauge->set($count, $label_values); - - // Update cache values. - set_cache_value("prometheus:$key", $count, 0); - set_cache_value("prometheus_metrics", json_encode($metrics), 0); - -} - -function render_metrics() { - if (!defined('EXTENSION_LOADED_APC') && !defined('EXTENSION_LOADED_MEMCACHE')) { - error_log("The /metrics route requires a valid 'options.cache' " - . "configuration; no cache is configured."); - return http_response_code(417); // EXPECTATION_FAILED - } - - global $registry; - - // First, we grab the set of metrics we're interested in in the - // form of a cached JSON list, if we can. - $metrics = get_cache_value("prometheus_metrics"); - if (!$metrics) - $metrics = array(); - else - $metrics = json_decode($metrics); - - // Now, we walk through each of those list values one by one, - // which happen to be JSON-serialized associative arrays, - // and process each metric via its associative array's contents: - // The route path and the query string. - // See web/html/index.php for the creation of such metrics. - foreach ($metrics as $metric) { - $data = json_decode($metric, true); - - $anchor = $data['anchor']; - $path = $data['path']; - $type = $data['type']; - $key = "$path:$type"; - - $labels = ["method", "route"]; - if ($type) - array_push($labels, "type"); - - $count = get_cache_value("prometheus:$key"); - $gauge = $registry->getOrRegisterGauge( - 'aurweb', - $anchor, - 'A metric count for the aurweb platform.', - $labels - ); - - $label_values = [$data['method'], $data['path']]; - if ($type) - array_push($label_values, $type); - - $gauge->set($count, $label_values); - } - - // Construct the results from RenderTextFormat renderer and - // registry's samples. - $renderer = new RenderTextFormat(); - $result = $renderer->render($registry->getMetricFamilySamples()); - - // Output the results with the right content type header. - http_response_code(200); // OK - header('Content-Type: ' . RenderTextFormat::MIME_TYPE); - echo $result; -} - -?> diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php index 0f452f22..73c667d2 100644 --- a/web/lib/routing.inc.php +++ b/web/lib/routing.inc.php @@ -19,8 +19,7 @@ $ROUTES = array( '/rss' => 'rss.php', '/tos' => 'tos.php', '/tu' => 'tu.php', - '/addvote' => 'addvote.php', - '/metrics' => 'metrics.php' // Prometheus Metrics + '/addvote' => 'addvote.php', ); $PKG_PATH = '/packages'; From dd420f8c4148a7696554499fd99eb8c5c726a994 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 11 Oct 2021 14:13:29 -0700 Subject: [PATCH 0952/1891] add Feature.md GitLab issue template Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Feature.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .gitlab/issue_templates/Feature.md diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md new file mode 100644 index 00000000..5b1524b1 --- /dev/null +++ b/.gitlab/issue_templates/Feature.md @@ -0,0 +1,30 @@ +- [ ] I have summed up the feature in concise words in the [Summary](#summary) section. +- [ ] I have completely described the feature in the [Description](#description) section. +- [ ] I have completed the [Blockers](#blockers) section. + +### Summary + +Fill this section out with a concise wording about the feature being +requested. + +Example: _A new `Tyrant` account type for users_. + +### Description + +Describe your feature in full detail. + +Example: _The `Tyrant` account type should be used to allow a user to be +tyrannical. When a user is a `Tyrant`, they should be able to assassinate +users due to not complying with their laws. Laws can be configured by updating +the Tyrant laws page at https://aur.archlinux.org/account/{username}/laws. +More specifics about laws._ + +### Blockers + +Include any blockers in a list. If there are no blockers, this section +should be omitted from the issue. + +Example: + +- [Feature] Do not allow users to be Tyrants + - \<(issue|merge_request)_link\> From 81c9312606458395c90984be3f4a758636f93c9f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 11 Oct 2021 14:48:00 -0700 Subject: [PATCH 0953/1891] add Bug.md GitLab issue template Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Bug.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .gitlab/issue_templates/Bug.md diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md new file mode 100644 index 00000000..d84a5181 --- /dev/null +++ b/.gitlab/issue_templates/Bug.md @@ -0,0 +1,34 @@ +- [ ] I have described the bug in complete detail in the + [Description](#description) section. +- [ ] I have specified steps in the [Reproduction](#reproduction) section. +- [ ] I have included any logs related to the bug in the + [Logs](#logs) section. +- [ ] I have included the versions which are affected in the + [Version(s)](#versions) section. + +### Description + +Describe the bug in full detail. + +### Reproduction + +Describe a specific set of actions that can be used to reproduce +this bug. + +### Logs + +If you have any logs relevent to the bug, include them here in +quoted or code blocks. + +### Version(s) + +In this section, please include a list of versions you have found +to be affected by this program. This can either come in the form +of `major.minor.patch` (if it affects a release tarball), or a +commit hash if the bug does not directly affect a release version. + +All development is done without modifying version displays in +aurweb's HTML render output. If you're testing locally, use the +commit on which you are experiencing the bug. If you have found +a bug which exists on live aur.archlinux.org, include the version +located at the bottom of the webpage. From 71b3f781f799f8c9d1d8b3e39682972b89d6c9c2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 15 Oct 2021 15:11:45 -0700 Subject: [PATCH 0954/1891] fix(FastAPI): maintainers are allowed to unflag their packages Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 2 +- test/test_packages_routes.py | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 8f4a7e1f..15d0591c 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -820,7 +820,7 @@ async def pkgbase_unflag(request: Request, name: str): pkgbase = get_pkg_or_base(name, PackageBase) has_cred = request.user.has_credential( - "CRED_PKGBASE_UNFLAG", approved=[pkgbase.Flagger]) + "CRED_PKGBASE_UNFLAG", approved=[pkgbase.Flagger, pkgbase.Maintainer]) if has_cred: with db.begin(): pkgbase.OutOfDateTS = None diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 12d7e33e..e2811a46 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1713,7 +1713,9 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, # Flag it with a valid comment. with client as request: - resp = request.post(endpoint, {"comments": "Test"}, cookies=cookies) + resp = request.post(endpoint, data={ + "comments": "Test" + }, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger == user assert pkgbase.FlaggerComment == "Test" @@ -1724,14 +1726,34 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, resp = request.get(endpoint, cookies=cookies, allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) - # Now, test that the 'maintainer' user can't unflag it, because they + with db.begin(): + user2 = db.create(User, Username="test2", + Email="test2@example.org", + Passwd="testPassword", + AccountType=user.AccountType) + + # Now, test that the 'user2' user can't unflag it, because they # didn't flag it to begin with. - maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + user2_cookies = {"AURSID": user2.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/unflag" + with client as request: + resp = request.post(endpoint, cookies=user2_cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert pkgbase.Flagger == user + + # Now, test that the 'maintainer' user can. + maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: resp = request.post(endpoint, cookies=maint_cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) - assert pkgbase.Flagger == user + assert pkgbase.Flagger is None + + # Flag it again. + with client as request: + resp = request.post(f"/pkgbase/{pkgbase.Name}/flag", data={ + "comments": "Test" + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Now, unflag it for real. with client as request: From 2d46811c45a14b89f0c9251ed25b53c8a7f0e775 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 15 Oct 2021 16:15:53 -0700 Subject: [PATCH 0955/1891] fix(FastAPI): display VCS note when flagging a VCS package Closes: #131 Signed-off-by: Kevin Morris --- po/aurweb.pot | 9 +++++++++ templates/packages/flag.html | 14 ++++++++++++++ test/test_packages_routes.py | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/po/aurweb.pot b/po/aurweb.pot index aeed9f02..1f7e8784 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -568,6 +568,15 @@ msgstr "" msgid "Flag Package Out-Of-Date" msgstr "" +#: templates/packages/flag.html +msgid "This seems to be a VCS package. Please do %snot%s flag " +"it out-of-date if the package version in the AUR does " +"not match the most recent commit. Flagging this package " +"should only be done if the sources moved or changes in " +"the PKGBUILD are required because of recent upstream " +"changes." +msgstr "" + #: html/pkgflag.php #, php-format msgid "" diff --git a/templates/packages/flag.html b/templates/packages/flag.html index 4e133acb..0335cf18 100644 --- a/templates/packages/flag.html +++ b/templates/packages/flag.html @@ -18,6 +18,20 @@ {% endfor %} + {% if pkgbase.Name.endswith(('-cvs', '-svn', '-git', '-hg', '-bzr', '-darcs')) %} +

    + {# TODO: This error is not yet translated. #} + {{ + "This seems to be a VCS package. Please do %snot%s flag " + "it out-of-date if the package version in the AUR does " + "not match the most recent commit. Flagging this package " + "should only be done if the sources moved or changes in " + "the PKGBUILD are required because of recent upstream " + "changes." | tr | format("", "") | safe + }} +

    + {% endif %} +

    {{ "Please do %snot%s use this form to report bugs. " diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index e2811a46..7eb4e532 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1762,6 +1762,27 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, assert pkgbase.Flagger is None +def test_pkgbase_flag_vcs(client: TestClient, user: User, package: Package): + # Morph our package fixture into a VCS package (-git). + with db.begin(): + package.PackageBase.Name += "-git" + package.Name += "-git" + + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.get(f"/pkgbase/{package.PackageBase.Name}/flag", + cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + expected = ("This seems to be a VCS package. Please do " + "not flag it out-of-date if the package " + "version in the AUR does not match the most recent commit. " + "Flagging this package should only be done if the sources " + "moved or changes in the PKGBUILD are required because of " + "recent upstream changes.") + assert expected in resp.text + + def test_pkgbase_notify(client: TestClient, user: User, package: Package): pkgbase = package.PackageBase From 8040ef5a9c53048598eb6d0b356923db00467b7e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 15 Oct 2021 19:02:53 -0700 Subject: [PATCH 0956/1891] fix(FastAPI): use pkgbase in package actions Previously, `result` was being used which was directly set to `pkgbase` before rendering the actions.html partial. It didn't make much sense. This commit cleans things up a bit. Signed-off-by: Kevin Morris --- templates/packages/show.html | 5 ++-- templates/partials/packages/actions.html | 36 ++++++++++++------------ 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/templates/packages/show.html b/templates/packages/show.html index ba531fc8..fbc9c0ea 100644 --- a/templates/packages/show.html +++ b/templates/packages/show.html @@ -5,7 +5,6 @@

    {{ 'Package Details' | tr }}: {{ package.Name }} {{ package.Version }}

    - {% set result = pkgbase %} {% include "partials/packages/actions.html" %} {% set show_package_details = True %} @@ -16,7 +15,7 @@
    - {% set pkgname = result.Name %} - {% set pkgbase_id = result.ID %} + {% set pkgname = package.Name %} + {% set pkgbase_id = pkgbase.ID %} {% include "partials/packages/comments.html" %} {% endblock %} diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index dd83c84d..81536a3d 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -1,38 +1,38 @@ diff --git a/templates/partials/account/comment.html b/templates/partials/account/comment.html new file mode 100644 index 00000000..bc167cf7 --- /dev/null +++ b/templates/partials/account/comment.html @@ -0,0 +1,40 @@ +{% set header_cls = "comment-header" %} +{% if comment.Deleter %} + {% set header_cls = "%s %s" | format(header_cls, "comment-deleted") %} +{% endif %} + +{% if not comment.Deleter or request.user.has_credential("CRED_COMMENT_VIEW_DELETED", approved=[comment.Deleter]) %} + + {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} +

    + {{ + "Commented on package %s%s%s on %s%s%s" | tr + | format( + '' | format(comment.PackageBase.Name), + comment.PackageBase.Name, + "", + '' | format( + username, + comment.ID + ), + commented_at.strftime("%Y-%m-%d %H:%M"), + "" + ) | safe + }} + {% if comment.Editor %} + {% set edited_on = comment.EditedTS | dt | as_timezone(timezone) %} + + ({{ "edited on %s by %s" | tr + | format(edited_on.strftime('%Y-%m-%d %H:%M'), + '%s' | format( + comment.Editor.Username, comment.Editor.Username)) + | safe + }}) + + {% endif %} + + {% include "partials/comment_actions.html" %} +

    + + {% include "partials/comment_content.html" %} +{% endif %} From 7f4c011dc3d4db377c7676bde50b67db9b937c72 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 29 Oct 2021 20:26:57 -0700 Subject: [PATCH 1032/1891] fix(fastapi): sanitize PP/O parameters for package search This definitely leaked through in more areas. We'll need to reuse this new utility function in a few other routes in upcoming commits. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 7 +++++-- aurweb/util.py | 18 ++++++++++++++++-- test/test_packages_routes.py | 10 +++------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index b0da3bf9..14b91221 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -30,8 +30,11 @@ async def packages_get(request: Request, context: Dict[str, Any], context["q"] = dict(request.query_params) # Per page and offset. - per_page = context["PP"] = int(request.query_params.get("PP", 50)) - offset = context["O"] = int(request.query_params.get("O", 0)) + offset, per_page = util.sanitize_params( + request.query_params.get("O", defaults.O), + request.query_params.get("PP", defaults.PP)) + context["O"] = offset + context["PP"] = per_page # Query search by. search_by = context["SeB"] = request.query_params.get("SeB", "nd") diff --git a/aurweb/util.py b/aurweb/util.py index dd7491d3..88142cbc 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -7,7 +7,7 @@ import secrets import string from datetime import datetime -from typing import Any, Callable, Dict, Iterable +from typing import Any, Callable, Dict, Iterable, Tuple from urllib.parse import urlencode, urlparse from zoneinfo import ZoneInfo @@ -18,7 +18,7 @@ from jinja2 import pass_context import aurweb.config -from aurweb import logging +from aurweb import defaults, logging logger = logging.get_logger(__name__) @@ -155,3 +155,17 @@ def get_ssh_fingerprints(): def apply_all(iterable: Iterable, fn: Callable): for item in iterable: fn(item) + + +def sanitize_params(offset: str, per_page: str) -> Tuple[int, int]: + try: + offset = int(offset) + except ValueError: + offset = defaults.O + + try: + per_page = int(per_page) + except ValueError: + per_page = defaults.PP + + return (offset, per_page) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index b4a582e3..2ef3f3d8 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -486,15 +486,11 @@ def test_pkgbase(client: TestClient, package: Package): def test_packages(client: TestClient, packages: List[Package]): - """ Test the / packages route with defaults. - - Defaults: - 50 results per page - offset of 0 - """ with client as request: response = request.get("/packages", params={ - "SeB": "X" # "X" isn't valid, defaults to "nd" + "SeB": "X", # "X" isn't valid, defaults to "nd" + "PP": "1 or 1", + "O": "0 or 0" }) assert response.status_code == int(HTTPStatus.OK) From 01e27fa34719b8e68def295c575bfb1f9b0ed362 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 29 Oct 2021 20:29:56 -0700 Subject: [PATCH 1033/1891] fix(fastapi): sanitize /requests params Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 14b91221..27125b60 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -635,6 +635,8 @@ async def requests(request: Request, context = make_context(request, "Requests") context["q"] = dict(request.query_params) + + O, PP = util.sanitize_params(O, PP) context["O"] = O context["PP"] = PP From 9464de108f39e3fe633083ddf3c7a3526426fd98 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 29 Oct 2021 21:37:52 -0700 Subject: [PATCH 1034/1891] feat(fastapi): add /pkgbase/{name}/comments/{id}/edit (get) This is needed so that users can edit comments when they don't have Javascript being used in their browser. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 15 +++++++++ templates/packages/comments/edit.html | 44 +++++++++++++++++++++++++++ test/test_packages_routes.py | 7 +++++ 3 files changed, 66 insertions(+) create mode 100644 templates/packages/comments/edit.html diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 27125b60..c574ec18 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -384,6 +384,21 @@ async def pkgbase_comment_post( status_code=HTTPStatus.SEE_OTHER) +@router.get("/pkgbase/{name}/comments/{id}/edit") +@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/edit") +async def pkgbase_comment_edit(request: Request, name: str, id: int, + next: str = Form(default=None)): + pkgbase = get_pkg_or_base(name, models.PackageBase) + comment = get_pkgbase_comment(pkgbase, id) + + if not next: + next = f"/pkgbase/{name}" + + context = await make_variable_context(request, "Edit comment", next=next) + context["comment"] = comment + return render_template(request, "packages/comments/edit.html", context) + + @router.post("/pkgbase/{name}/comments/{id}/delete") @auth_required(True, redirect="/pkgbase/{name}/comments/{id}/delete") async def pkgbase_comment_delete(request: Request, name: str, id: int, diff --git a/templates/packages/comments/edit.html b/templates/packages/comments/edit.html new file mode 100644 index 00000000..f938287e --- /dev/null +++ b/templates/packages/comments/edit.html @@ -0,0 +1,44 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {{ "Edit comment for: %s" | tr | format(comment.PackageBase.Name) }}

    + + +
    +
    + +
    + +

    + {{ + "Git commit identifiers referencing commits in " + "the AUR package repository and URLs are converted " + "to links automatically." | tr + }} + {{ + "%sMarkdown syntax%s is partiaully supported." + | tr | format( + '', + "" + ) | safe + }} +

    + +

    + +

    + +

    + +

    + +
    + + +
    +{% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 2ef3f3d8..207be379 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1084,6 +1084,13 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, assert len(bodies) == 1 assert bodies[0].text.strip() == "Test comment." + comment_id = headers[0].attrib["id"].split("-")[-1] + + # Test the non-javascript version of comment editing by + # visiting the /pkgbase/{name}/comments/{id}/edit route. + with client as request: + resp = request.get(f"{endpoint}/{comment_id}/edit", cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) # Clear up the PackageNotification. This doubles as testing # that the notification was created and clears it up so we can From b3b31394e840b2372134fb23f9217e9c40ef242b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 29 Oct 2021 22:59:40 -0700 Subject: [PATCH 1035/1891] fix(rpc): simplify json generation complexity This simply decouples depends and relations population into their own helper functions. Signed-off-by: Kevin Morris --- aurweb/rpc.py | 60 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 84bae53c..e92f9c70 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import List +from typing import Any, Dict, List from sqlalchemy import and_ @@ -95,6 +95,36 @@ class RPC: raise RPCError( f"Request type '{self.type}' is not yet implemented.") + def _update_json_depends(self, package: models.Package, + data: Dict[str, Any]): + # Walk through all related PackageDependencies and produce + # the appropriate dict entries. + depends = package.package_dependencies + for dep in depends: + if dep.DepTypeID in DEP_TYPES: + key = DEP_TYPES.get(dep.DepTypeID) + + display = dep.DepName + if dep.DepCondition: + display += dep.DepCondition + + data[key].append(display) + + def _update_json_relations(self, package: models.Package, + data: Dict[str, Any]): + # Walk through all related PackageRelations and produce + # the appropriate dict entries. + relations = package.package_relations + for rel in relations: + if rel.RelTypeID in REL_TYPES: + key = REL_TYPES.get(rel.RelTypeID) + + display = rel.RelName + if rel.RelCondition: + display += rel.RelCondition + + data[key].append(display) + def _get_json_data(self, package: models.Package): """ Produce dictionary data of one Package that can be JSON-serialized. @@ -137,32 +167,8 @@ class RPC: # We do have a maintainer: set the Maintainer key. data["Maintainer"] = package.PackageBase.Maintainer.Username - # Walk through all related PackageDependencies and produce - # the appropriate dict entries. - if depends := package.package_dependencies: - for dep in depends: - if dep.DepTypeID in DEP_TYPES: - key = DEP_TYPES.get(dep.DepTypeID) - - display = dep.DepName - if dep.DepCondition: - display += dep.DepCondition - - data[key].append(display) - - # Walk through all related PackageRelations and produce - # the appropriate dict entries. - if relations := package.package_relations: - for rel in relations: - if rel.RelTypeID in REL_TYPES: - key = REL_TYPES.get(rel.RelTypeID) - - display = rel.RelName - if rel.RelCondition: - display += rel.RelCondition - - data[key].append(display) - + self._update_json_depends(package, data) + self._update_json_relations(package, data) return data def _handle_multiinfo_type(self, args: List[str] = []): From 0af6a2c32f04f1c0f8b98e1be9fa45983eec9bd5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 29 Oct 2021 23:47:47 -0700 Subject: [PATCH 1036/1891] fix(docker): fix COMMIT_HASH variable check The previous method was super bad. Even if a variable was declared, if it was empty, we would run into a false-positive. Additionally, the previous method did not allow us to not specify the COMMIT_HASH variable; which is problematic for development environments. Signed-off-by: Kevin Morris --- docker/fastapi-entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index ec9eb5c1..58fafe56 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -11,7 +11,7 @@ sed -ri "s;^(aur_location) = .+;\1 = ${AURWEB_FASTAPI_PREFIX};" conf/config sed -ri 's/^(cache) = .+/\1 = redis/' conf/config sed -ri 's|^(redis_address) = .+|\1 = redis://redis|' conf/config -if [ "$COMMIT_HASH" ]; then +if [ ! -z ${COMMIT_HASH+x} ]; then sed -ri "s/^;?(commit_hash) =.*$/\1 = $COMMIT_HASH/" conf/config fi From 6d376fed1576e036d8a4ceb687493e647f3d8c0d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 29 Oct 2021 23:10:20 -0700 Subject: [PATCH 1037/1891] feat(rpc): add ETag header with md5 hash content The ETag header can be used for client-side caching. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 25 +++++++++++++++++++++++-- aurweb/rpc.py | 6 ++---- test/test_rpc.py | 8 ++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 0616326b..0c52404c 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -1,8 +1,12 @@ +import hashlib + from http import HTTPStatus from typing import List, Optional from urllib.parse import unquote -from fastapi import APIRouter, Query, Request +import orjson + +from fastapi import APIRouter, Query, Request, Response from fastapi.responses import JSONResponse from aurweb.ratelimit import check_ratelimit @@ -74,4 +78,21 @@ async def rpc(request: Request, # Prepare list of arguments for input. If 'arg' was given, it'll # be a list with one element. arguments = parse_args(request) - return JSONResponse(rpc.handle(arguments)) + data = rpc.handle(arguments) + + # Serialize `data` into JSON in a sorted fashion. This way, our + # ETag header produced below will never end up changed. + output = orjson.dumps(data, option=orjson.OPT_SORT_KEYS) + + # Produce an md5 hash based on `output`. + md5 = hashlib.md5() + md5.update(output) + etag = md5.hexdigest() + + # Finally, return our JSONResponse with the ETag header. + # The ETag header expects quotes to surround any identifier. + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag + return Response(output.decode(), headers={ + "Content-Type": "application/json", + "ETag": f'"{etag}"' + }) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index e92f9c70..87700a2f 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -99,8 +99,7 @@ class RPC: data: Dict[str, Any]): # Walk through all related PackageDependencies and produce # the appropriate dict entries. - depends = package.package_dependencies - for dep in depends: + for dep in package.package_dependencies: if dep.DepTypeID in DEP_TYPES: key = DEP_TYPES.get(dep.DepTypeID) @@ -114,8 +113,7 @@ class RPC: data: Dict[str, Any]): # Walk through all related PackageRelations and produce # the appropriate dict entries. - relations = package.package_relations - for rel in relations: + for rel in package.package_relations: if rel.RelTypeID in REL_TYPES: key = REL_TYPES.get(rel.RelTypeID) diff --git a/test/test_rpc.py b/test/test_rpc.py index 9400ee06..00703c23 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -488,3 +488,11 @@ def test_rpc_ratelimit(getint: mock.MagicMock, pipeline: Pipeline): # The new first request should be good. response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") assert response.status_code == int(HTTPStatus.OK) + + +def test_rpc_etag(): + response1 = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") + response2 = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") + assert response1.headers.get("ETag") is not None + assert response1.headers.get("ETag") != str() + assert response1.headers.get("ETag") == response2.headers.get("ETag") From 9d6dbaf0ecfaf576d0c966ca0c93ba68dbd07544 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Oct 2021 00:36:21 -0700 Subject: [PATCH 1038/1891] feat(rpc): add suggest type handler Signed-off-by: Kevin Morris --- aurweb/rpc.py | 8 ++++++++ test/test_rpc.py | 24 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 87700a2f..5c9df1a7 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -175,6 +175,14 @@ class RPC: models.Package.Name.in_(args)) return [self._get_json_data(pkg) for pkg in packages] + def _handle_suggest_type(self, args: List[str] = []): + arg = args[0] + packages = db.query(models.Package).join(models.PackageBase).filter( + and_(models.PackageBase.PackagerUID.isnot(None), + models.Package.Name.like(f"%{arg}%")) + ).order_by(models.Package.Name.asc()).limit(20) + return [pkg.Name for pkg in packages] + def _handle_suggest_pkgbase_type(self, args: List[str] = []): records = db.query(models.PackageBase).filter( and_(models.PackageBase.PackagerUID.isnot(None), diff --git a/test/test_rpc.py b/test/test_rpc.py index 00703c23..71c7397f 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -98,6 +98,17 @@ def setup(): Maintainer=user1, Packager=user1) + pkgbase4 = create(PackageBase, Name="fugly-chungus", + Maintainer=user1, + Packager=user1) + + desc = "A Package belonging to a PackageBase with another name." + create(Package, + PackageBase=pkgbase4, + Name="other-pkg", + Description=desc, + URL="https://example.com") + create(Package, PackageBase=pkgbase3, Name=pkgbase3.Name, @@ -451,8 +462,19 @@ def test_rpc_suggest_pkgbase(): assert data == ["chungy-chungus"] +def test_rpc_suggest(): + response = make_request("/rpc?v=5&type=suggest&arg=other") + data = response.json() + assert data == ["other-pkg"] + + # Test non-existent Package. + response = make_request("/rpc?v=5&type=suggest&arg=nonexistent") + data = response.json() + assert data == [] + + def test_rpc_unimplemented_types(): - unimplemented = ["search", "msearch", "suggest"] + unimplemented = ["search", "msearch"] for type in unimplemented: response = make_request(f"/rpc?v=5&type={type}&arg=big") data = response.json() From c28f1695edb6d94c038363648c99768e23d7fcf5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Oct 2021 16:22:54 -0700 Subject: [PATCH 1039/1891] fix(fastapi): support `by` maintainer search with no keywords In this case, package search should return orphaned packages. Signed-off-by: Kevin Morris --- aurweb/packages/search.py | 10 +++++++--- test/test_packages_routes.py | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index e4729d89..0319a2ba 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -90,9 +90,13 @@ class PackageSearch: return self def _search_by_maintainer(self, keywords: str) -> orm.Query: - self.query = self.query.join( - models.User, models.User.ID == models.PackageBase.MaintainerUID - ).filter(models.User.Username == keywords) + if keywords: + self.query = self.query.join( + models.User, models.User.ID == models.PackageBase.MaintainerUID + ).filter(models.User.Username == keywords) + else: + self.query = self.query.filter( + models.PackageBase.MaintainerUID.is_(None)) return self def _search_by_comaintainer(self, keywords: str) -> orm.Query: diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 207be379..c4d9ab1c 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -623,13 +623,36 @@ def test_packages_search_by_keywords(client: TestClient, def test_packages_search_by_maintainer(client: TestClient, maintainer: User, package: Package): + # We should expect that searching by `package`'s maintainer + # returns `package` in the results. with client as request: response = request.get("/packages", params={ "SeB": "m", "K": maintainer.Username }) assert response.status_code == int(HTTPStatus.OK) + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + # Search again by maintainer with no keywords given. + # This kind of search returns all orphans instead. + # In this first case, there are no orphan packages; assert that. + with client as request: + response = request.get("/packages", params={"SeB": "m"}) + assert response.status_code == int(HTTPStatus.OK) + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 0 + + # Orphan `package`. + with db.begin(): + package.PackageBase.Maintainer = None + + # This time, we should get `package` returned, since it's now an orphan. + with client as request: + response = request.get("/packages", params={"SeB": "m"}) + assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') assert len(rows) == 1 From af2f3694e7fa59f06ebe1af22ac6592b513ef42f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Oct 2021 16:39:20 -0700 Subject: [PATCH 1040/1891] feat(rpc): add search type handler This commit introduces a PackageSearch-derivative class: `RPCSearch`. This derivative modifies callback behavior of PackageSearch to suit RPC searches, including [make|check|opt]depends `by` types. Signed-off-by: Kevin Morris --- aurweb/defaults.py | 3 + aurweb/packages/search.py | 118 ++++++++++++++++++++++++++++++++------ aurweb/routers/rpc.py | 12 ++-- aurweb/rpc.py | 75 +++++++++++++++++++----- test/test_rpc.py | 74 +++++++++++++++++++++++- 5 files changed, 245 insertions(+), 37 deletions(-) diff --git a/aurweb/defaults.py b/aurweb/defaults.py index c2568d05..51072e8f 100644 --- a/aurweb/defaults.py +++ b/aurweb/defaults.py @@ -9,6 +9,9 @@ PP = 50 # A whitelist of valid PP values PP_WHITELIST = {50, 100, 250} +# Default `by` parameter for RPC search. +RPC_SEARCH_BY = "name-desc" + def fallback_pp(per_page: int) -> int: """ If `per_page` is a valid value in PP_WHITELIST, return it. diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 0319a2ba..a14fe19b 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -1,6 +1,7 @@ from sqlalchemy import and_, case, or_, orm -from aurweb import config, db, models +from aurweb import config, db, models, util +from aurweb.models.dependency_type import CHECKDEPENDS_ID, DEPENDS_ID, MAKEDEPENDS_ID, OPTDEPENDS_ID DEFAULT_MAX_RESULTS = 2500 @@ -11,24 +12,25 @@ class PackageSearch: # A constant mapping of short to full name sort orderings. FULL_SORT_ORDER = {"d": "desc", "a": "asc"} - def __init__(self, user: models.User): - """ Construct an instance of PackageSearch. - - This constructors performs several steps during initialization: - 1. Setup self.query: an ORM query of Package joined by PackageBase. - """ + def __init__(self, user: models.User = None): self.user = user - self.query = db.query(models.Package).join(models.PackageBase).join( - models.PackageVote, - and_(models.PackageVote.PackageBaseID == models.PackageBase.ID, - models.PackageVote.UsersID == self.user.ID), - isouter=True - ).join( - models.PackageNotification, - and_(models.PackageNotification.PackageBaseID == models.PackageBase.ID, - models.PackageNotification.UserID == self.user.ID), - isouter=True - ) + self.query = db.query(models.Package).join(models.PackageBase) + + if self.user: + PackageVote = models.PackageVote + join_vote_on = and_( + PackageVote.PackageBaseID == models.PackageBase.ID, + PackageVote.UsersID == self.user.ID) + + PackageNotification = models.PackageNotification + join_notif_on = and_( + PackageNotification.PackageBaseID == models.PackageBase.ID, + PackageNotification.UserID == self.user.ID) + + self.query = self.query.join( + models.PackageVote, join_vote_on, isouter=True + ).join(models.PackageNotification, join_notif_on, isouter=True) + self.ordering = "d" # Setup SeB (Search By) callbacks. @@ -198,3 +200,83 @@ class PackageSearch: # Return the query to the user. return self.query + + +class RPCSearch(PackageSearch): + """ A PackageSearch-derived RPC package search query builder. + + With RPC search, we need a subset of PackageSearch's handlers, + with a few additional handlers added. So, within the RPCSearch + constructor, we pop unneeded keys out of inherited self.search_by_cb + and add a few more keys to it, namely: depends, makedepends, + optdepends and checkdepends. + + Additionally, some logic within the inherited PackageSearch.search_by + method is not needed, so it is overridden in this class without + sanitization done for the PackageSearch `by` argument. + """ + + keys_removed = ("b", "N", "B", "k", "c", "M", "s") + + def __init__(self) -> "RPCSearch": + super().__init__() + + # Fix-up inherited search_by_cb to reflect RPC-specific by params. + # We keep: "nd", "n" and "m". We also overlay four new by params + # on top: "depends", "makedepends", "optdepends" and "checkdepends". + util.apply_all(RPCSearch.keys_removed, + lambda k: self.search_by_cb.pop(k)) + self.search_by_cb.update({ + "depends": self._search_by_depends, + "makedepends": self._search_by_makedepends, + "optdepends": self._search_by_optdepends, + "checkdepends": self._search_by_checkdepends + }) + + def _join_depends(self, dep_type_id: int) -> orm.Query: + """ Join Package with PackageDependency and filter results + based on `dep_type_id`. + + :param dep_type_id: DependencyType ID + :returns: PackageDependency-joined orm.Query + """ + self.query = self.query.join(models.PackageDependency).filter( + models.PackageDependency.DepTypeID == dep_type_id) + return self.query + + def _search_by_depends(self, keywords: str) -> "RPCSearch": + self.query = self._join_depends(DEPENDS_ID).filter( + models.PackageDependency.DepName == keywords) + return self + + def _search_by_makedepends(self, keywords: str) -> "RPCSearch": + self.query = self._join_depends(MAKEDEPENDS_ID).filter( + models.PackageDependency.DepName == keywords) + return self + + def _search_by_optdepends(self, keywords: str) -> "RPCSearch": + self.query = self._join_depends(OPTDEPENDS_ID).filter( + models.PackageDependency.DepName == keywords) + return self + + def _search_by_checkdepends(self, keywords: str) -> "RPCSearch": + self.query = self._join_depends(CHECKDEPENDS_ID).filter( + models.PackageDependency.DepName == keywords) + return self + + def search_by(self, by: str, keywords: str) -> "RPCSearch": + """ Override inherited search_by. In this override, we reduce the + scope of what we handle within this function. We do not set `by` + to a default of "nd" in the RPC, as the RPC returns an error when + incorrect `by` fields are specified. + + :param by: RPC `by` argument + :param keywords: RPC `arg` argument + :returns: self + """ + callback = self.search_by_cb.get(by) + result = callback(keywords) + return result + + def results(self) -> orm.Query: + return self.query diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 0c52404c..6d3dce54 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -9,6 +9,7 @@ import orjson from fastapi import APIRouter, Query, Request, Response from fastapi.responses import JSONResponse +from aurweb import defaults from aurweb.ratelimit import check_ratelimit from aurweb.rpc import RPC @@ -62,10 +63,11 @@ def parse_args(request: Request): @router.get("/rpc") async def rpc(request: Request, - v: Optional[int] = Query(None), - type: Optional[str] = Query(None), - arg: Optional[str] = Query(None), - args: Optional[List[str]] = Query(None, alias="arg[]")): + v: Optional[int] = Query(default=None), + type: Optional[str] = Query(default=None), + by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), + arg: Optional[str] = Query(default=None), + args: Optional[List[str]] = Query(default=[], alias="arg[]")): # Create a handle to our RPC class. rpc = RPC(version=v, type=type) @@ -78,7 +80,7 @@ async def rpc(request: Request, # Prepare list of arguments for input. If 'arg' was given, it'll # be a list with one element. arguments = parse_args(request) - data = rpc.handle(arguments) + data = rpc.handle(by=by, args=arguments) # Serialize `data` into JSON in a sorted fashion. This way, our # ETag header produced below will never end up changed. diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 5c9df1a7..009b1440 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -5,8 +5,9 @@ from sqlalchemy import and_ import aurweb.config as config -from aurweb import db, models, util +from aurweb import db, defaults, models, util from aurweb.models import dependency_type, relation_type +from aurweb.packages.search import RPCSearch # Define dependency type mappings from ID to RPC-compatible keys. DEP_TYPES = { @@ -60,8 +61,16 @@ class RPC: "suggest", "suggest-pkgbase" } - # A mapping of aliases. - ALIASES = {"info": "multiinfo"} + # A mapping of type aliases. + TYPE_ALIASES = {"info": "multiinfo"} + + EXPOSED_BYS = { + "name-desc", "name", "maintainer", + "depends", "makedepends", "optdepends", "checkdepends" + } + + # A mapping of by aliases. + BY_ALIASES = {"name-desc": "nd", "name": "n", "maintainer": "m"} def __init__(self, version: int = 0, type: str = None): self.version = version @@ -76,14 +85,17 @@ class RPC: "error": message } - def _verify_inputs(self, args: List[str] = []): + def _verify_inputs(self, by: str = [], args: List[str] = []): if self.version is None: raise RPCError("Please specify an API version.") if self.version not in RPC.EXPOSED_VERSIONS: raise RPCError("Invalid version specified.") - if self.type is None or not len(args): + if by not in RPC.EXPOSED_BYS: + raise RPCError("Incorrect by field specified.") + + if self.type is None: raise RPCError("No request type/data specified.") if self.type not in RPC.EXPOSED_TYPES: @@ -95,6 +107,10 @@ class RPC: raise RPCError( f"Request type '{self.type}' is not yet implemented.") + def _enforce_args(self, args: List[str]): + if not args: + raise RPCError("No request type/data specified.") + def _update_json_depends(self, package: models.Package, data: Dict[str, Any]): # Walk through all related PackageDependencies and produce @@ -169,13 +185,36 @@ class RPC: self._update_json_relations(package, data) return data - def _handle_multiinfo_type(self, args: List[str] = []): + def _handle_multiinfo_type(self, args: List[str] = [], **kwargs): + self._enforce_args(args) args = set(args) packages = db.query(models.Package).filter( models.Package.Name.in_(args)) return [self._get_json_data(pkg) for pkg in packages] - def _handle_suggest_type(self, args: List[str] = []): + def _handle_search_type(self, by: str = defaults.RPC_SEARCH_BY, + args: List[str] = []): + # If `by` isn't maintainer and we don't have any args, raise an error. + # In maintainer's case, return all orphans if there are no args, + # so we need args to pass through to the handler without errors. + if by != "m" and not len(args): + raise RPCError("No request type/data specified.") + + arg = args[0] + if len(arg) < 2: + raise RPCError("Query arg too small.") + + search = RPCSearch() + search.search_by(by, arg) + + max_results = config.getint("options", "max_rpc_results") + results = search.results().limit(max_results) + return [self._get_json_data(pkg) for pkg in results] + + def _handle_suggest_type(self, args: List[str] = [], **kwargs): + if not args: + return [] + arg = args[0] packages = db.query(models.Package).join(models.PackageBase).filter( and_(models.PackageBase.PackagerUID.isnot(None), @@ -183,14 +222,17 @@ class RPC: ).order_by(models.Package.Name.asc()).limit(20) return [pkg.Name for pkg in packages] - def _handle_suggest_pkgbase_type(self, args: List[str] = []): + def _handle_suggest_pkgbase_type(self, args: List[str] = [], **kwargs): + if not args: + return [] + records = db.query(models.PackageBase).filter( and_(models.PackageBase.PackagerUID.isnot(None), models.PackageBase.Name.like(f"%{args[0]}%")) ).order_by(models.PackageBase.Name.asc()).limit(20) return [record.Name for record in records] - def handle(self, args: List[str] = []): + def handle(self, by: str = defaults.RPC_SEARCH_BY, args: List[str] = []): """ Request entrypoint. A router should pass v, type and args to this function and expect an output dictionary to be returned. @@ -199,22 +241,29 @@ class RPC: :param args: Deciphered list of arguments based on arg/arg[] inputs """ # Convert type aliased types. - if self.type in RPC.ALIASES: - self.type = RPC.ALIASES.get(self.type) + if self.type in RPC.TYPE_ALIASES: + self.type = RPC.TYPE_ALIASES.get(self.type) # Prepare our output data dictionary with some basic keys. data = {"version": self.version, "type": self.type} # Run some verification on our given arguments. try: - self._verify_inputs(args) + self._verify_inputs(by=by, args=args) except RPCError as exc: return self.error(str(exc)) + # Convert by to its aliased value if it has one. + if by in RPC.BY_ALIASES: + by = RPC.BY_ALIASES.get(by) + # Get a handle to our callback and trap an RPCError with # an empty list of results based on callback's execution. callback = getattr(self, f"_handle_{self.type.replace('-', '_')}_type") - results = callback(args) + try: + results = callback(by=by, args=args) + except RPCError as exc: + return self.error(str(exc)) # These types are special: we produce a different kind of # successful JSON output: a list of results. diff --git a/test/test_rpc.py b/test/test_rpc.py index 71c7397f..38b81226 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -461,6 +461,11 @@ def test_rpc_suggest_pkgbase(): data = response.json() assert data == ["chungy-chungus"] + # Test no arg supplied. + response = make_request("/rpc?v=5&type=suggest-pkgbase") + data = response.json() + assert data == [] + def test_rpc_suggest(): response = make_request("/rpc?v=5&type=suggest&arg=other") @@ -472,9 +477,14 @@ def test_rpc_suggest(): data = response.json() assert data == [] + # Test no arg supplied. + response = make_request("/rpc?v=5&type=suggest") + data = response.json() + assert data == [] + def test_rpc_unimplemented_types(): - unimplemented = ["search", "msearch"] + unimplemented = ["msearch"] for type in unimplemented: response = make_request(f"/rpc?v=5&type={type}&arg=big") data = response.json() @@ -518,3 +528,65 @@ def test_rpc_etag(): assert response1.headers.get("ETag") is not None assert response1.headers.get("ETag") != str() assert response1.headers.get("ETag") == response2.headers.get("ETag") + + +def test_rpc_search_arg_too_small(): + response = make_request("/rpc?v=5&type=search&arg=b") + assert response.status_code == int(HTTPStatus.OK) + assert response.json().get("error") == "Query arg too small." + + +def test_rpc_search(): + response = make_request("/rpc?v=5&type=search&arg=big") + assert response.status_code == int(HTTPStatus.OK) + + data = response.json() + assert data.get("resultcount") == 1 + + result = data.get("results")[0] + assert result.get("Name") == "big-chungus" + + # No args on non-m by types return an error. + response = make_request("/rpc?v=5&type=search") + assert response.json().get("error") == "No request type/data specified." + + +def test_rpc_search_depends(): + response = make_request( + "/rpc?v=5&type=search&by=depends&arg=chungus-depends") + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == "big-chungus" + + +def test_rpc_search_makedepends(): + response = make_request( + "/rpc?v=5&type=search&by=makedepends&arg=chungus-makedepends") + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == "big-chungus" + + +def test_rpc_search_optdepends(): + response = make_request( + "/rpc?v=5&type=search&by=optdepends&arg=chungus-optdepends") + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == "big-chungus" + + +def test_rpc_search_checkdepends(): + response = make_request( + "/rpc?v=5&type=search&by=checkdepends&arg=chungus-checkdepends") + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == "big-chungus" + + +def test_rpc_incorrect_by(): + response = make_request("/rpc?v=5&type=search&by=fake&arg=big") + assert response.json().get("error") == "Incorrect by field specified." From 9fef8b06114e011cedab7c25fc6d44f9de99b2ab Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Oct 2021 22:53:30 -0700 Subject: [PATCH 1041/1891] fix(rpc): fix search arg check When by == 'maintainer', we allow an unspecified keyword, resulting in a search of orphan packages. Fix our search check so that when no arg is given, it is set to an empty str(). We already check for valid args when type is not maintainer, so there's no need to worry about other args falling through. Signed-off-by: Kevin Morris --- aurweb/rpc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 009b1440..16985f37 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -200,8 +200,8 @@ class RPC: if by != "m" and not len(args): raise RPCError("No request type/data specified.") - arg = args[0] - if len(arg) < 2: + arg = args[0] if args else str() + if by != "m" and len(arg) < 2: raise RPCError("Query arg too small.") search = RPCSearch() From 05e6cfca62162ffa5ca7e524f08810bc4d0df42a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 30 Oct 2021 22:56:18 -0700 Subject: [PATCH 1042/1891] feat(rpc): add msearch type handler Signed-off-by: Kevin Morris --- aurweb/rpc.py | 9 +++------ test/test_rpc.py | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 16985f37..56f75391 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -101,12 +101,6 @@ class RPC: if self.type not in RPC.EXPOSED_TYPES: raise RPCError("Incorrect request type specified.") - try: - getattr(self, f"_handle_{self.type.replace('-', '_')}_type") - except AttributeError: - raise RPCError( - f"Request type '{self.type}' is not yet implemented.") - def _enforce_args(self, args: List[str]): if not args: raise RPCError("No request type/data specified.") @@ -211,6 +205,9 @@ class RPC: results = search.results().limit(max_results) return [self._get_json_data(pkg) for pkg in results] + def _handle_msearch_type(self, args: List[str] = [], **kwargs): + return self._handle_search_type(by="m", args=args) + def _handle_suggest_type(self, args: List[str] = [], **kwargs): if not args: return [] diff --git a/test/test_rpc.py b/test/test_rpc.py index 38b81226..0636c792 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -483,15 +483,6 @@ def test_rpc_suggest(): assert data == [] -def test_rpc_unimplemented_types(): - unimplemented = ["msearch"] - for type in unimplemented: - response = make_request(f"/rpc?v=5&type={type}&arg=big") - data = response.json() - expected = f"Request type '{type}' is not yet implemented." - assert data.get("error") == expected - - def mock_config_getint(section: str, key: str): if key == "request_limit": return 4 @@ -551,6 +542,35 @@ def test_rpc_search(): assert response.json().get("error") == "No request type/data specified." +def test_rpc_msearch(): + response = make_request("/rpc?v=5&type=msearch&arg=user1") + data = response.json() + + # user1 maintains 4 packages; assert that we got them all. + assert data.get("resultcount") == 4 + names = list(sorted(r.get("Name") for r in data.get("results"))) + expected_results = list(sorted([ + "big-chungus", + "chungy-chungus", + "gluggly-chungus", + "other-pkg" + ])) + assert names == expected_results + + # Search for a non-existent maintainer, giving us zero packages. + response = make_request("/rpc?v=5&type=msearch&arg=blah-blah") + data = response.json() + assert data.get("resultcount") == 0 + + # A missing arg still succeeds, but it returns all orphans. + # Just verify that we receive no error and the orphaned result. + response = make_request("/rpc?v=5&type=msearch") + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == "woogly-chungus" + + def test_rpc_search_depends(): response = make_request( "/rpc?v=5&type=search&by=depends&arg=chungus-depends") From 12b4269ba8c1b4dbe9aa55b9e0541db4f0cdac77 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 00:28:55 -0700 Subject: [PATCH 1043/1891] feat(rpc): support jsonp callbacks This change introduces alternate rendering of text/javascript JSONP-compatible callback content. The `examples/jsonp.html` HTML document can be used to test this functionality against a running aurweb server. Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 26 +++++++++++---- examples/jsonp.html | 74 +++++++++++++++++++++++++++++++++++++++++++ test/test_rpc.py | 14 ++++++++ 3 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 examples/jsonp.html diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 6d3dce54..175e5f0f 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -67,7 +67,8 @@ async def rpc(request: Request, type: Optional[str] = Query(default=None), by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), arg: Optional[str] = Query(default=None), - args: Optional[List[str]] = Query(default=[], alias="arg[]")): + args: Optional[List[str]] = Query(default=[], alias="arg[]"), + callback: Optional[str] = Query(default=None)): # Create a handle to our RPC class. rpc = RPC(version=v, type=type) @@ -84,17 +85,28 @@ async def rpc(request: Request, # Serialize `data` into JSON in a sorted fashion. This way, our # ETag header produced below will never end up changed. - output = orjson.dumps(data, option=orjson.OPT_SORT_KEYS) + content = orjson.dumps(data, option=orjson.OPT_SORT_KEYS) # Produce an md5 hash based on `output`. md5 = hashlib.md5() - md5.update(output) + md5.update(content) etag = md5.hexdigest() - # Finally, return our JSONResponse with the ETag header. + # If `callback` was provided, produce a text/javascript response + # valid for the jsonp callback. Otherwise, by default, return + # application/json containing `output`. + # Note: Being the API hot path, `content` is not defaulted to + # avoid copying the JSON string in the case callback is provided. + content_type = "application/json" + if callback: + print("callback called") + content_type = "text/javascript" + content = f"/**/{callback}({content.decode()})" + # The ETag header expects quotes to surround any identifier. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag - return Response(output.decode(), headers={ - "Content-Type": "application/json", + headers = { + "Content-Type": content_type, "ETag": f'"{etag}"' - }) + } + return Response(content, headers=headers) diff --git a/examples/jsonp.html b/examples/jsonp.html new file mode 100644 index 00000000..d73ec91e --- /dev/null +++ b/examples/jsonp.html @@ -0,0 +1,74 @@ + + + + + + + + JSONP Callback Test + + + + + +
    +
    +

    + Searching with the following form uses a JSONP callback + to log data out to the javascript console. +

    + +
    + + +
    + +
    + + +
    + +
    + +
    +
    +
    + + diff --git a/test/test_rpc.py b/test/test_rpc.py index 0636c792..acf1ae26 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1,3 +1,5 @@ +import re + from http import HTTPStatus from unittest import mock @@ -610,3 +612,15 @@ def test_rpc_search_checkdepends(): def test_rpc_incorrect_by(): response = make_request("/rpc?v=5&type=search&by=fake&arg=big") assert response.json().get("error") == "Incorrect by field specified." + + +def test_rpc_jsonp_callback(): + """ Test the callback parameter. + + For end-to-end verification, the `examples/jsonp.html` file can be + used to submit jsonp callback requests to the RPC. + """ + response = make_request( + "/rpc?v=5&type=search&arg=big&callback=jsonCallback") + assert response.headers.get("content-type") == "text/javascript" + assert re.search(r'^/\*\*/jsonCallback\(.*\)$', response.text) is not None From 2cc44e8f28275c5ccdefc65e6075bd0bec245026 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 01:17:16 -0700 Subject: [PATCH 1044/1891] fix(rpc): perform regex match against callback name Since we're in the hot path, a constant re.compiled JSONP_EXPR is defined for checks against the callback. Additionally, reorganized `content_type` and `content` to avoid performing a DB query when we encounter a regex mismatch. Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 29 ++++++++++++++++++----------- test/test_rpc.py | 6 ++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 175e5f0f..6abd73d9 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -1,4 +1,5 @@ import hashlib +import re from http import HTTPStatus from typing import List, Optional @@ -61,6 +62,9 @@ def parse_args(request: Request): return args +JSONP_EXPR = re.compile(r'^[a-zA-Z0-9()_.]{1,128}$') + + @router.get("/rpc") async def rpc(request: Request, v: Optional[int] = Query(default=None), @@ -78,6 +82,16 @@ async def rpc(request: Request, return JSONResponse(rpc.error("Rate limit reached"), status_code=int(HTTPStatus.TOO_MANY_REQUESTS)) + # If `callback` was provided, produce a text/javascript response + # valid for the jsonp callback. Otherwise, by default, return + # application/json containing `output`. + content_type = "application/json" + if callback: + if not re.match(JSONP_EXPR, callback): + return rpc.error("Invalid callback name.") + + content_type = "text/javascript" + # Prepare list of arguments for input. If 'arg' was given, it'll # be a list with one element. arguments = parse_args(request) @@ -92,21 +106,14 @@ async def rpc(request: Request, md5.update(content) etag = md5.hexdigest() - # If `callback` was provided, produce a text/javascript response - # valid for the jsonp callback. Otherwise, by default, return - # application/json containing `output`. - # Note: Being the API hot path, `content` is not defaulted to - # avoid copying the JSON string in the case callback is provided. - content_type = "application/json" - if callback: - print("callback called") - content_type = "text/javascript" - content = f"/**/{callback}({content.decode()})" - # The ETag header expects quotes to surround any identifier. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag headers = { "Content-Type": content_type, "ETag": f'"{etag}"' } + + if callback: + content = f"/**/{callback}({content.decode()})" + return Response(content, headers=headers) diff --git a/test/test_rpc.py b/test/test_rpc.py index acf1ae26..f4ce6de8 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -624,3 +624,9 @@ def test_rpc_jsonp_callback(): "/rpc?v=5&type=search&arg=big&callback=jsonCallback") assert response.headers.get("content-type") == "text/javascript" assert re.search(r'^/\*\*/jsonCallback\(.*\)$', response.text) is not None + + # Test an invalid callback name; we get an application/json error. + response = make_request( + "/rpc?v=5&type=search&arg=big&callback=jsonCallback!") + assert response.headers.get("content-type") == "application/json" + assert response.json().get("error") == "Invalid callback name." From 61f3cb938ce601900aba70a1e73bf454689fa156 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 01:22:54 -0700 Subject: [PATCH 1045/1891] feat(rpc): support the If-None-Match request header If the If-None-Match header is supplied with a previously obtained ETag from the same query, a 304 Not Modified is returned with no content. This allows clients to completely leverage the ETag header. Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 5 +++++ test/test_rpc.py | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 6abd73d9..66376067 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -113,6 +113,11 @@ async def rpc(request: Request, "ETag": f'"{etag}"' } + if_none_match = request.headers.get("If-None-Match", str()) + if if_none_match and if_none_match.strip("\t\n\r\" ") == etag: + return Response(headers=headers, + status_code=int(HTTPStatus.NOT_MODIFIED)) + if callback: content = f"/**/{callback}({content.decode()})" diff --git a/test/test_rpc.py b/test/test_rpc.py index f4ce6de8..055baa33 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1,6 +1,7 @@ import re from http import HTTPStatus +from typing import Dict from unittest import mock import orjson @@ -28,9 +29,9 @@ from aurweb.redis import redis_connection from aurweb.testing import setup_test_db -def make_request(path): +def make_request(path, headers: Dict[str, str] = {}): with TestClient(app) as request: - return request.get(path) + return request.get(path, headers=headers) @pytest.fixture(autouse=True) @@ -539,6 +540,13 @@ def test_rpc_search(): result = data.get("results")[0] assert result.get("Name") == "big-chungus" + # Test the If-None-Match headers. + etag = response.headers.get("ETag").strip('"') + headers = {"If-None-Match": etag} + response = make_request("/rpc?v=5&type=search&arg=big", headers=headers) + assert response.status_code == int(HTTPStatus.NOT_MODIFIED) + assert response.content == b'' + # No args on non-m by types return an error. response = make_request("/rpc?v=5&type=search") assert response.json().get("error") == "No request type/data specified." From b7475a5bd0607200afae508729c53b95c2b40c6c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 04:11:42 -0700 Subject: [PATCH 1046/1891] fix(rpc): fix performance of suggest[-pkgbase] We were selecting the entire record; we should just select the Name column as done in this commit. Signed-off-by: Kevin Morris --- aurweb/rpc.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 56f75391..ca838050 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -213,7 +213,9 @@ class RPC: return [] arg = args[0] - packages = db.query(models.Package).join(models.PackageBase).filter( + packages = db.query(models.Package.Name).join( + models.PackageBase + ).filter( and_(models.PackageBase.PackagerUID.isnot(None), models.Package.Name.like(f"%{arg}%")) ).order_by(models.Package.Name.asc()).limit(20) @@ -223,11 +225,11 @@ class RPC: if not args: return [] - records = db.query(models.PackageBase).filter( + packages = db.query(models.PackageBase.Name).filter( and_(models.PackageBase.PackagerUID.isnot(None), models.PackageBase.Name.like(f"%{args[0]}%")) ).order_by(models.PackageBase.Name.asc()).limit(20) - return [record.Name for record in records] + return [pkg.Name for pkg in packages] def handle(self, by: str = defaults.RPC_SEARCH_BY, args: List[str] = []): """ Request entrypoint. A router should pass v, type and args From cef69b634233b54642c54350d89b6831605f2e81 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 15:47:39 -0700 Subject: [PATCH 1047/1891] fix(gitlab-ci): prune dangling images and build cache Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 156f0abf..e18df8ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -65,6 +65,7 @@ deploy: # Set secure login config for aurweb. - sed -ri "s/^(disable_http_login).*$/\1 = 1/" conf/config.dev - docker-compose build + - docker system prune -f - docker-compose -f docker-compose.yml -f docker-compose.aur-dev.yml up -d environment: name: development From f26cd1e9941d2ac3ffbd852c504251ce2f0d3c40 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 16:13:01 -0700 Subject: [PATCH 1048/1891] fix(gitlab-ci): add `docker` dep to deploy target Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e18df8ee..1590bf34 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,7 +58,7 @@ deploy: COMMIT_HASH: $CI_COMMIT_SHA GIT_DATA_DIR: git_data script: - - pacman -Syu --noconfirm docker-compose socat openssh + - pacman -Syu --noconfirm docker docker-compose socat openssh - chmod 600 ${SSH_KEY} - socat "UNIX-LISTEN:/tmp/docker.sock,reuseaddr,fork" EXEC:"ssh -o UserKnownHostsFile=${SSH_KNOWN_HOSTS} -Ti ${SSH_KEY} ${SSH_USER}@${SSH_HOST}" & - export DOCKER_HOST="unix:///tmp/docker.sock" From 451eec0c28113425c951861f70ba1fd55ecabf87 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 15:45:41 -0700 Subject: [PATCH 1049/1891] fix(fastapi): remove info-specific fields from search results Signed-off-by: Kevin Morris --- aurweb/rpc.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index ca838050..4ab005af 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -162,7 +162,20 @@ class RPC: "Popularity": pop, "OutOfDate": package.PackageBase.OutOfDateTS, "FirstSubmitted": package.PackageBase.SubmittedTS, - "LastModified": package.PackageBase.ModifiedTS, + "LastModified": package.PackageBase.ModifiedTS + }) + + if package.PackageBase.Maintainer is not None: + # We do have a maintainer: set the Maintainer key. + data["Maintainer"] = package.PackageBase.Maintainer.Username + + return data + + def _get_info_json_data(self, package: models.Package): + data = self._get_json_data(package) + + # Add licenses and keywords to info output. + data.update({ "License": [ lic.License.Name for lic in package.package_licenses ], @@ -171,10 +184,6 @@ class RPC: ] }) - if package.PackageBase.Maintainer is not None: - # We do have a maintainer: set the Maintainer key. - data["Maintainer"] = package.PackageBase.Maintainer.Username - self._update_json_depends(package, data) self._update_json_relations(package, data) return data @@ -184,7 +193,7 @@ class RPC: args = set(args) packages = db.query(models.Package).filter( models.Package.Name.in_(args)) - return [self._get_json_data(pkg) for pkg in packages] + return [self._get_info_json_data(pkg) for pkg in packages] def _handle_search_type(self, by: str = defaults.RPC_SEARCH_BY, args: List[str] = []): From a82879210c9dd04c511a5521d0cd163971db9838 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 19:56:56 -0700 Subject: [PATCH 1050/1891] fix(poetry): add mysql-connector dep This is not used anymore in our FastAPI code, however, for back-compatibility with pre-FastAPI scripts, we need it. Signed-off-by: Kevin Morris --- poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index eefec89b..4f41307d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -518,6 +518,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "mysql-connector" +version = "2.2.9" +description = "MySQL driver written in Python" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "mysqlclient" version = "2.0.3" @@ -962,7 +970,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "eb5ec82957f9fb964ca6f3852e353da51542982923dc6169658bd4bccfa78513" +content-hash = "6a45364297f5a6e88ee62240bb2eb1eaf3b41283b6d8f040ee67db02601f18e7" [metadata.files] aiofiles = [ @@ -1380,6 +1388,9 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +mysql-connector = [ + {file = "mysql-connector-2.2.9.tar.gz", hash = "sha256:1733e6ce52a049243de3264f1fbc22a852cb35458c4ad739ba88189285efdf32"}, +] mysqlclient = [ {file = "mysqlclient-2.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3"}, {file = "mysqlclient-2.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7"}, diff --git a/pyproject.toml b/pyproject.toml index 12812bc8..2f327318 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,6 +82,7 @@ SQLAlchemy = "^1.4.26" uvicorn = "^0.15.0" gunicorn = "^20.1.0" Hypercorn = "^0.11.2" +mysql-connector = "^2.2.9" [tool.poetry.dev-dependencies] flake8 = "^4.0.1" From cc45290ec274530d66d77bad5692576876b35446 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 1 Nov 2021 11:41:20 -0700 Subject: [PATCH 1051/1891] feat(poetry): add prometheus-fastapi-instrumentator Signed-off-by: Kevin Morris --- poetry.lock | 33 ++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 4f41307d..9f528d12 100644 --- a/poetry.lock +++ b/poetry.lock @@ -594,6 +594,29 @@ category = "main" optional = false python-versions = ">=3.6.1" +[[package]] +name = "prometheus-client" +version = "0.12.0" +description = "Python client for the Prometheus monitoring system." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +twisted = ["twisted"] + +[[package]] +name = "prometheus-fastapi-instrumentator" +version = "5.7.1" +description = "Instrument your FastAPI with Prometheus metrics" +category = "main" +optional = false +python-versions = ">=3.6.0,<4.0.0" + +[package.dependencies] +fastapi = ">=0.38.1,<1.0.0" +prometheus-client = ">=0.8.0,<1.0.0" + [[package]] name = "protobuf" version = "3.19.0" @@ -970,7 +993,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "6a45364297f5a6e88ee62240bb2eb1eaf3b41283b6d8f040ee67db02601f18e7" +content-hash = "569b0489389b884d269458f8e4252efcf3ebbbaa5fa77b6d09d7f0cdbda53362" [metadata.files] aiofiles = [ @@ -1440,6 +1463,14 @@ priority = [ {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, ] +prometheus-client = [ + {file = "prometheus_client-0.12.0-py2.py3-none-any.whl", hash = "sha256:317453ebabff0a1b02df7f708efbab21e3489e7072b61cb6957230dd004a0af0"}, + {file = "prometheus_client-0.12.0.tar.gz", hash = "sha256:1b12ba48cee33b9b0b9de64a1047cbd3c5f2d0ab6ebcead7ddda613a750ec3c5"}, +] +prometheus-fastapi-instrumentator = [ + {file = "prometheus-fastapi-instrumentator-5.7.1.tar.gz", hash = "sha256:5371f1b494e2b00017a02898d854119b4929025d1a203670b07b3f42dd0b5526"}, + {file = "prometheus_fastapi_instrumentator-5.7.1-py3-none-any.whl", hash = "sha256:da40ea0df14b0e95d584769747fba777522a8df6a8c47cec2edf798f1fff49b5"}, +] protobuf = [ {file = "protobuf-3.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:01a0645ef3acddfbc90237e1cdfae1086130fc7cb480b5874656193afd657083"}, {file = "protobuf-3.19.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d3861c9721a90ba83ee0936a9cfcc4fa1c4b4144ac9658fb6f6343b38558e9b4"}, diff --git a/pyproject.toml b/pyproject.toml index 2f327318..20855fa6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,6 +83,7 @@ uvicorn = "^0.15.0" gunicorn = "^20.1.0" Hypercorn = "^0.11.2" mysql-connector = "^2.2.9" +prometheus-fastapi-instrumentator = "^5.7.1" [tool.poetry.dev-dependencies] flake8 = "^4.0.1" From f21765bfe467f225825ddeeca48c37dd5220d225 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 02:16:50 -0700 Subject: [PATCH 1052/1891] feat(fastapi): add prometheus /metrics This commit provides custom metrics, so we can group requests into their route paths and not by the arguments given, e.g. /pkgbase/some-package -> /pkgbase/{name}. We also count RPC requests as `http_api_requests_total`, split by the RPC query "type" argument. - `http_api_requests_total` - Labels: ["type", "status"] - `http_requests_total` - Number of HTTP requests in total. - Labels: ["method", "path", "status"] Signed-off-by: Kevin Morris --- LICENSES/starlette_exporter | 201 ++++++++++++++++++++++++++++++++++++ aurweb/asgi.py | 8 ++ aurweb/prometheus.py | 101 ++++++++++++++++++ 3 files changed, 310 insertions(+) create mode 100644 LICENSES/starlette_exporter create mode 100644 aurweb/prometheus.py diff --git a/LICENSES/starlette_exporter b/LICENSES/starlette_exporter new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSES/starlette_exporter @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 8ebeef29..2ba2afd0 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -19,11 +19,18 @@ import aurweb.logging from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine, query from aurweb.models import AcceptedTerm, Term +from aurweb.prometheus import http_api_requests_total, http_requests_total, instrumentator from aurweb.routers import accounts, auth, errors, html, packages, rpc, rss, sso, trusted_user # Setup the FastAPI app. app = FastAPI(exception_handlers=errors.exceptions) +# Instrument routes with the prometheus-fastapi-instrumentator +# library with custom collectors and expose /metrics. +instrumentator().add(http_api_requests_total()) +instrumentator().add(http_requests_total()) +instrumentator().instrument(app).expose(app) + @app.on_event("startup") async def app_startup(): @@ -67,6 +74,7 @@ async def app_startup(): app.include_router(rss.router) app.include_router(packages.router) app.include_router(rpc.router) + # Initialize the database engine and ORM. get_engine() diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py new file mode 100644 index 00000000..0a3dd173 --- /dev/null +++ b/aurweb/prometheus.py @@ -0,0 +1,101 @@ +from typing import Any, Callable, Dict, List, Optional + +from prometheus_client import Counter +from prometheus_fastapi_instrumentator import Instrumentator +from prometheus_fastapi_instrumentator.metrics import Info +from starlette.routing import Match, Route + +from aurweb import logging + +logger = logging.get_logger(__name__) +_instrumentator = Instrumentator() + + +def instrumentator(): + return _instrumentator + + +# Taken from https://github.com/stephenhillier/starlette_exporter +# Their license is included in LICENSES/starlette_exporter. +# The code has been modified to remove child route checks +# (since we don't have any) and to stay within an 80-width limit. +def get_matching_route_path(scope: Dict[Any, Any], routes: List[Route], + route_name: Optional[str] = None) -> str: + """ + Find a matching route and return its original path string + + Will attempt to enter mounted routes and subrouters. + + Credit to https://github.com/elastic/apm-agent-python + + """ + for route in routes: + match, child_scope = route.matches(scope) + if match == Match.FULL: + route_name = route.path + + ''' + # This path exists in the original function's code, but we + # don't need it (currently), so it's been removed to avoid + # useless test coverage. + child_scope = {**scope, **child_scope} + if isinstance(route, Mount) and route.routes: + child_route_name = get_matching_route_path(child_scope, + route.routes, + route_name) + if child_route_name is None: + route_name = None + else: + route_name += child_route_name + ''' + + return route_name + elif match == Match.PARTIAL and route_name is None: + route_name = route.path + + +def http_requests_total() -> Callable[[Info], None]: + metric = Counter("http_requests_total", + "Number of HTTP requests.", + labelnames=("method", "path", "status")) + + def instrumentation(info: Info) -> None: + scope = info.request.scope + + # Taken from https://github.com/stephenhillier/starlette_exporter + # Their license is included at LICENSES/starlette_exporter. + # The code has been slightly modified: we no longer catch + # exceptions; we expect this collector to always succeed. + # Failures in this collector shall cause test failures. + if not (scope.get("endpoint", None) and scope.get("router", None)): + return None + + base_scope = { + "type": scope.get("type"), + "path": scope.get("root_path", "") + scope.get("path"), + "path_params": scope.get("path_params", {}), + "method": scope.get("method") + } + + method = scope.get("method") + path = get_matching_route_path(base_scope, scope.get("router").routes) + status = str(info.response.status_code)[:1] + "xx" + + metric.labels(method=method, path=path, status=status).inc() + + return instrumentation + + +def http_api_requests_total() -> Callable[[Info], None]: + metric = Counter( + "http_api_requests", + "Number of times an RPC API type has been requested.", + labelnames=("type", "status")) + + def instrumentation(info: Info) -> None: + if info.request.url.path.rstrip("/") == "/rpc": + type = info.request.query_params.get("type", "None") + status = str(info.response.status_code)[:1] + "xx" + metric.labels(type=type, status=status).inc() + + return instrumentation From 1be4ac2fde4f8d867fe476e52332f98ca18341f0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 1 Nov 2021 12:27:33 -0700 Subject: [PATCH 1053/1891] feat(docker): use PROMETHEUS_MULTIPROC_DIR Signed-off-by: Kevin Morris --- docker-compose.aur-dev.yml | 1 + docker-compose.yml | 1 + docker/fastapi-entrypoint.sh | 3 +++ 3 files changed, 5 insertions(+) diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 3f574d42..1db306cc 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -53,6 +53,7 @@ services: - FASTAPI_WORKERS=${FASTAPI_WORKERS} - AURWEB_FASTAPI_PREFIX=${AURWEB_FASTAPI_PREFIX} - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} + - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus volumes: - cache:/cache diff --git a/docker-compose.yml b/docker-compose.yml index 2b25c7d8..6c822e7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -168,6 +168,7 @@ services: - FASTAPI_WORKERS=${FASTAPI_WORKERS} - AURWEB_FASTAPI_PREFIX=${AURWEB_FASTAPI_PREFIX} - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} + - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus entrypoint: /docker/fastapi-entrypoint.sh command: /docker/scripts/run-fastapi.sh "${FASTAPI_BACKEND}" healthcheck: diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index 58fafe56..f4ceaafa 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -18,4 +18,7 @@ fi sed -ri "s|^(git_clone_uri_anon) = .+|\1 = ${AURWEB_FASTAPI_PREFIX}/%s.git|" conf/config.defaults sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ${AURWEB_SSHD_PREFIX}/%s.git|" conf/config.defaults +rm -rf $PROMETHEUS_MULTIPROC_DIR +mkdir -p $PROMETHEUS_MULTIPROC_DIR + exec "$@" From dc397f6bd8d95efcebfa479d897cc00651d3bb20 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 1 Nov 2021 13:17:24 -0700 Subject: [PATCH 1054/1891] fix(fastapi): utilize PROMETHEUS_MULTIPROC_DIR in our own /metrics Signed-off-by: Kevin Morris --- aurweb/asgi.py | 9 ++++++++- aurweb/routers/html.py | 21 +++++++++++++++++++-- test/test_html.py | 7 +++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 2ba2afd0..16de771e 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -9,6 +9,7 @@ from urllib.parse import quote_plus from fastapi import FastAPI, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.staticfiles import StaticFiles +from prometheus_client import multiprocess from sqlalchemy import and_, or_ from starlette.middleware.authentication import AuthenticationMiddleware from starlette.middleware.sessions import SessionMiddleware @@ -29,7 +30,7 @@ app = FastAPI(exception_handlers=errors.exceptions) # library with custom collectors and expose /metrics. instrumentator().add(http_api_requests_total()) instrumentator().add(http_requests_total()) -instrumentator().instrument(app).expose(app) +instrumentator().instrument(app) @app.on_event("startup") @@ -79,6 +80,12 @@ async def app_startup(): get_engine() +def child_exit(server, worker): # pragma: no cover + """ This function is required for gunicorn customization + of prometheus multiprocessing. """ + multiprocess.mark_process_dead(worker.pid) + + @app.exception_handler(HTTPException) async def http_exception_handler(request, exc): """ diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index c749ca67..4cee5f99 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -1,11 +1,14 @@ """ AURWeb's primary routing module. Define all routes via @app.app.{get,post} decorators in some way; more complex routes should be defined in their own modules and imported here. """ +import os + from datetime import datetime from http import HTTPStatus -from fastapi import APIRouter, Form, HTTPException, Request +from fastapi import APIRouter, Form, HTTPException, Request, Response from fastapi.responses import HTMLResponse, RedirectResponse +from prometheus_client import CONTENT_TYPE_LATEST, CollectorRegistry, generate_latest, multiprocess from sqlalchemy import and_, case, or_ import aurweb.config @@ -203,7 +206,21 @@ async def index(request: Request): return render_template(request, "index.html", context) -# A route that returns a error 503. For testing purposes. +@router.get("/metrics") +async def metrics(request: Request): + registry = CollectorRegistry() + if os.environ.get("FASTAPI_BACKEND", "") == "gunicorn": # pragma: no cover + # This case only ever happens in production, when we are running + # gunicorn. We don't test with gunicorn, so we don't cover this path. + multiprocess.MultiProcessCollector(registry) + data = generate_latest(registry) + headers = { + "Content-Type": CONTENT_TYPE_LATEST, + "Content-Length": str(len(data)) + } + return Response(data, headers=headers) + + @router.get("/raisefivethree", response_class=HTMLResponse) async def raise_service_unavailable(request: Request): raise HTTPException(status_code=503) diff --git a/test/test_html.py b/test/test_html.py index 2018840b..8e7cb2d1 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -117,3 +117,10 @@ def test_get_successes(): """ successes = get_successes(html) assert successes[0].text.strip() == "Test" + + +def test_metrics(client: TestClient): + with client as request: + resp = request.get("/metrics") + assert resp.status_code == int(HTTPStatus.OK) + assert resp.headers.get("Content-Type").startswith("text/plain") From cdb854259af49ff759ce1481cd799612cd657bbc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 1 Nov 2021 13:54:58 -0700 Subject: [PATCH 1055/1891] fix(docker): share FASTAPI_BACKEND with the server Signed-off-by: Kevin Morris --- docker-compose.yml | 1 + docker/scripts/run-fastapi.sh | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6c822e7c..5dffe5d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -165,6 +165,7 @@ services: init: true environment: - AUR_CONFIG=conf/config + - FASTAPI_BACKEND=${FASTAPI_BACKEND} - FASTAPI_WORKERS=${FASTAPI_WORKERS} - AURWEB_FASTAPI_PREFIX=${AURWEB_FASTAPI_PREFIX} - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} diff --git a/docker/scripts/run-fastapi.sh b/docker/scripts/run-fastapi.sh index 16ae3cb9..effc7fe4 100755 --- a/docker/scripts/run-fastapi.sh +++ b/docker/scripts/run-fastapi.sh @@ -14,10 +14,12 @@ fi # By default, set FASTAPI_WORKERS to 2. In production, this should # be configured by the deployer. -if [ -z "$FASTAPI_WORKERS" ]; then +if [ -z ${FASTAPI_WORKERS+x} ]; then FASTAPI_WORKERS=2 fi +export FASTAPI_BACKEND="$1" + echo "FASTAPI_BACKEND: $FASTAPI_BACKEND" echo "FASTAPI_WORKERS: $FASTAPI_WORKERS" From 9aa8decf403c618092b00db0f8b76c9917987b6b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 1 Nov 2021 14:18:19 -0700 Subject: [PATCH 1056/1891] fix(fastapi): use metrics in cases where PROMETHEUS_MULTIPROC_DIR is defined Previously, we restricted this to gunicorn to get it working on aur-dev. This change makes it usable through any backend, and also no-op if PROMETHEUS_MULTIPROC_DIR is not defined. Signed-off-by: Kevin Morris --- aurweb/routers/html.py | 4 +--- docker-compose.yml | 3 +++ docker/scripts/run-pytests.sh | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 4cee5f99..525fb626 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -209,9 +209,7 @@ async def index(request: Request): @router.get("/metrics") async def metrics(request: Request): registry = CollectorRegistry() - if os.environ.get("FASTAPI_BACKEND", "") == "gunicorn": # pragma: no cover - # This case only ever happens in production, when we are running - # gunicorn. We don't test with gunicorn, so we don't cover this path. + if os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): # pragma: no cover multiprocess.MultiProcessCollector(registry) data = generate_latest(registry) headers = { diff --git a/docker-compose.yml b/docker-compose.yml index 5dffe5d3..225e5b9b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -241,6 +241,7 @@ services: environment: - AUR_CONFIG=conf/config - TEST_RECURSION_LIMIT=${TEST_RECURSION_LIMIT} + - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus entrypoint: /docker/test-mysql-entrypoint.sh command: /docker/scripts/run-pytests.sh clean stdin_open: true @@ -267,6 +268,7 @@ services: environment: - AUR_CONFIG=conf/config.sqlite - TEST_RECURSION_LIMIT=${TEST_RECURSION_LIMIT} + - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus entrypoint: /docker/test-sqlite-entrypoint.sh command: setup-sqlite.sh run-pytests.sh clean stdin_open: true @@ -289,6 +291,7 @@ services: environment: - AUR_CONFIG=conf/config - TEST_RECURSION_LIMIT=${TEST_RECURSION_LIMIT} + - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus entrypoint: /docker/tests-entrypoint.sh command: setup-sqlite.sh run-tests.sh stdin_open: true diff --git a/docker/scripts/run-pytests.sh b/docker/scripts/run-pytests.sh index d992bf06..ee546fb7 100755 --- a/docker/scripts/run-pytests.sh +++ b/docker/scripts/run-pytests.sh @@ -22,6 +22,9 @@ while [ $# -ne 0 ]; do esac done +rm -rf $PROMETHEUS_MULTIPROC_DIR +mkdir -p $PROMETHEUS_MULTIPROC_DIR + # Initialize the new database; ignore errors. python -m aurweb.initdb 2>/dev/null || \ (echo "Error: aurweb.initdb failed; already initialized?" && /bin/true) From 16e6fa2cdd002fecf6ad5e4251727315d7a3dfc8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 1 Nov 2021 14:23:15 -0700 Subject: [PATCH 1057/1891] fix(fastapi): fix prometheus parsing of HTTPStatus This wasn't actually casting to int. We shouldn't be providing HTTPStatus.CONSTANTS directly anyway, but, in case we do, we now just convert the status to an int before converting it to a string. Signed-off-by: Kevin Morris --- aurweb/prometheus.py | 2 +- aurweb/routers/packages.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index 0a3dd173..a64f6b27 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -79,7 +79,7 @@ def http_requests_total() -> Callable[[Info], None]: method = scope.get("method") path = get_matching_route_path(base_scope, scope.get("router").routes) - status = str(info.response.status_code)[:1] + "xx" + status = str(int(info.response.status_code))[:1] + "xx" metric.labels(method=method, path=path, status=status).inc() diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index c574ec18..bcc0be56 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -269,7 +269,7 @@ async def package_base(request: Request, name: str) -> Response: # If this is not a split package, redirect to /packages/{name}. if pkgbase.packages.count() == 1: return RedirectResponse(f"/packages/{name}", - status_code=HTTPStatus.SEE_OTHER) + status_code=int(HTTPStatus.SEE_OTHER)) # Add our base information. context = await make_single_context(request, pkgbase) From e4a5b7fae968e1d1335b3c03a9b816b2d1b668ae Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 3 Nov 2021 05:39:28 -0700 Subject: [PATCH 1058/1891] fix(docker): use 3s intervals for all healthchecks This'll speed up the docker development and deployment processes significantly. Signed-off-by: Kevin Morris --- docker-compose.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 225e5b9b..038eb65b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,7 +37,8 @@ services: command: /docker/scripts/run-memcached.sh healthcheck: test: "bash /docker/health/memcached.sh" - + interval: 3s + redis: image: aurweb:latest init: true @@ -45,6 +46,7 @@ services: command: /docker/scripts/run-redis.sh healthcheck: test: "bash /docker/health/redis.sh" + interval: 3s ports: - "16379:6379" @@ -62,6 +64,7 @@ services: - mariadb_data:/var/lib/mysql healthcheck: test: "bash /docker/health/mariadb.sh" + interval: 3s mariadb_init: image: aurweb:latest @@ -85,6 +88,7 @@ services: - "2222:2222" healthcheck: test: "bash /docker/health/sshd.sh" + interval: 3s depends_on: mariadb_init: condition: service_started @@ -100,6 +104,7 @@ services: command: /docker/scripts/run-smartgit.sh healthcheck: test: "bash /docker/health/smartgit.sh" + interval: 3s cgit-php: image: aurweb:latest @@ -111,6 +116,7 @@ services: command: /docker/scripts/run-cgit.sh 3000 healthcheck: test: "bash /docker/health/cgit.sh 3000" + interval: 3s depends_on: git: condition: service_healthy @@ -129,6 +135,7 @@ services: command: /docker/scripts/run-cgit.sh 3000 healthcheck: test: "bash /docker/health/cgit.sh 3000" + interval: 3s depends_on: git: condition: service_healthy @@ -148,6 +155,7 @@ services: command: /docker/scripts/run-php.sh healthcheck: test: "bash /docker/health/php.sh" + interval: 3s depends_on: ca: condition: service_started @@ -174,6 +182,7 @@ services: command: /docker/scripts/run-fastapi.sh "${FASTAPI_BACKEND}" healthcheck: test: "bash /docker/health/fastapi.sh ${FASTAPI_BACKEND}" + interval: 3s depends_on: ca: condition: service_started @@ -198,6 +207,7 @@ services: - "8444:8444" # FastAPI healthcheck: test: "bash /docker/health/nginx.sh" + interval: 3s depends_on: cgit-php: condition: service_healthy From 020409ef46452bafb0e1bf0d6a9537912059a6dd Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Mon, 1 Nov 2021 17:18:09 -0400 Subject: [PATCH 1059/1891] fix(FastAPI): prevent CSRF forging login requests Signed-off-by: Steven Guikal --- aurweb/routers/auth.py | 12 +++++++++++- po/aurweb.pot | 4 ++++ test/test_auth_routes.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 4e6a416a..b8e83c7d 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -1,13 +1,14 @@ from datetime import datetime from http import HTTPStatus -from fastapi import APIRouter, Form, Request +from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse import aurweb.config from aurweb import cookies from aurweb.auth import auth_required +from aurweb.l10n import get_translator_for_request from aurweb.models import User from aurweb.templates import make_variable_context, render_template @@ -35,6 +36,15 @@ async def login_post(request: Request, user: str = Form(default=str()), passwd: str = Form(default=str()), remember_me: bool = Form(default=False)): + # TODO: Once the Origin header gets broader adoption, this code can be + # slightly simplified to use it. + login_path = aurweb.config.get("options", "aur_location") + "/login" + referer = request.headers.get("Referer") + if not referer or not referer.startswith(login_path): + _ = get_translator_for_request(request) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, + detail=_("Bad Referer header.")) + from aurweb.db import session user = session.query(User).filter(User.Username == user).first() diff --git a/po/aurweb.pot b/po/aurweb.pot index 721f874e..dd93ca27 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -964,6 +964,10 @@ msgstr "" msgid "Package details could not be found." msgstr "" +#: aurweb/routers/auth.py +msgid "Bad Referer header." +msgstr "" + #: aurweb/routers/packages.py msgid "You did not select any packages to be notified about." msgstr "" diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 313f9927..39afc6f9 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -18,6 +18,9 @@ from aurweb.testing import setup_test_db # Some test global constants. TEST_USERNAME = "test" TEST_EMAIL = "test@example.org" +TEST_REFERER = { + "referer": aurweb.config.get("options", "aur_location") + "/login", +} # Global mutables. user = client = None @@ -39,6 +42,10 @@ def setup(): client = TestClient(app) + # Necessary for forged login CSRF protection on the login route. Set here + # instead of only on the necessary requests for convenience. + client.headers.update(TEST_REFERER) + def test_login_logout(): post_data = { @@ -92,6 +99,10 @@ def test_secure_login(mock): # Create a local TestClient here since we mocked configuration. client = TestClient(app) + # Necessary for forged login CSRF protection on the login route. Set here + # instead of only on the necessary requests for convenience. + client.headers.update(TEST_REFERER) + # Data used for our upcoming http post request. post_data = { "user": user.Username, @@ -246,3 +257,26 @@ def test_login_incorrect_password(): assert post_data["user"] in content assert post_data["passwd"] not in content assert "checked" not in content + + +def test_login_bad_referer(): + post_data = { + "user": "test", + "passwd": "testPassword", + "next": "/", + } + + # Create new TestClient without a Referer header. + client = TestClient(app) + + with client as request: + response = request.post("/login", data=post_data) + assert "AURSID" not in response.cookies + + BAD_REFERER = { + "referer": aurweb.config.get("options", "aur_location") + ".mal.local", + } + with client as request: + response = request.post("/login", data=post_data, headers=BAD_REFERER) + assert response.status_code == int(HTTPStatus.BAD_REQUEST) + assert "AURSID" not in response.cookies From 69773a5b58ba86bf43a4c4240e5db4842c5dfbe0 Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Fri, 15 Oct 2021 20:14:31 +0200 Subject: [PATCH 1060/1891] feat(PHP): Add packages dump file with more metadata --- aurweb/scripts/mkpkglists.py | 10 ++++++++++ conf/config.defaults | 1 + test/setup.sh | 1 + web/html/index.php | 1 + 4 files changed, 13 insertions(+) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 6724141a..c73cc3be 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -2,11 +2,13 @@ import datetime import gzip +import json import aurweb.config import aurweb.db packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') +packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') userfile = aurweb.config.get('mkpkglists', 'userfile') @@ -27,6 +29,14 @@ def main(): "WHERE PackageBases.PackagerUID IS NOT NULL") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + with gzip.open(packagesmetafile, "wt") as f: + cur = conn.execute("SELECT * FROM Packages") + json.dump({ + "warning": "This is a experimental! It can be removed or modified without warning!", + "columns": [d[0] for d in cur.description], + "data": cur.fetchall() + }, f) + with gzip.open(pkgbasefile, "w") as f: f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) cur = conn.execute("SELECT Name FROM PackageBases " + diff --git a/conf/config.defaults b/conf/config.defaults index b7bc0368..36ea02ef 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -92,5 +92,6 @@ server = ftp://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] packagesfile = /srv/http/aurweb/web/html/packages.gz +packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz userfile = /srv/http/aurweb/web/html/users.gz diff --git a/test/setup.sh b/test/setup.sh index 764d4518..24bb5f48 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -61,6 +61,7 @@ server = file://$(pwd)/remote/ [mkpkglists] packagesfile = packages.gz +packagesmetafile = packages-meta-v1.json.gz pkgbasefile = pkgbase.gz userfile = users.gz EOF diff --git a/web/html/index.php b/web/html/index.php index e57e7708..3163c3e8 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -189,6 +189,7 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { readfile("./$path"); break; case "/packages.gz": + case "/packages-teapot.json.gz": case "/pkgbase.gz": case "/users.gz": header("Content-Type: text/plain"); From 51fb24ab730f3b09d78e200f020b01974dc9e457 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 16:52:30 -0700 Subject: [PATCH 1061/1891] fix(mkpkglists): improve package meta archive The SQL logic in this file for package metadata now exactly reflects RPC's search logic, without searching for specific packages. Two command line arguments are available: --extended | Include License, Keywords, Groups, relations and dependencies. When --extended is passed, the script will create a packages-meta-ext-v1.json.gz, configured via packagesmetaextfile. Archive JSON is in the following format: line-separated package objects enclosed in a list: [ {...}, {...}, {...} ] Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 +- INSTALL | 3 +- aurweb/scripts/mkpkglists.py | 273 ++++++++++++++++++++++++++++++++--- conf/config.defaults | 1 + test/setup.sh | 2 + web/html/index.php | 3 +- 6 files changed, 258 insertions(+), 26 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aff18a83..ce374082 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,7 @@ before_script: python-pygit2 python-srcinfo python-bleach python-markdown python-sqlalchemy python-alembic python-pytest python-werkzeug python-pytest-tap python-fastapi hypercorn nginx python-authlib - python-itsdangerous python-httpx + python-itsdangerous python-httpx python-orjson test: script: diff --git a/INSTALL b/INSTALL index 9bcd0759..dc9cc51f 100644 --- a/INSTALL +++ b/INSTALL @@ -49,7 +49,8 @@ read the instructions below. # pacman -S python-mysql-connector python-pygit2 python-srcinfo python-sqlalchemy \ python-bleach python-markdown python-alembic python-jinja \ - python-itsdangerous python-authlib python-httpx hypercorn + python-itsdangerous python-authlib python-httpx hypercorn \ + python-orjson # python3 setup.py install 5) Create a new MySQL database and a user and import the aurweb SQL schema: diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index c73cc3be..f2095a20 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -1,16 +1,192 @@ #!/usr/bin/env python3 +""" +Produces package, package base and user archives for the AUR +database. + +Archives: + + packages.gz | A line-separated list of package names + packages-meta-v1.json | A type=search RPC-formatted JSON dataset + packages-meta-ext-v1.json | An --extended archive + pkgbase.gz | A line-separated list of package base names + users.gz | A line-separated list of user names + +This script takes an optional argument: --extended. Based +on the following, right-hand side fields are added to each item. + + --extended | License, Keywords, Groups, relations and dependencies + +""" import datetime import gzip -import json +import os +import sys + +from collections import defaultdict +from decimal import Decimal +from typing import Tuple + +import orjson import aurweb.config import aurweb.db + +def state_path(archive: str) -> str: + # A hard-coded /tmp state directory. + # TODO: Use Redis cache to store this state after we merge + # FastAPI into master and removed PHP from the tree. + return os.path.join("/tmp", os.path.basename(archive) + ".state") + + packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') +packagesmetaextfile = aurweb.config.get('mkpkglists', 'packagesmetaextfile') +packages_state = state_path(packagesfile) + pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') +pkgbases_state = state_path(pkgbasefile) + userfile = aurweb.config.get('mkpkglists', 'userfile') +users_state = state_path(userfile) + + +def should_update(state: str, tablename: str) -> Tuple[bool, int]: + if aurweb.config.get("database", "backend") != "mysql": + return (False, 0) + + db_name = aurweb.config.get("database", "name") + conn = aurweb.db.Connection() + cur = conn.execute("SELECT auto_increment FROM information_schema.tables " + "WHERE table_schema = ? AND table_name = ?", + (db_name, tablename,)) + update_time = cur.fetchone()[0] + + saved_update_time = 0 + if os.path.exists(state): + with open(state) as f: + saved_update_time = int(f.read().strip()) + + return (saved_update_time == update_time, update_time) + + +def update_state(state: str, update_time: int) -> None: + with open(state, "w") as f: + f.write(str(update_time)) + + +TYPE_MAP = { + "depends": "Depends", + "makedepends": "MakeDepends", + "checkdepends": "CheckDepends", + "optdepends": "OptDepends", + "conflicts": "Conflicts", + "provides": "Provides", + "replaces": "Replaces", +} + + +def get_extended_dict(query: str): + """ + Produce data in the form in a single bulk SQL query: + + { + : { + "Depends": [...], + "Conflicts": [...], + "License": [...] + } + } + + The caller can then use this data to populate a dataset of packages. + + output = produce_base_output_data() + data = get_extended_dict(query) + for i in range(len(output)): + package_id = output[i].get("ID") + output[i].update(data.get(package_id)) + """ + + conn = aurweb.db.Connection() + + cursor = conn.execute(query) + + data = defaultdict(lambda: defaultdict(list)) + + for result in cursor.fetchall(): + + pkgid = result[0] + key = TYPE_MAP.get(result[1]) + output = result[2] + if result[3]: + output += result[3] + + # In all cases, we have at least an empty License list. + if "License" not in data[pkgid]: + data[pkgid]["License"] = [] + + # In all cases, we have at least an empty Keywords list. + if "Keywords" not in data[pkgid]: + data[pkgid]["Keywords"] = [] + + data[pkgid][key].append(output) + + conn.close() + return data + + +def get_extended_fields(): + # Returns: [ID, Type, Name, Cond] + query = """ + SELECT PackageDepends.PackageID AS ID, DependencyTypes.Name AS Type, + PackageDepends.DepName AS Name, PackageDepends.DepCondition AS Cond + FROM PackageDepends + LEFT JOIN DependencyTypes + ON DependencyTypes.ID = PackageDepends.DepTypeID + UNION SELECT PackageRelations.PackageID AS ID, RelationTypes.Name AS Type, + PackageRelations.RelName AS Name, + PackageRelations.RelCondition AS Cond + FROM PackageRelations + LEFT JOIN RelationTypes + ON RelationTypes.ID = PackageRelations.RelTypeID + UNION SELECT PackageGroups.PackageID AS ID, 'Groups' AS Type, + Groups.Name, '' AS Cond + FROM Groups + INNER JOIN PackageGroups ON PackageGroups.GroupID = Groups.ID + UNION SELECT PackageLicenses.PackageID AS ID, 'License' AS Type, + Licenses.Name, '' as Cond + FROM Licenses + INNER JOIN PackageLicenses ON PackageLicenses.LicenseID = Licenses.ID + UNION SELECT Packages.ID AS ID, 'Keywords' AS Type, + PackageKeywords.Keyword AS Name, '' as Cond + FROM PackageKeywords + INNER JOIN Packages ON Packages.PackageBaseID = PackageKeywords.PackageBaseID + """ + return get_extended_dict(query) + + +EXTENDED_FIELD_HANDLERS = { + "--extended": get_extended_fields +} + + +def is_decimal(column): + """ Check if an SQL column is of decimal.Decimal type. """ + if isinstance(column, Decimal): + return float(column) + return column + + +def write_archive(archive: str, output: list): + with gzip.open(archive, "wb") as f: + f.write(b"[\n") + for i, item in enumerate(output): + f.write(orjson.dumps(item)) + if i < len(output) - 1: + f.write(b",") + f.write(b"\n") + f.write(b"]") def main(): @@ -21,32 +197,83 @@ def main(): pkgbaselist_header = "# AUR package base list, generated on " + datestr userlist_header = "# AUR user name list, generated on " + datestr - with gzip.open(packagesfile, "w") as f: - f.write(bytes(pkglist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT Packages.Name FROM Packages " + - "INNER JOIN PackageBases " + - "ON PackageBases.ID = Packages.PackageBaseID " + + updated, update_time = should_update(packages_state, "Packages") + if not updated: + print("Updating Packages...") + + # Query columns; copied from RPC. + columns = ("Packages.ID, Packages.Name, " + "PackageBases.ID AS PackageBaseID, " + "PackageBases.Name AS PackageBase, " + "Version, Description, URL, NumVotes, " + "Popularity, OutOfDateTS AS OutOfDate, " + "Users.UserName AS Maintainer, " + "SubmittedTS AS FirstSubmitted, " + "ModifiedTS AS LastModified") + + # Perform query. + cur = conn.execute(f"SELECT {columns} FROM Packages " + "LEFT JOIN PackageBases " + "ON PackageBases.ID = Packages.PackageBaseID " + "LEFT JOIN Users " + "ON PackageBases.MaintainerUID = Users.ID " "WHERE PackageBases.PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - with gzip.open(packagesmetafile, "wt") as f: - cur = conn.execute("SELECT * FROM Packages") - json.dump({ - "warning": "This is a experimental! It can be removed or modified without warning!", - "columns": [d[0] for d in cur.description], - "data": cur.fetchall() - }, f) + # Produce packages-meta-v1.json.gz + output = list() + snapshot_uri = aurweb.config.get("options", "snapshot_uri") + for result in cur.fetchall(): + item = { + column[0]: is_decimal(result[i]) + for i, column in enumerate(cur.description) + } + item["URLPath"] = snapshot_uri % item.get("Name") + output.append(item) - with gzip.open(pkgbasefile, "w") as f: - f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT Name FROM PackageBases " + - "WHERE PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + write_archive(packagesmetafile, output) - with gzip.open(userfile, "w") as f: - f.write(bytes(userlist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT UserName FROM Users") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + # Produce packages-meta-ext-v1.json.gz + if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: + f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) + data = f() + + default_ = {"Groups": [], "License": [], "Keywords": []} + for i in range(len(output)): + data_ = data.get(output[i].get("ID"), default_) + output[i].update(data_) + + write_archive(packagesmetaextfile, output) + + # Produce packages.gz + with gzip.open(packagesfile, "wb") as f: + f.write(bytes(pkglist_header + "\n", "UTF-8")) + f.writelines([ + bytes(x.get("Name") + "\n", "UTF-8") + for x in output + ]) + + update_state(packages_state, update_time) + + updated, update_time = should_update(pkgbases_state, "PackageBases") + if not updated: + print("Updating PackageBases...") + # Produce pkgbase.gz + with gzip.open(pkgbasefile, "w") as f: + f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT Name FROM PackageBases " + + "WHERE PackagerUID IS NOT NULL") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + update_state(pkgbases_state, update_time) + + updated, update_time = should_update(users_state, "Users") + if not updated: + print("Updating Users...") + # Produce users.gz + with gzip.open(userfile, "w") as f: + f.write(bytes(userlist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT UserName FROM Users") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + update_state(users_state, update_time) conn.close() diff --git a/conf/config.defaults b/conf/config.defaults index 36ea02ef..a04f21bc 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -93,5 +93,6 @@ server = ftp://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] packagesfile = /srv/http/aurweb/web/html/packages.gz packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz +packagesmetaextfile = /srv/http/aurweb/web/html/packages-meta-ext-v1.json.gz pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz userfile = /srv/http/aurweb/web/html/users.gz diff --git a/test/setup.sh b/test/setup.sh index 24bb5f48..f74cd1b7 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -31,6 +31,7 @@ enable-maintenance = 0 maintenance-exceptions = 127.0.0.1 commit_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s&id=%s localedir = $TOPLEVEL/web/locale/ +snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz [notifications] notify-cmd = $NOTIFY @@ -62,6 +63,7 @@ server = file://$(pwd)/remote/ [mkpkglists] packagesfile = packages.gz packagesmetafile = packages-meta-v1.json.gz +packagesmetaextfile = packages-meta-ext-v1.json.gz pkgbasefile = pkgbase.gz userfile = users.gz EOF diff --git a/web/html/index.php b/web/html/index.php index 3163c3e8..dc435162 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -189,7 +189,8 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { readfile("./$path"); break; case "/packages.gz": - case "/packages-teapot.json.gz": + case "/packages-meta-v1.json.gz": + case "/packages-meta-ext-v1.json.gz": case "/pkgbase.gz": case "/users.gz": header("Content-Type: text/plain"); From cdca8bd2953f3c3aa3a1b4cedb89c3b7b9fd4ddb Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 6 Nov 2021 16:23:08 -0700 Subject: [PATCH 1062/1891] feat(mkpkglists): added metadata archives Two new archives are available: - packages-meta-v1.json.gz - RPC search formatted data for all packages - ~2.1MB at the time of writing. - packages-meta-ext-v1.json.gz (via --extended) - RPC multiinfo formatted data for all packages. - ~9.8MB at the time of writing. New dependencies are required for this update: - `python-orjson` All archives served out by aur.archlinux.org distribute the Last-Modified header and support the If-Modified-Since header, which should be populated with Last-Modified's value. These should be used by clients to avoid redownloading the archive when unnecessary. Additionally, the new meta archives contain a format suitable for streaming the data as the file is retrieved. It is still in JSON format, however, users can parse package objects line by line after the first '[' found in the file, until the last ']'; both contained on their own lines. Note: This commit is a documentation change and commit body. Signed-off-by: Kevin Morris --- doc/maintenance.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/maintenance.txt b/doc/maintenance.txt index d6094545..2c5c9faf 100644 --- a/doc/maintenance.txt +++ b/doc/maintenance.txt @@ -70,7 +70,8 @@ computations and clean up the database: * aurweb-pkgmaint automatically removes empty repositories that were created within the last 24 hours but never populated. -* aurweb-mkpkglists generates the package list files. +* aurweb-mkpkglists generates the package list files; it takes an optional + --extended flag, which additionally produces multiinfo metadata. * aurweb-usermaint removes the last login IP address of all users that did not login within the past seven days. @@ -79,7 +80,7 @@ These scripts can be installed by running `python3 setup.py install` and are usually scheduled using Cron. The current setup is: ---- -*/5 * * * * aurweb-mkpkglists +*/5 * * * * aurweb-mkpkglists [--extended] 1 */2 * * * aurweb-popupdate 2 */2 * * * aurweb-aurblup 3 */2 * * * aurweb-pkgmaint From 9f1f39995740e04d44309c7aed69a9b15d26dac0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 6 Nov 2021 17:13:16 -0700 Subject: [PATCH 1063/1891] fix(mkpkglists): remove caching We really need caching for this; however, our current caching method will cause the script to bypass changes to columns if they have nothing to do with IDs. Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 159 ++++++++++++----------------------- 1 file changed, 54 insertions(+), 105 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index f2095a20..2566a146 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -20,60 +20,23 @@ on the following, right-hand side fields are added to each item. import datetime import gzip -import os import sys from collections import defaultdict from decimal import Decimal -from typing import Tuple import orjson import aurweb.config import aurweb.db - -def state_path(archive: str) -> str: - # A hard-coded /tmp state directory. - # TODO: Use Redis cache to store this state after we merge - # FastAPI into master and removed PHP from the tree. - return os.path.join("/tmp", os.path.basename(archive) + ".state") - - packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') packagesmetaextfile = aurweb.config.get('mkpkglists', 'packagesmetaextfile') -packages_state = state_path(packagesfile) pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') -pkgbases_state = state_path(pkgbasefile) userfile = aurweb.config.get('mkpkglists', 'userfile') -users_state = state_path(userfile) - - -def should_update(state: str, tablename: str) -> Tuple[bool, int]: - if aurweb.config.get("database", "backend") != "mysql": - return (False, 0) - - db_name = aurweb.config.get("database", "name") - conn = aurweb.db.Connection() - cur = conn.execute("SELECT auto_increment FROM information_schema.tables " - "WHERE table_schema = ? AND table_name = ?", - (db_name, tablename,)) - update_time = cur.fetchone()[0] - - saved_update_time = 0 - if os.path.exists(state): - with open(state) as f: - saved_update_time = int(f.read().strip()) - - return (saved_update_time == update_time, update_time) - - -def update_state(state: str, update_time: int) -> None: - with open(state, "w") as f: - f.write(str(update_time)) TYPE_MAP = { @@ -197,83 +160,69 @@ def main(): pkgbaselist_header = "# AUR package base list, generated on " + datestr userlist_header = "# AUR user name list, generated on " + datestr - updated, update_time = should_update(packages_state, "Packages") - if not updated: - print("Updating Packages...") + # Query columns; copied from RPC. + columns = ("Packages.ID, Packages.Name, " + "PackageBases.ID AS PackageBaseID, " + "PackageBases.Name AS PackageBase, " + "Version, Description, URL, NumVotes, " + "Popularity, OutOfDateTS AS OutOfDate, " + "Users.UserName AS Maintainer, " + "SubmittedTS AS FirstSubmitted, " + "ModifiedTS AS LastModified") - # Query columns; copied from RPC. - columns = ("Packages.ID, Packages.Name, " - "PackageBases.ID AS PackageBaseID, " - "PackageBases.Name AS PackageBase, " - "Version, Description, URL, NumVotes, " - "Popularity, OutOfDateTS AS OutOfDate, " - "Users.UserName AS Maintainer, " - "SubmittedTS AS FirstSubmitted, " - "ModifiedTS AS LastModified") + # Perform query. + cur = conn.execute(f"SELECT {columns} FROM Packages " + "LEFT JOIN PackageBases " + "ON PackageBases.ID = Packages.PackageBaseID " + "LEFT JOIN Users " + "ON PackageBases.MaintainerUID = Users.ID " + "WHERE PackageBases.PackagerUID IS NOT NULL") - # Perform query. - cur = conn.execute(f"SELECT {columns} FROM Packages " - "LEFT JOIN PackageBases " - "ON PackageBases.ID = Packages.PackageBaseID " - "LEFT JOIN Users " - "ON PackageBases.MaintainerUID = Users.ID " - "WHERE PackageBases.PackagerUID IS NOT NULL") + # Produce packages-meta-v1.json.gz + output = list() + snapshot_uri = aurweb.config.get("options", "snapshot_uri") + for result in cur.fetchall(): + item = { + column[0]: is_decimal(result[i]) + for i, column in enumerate(cur.description) + } + item["URLPath"] = snapshot_uri % item.get("Name") + output.append(item) - # Produce packages-meta-v1.json.gz - output = list() - snapshot_uri = aurweb.config.get("options", "snapshot_uri") - for result in cur.fetchall(): - item = { - column[0]: is_decimal(result[i]) - for i, column in enumerate(cur.description) - } - item["URLPath"] = snapshot_uri % item.get("Name") - output.append(item) + write_archive(packagesmetafile, output) - write_archive(packagesmetafile, output) + # Produce packages-meta-ext-v1.json.gz + if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: + f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) + data = f() - # Produce packages-meta-ext-v1.json.gz - if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: - f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) - data = f() + default_ = {"Groups": [], "License": [], "Keywords": []} + for i in range(len(output)): + data_ = data.get(output[i].get("ID"), default_) + output[i].update(data_) - default_ = {"Groups": [], "License": [], "Keywords": []} - for i in range(len(output)): - data_ = data.get(output[i].get("ID"), default_) - output[i].update(data_) + write_archive(packagesmetaextfile, output) - write_archive(packagesmetaextfile, output) + # Produce packages.gz + with gzip.open(packagesfile, "wb") as f: + f.write(bytes(pkglist_header + "\n", "UTF-8")) + f.writelines([ + bytes(x.get("Name") + "\n", "UTF-8") + for x in output + ]) - # Produce packages.gz - with gzip.open(packagesfile, "wb") as f: - f.write(bytes(pkglist_header + "\n", "UTF-8")) - f.writelines([ - bytes(x.get("Name") + "\n", "UTF-8") - for x in output - ]) + # Produce pkgbase.gz + with gzip.open(pkgbasefile, "w") as f: + f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT Name FROM PackageBases " + + "WHERE PackagerUID IS NOT NULL") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - update_state(packages_state, update_time) - - updated, update_time = should_update(pkgbases_state, "PackageBases") - if not updated: - print("Updating PackageBases...") - # Produce pkgbase.gz - with gzip.open(pkgbasefile, "w") as f: - f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT Name FROM PackageBases " + - "WHERE PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - update_state(pkgbases_state, update_time) - - updated, update_time = should_update(users_state, "Users") - if not updated: - print("Updating Users...") - # Produce users.gz - with gzip.open(userfile, "w") as f: - f.write(bytes(userlist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT UserName FROM Users") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - update_state(users_state, update_time) + # Produce users.gz + with gzip.open(userfile, "w") as f: + f.write(bytes(userlist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT UserName FROM Users") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) conn.close() From 446a082352bf2bb8d7398afbdbe9dfad42f21fed Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 7 Nov 2021 17:26:05 -0800 Subject: [PATCH 1064/1891] change(fastapi): refactor database ORM model definitions We don't want to depend on the database to load up data about the models we define. We now leverage the existing `aurweb.schema` module for table definitions and set __table_args__["autoload"] to False. Signed-off-by: Kevin Morris --- aurweb/models/accepted_term.py | 16 +++----- aurweb/models/account_type.py | 56 +++++++++++---------------- aurweb/models/api_rate_limit.py | 10 ++--- aurweb/models/ban.py | 10 ++--- aurweb/models/declarative.py | 6 +-- aurweb/models/dependency_type.py | 27 +++++-------- aurweb/models/group.py | 10 ++--- aurweb/models/license.py | 10 ++--- aurweb/models/official_provider.py | 10 ++--- aurweb/models/package.py | 15 +++---- aurweb/models/package_base.py | 21 ++++------ aurweb/models/package_blacklist.py | 10 ++--- aurweb/models/package_comaintainer.py | 20 ++++------ aurweb/models/package_comment.py | 26 ++++--------- aurweb/models/package_dependency.py | 22 ++++------- aurweb/models/package_group.py | 18 ++++----- aurweb/models/package_keyword.py | 19 ++++----- aurweb/models/package_license.py | 20 ++++------ aurweb/models/package_notification.py | 20 ++++------ aurweb/models/package_relation.py | 22 ++++------- aurweb/models/package_request.py | 25 ++++-------- aurweb/models/package_source.py | 14 +++---- aurweb/models/package_vote.py | 20 ++++------ aurweb/models/relation_type.py | 24 ++++-------- aurweb/models/request_type.py | 21 ++++------ aurweb/models/session.py | 13 +++---- aurweb/models/ssh_pub_key.py | 19 +++------ aurweb/models/term.py | 10 ++--- aurweb/models/tu_vote.py | 18 ++++----- aurweb/models/tu_voteinfo.py | 15 +++---- aurweb/models/user.py | 21 ++++------ 31 files changed, 212 insertions(+), 356 deletions(-) diff --git a/aurweb/models/accepted_term.py b/aurweb/models/accepted_term.py index b4dbb410..0f9b187e 100644 --- a/aurweb/models/accepted_term.py +++ b/aurweb/models/accepted_term.py @@ -1,28 +1,24 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.term import Term as _Term from aurweb.models.user import User as _User class AcceptedTerm(Base): - __tablename__ = "AcceptedTerms" + __table__ = schema.AcceptedTerms + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.TermsID]} - UsersID = Column(Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) User = relationship( _User, backref=backref("accepted_terms", lazy="dynamic"), - foreign_keys=[UsersID]) + foreign_keys=[__table__.c.UsersID]) - TermsID = Column(Integer, ForeignKey("Terms.ID", ondelete="CASCADE"), - nullable=False) Term = relationship( _Term, backref=backref("accepted_terms", lazy="dynamic"), - foreign_keys=[TermsID]) - - __mapper_args__ = {"primary_key": [TermsID]} + foreign_keys=[__table__.c.TermsID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py index 7aa7733c..a849df02 100644 --- a/aurweb/models/account_type.py +++ b/aurweb/models/account_type.py @@ -1,6 +1,4 @@ -from sqlalchemy import Column, Integer - -from aurweb import db +from aurweb import schema from aurweb.models.declarative import Base USER = "User" @@ -8,37 +6,10 @@ TRUSTED_USER = "Trusted User" DEVELOPER = "Developer" TRUSTED_USER_AND_DEV = "Trusted User & Developer" - -class AccountType(Base): - """ An ORM model of a single AccountTypes record. """ - __tablename__ = "AccountTypes" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} - - def __init__(self, **kwargs): - self.AccountType = kwargs.pop("AccountType") - - def __str__(self): - return str(self.AccountType) - - def __repr__(self): - return "" % ( - self.ID, str(self)) - - -# Fetch account type IDs from the database for constants. -_account_types = db.query(AccountType) -USER_ID = _account_types.filter( - AccountType.AccountType == USER).first().ID -TRUSTED_USER_ID = _account_types.filter( - AccountType.AccountType == TRUSTED_USER).first().ID -DEVELOPER_ID = _account_types.filter( - AccountType.AccountType == DEVELOPER).first().ID -TRUSTED_USER_AND_DEV_ID = _account_types.filter( - AccountType.AccountType == TRUSTED_USER_AND_DEV).first().ID -_account_types = None # Get rid of the query handle. +USER_ID = 1 +TRUSTED_USER_ID = 2 +DEVELOPER_ID = 3 +TRUSTED_USER_AND_DEV_ID = 4 # Map string constants to integer constants. ACCOUNT_TYPE_ID = { @@ -50,3 +21,20 @@ ACCOUNT_TYPE_ID = { # Reversed ACCOUNT_TYPE_ID mapping. ACCOUNT_TYPE_NAME = {v: k for k, v in ACCOUNT_TYPE_ID.items()} + + +class AccountType(Base): + """ An ORM model of a single AccountTypes record. """ + __table__ = schema.AccountTypes + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} + + def __init__(self, **kwargs): + self.AccountType = kwargs.pop("AccountType") + + def __str__(self): + return str(self.AccountType) + + def __repr__(self): + return "" % ( + self.ID, str(self)) diff --git a/aurweb/models/api_rate_limit.py b/aurweb/models/api_rate_limit.py index f8641896..19b656df 100644 --- a/aurweb/models/api_rate_limit.py +++ b/aurweb/models/api_rate_limit.py @@ -1,15 +1,13 @@ -from sqlalchemy import Column, String from sqlalchemy.exc import IntegrityError +from aurweb import schema from aurweb.models.declarative import Base class ApiRateLimit(Base): - __tablename__ = "ApiRateLimit" - - IP = Column(String(45), primary_key=True, unique=True, default=str()) - - __mapper_args__ = {"primary_key": [IP]} + __table__ = schema.ApiRateLimit + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.IP]} def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/ban.py b/aurweb/models/ban.py index e10087b0..a70be7b9 100644 --- a/aurweb/models/ban.py +++ b/aurweb/models/ban.py @@ -1,15 +1,13 @@ from fastapi import Request -from sqlalchemy import Column, String +from aurweb import schema from aurweb.models.declarative import Base class Ban(Base): - __tablename__ = "Bans" - - IPAddress = Column(String(45), primary_key=True) - - __mapper_args__ = {"primary_key": [IPAddress]} + __table__ = schema.Bans + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.IPAddress]} def __init__(self, **kwargs): self.IPAddress = kwargs.get("IPAddress") diff --git a/aurweb/models/declarative.py b/aurweb/models/declarative.py index 96ee1829..20ddd20c 100644 --- a/aurweb/models/declarative.py +++ b/aurweb/models/declarative.py @@ -2,8 +2,6 @@ import json from sqlalchemy.ext.declarative import declarative_base -import aurweb.db - from aurweb import util @@ -25,12 +23,10 @@ Base = declarative_base() # Setup __table_args__ applicable to every table. Base.__table_args__ = { - "autoload": True, - "autoload_with": aurweb.db.get_engine(), + "autoload": False, "extend_existing": True } - # Setup Base.as_dict and Base.json. # # With this, declarative models can use .as_dict() or .json() diff --git a/aurweb/models/dependency_type.py b/aurweb/models/dependency_type.py index 3b5fafcc..98418802 100644 --- a/aurweb/models/dependency_type.py +++ b/aurweb/models/dependency_type.py @@ -1,6 +1,4 @@ -from sqlalchemy import Column, Integer - -from aurweb import db +from aurweb import schema from aurweb.models.declarative import Base DEPENDS = "depends" @@ -8,23 +6,16 @@ MAKEDEPENDS = "makedepends" CHECKDEPENDS = "checkdepends" OPTDEPENDS = "optdepends" +DEPENDS_ID = 1 +MAKEDEPENDS_ID = 2 +CHECKDEPENDS_ID = 3 +OPTDEPENDS_ID = 4 + class DependencyType(Base): - __tablename__ = "DependencyTypes" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.DependencyTypes + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def __init__(self, Name: str = None): self.Name = Name - - -DEPENDS_ID = db.query(DependencyType).filter( - DependencyType.Name == DEPENDS).first().ID -MAKEDEPENDS_ID = db.query(DependencyType).filter( - DependencyType.Name == MAKEDEPENDS).first().ID -CHECKDEPENDS_ID = db.query(DependencyType).filter( - DependencyType.Name == CHECKDEPENDS).first().ID -OPTDEPENDS_ID = db.query(DependencyType).filter( - DependencyType.Name == OPTDEPENDS).first().ID diff --git a/aurweb/models/group.py b/aurweb/models/group.py index 5493bb7f..0275ed94 100644 --- a/aurweb/models/group.py +++ b/aurweb/models/group.py @@ -1,15 +1,13 @@ -from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError +from aurweb import schema from aurweb.models.declarative import Base class Group(Base): - __tablename__ = "Groups" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.Groups + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/license.py b/aurweb/models/license.py index fa863379..86aeaa86 100644 --- a/aurweb/models/license.py +++ b/aurweb/models/license.py @@ -1,15 +1,13 @@ -from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError +from aurweb import schema from aurweb.models.declarative import Base class License(Base): - __tablename__ = "Licenses" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.Licenses + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/official_provider.py b/aurweb/models/official_provider.py index a273dd06..a8282ff1 100644 --- a/aurweb/models/official_provider.py +++ b/aurweb/models/official_provider.py @@ -1,6 +1,6 @@ -from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError +from aurweb import schema from aurweb.models.declarative import Base # TODO: Fix this! Official packages aren't from aur.archlinux.org... @@ -8,11 +8,9 @@ OFFICIAL_BASE = "https://aur.archlinux.org" class OfficialProvider(Base): - __tablename__ = "OfficialProviders" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.OfficialProviders + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package.py b/aurweb/models/package.py index ef119f3c..8f82dadd 100644 --- a/aurweb/models/package.py +++ b/aurweb/models/package.py @@ -1,24 +1,19 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase class Package(Base): - __tablename__ = "Packages" + __table__ = schema.Packages + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} - ID = Column(Integer, primary_key=True) - - PackageBaseID = Column( - Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), - nullable=False) PackageBase = relationship( _PackageBase, backref=backref("packages", lazy="dynamic"), - foreign_keys=[PackageBaseID]) - - __mapper_args__ = {"primary_key": [ID]} + foreign_keys=[__table__.c.PackageBaseID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_base.py b/aurweb/models/package_base.py index e6f28050..8c88b7b5 100644 --- a/aurweb/models/package_base.py +++ b/aurweb/models/package_base.py @@ -1,38 +1,33 @@ from datetime import datetime -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.user import User as _User class PackageBase(Base): - __tablename__ = "PackageBases" + __table__ = schema.PackageBases + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} - FlaggerUID = Column(Integer, - ForeignKey("Users.ID", ondelete="SET NULL")) Flagger = relationship( _User, backref=backref("flagged_bases", lazy="dynamic"), - foreign_keys=[FlaggerUID]) + foreign_keys=[__table__.c.FlaggerUID]) - SubmitterUID = Column(Integer, - ForeignKey("Users.ID", ondelete="SET NULL")) Submitter = relationship( _User, backref=backref("submitted_bases", lazy="dynamic"), - foreign_keys=[SubmitterUID]) + foreign_keys=[__table__.c.SubmitterUID]) - MaintainerUID = Column(Integer, - ForeignKey("Users.ID", ondelete="SET NULL")) Maintainer = relationship( _User, backref=backref("maintained_bases", lazy="dynamic"), - foreign_keys=[MaintainerUID]) + foreign_keys=[__table__.c.MaintainerUID]) - PackagerUID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) Packager = relationship( _User, backref=backref("package_bases", lazy="dynamic"), - foreign_keys=[PackagerUID]) + foreign_keys=[__table__.c.PackagerUID]) # A set used to check for floatable values. TO_FLOAT = {"Popularity"} diff --git a/aurweb/models/package_blacklist.py b/aurweb/models/package_blacklist.py index 4ba3f308..0f8f0cee 100644 --- a/aurweb/models/package_blacklist.py +++ b/aurweb/models/package_blacklist.py @@ -1,15 +1,13 @@ -from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError +from aurweb import schema from aurweb.models.declarative import Base class PackageBlacklist(Base): - __tablename__ = "PackageBlacklist" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.PackageBlacklist + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_comaintainer.py b/aurweb/models/package_comaintainer.py index 2f77782c..7641fb43 100644 --- a/aurweb/models/package_comaintainer.py +++ b/aurweb/models/package_comaintainer.py @@ -1,30 +1,26 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase from aurweb.models.user import User as _User class PackageComaintainer(Base): - __tablename__ = "PackageComaintainers" + __table__ = schema.PackageComaintainers + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.UsersID, __table__.c.PackageBaseID] + } - UsersID = Column( - Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) User = relationship( _User, backref=backref("comaintained", lazy="dynamic"), - foreign_keys=[UsersID]) + foreign_keys=[__table__.c.UsersID]) - PackageBaseID = Column( - Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), - nullable=False) PackageBase = relationship( _PackageBase, backref=backref("comaintainers", lazy="dynamic"), - foreign_keys=[PackageBaseID]) - - __mapper_args__ = {"primary_key": [UsersID, PackageBaseID]} + foreign_keys=[__table__.c.PackageBaseID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_comment.py b/aurweb/models/package_comment.py index a511df9b..2a529c9c 100644 --- a/aurweb/models/package_comment.py +++ b/aurweb/models/package_comment.py @@ -1,43 +1,33 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase from aurweb.models.user import User as _User class PackageComment(Base): - __tablename__ = "PackageComments" + __table__ = schema.PackageComments + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} - ID = Column(Integer, primary_key=True) - - PackageBaseID = Column( - Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), - nullable=False) PackageBase = relationship( _PackageBase, backref=backref("comments", lazy="dynamic", cascade="all, delete"), - foreign_keys=[PackageBaseID]) + foreign_keys=[__table__.c.PackageBaseID]) - UsersID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) User = relationship( _User, backref=backref("package_comments", lazy="dynamic"), - foreign_keys=[UsersID]) + foreign_keys=[__table__.c.UsersID]) - EditedUsersID = Column( - Integer, ForeignKey("Users.ID", ondelete="SET NULL")) Editor = relationship( _User, backref=backref("edited_comments", lazy="dynamic"), - foreign_keys=[EditedUsersID]) + foreign_keys=[__table__.c.EditedUsersID]) - DelUsersID = Column( - Integer, ForeignKey("Users.ID", ondelete="SET NULL")) Deleter = relationship( _User, backref=backref("deleted_comments", lazy="dynamic"), - foreign_keys=[DelUsersID]) - - __mapper_args__ = {"primary_key": [ID]} + foreign_keys=[__table__.c.DelUsersID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index 3f4e2baa..edaa6538 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -1,34 +1,28 @@ -from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.dependency_type import DependencyType as _DependencyType from aurweb.models.package import Package as _Package class PackageDependency(Base): - __tablename__ = "PackageDepends" + __table__ = schema.PackageDepends + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.PackageID, __table__.c.DepName] + } - PackageID = Column( - Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), - nullable=False) Package = relationship( _Package, backref=backref("package_dependencies", lazy="dynamic", cascade="all, delete"), - foreign_keys=[PackageID]) + foreign_keys=[__table__.c.PackageID]) - DepTypeID = Column( - Integer, ForeignKey("DependencyTypes.ID", ondelete="NO ACTION"), - nullable=False) DependencyType = relationship( _DependencyType, backref=backref("package_dependencies", lazy="dynamic"), - foreign_keys=[DepTypeID]) - - DepName = Column(String(255), nullable=False) - - __mapper_args__ = {"primary_key": [PackageID, DepName]} + foreign_keys=[__table__.c.DepTypeID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_group.py b/aurweb/models/package_group.py index c1d1e4f8..3b6db37d 100644 --- a/aurweb/models/package_group.py +++ b/aurweb/models/package_group.py @@ -1,28 +1,26 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.group import Group as _Group from aurweb.models.package import Package as _Package class PackageGroup(Base): - __tablename__ = "PackageGroups" + __table__ = schema.PackageGroups + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.PackageID, __table__.c.GroupID] + } - PackageID = Column(Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), - primary_key=True, nullable=True) Package = relationship( _Package, backref=backref("package_groups", lazy="dynamic"), - foreign_keys=[PackageID]) + foreign_keys=[__table__.c.PackageID]) - GroupID = Column(Integer, ForeignKey("Groups.ID", ondelete="CASCADE"), - primary_key=True, nullable=True) Group = relationship( _Group, backref=backref("package_groups", lazy="dynamic"), - foreign_keys=[GroupID]) - - __mapper_args__ = {"primary_key": [PackageID, GroupID]} + foreign_keys=[__table__.c.GroupID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_keyword.py b/aurweb/models/package_keyword.py index 25bd340b..581aafdc 100644 --- a/aurweb/models/package_keyword.py +++ b/aurweb/models/package_keyword.py @@ -1,27 +1,22 @@ -from sqlalchemy import Column, ForeignKey, Integer, String, text from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase class PackageKeyword(Base): - __tablename__ = "PackageKeywords" + __table__ = schema.PackageKeywords + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.PackageBaseID, __table__.c.Keyword] + } - PackageBaseID = Column( - Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), - primary_key=True, nullable=True) PackageBase = relationship( _PackageBase, backref=backref("keywords", lazy="dynamic", cascade="all, delete"), - foreign_keys=[PackageBaseID]) - - Keyword = Column( - String(255), primary_key=True, nullable=False, - server_default=text("''")) - - __mapper_args__ = {"primary_key": [PackageBaseID, Keyword]} + foreign_keys=[__table__.c.PackageBaseID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_license.py b/aurweb/models/package_license.py index db12a7c3..43dd0339 100644 --- a/aurweb/models/package_license.py +++ b/aurweb/models/package_license.py @@ -1,32 +1,28 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.license import License as _License from aurweb.models.package import Package as _Package class PackageLicense(Base): - __tablename__ = "PackageLicenses" + __table__ = schema.PackageLicenses + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.PackageID, __table__.c.LicenseID] + } - PackageID = Column( - Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), - primary_key=True, nullable=True) Package = relationship( _Package, backref=backref("package_licenses", lazy="dynamic", cascade="all, delete"), - foreign_keys=[PackageID]) + foreign_keys=[__table__.c.PackageID]) - LicenseID = Column( - Integer, ForeignKey("Licenses.ID", ondelete="CASCADE"), - primary_key=True, nullable=True) License = relationship( _License, backref=backref("package_licenses", lazy="dynamic", cascade="all, delete"), - foreign_keys=[LicenseID]) - - __mapper_args__ = {"primary_key": [PackageID, LicenseID]} + foreign_keys=[__table__.c.LicenseID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_notification.py b/aurweb/models/package_notification.py index 221067e1..97dbe38f 100644 --- a/aurweb/models/package_notification.py +++ b/aurweb/models/package_notification.py @@ -1,31 +1,27 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase from aurweb.models.user import User as _User class PackageNotification(Base): - __tablename__ = "PackageNotifications" + __table__ = schema.PackageNotifications + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.UserID, __table__.c.PackageBaseID] + } - UserID = Column( - Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) User = relationship( _User, backref=backref("notifications", lazy="dynamic"), - foreign_keys=[UserID]) + foreign_keys=[__table__.c.UserID]) - PackageBaseID = Column( - Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), - nullable=False) PackageBase = relationship( _PackageBase, backref=backref("notifications", lazy="dynamic"), - foreign_keys=[PackageBaseID]) - - __mapper_args__ = {"primary_key": [UserID, PackageBaseID]} + foreign_keys=[__table__.c.PackageBaseID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_relation.py b/aurweb/models/package_relation.py index e79a90d6..eb6caa84 100644 --- a/aurweb/models/package_relation.py +++ b/aurweb/models/package_relation.py @@ -1,33 +1,27 @@ -from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package import Package as _Package from aurweb.models.relation_type import RelationType as _RelationType class PackageRelation(Base): - __tablename__ = "PackageRelations" + __table__ = schema.PackageRelations + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.PackageID, __table__.c.RelName] + } - PackageID = Column( - Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), - nullable=False) Package = relationship( _Package, backref=backref("package_relations", lazy="dynamic", cascade="all, delete"), - foreign_keys=[PackageID]) + foreign_keys=[__table__.c.PackageID]) - RelTypeID = Column( - Integer, ForeignKey("RelationTypes.ID", ondelete="CASCADE"), - nullable=False) RelationType = relationship( _RelationType, backref=backref("package_relations", lazy="dynamic"), - foreign_keys=[RelTypeID]) - - RelName = Column(String(255), unique=True) - - __mapper_args__ = {"primary_key": [PackageID, RelName]} + foreign_keys=[__table__.c.RelTypeID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_request.py b/aurweb/models/package_request.py index f600566c..9669ec46 100644 --- a/aurweb/models/package_request.py +++ b/aurweb/models/package_request.py @@ -1,7 +1,7 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase from aurweb.models.request_type import RequestType as _RequestType @@ -20,34 +20,25 @@ REJECTED_ID = 3 class PackageRequest(Base): - __tablename__ = "PackageRequests" + __table__ = schema.PackageRequests + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} - ID = Column(Integer, primary_key=True) - - ReqTypeID = Column( - Integer, ForeignKey("RequestTypes.ID", ondelete="NO ACTION"), - nullable=False) RequestType = relationship( _RequestType, backref=backref("package_requests", lazy="dynamic"), - foreign_keys=[ReqTypeID]) + foreign_keys=[__table__.c.ReqTypeID]) - UsersID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) User = relationship( _User, backref=backref("package_requests", lazy="dynamic"), - foreign_keys=[UsersID]) + foreign_keys=[__table__.c.UsersID]) - PackageBaseID = Column( - Integer, ForeignKey("PackageBases.ID", ondelete="SET NULL")) PackageBase = relationship( _PackageBase, backref=backref("requests", lazy="dynamic"), - foreign_keys=[PackageBaseID]) + foreign_keys=[__table__.c.PackageBaseID]) - ClosedUID = Column(Integer, ForeignKey("Users.ID", ondelete="SET NULL")) Closer = relationship( _User, backref=backref("closed_requests", lazy="dynamic"), - foreign_keys=[ClosedUID]) - - __mapper_args__ = {"primary_key": [ID]} + foreign_keys=[__table__.c.ClosedUID]) STATUS_DISPLAY = { PENDING_ID: PENDING, diff --git a/aurweb/models/package_source.py b/aurweb/models/package_source.py index db983272..59046bbd 100644 --- a/aurweb/models/package_source.py +++ b/aurweb/models/package_source.py @@ -1,22 +1,22 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package import Package as _Package class PackageSource(Base): - __tablename__ = "PackageSources" + __table__ = schema.PackageSources + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.PackageID] + } - PackageID = Column(Integer, ForeignKey("Packages.ID", ondelete="CASCADE"), - nullable=False) Package = relationship( _Package, backref=backref("package_sources", lazy="dynamic", cascade="all, delete"), - foreign_keys=[PackageID]) - - __mapper_args__ = {"primary_key": [PackageID]} + foreign_keys=[__table__.c.PackageID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/package_vote.py b/aurweb/models/package_vote.py index 2d70be16..7221d527 100644 --- a/aurweb/models/package_vote.py +++ b/aurweb/models/package_vote.py @@ -1,30 +1,26 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase from aurweb.models.user import User as _User class PackageVote(Base): - __tablename__ = "PackageVotes" + __table__ = schema.PackageVotes + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.UsersID, __table__.c.PackageBaseID] + } - UsersID = Column( - Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) User = relationship( _User, backref=backref("package_votes", lazy="dynamic"), - foreign_keys=[UsersID]) + foreign_keys=[__table__.c.UsersID]) - PackageBaseID = Column( - Integer, ForeignKey("PackageBases.ID", ondelete="CASCADE"), - nullable=False) PackageBase = relationship( _PackageBase, backref=backref("package_votes", lazy="dynamic"), - foreign_keys=[PackageBaseID]) - - __mapper_args__ = {"primary_key": [UsersID, PackageBaseID]} + foreign_keys=[__table__.c.PackageBaseID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/relation_type.py b/aurweb/models/relation_type.py index 71b6adbb..b52c91ec 100644 --- a/aurweb/models/relation_type.py +++ b/aurweb/models/relation_type.py @@ -1,27 +1,19 @@ -from sqlalchemy import Column, Integer - -from aurweb import db +from aurweb import schema from aurweb.models.declarative import Base CONFLICTS = "conflicts" PROVIDES = "provides" REPLACES = "replaces" +CONFLICTS_ID = 1 +PROVIDES_ID = 2 +REPLACES_ID = 3 + class RelationType(Base): - __tablename__ = "RelationTypes" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.RelationTypes + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def __init__(self, Name: str = None): self.Name = Name - - -CONFLICTS_ID = db.query(RelationType).filter( - RelationType.Name == CONFLICTS).first().ID -PROVIDES_ID = db.query(RelationType).filter( - RelationType.Name == PROVIDES).first().ID -REPLACES_ID = db.query(RelationType).filter( - RelationType.Name == REPLACES).first().ID diff --git a/aurweb/models/request_type.py b/aurweb/models/request_type.py index 4578464c..cabab3d2 100644 --- a/aurweb/models/request_type.py +++ b/aurweb/models/request_type.py @@ -1,25 +1,20 @@ -from sqlalchemy import Column, Integer - -from aurweb import db +from aurweb import schema from aurweb.models.declarative import Base DELETION = "deletion" ORPHAN = "orphan" MERGE = "merge" +DELETION_ID = 1 +ORPHAN_ID = 2 +MERGE_ID = 3 + class RequestType(Base): - __tablename__ = "RequestTypes" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.RequestTypes + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def name_display(self) -> str: """ Return the Name column with its first char capitalized. """ return self.Name.title() - - -DELETION_ID = db.query(RequestType, RequestType.Name == DELETION).first().ID -ORPHAN_ID = db.query(RequestType, RequestType.Name == ORPHAN).first().ID -MERGE_ID = db.query(RequestType, RequestType.Name == MERGE).first().ID diff --git a/aurweb/models/session.py b/aurweb/models/session.py index a4034678..96f88d85 100644 --- a/aurweb/models/session.py +++ b/aurweb/models/session.py @@ -1,23 +1,20 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.db import make_random_value, query from aurweb.models.declarative import Base from aurweb.models.user import User as _User class Session(Base): - __tablename__ = "Sessions" + __table__ = schema.Sessions + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.UsersID]} - UsersID = Column( - Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) User = relationship( _User, backref=backref("session", uselist=False), - foreign_keys=[UsersID]) - - __mapper_args__ = {"primary_key": [UsersID]} + foreign_keys=[__table__.c.UsersID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/ssh_pub_key.py b/aurweb/models/ssh_pub_key.py index 268a585b..789be629 100644 --- a/aurweb/models/ssh_pub_key.py +++ b/aurweb/models/ssh_pub_key.py @@ -3,30 +3,23 @@ import tempfile from subprocess import PIPE, Popen -from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base class SSHPubKey(Base): - __tablename__ = "SSHPubKeys" + __table__ = schema.SSHPubKeys + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.Fingerprint]} - UserID = Column( - Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) User = relationship( "User", backref=backref("ssh_pub_key", uselist=False), - foreign_keys=[UserID]) - - Fingerprint = Column(String(44), primary_key=True) - - __mapper_args__ = {"primary_key": Fingerprint} + foreign_keys=[__table__.c.UserID]) def __init__(self, **kwargs): - self.UserID = kwargs.get("UserID") - self.Fingerprint = kwargs.get("Fingerprint") - self.PubKey = kwargs.get("PubKey") + super().__init__(**kwargs) def get_fingerprint(pubkey): diff --git a/aurweb/models/term.py b/aurweb/models/term.py index 0985cd76..59534bbc 100644 --- a/aurweb/models/term.py +++ b/aurweb/models/term.py @@ -1,15 +1,13 @@ -from sqlalchemy import Column, Integer from sqlalchemy.exc import IntegrityError +from aurweb import schema from aurweb.models.declarative import Base class Term(Base): - __tablename__ = "Terms" - - ID = Column(Integer, primary_key=True) - - __mapper_args__ = {"primary_key": [ID]} + __table__ = schema.Terms + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/tu_vote.py b/aurweb/models/tu_vote.py index 634c041e..efb23b19 100644 --- a/aurweb/models/tu_vote.py +++ b/aurweb/models/tu_vote.py @@ -1,28 +1,26 @@ -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.tu_voteinfo import TUVoteInfo as _TUVoteInfo from aurweb.models.user import User as _User class TUVote(Base): - __tablename__ = "TU_Votes" + __table__ = schema.TU_Votes + __tablename__ = __table__.name + __mapper_args__ = { + "primary_key": [__table__.c.VoteID, __table__.c.UserID] + } - VoteID = Column(Integer, ForeignKey("TU_VoteInfo.ID", ondelete="CASCADE"), - nullable=False) VoteInfo = relationship( _TUVoteInfo, backref=backref("tu_votes", lazy="dynamic"), - foreign_keys=[VoteID]) + foreign_keys=[__table__.c.VoteID]) - UserID = Column(Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) User = relationship( _User, backref=backref("tu_votes", lazy="dynamic"), - foreign_keys=[UserID]) - - __mapper_args__ = {"primary_key": [VoteID, UserID]} + foreign_keys=[__table__.c.UserID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/tu_voteinfo.py b/aurweb/models/tu_voteinfo.py index da43b097..35675ccc 100644 --- a/aurweb/models/tu_voteinfo.py +++ b/aurweb/models/tu_voteinfo.py @@ -2,27 +2,22 @@ import typing from datetime import datetime -from sqlalchemy import Column, ForeignKey, Integer from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship +from aurweb import schema from aurweb.models.declarative import Base from aurweb.models.user import User as _User class TUVoteInfo(Base): - __tablename__ = "TU_VoteInfo" + __table__ = schema.TU_VoteInfo + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} - ID = Column(Integer, primary_key=True) - - SubmitterID = Column( - Integer, ForeignKey("Users.ID", ondelete="CASCADE"), - nullable=False) Submitter = relationship( _User, backref=backref("tu_voteinfo_set", lazy="dynamic"), - foreign_keys=[SubmitterID]) - - __mapper_args__ = {"primary_key": [ID]} + foreign_keys=[__table__.c.SubmitterID]) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index e4223144..8db34c38 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -5,14 +5,14 @@ from datetime import datetime import bcrypt from fastapi import Request -from sqlalchemy import Column, ForeignKey, Integer, String, or_, text +from sqlalchemy import or_ from sqlalchemy.orm import backref, relationship import aurweb.config import aurweb.models.account_type import aurweb.schema -from aurweb import db +from aurweb import db, schema from aurweb.models.account_type import AccountType as _AccountType from aurweb.models.ban import is_banned from aurweb.models.declarative import Base @@ -22,23 +22,16 @@ SALT_ROUNDS_DEFAULT = 12 class User(Base): """ An ORM model of a single Users record. """ - __tablename__ = "Users" + __table__ = schema.Users + __tablename__ = __table__.name + __mapper_args__ = {"primary_key": [__table__.c.ID]} - ID = Column(Integer, primary_key=True) - - AccountTypeID = Column( - Integer, ForeignKey("AccountTypes.ID", ondelete="NO ACTION"), - nullable=False, server_default=text("1")) AccountType = relationship( _AccountType, backref=backref("users", lazy="dynamic"), - foreign_keys=[AccountTypeID], + foreign_keys=[__table__.c.AccountTypeID], uselist=False) - Passwd = Column(String(255), default=str()) - - __mapper_args__ = {"primary_key": [ID]} - # High-level variables used to track authentication (not in DB). authenticated = False nonce = None @@ -49,7 +42,7 @@ class User(Base): SALT_ROUNDS_DEFAULT) def __init__(self, Passwd: str = str(), **kwargs): - super().__init__(**kwargs) + super().__init__(**kwargs, Passwd=str()) # Run this again in the constructor in case we rehashed config. self.salt_rounds = aurweb.config.getint("options", "salt_rounds", From 3517862ecdaf665693bbfb6e06fe547249d34005 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 8 Nov 2021 18:46:21 -0800 Subject: [PATCH 1065/1891] change(poetry): use kevr@upgrade-starlette-0.17.0 as fastapi source Starlette 0.16.0 has a pretty bad bug in terms of logging which has been fixed in the 0.17.0 release. That being said, FastAPI has not yet merged a request at https://github.com/tiangolo/fastapi/pull/4145 which resolves this dependency resolution so we can use the updated starlette package. kevr has forked the pull request in question and we are using it for now in our poetry dependencies to get ahead of the game. When FastAPI upstream is updated to support 0.17.0, we'll need to switch this back to using upstream's source. Signed-off-by: Kevin Morris --- poetry.lock | 317 +++++++++++++++++++++++++++---------------------- pyproject.toml | 2 +- 2 files changed, 177 insertions(+), 142 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9f528d12..37e2f8f9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -165,7 +165,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.0.2" +version = "6.1.1" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -213,12 +213,15 @@ trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"] [[package]] name = "dunamai" -version = "1.6.0" +version = "1.7.0" description = "Dynamic version generation" category = "main" optional = false python-versions = ">=3.5,<4.0" +[package.dependencies] +packaging = ">=20.9" + [[package]] name = "email-validator" version = "1.1.3" @@ -256,10 +259,11 @@ description = "FastAPI framework, high performance, easy to learn, fast to code, category = "main" optional = false python-versions = ">=3.6.1" +develop = false [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.16.0" +starlette = "0.17.0" [package.extras] all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] @@ -267,6 +271,12 @@ dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,< doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] +[package.source] +type = "git" +url = "https://github.com/kevr/fastapi.git" +reference = "upgrade-starlette-0.17.0" +resolved_reference = "5d2d79e6bafd86564c318b7f99153132cd6ca466" + [[package]] name = "feedgen" version = "0.9.0" @@ -428,7 +438,7 @@ python-versions = "*" [[package]] name = "isort" -version = "5.9.3" +version = "5.10.0" description = "A Python utility / library to sort Python imports." category = "dev" optional = false @@ -464,7 +474,7 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "lxml" -version = "4.6.3" +version = "4.6.4" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." category = "main" optional = false @@ -544,14 +554,14 @@ python-versions = ">=3.7" [[package]] name = "packaging" -version = "21.0" +version = "21.2" description = "Core utilities for Python packages" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" +pyparsing = ">=2.0.2,<3" [[package]] name = "paginate" @@ -619,7 +629,7 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "3.19.0" +version = "3.19.1" description = "Protocol Buffers" category = "main" optional = false @@ -627,11 +637,11 @@ python-versions = ">=3.5" [[package]] name = "py" -version = "1.10.0" +version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pycodestyle" @@ -643,7 +653,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pycparser" -version = "2.20" +version = "2.21" description = "C parser in Python" category = "main" optional = false @@ -743,7 +753,7 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale [[package]] name = "pytest-tap" -version = "3.2" +version = "3.3" description = "Test Anything Protocol (TAP) reporting plugin for pytest" category = "dev" optional = false @@ -876,7 +886,7 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "starlette" -version = "0.16.0" +version = "0.17.0" description = "The little ASGI library that shines." category = "main" optional = false @@ -886,7 +896,7 @@ python-versions = ">=3.6" anyio = ">=3.0.0,<4" [package.extras] -full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] +full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] [[package]] name = "tap.py" @@ -909,7 +919,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" -version = "1.2.1" +version = "1.2.2" description = "A lil' TOML parser" category = "dev" optional = false @@ -993,7 +1003,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "569b0489389b884d269458f8e4252efcf3ebbbaa5fa77b6d09d7f0cdbda53362" +content-hash = "356b37d545d78b8aa1e1939f42522207bcf79526abe8193308c5a2955897d6fd" [metadata.files] aiofiles = [ @@ -1106,39 +1116,55 @@ colorama = [ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1549e1d08ce38259de2bc3e9a0d5f3642ff4a8f500ffc1b2df73fd621a6cdfc0"}, - {file = "coverage-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcae10fccb27ca2a5f456bf64d84110a5a74144be3136a5e598f9d9fb48c0caa"}, - {file = "coverage-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:53a294dc53cfb39c74758edaa6305193fb4258a30b1f6af24b360a6c8bd0ffa7"}, - {file = "coverage-6.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8251b37be1f2cd9c0e5ccd9ae0380909c24d2a5ed2162a41fcdbafaf59a85ebd"}, - {file = "coverage-6.0.2-cp310-cp310-win32.whl", hash = "sha256:db42baa892cba723326284490283a68d4de516bfb5aaba369b4e3b2787a778b7"}, - {file = "coverage-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:bbffde2a68398682623d9dd8c0ca3f46fda074709b26fcf08ae7a4c431a6ab2d"}, - {file = "coverage-6.0.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:60e51a3dd55540bec686d7fff61b05048ca31e804c1f32cbb44533e6372d9cc3"}, - {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a6a9409223a27d5ef3cca57dd7cd4dfcb64aadf2fad5c3b787830ac9223e01a"}, - {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4b34ae4f51bbfa5f96b758b55a163d502be3dcb24f505d0227858c2b3f94f5b9"}, - {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bbda1b550e70fa6ac40533d3f23acd4f4e9cb4e6e77251ce77fdf41b3309fb2"}, - {file = "coverage-6.0.2-cp36-cp36m-win32.whl", hash = "sha256:4e28d2a195c533b58fc94a12826f4431726d8eb029ac21d874345f943530c122"}, - {file = "coverage-6.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a82d79586a0a4f5fd1cf153e647464ced402938fbccb3ffc358c7babd4da1dd9"}, - {file = "coverage-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3be1206dc09fb6298de3fce70593e27436862331a85daee36270b6d0e1c251c4"}, - {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9cd3828bbe1a40070c11fe16a51df733fd2f0cb0d745fb83b7b5c1f05967df7"}, - {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d036dc1ed8e1388e995833c62325df3f996675779541f682677efc6af71e96cc"}, - {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04560539c19ec26995ecfb3d9307ff154fbb9a172cb57e3b3cfc4ced673103d1"}, - {file = "coverage-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:e4fb7ced4d9dec77d6cf533acfbf8e1415fe799430366affb18d69ee8a3c6330"}, - {file = "coverage-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:77b1da5767ed2f44611bc9bc019bc93c03fa495728ec389759b6e9e5039ac6b1"}, - {file = "coverage-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61b598cbdbaae22d9e34e3f675997194342f866bb1d781da5d0be54783dce1ff"}, - {file = "coverage-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36e9040a43d2017f2787b28d365a4bb33fcd792c7ff46a047a04094dc0e2a30d"}, - {file = "coverage-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9f1627e162e3864a596486774876415a7410021f4b67fd2d9efdf93ade681afc"}, - {file = "coverage-6.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e7a0b42db2a47ecb488cde14e0f6c7679a2c5a9f44814393b162ff6397fcdfbb"}, - {file = "coverage-6.0.2-cp38-cp38-win32.whl", hash = "sha256:a1b73c7c4d2a42b9d37dd43199c5711d91424ff3c6c22681bc132db4a4afec6f"}, - {file = "coverage-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:1db67c497688fd4ba85b373b37cc52c50d437fd7267520ecd77bddbd89ea22c9"}, - {file = "coverage-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f2f184bf38e74f152eed7f87e345b51f3ab0b703842f447c22efe35e59942c24"}, - {file = "coverage-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1cf1deb3d5544bd942356364a2fdc8959bad2b6cf6eb17f47d301ea34ae822"}, - {file = "coverage-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad9b8c1206ae41d46ec7380b78ba735ebb77758a650643e841dd3894966c31d0"}, - {file = "coverage-6.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:381d773d896cc7f8ba4ff3b92dee4ed740fb88dfe33b6e42efc5e8ab6dfa1cfe"}, - {file = "coverage-6.0.2-cp39-cp39-win32.whl", hash = "sha256:424c44f65e8be58b54e2b0bd1515e434b940679624b1b72726147cfc6a9fc7ce"}, - {file = "coverage-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:abbff240f77347d17306d3201e14431519bf64495648ca5a49571f988f88dee9"}, - {file = "coverage-6.0.2-pp36-none-any.whl", hash = "sha256:7092eab374346121805fb637572483270324407bf150c30a3b161fc0c4ca5164"}, - {file = "coverage-6.0.2-pp37-none-any.whl", hash = "sha256:30922626ce6f7a5a30bdba984ad21021529d3d05a68b4f71ea3b16bda35b8895"}, - {file = "coverage-6.0.2.tar.gz", hash = "sha256:6807947a09510dc31fa86f43595bf3a14017cd60bf633cc746d52141bfa6b149"}, + {file = "coverage-6.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42a1fb5dee3355df90b635906bb99126faa7936d87dfc97eacc5293397618cb7"}, + {file = "coverage-6.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a00284dbfb53b42e35c7dd99fc0e26ef89b4a34efff68078ed29d03ccb28402a"}, + {file = "coverage-6.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:51a441011a30d693e71dea198b2a6f53ba029afc39f8e2aeb5b77245c1b282ef"}, + {file = "coverage-6.1.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e76f017b6d4140a038c5ff12be1581183d7874e41f1c0af58ecf07748d36a336"}, + {file = "coverage-6.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7833c872718dc913f18e51ee97ea0dece61d9930893a58b20b3daf09bb1af6b6"}, + {file = "coverage-6.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8186b5a4730c896cbe1e4b645bdc524e62d874351ae50e1db7c3e9f5dc81dc26"}, + {file = "coverage-6.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbca34dca5a2d60f81326d908d77313816fad23d11b6069031a3d6b8c97a54f9"}, + {file = "coverage-6.1.1-cp310-cp310-win32.whl", hash = "sha256:72bf437d54186d104388cbae73c9f2b0f8a3e11b6e8d7deb593bd14625c96026"}, + {file = "coverage-6.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:994ce5a7b3d20981b81d83618aa4882f955bfa573efdbef033d5632b58597ba9"}, + {file = "coverage-6.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ab6a0fe4c96f8058d41948ddf134420d3ef8c42d5508b5a341a440cce7a37a1d"}, + {file = "coverage-6.1.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10ab138b153e4cc408b43792cb7f518f9ee02f4ff55cd1ab67ad6fd7e9905c7e"}, + {file = "coverage-6.1.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7e083d32965d2eb6638a77e65b622be32a094fdc0250f28ce6039b0732fbcaa8"}, + {file = "coverage-6.1.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:359a32515e94e398a5c0fa057e5887a42e647a9502d8e41165cf5cb8d3d1ca67"}, + {file = "coverage-6.1.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:bf656cd74ff7b4ed7006cdb2a6728150aaad69c7242b42a2a532f77b63ea233f"}, + {file = "coverage-6.1.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:dc5023be1c2a8b0a0ab5e31389e62c28b2453eb31dd069f4b8d1a0f9814d951a"}, + {file = "coverage-6.1.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:557594a50bfe3fb0b1b57460f6789affe8850ad19c1acf2d14a3e12b2757d489"}, + {file = "coverage-6.1.1-cp36-cp36m-win32.whl", hash = "sha256:9eb0a1923354e0fdd1c8a6f53f5db2e6180d670e2b587914bf2e79fa8acfd003"}, + {file = "coverage-6.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:04a92a6cf9afd99f9979c61348ec79725a9f9342fb45e63c889e33c04610d97b"}, + {file = "coverage-6.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:479228e1b798d3c246ac89b09897ee706c51b3e5f8f8d778067f38db73ccc717"}, + {file = "coverage-6.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78287731e3601ea5ce9d6468c82d88a12ef8fe625d6b7bdec9b45d96c1ad6533"}, + {file = "coverage-6.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c95257aa2ccf75d3d91d772060538d5fea7f625e48157f8ca44594f94d41cb33"}, + {file = "coverage-6.1.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9ad5895938a894c368d49d8470fe9f519909e5ebc6b8f8ea5190bd0df6aa4271"}, + {file = "coverage-6.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:326d944aad0189603733d646e8d4a7d952f7145684da973c463ec2eefe1387c2"}, + {file = "coverage-6.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e7d5606b9240ed4def9cbdf35be4308047d11e858b9c88a6c26974758d6225ce"}, + {file = "coverage-6.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:572f917267f363101eec375c109c9c1118037c7cc98041440b5eabda3185ac7b"}, + {file = "coverage-6.1.1-cp37-cp37m-win32.whl", hash = "sha256:35cd2230e1ed76df7d0081a997f0fe705be1f7d8696264eb508076e0d0b5a685"}, + {file = "coverage-6.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:65ad3ff837c89a229d626b8004f0ee32110f9bfdb6a88b76a80df36ccc60d926"}, + {file = "coverage-6.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:977ce557d79577a3dd510844904d5d968bfef9489f512be65e2882e1c6eed7d8"}, + {file = "coverage-6.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62512c0ec5d307f56d86504c58eace11c1bc2afcdf44e3ff20de8ca427ca1d0e"}, + {file = "coverage-6.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2e5b9c17a56b8bf0c0a9477fcd30d357deb486e4e1b389ed154f608f18556c8a"}, + {file = "coverage-6.1.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:666c6b32b69e56221ad1551d377f718ed00e6167c7a1b9257f780b105a101271"}, + {file = "coverage-6.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fb2fa2f6506c03c48ca42e3fe5a692d7470d290c047ee6de7c0f3e5fa7639ac9"}, + {file = "coverage-6.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f0f80e323a17af63eac6a9db0c9188c10f1fd815c3ab299727150cc0eb92c7a4"}, + {file = "coverage-6.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:738e823a746841248b56f0f3bd6abf3b73af191d1fd65e4c723b9c456216f0ad"}, + {file = "coverage-6.1.1-cp38-cp38-win32.whl", hash = "sha256:8605add58e6a960729aa40c0fd9a20a55909dd9b586d3e8104cc7f45869e4c6b"}, + {file = "coverage-6.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:6e994003e719458420e14ffb43c08f4c14990e20d9e077cb5cad7a3e419bbb54"}, + {file = "coverage-6.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e3c4f5211394cd0bf6874ac5d29684a495f9c374919833dcfff0bd6d37f96201"}, + {file = "coverage-6.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e14bceb1f3ae8a14374be2b2d7bc12a59226872285f91d66d301e5f41705d4d6"}, + {file = "coverage-6.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0147f7833c41927d84f5af9219d9b32f875c0689e5e74ac8ca3cb61e73a698f9"}, + {file = "coverage-6.1.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b1d0a1bce919de0dd8da5cff4e616b2d9e6ebf3bd1410ff645318c3dd615010a"}, + {file = "coverage-6.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ae6de0e41f44794e68d23644636544ed8003ce24845f213b24de097cbf44997f"}, + {file = "coverage-6.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2797ed7a7e883b9ab76e8e778bb4c859fc2037d6fd0644d8675e64d58d1653"}, + {file = "coverage-6.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c40966b683d92869b72ea3c11fd6b99a091fd30e12652727eca117273fc97366"}, + {file = "coverage-6.1.1-cp39-cp39-win32.whl", hash = "sha256:a11a2c019324fc111485e79d55907e7289e53d0031275a6c8daed30690bc50c0"}, + {file = "coverage-6.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:4d8b453764b9b26b0dd2afb83086a7c3f9379134e340288d2a52f8a91592394b"}, + {file = "coverage-6.1.1-pp36-none-any.whl", hash = "sha256:3b270c6b48d3ff5a35deb3648028ba2643ad8434b07836782b1139cf9c66313f"}, + {file = "coverage-6.1.1-pp37-none-any.whl", hash = "sha256:ffa8fee2b1b9e60b531c4c27cf528d6b5d5da46b1730db1f4d6eee56ff282e07"}, + {file = "coverage-6.1.1-pp38-none-any.whl", hash = "sha256:4cd919057636f63ab299ccb86ea0e78b87812400c76abab245ca385f17d19fb5"}, + {file = "coverage-6.1.1.tar.gz", hash = "sha256:b8e4f15b672c9156c1154249a9c5746e86ac9ae9edc3799ee3afebc323d9d9e0"}, ] cryptography = [ {file = "cryptography-35.0.0-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:d57e0cdc1b44b6cdf8af1d01807db06886f10177469312fbde8f44ccbb284bc9"}, @@ -1167,8 +1193,8 @@ dnspython = [ {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"}, ] dunamai = [ - {file = "dunamai-1.6.0-py3-none-any.whl", hash = "sha256:44a94a4edebb145bb6198a2f26de957b12b77d43b7c9c0646be814c60cf5d8df"}, - {file = "dunamai-1.6.0.tar.gz", hash = "sha256:6f1111f47e869ed58d44a7d37f112e3e7c761dce3c71f2c5464526928d7e9896"}, + {file = "dunamai-1.7.0-py3-none-any.whl", hash = "sha256:375e017eb014681e9c8f6e7f2c4c2065ef35832d429f8b70900bed24e8be83f8"}, + {file = "dunamai-1.7.0.tar.gz", hash = "sha256:6abfeb91768caea59d65a4989cec49472fa66ee04dcd6a5c9f92ebc019926a93"}, ] email-validator = [ {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, @@ -1178,10 +1204,7 @@ fakeredis = [ {file = "fakeredis-1.6.1-py3-none-any.whl", hash = "sha256:5eb1516f1fe1813e9da8f6c482178fc067af09f53de587ae03887ef5d9d13024"}, {file = "fakeredis-1.6.1.tar.gz", hash = "sha256:0d06a9384fb79da9f2164ce96e34eb9d4e2ea46215070805ea6fd3c174590b47"}, ] -fastapi = [ - {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, - {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, -] +fastapi = [] feedgen = [ {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, ] @@ -1282,8 +1305,8 @@ iniconfig = [ {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] isort = [ - {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, - {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, + {file = "isort-5.10.0-py3-none-any.whl", hash = "sha256:1a18ccace2ed8910bd9458b74a3ecbafd7b2f581301b0ab65cfdd4338272d76f"}, + {file = "isort-5.10.0.tar.gz", hash = "sha256:e52ff6d38012b131628cf0f26c51e7bd3a7c81592eefe3ac71411e692f1b9345"}, ] itsdangerous = [ {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, @@ -1294,54 +1317,66 @@ jinja2 = [ {file = "Jinja2-3.0.2.tar.gz", hash = "sha256:827a0e32839ab1600d4eb1c4c33ec5a8edfbc5cb42dafa13b81f182f97784b45"}, ] lxml = [ - {file = "lxml-4.6.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2"}, - {file = "lxml-4.6.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1b7584d421d254ab86d4f0b13ec662a9014397678a7c4265a02a6d7c2b18a75f"}, - {file = "lxml-4.6.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d"}, - {file = "lxml-4.6.3-cp27-cp27m-win32.whl", hash = "sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106"}, - {file = "lxml-4.6.3-cp27-cp27m-win_amd64.whl", hash = "sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee"}, - {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f"}, - {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4"}, - {file = "lxml-4.6.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:64812391546a18896adaa86c77c59a4998f33c24788cadc35789e55b727a37f4"}, - {file = "lxml-4.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c1a40c06fd5ba37ad39caa0b3144eb3772e813b5fb5b084198a985431c2f1e8d"}, - {file = "lxml-4.6.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51"}, - {file = "lxml-4.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"}, - {file = "lxml-4.6.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354"}, - {file = "lxml-4.6.3-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16"}, - {file = "lxml-4.6.3-cp35-cp35m-win32.whl", hash = "sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2"}, - {file = "lxml-4.6.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4"}, - {file = "lxml-4.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4"}, - {file = "lxml-4.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3"}, - {file = "lxml-4.6.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d"}, - {file = "lxml-4.6.3-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d916d31fd85b2f78c76400d625076d9124de3e4bda8b016d25a050cc7d603f24"}, - {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec"}, - {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617"}, - {file = "lxml-4.6.3-cp36-cp36m-win32.whl", hash = "sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04"}, - {file = "lxml-4.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a"}, - {file = "lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654"}, - {file = "lxml-4.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0"}, - {file = "lxml-4.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3"}, - {file = "lxml-4.6.3-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:36108c73739985979bf302006527cf8a20515ce444ba916281d1c43938b8bb96"}, - {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2"}, - {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92"}, - {file = "lxml-4.6.3-cp37-cp37m-win32.whl", hash = "sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade"}, - {file = "lxml-4.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b"}, - {file = "lxml-4.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa"}, - {file = "lxml-4.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a"}, - {file = "lxml-4.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927"}, - {file = "lxml-4.6.3-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:e1cbd3f19a61e27e011e02f9600837b921ac661f0c40560eefb366e4e4fb275e"}, - {file = "lxml-4.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791"}, - {file = "lxml-4.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1b38116b6e628118dea5b2186ee6820ab138dbb1e24a13e478490c7db2f326ae"}, - {file = "lxml-4.6.3-cp38-cp38-win32.whl", hash = "sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28"}, - {file = "lxml-4.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7"}, - {file = "lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0"}, - {file = "lxml-4.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1"}, - {file = "lxml-4.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23"}, - {file = "lxml-4.6.3-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3082c518be8e97324390614dacd041bb1358c882d77108ca1957ba47738d9d59"}, - {file = "lxml-4.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969"}, - {file = "lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a"}, - {file = "lxml-4.6.3-cp39-cp39-win32.whl", hash = "sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f"}, - {file = "lxml-4.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83"}, - {file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"}, + {file = "lxml-4.6.4-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bbf2dc330bd44bfc0254ab37677ec60f7c7ecea55ad8ba1b8b2ea7bf20c265f5"}, + {file = "lxml-4.6.4-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b667c51682fe9b9788c69465956baa8b6999531876ccedcafc895c74ad716cd8"}, + {file = "lxml-4.6.4-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:72e730d33fe2e302fd07285f14624fca5e5e2fb2bb4fb2c3941e318c41c443d1"}, + {file = "lxml-4.6.4-cp27-cp27m-win32.whl", hash = "sha256:433df8c7dde0f9e41cbf4f36b0829d50a378116ef5e962ba3881f2f5f025c7be"}, + {file = "lxml-4.6.4-cp27-cp27m-win_amd64.whl", hash = "sha256:35752ee40f7bbf6adc9ff4e1f4b84794a3593736dcce80db32e3c2aa85e294ac"}, + {file = "lxml-4.6.4-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ff5bb2a198ea67403bb6818705e9a4f90e0313f2215428ec51001ce56d939fb"}, + {file = "lxml-4.6.4-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9b87727561c1150c0cc91c5d9d389448b37a7d15f0ba939ed3d1acb2f11bf6c5"}, + {file = "lxml-4.6.4-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:45fdb2899c755138722797161547a40b3e2a06feda620cc41195ee7e97806d81"}, + {file = "lxml-4.6.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:38b9de0de3aa689fe9fb9877ae1be1e83b8cf9621f7e62049d0436b9ecf4ad64"}, + {file = "lxml-4.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:662523cd2a0246740225c7e32531f2e766544122e58bee70e700a024cfc0cf81"}, + {file = "lxml-4.6.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:4aa349c5567651f34d4eaae7de6ed5b523f6d70a288f9c6fbac22d13a0784e04"}, + {file = "lxml-4.6.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:08eb9200d88b376a8ed5e50f1dc1d1a45b49305169674002a3b5929943390591"}, + {file = "lxml-4.6.4-cp310-cp310-win32.whl", hash = "sha256:bdc224f216ead849e902151112efef6e96c41ee1322e15d4e5f7c8a826929aee"}, + {file = "lxml-4.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:ab6db93a2b6b66cbf62b4e4a7135f476e708e8c5c990d186584142c77d7f975a"}, + {file = "lxml-4.6.4-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50790313df028aa05cf22be9a8da033b86c42fa32523e4fd944827b482b17bf0"}, + {file = "lxml-4.6.4-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6764998345552b1dfc9326a932d2bad6367c6b37a176bb73ada6b9486bf602f7"}, + {file = "lxml-4.6.4-cp35-cp35m-win32.whl", hash = "sha256:543b239b191bb3b6d9bef5f09f1fb2be5b7eb09ab4d386aa655e4d53fbe9ff47"}, + {file = "lxml-4.6.4-cp35-cp35m-win_amd64.whl", hash = "sha256:a75c1ad05eedb1a3ff2a34a52a4f0836cfaa892e12796ba39a7732c82701eff4"}, + {file = "lxml-4.6.4-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:47e955112ce64241fdb357acf0216081f9f3255b3ac9c502ca4b3323ec1ca558"}, + {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:20d7c8d90d449c6a353b15ee0459abae8395dbe59ad01e406ccbf30cd81c6f98"}, + {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:240db6f3228d26e3c6f4fad914b9ddaaf8707254e8b3efd564dc680c8ec3c264"}, + {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:351482da8dd028834028537f08724b1de22d40dcf3bb723b469446564f409074"}, + {file = "lxml-4.6.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e678a643177c0e5ec947b645fa7bc84260dfb9b6bf8fb1fdd83008dfc2ca5928"}, + {file = "lxml-4.6.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:15d0381feb56f08f78c5cc4fc385ddfe0bde1456e37f54a9322833371aec4060"}, + {file = "lxml-4.6.4-cp36-cp36m-win32.whl", hash = "sha256:4ba74afe5ee5cb5e28d83b513a6e8f0875fda1dc1a9aea42cc0065f029160d2a"}, + {file = "lxml-4.6.4-cp36-cp36m-win_amd64.whl", hash = "sha256:9c91a73971a922c13070fd8fa5a114c858251791ba2122a941e6aa781c713e44"}, + {file = "lxml-4.6.4-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:6020c70ff695106bf80651953a23e37718ef1fee9abd060dcad8e32ab2dc13f3"}, + {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f5dd358536b8a964bf6bd48de038754c1609e72e5f17f5d21efe2dda17594dbf"}, + {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7ae7089d81fc502df4b217ad77f03c54039fe90dac0acbe70448d7e53bfbc57e"}, + {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:80d10d53d3184837445ff8562021bdd37f57c4cadacbf9d8726cc16220a00d54"}, + {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e95da348d57eb448d226a44b868ff2ca5786fbcbe417ac99ff62d0a7d724b9c7"}, + {file = "lxml-4.6.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ffd65cfa33fed01735c82aca640fde4cc63f0414775cba11e06f84fae2085a6e"}, + {file = "lxml-4.6.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:877666418598f6cb289546c77ff87590cfd212f903b522b0afa0b9fb73b3ccfb"}, + {file = "lxml-4.6.4-cp37-cp37m-win32.whl", hash = "sha256:e91d24623e747eeb2d8121f4a94c6a7ad27dc48e747e2dc95bfe88632bd028a2"}, + {file = "lxml-4.6.4-cp37-cp37m-win_amd64.whl", hash = "sha256:4ec9a80dd5704ecfde54319b6964368daf02848c8954d3bacb9b64d1c7659159"}, + {file = "lxml-4.6.4-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:2901625f4a878a055d275beedc20ba9cb359cefc4386a967222fee29eb236038"}, + {file = "lxml-4.6.4-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b567178a74a2261345890eac66fbf394692a6e002709d329f28a673ca6042473"}, + {file = "lxml-4.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4717123f7c11c81e0da69989e5a64079c3f402b0efeb4c6241db6c369d657bd8"}, + {file = "lxml-4.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:cf201bf5594d1aab139fe53e3fca457e4f8204a5bbd65d48ab3b82a16f517868"}, + {file = "lxml-4.6.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a77a3470ba37e11872c75ca95baf9b3312133a3d5a5dc720803b23098c653976"}, + {file = "lxml-4.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:619c6d2b552bba00491e96c0518aad94002651c108a0f7364ff2d7798812c00e"}, + {file = "lxml-4.6.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:601f0ab75538b280aaf1e720eb9d68d4fa104ac274e1e9e6971df488f4dcdb0f"}, + {file = "lxml-4.6.4-cp38-cp38-win32.whl", hash = "sha256:75d3c5bbc0ddbad03bb68b9be638599f67e4b98ed3dcd0fec9f6f39e41ee96cb"}, + {file = "lxml-4.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:4341d135f5660db10184963d9c3418c3e28d7f868aaf8b11a323ebf85813f7f4"}, + {file = "lxml-4.6.4-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:9db24803fa71e3305fe4a7812782b708da21a0b774b130dd1860cf40a6d7a3ee"}, + {file = "lxml-4.6.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:afd60230ad9d8bcba005945ec3a343722f09e0b7f8ae804246e5d2cfc6bd71a6"}, + {file = "lxml-4.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:0c15e1cd55055956e77b0732270f1c6005850696bc3ef3e03d01e78af84eaa42"}, + {file = "lxml-4.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d422b3c729737d8a39279a25fa156c983a56458f8b2f97661ee6fb22b80b1d6"}, + {file = "lxml-4.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2eb90f6ec3c236ef2f1bb38aee7c0d23e77d423d395af6326e7cca637519a4cb"}, + {file = "lxml-4.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:51a0e5d243687596f46e24e464121d4b232ad772e2d1785b2a2c0eb413c285d4"}, + {file = "lxml-4.6.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d43bd68714049c84e297c005456a15ecdec818f7b5aa5868c8b0a865cfb78a44"}, + {file = "lxml-4.6.4-cp39-cp39-win32.whl", hash = "sha256:ee9e4b07b0eba4b6a521509e9e1877476729c1243246b6959de697ebea739643"}, + {file = "lxml-4.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:48eaac2991b3036175b42ee8d3c23f4cca13f2be8426bf29401a690ab58c88f4"}, + {file = "lxml-4.6.4-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:2b06a91cf7b8acea7793006e4ae50646cef0fe35ce5acd4f5cb1c77eb228e4a1"}, + {file = "lxml-4.6.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:523f195948a1ba4f9f5b7294d83c6cd876547dc741820750a7e5e893a24bbe38"}, + {file = "lxml-4.6.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b0ca0ada9d3bc18bd6f611bd001a28abdd49ab9698bd6d717f7f5394c8e94628"}, + {file = "lxml-4.6.4-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:197b7cb7a753cf553a45115739afd8458464a28913da00f5c525063f94cd3f48"}, + {file = "lxml-4.6.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:6298f5b42a26581206ef63fffa97c754245d329414108707c525512a5197f2ba"}, + {file = "lxml-4.6.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0b12c95542f04d10cba46b3ff28ea52ea56995b78cf918f0b11b05e75812bb79"}, + {file = "lxml-4.6.4.tar.gz", hash = "sha256:daf9bd1fee31f1c7a5928b3e1059e09a8d683ea58fb3ffc773b6c88cb8d1399c"}, ] mako = [ {file = "Mako-1.1.5-py2.py3-none-any.whl", hash = "sha256:6804ee66a7f6a6416910463b00d76a7b25194cd27f1918500c5bd7be2a088a23"}, @@ -1445,8 +1480,8 @@ orjson = [ {file = "orjson-3.6.4.tar.gz", hash = "sha256:f8dbc428fc6d7420f231a7133d8dff4c882e64acb585dcf2fda74bdcfe1a6d9d"}, ] packaging = [ - {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, - {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, + {file = "packaging-21.2-py3-none-any.whl", hash = "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0"}, + {file = "packaging-21.2.tar.gz", hash = "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966"}, ] paginate = [ {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, @@ -1472,42 +1507,42 @@ prometheus-fastapi-instrumentator = [ {file = "prometheus_fastapi_instrumentator-5.7.1-py3-none-any.whl", hash = "sha256:da40ea0df14b0e95d584769747fba777522a8df6a8c47cec2edf798f1fff49b5"}, ] protobuf = [ - {file = "protobuf-3.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:01a0645ef3acddfbc90237e1cdfae1086130fc7cb480b5874656193afd657083"}, - {file = "protobuf-3.19.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d3861c9721a90ba83ee0936a9cfcc4fa1c4b4144ac9658fb6f6343b38558e9b4"}, - {file = "protobuf-3.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b64be5d7270cf5e76375bac049846e8a9543a2d4368b69afe78ab725380a7487"}, - {file = "protobuf-3.19.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2f6046b9e2feee0dce994493186e8715b4392ed5f50f356280ad9c2f9f93080a"}, - {file = "protobuf-3.19.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac2f8ec942d414609aba0331952ae12bb823e8f424bbb6b8c422f1cef32dc842"}, - {file = "protobuf-3.19.0-cp36-cp36m-win32.whl", hash = "sha256:3fea09aa04ef2f8b01fcc9bb87f19509934f8a35d177c865b8f9ee5c32b60c1b"}, - {file = "protobuf-3.19.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d1f4277d321f60456845ca9b882c4845736f1f5c1c69eb778eba22a97977d8af"}, - {file = "protobuf-3.19.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8488c2276f14f294e890cc1260ab342a13e90cd20dcc03319d2eea258f1fd321"}, - {file = "protobuf-3.19.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:36bf292f44966c67080e535321501717f4f1eba30faef8f2cd4b0c745a027211"}, - {file = "protobuf-3.19.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99af73ae34c93e0e2ace57ea2e70243f34fc015c8c23fd39ee93652e726f7e7"}, - {file = "protobuf-3.19.0-cp37-cp37m-win32.whl", hash = "sha256:f7a031cf8e2fc14acc0ba694f6dff0a01e06b70d817eba6edc72ee6cc20517ac"}, - {file = "protobuf-3.19.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d4ca5f0c7bc8d2e6966ca3bbd85e9ebe7191b6e21f067896d4af6b28ecff29fe"}, - {file = "protobuf-3.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9a8a880593015ef2c83f7af797fa4fbf583b2c98b4bd94e46c5b61fee319d84b"}, - {file = "protobuf-3.19.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:6f16925f5c977dd7787973a50c242e60c22b1d1182aba6bec7bd02862579c10f"}, - {file = "protobuf-3.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9097327d277b0aa4a3224e61cd6850aef3269172397715299bcffc9f90293c9"}, - {file = "protobuf-3.19.0-cp38-cp38-win32.whl", hash = "sha256:708d04394a63ee9bdc797938b6e15ed5bf24a1cb37743eb3886fd74a5a67a234"}, - {file = "protobuf-3.19.0-cp38-cp38-win_amd64.whl", hash = "sha256:ee4d07d596357f51316b6ecf1cc1927660e9d5e418385bb1c51fd2496cd9bee7"}, - {file = "protobuf-3.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34a77b8fafdeb8f89fee2b7108ae60d8958d72e33478680cc1e05517892ecc46"}, - {file = "protobuf-3.19.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:4f93e0f6af796ddd1502225ff8ea25340ced186ca05b601c44d5c88b45ba80a0"}, - {file = "protobuf-3.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:942dd6bc8bd2a3c6a156d8ab0f80bd45313f22b78e1176283270054dcc8ca4c2"}, - {file = "protobuf-3.19.0-cp39-cp39-win32.whl", hash = "sha256:7b3867795708ac88fde8d6f34f0d9a50af56087e41f624bdb2e9ff808ea5dda7"}, - {file = "protobuf-3.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:a74432e9d28a6072a2359a0f49f81eb14dd718e7dbbfb6c0789b456c49e1f130"}, - {file = "protobuf-3.19.0-py2.py3-none-any.whl", hash = "sha256:c96e94d3e523a82caa3e5f74b35dd1c4884199358d01c950d95c341255ff48bc"}, - {file = "protobuf-3.19.0.tar.gz", hash = "sha256:6a1dc6584d24ef86f5b104bcad64fa0fe06ed36e5687f426e0445d363a041d18"}, + {file = "protobuf-3.19.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f"}, + {file = "protobuf-3.19.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6"}, + {file = "protobuf-3.19.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6"}, + {file = "protobuf-3.19.1-cp36-cp36m-win32.whl", hash = "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c"}, + {file = "protobuf-3.19.1-cp36-cp36m-win_amd64.whl", hash = "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942"}, + {file = "protobuf-3.19.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6"}, + {file = "protobuf-3.19.1-cp37-cp37m-win32.whl", hash = "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04"}, + {file = "protobuf-3.19.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea"}, + {file = "protobuf-3.19.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e"}, + {file = "protobuf-3.19.1-cp38-cp38-win32.whl", hash = "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3"}, + {file = "protobuf-3.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b"}, + {file = "protobuf-3.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560"}, + {file = "protobuf-3.19.1-cp39-cp39-win32.whl", hash = "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2"}, + {file = "protobuf-3.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002"}, + {file = "protobuf-3.19.1-py2.py3-none-any.whl", hash = "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17"}, + {file = "protobuf-3.19.1.tar.gz", hash = "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7"}, ] py = [ - {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, - {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pycodestyle = [ {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, ] pycparser = [ - {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, - {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] pydantic = [ {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, @@ -1575,8 +1610,8 @@ pytest-cov = [ {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] pytest-tap = [ - {file = "pytest-tap-3.2.tar.gz", hash = "sha256:1b585c4a636458dbd958d136381bbabb1752c5877d05fac7d6a6001a8a9ddc29"}, - {file = "pytest_tap-3.2-py3-none-any.whl", hash = "sha256:18f59047f8bc68247d37f807fae7f2f8897d2c7397aea2fd2870f0421dc566cb"}, + {file = "pytest-tap-3.3.tar.gz", hash = "sha256:5f0919a147cf0396b2f10d64d365a0bf8062e06543e93c675c9d37f5605e983c"}, + {file = "pytest_tap-3.3-py3-none-any.whl", hash = "sha256:4fbbc0e090c2e94f6199bee4e4f68ab3c5e176b37a72a589ad84e0f72a2fce55"}, ] python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, @@ -1648,8 +1683,8 @@ sqlalchemy = [ {file = "SQLAlchemy-1.4.26.tar.gz", hash = "sha256:6bc7f9d7d90ef55e8c6db1308a8619cd8f40e24a34f759119b95e7284dca351a"}, ] starlette = [ - {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, - {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, + {file = "starlette-0.17.0-py3-none-any.whl", hash = "sha256:64ffd950183d474df2cf7a4018c8bbb31a481367691c70f5ace4b2d376235f72"}, + {file = "starlette-0.17.0.tar.gz", hash = "sha256:31a889e7d7bf487f70d9d197ed7efadb47fa938c58626ed93e381480833c5b84"}, ] "tap.py" = [ {file = "tap.py-3.0-py2.py3-none-any.whl", hash = "sha256:a598bfaa2e224d71f2e86147c2ef822c18ff2e1b8ef006397e5056b08f92f699"}, @@ -1660,8 +1695,8 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomli = [ - {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"}, - {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, + {file = "tomli-1.2.2-py3-none-any.whl", hash = "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"}, + {file = "tomli-1.2.2.tar.gz", hash = "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee"}, ] tomlkit = [ {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, diff --git a/pyproject.toml b/pyproject.toml index 20855fa6..1d4c858c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,7 @@ bcrypt = "^3.2.0" bleach = "^4.1.0" email-validator = "^1.1.3" fakeredis = "^1.6.1" -fastapi = "^0.70.0" +fastapi = { git = "https://github.com/kevr/fastapi.git", branch = "upgrade-starlette-0.17.0" } feedgen = "^0.9.0" httpx = "^0.20.0" itsdangerous = "^2.0.1" From 85ebc72e8af542d73909b6f58f9bfb3b4f40ccd3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 8 Nov 2021 18:18:41 -0800 Subject: [PATCH 1066/1891] fix(fastapi): only elevated users are allowed to suspend accounts Signed-off-by: Kevin Morris --- aurweb/auth.py | 3 ++ aurweb/routers/accounts.py | 7 +++- po/aurweb.pot | 4 +++ templates/partials/account_form.html | 18 +++++----- test/test_accounts_routes.py | 49 ++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 5e45ee83..38754db0 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -51,6 +51,9 @@ class AnonymousUser: LangPreference = aurweb.config.get("options", "default_lang") Timezone = aurweb.config.get("options", "default_timezone") + Suspended = 0 + InactivityTS = 0 + # A stub ssh_pub_key relationship. ssh_pub_key = None diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 152b0a15..498568ad 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -143,6 +143,10 @@ def process_account_form(request: Request, user: models.User, args: dict): if not email or not username: return (False, ["Missing a required field."]) + inactive = args.get("J", False) + if not request.user.is_elevated() and inactive != bool(user.InactivityTS): + return (False, ["You do not have permission to suspend accounts."]) + username_min_len = aurweb.config.getint("options", "username_min_len") username_max_len = aurweb.config.getint("options", "username_max_len") if not util.valid_username(args.get("U")): @@ -528,7 +532,8 @@ async def account_edit_post(request: Request, user.Homepage = HP or user.Homepage user.IRCNick = I or user.IRCNick user.PGPKey = K or user.PGPKey - user.InactivityTS = datetime.utcnow().timestamp() if J else 0 + user.Suspended = J + user.InactivityTS = int(datetime.utcnow().timestamp()) * int(J) # If we update the language, update the cookie as well. if L and L != user.LangPreference: diff --git a/po/aurweb.pot b/po/aurweb.pot index 721f874e..f4deee70 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -879,6 +879,10 @@ msgstr "" msgid "Account suspended" msgstr "" +#: aurweb/routers/accounts.py +msgid "You do not have permission to suspend accounts." +msgstr "" + #: lib/acctfuncs.inc.php #, php-format msgid "" diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index f166c230..2e47a932 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -42,14 +42,16 @@ "account is inactive." | tr }}

    -

    - - -

    + {% if request.user.is_elevated() %} +

    + + +

    + {% endif %} {% if request.user.has_credential("CRED_ACCOUNT_CHANGE_TYPE") %}

    diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 188f7048..5e855daf 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -780,6 +780,55 @@ def test_post_account_edit_error_invalid_password(): assert "Invalid password." in content +def test_post_account_edit_inactivity_unauthorized(): + cookies = {"AURSID": user.login(Request(), "testPassword")} + post_data = { + "U": "test", + "E": "test@example.org", + "J": True, + "passwd": "testPassword" + } + with client as request: + resp = request.post(f"/account/{user.Username}/edit", data=post_data, + cookies=cookies) + assert resp.status_code == int(HTTPStatus.BAD_REQUEST) + + errors = get_errors(resp.text) + expected = "You do not have permission to suspend accounts." + assert errors[0].text.strip() == expected + + +def test_post_account_edit_inactivity(): + with db.begin(): + user.AccountTypeID = TRUSTED_USER_ID + assert not user.Suspended + + cookies = {"AURSID": user.login(Request(), "testPassword")} + post_data = { + "U": "test", + "E": "test@example.org", + "J": True, + "passwd": "testPassword" + } + with client as request: + resp = request.post(f"/account/{user.Username}/edit", data=post_data, + cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # Make sure the user record got updated correctly. + assert user.Suspended + assert user.InactivityTS > 0 + + post_data.update({"J": False}) + with client as request: + resp = request.post(f"/account/{user.Username}/edit", data=post_data, + cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + assert not user.Suspended + assert user.InactivityTS == 0 + + def test_post_account_edit_error_unauthorized(): request = Request() sid = user.login(request, "testPassword") From 464540c9a9f41aad52e633698647a9030092dc51 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 00:14:24 -0800 Subject: [PATCH 1067/1891] fix: use https for aurblup's default mirror instead of ftp It seems the ftp mirror from kernel.org cannot be used anymore, but the https mirror can. So, the default config has been updated to reflect this; otherwise, aurblup bugs out. Signed-off-by: Kevin Morris --- conf/config.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.defaults b/conf/config.defaults index b078e57c..babfd482 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -98,7 +98,7 @@ max-blob-size = 256000 [aurblup] db-path = /srv/http/aurweb/aurblup/ sync-dbs = core extra community multilib testing community-testing -server = ftp://mirrors.kernel.org/archlinux/%s/os/x86_64 +server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] packagesfile = /srv/http/aurweb/web/html/packages.gz From b8d7619dbc34c41d2dac59fd717c7553054eb9d9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 00:17:52 -0800 Subject: [PATCH 1068/1891] change: add mkpkglists options to config.dev Here, we default to using root as the storage directory. Primarily because it makes sense in Docker; config.dev can always be fixed up by developers to reflect local system changes. Signed-off-by: Kevin Morris --- conf/config.dev | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conf/config.dev b/conf/config.dev index fb43612e..6cbe97cc 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -65,3 +65,8 @@ session_secret = secret [devel] ;commit_hash = 1234567 + +[mkpkglists] +packagesfile = /packages.gz +pkgbasefile = /pkgbase.gz +userfile = /users.gz From 338a44839f02850890e69f2985827cab9a1aefb4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 00:18:54 -0800 Subject: [PATCH 1069/1891] fix: override aurblup's db-path option in config.dev Signed-off-by: Kevin Morris --- conf/config.dev | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conf/config.dev b/conf/config.dev index 6cbe97cc..dac85477 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -70,3 +70,6 @@ session_secret = secret packagesfile = /packages.gz pkgbasefile = /pkgbase.gz userfile = /users.gz + +[aurblup] +db-path = YOUR_AUR_ROOT/aurblup/ From 4b8963b7bac999e2effb9840b01c9c01b8218fc0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 00:29:19 -0800 Subject: [PATCH 1070/1891] feat(docker): add cron service (aurblup + mkpkglists) Normally, these scripts are used to update official providers in the aurweb database along with archives that can be retrieved. Run both of these scripts in a 5 minute cron job, to both reflect the live instance database and production load. Signed-off-by: Kevin Morris --- docker-compose.yml | 17 +++++++++++++++++ docker/config/aurweb-cron | 2 ++ docker/cron-entrypoint.sh | 16 ++++++++++++++++ docker/scripts/install-deps.sh | 2 +- docker/scripts/run-cron.sh | 7 +++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 docker/config/aurweb-cron create mode 100755 docker/cron-entrypoint.sh create mode 100755 docker/scripts/run-cron.sh diff --git a/docker-compose.yml b/docker-compose.yml index 038eb65b..c2b14f91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -144,6 +144,19 @@ services: volumes: - git_data:/aurweb/aur.git + cron: + image: aurweb:latest + init: true + environment: + - AUR_CONFIG=/aurweb/conf/config + entrypoint: /docker/cron-entrypoint.sh + command: /docker/scripts/run-cron.sh + depends_on: + mariadb_init: + condition: service_started + volumes: + - mariadb_run:/var/run/mysqld + php-fpm: image: aurweb:latest init: true @@ -163,6 +176,8 @@ services: condition: service_healthy memcached: condition: service_healthy + cron: + condition: service_started volumes: - mariadb_run:/var/run/mysqld ports: @@ -190,6 +205,8 @@ services: condition: service_healthy redis: condition: service_healthy + cron: + condition: service_started volumes: - mariadb_run:/var/run/mysqld ports: diff --git a/docker/config/aurweb-cron b/docker/config/aurweb-cron new file mode 100644 index 00000000..1be7c13c --- /dev/null +++ b/docker/config/aurweb-cron @@ -0,0 +1,2 @@ +*/5 * * * * aurweb-aurblup +*/5 * * * * aurweb-mkpkglists diff --git a/docker/cron-entrypoint.sh b/docker/cron-entrypoint.sh new file mode 100755 index 00000000..d4173eaf --- /dev/null +++ b/docker/cron-entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -eou pipefail + +# Prepare AUR_CONFIG. +cp -vf conf/config.dev conf/config +sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config + +# Create directories we need. +mkdir -p /aurweb/aurblup + +# Install the cron configuration. +cp /docker/config/aurweb-cron /etc/cron.d/aurweb-cron +chmod 0644 /etc/cron.d/aurweb-cron +crontab /etc/cron.d/aurweb-cron + +exec "$@" diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 52ad6747..d64340e3 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -8,7 +8,7 @@ pacman -Syu --noconfirm --noprogressbar \ --cachedir .pkg-cache git gpgme nginx redis openssh \ mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \ php php-fpm memcached php-memcached python-pip pyalpm \ - python-srcinfo curl libeatmydata + python-srcinfo curl libeatmydata cronie # https://python-poetry.org/docs/ Installation section. curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - diff --git a/docker/scripts/run-cron.sh b/docker/scripts/run-cron.sh new file mode 100755 index 00000000..d927a790 --- /dev/null +++ b/docker/scripts/run-cron.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd /aurweb +aurweb-aurblup +aurweb-mkpkglists + +exec /usr/bin/crond -n From 10fcf939911cce4481bc1ec825329c8bc57ebd1d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 01:51:23 -0800 Subject: [PATCH 1071/1891] fix(fastapi): use correct official pkg base url Signed-off-by: Kevin Morris --- aurweb/models/official_provider.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aurweb/models/official_provider.py b/aurweb/models/official_provider.py index a8282ff1..ff70fe43 100644 --- a/aurweb/models/official_provider.py +++ b/aurweb/models/official_provider.py @@ -3,8 +3,7 @@ from sqlalchemy.exc import IntegrityError from aurweb import schema from aurweb.models.declarative import Base -# TODO: Fix this! Official packages aren't from aur.archlinux.org... -OFFICIAL_BASE = "https://aur.archlinux.org" +OFFICIAL_BASE = "https://archlinux.org" class OfficialProvider(Base): From f6061400509fdd808d066fceb4572c2728a39fde Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Fri, 15 Oct 2021 20:14:31 +0200 Subject: [PATCH 1072/1891] feat(PHP): Add packages dump file with more metadata --- aurweb/scripts/mkpkglists.py | 10 ++++++++++ conf/config.defaults | 1 + test/setup.sh | 1 + web/html/index.php | 1 + 4 files changed, 13 insertions(+) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 6724141a..c73cc3be 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -2,11 +2,13 @@ import datetime import gzip +import json import aurweb.config import aurweb.db packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') +packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') userfile = aurweb.config.get('mkpkglists', 'userfile') @@ -27,6 +29,14 @@ def main(): "WHERE PackageBases.PackagerUID IS NOT NULL") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + with gzip.open(packagesmetafile, "wt") as f: + cur = conn.execute("SELECT * FROM Packages") + json.dump({ + "warning": "This is a experimental! It can be removed or modified without warning!", + "columns": [d[0] for d in cur.description], + "data": cur.fetchall() + }, f) + with gzip.open(pkgbasefile, "w") as f: f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) cur = conn.execute("SELECT Name FROM PackageBases " + diff --git a/conf/config.defaults b/conf/config.defaults index babfd482..6ccf42d0 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -102,6 +102,7 @@ server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] packagesfile = /srv/http/aurweb/web/html/packages.gz +packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz userfile = /srv/http/aurweb/web/html/users.gz diff --git a/test/setup.sh b/test/setup.sh index 191a73d8..8ee9eef2 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -67,6 +67,7 @@ server = file://$(pwd)/remote/ [mkpkglists] packagesfile = packages.gz +packagesmetafile = packages-meta-v1.json.gz pkgbasefile = pkgbase.gz userfile = users.gz EOF diff --git a/web/html/index.php b/web/html/index.php index e57e7708..3163c3e8 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -189,6 +189,7 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { readfile("./$path"); break; case "/packages.gz": + case "/packages-teapot.json.gz": case "/pkgbase.gz": case "/users.gz": header("Content-Type: text/plain"); From f3f662c696aaa35b57737c63bc506ded464a7d81 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 31 Oct 2021 16:52:30 -0700 Subject: [PATCH 1073/1891] fix(mkpkglists): improve package meta archive The SQL logic in this file for package metadata now exactly reflects RPC's search logic, without searching for specific packages. Two command line arguments are available: --extended | Include License, Keywords, Groups, relations and dependencies. When --extended is passed, the script will create a packages-meta-ext-v1.json.gz, configured via packagesmetaextfile. Archive JSON is in the following format: line-separated package objects enclosed in a list: [ {...}, {...}, {...} ] Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 273 ++++++++++++++++++++++++++++++++--- conf/config.defaults | 1 + test/setup.sh | 2 + web/html/index.php | 3 +- 4 files changed, 255 insertions(+), 24 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index c73cc3be..f2095a20 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -1,16 +1,192 @@ #!/usr/bin/env python3 +""" +Produces package, package base and user archives for the AUR +database. + +Archives: + + packages.gz | A line-separated list of package names + packages-meta-v1.json | A type=search RPC-formatted JSON dataset + packages-meta-ext-v1.json | An --extended archive + pkgbase.gz | A line-separated list of package base names + users.gz | A line-separated list of user names + +This script takes an optional argument: --extended. Based +on the following, right-hand side fields are added to each item. + + --extended | License, Keywords, Groups, relations and dependencies + +""" import datetime import gzip -import json +import os +import sys + +from collections import defaultdict +from decimal import Decimal +from typing import Tuple + +import orjson import aurweb.config import aurweb.db + +def state_path(archive: str) -> str: + # A hard-coded /tmp state directory. + # TODO: Use Redis cache to store this state after we merge + # FastAPI into master and removed PHP from the tree. + return os.path.join("/tmp", os.path.basename(archive) + ".state") + + packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') +packagesmetaextfile = aurweb.config.get('mkpkglists', 'packagesmetaextfile') +packages_state = state_path(packagesfile) + pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') +pkgbases_state = state_path(pkgbasefile) + userfile = aurweb.config.get('mkpkglists', 'userfile') +users_state = state_path(userfile) + + +def should_update(state: str, tablename: str) -> Tuple[bool, int]: + if aurweb.config.get("database", "backend") != "mysql": + return (False, 0) + + db_name = aurweb.config.get("database", "name") + conn = aurweb.db.Connection() + cur = conn.execute("SELECT auto_increment FROM information_schema.tables " + "WHERE table_schema = ? AND table_name = ?", + (db_name, tablename,)) + update_time = cur.fetchone()[0] + + saved_update_time = 0 + if os.path.exists(state): + with open(state) as f: + saved_update_time = int(f.read().strip()) + + return (saved_update_time == update_time, update_time) + + +def update_state(state: str, update_time: int) -> None: + with open(state, "w") as f: + f.write(str(update_time)) + + +TYPE_MAP = { + "depends": "Depends", + "makedepends": "MakeDepends", + "checkdepends": "CheckDepends", + "optdepends": "OptDepends", + "conflicts": "Conflicts", + "provides": "Provides", + "replaces": "Replaces", +} + + +def get_extended_dict(query: str): + """ + Produce data in the form in a single bulk SQL query: + + { + : { + "Depends": [...], + "Conflicts": [...], + "License": [...] + } + } + + The caller can then use this data to populate a dataset of packages. + + output = produce_base_output_data() + data = get_extended_dict(query) + for i in range(len(output)): + package_id = output[i].get("ID") + output[i].update(data.get(package_id)) + """ + + conn = aurweb.db.Connection() + + cursor = conn.execute(query) + + data = defaultdict(lambda: defaultdict(list)) + + for result in cursor.fetchall(): + + pkgid = result[0] + key = TYPE_MAP.get(result[1]) + output = result[2] + if result[3]: + output += result[3] + + # In all cases, we have at least an empty License list. + if "License" not in data[pkgid]: + data[pkgid]["License"] = [] + + # In all cases, we have at least an empty Keywords list. + if "Keywords" not in data[pkgid]: + data[pkgid]["Keywords"] = [] + + data[pkgid][key].append(output) + + conn.close() + return data + + +def get_extended_fields(): + # Returns: [ID, Type, Name, Cond] + query = """ + SELECT PackageDepends.PackageID AS ID, DependencyTypes.Name AS Type, + PackageDepends.DepName AS Name, PackageDepends.DepCondition AS Cond + FROM PackageDepends + LEFT JOIN DependencyTypes + ON DependencyTypes.ID = PackageDepends.DepTypeID + UNION SELECT PackageRelations.PackageID AS ID, RelationTypes.Name AS Type, + PackageRelations.RelName AS Name, + PackageRelations.RelCondition AS Cond + FROM PackageRelations + LEFT JOIN RelationTypes + ON RelationTypes.ID = PackageRelations.RelTypeID + UNION SELECT PackageGroups.PackageID AS ID, 'Groups' AS Type, + Groups.Name, '' AS Cond + FROM Groups + INNER JOIN PackageGroups ON PackageGroups.GroupID = Groups.ID + UNION SELECT PackageLicenses.PackageID AS ID, 'License' AS Type, + Licenses.Name, '' as Cond + FROM Licenses + INNER JOIN PackageLicenses ON PackageLicenses.LicenseID = Licenses.ID + UNION SELECT Packages.ID AS ID, 'Keywords' AS Type, + PackageKeywords.Keyword AS Name, '' as Cond + FROM PackageKeywords + INNER JOIN Packages ON Packages.PackageBaseID = PackageKeywords.PackageBaseID + """ + return get_extended_dict(query) + + +EXTENDED_FIELD_HANDLERS = { + "--extended": get_extended_fields +} + + +def is_decimal(column): + """ Check if an SQL column is of decimal.Decimal type. """ + if isinstance(column, Decimal): + return float(column) + return column + + +def write_archive(archive: str, output: list): + with gzip.open(archive, "wb") as f: + f.write(b"[\n") + for i, item in enumerate(output): + f.write(orjson.dumps(item)) + if i < len(output) - 1: + f.write(b",") + f.write(b"\n") + f.write(b"]") def main(): @@ -21,32 +197,83 @@ def main(): pkgbaselist_header = "# AUR package base list, generated on " + datestr userlist_header = "# AUR user name list, generated on " + datestr - with gzip.open(packagesfile, "w") as f: - f.write(bytes(pkglist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT Packages.Name FROM Packages " + - "INNER JOIN PackageBases " + - "ON PackageBases.ID = Packages.PackageBaseID " + + updated, update_time = should_update(packages_state, "Packages") + if not updated: + print("Updating Packages...") + + # Query columns; copied from RPC. + columns = ("Packages.ID, Packages.Name, " + "PackageBases.ID AS PackageBaseID, " + "PackageBases.Name AS PackageBase, " + "Version, Description, URL, NumVotes, " + "Popularity, OutOfDateTS AS OutOfDate, " + "Users.UserName AS Maintainer, " + "SubmittedTS AS FirstSubmitted, " + "ModifiedTS AS LastModified") + + # Perform query. + cur = conn.execute(f"SELECT {columns} FROM Packages " + "LEFT JOIN PackageBases " + "ON PackageBases.ID = Packages.PackageBaseID " + "LEFT JOIN Users " + "ON PackageBases.MaintainerUID = Users.ID " "WHERE PackageBases.PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - with gzip.open(packagesmetafile, "wt") as f: - cur = conn.execute("SELECT * FROM Packages") - json.dump({ - "warning": "This is a experimental! It can be removed or modified without warning!", - "columns": [d[0] for d in cur.description], - "data": cur.fetchall() - }, f) + # Produce packages-meta-v1.json.gz + output = list() + snapshot_uri = aurweb.config.get("options", "snapshot_uri") + for result in cur.fetchall(): + item = { + column[0]: is_decimal(result[i]) + for i, column in enumerate(cur.description) + } + item["URLPath"] = snapshot_uri % item.get("Name") + output.append(item) - with gzip.open(pkgbasefile, "w") as f: - f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT Name FROM PackageBases " + - "WHERE PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + write_archive(packagesmetafile, output) - with gzip.open(userfile, "w") as f: - f.write(bytes(userlist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT UserName FROM Users") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + # Produce packages-meta-ext-v1.json.gz + if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: + f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) + data = f() + + default_ = {"Groups": [], "License": [], "Keywords": []} + for i in range(len(output)): + data_ = data.get(output[i].get("ID"), default_) + output[i].update(data_) + + write_archive(packagesmetaextfile, output) + + # Produce packages.gz + with gzip.open(packagesfile, "wb") as f: + f.write(bytes(pkglist_header + "\n", "UTF-8")) + f.writelines([ + bytes(x.get("Name") + "\n", "UTF-8") + for x in output + ]) + + update_state(packages_state, update_time) + + updated, update_time = should_update(pkgbases_state, "PackageBases") + if not updated: + print("Updating PackageBases...") + # Produce pkgbase.gz + with gzip.open(pkgbasefile, "w") as f: + f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT Name FROM PackageBases " + + "WHERE PackagerUID IS NOT NULL") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + update_state(pkgbases_state, update_time) + + updated, update_time = should_update(users_state, "Users") + if not updated: + print("Updating Users...") + # Produce users.gz + with gzip.open(userfile, "w") as f: + f.write(bytes(userlist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT UserName FROM Users") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + update_state(users_state, update_time) conn.close() diff --git a/conf/config.defaults b/conf/config.defaults index 6ccf42d0..25d6dff9 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -103,6 +103,7 @@ server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] packagesfile = /srv/http/aurweb/web/html/packages.gz packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz +packagesmetaextfile = /srv/http/aurweb/web/html/packages-meta-ext-v1.json.gz pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz userfile = /srv/http/aurweb/web/html/users.gz diff --git a/test/setup.sh b/test/setup.sh index 8ee9eef2..d0c15b82 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -37,6 +37,7 @@ enable-maintenance = 0 maintenance-exceptions = 127.0.0.1 commit_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s&id=%s localedir = $TOPLEVEL/web/locale/ +snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz [notifications] notify-cmd = $NOTIFY @@ -68,6 +69,7 @@ server = file://$(pwd)/remote/ [mkpkglists] packagesfile = packages.gz packagesmetafile = packages-meta-v1.json.gz +packagesmetaextfile = packages-meta-ext-v1.json.gz pkgbasefile = pkgbase.gz userfile = users.gz EOF diff --git a/web/html/index.php b/web/html/index.php index 3163c3e8..dc435162 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -189,7 +189,8 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { readfile("./$path"); break; case "/packages.gz": - case "/packages-teapot.json.gz": + case "/packages-meta-v1.json.gz": + case "/packages-meta-ext-v1.json.gz": case "/pkgbase.gz": case "/users.gz": header("Content-Type: text/plain"); From d62af4ceb582c360a6d7bbb876418170efbd92fc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 6 Nov 2021 16:23:08 -0700 Subject: [PATCH 1074/1891] feat(mkpkglists): added metadata archives Two new archives are available: - packages-meta-v1.json.gz - RPC search formatted data for all packages - ~2.1MB at the time of writing. - packages-meta-ext-v1.json.gz (via --extended) - RPC multiinfo formatted data for all packages. - ~9.8MB at the time of writing. New dependencies are required for this update: - `python-orjson` All archives served out by aur.archlinux.org distribute the Last-Modified header and support the If-Modified-Since header, which should be populated with Last-Modified's value. These should be used by clients to avoid redownloading the archive when unnecessary. Additionally, the new meta archives contain a format suitable for streaming the data as the file is retrieved. It is still in JSON format, however, users can parse package objects line by line after the first '[' found in the file, until the last ']'; both contained on their own lines. Note: This commit is a documentation change and commit body. Signed-off-by: Kevin Morris --- doc/maintenance.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/maintenance.txt b/doc/maintenance.txt index d6094545..2c5c9faf 100644 --- a/doc/maintenance.txt +++ b/doc/maintenance.txt @@ -70,7 +70,8 @@ computations and clean up the database: * aurweb-pkgmaint automatically removes empty repositories that were created within the last 24 hours but never populated. -* aurweb-mkpkglists generates the package list files. +* aurweb-mkpkglists generates the package list files; it takes an optional + --extended flag, which additionally produces multiinfo metadata. * aurweb-usermaint removes the last login IP address of all users that did not login within the past seven days. @@ -79,7 +80,7 @@ These scripts can be installed by running `python3 setup.py install` and are usually scheduled using Cron. The current setup is: ---- -*/5 * * * * aurweb-mkpkglists +*/5 * * * * aurweb-mkpkglists [--extended] 1 */2 * * * aurweb-popupdate 2 */2 * * * aurweb-aurblup 3 */2 * * * aurweb-pkgmaint From 0155f4ea84917ca12c905e9035a1d202ea91a3ff Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 6 Nov 2021 17:13:16 -0700 Subject: [PATCH 1075/1891] fix(mkpkglists): remove caching We really need caching for this; however, our current caching method will cause the script to bypass changes to columns if they have nothing to do with IDs. Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 159 ++++++++++++----------------------- 1 file changed, 54 insertions(+), 105 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index f2095a20..2566a146 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -20,60 +20,23 @@ on the following, right-hand side fields are added to each item. import datetime import gzip -import os import sys from collections import defaultdict from decimal import Decimal -from typing import Tuple import orjson import aurweb.config import aurweb.db - -def state_path(archive: str) -> str: - # A hard-coded /tmp state directory. - # TODO: Use Redis cache to store this state after we merge - # FastAPI into master and removed PHP from the tree. - return os.path.join("/tmp", os.path.basename(archive) + ".state") - - packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') packagesmetaextfile = aurweb.config.get('mkpkglists', 'packagesmetaextfile') -packages_state = state_path(packagesfile) pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') -pkgbases_state = state_path(pkgbasefile) userfile = aurweb.config.get('mkpkglists', 'userfile') -users_state = state_path(userfile) - - -def should_update(state: str, tablename: str) -> Tuple[bool, int]: - if aurweb.config.get("database", "backend") != "mysql": - return (False, 0) - - db_name = aurweb.config.get("database", "name") - conn = aurweb.db.Connection() - cur = conn.execute("SELECT auto_increment FROM information_schema.tables " - "WHERE table_schema = ? AND table_name = ?", - (db_name, tablename,)) - update_time = cur.fetchone()[0] - - saved_update_time = 0 - if os.path.exists(state): - with open(state) as f: - saved_update_time = int(f.read().strip()) - - return (saved_update_time == update_time, update_time) - - -def update_state(state: str, update_time: int) -> None: - with open(state, "w") as f: - f.write(str(update_time)) TYPE_MAP = { @@ -197,83 +160,69 @@ def main(): pkgbaselist_header = "# AUR package base list, generated on " + datestr userlist_header = "# AUR user name list, generated on " + datestr - updated, update_time = should_update(packages_state, "Packages") - if not updated: - print("Updating Packages...") + # Query columns; copied from RPC. + columns = ("Packages.ID, Packages.Name, " + "PackageBases.ID AS PackageBaseID, " + "PackageBases.Name AS PackageBase, " + "Version, Description, URL, NumVotes, " + "Popularity, OutOfDateTS AS OutOfDate, " + "Users.UserName AS Maintainer, " + "SubmittedTS AS FirstSubmitted, " + "ModifiedTS AS LastModified") - # Query columns; copied from RPC. - columns = ("Packages.ID, Packages.Name, " - "PackageBases.ID AS PackageBaseID, " - "PackageBases.Name AS PackageBase, " - "Version, Description, URL, NumVotes, " - "Popularity, OutOfDateTS AS OutOfDate, " - "Users.UserName AS Maintainer, " - "SubmittedTS AS FirstSubmitted, " - "ModifiedTS AS LastModified") + # Perform query. + cur = conn.execute(f"SELECT {columns} FROM Packages " + "LEFT JOIN PackageBases " + "ON PackageBases.ID = Packages.PackageBaseID " + "LEFT JOIN Users " + "ON PackageBases.MaintainerUID = Users.ID " + "WHERE PackageBases.PackagerUID IS NOT NULL") - # Perform query. - cur = conn.execute(f"SELECT {columns} FROM Packages " - "LEFT JOIN PackageBases " - "ON PackageBases.ID = Packages.PackageBaseID " - "LEFT JOIN Users " - "ON PackageBases.MaintainerUID = Users.ID " - "WHERE PackageBases.PackagerUID IS NOT NULL") + # Produce packages-meta-v1.json.gz + output = list() + snapshot_uri = aurweb.config.get("options", "snapshot_uri") + for result in cur.fetchall(): + item = { + column[0]: is_decimal(result[i]) + for i, column in enumerate(cur.description) + } + item["URLPath"] = snapshot_uri % item.get("Name") + output.append(item) - # Produce packages-meta-v1.json.gz - output = list() - snapshot_uri = aurweb.config.get("options", "snapshot_uri") - for result in cur.fetchall(): - item = { - column[0]: is_decimal(result[i]) - for i, column in enumerate(cur.description) - } - item["URLPath"] = snapshot_uri % item.get("Name") - output.append(item) + write_archive(packagesmetafile, output) - write_archive(packagesmetafile, output) + # Produce packages-meta-ext-v1.json.gz + if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: + f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) + data = f() - # Produce packages-meta-ext-v1.json.gz - if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: - f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) - data = f() + default_ = {"Groups": [], "License": [], "Keywords": []} + for i in range(len(output)): + data_ = data.get(output[i].get("ID"), default_) + output[i].update(data_) - default_ = {"Groups": [], "License": [], "Keywords": []} - for i in range(len(output)): - data_ = data.get(output[i].get("ID"), default_) - output[i].update(data_) + write_archive(packagesmetaextfile, output) - write_archive(packagesmetaextfile, output) + # Produce packages.gz + with gzip.open(packagesfile, "wb") as f: + f.write(bytes(pkglist_header + "\n", "UTF-8")) + f.writelines([ + bytes(x.get("Name") + "\n", "UTF-8") + for x in output + ]) - # Produce packages.gz - with gzip.open(packagesfile, "wb") as f: - f.write(bytes(pkglist_header + "\n", "UTF-8")) - f.writelines([ - bytes(x.get("Name") + "\n", "UTF-8") - for x in output - ]) + # Produce pkgbase.gz + with gzip.open(pkgbasefile, "w") as f: + f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT Name FROM PackageBases " + + "WHERE PackagerUID IS NOT NULL") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - update_state(packages_state, update_time) - - updated, update_time = should_update(pkgbases_state, "PackageBases") - if not updated: - print("Updating PackageBases...") - # Produce pkgbase.gz - with gzip.open(pkgbasefile, "w") as f: - f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT Name FROM PackageBases " + - "WHERE PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - update_state(pkgbases_state, update_time) - - updated, update_time = should_update(users_state, "Users") - if not updated: - print("Updating Users...") - # Produce users.gz - with gzip.open(userfile, "w") as f: - f.write(bytes(userlist_header + "\n", "UTF-8")) - cur = conn.execute("SELECT UserName FROM Users") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) - update_state(users_state, update_time) + # Produce users.gz + with gzip.open(userfile, "w") as f: + f.write(bytes(userlist_header + "\n", "UTF-8")) + cur = conn.execute("SELECT UserName FROM Users") + f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) conn.close() From 0403b89f53302f7d58b170081ef7bbd2726d8fc1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 02:08:03 -0800 Subject: [PATCH 1076/1891] feat: add packagesmeta[ext]file option to conf/config.dev Better defaults for Docker here. Signed-off-by: Kevin Morris --- conf/config.dev | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/config.dev b/conf/config.dev index dac85477..05566e8b 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -68,6 +68,8 @@ session_secret = secret [mkpkglists] packagesfile = /packages.gz +packagesmetafile = /packages-meta-v1.json.gz +packagesmetaextfile = /packages-meta-ext-v1.json.gz pkgbasefile = /pkgbase.gz userfile = /users.gz From 068b067e148cb4f39fdfb7aa2086568084ac6a0a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 02:28:52 -0800 Subject: [PATCH 1077/1891] feat(docker): log cron executions Signed-off-by: Kevin Morris --- docker/config/aurweb-cron | 4 ++-- docker/scripts/run-cron.sh | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docker/config/aurweb-cron b/docker/config/aurweb-cron index 1be7c13c..87d7ed05 100644 --- a/docker/config/aurweb-cron +++ b/docker/config/aurweb-cron @@ -1,2 +1,2 @@ -*/5 * * * * aurweb-aurblup -*/5 * * * * aurweb-mkpkglists +*/5 * * * * bash -c 'aurweb-aurblup && echo "[$(date -u)] executed aurblup" >> /var/log/mkpkglists.log' +*/5 * * * * bash -c 'aurweb-mkpkglists && echo "[$(date -u)] executed mkpkglists" >> /var/log/mkpkglists.log' diff --git a/docker/scripts/run-cron.sh b/docker/scripts/run-cron.sh index d927a790..d227be94 100755 --- a/docker/scripts/run-cron.sh +++ b/docker/scripts/run-cron.sh @@ -2,6 +2,13 @@ cd /aurweb aurweb-aurblup +if [ $? -eq 0 ]; then + echo "[$(date -u)] executed aurblup" >> /var/log/aurblup.log +fi + aurweb-mkpkglists +if [ $? -eq 0 ]; then + echo "[$(date -u)] executed mkpkglists" >> /var/log/mkpkglists.log +fi exec /usr/bin/crond -n From 107367f958ef320d63952def915b65cef1ed31bd Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Nov 2021 02:29:39 -0800 Subject: [PATCH 1078/1891] feat(docker): use mkpkglists --extended flag Signed-off-by: Kevin Morris --- docker/config/aurweb-cron | 2 +- docker/scripts/run-cron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/config/aurweb-cron b/docker/config/aurweb-cron index 87d7ed05..149b9d19 100644 --- a/docker/config/aurweb-cron +++ b/docker/config/aurweb-cron @@ -1,2 +1,2 @@ */5 * * * * bash -c 'aurweb-aurblup && echo "[$(date -u)] executed aurblup" >> /var/log/mkpkglists.log' -*/5 * * * * bash -c 'aurweb-mkpkglists && echo "[$(date -u)] executed mkpkglists" >> /var/log/mkpkglists.log' +*/5 * * * * bash -c 'aurweb-mkpkglists --extended && echo "[$(date -u)] executed mkpkglists" >> /var/log/mkpkglists.log' diff --git a/docker/scripts/run-cron.sh b/docker/scripts/run-cron.sh index d227be94..83ad6566 100755 --- a/docker/scripts/run-cron.sh +++ b/docker/scripts/run-cron.sh @@ -6,7 +6,7 @@ if [ $? -eq 0 ]; then echo "[$(date -u)] executed aurblup" >> /var/log/aurblup.log fi -aurweb-mkpkglists +aurweb-mkpkglists --extended if [ $? -eq 0 ]; then echo "[$(date -u)] executed mkpkglists" >> /var/log/mkpkglists.log fi From abbecf5194b69d419e81b547eaa8b3e72d550524 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 06:18:34 -0800 Subject: [PATCH 1079/1891] change(mkpkglists): remove header comments These comments change every time mkpkglists is run; which would invalidate the ETag headers disbursed by the gzip host. This commit removes those changing headers. Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 2566a146..b2d37d85 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -18,7 +18,6 @@ on the following, right-hand side fields are added to each item. """ -import datetime import gzip import sys @@ -155,11 +154,6 @@ def write_archive(archive: str, output: list): def main(): conn = aurweb.db.Connection() - datestr = datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT") - pkglist_header = "# AUR package list, generated on " + datestr - pkgbaselist_header = "# AUR package base list, generated on " + datestr - userlist_header = "# AUR user name list, generated on " + datestr - # Query columns; copied from RPC. columns = ("Packages.ID, Packages.Name, " "PackageBases.ID AS PackageBaseID, " @@ -205,7 +199,6 @@ def main(): # Produce packages.gz with gzip.open(packagesfile, "wb") as f: - f.write(bytes(pkglist_header + "\n", "UTF-8")) f.writelines([ bytes(x.get("Name") + "\n", "UTF-8") for x in output @@ -213,14 +206,12 @@ def main(): # Produce pkgbase.gz with gzip.open(pkgbasefile, "w") as f: - f.write(bytes(pkgbaselist_header + "\n", "UTF-8")) cur = conn.execute("SELECT Name FROM PackageBases " + "WHERE PackagerUID IS NOT NULL") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) # Produce users.gz with gzip.open(userfile, "w") as f: - f.write(bytes(userlist_header + "\n", "UTF-8")) cur = conn.execute("SELECT UserName FROM Users") f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) From 4f7aeafa8d9fc835c604b82bd8f94308220ed0dd Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 06:20:22 -0800 Subject: [PATCH 1080/1891] feat(docker): host gzip archive downloads - added config option [mkpkglists] archivedir - created by mkpkglists Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 4 ++++ conf/config.defaults | 1 + conf/config.dev | 11 ++++++----- docker-compose.yml | 5 +++++ docker/config/nginx.conf | 19 ++++++++++++++++++- docker/php-entrypoint.sh | 4 ++++ 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index b2d37d85..f4b0fbe5 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -19,6 +19,7 @@ on the following, right-hand side fields are added to each item. """ import gzip +import os import sys from collections import defaultdict @@ -29,6 +30,9 @@ import orjson import aurweb.config import aurweb.db +archivedir = aurweb.config.get("mkpkglists", "archivedir") +os.makedirs(archivedir, exist_ok=True) + packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') packagesmetaextfile = aurweb.config.get('mkpkglists', 'packagesmetaextfile') diff --git a/conf/config.defaults b/conf/config.defaults index 25d6dff9..c29d7045 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -101,6 +101,7 @@ sync-dbs = core extra community multilib testing community-testing server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] +archivedir = /srv/http/aurweb/web/html packagesfile = /srv/http/aurweb/web/html/packages.gz packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz packagesmetaextfile = /srv/http/aurweb/web/html/packages-meta-ext-v1.json.gz diff --git a/conf/config.dev b/conf/config.dev index 05566e8b..9467615e 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -67,11 +67,12 @@ session_secret = secret ;commit_hash = 1234567 [mkpkglists] -packagesfile = /packages.gz -packagesmetafile = /packages-meta-v1.json.gz -packagesmetaextfile = /packages-meta-ext-v1.json.gz -pkgbasefile = /pkgbase.gz -userfile = /users.gz +archivedir = /var/lib/aurweb/archives +packagesfile = /var/lib/aurweb/archives/packages.gz +packagesmetafile = /var/lib/aurweb/archives/packages-meta-v1.json.gz +packagesmetaextfile = /var/lib/aurweb/archives/packages-meta-ext-v1.json.gz +pkgbasefile = /var/lib/aurweb/archives/pkgbase.gz +userfile = /var/lib/aurweb/archives/users.gz [aurblup] db-path = YOUR_AUR_ROOT/aurblup/ diff --git a/docker-compose.yml b/docker-compose.yml index c2b14f91..2fba1305 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -156,6 +156,7 @@ services: condition: service_started volumes: - mariadb_run:/var/run/mysqld + - archives:/var/lib/aurweb/archives php-fpm: image: aurweb:latest @@ -180,6 +181,7 @@ services: condition: service_started volumes: - mariadb_run:/var/run/mysqld + - archives:/var/lib/aurweb/archives ports: - "19000:9000" @@ -236,6 +238,8 @@ services: condition: service_healthy php-fpm: condition: service_healthy + volumes: + - archives:/var/lib/aurweb/archives sharness: image: aurweb:latest @@ -343,3 +347,4 @@ volumes: mariadb_data: {} # Share /var/lib/mysql git_data: {} # Share aurweb/aur.git smartgit_run: {} + archives: {} diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index 4288a57d..c3ffd7fa 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -94,7 +94,24 @@ http { ssl_certificate /etc/ssl/certs/web.cert.pem; ssl_certificate_key /etc/ssl/private/web.key.pem; - root /aurweb/web/html; + location ~ ^/.*\.gz$ { + # Override mime type to text/plain. + types { text/plain gz; } + default_type text/plain; + + # Filesystem location of .gz archives. + root /var/lib/aurweb/archives; + + # When we match this block, fix-up trying without a trailing slash. + try_files $uri $uri/ =404; + + # Caching headers. + expires max; + add_header Content-Encoding gzip; + add_header Cache-Control public; + add_header Last-Modified ""; + add_header ETag ""; + } location / { try_files $uri @proxy_to_app; diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index 81f70673..274f8e17 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -1,6 +1,10 @@ #!/bin/bash set -eou pipefail +for archive in packages pkgbase users packages-meta-v1.json packages-meta-ext-v1.json; do + ln -vsf /var/lib/aurweb/archives/${archive}.gz /aurweb/web/html/${archive}.gz +done + # Setup a config for our mysql db. cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config From 0c57c53da18b36c470471a754e5ea892a46db505 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 07:04:03 -0800 Subject: [PATCH 1081/1891] fix(sharness): fix AUR_CONFIG generation for mkpkglists test Signed-off-by: Kevin Morris --- test/setup.sh | 1 + test/t2100-mkpkglists.t | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/setup.sh b/test/setup.sh index d0c15b82..a09e0c6e 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -67,6 +67,7 @@ sync-dbs = test server = file://$(pwd)/remote/ [mkpkglists] +archivedir = $(pwd)/archive packagesfile = packages.gz packagesmetafile = packages-meta-v1.json.gz packagesmetaextfile = packages-meta-ext-v1.json.gz diff --git a/test/t2100-mkpkglists.t b/test/t2100-mkpkglists.t index 6bb6838d..d217c4f6 100755 --- a/test/t2100-mkpkglists.t +++ b/test/t2100-mkpkglists.t @@ -8,8 +8,8 @@ test_expect_success 'Test package list generation with no packages.' ' echo "DELETE FROM Packages;" | sqlite3 aur.db && echo "DELETE FROM PackageBases;" | sqlite3 aur.db && cover "$MKPKGLISTS" && - test $(zcat packages.gz | wc -l) -eq 1 && - test $(zcat pkgbase.gz | wc -l) -eq 1 + test $(zcat packages.gz | wc -l) -eq 0 && + test $(zcat pkgbase.gz | wc -l) -eq 0 ' test_expect_success 'Test package list generation.' ' From 4b2be7fff8f8e5203cd84a9f25f590d4bdf8ef5d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 13:00:01 -0800 Subject: [PATCH 1082/1891] feat(docker): add poetry caching Signed-off-by: Kevin Morris --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index b490d2fa..3c12cbf8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ FROM archlinux:base-devel +VOLUME /root/.cache/pypoetry/cache +VOLUME /root/.cache/pypoetry/artifacts + ENV PATH="/root/.poetry/bin:${PATH}" ENV PYTHONPATH=/aurweb ENV AUR_CONFIG=conf/config From daef98080e7f1f595dde09c20da1b7b57f5478ed Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 13:05:19 -0800 Subject: [PATCH 1083/1891] fix(fastapi): fix broken official package query Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index be351ebe..cdec26f3 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -56,8 +56,8 @@ def dep_extra_desc(dep: models.PackageDependency) -> str: def pkgname_link(pkgname: str) -> str: base = "/".join([OFFICIAL_BASE, "packages"]) official = db.query(models.OfficialProvider).filter( - models.OfficialProvider.Name == pkgname) - if official.scalar(): + models.OfficialProvider.Name == pkgname).exists() + if db.query(official).scalar(): return f"{base}/?q={pkgname}" return f"/packages/{pkgname}" From 52110b7db5e9b6f3a1dc4fefdf60a31dc946d487 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 13:40:19 -0800 Subject: [PATCH 1084/1891] fix(mkpkglists): default keys to result[1] Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 2566a146..72efcd0a 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -21,14 +21,12 @@ on the following, right-hand side fields are added to each item. import datetime import gzip import sys - from collections import defaultdict from decimal import Decimal -import orjson - import aurweb.config import aurweb.db +import orjson packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') @@ -80,7 +78,7 @@ def get_extended_dict(query: str): for result in cursor.fetchall(): pkgid = result[0] - key = TYPE_MAP.get(result[1]) + key = TYPE_MAP.get(result[1], result[1]) output = result[2] if result[3]: output += result[3] From 6e344ce9da894cdb70fb02cc531145907ac28a48 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 13:40:19 -0800 Subject: [PATCH 1085/1891] fix(mkpkglists): default keys to result[1] Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index f4b0fbe5..74d41c7c 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -21,7 +21,6 @@ on the following, right-hand side fields are added to each item. import gzip import os import sys - from collections import defaultdict from decimal import Decimal @@ -83,7 +82,7 @@ def get_extended_dict(query: str): for result in cursor.fetchall(): pkgid = result[0] - key = TYPE_MAP.get(result[1]) + key = TYPE_MAP.get(result[1], result[1]) output = result[2] if result[3]: output += result[3] From 8788f9900576bc7fa79b54566f23cdaeaeafa9eb Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 13:54:18 -0800 Subject: [PATCH 1086/1891] fix(mkpkglists): restore isort order Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 74d41c7c..307b2b12 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -21,6 +21,7 @@ on the following, right-hand side fields are added to each item. import gzip import os import sys + from collections import defaultdict from decimal import Decimal From 66978e40a46cd096a49c0c7cba1ad60010313ba1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 10 Nov 2021 13:57:33 -0800 Subject: [PATCH 1087/1891] fix(mkpkglists): fix isort order (master) Signed-off-by: Kevin Morris --- aurweb/scripts/mkpkglists.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 72efcd0a..2d34a17b 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -21,12 +21,14 @@ on the following, right-hand side fields are added to each item. import datetime import gzip import sys + from collections import defaultdict from decimal import Decimal +import orjson + import aurweb.config import aurweb.db -import orjson packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') From 567090547d5f96b5e4266bb2d88c7344348bccf2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 13:09:05 -0800 Subject: [PATCH 1088/1891] add labels to gitlab issue templates Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Account Request.md | 2 ++ .gitlab/issue_templates/Bug.md | 2 ++ .gitlab/issue_templates/Feature.md | 2 ++ .gitlab/issue_templates/Feedback.md | 2 ++ 4 files changed, 8 insertions(+) diff --git a/.gitlab/issue_templates/Account Request.md b/.gitlab/issue_templates/Account Request.md index 244cfbe8..6831d3ad 100644 --- a/.gitlab/issue_templates/Account Request.md +++ b/.gitlab/issue_templates/Account Request.md @@ -10,3 +10,5 @@ - Username: the_username_you_want - Email: valid@email.org - Account Type: (User|Trusted User) + +/label account-request diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md index d84a5181..d125e22b 100644 --- a/.gitlab/issue_templates/Bug.md +++ b/.gitlab/issue_templates/Bug.md @@ -32,3 +32,5 @@ aurweb's HTML render output. If you're testing locally, use the commit on which you are experiencing the bug. If you have found a bug which exists on live aur.archlinux.org, include the version located at the bottom of the webpage. + +/label bug unconfirmed diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md index 5b1524b1..c907adcd 100644 --- a/.gitlab/issue_templates/Feature.md +++ b/.gitlab/issue_templates/Feature.md @@ -28,3 +28,5 @@ Example: - [Feature] Do not allow users to be Tyrants - \<(issue|merge_request)_link\> + +/label feature unconsidered diff --git a/.gitlab/issue_templates/Feedback.md b/.gitlab/issue_templates/Feedback.md index e32120aa..950ec0c6 100644 --- a/.gitlab/issue_templates/Feedback.md +++ b/.gitlab/issue_templates/Feedback.md @@ -54,3 +54,5 @@ That being said: please include an overall summary of your experience and how you felt about the current implementation which you're testing in comparison with PHP (current aur.archlinux.org, or https://localhost:8443 through docker). + +/label feedback From 0da11f068bd34bc534baf34027b2a925475f6666 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 16:22:30 -0800 Subject: [PATCH 1089/1891] fix(fastapi): check for prometheus info.response When this is unchecked, exceptions cause the resulting stack trace to be oblivious to the original exception thrown. This commit changes that behavior so that metrics are created only when info.response exists. Signed-off-by: Kevin Morris --- aurweb/prometheus.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index a64f6b27..dae56320 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -79,9 +79,10 @@ def http_requests_total() -> Callable[[Info], None]: method = scope.get("method") path = get_matching_route_path(base_scope, scope.get("router").routes) - status = str(int(info.response.status_code))[:1] + "xx" - metric.labels(method=method, path=path, status=status).inc() + if info.response: + status = str(int(info.response.status_code))[:1] + "xx" + metric.labels(method=method, path=path, status=status).inc() return instrumentation @@ -95,7 +96,8 @@ def http_api_requests_total() -> Callable[[Info], None]: def instrumentation(info: Info) -> None: if info.request.url.path.rstrip("/") == "/rpc": type = info.request.query_params.get("type", "None") - status = str(info.response.status_code)[:1] + "xx" - metric.labels(type=type, status=status).inc() + if info.response: + status = str(info.response.status_code)[:1] + "xx" + metric.labels(type=type, status=status).inc() return instrumentation From cef217388adaa97e66e638ca4baf99f3b8d0f865 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 13:09:05 -0800 Subject: [PATCH 1090/1891] add labels to gitlab issue templates Signed-off-by: Kevin Morris --- .gitlab/issue_templates/Account Request.md | 2 ++ .gitlab/issue_templates/Bug.md | 2 ++ .gitlab/issue_templates/Feature.md | 2 ++ .gitlab/issue_templates/Feedback.md | 2 ++ 4 files changed, 8 insertions(+) diff --git a/.gitlab/issue_templates/Account Request.md b/.gitlab/issue_templates/Account Request.md index 244cfbe8..6831d3ad 100644 --- a/.gitlab/issue_templates/Account Request.md +++ b/.gitlab/issue_templates/Account Request.md @@ -10,3 +10,5 @@ - Username: the_username_you_want - Email: valid@email.org - Account Type: (User|Trusted User) + +/label account-request diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md index d84a5181..d125e22b 100644 --- a/.gitlab/issue_templates/Bug.md +++ b/.gitlab/issue_templates/Bug.md @@ -32,3 +32,5 @@ aurweb's HTML render output. If you're testing locally, use the commit on which you are experiencing the bug. If you have found a bug which exists on live aur.archlinux.org, include the version located at the bottom of the webpage. + +/label bug unconfirmed diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md index 5b1524b1..c907adcd 100644 --- a/.gitlab/issue_templates/Feature.md +++ b/.gitlab/issue_templates/Feature.md @@ -28,3 +28,5 @@ Example: - [Feature] Do not allow users to be Tyrants - \<(issue|merge_request)_link\> + +/label feature unconsidered diff --git a/.gitlab/issue_templates/Feedback.md b/.gitlab/issue_templates/Feedback.md index e32120aa..950ec0c6 100644 --- a/.gitlab/issue_templates/Feedback.md +++ b/.gitlab/issue_templates/Feedback.md @@ -54,3 +54,5 @@ That being said: please include an overall summary of your experience and how you felt about the current implementation which you're testing in comparison with PHP (current aur.archlinux.org, or https://localhost:8443 through docker). + +/label feedback From 5f5fa44d0d3b1930ce22e64968392c8b595205c7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 17:12:13 -0800 Subject: [PATCH 1091/1891] fix(fastapi): fix licenses check Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index e8414bf4..583149f8 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -61,7 +61,7 @@ {% endif %} - {% if licenses and licenses.scalar() and show_package_details %} + {% if licenses and licenses.count() and show_package_details %} {{ "Licenses" | tr }}: {{ licenses | join(', ', attribute='Name') | default('None' | tr) }} From 363afff33260b2e3ce6236a22c8d6c32f0ffdd70 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 17:36:08 -0800 Subject: [PATCH 1092/1891] feat(fastapi): add /pkgbase/{name}/keywords (post) Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 23 ++++++++++++++++++ templates/partials/packages/details.html | 4 ++-- test/test_packages_routes.py | 30 ++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index bcc0be56..e227fe23 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -816,6 +816,29 @@ async def requests_close_post(request: Request, id: int, return RedirectResponse("/requests", status_code=HTTPStatus.SEE_OTHER) +@router.post("/pkgbase/{name}/keywords") +async def pkgbase_keywords(request: Request, name: str, + keywords: str = Form(default=str())): + pkgbase = get_pkg_or_base(name, models.PackageBase) + keywords = set(keywords.split(" ")) + + # Delete all keywords which are not supplied by the user. + with db.begin(): + db.delete(models.PackageKeyword, + and_(models.PackageKeyword.PackageBaseID == pkgbase.ID, + ~models.PackageKeyword.Keyword.in_(keywords))) + + existing_keywords = set(kwd.Keyword for kwd in pkgbase.keywords.all()) + with db.begin(): + for keyword in keywords.difference(existing_keywords): + db.create(models.PackageKeyword, + PackageBase=pkgbase, + Keyword=keyword) + + return RedirectResponse(f"/pkgbase/{name}", + status_code=HTTPStatus.SEE_OTHER) + + @router.get("/pkgbase/{name}/flag") @auth_required(True, redirect="/pkgbase/{name}/flag") async def pkgbase_flag_get(request: Request, name: str): diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 583149f8..d525f63b 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -37,7 +37,7 @@ {{ "Keywords" | tr }}: {% if request.user.has_credential("CRED_PKGBASE_SET_KEYWORDS", approved=[pkgbase.Maintainer]) %} -

    @@ -51,7 +51,7 @@ {% else %} - {% for keyword in pkgbase.keywords %} + {% for keyword in pkgbase.keywords.all() %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index c4d9ab1c..887945d9 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -2604,3 +2604,33 @@ def test_account_comments(client: TestClient, user: User, package: Package): expected = rendered_comment.RenderedComment.replace( "

    ", "").replace("

    ", "") assert rendered[0].text.strip() == expected + + +def test_pkgbase_keywords(client: TestClient, user: User, package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}" + with client as request: + resp = request.get(endpoint) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + keywords = root.xpath('//a[@class="keyword"]') + assert len(keywords) == 0 + + cookies = {"AURSID": user.login(Request(), "testPassword")} + post_endpoint = f"{endpoint}/keywords" + with client as request: + resp = request.post(post_endpoint, data={ + "keywords": "abc test" + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + with client as request: + resp = request.get(resp.headers.get("location")) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + keywords = root.xpath('//a[@class="keyword"]') + assert len(keywords) == 2 + expected = ["abc", "test"] + for i, keyword in enumerate(keywords): + assert keyword.text.strip() == expected[i] From 20f5519b99a29dc376a6d8a2325f58ca9305380c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 18:13:21 -0800 Subject: [PATCH 1093/1891] fix(fastapi): hide keywords when there are none or they can't be edited Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 56 ++++++++++++------------ 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index d525f63b..00859068 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -33,34 +33,36 @@ {% endif %} - - {{ "Keywords" | tr }}: - {% if request.user.has_credential("CRED_PKGBASE_SET_KEYWORDS", approved=[pkgbase.Maintainer]) %} - - -
    - - -
    - - - {% else %} - - {% for keyword in pkgbase.keywords.all() %} -
    + {{ "Keywords" | tr }}: + {% if request.user.has_credential("CRED_PKGBASE_SET_KEYWORDS", approved=[pkgbase.Maintainer]) %} + +
    - {{ keyword.Keyword }} - - {% endfor %} - - {% endif %} - +
    + + +
    +
    + + {% else %} + + {% for keyword in pkgbase.keywords.all() %} + + {{ keyword.Keyword }} + + {% endfor %} + + {% endif %} + + {% endif %} {% if licenses and licenses.count() and show_package_details %} {{ "Licenses" | tr }}: From 2dc6cfec23dcc8432db52f0676e7aa9f643d521c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 18:14:15 -0800 Subject: [PATCH 1094/1891] fix(fastapi): reorganize licenses display Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 00859068..1fbd47d9 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -63,10 +63,10 @@ {% endif %} {% endif %} - {% if licenses and licenses.count() and show_package_details %} + {% if show_package_details and licenses and licenses.count() %} {{ "Licenses" | tr }}: - {{ licenses | join(', ', attribute='Name') | default('None' | tr) }} + {{ licenses.all() | join(', ', attribute='Name') | default('None' | tr) }} {% endif %} {% if show_package_details %} From 2016b80ea97dc89d3170a91265abfd05763b81ab Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 18:14:50 -0800 Subject: [PATCH 1095/1891] fix(fastapi): hide conflicts when there are none Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 1fbd47d9..da99cf1b 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -69,11 +69,11 @@ {{ licenses.all() | join(', ', attribute='Name') | default('None' | tr) }} {% endif %} - {% if show_package_details %} + {% if show_package_details and conflicts and conflicts.count() %} {{ "Conflicts" | tr }}: - {{ conflicts | join(', ', attribute='RelName') }} + {{ conflicts.all() | join(', ', attribute='RelName') }} {% endif %} From 50a9690c2ddefeb3fe758ed998f2edbe3773d5f1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 19:09:24 -0800 Subject: [PATCH 1096/1891] feat(fastapi): add Provides field in package details Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 6 +++++- templates/partials/packages/details.html | 8 ++++++++ test/test_packages_routes.py | 14 +++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index e227fe23..fb91a8e3 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -12,7 +12,7 @@ import aurweb.packages.util from aurweb import db, defaults, l10n, logging, models, util from aurweb.auth import auth_required from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID -from aurweb.models.relation_type import CONFLICTS_ID +from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID from aurweb.models.request_type import DELETION_ID, MERGE, MERGE_ID from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted @@ -258,6 +258,10 @@ async def package(request: Request, name: str) -> Response: ) context["conflicts"] = conflicts + provides = pkg.package_relations.filter( + models.PackageRelation.RelTypeID == PROVIDES_ID) + context["provides"] = provides + return render_template(request, "packages/show.html", context) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index da99cf1b..70636926 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -77,6 +77,14 @@ {% endif %} + {% if show_package_details and provides and provides.count() %} + + {{ "Provides" | tr }}: + + {{ provides.all() | join(', ', attribute='RelName') }} + + + {% endif %} {{ "Submitter" | tr }}: diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 887945d9..464a7f60 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -217,8 +217,16 @@ def test_package_official_not_found(client: TestClient, package: Package): def test_package(client: TestClient, package: Package): """ Test a single / packages / {name} route. """ - with client as request: + with db.begin(): + db.create(PackageRelation, PackageID=package.ID, + RelTypeID=PROVIDES_ID, + RelName="test_provider1") + db.create(PackageRelation, PackageID=package.ID, + RelTypeID=PROVIDES_ID, + RelName="test_provider2") + + with client as request: resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) @@ -238,6 +246,10 @@ def test_package(client: TestClient, package: Package): pkgbase = row.find("./td/a") assert pkgbase.text.strip() == package.PackageBase.Name + provides = root.xpath('//tr[@id="provides"]/td') + expected = ["test_provider1", "test_provider2"] + assert provides[0].text.strip() == ", ".join(expected) + def test_package_comments(client: TestClient, user: User, package: Package): now = (datetime.utcnow().timestamp()) From a33e9bd571dfaf1bd2a719df0a80e66f0c33cc2e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 19:14:08 -0800 Subject: [PATCH 1097/1891] feat(fastapi): add Replaces field to package details Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 6 +++++- templates/partials/packages/details.html | 8 ++++++++ test/test_packages_routes.py | 13 ++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index fb91a8e3..f03be217 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -12,7 +12,7 @@ import aurweb.packages.util from aurweb import db, defaults, l10n, logging, models, util from aurweb.auth import auth_required from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID -from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID +from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.models.request_type import DELETION_ID, MERGE, MERGE_ID from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted @@ -262,6 +262,10 @@ async def package(request: Request, name: str) -> Response: models.PackageRelation.RelTypeID == PROVIDES_ID) context["provides"] = provides + replaces = pkg.package_relations.filter( + models.PackageRelation.RelTypeID == REPLACES_ID) + context["replaces"] = replaces + return render_template(request, "packages/show.html", context) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 70636926..7516b324 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -85,6 +85,14 @@ {% endif %} + {% if show_package_details and replaces and replaces.count() %} + + {{ "Replaces" | tr }}: + + {{ replaces.all() | join(', ', attribute='RelName') }} + + + {% endif %} {{ "Submitter" | tr }}: diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 464a7f60..b00844c2 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -24,7 +24,7 @@ from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation from aurweb.models.package_request import ACCEPTED_ID, REJECTED_ID, PackageRequest from aurweb.models.package_vote import PackageVote -from aurweb.models.relation_type import PROVIDES_ID, RelationType +from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID, RelationType from aurweb.models.request_type import DELETION_ID, MERGE_ID, RequestType from aurweb.models.user import User from aurweb.testing import setup_test_db @@ -226,6 +226,13 @@ def test_package(client: TestClient, package: Package): RelTypeID=PROVIDES_ID, RelName="test_provider2") + db.create(PackageRelation, PackageID=package.ID, + RelTypeID=REPLACES_ID, + RelName="test_replacer1") + db.create(PackageRelation, PackageID=package.ID, + RelTypeID=REPLACES_ID, + RelName="test_replacer2") + with client as request: resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) @@ -250,6 +257,10 @@ def test_package(client: TestClient, package: Package): expected = ["test_provider1", "test_provider2"] assert provides[0].text.strip() == ", ".join(expected) + replaces = root.xpath('//tr[@id="replaces"]/td') + expected = ["test_replacer1", "test_replacer2"] + assert replaces[0].text.strip() == ", ".join(expected) + def test_package_comments(client: TestClient, user: User, package: Package): now = (datetime.utcnow().timestamp()) From e8e9edbb21cfe5dd33f491acbdcc1d9b98845a69 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 19:30:21 -0800 Subject: [PATCH 1098/1891] change(fastapi): simplify package details database queries Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 16 ++++------------ templates/partials/packages/details.html | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index f03be217..0949909e 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -229,9 +229,7 @@ async def package(request: Request, name: str) -> Response: context["package"] = pkg # Package sources. - context["sources"] = db.query(models.PackageSource).join( - models.Package).join(models.PackageBase).filter( - models.PackageBase.ID == pkgbase.ID) + context["sources"] = pkg.package_sources # Package dependencies. dependencies = db.query(models.PackageDependency).join( @@ -246,16 +244,10 @@ async def package(request: Request, name: str) -> Response: models.Package.Name.asc()) context["required_by"] = required_by - licenses = db.query(models.License).join(models.PackageLicense).join( - models.Package).join(models.PackageBase).filter( - models.PackageBase.ID == pkgbase.ID) - context["licenses"] = licenses + context["licenses"] = pkg.package_licenses - conflicts = db.query(models.PackageRelation).join(models.Package).join( - models.PackageBase).filter( - and_(models.PackageRelation.RelTypeID == CONFLICTS_ID, - models.PackageBase.ID == pkgbase.ID) - ) + conflicts = pkg.package_relations.filter( + models.PackageRelation.RelTypeID == CONFLICTS_ID) context["conflicts"] = conflicts provides = pkg.package_relations.filter( diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 7516b324..7e20b082 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -66,7 +66,7 @@ {% if show_package_details and licenses and licenses.count() %} {{ "Licenses" | tr }}: - {{ licenses.all() | join(', ', attribute='Name') | default('None' | tr) }} + {{ licenses.all() | join(', ', attribute='License.Name') }} {% endif %} {% if show_package_details and conflicts and conflicts.count() %} From 7aa959150ec6614fbf0684917a3efe1c2e3918d4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 19:53:50 -0800 Subject: [PATCH 1099/1891] feat(fastapi): add id="conflicts" to package details conflicts Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 2 +- test/test_packages_routes.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 7e20b082..c9b95a26 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -70,7 +70,7 @@ {% endif %} {% if show_package_details and conflicts and conflicts.count() %} - + {{ "Conflicts" | tr }}: {{ conflicts.all() | join(', ', attribute='RelName') }} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index b00844c2..1dabada8 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -24,7 +24,7 @@ from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation from aurweb.models.package_request import ACCEPTED_ID, REJECTED_ID, PackageRequest from aurweb.models.package_vote import PackageVote -from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID, RelationType +from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID, RelationType from aurweb.models.request_type import DELETION_ID, MERGE_ID, RequestType from aurweb.models.user import User from aurweb.testing import setup_test_db @@ -233,6 +233,13 @@ def test_package(client: TestClient, package: Package): RelTypeID=REPLACES_ID, RelName="test_replacer2") + db.create(PackageRelation, PackageID=package.ID, + RelTypeID=CONFLICTS_ID, + RelName="test_conflict1") + db.create(PackageRelation, PackageID=package.ID, + RelTypeID=CONFLICTS_ID, + RelName="test_conflict2") + with client as request: resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) @@ -261,6 +268,10 @@ def test_package(client: TestClient, package: Package): expected = ["test_replacer1", "test_replacer2"] assert replaces[0].text.strip() == ", ".join(expected) + conflicts = root.xpath('//tr[@id="conflicts"]/td') + expected = ["test_conflict1", "test_conflict2"] + assert conflicts[0].text.strip() == ", ".join(expected) + def test_package_comments(client: TestClient, user: User, package: Package): now = (datetime.utcnow().timestamp()) From 686c0322907ed3bb8015c42f050f845323549776 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 11 Nov 2021 19:55:04 -0800 Subject: [PATCH 1100/1891] feat(fastapi): add id="licenses" to package details licenses Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 2 +- test/test_packages_routes.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index c9b95a26..67c32170 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -64,7 +64,7 @@ {% endif %} {% if show_package_details and licenses and licenses.count() %} - + {{ "Licenses" | tr }}: {{ licenses.all() | join(', ', attribute='License.Name') }} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 1dabada8..1bdb3ea3 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -11,6 +11,7 @@ from fastapi.testclient import TestClient from sqlalchemy import and_ from aurweb import asgi, db, defaults +from aurweb.models import License, PackageLicense from aurweb.models.account_type import USER_ID, AccountType from aurweb.models.dependency_type import DependencyType from aurweb.models.official_provider import OfficialProvider @@ -240,6 +241,17 @@ def test_package(client: TestClient, package: Package): RelTypeID=CONFLICTS_ID, RelName="test_conflict2") + # Create some licenses. + licenses = [ + db.create(License, Name="test_license1"), + db.create(License, Name="test_license2") + ] + + db.create(PackageLicense, PackageID=package.ID, + License=licenses[0]) + db.create(PackageLicense, PackageID=package.ID, + License=licenses[1]) + with client as request: resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) @@ -260,6 +272,10 @@ def test_package(client: TestClient, package: Package): pkgbase = row.find("./td/a") assert pkgbase.text.strip() == package.PackageBase.Name + licenses = root.xpath('//tr[@id="licenses"]/td') + expected = ["test_license1", "test_license2"] + assert licenses[0].text.strip() == ", ".join(expected) + provides = root.xpath('//tr[@id="provides"]/td') expected = ["test_provider1", "test_provider2"] assert provides[0].text.strip() == ", ".join(expected) From bd59adc886a6ce53fc5fe4c874a81cc9f8d4fcb5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 12 Nov 2021 17:39:26 -0800 Subject: [PATCH 1101/1891] fix(fastapi): use NumVotes for votes field in package details Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 67c32170..dbb81c19 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -132,11 +132,11 @@ {{ "Votes" | tr }}: {% if not is_maintainer %} - {{ pkgbase.package_votes.count() }} + {{ pkgbase.NumVotes }} {% else %} - {{ pkgbase.package_votes.count() }} + {{ pkgbase.NumVotes }} {% endif %} From cee7512e4d843c771a1aee42277781fd949648cc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 12 Nov 2021 20:49:25 -0800 Subject: [PATCH 1102/1891] cleanup(fastapi): simplify PackageDependency.is_package() Signed-off-by: Kevin Morris --- aurweb/models/package_dependency.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index edaa6538..c4c5f6c1 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -1,9 +1,10 @@ from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship -from aurweb import schema +from aurweb import db, schema from aurweb.models.declarative import Base from aurweb.models.dependency_type import DependencyType as _DependencyType +from aurweb.models.official_provider import OfficialProvider as _OfficialProvider from aurweb.models.package import Package as _Package @@ -46,11 +47,7 @@ class PackageDependency(Base): params=("NULL")) def is_package(self) -> bool: - # TODO: Improve the speed of this query if possible. - from aurweb import db - from aurweb.models.official_provider import OfficialProvider - from aurweb.models.package import Package - pkg = db.query(Package, Package.Name == self.DepName) - official = db.query(OfficialProvider, - OfficialProvider.Name == self.DepName) - return pkg.scalar() or official.scalar() + pkg = db.query(_Package).filter(_Package.Name == self.DepName).exists() + official = db.query(_OfficialProvider).filter( + _OfficialProvider.Name == self.DepName).exists() + return db.query(pkg).scalar() or db.query(official).scalar() From f8ba2c53421050ab154040a7cbb2c0de554ae8d1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 14 Nov 2021 15:32:11 -0800 Subject: [PATCH 1103/1891] cleanup(fastapi): simplify aurweb.routers.accounts.accounts_post Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 498568ad..83c16ed0 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -662,7 +662,7 @@ async def accounts(request: Request): account_type.TRUSTED_USER_AND_DEV}) async def accounts_post(request: Request, O: int = Form(default=0), # Offset - SB: str = Form(default=str()), # Search By + SB: str = Form(default=str()), # Sort By U: str = Form(default=str()), # Username T: str = Form(default=str()), # Account Type S: bool = Form(default=False), # Suspended @@ -705,23 +705,19 @@ async def accounts_post(request: Request, # Populate this list with any additional statements to # be ANDed together. - statements = [] - if account_type_id is not None: - statements.append(models.AccountType.ID == account_type_id) - if U: - statements.append(models.User.Username.like(f"%{U}%")) - if S: - statements.append(models.User.Suspended == S) - if E: - statements.append(models.User.Email.like(f"%{E}%")) - if R: - statements.append(models.User.RealName.like(f"%{R}%")) - if I: - statements.append(models.User.IRCNick.like(f"%{I}%")) - if K: - statements.append(models.User.PGPKey.like(f"%{K}%")) + statements = [ + v for k, v in [ + (account_type_id is not None, models.AccountType.ID == account_type_id), + (bool(U), models.User.Username.like(f"%{U}%")), + (bool(S), models.User.Suspended == S), + (bool(E), models.User.Email.like(f"%{E}%")), + (bool(R), models.User.RealName.like(f"%{R}%")), + (bool(I), models.User.IRCNick.like(f"%{I}%")), + (bool(K), models.User.PGPKey.like(f"%{K}%")), + ] if k + ] - # Filter the query by combining all statements added above into + # Filter the query by coe-mbining all statements added above into # an AND statement, unless there's just one statement, which # we pass on to filter() as args. if statements: From 4103ab49c9c6922e89f89a25fc3b2b5b461c1bcb Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 14 Nov 2021 15:36:06 -0800 Subject: [PATCH 1104/1891] housekeep(fastapi): rework aurweb.db session API Changes: ------- - Add aurweb.db.get_session() - Returns aurweb.db's global `session` instance - Provides us a way to change the implementation of the session instance without interrupting user code. - Use aurweb.db.get_session() in session API methods - Add docstrings to session API methods - Refactor aurweb.db.delete - Normalize aurweb.db.delete to an alias of session.delete - Refresh instances in places we depend on their non-PK columns being up to date. Signed-off-by: Kevin Morris --- aurweb/auth.py | 8 ++- aurweb/db.py | 89 ++++++++++++++++++++------------- aurweb/models/ban.py | 9 ++-- aurweb/models/user.py | 2 +- aurweb/packages/util.py | 18 +++++-- aurweb/ratelimit.py | 4 +- aurweb/routers/accounts.py | 49 ++++++++---------- aurweb/routers/packages.py | 68 +++++++++++++------------ aurweb/rpc.py | 31 ++++++++++-- aurweb/scripts/popupdate.py | 2 +- aurweb/scripts/rendercomment.py | 12 +++-- aurweb/testing/__init__.py | 10 ++-- aurweb/users/__init__.py | 0 aurweb/users/util.py | 19 +++++++ aurweb/util.py | 1 + test/test_account_type.py | 4 +- test/test_db.py | 6 +-- test/test_dependency_type.py | 4 +- test/test_packages_util.py | 6 +++ test/test_ratelimit.py | 2 +- test/test_relation_type.py | 2 +- test/test_request_type.py | 4 +- 22 files changed, 212 insertions(+), 138 deletions(-) create mode 100644 aurweb/users/__init__.py create mode 100644 aurweb/users/util.py diff --git a/aurweb/auth.py b/aurweb/auth.py index 38754db0..98a43fd5 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -13,7 +13,7 @@ from starlette.requests import HTTPConnection import aurweb.config -from aurweb import l10n, util +from aurweb import db, l10n, util from aurweb.models import Session, User from aurweb.models.account_type import ACCOUNT_TYPE_ID from aurweb.templates import make_variable_context, render_template @@ -98,14 +98,12 @@ class AnonymousUser: class BasicAuthBackend(AuthenticationBackend): async def authenticate(self, conn: HTTPConnection): - from aurweb.db import session - sid = conn.cookies.get("AURSID") if not sid: return (None, AnonymousUser()) now_ts = datetime.utcnow().timestamp() - record = session.query(Session).filter( + record = db.query(Session).filter( and_(Session.SessionID == sid, Session.LastUpdateTS >= now_ts)).first() @@ -116,7 +114,7 @@ class BasicAuthBackend(AuthenticationBackend): # At this point, we cannot have an invalid user if the record # exists, due to ForeignKey constraints in the schema upheld # by mysqlclient. - user = session.query(User).filter(User.ID == record.UsersID).first() + user = db.query(User).filter(User.ID == record.UsersID).first() user.nonce = util.make_nonce() user.authenticated = True diff --git a/aurweb/db.py b/aurweb/db.py index c1e80751..39232d5a 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -2,10 +2,10 @@ import functools import math import re -from typing import Iterable +from typing import Iterable, NewType from sqlalchemy import event -from sqlalchemy.orm import scoped_session +from sqlalchemy.orm import Query, scoped_session import aurweb.config import aurweb.util @@ -22,6 +22,9 @@ session = None # Global introspected object memo. introspected = dict() +# A mocked up type. +Base = NewType("aurweb.models.declarative_base.Base", "Base") + def make_random_value(table: str, column: str): """ Generate a unique, random value for a string column in a table. @@ -58,55 +61,69 @@ def make_random_value(table: str, column: str): return string -def query(model, *args, **kwargs): - return session.query(model).filter(*args, **kwargs) +def get_session(): + """ Return aurweb.db's global session. """ + return session -def create(model, *args, **kwargs): - instance = model(*args, **kwargs) +def refresh(model: Base) -> Base: + """ Refresh the session's knowledge of `model`. """ + get_session().refresh(model) + return model + + +def query(Model: Base, *args, **kwargs) -> Query: + """ + Perform an ORM query against the database session. + + This method also runs Query.filter on the resulting model + query with *args and **kwargs. + + :param Model: Declarative ORM class + """ + return get_session().query(Model).filter(*args, **kwargs) + + +def create(Model: Base, *args, **kwargs) -> Base: + """ + Create a record and add() it to the database session. + + :param Model: Declarative ORM class + :return: Model instance + """ + instance = Model(*args, **kwargs) return add(instance) -def delete(model, *args, **kwargs): - instance = session.query(model).filter(*args, **kwargs) - for record in instance: - session.delete(record) +def delete(model: Base) -> None: + """ + Delete a set of records found by Query.filter(*args, **kwargs). + + :param Model: Declarative ORM class + """ + get_session().delete(model) -def delete_all(iterable: Iterable): - with begin(): - for obj in iterable: - session.delete(obj) +def delete_all(iterable: Iterable) -> None: + """ Delete each instance found in `iterable`. """ + session_ = get_session() + aurweb.util.apply_all(iterable, session_.delete) -def rollback(): - session.rollback() +def rollback() -> None: + """ Rollback the database session. """ + get_session().rollback() -def add(model): - session.add(model) +def add(model: Base) -> Base: + """ Add `model` to the database session. """ + get_session().add(model) return model def begin(): - """ Begin an SQLAlchemy SessionTransaction. - - This context is **required** to perform an modifications to the - database. - - Example: - - with db.begin(): - object = db.create(...) - # On __exit__, db.commit() is run. - - with db.begin(): - object = db.delete(...) - # On __exit__, db.commit() is run. - - :return: A new SessionTransaction based on session - """ - return session.begin() + """ Begin an SQLAlchemy SessionTransaction. """ + return get_session().begin() def get_sqlalchemy_url(): diff --git a/aurweb/models/ban.py b/aurweb/models/ban.py index a70be7b9..0fcb6d2e 100644 --- a/aurweb/models/ban.py +++ b/aurweb/models/ban.py @@ -1,6 +1,6 @@ from fastapi import Request -from aurweb import schema +from aurweb import db, schema from aurweb.models.declarative import Base @@ -10,11 +10,10 @@ class Ban(Base): __mapper_args__ = {"primary_key": [__table__.c.IPAddress]} def __init__(self, **kwargs): - self.IPAddress = kwargs.get("IPAddress") - self.BanTS = kwargs.get("BanTS") + super().__init__(**kwargs) def is_banned(request: Request): - from aurweb.db import session ip = request.client.host - return session.query(Ban).filter(Ban.IPAddress == ip).first() is not None + exists = db.query(Ban).filter(Ban.IPAddress == ip).exists() + return db.query(exists).scalar() diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 8db34c38..43910db9 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -146,7 +146,7 @@ class User(Base): self.authenticated = False if self.session: with db.begin(): - db.session.delete(self.session) + db.delete(self.session) def is_trusted_user(self): return self.AccountType.ID in { diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index cdec26f3..78f5bf18 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -110,18 +110,26 @@ def get_pkg_or_base( raise HTTPException(status_code=HTTPStatus.NOT_FOUND) instance = db.query(cls).filter(cls.Name == name).first() - if cls == models.PackageBase and not instance: + if not instance: raise HTTPException(status_code=HTTPStatus.NOT_FOUND) - return instance + return db.refresh(instance) -def get_pkgbase_comment( - pkgbase: models.PackageBase, id: int) -> models.PackageComment: +def get_pkgbase_comment(pkgbase: models.PackageBase, id: int) \ + -> models.PackageComment: comment = pkgbase.comments.filter(models.PackageComment.ID == id).first() if not comment: raise HTTPException(status_code=HTTPStatus.NOT_FOUND) - return comment + return db.refresh(comment) + + +def get_pkgreq_by_id(id: int): + pkgreq = db.query(models.PackageRequest).filter( + models.PackageRequest.ID == id).first() + if not pkgreq: + raise HTTPException(status_code=HTTPStatus.NOT_FOUND) + return db.refresh(pkgreq) @register_filter("out_of_date") diff --git a/aurweb/ratelimit.py b/aurweb/ratelimit.py index e306f7a7..a71cb1cc 100644 --- a/aurweb/ratelimit.py +++ b/aurweb/ratelimit.py @@ -40,8 +40,10 @@ def _update_ratelimit_db(request: Request): now = int(datetime.utcnow().timestamp()) time_to_delete = now - window_length + records = db.query(ApiRateLimit).filter( + ApiRateLimit.WindowStart < time_to_delete) with db.begin(): - db.delete(ApiRateLimit, ApiRateLimit.WindowStart < time_to_delete) + db.delete_all(records) host = request.client.host record = db.query(ApiRateLimit, ApiRateLimit.IP == host).first() diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 83c16ed0..aca322b5 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -4,7 +4,7 @@ import typing from datetime import datetime from http import HTTPStatus -from fastapi import APIRouter, Form, HTTPException, Request +from fastapi import APIRouter, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, func, or_ @@ -20,6 +20,7 @@ from aurweb.models.account_type import (DEVELOPER, DEVELOPER_ID, TRUSTED_USER, T from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.scripts.notify import ResetKeyNotification, WelcomeNotification from aurweb.templates import make_context, make_variable_context, render_template +from aurweb.users.util import get_user_by_name router = APIRouter() logger = logging.get_logger(__name__) @@ -49,6 +50,7 @@ async def passreset_post(request: Request, return render_template(request, "passreset.html", context, status_code=HTTPStatus.NOT_FOUND) + db.refresh(user) if resetkey: context["resetkey"] = resetkey @@ -83,7 +85,7 @@ async def passreset_post(request: Request, with db.begin(): user.ResetKey = str() if user.session: - db.session.delete(user.session) + db.delete(user.session) user.update_password(password) # Render ?step=complete. @@ -458,15 +460,15 @@ def cannot_edit(request, user): @router.get("/account/{username}/edit", response_class=HTMLResponse) @auth_required(True, redirect="/account/{username}") -async def account_edit(request: Request, - username: str): +async def account_edit(request: Request, username: str): user = db.query(models.User, models.User.Username == username).first() + response = cannot_edit(request, user) if response: return response context = await make_variable_context(request, "Accounts") - context["user"] = user + context["user"] = db.refresh(user) context = make_account_form_context(context, request, user, dict()) return render_template(request, "account/edit.html", context) @@ -497,16 +499,14 @@ async def account_edit_post(request: Request, ON: bool = Form(default=False), # Owner Notify T: int = Form(default=None), passwd: str = Form(default=str())): - from aurweb.db import session - - user = session.query(models.User).filter( + user = db.query(models.User).filter( models.User.Username == username).first() response = cannot_edit(request, user) if response: return response context = await make_variable_context(request, "Accounts") - context["user"] = user + context["user"] = db.refresh(user) args = dict(await request.form()) context = make_account_form_context(context, request, user, args) @@ -575,7 +575,7 @@ async def account_edit_post(request: Request, user.ssh_pub_key.Fingerprint = fingerprint elif user.ssh_pub_key: # Else, if the user has a public key already, delete it. - session.delete(user.ssh_pub_key) + db.delete(user.ssh_pub_key) if T and T != user.AccountTypeID: with db.begin(): @@ -617,27 +617,16 @@ account_template = ( status_code=HTTPStatus.UNAUTHORIZED) async def account(request: Request, username: str): _ = l10n.get_translator_for_request(request) - context = await make_variable_context(request, - _("Account") + " " + username) - - user = db.query(models.User, models.User.Username == username).first() - if not user: - raise HTTPException(status_code=HTTPStatus.NOT_FOUND) - - context["user"] = user - + context = await make_variable_context( + request, _("Account") + " " + username) + context["user"] = get_user_by_name(username) return render_template(request, "account/show.html", context) @router.get("/account/{username}/comments") @auth_required(redirect="/account/{username}/comments") async def account_comments(request: Request, username: str): - user = db.query(models.User).filter( - models.User.Username == username - ).first() - if not user: - raise HTTPException(status_code=HTTPStatus.NOT_FOUND) - + user = get_user_by_name(username) context = make_context(request, "Accounts") context["username"] = username context["comments"] = user.package_comments.order_by( @@ -725,7 +714,7 @@ async def accounts_post(request: Request, # Finally, order and truncate our users for the current page. users = query.order_by(*order_by).limit(pp).offset(offset) - context["users"] = users + context["users"] = util.apply_all(users, db.refresh) return render_template(request, "account/index.html", context) @@ -751,6 +740,9 @@ async def terms_of_service(request: Request): unaccepted = db.query(models.Term).filter( ~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID))).all() + for record in (diffs + unaccepted): + db.refresh(record) + # Translate the 'Terms of Service' part of our page title. _ = l10n.get_translator_for_request(request) title = f"AUR {_('Terms of Service')}" @@ -782,18 +774,21 @@ async def terms_of_service_post(request: Request, # We already did the database filters here, so let's just use # them instead of reiterating the process in terms_of_service. accept_needed = sorted(unaccepted + diffs) - return render_terms_of_service(request, context, accept_needed) + return render_terms_of_service( + request, context, util.apply_all(accept_needed, db.refresh)) with db.begin(): # For each term we found, query for the matching accepted term # and update its Revision to the term's current Revision. for term in diffs: + db.refresh(term) accepted_term = request.user.accepted_terms.filter( models.AcceptedTerm.TermsID == term.ID).first() accepted_term.Revision = term.Revision # For each term that was never accepted, accept it! for term in unaccepted: + db.refresh(term) db.create(models.AcceptedTerm, User=request.user, Term=term, Revision=term.Revision) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 0949909e..07e8af72 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -4,7 +4,7 @@ from typing import Any, Dict, List from fastapi import APIRouter, Form, HTTPException, Query, Request, Response from fastapi.responses import JSONResponse, RedirectResponse -from sqlalchemy import and_, case +from sqlalchemy import case import aurweb.filters import aurweb.packages.util @@ -15,9 +15,9 @@ from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.models.request_type import DELETION_ID, MERGE, MERGE_ID from aurweb.packages.search import PackageSearch -from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, query_notified, query_voted +from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, get_pkgreq_by_id, query_notified, query_voted from aurweb.scripts import notify, popupdate -from aurweb.scripts.rendercomment import update_comment_render +from aurweb.scripts.rendercomment import update_comment_render_fastapi from aurweb.templates import make_context, make_variable_context, render_raw_template, render_template logger = logging.get_logger(__name__) @@ -92,7 +92,10 @@ async def packages_get(request: Request, context: Dict[str, Any], # Insert search results into the context. results = search.results() - context["packages"] = results.limit(per_page).offset(offset) + + packages = results.limit(per_page).offset(offset) + util.apply_all(packages, db.refresh) + context["packages"] = packages context["packages_voted"] = query_voted( context.get("packages"), request.user) context["packages_notified"] = query_notified( @@ -132,6 +135,7 @@ def create_request_if_missing(requests: List[models.PackageRequest], ClosedTS=now, Closer=user) requests.append(pkgreq) + return pkgreq def delete_package(deleter: models.User, package: models.Package): @@ -147,8 +151,9 @@ def delete_package(deleter: models.User, package: models.Package): ).first() with db.begin(): - create_request_if_missing( + pkgreq = create_request_if_missing( requests, reqtype, deleter, package) + db.refresh(pkgreq) bases_to_delete.append(package.PackageBase) @@ -171,8 +176,9 @@ def delete_package(deleter: models.User, package: models.Package): ) # Perform all the deletions. - db.delete_all([package]) - db.delete_all(bases_to_delete) + with db.begin(): + db.delete(package) + db.delete_all(bases_to_delete) # Send out all the notifications. util.apply_all(notifications, lambda n: n.send()) @@ -221,8 +227,7 @@ async def make_single_context(request: Request, async def package(request: Request, name: str) -> Response: # Get the Package. pkg = get_pkg_or_base(name, models.Package) - pkgbase = (get_pkg_or_base(name, models.PackageBase) - if not pkg else pkg.PackageBase) + pkgbase = pkg.PackageBase # Add our base information. context = await make_single_context(request, pkgbase) @@ -312,7 +317,7 @@ async def pkgbase_comments_post( db.create(models.PackageNotification, User=request.user, PackageBase=pkgbase) - update_comment_render(comment.ID) + update_comment_render_fastapi(comment) # Redirect to the pkgbase page. return RedirectResponse(f"/pkgbase/{pkgbase.Name}#comment-{comment.ID}", @@ -374,7 +379,7 @@ async def pkgbase_comment_post( db.create(models.PackageNotification, User=request.user, PackageBase=pkgbase) - update_comment_render(db_comment.ID) + update_comment_render_fastapi(db_comment) if not next: next = f"/pkgbase/{pkgbase.Name}" @@ -539,7 +544,7 @@ def remove_users(pkgbase, usernames): conn, comaintainer.User.ID, pkgbase.ID ) ) - db.session.delete(comaintainer) + db.delete(comaintainer) # Send out notifications if need be. for notify_ in notifications: @@ -679,14 +684,8 @@ async def requests(request: Request, @router.get("/pkgbase/{name}/request") @auth_required(True, redirect="/pkgbase/{name}/request") async def package_request(request: Request, name: str): + pkgbase = get_pkg_or_base(name, models.PackageBase) context = await make_variable_context(request, "Submit Request") - - pkgbase = db.query(models.PackageBase).filter( - models.PackageBase.Name == name).first() - - if not pkgbase: - raise HTTPException(status_code=HTTPStatus.NOT_FOUND) - context["pkgbase"] = pkgbase return render_template(request, "pkgbase/request.html", context) @@ -729,6 +728,7 @@ async def pkgbase_request_post(request: Request, name: str, ] return render_template(request, "pkgbase/request.html", context) + db.refresh(target) if target.ID == pkgbase.ID: # TODO: This error needs to be translated. context["errors"] = [ @@ -767,8 +767,7 @@ async def pkgbase_request_post(request: Request, name: str, @router.get("/requests/{id}/close") @auth_required(True, redirect="/requests/{id}/close") async def requests_close(request: Request, id: int): - pkgreq = db.query(models.PackageRequest).filter( - models.PackageRequest.ID == id).first() + pkgreq = get_pkgreq_by_id(id) if not request.user.is_elevated() and request.user != pkgreq.User: # Request user doesn't have permission here: redirect to '/'. return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) @@ -783,8 +782,7 @@ async def requests_close(request: Request, id: int): async def requests_close_post(request: Request, id: int, reason: int = Form(default=0), comments: str = Form(default=str())): - pkgreq = db.query(models.PackageRequest).filter( - models.PackageRequest.ID == id).first() + pkgreq = get_pkgreq_by_id(id) if not request.user.is_elevated() and request.user != pkgreq.User: # Request user doesn't have permission here: redirect to '/'. return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) @@ -823,13 +821,17 @@ async def pkgbase_keywords(request: Request, name: str, keywords = set(keywords.split(" ")) # Delete all keywords which are not supplied by the user. - with db.begin(): - db.delete(models.PackageKeyword, - and_(models.PackageKeyword.PackageBaseID == pkgbase.ID, - ~models.PackageKeyword.Keyword.in_(keywords))) + other_keywords = pkgbase.keywords.filter( + ~models.PackageKeyword.Keyword.in_(keywords)) + other_keyword_strings = [kwd.Keyword for kwd in other_keywords] - existing_keywords = set(kwd.Keyword for kwd in pkgbase.keywords.all()) + existing_keywords = set( + kwd.Keyword for kwd in + pkgbase.keywords.filter( + ~models.PackageKeyword.Keyword.in_(other_keyword_strings)) + ) with db.begin(): + db.delete_all(other_keywords) for keyword in keywords.difference(existing_keywords): db.create(models.PackageKeyword, PackageBase=pkgbase, @@ -940,7 +942,7 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: models.PackageBase): has_cred = request.user.has_credential("CRED_PKGBASE_NOTIFY") if has_cred and notif: with db.begin(): - db.session.delete(notif) + db.delete(notif) @router.post("/pkgbase/{name}/unnotify") @@ -988,7 +990,7 @@ async def pkgbase_unvote(request: Request, name: str): has_cred = request.user.has_credential("CRED_PKGBASE_VOTE") if has_cred and vote: with db.begin(): - db.session.delete(vote) + db.delete(vote) # Update NumVotes/Popularity. conn = db.ConnectionExecutor(db.get_engine().raw_connection()) @@ -1015,7 +1017,7 @@ def pkgbase_disown_instance(request: Request, pkgbase: models.PackageBase): if co: with db.begin(): pkgbase.Maintainer = co.User - db.session.delete(co) + db.delete(co) else: pkgbase.Maintainer = None @@ -1463,8 +1465,8 @@ def pkgbase_merge_instance(request: Request, pkgbase: models.PackageBase, with db.begin(): # Delete pkgbase and its packages now that everything's merged. for pkg in pkgbase.packages: - db.session.delete(pkg) - db.session.delete(pkgbase) + db.delete(pkg) + db.delete(pkgbase) # Accept merge requests related to this pkgbase and target. for pkgreq in requests: diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 4ab005af..03662790 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import Any, Dict, List +from typing import Any, Callable, Dict, List, NewType from sqlalchemy import and_ @@ -25,6 +25,10 @@ REL_TYPES = { } +DataGenerator = NewType("DataGenerator", + Callable[[models.Package], Dict[str, Any]]) + + class RPCError(Exception): pass @@ -188,15 +192,32 @@ class RPC: self._update_json_relations(package, data) return data - def _handle_multiinfo_type(self, args: List[str] = [], **kwargs): + def _assemble_json_data(self, packages: List[models.Package], + data_generator: DataGenerator) \ + -> List[Dict[str, Any]]: + """ + Assemble JSON data out of a list of packages. + + :param packages: A list of Package instances or a Package ORM query + :param data_generator: Generator callable of single-Package JSON data + """ + output = [] + for pkg in packages: + db.refresh(pkg) + output.append(data_generator(pkg)) + return output + + def _handle_multiinfo_type(self, args: List[str] = [], **kwargs) \ + -> List[Dict[str, Any]]: self._enforce_args(args) args = set(args) packages = db.query(models.Package).filter( models.Package.Name.in_(args)) - return [self._get_info_json_data(pkg) for pkg in packages] + return self._assemble_json_data(packages, self._get_info_json_data) def _handle_search_type(self, by: str = defaults.RPC_SEARCH_BY, - args: List[str] = []): + args: List[str] = []) \ + -> List[Dict[str, Any]]: # If `by` isn't maintainer and we don't have any args, raise an error. # In maintainer's case, return all orphans if there are no args, # so we need args to pass through to the handler without errors. @@ -212,7 +233,7 @@ class RPC: max_results = config.getint("options", "max_rpc_results") results = search.results().limit(max_results) - return [self._get_json_data(pkg) for pkg in results] + return self._assemble_json_data(results, self._get_json_data) def _handle_msearch_type(self, args: List[str] = [], **kwargs): return self._handle_search_type(by="m", args=args) diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index fa82208d..db4ba170 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -29,7 +29,7 @@ def run_single(conn, pkgbase): conn.commit() conn.close() - aurweb.db.session.refresh(pkgbase) + aurweb.db.refresh(pkgbase) def main(): diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index a00448d8..efa5357f 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -129,9 +129,14 @@ def save_rendered_comment(conn, commentid, html): [html, commentid]) -def update_comment_render(commentid): - conn = aurweb.db.Connection() +def update_comment_render_fastapi(comment): + conn = aurweb.db.ConnectionExecutor( + aurweb.db.get_engine().raw_connection()) + update_comment_render(conn, comment.ID) + aurweb.db.refresh(comment) + +def update_comment_render(conn, commentid): text, pkgbase = get_comment(conn, commentid) html = markdown.markdown(text, extensions=[ 'fenced_code', @@ -152,7 +157,8 @@ def update_comment_render(commentid): def main(): commentid = int(sys.argv[1]) - update_comment_render(commentid) + conn = aurweb.db.Connection() + update_comment_render(conn, commentid) if __name__ == '__main__': diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py index 65d34253..2dd377e1 100644 --- a/aurweb/testing/__init__.py +++ b/aurweb/testing/__init__.py @@ -19,7 +19,7 @@ def references_graph(table): "regexp_1": r'(?i)\s+references\s+("|\')?', "regexp_2": r'("|\')?\s*\(', } - cursor = aurweb.db.session.execute(query, params=params) + cursor = aurweb.db.get_session().execute(query, params=params) return [row[0] for row in cursor.fetchall()] @@ -51,7 +51,7 @@ def setup_test_db(*args): db_backend = aurweb.config.get("database", "backend") if db_backend != "sqlite": # pragma: no cover - aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 0") + aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 0") else: # We're using sqlite, setup tables to be deleted without violating # foreign key constraints by graphing references. @@ -59,10 +59,10 @@ def setup_test_db(*args): references_graph(table) for table in tables)) for table in tables: - aurweb.db.session.execute(f"DELETE FROM {table}") + aurweb.db.get_session().execute(f"DELETE FROM {table}") if db_backend != "sqlite": # pragma: no cover - aurweb.db.session.execute("SET FOREIGN_KEY_CHECKS = 1") + aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 1") # Expunge all objects from SQLAlchemy's IdentityMap. - aurweb.db.session.expunge_all() + aurweb.db.get_session().expunge_all() diff --git a/aurweb/users/__init__.py b/aurweb/users/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aurweb/users/util.py b/aurweb/users/util.py new file mode 100644 index 00000000..e9635f08 --- /dev/null +++ b/aurweb/users/util.py @@ -0,0 +1,19 @@ +from http import HTTPStatus + +from fastapi import HTTPException + +from aurweb import db +from aurweb.models import User + + +def get_user_by_name(username: str) -> User: + """ + Query a user by its username. + + :param username: User.Username + :return: User instance + """ + user = db.query(User).filter(User.Username == username).first() + if not user: + raise HTTPException(status_code=int(HTTPStatus.NOT_FOUND)) + return db.refresh(user) diff --git a/aurweb/util.py b/aurweb/util.py index 88142cbc..1c2042fa 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -155,6 +155,7 @@ def get_ssh_fingerprints(): def apply_all(iterable: Iterable, fn: Callable): for item in iterable: fn(item) + return iterable def sanitize_params(offset: str, per_page: str) -> Tuple[int, int]: diff --git a/test/test_account_type.py b/test/test_account_type.py index 86e68253..12472348 100644 --- a/test/test_account_type.py +++ b/test/test_account_type.py @@ -20,7 +20,7 @@ def setup(): yield account_type with begin(): - delete(AccountType, AccountType.ID == account_type.ID) + delete(account_type) def test_account_type(): @@ -50,4 +50,4 @@ def test_user_account_type_relationship(): # This must be deleted here to avoid foreign key issues when # deleting the temporary AccountType in the fixture. with begin(): - delete(User, User.ID == user.ID) + delete(user) diff --git a/test/test_db.py b/test/test_db.py index 7798d2f6..8283a957 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -279,13 +279,13 @@ def test_connection_execute_paramstyle_unsupported(): def test_create_delete(): with db.begin(): - db.create(AccountType, AccountType="test") + account_type = db.create(AccountType, AccountType="test") record = db.query(AccountType, AccountType.AccountType == "test").first() assert record is not None with db.begin(): - db.delete(AccountType, AccountType.AccountType == "test") + db.delete(account_type) record = db.query(AccountType, AccountType.AccountType == "test").first() assert record is None @@ -306,7 +306,7 @@ def test_add_commit(): # Remove the record. with db.begin(): - db.delete(AccountType, AccountType.ID == account_type.ID) + db.delete(account_type) def test_connection_executor_mysql_paramstyle(): diff --git a/test/test_dependency_type.py b/test/test_dependency_type.py index 4d555123..cb8dece4 100644 --- a/test/test_dependency_type.py +++ b/test/test_dependency_type.py @@ -24,7 +24,7 @@ def test_dependency_type_creation(): assert bool(dependency_type.ID) assert dependency_type.Name == "Test Type" with begin(): - delete(DependencyType, DependencyType.ID == dependency_type.ID) + delete(dependency_type) def test_dependency_type_null_name_uses_default(): @@ -32,4 +32,4 @@ def test_dependency_type_null_name_uses_default(): dependency_type = create(DependencyType) assert dependency_type.Name == str() with begin(): - delete(DependencyType, DependencyType.ID == dependency_type.ID) + delete(dependency_type) diff --git a/test/test_packages_util.py b/test/test_packages_util.py index 1396734b..622c08c2 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -2,6 +2,7 @@ from datetime import datetime import pytest +from fastapi import HTTPException from fastapi.testclient import TestClient from aurweb import asgi, db @@ -98,3 +99,8 @@ def test_query_notified(maintainer: User, package: Package): query = db.query(Package).filter(Package.ID == package.ID).all() query_notified = util.query_notified(query, maintainer) assert query_notified[package.PackageBase.ID] + + +def test_pkgreq_by_id_not_found(): + with pytest.raises(HTTPException): + util.get_pkgreq_by_id(0) diff --git a/test/test_ratelimit.py b/test/test_ratelimit.py index 2634b714..0a72a7e4 100644 --- a/test/test_ratelimit.py +++ b/test/test_ratelimit.py @@ -103,7 +103,7 @@ def test_ratelimit_db(get: mock.MagicMock, getboolean: mock.MagicMock, # Delete the ApiRateLimit record. with db.begin(): - db.delete(ApiRateLimit) + db.delete(db.query(ApiRateLimit).first()) # Should be good to go again! assert not check_ratelimit(request) diff --git a/test/test_relation_type.py b/test/test_relation_type.py index fbc22c71..d2dabceb 100644 --- a/test/test_relation_type.py +++ b/test/test_relation_type.py @@ -18,7 +18,7 @@ def test_relation_type_creation(): assert relation_type.Name == "test-relation" with db.begin(): - db.delete(RelationType, RelationType.ID == relation_type.ID) + db.delete(relation_type) def test_relation_types(): diff --git a/test/test_request_type.py b/test/test_request_type.py index 8d21c2d9..0db24921 100644 --- a/test/test_request_type.py +++ b/test/test_request_type.py @@ -18,7 +18,7 @@ def test_request_type_creation(): assert request_type.Name == "Test Request" with db.begin(): - db.delete(RequestType, RequestType.ID == request_type.ID) + db.delete(request_type) def test_request_type_null_name_returns_empty_string(): @@ -29,7 +29,7 @@ def test_request_type_null_name_returns_empty_string(): assert request_type.Name == str() with db.begin(): - db.delete(RequestType, RequestType.ID == request_type.ID) + db.delete(request_type) def test_request_type_name_display(): From 12400147fc0e1f3bed2bc54a92c4de76cf8312f2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 14 Nov 2021 16:02:00 -0800 Subject: [PATCH 1105/1891] fix: initialize engine and session in util/adduser.py Signed-off-by: Kevin Morris --- util/adduser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/util/adduser.py b/util/adduser.py index 7e35d13d..1853869a 100644 --- a/util/adduser.py +++ b/util/adduser.py @@ -33,6 +33,7 @@ def parse_args(): def main(): args = parse_args() + db.get_engine() type = db.query(AccountType, AccountType.AccountType == args.type).first() with db.begin(): From 9424341b55bf55b4b064cfc2b8e4d89536901e69 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 14 Nov 2021 23:33:58 -0800 Subject: [PATCH 1106/1891] fix(docker): fix cgit css config Signed-off-by: Kevin Morris --- docker-compose.yml | 2 ++ docker/cgit-entrypoint.sh | 1 + 2 files changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 2fba1305..bda4ddfb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -112,6 +112,7 @@ services: environment: - AUR_CONFIG=/aurweb/conf/config - CGIT_CLONE_PREFIX=${AURWEB_PHP_PREFIX} + - CGIT_CSS=/css/cgit.css entrypoint: /docker/cgit-entrypoint.sh command: /docker/scripts/run-cgit.sh 3000 healthcheck: @@ -131,6 +132,7 @@ services: environment: - AUR_CONFIG=/aurweb/conf/config - CGIT_CLONE_PREFIX=${AURWEB_FASTAPI_PREFIX} + - CGIT_CSS=/static/css/cgit.css entrypoint: /docker/cgit-entrypoint.sh command: /docker/scripts/run-cgit.sh 3000 healthcheck: diff --git a/docker/cgit-entrypoint.sh b/docker/cgit-entrypoint.sh index 3615ade5..f9ca86c0 100755 --- a/docker/cgit-entrypoint.sh +++ b/docker/cgit-entrypoint.sh @@ -8,5 +8,6 @@ sed -ri "s|clone-prefix=.*|clone-prefix=${CGIT_CLONE_PREFIX}|" /etc/cgitrc sed -ri 's|header=.*|header=/aurweb/web/template/cgit/header.html|' /etc/cgitrc sed -ri 's|footer=.*|footer=/aurweb/web/template/cgit/footer.html|' /etc/cgitrc sed -ri 's|repo\.path=.*|repo.path=/aurweb/aur.git|' /etc/cgitrc +sed -ri "s|^(css)=.*$|\1=${CGIT_CSS}|" /etc/cgitrc exec "$@" From 7f6d9966e585626da181a6e642e1a73710f2f817 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 14 Nov 2021 16:02:00 -0800 Subject: [PATCH 1107/1891] fix: initialize engine and session in util/adduser.py Signed-off-by: Kevin Morris --- util/adduser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/util/adduser.py b/util/adduser.py index 7e35d13d..1853869a 100644 --- a/util/adduser.py +++ b/util/adduser.py @@ -33,6 +33,7 @@ def parse_args(): def main(): args = parse_args() + db.get_engine() type = db.query(AccountType, AccountType.AccountType == args.type).first() with db.begin(): From b0b05df19341f5c4a75a78b69b3abc08d61fc238 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 16 Nov 2021 21:10:53 -0800 Subject: [PATCH 1108/1891] fix(fastapi): pin markdown to 3.3.4 Signed-off-by: Kevin Morris --- poetry.lock | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 37e2f8f9..550a91fa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1003,7 +1003,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "356b37d545d78b8aa1e1939f42522207bcf79526abe8193308c5a2955897d6fd" +content-hash = "844618f499e19d6d20f8479d165be3f60495bfa66fcb1f462256b101f9d395f9" [metadata.files] aiofiles = [ diff --git a/pyproject.toml b/pyproject.toml index 1d4c858c..7b2e9ef3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ alembic = "^1.7.4" mysqlclient = "^2.0.3" Authlib = "^0.15.5" Jinja2 = "^3.0.2" -Markdown = "^3.3.4" +Markdown = "3.3.4" Werkzeug = "^2.0.2" SQLAlchemy = "^1.4.26" From cea9104efb3c496230bee60f6b76be42a8719c61 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 16 Nov 2021 01:45:32 -0800 Subject: [PATCH 1109/1891] feat(poetry): add pytest-xdist Signed-off-by: Kevin Morris --- poetry.lock | 67 ++++++++++++++++++++++++++++++++++++++++++++------ pyproject.toml | 1 + 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 550a91fa..8d42cc50 100644 --- a/poetry.lock +++ b/poetry.lock @@ -53,7 +53,7 @@ tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] name = "atomicwrites" version = "1.4.0" description = "Atomic file writes." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -61,7 +61,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" name = "attrs" version = "21.2.0" description = "Classes Without Boilerplate" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -234,6 +234,17 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" dnspython = ">=1.15.0" idna = ">=2.0.0" +[[package]] +name = "execnet" +version = "1.9.0" +description = "execnet: rapid multi-Python deployment" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +testing = ["pre-commit"] + [[package]] name = "fakeredis" version = "1.6.1" @@ -432,7 +443,7 @@ python-versions = ">=3.5" name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -575,7 +586,7 @@ python-versions = "*" name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -639,7 +650,7 @@ python-versions = ">=3.5" name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -705,7 +716,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" name = "pytest" version = "6.2.5" description = "pytest: simple powerful testing with Python" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -751,6 +762,18 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] +[[package]] +name = "pytest-forked" +version = "1.3.0" +description = "run tests in isolated forked subprocesses" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +py = "*" +pytest = ">=3.10" + [[package]] name = "pytest-tap" version = "3.3" @@ -763,6 +786,24 @@ python-versions = "*" pytest = ">=3.0" "tap.py" = ">=3.0,<4.0" +[[package]] +name = "pytest-xdist" +version = "2.4.0" +description = "pytest xdist plugin for distributed testing and loop-on-failing modes" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +execnet = ">=1.1" +pytest = ">=6.0.0" +pytest-forked = "*" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1003,7 +1044,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "844618f499e19d6d20f8479d165be3f60495bfa66fcb1f462256b101f9d395f9" +content-hash = "6ab137fb829b2a6d49552c4864d00be04a2d58d80a872f3cd3b9e5cc67f95b9d" [metadata.files] aiofiles = [ @@ -1200,6 +1241,10 @@ email-validator = [ {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"}, ] +execnet = [ + {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, + {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, +] fakeredis = [ {file = "fakeredis-1.6.1-py3-none-any.whl", hash = "sha256:5eb1516f1fe1813e9da8f6c482178fc067af09f53de587ae03887ef5d9d13024"}, {file = "fakeredis-1.6.1.tar.gz", hash = "sha256:0d06a9384fb79da9f2164ce96e34eb9d4e2ea46215070805ea6fd3c174590b47"}, @@ -1609,10 +1654,18 @@ pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] +pytest-forked = [ + {file = "pytest-forked-1.3.0.tar.gz", hash = "sha256:6aa9ac7e00ad1a539c41bec6d21011332de671e938c7637378ec9710204e37ca"}, + {file = "pytest_forked-1.3.0-py2.py3-none-any.whl", hash = "sha256:dc4147784048e70ef5d437951728825a131b81714b398d5d52f17c7c144d8815"}, +] pytest-tap = [ {file = "pytest-tap-3.3.tar.gz", hash = "sha256:5f0919a147cf0396b2f10d64d365a0bf8062e06543e93c675c9d37f5605e983c"}, {file = "pytest_tap-3.3-py3-none-any.whl", hash = "sha256:4fbbc0e090c2e94f6199bee4e4f68ab3c5e176b37a72a589ad84e0f72a2fce55"}, ] +pytest-xdist = [ + {file = "pytest-xdist-2.4.0.tar.gz", hash = "sha256:89b330316f7fc475f999c81b577c2b926c9569f3d397ae432c0c2e2496d61ff9"}, + {file = "pytest_xdist-2.4.0-py3-none-any.whl", hash = "sha256:7b61ebb46997a0820a263553179d6d1e25a8c50d8a8620cd1aa1e20e3be99168"}, +] python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, diff --git a/pyproject.toml b/pyproject.toml index 7b2e9ef3..d296fb4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,6 +84,7 @@ gunicorn = "^20.1.0" Hypercorn = "^0.11.2" mysql-connector = "^2.2.9" prometheus-fastapi-instrumentator = "^5.7.1" +pytest-xdist = "^2.4.0" [tool.poetry.dev-dependencies] flake8 = "^4.0.1" From 40b21203ed8b1cd833fa0333ebf3d1985567fcbe Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 16 Nov 2021 01:46:07 -0800 Subject: [PATCH 1110/1891] feat(poetry): add filelock Signed-off-by: Kevin Morris --- poetry.lock | 18 +++++++++++++++++- pyproject.toml | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 8d42cc50..ab559b77 100644 --- a/poetry.lock +++ b/poetry.lock @@ -300,6 +300,18 @@ python-versions = "*" lxml = "*" python-dateutil = "*" +[[package]] +name = "filelock" +version = "3.3.2" +description = "A platform independent file lock." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] +testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] + [[package]] name = "flake8" version = "4.0.1" @@ -1044,7 +1056,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "6ab137fb829b2a6d49552c4864d00be04a2d58d80a872f3cd3b9e5cc67f95b9d" +content-hash = "ca42bd35717062d6784025ed3956423502ac66adba059ccc080bcaaa666651cd" [metadata.files] aiofiles = [ @@ -1253,6 +1265,10 @@ fastapi = [] feedgen = [ {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, ] +filelock = [ + {file = "filelock-3.3.2-py3-none-any.whl", hash = "sha256:bb2a1c717df74c48a2d00ed625e5a66f8572a3a30baacb7657add1d7bac4097b"}, + {file = "filelock-3.3.2.tar.gz", hash = "sha256:7afc856f74fa7006a289fd10fa840e1eebd8bbff6bffb69c26c54a0512ea8cf8"}, +] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, diff --git a/pyproject.toml b/pyproject.toml index d296fb4e..8d14735a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,6 +85,7 @@ Hypercorn = "^0.11.2" mysql-connector = "^2.2.9" prometheus-fastapi-instrumentator = "^5.7.1" pytest-xdist = "^2.4.0" +filelock = "^3.3.2" [tool.poetry.dev-dependencies] flake8 = "^4.0.1" From 0abdf8d468579c5e98ddac29c5f97ec1e546bd5e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:22:52 -0800 Subject: [PATCH 1111/1891] fix(fastapi): close connection used for initdb Signed-off-by: Kevin Morris --- aurweb/initdb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aurweb/initdb.py b/aurweb/initdb.py index 9a063ba4..a4a9f621 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -46,7 +46,9 @@ def run(args): engine = aurweb.db.get_engine(echo=(args.verbose >= 1)) aurweb.schema.metadata.create_all(engine) - feed_initial_data(engine.connect()) + conn = engine.connect() + feed_initial_data(conn) + conn.close() if args.use_alembic: alembic.command.stamp(alembic_config, 'head') From 07aac768d633288d61abd85d055629cfe65800b2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:27:44 -0800 Subject: [PATCH 1112/1891] change(fastapi): remove sqlite support Signed-off-by: Kevin Morris --- aurweb/asgi.py | 6 ++++++ test/test_asgi.py | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 16de771e..aafb00b2 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -48,6 +48,12 @@ async def app_startup(): "TEST_RECURSION_LIMIT", sys.getrecursionlimit())) sys.setrecursionlimit(recursion_limit) + backend = aurweb.config.get("database", "backend") + if backend not in aurweb.db.DRIVERS: + raise ValueError( + f"The configured database backend ({backend}) is unsupported. " + f"Supported backends: {str(aurweb.db.DRIVERS.keys())}") + session_secret = aurweb.config.get("fastapi", "session_secret") if not session_secret: raise Exception("[fastapi] session_secret must not be empty") diff --git a/test/test_asgi.py b/test/test_asgi.py index b8856741..fa2df5a1 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -45,3 +45,20 @@ async def test_asgi_http_exception_handler(): response = await aurweb.asgi.http_exception_handler(None, exc) assert response.body.decode() == \ f"

    {exc.status_code} {phrase}

    {exc.detail}

    " + + +@pytest.mark.asyncio +async def test_asgi_app_unsupported_backends(): + config_get = aurweb.config.get + + # Test that the previously supported "sqlite" backend is now + # unsupported by FastAPI. + def mock_sqlite_backend(section: str, key: str): + if section == "database" and key == "backend": + return "sqlite" + return config_get(section, key) + + with mock.patch("aurweb.config.get", side_effect=mock_sqlite_backend): + expr = r"^.*\(sqlite\) is unsupported.*$" + with pytest.raises(ValueError, match=expr): + await aurweb.asgi.app_startup() From fa43f6bc3ebebff7d97f3361ec07a61e92bd1ce5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:33:41 -0800 Subject: [PATCH 1113/1891] change(aurweb): add parallel tests and improve aurweb.db This change utilizes pytest-xdist to perform a multiproc test run and reworks aurweb.db's code. We no longer use a global engine, session or Session, but we now use a memo of engines and sessions as they are requested, based on the PYTEST_CURRENT_TEST environment variable, which is available during testing. Additionally, this change strips several SQLite components out of the Python code-base. SQLite is still compatible with PHP and sharness tests, but not with our FastAPI implementation. More changes: ------------ - Remove use of aurweb.db.session global in other code. - Use new aurweb.db.name() dynamic db name function in env.py. - Added 'addopts' to pytest.ini which utilizes multiprocessing. - Highly recommended to leave this be or modify `-n auto` to `-n {cpu_threads}` where cpu_threads is at least 2. Signed-off-by: Kevin Morris --- aurweb/db.py | 251 +++++++++++++++++++++--------- aurweb/routers/auth.py | 6 +- aurweb/routers/packages.py | 8 +- aurweb/schema.py | 4 +- aurweb/testing/__init__.py | 68 ++++---- migrations/env.py | 8 +- pytest.ini | 6 + test/conftest.py | 178 +++++++++++++++++++++ test/test_accepted_term.py | 37 ++--- test/test_account_type.py | 54 ++++--- test/test_accounts_routes.py | 9 +- test/test_api_rate_limit.py | 19 +-- test/test_auth.py | 26 ++-- test/test_auth_routes.py | 5 +- test/test_ban.py | 9 +- test/test_cache.py | 7 +- test/test_captcha.py | 7 + test/test_db.py | 110 +------------ test/test_dependency_type.py | 5 +- test/test_group.py | 9 +- test/test_homepage.py | 11 +- test/test_html.py | 5 +- test/test_initdb.py | 9 ++ test/test_license.py | 9 +- test/test_official_provider.py | 23 +-- test/test_package.py | 5 +- test/test_package_base.py | 5 +- test/test_package_blacklist.py | 16 +- test/test_package_comaintainer.py | 28 ++-- test/test_package_comment.py | 59 +++---- test/test_package_dependency.py | 95 +++-------- test/test_package_group.py | 37 ++--- test/test_package_keyword.py | 37 ++--- test/test_package_license.py | 38 ++--- test/test_package_notification.py | 25 ++- test/test_package_relation.py | 90 +++-------- test/test_package_request.py | 107 +++++-------- test/test_package_source.py | 2 +- test/test_package_vote.py | 29 ++-- test/test_packages_routes.py | 23 +-- test/test_packages_util.py | 17 +- test/test_popupdate.py | 7 + test/test_ratelimit.py | 20 ++- test/test_relation_type.py | 5 +- test/test_request_type.py | 5 +- test/test_routes.py | 12 +- test/test_rpc.py | 8 +- test/test_rss.py | 8 +- test/test_session.py | 5 +- test/test_ssh_pub_key.py | 14 +- test/test_term.py | 18 +-- test/test_trusted_user_routes.py | 5 +- test/test_tu_vote.py | 43 +++-- test/test_tu_voteinfo.py | 5 +- test/test_user.py | 14 +- 55 files changed, 781 insertions(+), 884 deletions(-) create mode 100644 test/conftest.py diff --git a/aurweb/db.py b/aurweb/db.py index 39232d5a..b8b49e40 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,29 +1,34 @@ import functools +import hashlib import math +import os import re from typing import Iterable, NewType -from sqlalchemy import event -from sqlalchemy.orm import Query, scoped_session +import sqlalchemy + +from sqlalchemy import create_engine, event +from sqlalchemy.engine.base import Engine +from sqlalchemy.engine.url import URL +from sqlalchemy.orm import Query, Session, SessionTransaction, scoped_session, sessionmaker import aurweb.config import aurweb.util -# See get_engine. -engine = None +from aurweb import logging -# ORM Session class. -Session = None +logger = logging.get_logger(__name__) -# Global ORM Session object. -session = None +DRIVERS = { + "mysql": "mysql+mysqldb" +} # Global introspected object memo. introspected = dict() -# A mocked up type. -Base = NewType("aurweb.models.declarative_base.Base", "Base") +# Some types we don't get access to in this module. +Base = NewType("Base", "aurweb.models.declarative_base.Base") def make_random_value(table: str, column: str): @@ -56,14 +61,85 @@ def make_random_value(table: str, column: str): length = col.type.length string = aurweb.util.make_random_string(length) - while session.query(table).filter(column == string).first(): + while query(table).filter(column == string).first(): string = aurweb.util.make_random_string(length) return string -def get_session(): +def test_name() -> str: + """ + Return the unhashed database name. + + The unhashed database name is determined (lower = higher priority) by: + ------------------------------------------- + 1. {test_suite} portion of PYTEST_CURRENT_TEST + 2. aurweb.config.get("database", "name") + + During `pytest` runs, the PYTEST_CURRENT_TEST environment variable + is set to the current test in the format `{test_suite}::{test_func}`. + + This allows tests to use a suite-specific database for its runs, + which decouples database state from test suites. + + :return: Unhashed database name + """ + db = os.environ.get("PYTEST_CURRENT_TEST", + aurweb.config.get("database", "name")) + return db.split(":")[0] + + +def name() -> str: + """ + Return sanitized database name that can be used for tests or production. + + If test_name() starts with "test/", the database name is SHA-1 hashed, + prefixed with 'db', and returned. Otherwise, test_name() is passed + through and not hashed at all. + + :return: SHA1-hashed database name prefixed with 'db' + """ + dbname = test_name() + if not dbname.startswith("test/"): + return dbname + sha1 = hashlib.sha1(dbname.encode()).hexdigest() + return "db" + sha1 + + +# Module-private global memo used to store SQLAlchemy sessions. +_sessions = dict() + + +def get_session(engine: Engine = None) -> Session: """ Return aurweb.db's global session. """ - return session + dbname = name() + + global _sessions + if dbname not in _sessions: + + if not engine: # pragma: no cover + engine = get_engine() + + Session = scoped_session( + sessionmaker(autocommit=True, autoflush=False, bind=engine)) + _sessions[dbname] = Session() + + # If this is the first grab of this session, log out the + # database name used. + raw_dbname = test_name() + logger.debug(f"DBName({raw_dbname}): {dbname}") + + return _sessions.get(dbname) + + +def pop_session(dbname: str) -> None: + """ + Pop a Session out of the private _sessions memo. + + :param dbname: Database name + :raises KeyError: When `dbname` does not exist in the memo + """ + global _sessions + _sessions.pop(dbname) def refresh(model: Base) -> Base: @@ -121,41 +197,40 @@ def add(model: Base) -> Base: return model -def begin(): +def begin() -> SessionTransaction: """ Begin an SQLAlchemy SessionTransaction. """ return get_session().begin() -def get_sqlalchemy_url(): +def get_sqlalchemy_url() -> URL: """ - Build an SQLAlchemy for use with create_engine based on the aurweb configuration. - """ - import sqlalchemy + Build an SQLAlchemy URL for use with create_engine. - constructor = sqlalchemy.engine.url.URL + :return: sqlalchemy.engine.url.URL + """ + constructor = URL parts = sqlalchemy.__version__.split('.') major = int(parts[0]) minor = int(parts[1]) if major == 1 and minor >= 4: # pragma: no cover - constructor = sqlalchemy.engine.url.URL.create + constructor = URL.create aur_db_backend = aurweb.config.get('database', 'backend') if aur_db_backend == 'mysql': - if aurweb.config.get_with_fallback('database', 'port', fallback=None): - port = aurweb.config.get('database', 'port') - param_query = None - else: - port = None - param_query = { - 'unix_socket': aurweb.config.get('database', 'socket') - } + param_query = {} + port = aurweb.config.get_with_fallback("database", "port", None) + if not port: + param_query["unix_socket"] = aurweb.config.get( + "database", "socket") + return constructor( - 'mysql+mysqldb', + DRIVERS.get(aur_db_backend), username=aurweb.config.get('database', 'user'), - password=aurweb.config.get('database', 'password'), + password=aurweb.config.get_with_fallback('database', 'password', + fallback=None), host=aurweb.config.get('database', 'host'), - database=aurweb.config.get('database', 'name'), + database=name(), port=port, query=param_query ) @@ -168,58 +243,83 @@ def get_sqlalchemy_url(): raise ValueError('unsupported database backend') -def get_engine(echo: bool = False): +def sqlite_regexp(regex, item) -> bool: # pragma: no cover + """ Method which mimics SQL's REGEXP for SQLite. """ + return bool(re.search(regex, str(item))) + + +def setup_sqlite(engine: Engine) -> None: # pragma: no cover + """ Perform setup for an SQLite engine. """ + @event.listens_for(engine, "connect") + def do_begin(conn, record): + create_deterministic_function = functools.partial( + conn.create_function, + deterministic=True + ) + create_deterministic_function("REGEXP", 2, sqlite_regexp) + + +# Module-private global memo used to store SQLAlchemy engines. +_engines = dict() + + +def get_engine(dbname: str = None, echo: bool = False) -> Engine: """ - Return the global SQLAlchemy engine. + Return the SQLAlchemy engine for `dbname`. The engine is created on the first call to get_engine and then stored in the `engine` global variable for the next calls. + + :param dbname: Database name (default: aurweb.db.name()) + :param echo: Flag passed through to sqlalchemy.create_engine + :return: SQLAlchemy Engine instance """ - from sqlalchemy import create_engine - from sqlalchemy.orm import sessionmaker + if not dbname: + dbname = name() - global engine, session, Session - - if engine is None: + global _engines + if dbname not in _engines: + db_backend = aurweb.config.get("database", "backend") connect_args = dict() - db_backend = aurweb.config.get("database", "backend") - if db_backend == "sqlite": - # check_same_thread is for a SQLite technicality - # https://fastapi.tiangolo.com/tutorial/sql-databases/#note + is_sqlite = bool(db_backend == "sqlite") + if is_sqlite: # pragma: no cover connect_args["check_same_thread"] = False - engine = create_engine(get_sqlalchemy_url(), - connect_args=connect_args, - echo=echo) + kwargs = { + "echo": echo, + "connect_args": connect_args + } + _engines[dbname] = create_engine(get_sqlalchemy_url(), **kwargs) - Session = scoped_session( - sessionmaker(autocommit=True, autoflush=False, bind=engine)) - session = Session() + if is_sqlite: # pragma: no cover + setup_sqlite(_engines.get(dbname)) - if db_backend == "sqlite": - # For SQLite, we need to add some custom functions as - # they are used in the reference graph method. - def regexp(regex, item): - return bool(re.search(regex, str(item))) - - @event.listens_for(engine, "connect") - def do_begin(conn, record): - create_deterministic_function = functools.partial( - conn.create_function, - deterministic=True - ) - create_deterministic_function("REGEXP", 2, regexp) - - return engine + return _engines.get(dbname) -def kill_engine(): - global engine, Session, session - if engine: - session.close() - engine.dispose() - engine = Session = session = None +def pop_engine(dbname: str) -> None: + """ + Pop an Engine out of the private _engines memo. + + :param dbname: Database name + :raises KeyError: When `dbname` does not exist in the memo + """ + global _engines + _engines.pop(dbname) + + +def kill_engine() -> None: + """ Close the current session and dispose of the engine. """ + dbname = name() + + session = get_session() + session.close() + pop_session(dbname) + + engine = get_engine() + engine.dispose() + pop_engine(dbname) def connect(): @@ -248,7 +348,9 @@ class ConnectionExecutor: def paramstyle(self): return self._paramstyle - def execute(self, query, params=()): + def execute(self, query, params=()): # pragma: no cover + # TODO: SQLite support has been removed in FastAPI. It remains + # here to fund its support for PHP until it is removed. if self._paramstyle in ('format', 'pyformat'): query = query.replace('%', '%%').replace('?', '%s') elif self._paramstyle == 'qmark': @@ -278,16 +380,19 @@ class Connection: if aur_db_backend == 'mysql': import MySQLdb aur_db_host = aurweb.config.get('database', 'host') - aur_db_name = aurweb.config.get('database', 'name') + aur_db_name = name() aur_db_user = aurweb.config.get('database', 'user') - aur_db_pass = aurweb.config.get('database', 'password') + aur_db_pass = aurweb.config.get_with_fallback( + 'database', 'password', str()) aur_db_socket = aurweb.config.get('database', 'socket') self._conn = MySQLdb.connect(host=aur_db_host, user=aur_db_user, passwd=aur_db_pass, db=aur_db_name, unix_socket=aur_db_socket) - elif aur_db_backend == 'sqlite': + elif aur_db_backend == 'sqlite': # pragma: no cover + # TODO: SQLite support has been removed in FastAPI. It remains + # here to fund its support for PHP until it is removed. import sqlite3 aur_db_name = aurweb.config.get('database', 'name') self._conn = sqlite3.connect(aur_db_name) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index b8e83c7d..055f0dca 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -6,7 +6,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse import aurweb.config -from aurweb import cookies +from aurweb import cookies, db from aurweb.auth import auth_required from aurweb.l10n import get_translator_for_request from aurweb.models import User @@ -45,9 +45,7 @@ async def login_post(request: Request, raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=_("Bad Referer header.")) - from aurweb.db import session - - user = session.query(User).filter(User.Username == user).first() + user = db.query(User).filter(User.Username == user).first() if not user: return await login_template(request, next, errors=["Bad username or password."]) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 07e8af72..c8ceb275 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -1014,12 +1014,12 @@ def pkgbase_disown_instance(request: Request, pkgbase: models.PackageBase): models.PackageComaintainer.Priority.asc() ).limit(1).first() - if co: - with db.begin(): + with db.begin(): + if co: pkgbase.Maintainer = co.User db.delete(co) - else: - pkgbase.Maintainer = None + else: + pkgbase.Maintainer = None notif.send() diff --git a/aurweb/schema.py b/aurweb/schema.py index fb8f0dee..43db920d 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -16,13 +16,13 @@ db_backend = aurweb.config.get("database", "backend") @compiles(TINYINT, 'sqlite') -def compile_tinyint_sqlite(type_, compiler, **kw): +def compile_tinyint_sqlite(type_, compiler, **kw): # pragma: no cover """TINYINT is not supported on SQLite. Substitute it with INTEGER.""" return 'INTEGER' @compiles(BIGINT, 'sqlite') -def compile_bigint_sqlite(type_, compiler, **kw): +def compile_bigint_sqlite(type_, compiler, **kw): # pragma: no cover """ For SQLite's AUTOINCREMENT to work on BIGINT columns, we need to map BIGINT to INTEGER. Aside from that, BIGINT is the same as INTEGER for SQLite. diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py index 2dd377e1..8261051d 100644 --- a/aurweb/testing/__init__.py +++ b/aurweb/testing/__init__.py @@ -1,26 +1,6 @@ -from itertools import chain - import aurweb.db - -def references_graph(table): - """ Taken from Django's sqlite3/operations.py. """ - query = """ - WITH tables AS ( - SELECT :table name - UNION - SELECT sqlite_master.name - FROM sqlite_master - JOIN tables ON (sql REGEXP :regexp_1 || tables.name || :regexp_2) - ) SELECT name FROM tables; - """ - params = { - "table": table, - "regexp_1": r'(?i)\s+references\s+("|\')?', - "regexp_2": r'("|\')?\s*\(', - } - cursor = aurweb.db.get_session().execute(query, params=params) - return [row[0] for row in cursor.fetchall()] +from aurweb import models def setup_test_db(*args): @@ -47,22 +27,38 @@ def setup_test_db(*args): aurweb.db.get_engine() tables = list(args) + if not tables: + tables = [ + models.AcceptedTerm.__tablename__, + models.ApiRateLimit.__tablename__, + models.Ban.__tablename__, + models.Group.__tablename__, + models.License.__tablename__, + models.OfficialProvider.__tablename__, + models.Package.__tablename__, + models.PackageBase.__tablename__, + models.PackageBlacklist.__tablename__, + models.PackageComaintainer.__tablename__, + models.PackageComment.__tablename__, + models.PackageDependency.__tablename__, + models.PackageGroup.__tablename__, + models.PackageKeyword.__tablename__, + models.PackageLicense.__tablename__, + models.PackageNotification.__tablename__, + models.PackageRelation.__tablename__, + models.PackageRequest.__tablename__, + models.PackageSource.__tablename__, + models.PackageVote.__tablename__, + models.Session.__tablename__, + models.SSHPubKey.__tablename__, + models.Term.__tablename__, + models.TUVote.__tablename__, + models.TUVoteInfo.__tablename__, + models.User.__tablename__, + ] - db_backend = aurweb.config.get("database", "backend") - - if db_backend != "sqlite": # pragma: no cover - aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 0") - else: - # We're using sqlite, setup tables to be deleted without violating - # foreign key constraints by graphing references. - tables = set(chain.from_iterable( - references_graph(table) for table in tables)) - + aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 0") for table in tables: aurweb.db.get_session().execute(f"DELETE FROM {table}") - - if db_backend != "sqlite": # pragma: no cover - aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 1") - - # Expunge all objects from SQLAlchemy's IdentityMap. + aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 1") aurweb.db.get_session().expunge_all() diff --git a/migrations/env.py b/migrations/env.py index 7130d141..774ecdeb 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -41,8 +41,8 @@ def run_migrations_offline(): script output. """ - db_name = aurweb.config.get("database", "name") - logging.info(f"Performing offline migration on database '{db_name}'.") + dbname = aurweb.db.name() + logging.info(f"Performing offline migration on database '{dbname}'.") context.configure( url=aurweb.db.get_sqlalchemy_url(), target_metadata=target_metadata, @@ -61,8 +61,8 @@ def run_migrations_online(): and associate a connection with the context. """ - db_name = aurweb.config.get("database", "name") - logging.info(f"Performing online migration on database '{db_name}'.") + dbname = aurweb.db.name() + logging.info(f"Performing online migration on database '{dbname}'.") connectable = sqlalchemy.create_engine( aurweb.db.get_sqlalchemy_url(), poolclass=sqlalchemy.pool.NullPool, diff --git a/pytest.ini b/pytest.ini index 510447c9..9f70a2bd 100644 --- a/pytest.ini +++ b/pytest.ini @@ -8,3 +8,9 @@ # https://bugs.python.org/issue45097 filterwarnings = ignore::DeprecationWarning:asyncio.base_events + +# Build in coverage and pytest-xdist multiproc testing. +addopts = --cov=aurweb --cov-append --dist load --dist loadfile -n auto + +# Our pytest units are located in the ./test/ directory. +testpaths = test diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 00000000..47d9ca4b --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,178 @@ +""" +pytest configuration. + +The conftest.py file is used to define pytest-global fixtures +or actions run before tests. + +Module scoped fixtures: +---------------------- +- setup_database +- db_session (depends: setup_database) + +Function scoped fixtures: +------------------------ +- db_test (depends: db_session) + +Tests in aurweb which access the database **must** use the `db_test` +function fixture. Most database tests simply require this fixture in +an autouse=True setup fixture, or for fixtures used in DB tests example: + + # In scenarios which there are no other database fixtures + # or other database fixtures dependency paths don't always + # hit `db_test`. + @pytest.fixture(autouse=True) + def setup(db_test): + return + + # In scenarios where we can embed the `db_test` fixture in + # specific fixtures that already exist. + @pytest.fixture + def user(db_test): + with db.begin(): + user = db.create(User, ...) + yield user + +The `db_test` fixture triggers our module-level database fixtures, +then clears the database for each test function run in that module. +It is done this way because migration has a large cost; migrating +ahead of each function takes too long when compared to this method. +""" +import pytest + +from filelock import FileLock +from sqlalchemy import create_engine +from sqlalchemy.engine import URL +from sqlalchemy.engine.base import Engine +from sqlalchemy.orm import scoped_session + +import aurweb.config +import aurweb.db + +from aurweb import initdb, logging, testing + +logger = logging.get_logger(__name__) + + +def test_engine() -> Engine: + """ + Return a privileged SQLAlchemy engine with no database. + + This method is particularly useful for providing an engine that + can be used to create and drop databases from an SQL server. + + :return: SQLAlchemy Engine instance (not connected to a database) + """ + unix_socket = aurweb.config.get_with_fallback("database", "socket", None) + kwargs = { + "username": aurweb.config.get("database", "user"), + "password": aurweb.config.get_with_fallback( + "database", "password", None), + "host": aurweb.config.get("database", "host"), + "port": aurweb.config.get_with_fallback("database", "port", None), + "query": { + "unix_socket": unix_socket + } + } + + backend = aurweb.config.get("database", "backend") + driver = aurweb.db.DRIVERS.get(backend) + return create_engine(URL.create(driver, **kwargs)) + + +class AlembicArgs: + """ + Masquerade an ArgumentParser like structure. + + This structure is needed to pass conftest-specific arguments + to initdb.run duration database creation. + """ + verbose = False + use_alembic = True + + +def _create_database(engine: Engine, dbname: str) -> None: + """ + Create a test database. + + :param engine: Engine returned by test_engine() + :param dbname: Database name to create + """ + conn = engine.connect() + conn.execute(f"CREATE DATABASE {dbname}") + conn.close() + initdb.run(AlembicArgs) + + +def _drop_database(engine: Engine, dbname: str) -> None: + """ + Drop a test database. + + :param engine: Engine returned by test_engine() + :param dbname: Database name to drop + """ + aurweb.schema.metadata.drop_all(bind=engine) + conn = engine.connect() + conn.execute(f"DROP DATABASE {dbname}") + conn.close() + + +@pytest.fixture(scope="module") +def setup_database(tmp_path_factory: pytest.fixture, + worker_id: pytest.fixture) -> None: + """ Create and drop a database for the suite this fixture is used in. """ + engine = test_engine() + dbname = aurweb.db.name() + + if worker_id == "master": # pragma: no cover + # If we're not running tests through multiproc pytest-xdist. + yield _create_database(engine, dbname) + _drop_database(engine, dbname) + return + + root_tmp_dir = tmp_path_factory.getbasetemp().parent + fn = root_tmp_dir / dbname + + with FileLock(str(fn) + ".lock"): + if fn.is_file(): + # If the data file exists, skip database creation. + yield + else: + # Otherwise, create the data file and create the database. + fn.write_text("1") + yield _create_database(engine, dbname) + _drop_database(engine, dbname) + + +@pytest.fixture(scope="module") +def db_session(setup_database: pytest.fixture) -> scoped_session: + """ + Yield a database session based on aurweb.db.name(). + + The returned session is popped out of persistence after the test is run. + """ + # After the test runs, aurweb.db.name() ends up returning the + # configured database, because PYTEST_CURRENT_TEST is removed. + dbname = aurweb.db.name() + session = aurweb.db.get_session() + yield session + + # Close the session and pop it. + session.close() + aurweb.db.pop_session(dbname) + + +@pytest.fixture +def db_test(db_session: scoped_session) -> None: + """ + Database test fixture. + + This fixture should be included in any tests which access the + database. It ensures that a test database is created and + alembic migrated, takes care of dropping the database when + the module is complete, and runs setup_test_db() to clear out + tables for each test. + + Tests using this fixture should access the database + session via aurweb.db.get_session(). + """ + testing.setup_test_db() diff --git a/test/test_accepted_term.py b/test/test_accepted_term.py index cd8bd7af..de18c61a 100644 --- a/test/test_accepted_term.py +++ b/test/test_accepted_term.py @@ -2,38 +2,33 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query +from aurweb import db from aurweb.models.accepted_term import AcceptedTerm -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.term import Term from aurweb.models.user import User -from aurweb.testing import setup_test_db user = term = accepted_term = None @pytest.fixture(autouse=True) -def setup(): - global user, term, accepted_term +def setup(db_test): + global user, term - setup_test_db("Users", "AcceptedTerms", "Terms") + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - - term = create(Term, Description="Test term", URL="https://test.term") + term = db.create(Term, Description="Test term", + URL="https://test.term") yield term - # Eradicate any terms we created. - setup_test_db("AcceptedTerms", "Terms") - def test_accepted_term(): - accepted_term = create(AcceptedTerm, User=user, Term=term) + with db.begin(): + accepted_term = db.create(AcceptedTerm, User=user, Term=term) # Make sure our AcceptedTerm relationships got initialized properly. assert accepted_term.User == user @@ -42,14 +37,10 @@ def test_accepted_term(): def test_accepted_term_null_user_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(AcceptedTerm, Term=term) - session.rollback() + AcceptedTerm(Term=term) def test_accepted_term_null_term_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(AcceptedTerm, User=user) - session.rollback() + AcceptedTerm(User=user) diff --git a/test/test_account_type.py b/test/test_account_type.py index 12472348..1d71f878 100644 --- a/test/test_account_type.py +++ b/test/test_account_type.py @@ -1,31 +1,29 @@ import pytest -from aurweb.db import begin, create, delete, query +from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.user import User -from aurweb.testing import setup_test_db - -account_type = None @pytest.fixture(autouse=True) -def setup(): - setup_test_db("Users") - - global account_type - - with begin(): - account_type = create(AccountType, AccountType="TestUser") - - yield account_type - - with begin(): - delete(account_type) +def setup(db_test): + return -def test_account_type(): +@pytest.fixture +def account_type() -> AccountType: + with db.begin(): + account_type_ = db.create(AccountType, AccountType="TestUser") + + yield account_type_ + + with db.begin(): + db.delete(account_type_) + + +def test_account_type(account_type): """ Test creating an AccountType, and reading its columns. """ - # Make sure it got created and was given an ID. + # Make sure it got db.created and was given an ID. assert bool(account_type.ID) # Next, test our string functions. @@ -34,20 +32,20 @@ def test_account_type(): "" % ( account_type.ID) - record = query(AccountType, - AccountType.AccountType == "TestUser").first() + record = db.query(AccountType, + AccountType.AccountType == "TestUser").first() assert account_type == record -def test_user_account_type_relationship(): - with begin(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) +def test_user_account_type_relationship(account_type): + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountType=account_type) assert user.AccountType == account_type - # This must be deleted here to avoid foreign key issues when + # This must be db.deleted here to avoid foreign key issues when # deleting the temporary AccountType in the fixture. - with begin(): - delete(user) + with db.begin(): + db.delete(user) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 5e855daf..e828f70f 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -20,7 +20,6 @@ from aurweb.models.session import Session from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.term import Term from aurweb.models.user import User -from aurweb.testing import setup_test_db from aurweb.testing.html import get_errors from aurweb.testing.requests import Request @@ -50,11 +49,9 @@ def make_ssh_pubkey(): @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user - setup_test_db("Users", "Sessions", "Bans", "Terms", "AcceptedTerms") - account_type = query(AccountType, AccountType.AccountType == "User").first() @@ -65,10 +62,6 @@ def setup(): yield user - # Remove term records so other tests don't get them - # and falsely redirect. - setup_test_db("Terms", "AcceptedTerms") - @pytest.fixture def tu_user(): diff --git a/test/test_api_rate_limit.py b/test/test_api_rate_limit.py index 25cb3e0f..82805ecf 100644 --- a/test/test_api_rate_limit.py +++ b/test/test_api_rate_limit.py @@ -3,19 +3,18 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.db import create from aurweb.models.api_rate_limit import ApiRateLimit -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db("ApiRateLimit") +def setup(db_test): + return def test_api_rate_key_creation(): with db.begin(): - rate = create(ApiRateLimit, IP="127.0.0.1", Requests=10, WindowStart=1) + rate = db.create(ApiRateLimit, IP="127.0.0.1", Requests=10, + WindowStart=1) assert rate.IP == "127.0.0.1" assert rate.Requests == 10 assert rate.WindowStart == 1 @@ -23,19 +22,15 @@ def test_api_rate_key_creation(): def test_api_rate_key_ip_default(): with db.begin(): - api_rate_limit = create(ApiRateLimit, Requests=10, WindowStart=1) + api_rate_limit = db.create(ApiRateLimit, Requests=10, WindowStart=1) assert api_rate_limit.IP == str() def test_api_rate_key_null_requests_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - create(ApiRateLimit, IP="127.0.0.1", WindowStart=1) - db.rollback() + ApiRateLimit(IP="127.0.0.1", WindowStart=1) def test_api_rate_key_null_window_start_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - create(ApiRateLimit, IP="127.0.0.1", Requests=1) - db.rollback() + ApiRateLimit(IP="127.0.0.1", Requests=1) diff --git a/test/test_auth.py b/test/test_auth.py index 7aea17a0..08eaac0b 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -6,28 +6,22 @@ from sqlalchemy.exc import IntegrityError from aurweb import db from aurweb.auth import AnonymousUser, BasicAuthBackend, account_type_required, has_credential -from aurweb.db import create, query -from aurweb.models.account_type import USER, USER_ID, AccountType +from aurweb.models.account_type import USER, USER_ID from aurweb.models.session import Session from aurweb.models.user import User -from aurweb.testing import setup_test_db from aurweb.testing.requests import Request user = backend = request = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, backend, request - setup_test_db("Users", "Sessions") - - account_type = query(AccountType, - AccountType.AccountType == "User").first() with db.begin(): - user = create(User, Username="test", Email="test@example.com", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = db.create(User, Username="test", Email="test@example.com", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) backend = BasicAuthBackend() request = Request() @@ -56,10 +50,8 @@ async def test_auth_backend_invalid_user_id(): # Create a new session with a fake user id. now_ts = datetime.utcnow().timestamp() with pytest.raises(IntegrityError): - with db.begin(): - create(Session, UsersID=666, SessionID="realSession", - LastUpdateTS=now_ts + 5) - db.rollback() + Session(UsersID=666, SessionID="realSession", + LastUpdateTS=now_ts + 5) @pytest.mark.asyncio @@ -68,8 +60,8 @@ async def test_basic_auth_backend(): # equal the real_user. now_ts = datetime.utcnow().timestamp() with db.begin(): - create(Session, UsersID=user.ID, SessionID="realSession", - LastUpdateTS=now_ts + 5) + db.create(Session, UsersID=user.ID, SessionID="realSession", + LastUpdateTS=now_ts + 5) request.cookies["AURSID"] = "realSession" _, result = await backend.authenticate(request) assert result == user diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 39afc6f9..a0bb8a7c 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -13,7 +13,6 @@ from aurweb.db import begin, create, query from aurweb.models.account_type import AccountType from aurweb.models.session import Session from aurweb.models.user import User -from aurweb.testing import setup_test_db # Some test global constants. TEST_USERNAME = "test" @@ -27,11 +26,9 @@ user = client = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, client - setup_test_db("Users", "Sessions", "Bans") - account_type = query(AccountType, AccountType.AccountType == "User").first() diff --git a/test/test_ban.py b/test/test_ban.py index f96e9d14..2c705410 100644 --- a/test/test_ban.py +++ b/test/test_ban.py @@ -9,18 +9,15 @@ from sqlalchemy import exc as sa_exc from aurweb import db from aurweb.db import create from aurweb.models.ban import Ban, is_banned -from aurweb.testing import setup_test_db from aurweb.testing.requests import Request ban = request = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global ban, request - setup_test_db("Bans") - ts = datetime.utcnow() + timedelta(seconds=30) with db.begin(): ban = create(Ban, IPAddress="127.0.0.1", BanTS=ts) @@ -33,8 +30,6 @@ def test_ban(): def test_invalid_ban(): - from aurweb.db import session - with pytest.raises(sa_exc.IntegrityError): bad_ban = Ban(BanTS=datetime.utcnow()) @@ -44,7 +39,7 @@ def test_invalid_ban(): with warnings.catch_warnings(): warnings.simplefilter("ignore", sa_exc.SAWarning) with db.begin(): - session.add(bad_ban) + db.add(bad_ban) # Since we got a transaction failure, we need to rollback. db.rollback() diff --git a/test/test_cache.py b/test/test_cache.py index 35346e52..b49ee386 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -3,14 +3,11 @@ import pytest from aurweb import cache, db from aurweb.models.account_type import USER_ID from aurweb.models.user import User -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db( - User.__tablename__ - ) +def setup(db_test): + return class StubRedis: diff --git a/test/test_captcha.py b/test/test_captcha.py index ec19dee9..e5f8c71a 100644 --- a/test/test_captcha.py +++ b/test/test_captcha.py @@ -1,8 +1,15 @@ import hashlib +import pytest + from aurweb import captcha +@pytest.fixture(autouse=True) +def setup(db_test): + return + + def test_captcha_salts(): """ Make sure we can get some captcha salts. """ salts = captcha.get_captcha_salts() diff --git a/test/test_db.py b/test/test_db.py index 8283a957..f36fff2c 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -12,7 +12,6 @@ import aurweb.initdb from aurweb import db from aurweb.models.account_type import AccountType -from aurweb.testing import setup_test_db class Args: @@ -96,16 +95,10 @@ def make_temp_mysql_config(): @pytest.fixture(autouse=True) -def setup_db(): +def setup(db_test): if os.path.exists("/tmp/aurweb.sqlite3"): os.remove("/tmp/aurweb.sqlite3") - # In various places in this test, we reinitialize the engine. - # Make sure we kill the previous engine before initializing - # it via setup_test_db(). - aurweb.db.kill_engine() - setup_test_db() - def test_sqlalchemy_sqlite_url(): tmpctx, tmp = make_temp_sqlite_config() @@ -159,24 +152,6 @@ def test_sqlalchemy_unknown_backend(): def test_db_connects_without_fail(): """ This only tests the actual config supplied to pytest. """ db.connect() - assert db.engine is not None - - -def test_connection_class_sqlite_without_fail(): - tmpctx, tmp = make_temp_sqlite_config() - with tmpctx: - with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): - aurweb.config.rehash() - - aurweb.db.kill_engine() - aurweb.initdb.run(Args()) - - conn = db.Connection() - cur = conn.execute( - "SELECT AccountType FROM AccountTypes WHERE ID = ?", (1,)) - account_type = cur.fetchone()[0] - assert account_type == "User" - aurweb.config.rehash() def test_connection_class_unsupported_backend(): @@ -200,83 +175,6 @@ def test_connection_mysql(): aurweb.config.rehash() -@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) -@mock.patch.object(sqlite3, "paramstyle", "qmark") -def test_connection_sqlite(): - db.Connection() - - -@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) -@mock.patch.object(sqlite3, "paramstyle", "format") -def test_connection_execute_paramstyle_format(): - tmpctx, tmp = make_temp_sqlite_config() - - with tmpctx: - with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): - aurweb.config.rehash() - - aurweb.db.kill_engine() - aurweb.initdb.run(Args()) - - # Test SQLite route of clearing tables. - setup_test_db("Users", "Bans") - - conn = db.Connection() - - # First, test ? to %s format replacement. - account_types = conn\ - .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", - ["User"]).fetchall() - assert account_types == \ - ["SELECT * FROM AccountTypes WHERE AccountType = %s", ["User"]] - - # Test other format replacement. - account_types = conn\ - .execute("SELECT * FROM AccountTypes WHERE AccountType = %", - ["User"]).fetchall() - assert account_types == \ - ["SELECT * FROM AccountTypes WHERE AccountType = %%", ["User"]] - aurweb.config.rehash() - - -@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) -@mock.patch.object(sqlite3, "paramstyle", "qmark") -def test_connection_execute_paramstyle_qmark(): - tmpctx, tmp = make_temp_sqlite_config() - - with tmpctx: - with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): - aurweb.config.rehash() - - aurweb.db.kill_engine() - aurweb.initdb.run(Args()) - - conn = db.Connection() - # We don't modify anything when using qmark, so test equality. - account_types = conn\ - .execute("SELECT * FROM AccountTypes WHERE AccountType = ?", - ["User"]).fetchall() - assert account_types == \ - ["SELECT * FROM AccountTypes WHERE AccountType = ?", ["User"]] - aurweb.config.rehash() - - -@mock.patch("sqlite3.connect", mock.MagicMock(return_value=DBConnection())) -@mock.patch.object(sqlite3, "paramstyle", "unsupported") -def test_connection_execute_paramstyle_unsupported(): - tmpctx, tmp = make_temp_sqlite_config() - with tmpctx: - with mock.patch.dict(os.environ, {"AUR_CONFIG": tmp}): - aurweb.config.rehash() - conn = db.Connection() - with pytest.raises(ValueError, match="unsupported paramstyle"): - conn.execute( - "SELECT * FROM AccountTypes WHERE AccountType = ?", - ["User"] - ).fetchall() - aurweb.config.rehash() - - def test_create_delete(): with db.begin(): account_type = db.create(AccountType, AccountType="test") @@ -318,3 +216,9 @@ def test_connection_executor_mysql_paramstyle(): def test_connection_executor_sqlite_paramstyle(): executor = db.ConnectionExecutor(None, backend="sqlite") assert executor.paramstyle() == sqlite3.paramstyle + + +def test_name_without_pytest_current_test(): + with mock.patch.dict("os.environ", {}, clear=True): + dbname = aurweb.db.name() + assert dbname == aurweb.config.get("database", "name") diff --git a/test/test_dependency_type.py b/test/test_dependency_type.py index cb8dece4..c5afd38d 100644 --- a/test/test_dependency_type.py +++ b/test/test_dependency_type.py @@ -2,12 +2,11 @@ import pytest from aurweb.db import begin, create, delete, query from aurweb.models.dependency_type import DependencyType -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db() +def setup(db_test): + return def test_dependency_types(): diff --git a/test/test_group.py b/test/test_group.py index cea69b68..82b82464 100644 --- a/test/test_group.py +++ b/test/test_group.py @@ -4,12 +4,11 @@ from sqlalchemy.exc import IntegrityError from aurweb import db from aurweb.models.group import Group -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db("Groups") +def setup(db_test): + return def test_group_creation(): @@ -21,6 +20,4 @@ def test_group_creation(): def test_group_null_name_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(Group) - db.rollback() + Group() diff --git a/test/test_homepage.py b/test/test_homepage.py index 5c678b71..2e6d53c9 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -18,7 +18,6 @@ from aurweb.models.package_request import PackageRequest from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User from aurweb.redis import redis_connection -from aurweb.testing import setup_test_db from aurweb.testing.html import parse_root from aurweb.testing.requests import Request @@ -26,14 +25,8 @@ client = TestClient(app) @pytest.fixture(autouse=True) -def setup(): - yield setup_test_db( - User.__tablename__, - Package.__tablename__, - PackageBase.__tablename__, - PackageComaintainer.__tablename__, - PackageRequest.__tablename__ - ) +def setup(db_test): + return @pytest.fixture diff --git a/test/test_html.py b/test/test_html.py index 8e7cb2d1..db47c5e5 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -8,14 +8,13 @@ from fastapi.testclient import TestClient from aurweb import asgi, db from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID, AccountType from aurweb.models.user import User -from aurweb.testing import setup_test_db from aurweb.testing.html import get_errors, get_successes, parse_root from aurweb.testing.requests import Request @pytest.fixture(autouse=True) -def setup(): - setup_test_db(User.__tablename__) +def setup(db_test): + return @pytest.fixture diff --git a/test/test_initdb.py b/test/test_initdb.py index c7d29ee2..44681d8e 100644 --- a/test/test_initdb.py +++ b/test/test_initdb.py @@ -1,3 +1,5 @@ +import pytest + import aurweb.config import aurweb.db import aurweb.initdb @@ -5,6 +7,11 @@ import aurweb.initdb from aurweb.models.account_type import AccountType +@pytest.fixture(autouse=True) +def setup(db_test): + return + + class Args: use_alembic = True verbose = True @@ -15,6 +22,8 @@ def test_run(): aurweb.db.kill_engine() metadata.drop_all(aurweb.db.get_engine()) aurweb.initdb.run(Args()) + + # Check that constant table rows got added via initdb. record = aurweb.db.query(AccountType, AccountType.AccountType == "User").first() assert record is not None diff --git a/test/test_license.py b/test/test_license.py index 2c52f058..b34bd260 100644 --- a/test/test_license.py +++ b/test/test_license.py @@ -4,12 +4,11 @@ from sqlalchemy.exc import IntegrityError from aurweb import db from aurweb.models.license import License -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db("Licenses") +def setup(db_test): + return def test_license_creation(): @@ -21,6 +20,4 @@ def test_license_creation(): def test_license_null_name_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(License) - db.rollback() + License() diff --git a/test/test_official_provider.py b/test/test_official_provider.py index 0aa4f1d1..9287ea2d 100644 --- a/test/test_official_provider.py +++ b/test/test_official_provider.py @@ -4,12 +4,11 @@ from sqlalchemy.exc import IntegrityError from aurweb import db from aurweb.models.official_provider import OfficialProvider -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db("OfficialProviders") +def setup(db_test): + return def test_official_provider_creation(): @@ -53,26 +52,14 @@ def test_official_provider_cs(): def test_official_provider_null_name_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(OfficialProvider, - Repo="some-repo", - Provides="some-provides") - db.rollback() + OfficialProvider(Repo="some-repo", Provides="some-provides") def test_official_provider_null_repo_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(OfficialProvider, - Name="some-name", - Provides="some-provides") - db.rollback() + OfficialProvider(Name="some-name", Provides="some-provides") def test_official_provider_null_provides_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(OfficialProvider, - Name="some-name", - Repo="some-repo") - db.rollback() + OfficialProvider(Name="some-name", Repo="some-repo") diff --git a/test/test_package.py b/test/test_package.py index 112ca9b4..c2afa660 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -8,17 +8,14 @@ from aurweb.models.account_type import AccountType from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = package = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase, package - setup_test_db("Packages", "PackageBases", "Users") - account_type = db.query(AccountType, AccountType.AccountType == "User").first() diff --git a/test/test_package_base.py b/test/test_package_base.py index 2bc6278f..8e4b2edf 100644 --- a/test/test_package_base.py +++ b/test/test_package_base.py @@ -8,17 +8,14 @@ from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.package_base import PackageBase from aurweb.models.user import User -from aurweb.testing import setup_test_db user = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user - setup_test_db("Users", "PackageBases") - account_type = db.query(AccountType, AccountType.AccountType == "User").first() with db.begin(): diff --git a/test/test_package_blacklist.py b/test/test_package_blacklist.py index 93f15de7..6f4c36d7 100644 --- a/test/test_package_blacklist.py +++ b/test/test_package_blacklist.py @@ -6,20 +6,18 @@ from aurweb import db from aurweb.models.package_base import PackageBase from aurweb.models.package_blacklist import PackageBlacklist from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase - setup_test_db("PackageBlacklist", "PackageBases", "Users") - - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) def test_package_blacklist_creation(): @@ -31,6 +29,4 @@ def test_package_blacklist_creation(): def test_package_blacklist_null_name_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(PackageBlacklist) - db.rollback() + PackageBlacklist() diff --git a/test/test_package_comaintainer.py b/test/test_package_comaintainer.py index cba99ba0..ff74cddf 100644 --- a/test/test_package_comaintainer.py +++ b/test/test_package_comaintainer.py @@ -2,29 +2,28 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, rollback +from aurweb import db from aurweb.models.package_base import PackageBase from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase - setup_test_db("Users", "PackageBases", "PackageComaintainers") - - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) def test_package_comaintainer_creation(): - package_comaintainer = create(PackageComaintainer, User=user, - PackageBase=pkgbase, Priority=5) + with db.begin(): + package_comaintainer = db.create(PackageComaintainer, User=user, + PackageBase=pkgbase, Priority=5) assert bool(package_comaintainer) assert package_comaintainer.User == user assert package_comaintainer.PackageBase == pkgbase @@ -33,17 +32,14 @@ def test_package_comaintainer_creation(): def test_package_comaintainer_null_user_raises_exception(): with pytest.raises(IntegrityError): - create(PackageComaintainer, PackageBase=pkgbase, Priority=1) - rollback() + PackageComaintainer(PackageBase=pkgbase, Priority=1) def test_package_comaintainer_null_pkgbase_raises_exception(): with pytest.raises(IntegrityError): - create(PackageComaintainer, User=user, Priority=1) - rollback() + PackageComaintainer(User=user, Priority=1) def test_package_comaintainer_null_priority_raises_exception(): with pytest.raises(IntegrityError): - create(PackageComaintainer, User=user, PackageBase=pkgbase) - rollback() + PackageComaintainer(User=user, PackageBase=pkgbase) diff --git a/test/test_package_comment.py b/test/test_package_comment.py index 60f0333d..b00e08c3 100644 --- a/test/test_package_comment.py +++ b/test/test_package_comment.py @@ -2,70 +2,55 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import begin, create, query, rollback -from aurweb.models.account_type import AccountType +from aurweb import db +from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase from aurweb.models.package_comment import PackageComment from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = None @pytest.fixture(autouse=True) -def setup(): - setup_test_db("PackageBases", "PackageComments", "Users") - +def setup(db_test): global user, pkgbase - account_type = query(AccountType, - AccountType.AccountType == "User").first() - with begin(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) def test_package_comment_creation(): - with begin(): - package_comment = create(PackageComment, - PackageBase=pkgbase, - User=user, - Comments="Test comment.", - RenderedComment="Test rendered comment.") + with db.begin(): + package_comment = db.create(PackageComment, PackageBase=pkgbase, + User=user, Comments="Test comment.", + RenderedComment="Test rendered comment.") assert bool(package_comment.ID) def test_package_comment_null_package_base_raises_exception(): with pytest.raises(IntegrityError): - with begin(): - create(PackageComment, User=user, Comments="Test comment.", - RenderedComment="Test rendered comment.") - rollback() + PackageComment(User=user, Comments="Test comment.", + RenderedComment="Test rendered comment.") def test_package_comment_null_user_raises_exception(): with pytest.raises(IntegrityError): - with begin(): - create(PackageComment, PackageBase=pkgbase, - Comments="Test comment.", - RenderedComment="Test rendered comment.") - rollback() + PackageComment(PackageBase=pkgbase, + Comments="Test comment.", + RenderedComment="Test rendered comment.") def test_package_comment_null_comments_raises_exception(): with pytest.raises(IntegrityError): - with begin(): - create(PackageComment, PackageBase=pkgbase, User=user, - RenderedComment="Test rendered comment.") - rollback() + PackageComment(PackageBase=pkgbase, User=user, + RenderedComment="Test rendered comment.") def test_package_comment_null_renderedcomment_defaults(): - with begin(): - record = create(PackageComment, - PackageBase=pkgbase, - User=user, - Comments="Test comment.") + with db.begin(): + record = db.create(PackageComment, PackageBase=pkgbase, + User=user, Comments="Test comment.") assert record.RenderedComment == str() diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py index 2ddef68e..e6125669 100644 --- a/test/test_package_dependency.py +++ b/test/test_package_dependency.py @@ -3,117 +3,70 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.db import create, query -from aurweb.models.account_type import AccountType -from aurweb.models.dependency_type import DependencyType +from aurweb.models.account_type import USER_ID +from aurweb.models.dependency_type import CHECKDEPENDS_ID, DEPENDS_ID, MAKEDEPENDS_ID, OPTDEPENDS_ID from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = package = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase, package - setup_test_db("Users", "PackageBases", "Packages", "PackageDepends") - - account_type = query(AccountType, - AccountType.AccountType == "User").first() - with db.begin(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, - Name="test-package", - Maintainer=user) - package = create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + pkgbase = db.create(PackageBase, + Name="test-package", + Maintainer=user) + package = db.create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") def test_package_dependencies(): - depends = query(DependencyType, DependencyType.Name == "depends").first() - with db.begin(): - pkgdep = create(PackageDependency, Package=package, - DependencyType=depends, - DepName="test-dep") + pkgdep = db.create(PackageDependency, Package=package, + DepTypeID=DEPENDS_ID, DepName="test-dep") assert pkgdep.DepName == "test-dep" assert pkgdep.Package == package - assert pkgdep.DependencyType == depends - assert pkgdep in depends.package_dependencies assert pkgdep in package.package_dependencies - makedepends = query(DependencyType, - DependencyType.Name == "makedepends").first() with db.begin(): - pkgdep.DependencyType = makedepends - assert pkgdep.DepName == "test-dep" - assert pkgdep.Package == package - assert pkgdep.DependencyType == makedepends - assert pkgdep in makedepends.package_dependencies - assert pkgdep in package.package_dependencies + pkgdep.DepTypeID = MAKEDEPENDS_ID - checkdepends = query(DependencyType, - DependencyType.Name == "checkdepends").first() with db.begin(): - pkgdep.DependencyType = checkdepends - assert pkgdep.DepName == "test-dep" - assert pkgdep.Package == package - assert pkgdep.DependencyType == checkdepends - assert pkgdep in checkdepends.package_dependencies - assert pkgdep in package.package_dependencies + pkgdep.DepTypeID = CHECKDEPENDS_ID - optdepends = query(DependencyType, - DependencyType.Name == "optdepends").first() with db.begin(): - pkgdep.DependencyType = optdepends - assert pkgdep.DepName == "test-dep" - assert pkgdep.Package == package - assert pkgdep.DependencyType == optdepends - assert pkgdep in optdepends.package_dependencies - assert pkgdep in package.package_dependencies + pkgdep.DepTypeID = OPTDEPENDS_ID assert not pkgdep.is_package() with db.begin(): - base = create(PackageBase, Name=pkgdep.DepName, Maintainer=user) - create(Package, PackageBase=base, Name=pkgdep.DepName) + base = db.create(PackageBase, Name=pkgdep.DepName, Maintainer=user) + db.create(Package, PackageBase=base, Name=pkgdep.DepName) assert pkgdep.is_package() def test_package_dependencies_null_package_raises_exception(): - depends = query(DependencyType, DependencyType.Name == "depends").first() with pytest.raises(IntegrityError): - with db.begin(): - create(PackageDependency, - DependencyType=depends, - DepName="test-dep") - db.rollback() + PackageDependency(DepTypeID=DEPENDS_ID, DepName="test-dep") def test_package_dependencies_null_dependency_type_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - create(PackageDependency, - Package=package, - DepName="test-dep") - db.rollback() + PackageDependency(Package=package, DepName="test-dep") def test_package_dependencies_null_depname_raises_exception(): - depends = query(DependencyType, DependencyType.Name == "depends").first() with pytest.raises(IntegrityError): - with db.begin(): - create(PackageDependency, - Package=package, - DependencyType=depends) - db.rollback() + PackageDependency(DepTypeID=DEPENDS_ID, Package=package) diff --git a/test/test_package_group.py b/test/test_package_group.py index 0e6e41e3..2c91e0b1 100644 --- a/test/test_package_group.py +++ b/test/test_package_group.py @@ -2,51 +2,44 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query -from aurweb.models.account_type import AccountType +from aurweb import db +from aurweb.models.account_type import USER_ID from aurweb.models.group import Group from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_group import PackageGroup from aurweb.models.user import User -from aurweb.testing import setup_test_db user = group = pkgbase = package = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, group, pkgbase, package - setup_test_db("Users", "PackageBases", "Packages", - "Groups", "PackageGroups") + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + group = db.create(Group, Name="Test Group") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - - group = create(Group, Name="Test Group") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) - package = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + with db.begin(): + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) def test_package_group(): - package_group = create(PackageGroup, Package=package, Group=group) + with db.begin(): + package_group = db.create(PackageGroup, Package=package, Group=group) assert package_group.Group == group assert package_group.Package == package def test_package_group_null_package_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(PackageGroup, Group=group) - session.rollback() + PackageGroup(Group=group) def test_package_group_null_group_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(PackageGroup, Package=package) - session.rollback() + PackageGroup(Package=package) diff --git a/test/test_package_keyword.py b/test/test_package_keyword.py index 316e7ca8..88ccb734 100644 --- a/test/test_package_keyword.py +++ b/test/test_package_keyword.py @@ -2,44 +2,37 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query -from aurweb.models.account_type import AccountType +from aurweb import db +from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase from aurweb.models.package_keyword import PackageKeyword from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase - setup_test_db("Users", "PackageBases", "PackageKeywords") - - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, - Name="beautiful-package", - Maintainer=user) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + pkgbase = db.create(PackageBase, + Name="beautiful-package", + Maintainer=user) def test_package_keyword(): - pkg_keyword = create(PackageKeyword, - PackageBase=pkgbase, - Keyword="test") + with db.begin(): + pkg_keyword = db.create(PackageKeyword, + PackageBase=pkgbase, + Keyword="test") assert pkg_keyword in pkgbase.keywords assert pkgbase == pkg_keyword.PackageBase def test_package_keyword_null_pkgbase_raises_exception(): - from aurweb.db import session - with pytest.raises(IntegrityError): - create(PackageKeyword, - Keyword="test") - session.rollback() + PackageKeyword(Keyword="test") diff --git a/test/test_package_license.py b/test/test_package_license.py index f7654dee..965d0c6f 100644 --- a/test/test_package_license.py +++ b/test/test_package_license.py @@ -2,51 +2,45 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query -from aurweb.models.account_type import AccountType +from aurweb import db +from aurweb.models.account_type import USER_ID from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_license import PackageLicense from aurweb.models.user import User -from aurweb.testing import setup_test_db user = license = pkgbase = package = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, license, pkgbase, package - setup_test_db("Users", "PackageBases", "Packages", - "Licenses", "PackageLicenses") + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + license = db.create(License, Name="Test License") - account_type = query(AccountType, - AccountType.AccountType == "User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - - license = create(License, Name="Test License") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) - package = create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + with db.begin(): + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) def test_package_license(): - package_license = create(PackageLicense, Package=package, License=license) + with db.begin(): + package_license = db.create(PackageLicense, Package=package, + License=license) assert package_license.License == license assert package_license.Package == package def test_package_license_null_package_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(PackageLicense, License=license) - session.rollback() + PackageLicense(License=license) def test_package_license_null_license_raises_exception(): - from aurweb.db import session with pytest.raises(IntegrityError): - create(PackageLicense, Package=package) - session.rollback() + PackageLicense(Package=package) diff --git a/test/test_package_notification.py b/test/test_package_notification.py index 2898a904..2e505dd8 100644 --- a/test/test_package_notification.py +++ b/test/test_package_notification.py @@ -2,29 +2,28 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, rollback +from aurweb import db from aurweb.models.package_base import PackageBase from aurweb.models.package_notification import PackageNotification from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase - setup_test_db("Users", "PackageBases", "PackageNotifications") - - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) def test_package_notification_creation(): - package_notification = create(PackageNotification, User=user, - PackageBase=pkgbase) + with db.begin(): + package_notification = db.create( + PackageNotification, User=user, PackageBase=pkgbase) assert bool(package_notification) assert package_notification.User == user assert package_notification.PackageBase == pkgbase @@ -32,11 +31,9 @@ def test_package_notification_creation(): def test_package_notification_null_user_raises_exception(): with pytest.raises(IntegrityError): - create(PackageNotification, PackageBase=pkgbase) - rollback() + PackageNotification(PackageBase=pkgbase) def test_package_notification_null_pkgbase_raises_exception(): with pytest.raises(IntegrityError): - create(PackageNotification, User=user) - rollback() + PackageNotification(User=user) diff --git a/test/test_package_relation.py b/test/test_package_relation.py index edb67078..e5f7f453 100644 --- a/test/test_package_relation.py +++ b/test/test_package_relation.py @@ -1,103 +1,63 @@ import pytest -from sqlalchemy.exc import IntegrityError, OperationalError +from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.db import create, query -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_relation import PackageRelation -from aurweb.models.relation_type import RelationType +from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = package = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase, package - setup_test_db("Users", "PackageBases", "Packages", "PackageRelations") - - account_type = query(AccountType, - AccountType.AccountType == "User").first() - with db.begin(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, - Name="test-package", - Maintainer=user) - package = create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + pkgbase = db.create(PackageBase, + Name="test-package", + Maintainer=user) + package = db.create(Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package") def test_package_relation(): - conflicts = query(RelationType, RelationType.Name == "conflicts").first() - with db.begin(): - pkgrel = create(PackageRelation, Package=package, - RelationType=conflicts, - RelName="test-relation") + pkgrel = db.create(PackageRelation, Package=package, + RelTypeID=CONFLICTS_ID, + RelName="test-relation") + assert pkgrel.RelName == "test-relation" assert pkgrel.Package == package - assert pkgrel.RelationType == conflicts - assert pkgrel in conflicts.package_relations assert pkgrel in package.package_relations - provides = query(RelationType, RelationType.Name == "provides").first() with db.begin(): - pkgrel.RelationType = provides - assert pkgrel.RelName == "test-relation" - assert pkgrel.Package == package - assert pkgrel.RelationType == provides - assert pkgrel in provides.package_relations - assert pkgrel in package.package_relations + pkgrel.RelTypeID = PROVIDES_ID - replaces = query(RelationType, RelationType.Name == "replaces").first() with db.begin(): - pkgrel.RelationType = replaces - assert pkgrel.RelName == "test-relation" - assert pkgrel.Package == package - assert pkgrel.RelationType == replaces - assert pkgrel in replaces.package_relations - assert pkgrel in package.package_relations + pkgrel.RelTypeID = REPLACES_ID def test_package_relation_null_package_raises_exception(): - conflicts = query(RelationType, RelationType.Name == "conflicts").first() - assert conflicts is not None - with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRelation, - RelationType=conflicts, - RelName="test-relation") - db.rollback() + PackageRelation(RelTypeID=CONFLICTS_ID, RelName="test-relation") def test_package_relation_null_relation_type_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRelation, - Package=package, - RelName="test-relation") - db.rollback() + PackageRelation(Package=package, RelName="test-relation") def test_package_relation_null_relname_raises_exception(): - depends = query(RelationType, RelationType.Name == "conflicts").first() - assert depends is not None - - with pytest.raises((OperationalError, IntegrityError)): - with db.begin(): - create(PackageRelation, - Package=package, - RelationType=depends) - db.rollback() + with pytest.raises(IntegrityError): + PackageRelation(Package=package, RelTypeID=CONFLICTS_ID) diff --git a/test/test_package_request.py b/test/test_package_request.py index 1589ffc2..4b5dfb2b 100644 --- a/test/test_package_request.py +++ b/test/test_package_request.py @@ -5,41 +5,35 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.db import create, query, rollback +from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase from aurweb.models.package_request import (ACCEPTED, ACCEPTED_ID, CLOSED, CLOSED_ID, PENDING, PENDING_ID, REJECTED, REJECTED_ID, PackageRequest) -from aurweb.models.request_type import RequestType +from aurweb.models.request_type import MERGE_ID from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase - setup_test_db("PackageRequests", "PackageBases", "Users") - with db.begin(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) def test_package_request_creation(): - request_type = query(RequestType, RequestType.Name == "merge").first() - assert request_type.Name == "merge" - with db.begin(): - package_request = create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) assert bool(package_request.ID) - assert package_request.RequestType == request_type assert package_request.User == user assert package_request.PackageBase == pkgbase assert package_request.PackageBaseName == pkgbase.Name @@ -47,22 +41,18 @@ def test_package_request_creation(): assert package_request.ClosureComment == str() # Make sure that everything is cross-referenced with relationships. - assert package_request in request_type.package_requests assert package_request in user.package_requests assert package_request in pkgbase.requests def test_package_request_closed(): - request_type = query(RequestType, RequestType.Name == "merge").first() - assert request_type.Name == "merge" - ts = int(datetime.utcnow().timestamp()) with db.begin(): - package_request = create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Closer=user, ClosedTS=ts, - Comments=str(), ClosureComment=str()) + package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Closer=user, ClosedTS=ts, + Comments=str(), ClosureComment=str()) assert package_request.Closer == user assert package_request.ClosedTS == ts @@ -73,73 +63,54 @@ def test_package_request_closed(): def test_package_request_null_request_type_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRequest, User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) - rollback() + PackageRequest(User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) def test_package_request_null_user_raises_exception(): - request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRequest, RequestType=request_type, - PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) - rollback() + PackageRequest(ReqTypeID=MERGE_ID, + PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) def test_package_request_null_package_base_raises_exception(): - request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRequest, RequestType=request_type, - User=user, PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) - rollback() + PackageRequest(ReqTypeID=MERGE_ID, + User=user, PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str()) def test_package_request_null_package_base_name_raises_exception(): - request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - Comments=str(), ClosureComment=str()) - rollback() + PackageRequest(ReqTypeID=MERGE_ID, + User=user, PackageBase=pkgbase, + Comments=str(), ClosureComment=str()) def test_package_request_null_comments_raises_exception(): - request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRequest, RequestType=request_type, User=user, - PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - ClosureComment=str()) - rollback() + PackageRequest(ReqTypeID=MERGE_ID, User=user, + PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + ClosureComment=str()) def test_package_request_null_closure_comment_raises_exception(): - request_type = query(RequestType, RequestType.Name == "merge").first() with pytest.raises(IntegrityError): - with db.begin(): - create(PackageRequest, RequestType=request_type, User=user, - PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - Comments=str()) - rollback() + PackageRequest(ReqTypeID=MERGE_ID, User=user, + PackageBase=pkgbase, PackageBaseName=pkgbase.Name, + Comments=str()) def test_package_request_status_display(): """ Test status_display() based on the Status column value. """ - request_type = query(RequestType, RequestType.Name == "merge").first() - with db.begin(): - pkgreq = create(PackageRequest, RequestType=request_type, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str(), - Status=PENDING_ID) + pkgreq = db.create(PackageRequest, ReqTypeID=MERGE_ID, + User=user, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), ClosureComment=str(), + Status=PENDING_ID) assert pkgreq.status_display() == PENDING with db.begin(): diff --git a/test/test_package_source.py b/test/test_package_source.py index d1adcf9c..b83c9d48 100644 --- a/test/test_package_source.py +++ b/test/test_package_source.py @@ -14,7 +14,7 @@ user = pkgbase = package = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase, package setup_test_db("PackageSources", "Packages", "PackageBases", "Users") diff --git a/test/test_package_vote.py b/test/test_package_vote.py index cb15e217..d1ec203b 100644 --- a/test/test_package_vote.py +++ b/test/test_package_vote.py @@ -4,30 +4,30 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, rollback +from aurweb import db from aurweb.models.package_base import PackageBase from aurweb.models.package_vote import PackageVote from aurweb.models.user import User -from aurweb.testing import setup_test_db user = pkgbase = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, pkgbase - setup_test_db("Users", "PackageBases", "PackageVotes") - - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = create(PackageBase, Name="test-package", Maintainer=user) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword") + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) def test_package_vote_creation(): ts = int(datetime.utcnow().timestamp()) - package_vote = create(PackageVote, User=user, PackageBase=pkgbase, - VoteTS=ts) + + with db.begin(): + package_vote = db.create(PackageVote, User=user, + PackageBase=pkgbase, VoteTS=ts) assert bool(package_vote) assert package_vote.User == user assert package_vote.PackageBase == pkgbase @@ -36,17 +36,14 @@ def test_package_vote_creation(): def test_package_vote_null_user_raises_exception(): with pytest.raises(IntegrityError): - create(PackageVote, PackageBase=pkgbase, VoteTS=1) - rollback() + PackageVote(PackageBase=pkgbase, VoteTS=1) def test_package_vote_null_pkgbase_raises_exception(): with pytest.raises(IntegrityError): - create(PackageVote, User=user, VoteTS=1) - rollback() + PackageVote(User=user, VoteTS=1) def test_package_vote_null_votets_raises_exception(): with pytest.raises(IntegrityError): - create(PackageVote, User=user, PackageBase=pkgbase) - rollback() + PackageVote(User=user, PackageBase=pkgbase) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 1bdb3ea3..02c22d9d 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -28,7 +28,6 @@ from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID, RelationType from aurweb.models.request_type import DELETION_ID, MERGE_ID, RequestType from aurweb.models.user import User -from aurweb.testing import setup_test_db from aurweb.testing.html import get_errors, get_successes, parse_root from aurweb.testing.requests import Request @@ -65,21 +64,8 @@ def create_package_rel(package: Package, @pytest.fixture(autouse=True) -def setup(): - setup_test_db( - User.__tablename__, - Package.__tablename__, - PackageBase.__tablename__, - PackageDependency.__tablename__, - PackageRelation.__tablename__, - PackageKeyword.__tablename__, - PackageVote.__tablename__, - PackageNotification.__tablename__, - PackageComaintainer.__tablename__, - PackageComment.__tablename__, - PackageRequest.__tablename__, - OfficialProvider.__tablename__ - ) +def setup(db_test): + return @pytest.fixture @@ -91,12 +77,11 @@ def client() -> TestClient: @pytest.fixture def user() -> User: """ Yield a user. """ - account_type = db.query(AccountType, AccountType.ID == USER_ID).first() with db.begin(): user = db.create(User, Username="test", Email="test@example.org", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) yield user @@ -1173,7 +1158,7 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, PackageNotification.UserID == maintainer.ID ).first() with db.begin(): - db.session.delete(db_notif) + db.delete(db_notif) # Now, let's edit the comment we just created. comment_id = int(headers[0].attrib["id"].split("-")[-1]) diff --git a/test/test_packages_util.py b/test/test_packages_util.py index 622c08c2..cd0982b2 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -6,7 +6,7 @@ from fastapi import HTTPException from fastapi.testclient import TestClient from aurweb import asgi, db -from aurweb.models.account_type import USER_ID, AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -15,29 +15,20 @@ from aurweb.models.package_vote import PackageVote from aurweb.models.user import User from aurweb.packages import util from aurweb.redis import kill_redis -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db( - User.__tablename__, - Package.__tablename__, - PackageBase.__tablename__, - PackageVote.__tablename__, - PackageNotification.__tablename__, - OfficialProvider.__tablename__ - ) +def setup(db_test): + return @pytest.fixture def maintainer() -> User: - account_type = db.query(AccountType, AccountType.ID == USER_ID).first() with db.begin(): maintainer = db.create(User, Username="test_maintainer", Email="test_maintainer@examepl.org", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) yield maintainer diff --git a/test/test_popupdate.py b/test/test_popupdate.py index 93f86f10..ce3f9f11 100644 --- a/test/test_popupdate.py +++ b/test/test_popupdate.py @@ -1,5 +1,12 @@ +import pytest + from aurweb.scripts import popupdate +@pytest.fixture(autouse=True) +def setup(db_test): + return + + def test_popupdate(): popupdate.main() diff --git a/test/test_ratelimit.py b/test/test_ratelimit.py index 0a72a7e4..859adea9 100644 --- a/test/test_ratelimit.py +++ b/test/test_ratelimit.py @@ -8,15 +8,14 @@ from aurweb import config, db, logging from aurweb.models import ApiRateLimit from aurweb.ratelimit import check_ratelimit from aurweb.redis import redis_connection -from aurweb.testing import setup_test_db from aurweb.testing.requests import Request logger = logging.get_logger(__name__) @pytest.fixture(autouse=True) -def setup(): - setup_test_db(ApiRateLimit.__tablename__) +def setup(db_test): + return @pytest.fixture @@ -31,27 +30,36 @@ def pipeline(): yield pipeline +config_getint = config.getint + + def mock_config_getint(section: str, key: str): if key == "request_limit": return 4 elif key == "window_length": return 100 - return config.getint(section, key) + return config_getint(section, key) + + +config_getboolean = config.getboolean def mock_config_getboolean(return_value: int = 0): def fn(section: str, key: str): if section == "ratelimit" and key == "cache": return return_value - return config.getboolean(section, key) + return config_getboolean(section, key) return fn +config_get = config.get + + def mock_config_get(return_value: str = "none"): def fn(section: str, key: str): if section == "options" and key == "cache": return return_value - return config.get(section, key) + return config_get(section, key) return fn diff --git a/test/test_relation_type.py b/test/test_relation_type.py index d2dabceb..263ae1ec 100644 --- a/test/test_relation_type.py +++ b/test/test_relation_type.py @@ -2,12 +2,11 @@ import pytest from aurweb import db from aurweb.models.relation_type import RelationType -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db() +def setup(db_test): + return def test_relation_type_creation(): diff --git a/test/test_request_type.py b/test/test_request_type.py index 0db24921..0bc86319 100644 --- a/test/test_request_type.py +++ b/test/test_request_type.py @@ -2,12 +2,11 @@ import pytest from aurweb import db from aurweb.models.request_type import DELETION_ID, MERGE_ID, ORPHAN_ID, RequestType -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db() +def setup(db_test): + return def test_request_type_creation(): diff --git a/test/test_routes.py b/test/test_routes.py index e3f69d7a..32f507f3 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -10,27 +10,21 @@ from fastapi.testclient import TestClient from aurweb import db from aurweb.asgi import app -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.user import User -from aurweb.testing import setup_test_db from aurweb.testing.requests import Request user = client = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, client - setup_test_db("Users", "Sessions") - - account_type = db.query(AccountType, - AccountType.AccountType == "User").first() - with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) client = TestClient(app) diff --git a/test/test_rpc.py b/test/test_rpc.py index 055baa33..f20c9b02 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -26,7 +26,6 @@ from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import RelationType from aurweb.models.user import User from aurweb.redis import redis_connection -from aurweb.testing import setup_test_db def make_request(path, headers: Dict[str, str] = {}): @@ -35,11 +34,8 @@ def make_request(path, headers: Dict[str, str] = {}): @pytest.fixture(autouse=True) -def setup(): - # Set up tables. - setup_test_db("Users", "PackageBases", "Packages", "Licenses", - "PackageDepends", "PackageRelations", "PackageLicenses", - "PackageKeywords", "PackageVotes", "ApiRateLimit") +def setup(db_test): + # TODO: Rework this into organized fixtures. # Create test package details. with begin(): diff --git a/test/test_rss.py b/test/test_rss.py index 40607ade..7123fbf1 100644 --- a/test/test_rss.py +++ b/test/test_rss.py @@ -12,17 +12,13 @@ from aurweb.models.account_type import AccountType from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.user import User -from aurweb.testing import setup_test_db logger = logging.get_logger(__name__) @pytest.fixture(autouse=True) -def setup(): - setup_test_db( - Package.__tablename__, - PackageBase.__tablename__, - User.__tablename__) +def setup(db_test): + return @pytest.fixture diff --git a/test/test_session.py b/test/test_session.py index 4e6f4db4..7d3037a1 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -8,17 +8,14 @@ from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.session import Session, generate_unique_sid from aurweb.models.user import User -from aurweb.testing import setup_test_db account_type = user = session = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global account_type, user, session - setup_test_db("Users", "Sessions") - account_type = db.query(AccountType, AccountType.AccountType == "User").first() with db.begin(): diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py index 12a3e1ce..bb787759 100644 --- a/test/test_ssh_pub_key.py +++ b/test/test_ssh_pub_key.py @@ -1,10 +1,9 @@ import pytest from aurweb import db -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.user import User -from aurweb.testing import setup_test_db TEST_SSH_PUBKEY = """ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCycoCi5yGCvSclH2wmNBUuwsYEzRZZBJaQquRc4ysl+Tg+/jiDkR3Zn9fIznC4KnFoyrIHzkKuePZ3bNDYwkZxkJKoWBCh4hXKDXSm87FMN0+VDC+1QxF/z0XaAGr/P6f4XukabyddypBdnHcZiplbw+YOSqcAE2TCqOlSXwNMOcF9U89UsR/Q9i9I52hlvU0q8+fZVGhou1KCowFSnHYtrr5KYJ04CXkJ13DkVf3+pjQWyrByvBcf1hGEaczlgfobrrv/y96jDhgfXucxliNKLdufDPPkii3LhhsNcDmmI1VZ3v0irKvd9WZuauqloobY84zEFcDTyjn0hxGjVeYFejm4fBnvjga0yZXORuWksdNfXWLDxFk6MDDd1jF0ExRbP+OxDuU4IVyIuDL7S3cnbf2YjGhkms/8voYT2OBE7FwNlfv98Kr0NUp51zpf55Arxn9j0Rz9xTA7FiODQgCn6iQ0SDtzUNL0IKTCw26xJY5gzMxbfpvzPQGeulx/ioM= kevr@volcano @@ -14,21 +13,16 @@ user = ssh_pub_key = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, ssh_pub_key - setup_test_db("Users", "SSHPubKeys") - - account_type = db.query(AccountType, - AccountType.AccountType == "User").first() with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) with db.begin(): - ssh_pub_key = db.create(SSHPubKey, - UserID=user.ID, + ssh_pub_key = db.create(SSHPubKey, UserID=user.ID, Fingerprint="testFingerprint", PubKey="testPubKey") diff --git a/test/test_term.py b/test/test_term.py index 3f28311f..bfa73a76 100644 --- a/test/test_term.py +++ b/test/test_term.py @@ -4,17 +4,11 @@ from sqlalchemy.exc import IntegrityError from aurweb import db from aurweb.models.term import Term -from aurweb.testing import setup_test_db @pytest.fixture(autouse=True) -def setup(): - setup_test_db("Terms") - - yield None - - # Wipe em out just in case records are leftover. - setup_test_db("Terms") +def setup(db_test): + return def test_term_creation(): @@ -29,13 +23,9 @@ def test_term_creation(): def test_term_null_description_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(Term, URL="https://fake_url.io") - db.rollback() + Term(URL="https://fake_url.io") def test_term_null_url_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(Term, Description="Term description") - db.rollback() + Term(Description="Term description") diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index 0579247e..43a3443b 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -14,7 +14,6 @@ from aurweb.models.account_type import AccountType from aurweb.models.tu_vote import TUVote from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User -from aurweb.testing import setup_test_db from aurweb.testing.requests import Request DATETIME_REGEX = r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$' @@ -76,8 +75,8 @@ def assert_past_vote_html(row, expected): @pytest.fixture(autouse=True) -def setup(): - setup_test_db("TU_Votes", "TU_VoteInfo", "Users") +def setup(db_test): + return @pytest.fixture diff --git a/test/test_tu_vote.py b/test/test_tu_vote.py index 9ff4a8d9..1dd33387 100644 --- a/test/test_tu_vote.py +++ b/test/test_tu_vote.py @@ -4,53 +4,48 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import create, query, rollback -from aurweb.models.account_type import AccountType +from aurweb import db +from aurweb.models.account_type import TRUSTED_USER_ID from aurweb.models.tu_vote import TUVote from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User -from aurweb.testing import setup_test_db user = tu_voteinfo = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user, tu_voteinfo - setup_test_db("Users", "TU_VoteInfo", "TU_Votes") - - tu_type = query(AccountType, - AccountType.AccountType == "Trusted User").first() - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=tu_type) - ts = int(datetime.utcnow().timestamp()) - tu_voteinfo = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 5, - Quorum=0.5, - Submitter=user) + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=TRUSTED_USER_ID) + + tu_voteinfo = db.create(TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, End=ts + 5, + Quorum=0.5, + Submitter=user) def test_tu_vote_creation(): - tu_vote = create(TUVote, User=user, VoteInfo=tu_voteinfo) + with db.begin(): + tu_vote = db.create(TUVote, User=user, VoteInfo=tu_voteinfo) + assert tu_vote.VoteInfo == tu_voteinfo assert tu_vote.User == user - assert tu_vote in user.tu_votes assert tu_vote in tu_voteinfo.tu_votes def test_tu_vote_null_user_raises_exception(): with pytest.raises(IntegrityError): - create(TUVote, VoteInfo=tu_voteinfo) - rollback() + TUVote(VoteInfo=tu_voteinfo) def test_tu_vote_null_voteinfo_raises_exception(): with pytest.raises(IntegrityError): - create(TUVote, User=user) - rollback() + TUVote(User=user) diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py index b60e2e6a..5926fbf9 100644 --- a/test/test_tu_voteinfo.py +++ b/test/test_tu_voteinfo.py @@ -9,17 +9,14 @@ from aurweb.db import create, query, rollback from aurweb.models.account_type import AccountType from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User -from aurweb.testing import setup_test_db user = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global user - setup_test_db("Users", "PackageBases", "TU_VoteInfo") - tu_type = query(AccountType, AccountType.AccountType == "Trusted User").first() with db.begin(): diff --git a/test/test_user.py b/test/test_user.py index 771611d8..07f10487 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -19,27 +19,15 @@ from aurweb.models.package_vote import PackageVote from aurweb.models.session import Session from aurweb.models.ssh_pub_key import SSHPubKey from aurweb.models.user import User -from aurweb.testing import setup_test_db from aurweb.testing.requests import Request account_type = user = None @pytest.fixture(autouse=True) -def setup(): +def setup(db_test): global account_type, user - setup_test_db( - User.__tablename__, - Session.__tablename__, - Ban.__tablename__, - SSHPubKey.__tablename__, - Package.__tablename__, - PackageBase.__tablename__, - PackageVote.__tablename__, - PackageNotification.__tablename__ - ) - account_type = db.query(AccountType, AccountType.AccountType == "User").first() From fa26c8078b5dd305fcc62e349a2856ddd29d0b68 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:44:35 -0800 Subject: [PATCH 1114/1891] fix(docker): modify db configuration for new tests A user that can create databases is now required for tests, we use the 'root' user in Docker. Added docker services: --------------------- - mariadb_test - host localhost:13307 Signed-off-by: Kevin Morris --- conf/config.defaults | 2 +- conf/config.dev | 7 ++-- docker-compose.yml | 65 ++++++++++++++----------------- docker/fastapi-entrypoint.sh | 4 ++ docker/mariadb-entrypoint.sh | 15 +++---- docker/mariadb-init-entrypoint.sh | 2 + docker/php-entrypoint.sh | 7 +++- docker/scripts/run-php.sh | 3 -- docker/scripts/run-pytests.sh | 11 +----- docker/scripts/run-tests.sh | 6 --- docker/test-mysql-entrypoint.sh | 9 ----- docker/tests-entrypoint.sh | 1 - 12 files changed, 53 insertions(+), 79 deletions(-) diff --git a/conf/config.defaults b/conf/config.defaults index c29d7045..68e235be 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -5,7 +5,7 @@ socket = /var/run/mysqld/mysqld.sock ;port = 3306 name = AUR user = aur -password = aur +;password = aur [options] username_min_len = 3 diff --git a/conf/config.dev b/conf/config.dev index 9467615e..e97f6f12 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -6,7 +6,8 @@ ; development-specific options too. [database] -; Options: mysql, sqlite. +; PHP options: mysql, sqlite. +; FastAPI options: mysql. backend = mysql ; If using sqlite, set name to the database file path. @@ -14,8 +15,8 @@ name = aurweb ; MySQL database information. User defaults to root for containerized ; testing with mysqldb. This should be set to a non-root user. -user = aur -password = aur +user = root +;password = aur host = localhost ;port = 3306 socket = /var/run/mysqld/mysqld.sock diff --git a/docker-compose.yml b/docker-compose.yml index bda4ddfb..c39d38bf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -77,6 +77,24 @@ services: mariadb: condition: service_healthy + mariadb_test: + # Test database. + image: aurweb:latest + init: true + environment: + - MARIADB_PRIVILEGED=1 + entrypoint: /docker/mariadb-entrypoint.sh + command: /usr/bin/mysqld_safe --datadir=/var/lib/mysql + ports: + # This will expose mariadbd on 127.0.0.1:13307 in the host. + # Ex: `mysql -uaur -paur -h 127.0.0.1 -P 13306 aurweb` + - "13307:3306" + volumes: + - mariadb_test_run:/var/run/mysqld # Bind socket in this volume. + healthcheck: + test: "bash /docker/health/mariadb.sh" + interval: 3s + git: image: aurweb:latest init: true @@ -254,10 +272,9 @@ services: stdin_open: true tty: true depends_on: - git: + mariadb_test: condition: service_healthy volumes: - - git_data:/aurweb/aur.git - ./cache:/cache - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations @@ -280,34 +297,12 @@ services: stdin_open: true tty: true depends_on: - mariadb_init: - condition: service_started + mariadb_test: + condition: service_healthy + tmpfs: + - /tmp volumes: - - mariadb_run:/var/run/mysqld - - git_data:/aurweb/aur.git - - ./cache:/cache - - ./aurweb:/aurweb/aurweb - - ./migrations:/aurweb/migrations - - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - ./templates:/aurweb/templates - - pytest-sqlite: - image: aurweb:latest - profiles: ["dev"] - init: true - environment: - - AUR_CONFIG=conf/config.sqlite - - TEST_RECURSION_LIMIT=${TEST_RECURSION_LIMIT} - - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus - entrypoint: /docker/test-sqlite-entrypoint.sh - command: setup-sqlite.sh run-pytests.sh clean - stdin_open: true - tty: true - volumes: - - git_data:/aurweb/aur.git + - mariadb_test_run:/var/run/mysqld - ./cache:/cache - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations @@ -325,16 +320,15 @@ services: - AUR_CONFIG=conf/config - TEST_RECURSION_LIMIT=${TEST_RECURSION_LIMIT} - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus - entrypoint: /docker/tests-entrypoint.sh - command: setup-sqlite.sh run-tests.sh + entrypoint: /docker/test-mysql-entrypoint.sh + command: /docker/scripts/run-tests.sh stdin_open: true tty: true depends_on: - mariadb_init: - condition: service_started + mariadb_test: + condition: service_healthy volumes: - - mariadb_run:/var/run/mysqld - - git_data:/aurweb/aur.git + - mariadb_test_run:/var/run/mysqld - ./cache:/cache - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations @@ -345,6 +339,7 @@ services: - ./templates:/aurweb/templates volumes: + mariadb_test_run: {} mariadb_run: {} # Share /var/run/mysqld/mysqld.sock mariadb_data: {} # Share /var/lib/mysql git_data: {} # Share aurweb/aur.git diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index f4ceaafa..9df6382d 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -5,6 +5,10 @@ set -eou pipefail cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config +# Change database user/password. +sed -ri "s/^;?(user) = .*$/\1 = aur/" conf/config +sed -ri "s/^;?(password) = .*$/\1 = aur/" conf/config + sed -ri "s;^(aur_location) = .+;\1 = ${AURWEB_FASTAPI_PREFIX};" conf/config # Setup Redis for FastAPI. diff --git a/docker/mariadb-entrypoint.sh b/docker/mariadb-entrypoint.sh index e1ebfa6a..a00f6106 100755 --- a/docker/mariadb-entrypoint.sh +++ b/docker/mariadb-entrypoint.sh @@ -13,23 +13,18 @@ done # Configure databases. DATABASE="aurweb" # Persistent database for fastapi/php-fpm. -TEST_DB="aurweb_test" # Test database (ephemereal). echo "Taking care of primary database '${DATABASE}'..." mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'localhost' IDENTIFIED BY 'aur';" mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'%' IDENTIFIED BY 'aur';" mysql -u root -e "CREATE DATABASE IF NOT EXISTS $DATABASE;" -mysql -u root -e "GRANT ALL ON ${DATABASE}.* TO 'aur'@'localhost';" -mysql -u root -e "GRANT ALL ON ${DATABASE}.* TO 'aur'@'%';" -# Drop and create our test database. -echo "Dropping test database '$TEST_DB'..." -mysql -u root -e "DROP DATABASE IF EXISTS $TEST_DB;" -mysql -u root -e "CREATE DATABASE $TEST_DB;" -mysql -u root -e "GRANT ALL ON ${TEST_DB}.* TO 'aur'@'localhost';" -mysql -u root -e "GRANT ALL ON ${TEST_DB}.* TO 'aur'@'%';" +mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'%' IDENTIFIED BY 'aur';" +mysql -u root -e "GRANT ALL ON aurweb.* TO 'aur'@'localhost';" +mysql -u root -e "GRANT ALL ON aurweb.* TO 'aur'@'%';" -echo "Created new '$TEST_DB'!" +mysql -u root -e "CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY 'aur';" +mysql -u root -e "GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION;" mysqladmin -uroot shutdown diff --git a/docker/mariadb-init-entrypoint.sh b/docker/mariadb-init-entrypoint.sh index 413227b9..6df98e4f 100755 --- a/docker/mariadb-init-entrypoint.sh +++ b/docker/mariadb-init-entrypoint.sh @@ -4,6 +4,8 @@ set -eou pipefail # Setup a config for our mysql db. cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config +sed -ri "s/^;?(user) = .*$/\1 = aur/g" conf/config +sed -ri "s/^;?(password) = .*$/\1 = aur/g" conf/config python -m aurweb.initdb 2>/dev/null || /bin/true diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index 274f8e17..05b76408 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -9,14 +9,19 @@ done cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config -sed -ri "s;^(aur_location) = .+;\1 = ${AURWEB_PHP_PREFIX};" conf/config +# Change database user/password. +sed -ri "s/^;?(user) = .*$/\1 = aur/" conf/config +sed -ri "s/^;?(password) = .*$/\1 = aur/" conf/config # Enable memcached. sed -ri 's/^(cache) = .+$/\1 = memcache/' conf/config +# Setup various location configurations. +sed -ri "s;^(aur_location) = .+;\1 = ${AURWEB_PHP_PREFIX};" conf/config sed -ri "s|^(git_clone_uri_anon) = .+|\1 = ${AURWEB_PHP_PREFIX}/%s.git|" conf/config.defaults sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ${AURWEB_SSHD_PREFIX}/%s.git|" conf/config.defaults +# Listen on :9000. sed -ri 's/^(listen).*/\1 = 0.0.0.0:9000/' /etc/php/php-fpm.d/www.conf sed -ri 's/^;?(clear_env).*/\1 = no/' /etc/php/php-fpm.d/www.conf diff --git a/docker/scripts/run-php.sh b/docker/scripts/run-php.sh index 22346b47..b86f8ce5 100755 --- a/docker/scripts/run-php.sh +++ b/docker/scripts/run-php.sh @@ -1,7 +1,4 @@ #!/bin/bash set -eou pipefail -# Initialize the new database; ignore errors. -python -m aurweb.initdb 2>/dev/null || /bin/true - exec php-fpm --fpm-config /etc/php/php-fpm.conf --nodaemonize diff --git a/docker/scripts/run-pytests.sh b/docker/scripts/run-pytests.sh index ee546fb7..b8f695df 100755 --- a/docker/scripts/run-pytests.sh +++ b/docker/scripts/run-pytests.sh @@ -25,17 +25,8 @@ done rm -rf $PROMETHEUS_MULTIPROC_DIR mkdir -p $PROMETHEUS_MULTIPROC_DIR -# Initialize the new database; ignore errors. -python -m aurweb.initdb 2>/dev/null || \ - (echo "Error: aurweb.initdb failed; already initialized?" && /bin/true) - -# Run test_initdb ahead of time, which clears out the database, -# in case of previous failures which stopped the test suite before -# finishing the ends of some test fixtures. -eatmydata -- pytest test/test_initdb.py - # Run pytest with optional targets in front of it. -eatmydata -- make -C test "${PARAMS[@]}" pytest +pytest # By default, report coverage and move it into cache. if [ $COVERAGE -eq 1 ]; then diff --git a/docker/scripts/run-tests.sh b/docker/scripts/run-tests.sh index 3181a623..45c7835f 100755 --- a/docker/scripts/run-tests.sh +++ b/docker/scripts/run-tests.sh @@ -12,12 +12,6 @@ bash $dir/run-sharness.sh # Pass --silence to avoid reporting coverage. We will do that below. bash $dir/run-pytests.sh --no-coverage -# Export SQLite aurweb configuration. -export AUR_CONFIG=conf/config.sqlite - -# Run Python tests. -bash $dir/run-pytests.sh --no-coverage - make -C test coverage # /cache is mounted as a volume. Copy coverage into it. diff --git a/docker/test-mysql-entrypoint.sh b/docker/test-mysql-entrypoint.sh index 7be3626b..a46b2572 100755 --- a/docker/test-mysql-entrypoint.sh +++ b/docker/test-mysql-entrypoint.sh @@ -1,17 +1,8 @@ #!/bin/bash set -eou pipefail -DB_NAME="aurweb_test" - # Setup a config for our mysql db. cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config -sed -ri "s/^(name) = .+/\1 = ${DB_NAME}/" conf/config -# The port can be excluded from use if properly using -# volumes to share the mysql socket from the mariadb service. -# Example port sed: -# sed -i "s/^;?(port = .+)$/\1/" conf/config - -# Continue onto the main command. exec "$@" diff --git a/docker/tests-entrypoint.sh b/docker/tests-entrypoint.sh index ca3d3d9a..145bee6e 100755 --- a/docker/tests-entrypoint.sh +++ b/docker/tests-entrypoint.sh @@ -3,6 +3,5 @@ set -eou pipefail dir="$(dirname $0)" bash $dir/test-mysql-entrypoint.sh -bash $dir/test-sqlite-entrypoint.sh exec "$@" From a025118344ff857f5eab7a869b56b952cb46e6d8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:47:33 -0800 Subject: [PATCH 1115/1891] change(docker): get python-poetry from arch instead of poetry Signed-off-by: Kevin Morris --- docker/scripts/install-deps.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index d64340e3..ad0157f8 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -8,9 +8,7 @@ pacman -Syu --noconfirm --noprogressbar \ --cachedir .pkg-cache git gpgme nginx redis openssh \ mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \ php php-fpm memcached php-memcached python-pip pyalpm \ - python-srcinfo curl libeatmydata cronie - -# https://python-poetry.org/docs/ Installation section. -curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + python-srcinfo curl libeatmydata cronie python-poetry \ + python-poetry-core exec "$@" From 60f63876c42b5900cfa7af3442d4feaced3c88c4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:48:31 -0800 Subject: [PATCH 1116/1891] change(.gitignore): ignore archives Signed-off-by: Kevin Morris --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e3201e94..8388694c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ schema/aur-schema-sqlite.sql test/test-results/ test/trash directory* web/locale/*/ +web/html/*.gz # Do not stage compiled asciidoc: make -C doc doc/rpc.html From fb92fb509b4a5769154096969cbfb90f8f69e798 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:49:00 -0800 Subject: [PATCH 1117/1891] change(fastapi): use sys.getrecursionlimit() + 1000 as default Without the increment, we've seen tests failed due to recursion errors caused by starlette's base middleware. Just make it safe in case nobody supplies TEST_RECURSION_LIMIT. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index aafb00b2..b399cfb1 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -45,7 +45,7 @@ async def app_startup(): # when running test suites. # TODO: Find a proper fix to this issue. recursion_limit = int(os.environ.get( - "TEST_RECURSION_LIMIT", sys.getrecursionlimit())) + "TEST_RECURSION_LIMIT", sys.getrecursionlimit() + 1000)) sys.setrecursionlimit(recursion_limit) backend = aurweb.config.get("database", "backend") From a5c0c47e5b82334b6416b13ffcc0f2948377b582 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 00:59:10 -0800 Subject: [PATCH 1118/1891] change(.gitlab-ci): adapt for new conftest No longer do we need to create any database in .gitlab-ci. Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1590bf34..739c9408 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,14 +22,11 @@ test: - (cd '/usr' && /usr/bin/mysqld_safe --datadir='/var/lib/mysql') & - 'until : > /dev/tcp/127.0.0.1/3306; do sleep 1s; done' - ./docker/test-mysql-entrypoint.sh # Create mysql AUR_CONFIG. - - ./docker/test-sqlite-entrypoint.sh # Create sqlite AUR_CONFIG. - make -C po all install - - python -m aurweb.initdb # Initialize MySQL tables. - - AUR_CONFIG=conf/config.sqlite python -m aurweb.initdb - make -C test clean script: - - make -C test sh pytest # sharness tests use sqlite & pytest w/ mysql. - - AUR_CONFIG=conf/config.sqlite make -C test pytest + - make -C test sh # sharness tests use sqlite. + - pytest # Run pytest suites. - make -C test coverage # Produce coverage reports. - flake8 --count aurweb # Assert no flake8 violations in aurweb. - flake8 --count test # Assert no flake8 violations in test. @@ -65,8 +62,11 @@ deploy: # Set secure login config for aurweb. - sed -ri "s/^(disable_http_login).*$/\1 = 1/" conf/config.dev - docker-compose build - - docker system prune -f - docker-compose -f docker-compose.yml -f docker-compose.aur-dev.yml up -d + - docker image prune -f + - docker container prune -f + - docker volume prune -f + environment: name: development url: https://aur-dev.archlinux.org From 912b7e0c118c5717d96fc2770770be8b91b2f81e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 02:19:43 -0800 Subject: [PATCH 1119/1891] fix(docker): fix database user/password for git-entrypoint Signed-off-by: Kevin Morris --- docker/git-entrypoint.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index 3fee426a..296c1e47 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -42,6 +42,9 @@ EOF cp -vf conf/config.dev $AUR_CONFIG sed -i "s;YOUR_AUR_ROOT;$(pwd);g" $AUR_CONFIG +sed -ri "s/^;?(user) = .*$/\1 = aur/" $AUR_CONFIG +sed -ri "s/^;?(password) = .*$/\1 = aur/" $AUR_CONFIG + AUR_CONFIG_DEFAULTS="${AUR_CONFIG}.defaults" if [[ "$AUR_CONFIG_DEFAULTS" != "/aurweb/conf/config.defaults" ]]; then From abe8c0630c52bc5694f9284347045ae353c67507 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 3 Nov 2021 19:34:20 -0700 Subject: [PATCH 1120/1891] fix(rpc): improve type=info performance Now, we use an equivalent query to PHP's query, yet we grab every piece of data we need for all packages asked for in one database query. At this time, local benchmarks have shown a slight performance improvement when compared to PHP. fastapi 262 requests/sec php 250 requests/sec Extras: - Moved RPCError to the aurweb.exceptions module Signed-off-by: Kevin Morris --- aurweb/exceptions.py | 4 + aurweb/rpc.py | 220 +++++++++++++++++++++++++++---------------- 2 files changed, 141 insertions(+), 83 deletions(-) diff --git a/aurweb/exceptions.py b/aurweb/exceptions.py index 62015284..82628b0a 100644 --- a/aurweb/exceptions.py +++ b/aurweb/exceptions.py @@ -73,3 +73,7 @@ class NotVotedException(AurwebException): class InvalidArgumentsException(AurwebException): def __init__(self, msg): super(InvalidArgumentsException, self).__init__(msg) + + +class RPCError(AurwebException): + pass diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 03662790..c70ddf1a 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -1,38 +1,28 @@ from collections import defaultdict -from typing import Any, Callable, Dict, List, NewType +from typing import Any, Callable, Dict, List, NewType, Union -from sqlalchemy import and_ +from sqlalchemy import and_, literal import aurweb.config as config from aurweb import db, defaults, models, util -from aurweb.models import dependency_type, relation_type +from aurweb.exceptions import RPCError from aurweb.packages.search import RPCSearch -# Define dependency type mappings from ID to RPC-compatible keys. -DEP_TYPES = { - dependency_type.DEPENDS_ID: "Depends", - dependency_type.MAKEDEPENDS_ID: "MakeDepends", - dependency_type.CHECKDEPENDS_ID: "CheckDepends", - dependency_type.OPTDEPENDS_ID: "OptDepends" +TYPE_MAPPING = { + "depends": "Depends", + "makedepends": "MakeDepends", + "checkdepends": "CheckDepends", + "optdepends": "OptDepends", + "conflicts": "Conflicts", + "provides": "Provides", + "replaces": "Replaces", } -# Define relationship type mappings from ID to RPC-compatible keys. -REL_TYPES = { - relation_type.CONFLICTS_ID: "Conflicts", - relation_type.PROVIDES_ID: "Provides", - relation_type.REPLACES_ID: "Replaces" -} - - DataGenerator = NewType("DataGenerator", Callable[[models.Package], Dict[str, Any]]) -class RPCError(Exception): - pass - - class RPC: """ RPC API handler class. @@ -76,11 +66,11 @@ class RPC: # A mapping of by aliases. BY_ALIASES = {"name-desc": "nd", "name": "n", "maintainer": "m"} - def __init__(self, version: int = 0, type: str = None): + def __init__(self, version: int = 0, type: str = None) -> "RPC": self.version = version - self.type = type + self.type = RPC.TYPE_ALIASES.get(type, type) - def error(self, message: str) -> dict: + def error(self, message: str) -> Dict[str, Any]: return { "version": self.version, "results": [], @@ -89,7 +79,7 @@ class RPC: "error": message } - def _verify_inputs(self, by: str = [], args: List[str] = []): + def _verify_inputs(self, by: str = [], args: List[str] = []) -> None: if self.version is None: raise RPCError("Please specify an API version.") @@ -105,39 +95,11 @@ class RPC: if self.type not in RPC.EXPOSED_TYPES: raise RPCError("Incorrect request type specified.") - def _enforce_args(self, args: List[str]): + def _enforce_args(self, args: List[str]) -> None: if not args: raise RPCError("No request type/data specified.") - def _update_json_depends(self, package: models.Package, - data: Dict[str, Any]): - # Walk through all related PackageDependencies and produce - # the appropriate dict entries. - for dep in package.package_dependencies: - if dep.DepTypeID in DEP_TYPES: - key = DEP_TYPES.get(dep.DepTypeID) - - display = dep.DepName - if dep.DepCondition: - display += dep.DepCondition - - data[key].append(display) - - def _update_json_relations(self, package: models.Package, - data: Dict[str, Any]): - # Walk through all related PackageRelations and produce - # the appropriate dict entries. - for rel in package.package_relations: - if rel.RelTypeID in REL_TYPES: - key = REL_TYPES.get(rel.RelTypeID) - - display = rel.RelName - if rel.RelCondition: - display += rel.RelCondition - - data[key].append(display) - - def _get_json_data(self, package: models.Package): + def _get_json_data(self, package: models.Package) -> Dict[str, Any]: """ Produce dictionary data of one Package that can be JSON-serialized. :param package: Package instance @@ -175,21 +137,21 @@ class RPC: return data - def _get_info_json_data(self, package: models.Package): + def _get_info_json_data(self, package: models.Package) -> Dict[str, Any]: data = self._get_json_data(package) - # Add licenses and keywords to info output. + # All info results have _at least_ an empty list of + # License and Keywords. data.update({ - "License": [ - lic.License.Name for lic in package.package_licenses - ], - "Keywords": [ - keyword.Keyword for keyword in package.PackageBase.keywords - ] + "License": [], + "Keywords": [] }) - self._update_json_depends(package, data) - self._update_json_relations(package, data) + # If we actually got extra_info records, update data with + # them for this particular package. + if self.extra_info: + data.update(self.extra_info.get(package.ID, {})) + return data def _assemble_json_data(self, packages: List[models.Package], @@ -211,13 +173,97 @@ class RPC: -> List[Dict[str, Any]]: self._enforce_args(args) args = set(args) - packages = db.query(models.Package).filter( + + packages = db.query(models.Package).join(models.PackageBase).filter( models.Package.Name.in_(args)) + ids = {pkg.ID for pkg in packages} + + # Aliases for 80-width. + Package = models.Package + PackageKeyword = models.PackageKeyword + + subqueries = [ + # PackageDependency + db.query( + models.PackageDependency + ).join(models.DependencyType).filter( + models.PackageDependency.PackageID.in_(ids) + ).with_entities( + models.PackageDependency.PackageID.label("ID"), + models.DependencyType.Name.label("Type"), + models.PackageDependency.DepName.label("Name"), + models.PackageDependency.DepCondition.label("Cond") + ).distinct().order_by("ID"), + + # PackageRelation + db.query( + models.PackageRelation + ).join(models.RelationType).filter( + models.PackageRelation.PackageID.in_(ids) + ).with_entities( + models.PackageRelation.PackageID.label("ID"), + models.RelationType.Name.label("Type"), + models.PackageRelation.RelName.label("Name"), + models.PackageRelation.RelCondition.label("Cond") + ).distinct().order_by("ID"), + + # Groups + db.query(models.PackageGroup).join( + models.Group, + and_(models.PackageGroup.GroupID == models.Group.ID, + models.PackageGroup.PackageID.in_(ids)) + ).with_entities( + models.PackageGroup.PackageID.label("ID"), + literal("Groups").label("Type"), + models.Group.Name.label("Name"), + literal(str()).label("Cond") + ).distinct().order_by("ID"), + + # Licenses + db.query(models.PackageLicense).join( + models.License, + models.PackageLicense.LicenseID == models.License.ID + ).filter( + models.PackageLicense.PackageID.in_(ids) + ).with_entities( + models.PackageLicense.PackageID.label("ID"), + literal("License").label("Type"), + models.License.Name.label("Name"), + literal(str()).label("Cond") + ).distinct().order_by("ID"), + + # Keywords + db.query(models.PackageKeyword).join( + models.Package, + and_(Package.PackageBaseID == PackageKeyword.PackageBaseID, + Package.ID.in_(ids)) + ).with_entities( + models.Package.ID.label("ID"), + literal("Keywords").label("Type"), + models.PackageKeyword.Keyword.label("Name"), + literal(str()).label("Cond") + ).distinct().order_by("ID") + ] + + # Union all subqueries together. + query = subqueries[0].union_all(*subqueries[1:]) + + # Store our extra information in a class-wise dictionary, + # which contains package id -> extra info dict mappings. + self.extra_info = defaultdict(lambda: defaultdict(list)) + for record in query: + type_ = TYPE_MAPPING.get(record.Type, record.Type) + + name = record.Name + if record.Cond: + name += record.Cond + + self.extra_info[record.ID][type_].append(name) + return self._assemble_json_data(packages, self._get_info_json_data) def _handle_search_type(self, by: str = defaults.RPC_SEARCH_BY, - args: List[str] = []) \ - -> List[Dict[str, Any]]: + args: List[str] = []) -> List[Dict[str, Any]]: # If `by` isn't maintainer and we don't have any args, raise an error. # In maintainer's case, return all orphans if there are no args, # so we need args to pass through to the handler without errors. @@ -235,10 +281,12 @@ class RPC: results = search.results().limit(max_results) return self._assemble_json_data(results, self._get_json_data) - def _handle_msearch_type(self, args: List[str] = [], **kwargs): + def _handle_msearch_type(self, args: List[str] = [], **kwargs)\ + -> List[Dict[str, Any]]: return self._handle_search_type(by="m", args=args) - def _handle_suggest_type(self, args: List[str] = [], **kwargs): + def _handle_suggest_type(self, args: List[str] = [], **kwargs)\ + -> List[str]: if not args: return [] @@ -251,7 +299,8 @@ class RPC: ).order_by(models.Package.Name.asc()).limit(20) return [pkg.Name for pkg in packages] - def _handle_suggest_pkgbase_type(self, args: List[str] = [], **kwargs): + def _handle_suggest_pkgbase_type(self, args: List[str] = [], **kwargs)\ + -> List[str]: if not args: return [] @@ -261,7 +310,19 @@ class RPC: ).order_by(models.PackageBase.Name.asc()).limit(20) return [pkg.Name for pkg in packages] - def handle(self, by: str = defaults.RPC_SEARCH_BY, args: List[str] = []): + def _is_suggestion(self) -> bool: + return self.type.startswith("suggest") + + def _handle_callback(self, by: str, args: List[str])\ + -> Union[List[Dict[str, Any]], List[str]]: + # Get a handle to our callback and trap an RPCError with + # an empty list of results based on callback's execution. + callback = getattr(self, f"_handle_{self.type.replace('-', '_')}_type") + results = callback(by=by, args=args) + return results + + def handle(self, by: str = defaults.RPC_SEARCH_BY, args: List[str] = [])\ + -> Union[List[Dict[str, Any]], Dict[str, Any]]: """ Request entrypoint. A router should pass v, type and args to this function and expect an output dictionary to be returned. @@ -269,10 +330,6 @@ class RPC: :param type: RPC type argument :param args: Deciphered list of arguments based on arg/arg[] inputs """ - # Convert type aliased types. - if self.type in RPC.TYPE_ALIASES: - self.type = RPC.TYPE_ALIASES.get(self.type) - # Prepare our output data dictionary with some basic keys. data = {"version": self.version, "type": self.type} @@ -283,20 +340,17 @@ class RPC: return self.error(str(exc)) # Convert by to its aliased value if it has one. - if by in RPC.BY_ALIASES: - by = RPC.BY_ALIASES.get(by) + by = RPC.BY_ALIASES.get(by, by) - # Get a handle to our callback and trap an RPCError with - # an empty list of results based on callback's execution. - callback = getattr(self, f"_handle_{self.type.replace('-', '_')}_type") + # Process the requested handler. try: - results = callback(by=by, args=args) + results = self._handle_callback(by, args) except RPCError as exc: return self.error(str(exc)) # These types are special: we produce a different kind of # successful JSON output: a list of results. - if self.type in ("suggest", "suggest-pkgbase"): + if self._is_suggestion(): return results # Return JSON output. From ccf50cbdf5135978dbb86e2c37e04b72911d4732 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 3 Nov 2021 19:36:08 -0700 Subject: [PATCH 1121/1891] change: rework test_rpc's TestClient usage into a fixture This is the first step on our path to reworking the test suite in general. Signed-off-by: Kevin Morris --- test/test_rpc.py | 186 ++++++++++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 73 deletions(-) diff --git a/test/test_rpc.py b/test/test_rpc.py index f20c9b02..a4cdb5da 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1,7 +1,6 @@ import re from http import HTTPStatus -from typing import Dict from unittest import mock import orjson @@ -10,8 +9,7 @@ import pytest from fastapi.testclient import TestClient from redis.client import Pipeline -from aurweb import config, db, scripts -from aurweb.asgi import app +from aurweb import asgi, config, db, scripts from aurweb.db import begin, create, query from aurweb.models.account_type import AccountType from aurweb.models.dependency_type import DependencyType @@ -28,9 +26,9 @@ from aurweb.models.user import User from aurweb.redis import redis_connection -def make_request(path, headers: Dict[str, str] = {}): - with TestClient(app) as request: - return request.get(path, headers=headers) +@pytest.fixture +def client() -> TestClient: + yield TestClient(app=asgi.app) @pytest.fixture(autouse=True) @@ -205,7 +203,7 @@ def pipeline(): yield pipeline -def test_rpc_singular_info(): +def test_rpc_singular_info(client: TestClient): # Define expected response. expected_data = { "version": 5, @@ -239,7 +237,9 @@ def test_rpc_singular_info(): } # Make dummy request. - response_arg = make_request("/rpc/?v=5&type=info&arg=chungy-chungus&arg=big-chungus") + with client as request: + response_arg = request.get( + "/rpc/?v=5&type=info&arg=chungy-chungus&arg=big-chungus") # Load request response into Python dictionary. response_info_arg = orjson.loads(response_arg.content.decode()) @@ -254,9 +254,10 @@ def test_rpc_singular_info(): assert response_info_arg == expected_data -def test_rpc_nonexistent_package(): +def test_rpc_nonexistent_package(client: TestClient): # Make dummy request. - response = make_request("/rpc/?v=5&type=info&arg=nonexistent-package") + with client as request: + response = request.get("/rpc/?v=5&type=info&arg=nonexistent-package") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -265,10 +266,12 @@ def test_rpc_nonexistent_package(): assert response_data["resultcount"] == 0 -def test_rpc_multiinfo(): +def test_rpc_multiinfo(client: TestClient): # Make dummy request. request_packages = ["big-chungus", "chungy-chungus"] - response = make_request("/rpc/?v=5&type=info&arg[]=big-chungus&arg[]=chungy-chungus") + with client as request: + response = request.get( + "/rpc/?v=5&type=info&arg[]=big-chungus&arg[]=chungy-chungus") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -280,13 +283,20 @@ def test_rpc_multiinfo(): assert request_packages == [] -def test_rpc_mixedargs(): +def test_rpc_mixedargs(client: TestClient): # Make dummy request. response1_packages = ["gluggly-chungus"] response2_packages = ["gluggly-chungus", "chungy-chungus"] - response1 = make_request("/rpc/?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info") - response2 = make_request("/rpc/?v=5&arg=big-chungus&arg[]=gluggly-chungus&type=info&arg[]=chungy-chungus") + with client as request: + response1 = request.get( + "/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info") + assert response1.status_code == int(HTTPStatus.OK) + + with client as request: + response2 = request.get( + "/rpc?v=5&arg=big-chungus&arg[]=gluggly-chungus&type=info&arg[]=chungy-chungus") + assert response1.status_code == int(HTTPStatus.OK) # Load request response into Python dictionary. response1_data = orjson.loads(response1.content.decode()) @@ -303,7 +313,7 @@ def test_rpc_mixedargs(): assert i == [] -def test_rpc_no_dependencies(): +def test_rpc_no_dependencies(client: TestClient): """This makes sure things like 'MakeDepends' get removed from JSON strings when they don't have set values.""" @@ -330,7 +340,8 @@ def test_rpc_no_dependencies(): } # Make dummy request. - response = make_request("/rpc/?v=5&type=info&arg=chungy-chungus") + with client as request: + response = request.get("/rpc/?v=5&type=info&arg=chungy-chungus") response_data = orjson.loads(response.content.decode()) # Remove inconsistent keys. @@ -340,7 +351,7 @@ def test_rpc_no_dependencies(): assert response_data == expected_response -def test_rpc_bad_type(): +def test_rpc_bad_type(client: TestClient): # Define expected response. expected_data = { 'version': 5, @@ -351,7 +362,8 @@ def test_rpc_bad_type(): } # Make dummy request. - response = make_request("/rpc/?v=5&type=invalid-type&arg=big-chungus") + with client as request: + response = request.get("/rpc/?v=5&type=invalid-type&arg=big-chungus") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -360,7 +372,7 @@ def test_rpc_bad_type(): assert expected_data == response_data -def test_rpc_bad_version(): +def test_rpc_bad_version(client: TestClient): # Define expected response. expected_data = { 'version': 0, @@ -371,7 +383,8 @@ def test_rpc_bad_version(): } # Make dummy request. - response = make_request("/rpc/?v=0&type=info&arg=big-chungus") + with client as request: + response = request.get("/rpc/?v=0&type=info&arg=big-chungus") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -380,7 +393,7 @@ def test_rpc_bad_version(): assert expected_data == response_data -def test_rpc_no_version(): +def test_rpc_no_version(client: TestClient): # Define expected response. expected_data = { 'version': None, @@ -391,7 +404,8 @@ def test_rpc_no_version(): } # Make dummy request. - response = make_request("/rpc/?type=info&arg=big-chungus") + with client as request: + response = request.get("/rpc/?type=info&arg=big-chungus") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -400,7 +414,7 @@ def test_rpc_no_version(): assert expected_data == response_data -def test_rpc_no_type(): +def test_rpc_no_type(client: TestClient): # Define expected response. expected_data = { 'version': 5, @@ -411,7 +425,8 @@ def test_rpc_no_type(): } # Make dummy request. - response = make_request("/rpc/?v=5&arg=big-chungus") + with client as request: + response = request.get("/rpc/?v=5&arg=big-chungus") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -420,7 +435,7 @@ def test_rpc_no_type(): assert expected_data == response_data -def test_rpc_no_args(): +def test_rpc_no_args(client: TestClient): # Define expected response. expected_data = { 'version': 5, @@ -431,7 +446,8 @@ def test_rpc_no_args(): } # Make dummy request. - response = make_request("/rpc/?v=5&type=info") + with client as request: + response = request.get("/rpc/?v=5&type=info") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -440,9 +456,10 @@ def test_rpc_no_args(): assert expected_data == response_data -def test_rpc_no_maintainer(): +def test_rpc_no_maintainer(client: TestClient): # Make dummy request. - response = make_request("/rpc/?v=5&type=info&arg=woogly-chungus") + with client as request: + response = request.get("/rpc/?v=5&type=info&arg=woogly-chungus") # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -451,33 +468,39 @@ def test_rpc_no_maintainer(): assert response_data["results"][0]["Maintainer"] is None -def test_rpc_suggest_pkgbase(): - response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") +def test_rpc_suggest_pkgbase(client: TestClient): + with client as request: + response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") data = response.json() assert data == ["big-chungus"] - response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=chungy") + with client as request: + response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=chungy") data = response.json() assert data == ["chungy-chungus"] # Test no arg supplied. - response = make_request("/rpc?v=5&type=suggest-pkgbase") + with client as request: + response = request.get("/rpc?v=5&type=suggest-pkgbase") data = response.json() assert data == [] -def test_rpc_suggest(): - response = make_request("/rpc?v=5&type=suggest&arg=other") +def test_rpc_suggest(client: TestClient): + with client as request: + response = request.get("/rpc?v=5&type=suggest&arg=other") data = response.json() assert data == ["other-pkg"] # Test non-existent Package. - response = make_request("/rpc?v=5&type=suggest&arg=nonexistent") + with client as request: + response = request.get("/rpc?v=5&type=suggest&arg=nonexistent") data = response.json() assert data == [] # Test no arg supplied. - response = make_request("/rpc?v=5&type=suggest") + with client as request: + response = request.get("/rpc?v=5&type=suggest") data = response.json() assert data == [] @@ -491,14 +514,17 @@ def mock_config_getint(section: str, key: str): @mock.patch("aurweb.config.getint", side_effect=mock_config_getint) -def test_rpc_ratelimit(getint: mock.MagicMock, pipeline: Pipeline): +def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient, + pipeline: Pipeline): for i in range(4): # The first 4 requests should be good. - response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") + with client as request: + response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") assert response.status_code == int(HTTPStatus.OK) # The fifth request should be banned. - response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") + with client as request: + response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") assert response.status_code == int(HTTPStatus.TOO_MANY_REQUESTS) # Delete the cached records. @@ -508,26 +534,32 @@ def test_rpc_ratelimit(getint: mock.MagicMock, pipeline: Pipeline): assert one and two # The new first request should be good. - response = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") + with client as request: + response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") assert response.status_code == int(HTTPStatus.OK) -def test_rpc_etag(): - response1 = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") - response2 = make_request("/rpc?v=5&type=suggest-pkgbase&arg=big") +def test_rpc_etag(client: TestClient): + with client as request: + response1 = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") + + with client as request: + response2 = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") assert response1.headers.get("ETag") is not None assert response1.headers.get("ETag") != str() assert response1.headers.get("ETag") == response2.headers.get("ETag") -def test_rpc_search_arg_too_small(): - response = make_request("/rpc?v=5&type=search&arg=b") +def test_rpc_search_arg_too_small(client: TestClient): + with client as request: + response = request.get("/rpc?v=5&type=search&arg=b") assert response.status_code == int(HTTPStatus.OK) assert response.json().get("error") == "Query arg too small." -def test_rpc_search(): - response = make_request("/rpc?v=5&type=search&arg=big") +def test_rpc_search(client: TestClient): + with client as request: + response = request.get("/rpc?v=5&type=search&arg=big") assert response.status_code == int(HTTPStatus.OK) data = response.json() @@ -539,17 +571,18 @@ def test_rpc_search(): # Test the If-None-Match headers. etag = response.headers.get("ETag").strip('"') headers = {"If-None-Match": etag} - response = make_request("/rpc?v=5&type=search&arg=big", headers=headers) + response = request.get("/rpc?v=5&type=search&arg=big", headers=headers) assert response.status_code == int(HTTPStatus.NOT_MODIFIED) assert response.content == b'' # No args on non-m by types return an error. - response = make_request("/rpc?v=5&type=search") + response = request.get("/rpc?v=5&type=search") assert response.json().get("error") == "No request type/data specified." -def test_rpc_msearch(): - response = make_request("/rpc?v=5&type=msearch&arg=user1") +def test_rpc_msearch(client: TestClient): + with client as request: + response = request.get("/rpc?v=5&type=msearch&arg=user1") data = response.json() # user1 maintains 4 packages; assert that we got them all. @@ -564,73 +597,80 @@ def test_rpc_msearch(): assert names == expected_results # Search for a non-existent maintainer, giving us zero packages. - response = make_request("/rpc?v=5&type=msearch&arg=blah-blah") + response = request.get("/rpc?v=5&type=msearch&arg=blah-blah") data = response.json() assert data.get("resultcount") == 0 # A missing arg still succeeds, but it returns all orphans. # Just verify that we receive no error and the orphaned result. - response = make_request("/rpc?v=5&type=msearch") + response = request.get("/rpc?v=5&type=msearch") data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] assert result.get("Name") == "woogly-chungus" -def test_rpc_search_depends(): - response = make_request( - "/rpc?v=5&type=search&by=depends&arg=chungus-depends") +def test_rpc_search_depends(client: TestClient): + with client as request: + response = request.get( + "/rpc?v=5&type=search&by=depends&arg=chungus-depends") data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] assert result.get("Name") == "big-chungus" -def test_rpc_search_makedepends(): - response = make_request( - "/rpc?v=5&type=search&by=makedepends&arg=chungus-makedepends") +def test_rpc_search_makedepends(client: TestClient): + with client as request: + response = request.get( + "/rpc?v=5&type=search&by=makedepends&arg=chungus-makedepends") data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] assert result.get("Name") == "big-chungus" -def test_rpc_search_optdepends(): - response = make_request( - "/rpc?v=5&type=search&by=optdepends&arg=chungus-optdepends") +def test_rpc_search_optdepends(client: TestClient): + with client as request: + response = request.get( + "/rpc?v=5&type=search&by=optdepends&arg=chungus-optdepends") data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] assert result.get("Name") == "big-chungus" -def test_rpc_search_checkdepends(): - response = make_request( - "/rpc?v=5&type=search&by=checkdepends&arg=chungus-checkdepends") +def test_rpc_search_checkdepends(client: TestClient): + with client as request: + response = request.get( + "/rpc?v=5&type=search&by=checkdepends&arg=chungus-checkdepends") data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] assert result.get("Name") == "big-chungus" -def test_rpc_incorrect_by(): - response = make_request("/rpc?v=5&type=search&by=fake&arg=big") +def test_rpc_incorrect_by(client: TestClient): + with client as request: + response = request.get("/rpc?v=5&type=search&by=fake&arg=big") assert response.json().get("error") == "Incorrect by field specified." -def test_rpc_jsonp_callback(): +def test_rpc_jsonp_callback(client: TestClient): """ Test the callback parameter. For end-to-end verification, the `examples/jsonp.html` file can be used to submit jsonp callback requests to the RPC. """ - response = make_request( - "/rpc?v=5&type=search&arg=big&callback=jsonCallback") + with client as request: + response = request.get( + "/rpc?v=5&type=search&arg=big&callback=jsonCallback") assert response.headers.get("content-type") == "text/javascript" assert re.search(r'^/\*\*/jsonCallback\(.*\)$', response.text) is not None # Test an invalid callback name; we get an application/json error. - response = make_request( - "/rpc?v=5&type=search&arg=big&callback=jsonCallback!") + with client as request: + response = request.get( + "/rpc?v=5&type=search&arg=big&callback=jsonCallback!") assert response.headers.get("content-type") == "application/json" assert response.json().get("error") == "Invalid callback name." From 94972841d6c6330503cdf33d53336c1bd47f9469 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 04:36:39 -0800 Subject: [PATCH 1122/1891] change(fastapi): decouple error logic from process_account_form Signed-off-by: Kevin Morris --- aurweb/exceptions.py | 9 ++ aurweb/routers/accounts.py | 209 ++++++++--------------------------- aurweb/users/validate.py | 204 ++++++++++++++++++++++++++++++++++ test/test_accounts_routes.py | 25 ++++- 4 files changed, 278 insertions(+), 169 deletions(-) create mode 100644 aurweb/users/validate.py diff --git a/aurweb/exceptions.py b/aurweb/exceptions.py index 82628b0a..31212676 100644 --- a/aurweb/exceptions.py +++ b/aurweb/exceptions.py @@ -1,3 +1,6 @@ +from typing import Any + + class AurwebException(Exception): pass @@ -77,3 +80,9 @@ class InvalidArgumentsException(AurwebException): class RPCError(AurwebException): pass + + +class ValidationError(AurwebException): + def __init__(self, data: Any, *args, **kwargs): + super().__init__(*args, **kwargs) + self.data = data diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index aca322b5..47483acc 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -6,20 +6,20 @@ from http import HTTPStatus from fastapi import APIRouter, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse -from sqlalchemy import and_, func, or_ +from sqlalchemy import and_, or_ import aurweb.config -from aurweb import cookies, db, l10n, logging, models, time, util +from aurweb import cookies, db, l10n, logging, models, util from aurweb.auth import account_type_required, auth_required -from aurweb.captcha import get_captcha_answer, get_captcha_salts, get_captcha_token +from aurweb.captcha import get_captcha_salts +from aurweb.exceptions import ValidationError from aurweb.l10n import get_translator_for_request -from aurweb.models import account_type -from aurweb.models.account_type import (DEVELOPER, DEVELOPER_ID, TRUSTED_USER, TRUSTED_USER_AND_DEV, TRUSTED_USER_AND_DEV_ID, - TRUSTED_USER_ID, USER_ID) +from aurweb.models import account_type as at from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.scripts.notify import ResetKeyNotification, WelcomeNotification from aurweb.templates import make_context, make_variable_context, render_template +from aurweb.users import validate from aurweb.users.util import get_user_by_name router = APIRouter() @@ -126,146 +126,31 @@ def process_account_form(request: Request, user: models.User, args: dict): # Get a local translator. _ = get_translator_for_request(request) - host = request.client.host - ban = db.query(models.Ban, models.Ban.IPAddress == host).first() - if ban: - return (False, [ - "Account registration has been disabled for your " - "IP address, probably due to sustained spam attacks. " - "Sorry for the inconvenience." - ]) + checks = [ + validate.is_banned, + validate.invalid_user_password, + validate.invalid_fields, + validate.invalid_suspend_permission, + validate.invalid_username, + validate.invalid_password, + validate.invalid_email, + validate.invalid_backup_email, + validate.invalid_homepage, + validate.invalid_pgp_key, + validate.invalid_ssh_pubkey, + validate.invalid_language, + validate.invalid_timezone, + validate.username_in_use, + validate.email_in_use, + validate.invalid_account_type, + validate.invalid_captcha + ] - if request.user.is_authenticated(): - if not request.user.valid_password(args.get("passwd", None)): - return (False, ["Invalid password."]) - - email = args.get("E", None) - username = args.get("U", None) - - if not email or not username: - return (False, ["Missing a required field."]) - - inactive = args.get("J", False) - if not request.user.is_elevated() and inactive != bool(user.InactivityTS): - return (False, ["You do not have permission to suspend accounts."]) - - username_min_len = aurweb.config.getint("options", "username_min_len") - username_max_len = aurweb.config.getint("options", "username_max_len") - if not util.valid_username(args.get("U")): - return (False, [ - "The username is invalid.", - [ - _("It must be between %s and %s characters long") % ( - username_min_len, username_max_len), - "Start and end with a letter or number", - "Can contain only one period, underscore or hyphen.", - ] - ]) - - password = args.get("P", None) - if password: - confirmation = args.get("C", None) - if not util.valid_password(password): - return (False, [ - _("Your password must be at least %s characters.") % ( - username_min_len) - ]) - elif not confirmation: - return (False, ["Please confirm your new password."]) - elif password != confirmation: - return (False, ["Password fields do not match."]) - - backup_email = args.get("BE", None) - homepage = args.get("HP", None) - pgp_key = args.get("K", None) - ssh_pubkey = args.get("PK", None) - language = args.get("L", None) - timezone = args.get("TZ", None) - - def username_exists(username): - return and_(models.User.ID != user.ID, - func.lower(models.User.Username) == username.lower()) - - def email_exists(email): - return and_(models.User.ID != user.ID, - func.lower(models.User.Email) == email.lower()) - - if not util.valid_email(email): - return (False, ["The email address is invalid."]) - elif backup_email and not util.valid_email(backup_email): - return (False, ["The backup email address is invalid."]) - elif homepage and not util.valid_homepage(homepage): - return (False, [ - "The home page is invalid, please specify the full HTTP(s) URL."]) - elif pgp_key and not util.valid_pgp_fingerprint(pgp_key): - return (False, ["The PGP key fingerprint is invalid."]) - elif ssh_pubkey and not util.valid_ssh_pubkey(ssh_pubkey): - return (False, ["The SSH public key is invalid."]) - elif language and language not in l10n.SUPPORTED_LANGUAGES: - return (False, ["Language is not currently supported."]) - elif timezone and timezone not in time.SUPPORTED_TIMEZONES: - return (False, ["Timezone is not currently supported."]) - elif db.query(models.User, username_exists(username)).first(): - # If the username already exists... - return (False, [ - _("The username, %s%s%s, is already in use.") % ( - "", username, "") - ]) - elif db.query(models.User, email_exists(email)).first(): - # If the email already exists... - return (False, [ - _("The address, %s%s%s, is already in use.") % ( - "", email, "") - ]) - - def ssh_fingerprint_exists(fingerprint): - return and_(models.SSHPubKey.UserID != user.ID, - models.SSHPubKey.Fingerprint == fingerprint) - - if ssh_pubkey: - fingerprint = get_fingerprint(ssh_pubkey.strip().rstrip()) - if fingerprint is None: - return (False, ["The SSH public key is invalid."]) - - if db.query(models.SSHPubKey, - ssh_fingerprint_exists(fingerprint)).first(): - return (False, [ - _("The SSH public key, %s%s%s, is already in use.") % ( - "", fingerprint, "") - ]) - - T = int(args.get("T", user.AccountTypeID)) - if T != user.AccountTypeID: - if T not in account_type.ACCOUNT_TYPE_NAME: - return (False, - ["Invalid account type provided."]) - elif not request.user.is_elevated(): - return (False, - ["You do not have permission to change account types."]) - - credential_checks = { - DEVELOPER_ID: request.user.is_developer, - TRUSTED_USER_AND_DEV_ID: request.user.is_developer, - TRUSTED_USER_ID: request.user.is_elevated, - USER_ID: request.user.is_elevated - } - credential_check = credential_checks.get(T) - - if not credential_check(): - name = account_type.ACCOUNT_TYPE_NAME.get(T) - error = _("You do not have permission to change " - "this user's account type to %s.") % name - return (False, [error]) - - captcha_salt = args.get("captcha_salt", None) - if captcha_salt and captcha_salt not in get_captcha_salts(): - return (False, ["This CAPTCHA has expired. Please try again."]) - - captcha = args.get("captcha", None) - if captcha: - answer = get_captcha_answer(get_captcha_token(captcha_salt)) - if captcha != answer: - return (False, ["The entered CAPTCHA answer is invalid."]) + try: + for check in checks: + check(**args, request=request, user=user, _=_) + except ValidationError as exc: + return (False, exc.data) return (True, []) @@ -286,16 +171,16 @@ def make_account_form_context(context: dict, context = copy.copy(context) context["account_types"] = [ - (USER_ID, "Normal User"), - (TRUSTED_USER_ID, TRUSTED_USER) + (at.USER_ID, "Normal User"), + (at.TRUSTED_USER_ID, at.TRUSTED_USER) ] user_account_type_id = context.get("account_types")[0][0] if request.user.has_credential("CRED_ACCOUNT_EDIT_DEV"): - context["account_types"].append((DEVELOPER_ID, DEVELOPER)) - context["account_types"].append((TRUSTED_USER_AND_DEV_ID, - TRUSTED_USER_AND_DEV)) + context["account_types"].append((at.DEVELOPER_ID, at.DEVELOPER)) + context["account_types"].append((at.TRUSTED_USER_AND_DEV_ID, + at.TRUSTED_USER_AND_DEV)) if request.user.is_authenticated(): context["username"] = args.get("U", user.Username) @@ -389,12 +274,10 @@ async def account_register_post(request: Request, captcha: str = Form(default=None), captcha_salt: str = Form(...)): context = await make_variable_context(request, "Register") - args = dict(await request.form()) + context = make_account_form_context(context, request, None, args) - ok, errors = process_account_form(request, request.user, args) - if not ok: # If the field values given do not meet the requirements, # return HTTP 400 with an error. @@ -636,9 +519,9 @@ async def account_comments(request: Request, username: str): @router.get("/accounts") @auth_required(True, redirect="/accounts") -@account_type_required({account_type.TRUSTED_USER, - account_type.DEVELOPER, - account_type.TRUSTED_USER_AND_DEV}) +@account_type_required({at.TRUSTED_USER, + at.DEVELOPER, + at.TRUSTED_USER_AND_DEV}) async def accounts(request: Request): context = make_context(request, "Accounts") return render_template(request, "account/search.html", context) @@ -646,9 +529,9 @@ async def accounts(request: Request): @router.post("/accounts") @auth_required(True, redirect="/accounts") -@account_type_required({account_type.TRUSTED_USER, - account_type.DEVELOPER, - account_type.TRUSTED_USER_AND_DEV}) +@account_type_required({at.TRUSTED_USER, + at.DEVELOPER, + at.TRUSTED_USER_AND_DEV}) async def accounts_post(request: Request, O: int = Form(default=0), # Offset SB: str = Form(default=str()), # Sort By @@ -680,10 +563,10 @@ async def accounts_post(request: Request, # Convert parameter T to an AccountType ID. account_types = { - "u": account_type.USER_ID, - "t": account_type.TRUSTED_USER_ID, - "d": account_type.DEVELOPER_ID, - "td": account_type.TRUSTED_USER_AND_DEV_ID + "u": at.USER_ID, + "t": at.TRUSTED_USER_ID, + "d": at.DEVELOPER_ID, + "td": at.TRUSTED_USER_AND_DEV_ID } account_type_id = account_types.get(T, None) diff --git a/aurweb/users/validate.py b/aurweb/users/validate.py new file mode 100644 index 00000000..4959e316 --- /dev/null +++ b/aurweb/users/validate.py @@ -0,0 +1,204 @@ +""" +Validation functions for account registration and edit fields. +Each of these functions extracts a subset of keyword arguments +out of form data from /account/register or /account/{username}/edit. + +All functions in this module raise aurweb.exceptions.ValidationError +when encountering invalid criteria and return silently otherwise. +""" +from typing import List, Optional, Tuple + +from fastapi import Request +from sqlalchemy import and_ + +from aurweb import config, db, l10n, models, time, util +from aurweb.captcha import get_captcha_answer, get_captcha_salts, get_captcha_token +from aurweb.exceptions import ValidationError +from aurweb.models import account_type as at +from aurweb.models.account_type import ACCOUNT_TYPE_NAME +from aurweb.models.ssh_pub_key import get_fingerprint + + +def invalid_fields(E: str = str(), U: str = str(), **kwargs) \ + -> Optional[Tuple[bool, List[str]]]: + if not E or not U: + raise ValidationError(["Missing a required field."]) + + +def invalid_suspend_permission(request: Request = None, + user: models.User = None, + J: bool = False, + **kwargs) \ + -> Optional[Tuple[bool, List[str]]]: + if not request.user.is_elevated() and J != bool(user.InactivityTS): + raise ValidationError([ + "You do not have permission to suspend accounts."]) + + +def invalid_username(request: Request = None, U: str = str(), _=None, + **kwargs): + if not util.valid_username(U): + username_min_len = config.getint("options", "username_min_len") + username_max_len = config.getint("options", "username_max_len") + raise ValidationError([ + "The username is invalid.", + [ + _("It must be between %s and %s characters long") % ( + username_min_len, username_max_len), + "Start and end with a letter or number", + "Can contain only one period, underscore or hyphen.", + ] + ]) + + +def invalid_password(P: str = str(), C: str = str(), + _: l10n.Translator = None, **kwargs) -> None: + if P: + if not util.valid_password(P): + username_min_len = config.getint( + "options", "username_min_len") + raise ValidationError([ + _("Your password must be at least %s characters.") % ( + username_min_len) + ]) + elif not C: + raise ValidationError(["Please confirm your new password."]) + elif P != C: + raise ValidationError(["Password fields do not match."]) + + +def is_banned(request: Request = None, **kwargs) -> None: + host = request.client.host + exists = db.query(models.Ban, models.Ban.IPAddress == host).exists() + if db.query(exists).scalar(): + raise ValidationError([ + "Account registration has been disabled for your " + "IP address, probably due to sustained spam attacks. " + "Sorry for the inconvenience." + ]) + + +def invalid_user_password(request: Request = None, passwd: str = str(), + **kwargs) -> None: + if request.user.is_authenticated(): + if not request.user.valid_password(passwd): + raise ValidationError(["Invalid password."]) + + +def invalid_email(E: str = str(), **kwargs) -> None: + if not util.valid_email(E): + raise ValidationError(["The email address is invalid."]) + + +def invalid_backup_email(BE: str = str(), **kwargs) -> None: + if BE and not util.valid_email(BE): + raise ValidationError(["The backup email address is invalid."]) + + +def invalid_homepage(HP: str = str(), **kwargs) -> None: + if HP and not util.valid_homepage(HP): + raise ValidationError([ + "The home page is invalid, please specify the full HTTP(s) URL."]) + + +def invalid_pgp_key(K: str = str(), **kwargs) -> None: + if K and not util.valid_pgp_fingerprint(K): + raise ValidationError(["The PGP key fingerprint is invalid."]) + + +def invalid_ssh_pubkey(PK: str = str(), user: models.User = None, + _: l10n.Translator = None, **kwargs) -> None: + if PK: + invalid_exc = ValidationError(["The SSH public key is invalid."]) + if not util.valid_ssh_pubkey(PK): + raise invalid_exc + + fingerprint = get_fingerprint(PK.strip().rstrip()) + if not fingerprint: + raise invalid_exc + + exists = db.query(models.SSHPubKey).filter( + and_(models.SSHPubKey.UserID != user.ID, + models.SSHPubKey.Fingerprint == fingerprint) + ).exists() + if db.query(exists).scalar(): + raise ValidationError([ + _("The SSH public key, %s%s%s, is already in use.") % ( + "", fingerprint, "") + ]) + + +def invalid_language(L: str = str(), **kwargs) -> None: + if L and L not in l10n.SUPPORTED_LANGUAGES: + raise ValidationError(["Language is not currently supported."]) + + +def invalid_timezone(TZ: str = str(), **kwargs) -> None: + if TZ and TZ not in time.SUPPORTED_TIMEZONES: + raise ValidationError(["Timezone is not currently supported."]) + + +def username_in_use(U: str = str(), user: models.User = None, + _: l10n.Translator = None, **kwargs) -> None: + exists = db.query(models.User).filter( + and_(models.User.ID != user.ID, + models.User.Username == U) + ).exists() + if db.query(exists).scalar(): + # If the username already exists... + raise ValidationError([ + _("The username, %s%s%s, is already in use.") % ( + "", U, "") + ]) + + +def email_in_use(E: str = str(), user: models.User = None, + _: l10n.Translator = None, **kwargs) -> None: + exists = db.query(models.User).filter( + and_(models.User.ID != user.ID, + models.User.Email == E) + ).exists() + if db.query(exists).scalar(): + # If the email already exists... + raise ValidationError([ + _("The address, %s%s%s, is already in use.") % ( + "", E, "") + ]) + + +def invalid_account_type(T: int = None, request: Request = None, + user: models.User = None, + _: l10n.Translator = None, + **kwargs) -> None: + if T is not None and (T := int(T)) != user.AccountTypeID: + if T not in ACCOUNT_TYPE_NAME: + raise ValidationError(["Invalid account type provided."]) + elif not request.user.is_elevated(): + raise ValidationError([ + "You do not have permission to change account types."]) + + credential_checks = { + at.USER_ID: request.user.is_trusted_user, + at.TRUSTED_USER_ID: request.user.is_trusted_user, + at.DEVELOPER_ID: lambda: request.user.is_developer(), + at.TRUSTED_USER_AND_DEV_ID: (lambda: request.user.is_trusted_user() + and request.user.is_developer()) + } + credential_check = credential_checks.get(T) + + if not credential_check(): + name = ACCOUNT_TYPE_NAME.get(T) + error = _("You do not have permission to change " + "this user's account type to %s.") % name + raise ValidationError([error]) + + +def invalid_captcha(captcha_salt: str = None, captcha: str = None, **kwargs) \ + -> None: + if captcha_salt and captcha_salt not in get_captcha_salts(): + raise ValidationError(["This CAPTCHA has expired. Please try again."]) + + if captcha: + answer = get_captcha_answer(get_captcha_token(captcha_salt)) + if captcha != answer: + raise ValidationError(["The entered CAPTCHA answer is invalid."]) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index e828f70f..be929e97 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -1035,12 +1035,25 @@ def test_post_account_edit_account_types(): # Make sure it got changed to USER_ID as we intended. assert user.AccountTypeID == USER_ID - # Change user to a Developer. + # Change user to a TU & Dev, which can change themselves to a Developer. with db.begin(): - user.AccountTypeID = DEVELOPER_ID + user.AccountTypeID = TRUSTED_USER_AND_DEV_ID - # As a developer, we can absolutely change all account types. - # For example, from DEVELOPER_ID to TRUSTED_USER_AND_DEV_ID: + # As a TU & Dev, we can absolutely change all account types. + # For example, from TRUSTED_USER_AND_DEV_ID to DEVELOPER_ID: + post_data = { + "U": user.Username, + "E": user.Email, + "T": DEVELOPER_ID, + "passwd": "testPassword" + } + with client as request: + resp = request.post(endpoint, data=post_data, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + assert user.AccountTypeID == DEVELOPER_ID + + # But we can't change a user to a Trusted User & Developer when + # we're just a Developer. post_data = { "U": user.Username, "E": user.Email, @@ -1049,8 +1062,8 @@ def test_post_account_edit_account_types(): } with client as request: resp = request.post(endpoint, data=post_data, cookies=cookies) - assert resp.status_code == int(HTTPStatus.OK) - assert user.AccountTypeID == TRUSTED_USER_AND_DEV_ID + assert resp.status_code == int(HTTPStatus.BAD_REQUEST) + assert user.AccountTypeID == DEVELOPER_ID def test_get_account(): From 303585cdbf50ffa70c7bc6f579c17d5e6bc08a42 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 05:40:11 -0800 Subject: [PATCH 1123/1891] change(fastapi): decouple update logic from account edit Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 85 ++++------------------------ aurweb/users/update.py | 110 +++++++++++++++++++++++++++++++++++++ aurweb/util.py | 7 +++ 3 files changed, 128 insertions(+), 74 deletions(-) create mode 100644 aurweb/users/update.py diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 47483acc..02a7f4c6 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -1,7 +1,6 @@ import copy import typing -from datetime import datetime from http import HTTPStatus from fastapi import APIRouter, Form, Request @@ -19,7 +18,7 @@ from aurweb.models import account_type as at from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.scripts.notify import ResetKeyNotification, WelcomeNotification from aurweb.templates import make_context, make_variable_context, render_template -from aurweb.users import validate +from aurweb.users import update, validate from aurweb.users.util import get_user_by_name router = APIRouter() @@ -405,79 +404,17 @@ async def account_edit_post(request: Request, return render_template(request, "account/edit.html", context, status_code=HTTPStatus.BAD_REQUEST) - # Set all updated fields as needed. - with db.begin(): - user.Username = U or user.Username - user.Email = E or user.Email - user.HideEmail = bool(H) - user.BackupEmail = BE or user.BackupEmail - user.RealName = R or user.RealName - user.Homepage = HP or user.Homepage - user.IRCNick = I or user.IRCNick - user.PGPKey = K or user.PGPKey - user.Suspended = J - user.InactivityTS = int(datetime.utcnow().timestamp()) * int(J) + updates = [ + update.simple, + update.language, + update.timezone, + update.ssh_pubkey, + update.account_type, + update.password + ] - # If we update the language, update the cookie as well. - if L and L != user.LangPreference: - request.cookies["AURLANG"] = L - with db.begin(): - user.LangPreference = L - context["language"] = L - - # If we update the timezone, also update the cookie. - if TZ and TZ != user.Timezone: - with db.begin(): - user.Timezone = TZ - request.cookies["AURTZ"] = TZ - context["timezone"] = TZ - - with db.begin(): - user.CommentNotify = bool(CN) - user.UpdateNotify = bool(UN) - user.OwnershipNotify = bool(ON) - - # If a PK is given, compare it against the target user's PK. - with db.begin(): - if PK: - # Get the second token in the public key, which is the actual key. - pubkey = PK.strip().rstrip() - parts = pubkey.split(" ") - if len(parts) == 3: - # Remove the host part. - pubkey = parts[0] + " " + parts[1] - fingerprint = get_fingerprint(pubkey) - if not user.ssh_pub_key: - # No public key exists, create one. - user.ssh_pub_key = models.SSHPubKey(UserID=user.ID, - PubKey=pubkey, - Fingerprint=fingerprint) - elif user.ssh_pub_key.PubKey != pubkey: - # A public key already exists, update it. - user.ssh_pub_key.PubKey = pubkey - user.ssh_pub_key.Fingerprint = fingerprint - elif user.ssh_pub_key: - # Else, if the user has a public key already, delete it. - db.delete(user.ssh_pub_key) - - if T and T != user.AccountTypeID: - with db.begin(): - user.AccountTypeID = T - - if P and not user.valid_password(P): - # Remove the fields we consumed for passwords. - context["P"] = context["C"] = str() - - # If a password was given and it doesn't match the user's, update it. - with db.begin(): - user.update_password(P) - - if user == request.user: - remember_me = request.cookies.get("AURREMEMBER", False) - - # If the target user is the request user, login with - # the updated password to update the Session record. - user.login(request, P, cookies.timeout(remember_me)) + for f in updates: + f(**args, request=request, user=user, context=context) if not errors: context["complete"] = True diff --git a/aurweb/users/update.py b/aurweb/users/update.py new file mode 100644 index 00000000..60a6184e --- /dev/null +++ b/aurweb/users/update.py @@ -0,0 +1,110 @@ +from datetime import datetime +from typing import Any, Dict + +from fastapi import Request + +from aurweb import cookies, db, models +from aurweb.models.ssh_pub_key import get_fingerprint +from aurweb.util import strtobool + + +def simple(U: str = str(), E: str = str(), H: bool = False, + BE: str = str(), R: str = str(), HP: str = str(), + I: str = str(), K: str = str(), J: bool = False, + CN: bool = False, UN: bool = False, ON: bool = False, + user: models.User = None, + **kwargs) -> None: + now = int(datetime.utcnow().timestamp()) + with db.begin(): + user.Username = U or user.Username + user.Email = E or user.Email + user.HideEmail = strtobool(H) + user.BackupEmail = BE or user.BackupEmail + user.RealName = R or user.RealName + user.Homepage = HP or user.Homepage + user.IRCNick = I or user.IRCNick + user.PGPKey = K or user.PGPKey + user.Suspended = strtobool(J) + user.InactivityTS = now * int(strtobool(J)) + user.CommentNotify = strtobool(CN) + user.UpdateNotify = strtobool(UN) + user.OwnershipNotify = strtobool(ON) + + +def language(L: str = str(), + request: Request = None, + user: models.User = None, + context: Dict[str, Any] = {}, + **kwargs) -> None: + if L and L != user.LangPreference: + with db.begin(): + user.LangPreference = L + context["language"] = L + + +def timezone(TZ: str = str(), + request: Request = None, + user: models.User = None, + context: Dict[str, Any] = {}, + **kwargs) -> None: + if TZ and TZ != user.Timezone: + with db.begin(): + user.Timezone = TZ + context["language"] = TZ + + +def ssh_pubkey(PK: str = str(), + user: models.User = None, + **kwargs) -> None: + # If a PK is given, compare it against the target user's PK. + if PK: + # Get the second token in the public key, which is the actual key. + pubkey = PK.strip().rstrip() + parts = pubkey.split(" ") + if len(parts) == 3: + # Remove the host part. + pubkey = parts[0] + " " + parts[1] + fingerprint = get_fingerprint(pubkey) + if not user.ssh_pub_key: + # No public key exists, create one. + with db.begin(): + db.create(models.SSHPubKey, UserID=user.ID, + PubKey=pubkey, Fingerprint=fingerprint) + elif user.ssh_pub_key.PubKey != pubkey: + # A public key already exists, update it. + with db.begin(): + user.ssh_pub_key.PubKey = pubkey + user.ssh_pub_key.Fingerprint = fingerprint + elif user.ssh_pub_key: + # Else, if the user has a public key already, delete it. + with db.begin(): + db.delete(user.ssh_pub_key) + + +def account_type(T: int = None, + user: models.User = None, + **kwargs) -> None: + if T is not None and (T := int(T)) != user.AccountTypeID: + with db.begin(): + user.AccountTypeID = T + + +def password(P: str = str(), + request: Request = None, + user: models.User = None, + context: Dict[str, Any] = {}, + **kwargs) -> None: + if P and not user.valid_password(P): + # Remove the fields we consumed for passwords. + context["P"] = context["C"] = str() + + # If a password was given and it doesn't match the user's, update it. + with db.begin(): + user.update_password(P) + + if user == request.user: + remember_me = request.cookies.get("AURREMEMBER", False) + + # If the target user is the request user, login with + # the updated password to update the Session record. + user.login(request, P, cookies.timeout(remember_me)) diff --git a/aurweb/util.py b/aurweb/util.py index 1c2042fa..b95fc6a3 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -7,6 +7,7 @@ import secrets import string from datetime import datetime +from distutils.util import strtobool as _strtobool from typing import Any, Callable, Dict, Iterable, Tuple from urllib.parse import urlencode, urlparse from zoneinfo import ZoneInfo @@ -170,3 +171,9 @@ def sanitize_params(offset: str, per_page: str) -> Tuple[int, int]: per_page = defaults.PP return (offset, per_page) + + +def strtobool(value: str) -> bool: + if isinstance(value, str): + return _strtobool(value) + return value From 2892d21ff173af8f484274b1b175447be2ae4bab Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 05:47:22 -0800 Subject: [PATCH 1124/1891] remove global aurweb.models flake8 F401 ignore Signed-off-by: Kevin Morris --- aurweb/models/__init__.py | 60 +++++++++++++++++++-------------------- setup.cfg | 1 - 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/aurweb/models/__init__.py b/aurweb/models/__init__.py index b430acd2..a06077ad 100644 --- a/aurweb/models/__init__.py +++ b/aurweb/models/__init__.py @@ -1,31 +1,31 @@ """ Collection of all aurweb SQLAlchemy declarative models. """ -from .accepted_term import AcceptedTerm -from .account_type import AccountType -from .api_rate_limit import ApiRateLimit -from .ban import Ban -from .dependency_type import DependencyType -from .group import Group -from .license import License -from .official_provider import OfficialProvider -from .package import Package -from .package_base import PackageBase -from .package_blacklist import PackageBlacklist -from .package_comaintainer import PackageComaintainer -from .package_comment import PackageComment -from .package_dependency import PackageDependency -from .package_group import PackageGroup -from .package_keyword import PackageKeyword -from .package_license import PackageLicense -from .package_notification import PackageNotification -from .package_relation import PackageRelation -from .package_request import PackageRequest -from .package_source import PackageSource -from .package_vote import PackageVote -from .relation_type import RelationType -from .request_type import RequestType -from .session import Session -from .ssh_pub_key import SSHPubKey -from .term import Term -from .tu_vote import TUVote -from .tu_voteinfo import TUVoteInfo -from .user import User +from .accepted_term import AcceptedTerm # noqa: F401 +from .account_type import AccountType # noqa: F401 +from .api_rate_limit import ApiRateLimit # noqa: F401 +from .ban import Ban # noqa: F401 +from .dependency_type import DependencyType # noqa: F401 +from .group import Group # noqa: F401 +from .license import License # noqa: F401 +from .official_provider import OfficialProvider # noqa: F401 +from .package import Package # noqa: F401 +from .package_base import PackageBase # noqa: F401 +from .package_blacklist import PackageBlacklist # noqa: F401 +from .package_comaintainer import PackageComaintainer # noqa: F401 +from .package_comment import PackageComment # noqa: F401 +from .package_dependency import PackageDependency # noqa: F401 +from .package_group import PackageGroup # noqa: F401 +from .package_keyword import PackageKeyword # noqa: F401 +from .package_license import PackageLicense # noqa: F401 +from .package_notification import PackageNotification # noqa: F401 +from .package_relation import PackageRelation # noqa: F401 +from .package_request import PackageRequest # noqa: F401 +from .package_source import PackageSource # noqa: F401 +from .package_vote import PackageVote # noqa: F401 +from .relation_type import RelationType # noqa: F401 +from .request_type import RequestType # noqa: F401 +from .session import Session # noqa: F401 +from .ssh_pub_key import SSHPubKey # noqa: F401 +from .term import Term # noqa: F401 +from .tu_vote import TUVote # noqa: F401 +from .tu_voteinfo import TUVoteInfo # noqa: F401 +from .user import User # noqa: F401 diff --git a/setup.cfg b/setup.cfg index 7c64a01f..cec1bcf5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,6 @@ per-file-ignores = aurweb/routers/accounts.py:C901 test/test_ssh_pub_key.py:E501 aurweb/routers/packages.py:E741 - aurweb/models/__init__.py:F401 [isort] line_length = 127 From 2df7187514a64d0e0ff88130562a9fc95c0f6611 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 05:48:43 -0800 Subject: [PATCH 1125/1891] fix global test_ssh_pub_key E501 flake8 violation Signed-off-by: Kevin Morris --- setup.cfg | 1 - test/test_ssh_pub_key.py | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index cec1bcf5..997bf4b7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,7 +30,6 @@ ignore = E741, W503, W504 # per-file-ignores = aurweb/routers/accounts.py:C901 - test/test_ssh_pub_key.py:E501 aurweb/routers/packages.py:E741 [isort] diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py index bb787759..e17af5a7 100644 --- a/test/test_ssh_pub_key.py +++ b/test/test_ssh_pub_key.py @@ -6,7 +6,14 @@ from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint from aurweb.models.user import User TEST_SSH_PUBKEY = """ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCycoCi5yGCvSclH2wmNBUuwsYEzRZZBJaQquRc4ysl+Tg+/jiDkR3Zn9fIznC4KnFoyrIHzkKuePZ3bNDYwkZxkJKoWBCh4hXKDXSm87FMN0+VDC+1QxF/z0XaAGr/P6f4XukabyddypBdnHcZiplbw+YOSqcAE2TCqOlSXwNMOcF9U89UsR/Q9i9I52hlvU0q8+fZVGhou1KCowFSnHYtrr5KYJ04CXkJ13DkVf3+pjQWyrByvBcf1hGEaczlgfobrrv/y96jDhgfXucxliNKLdufDPPkii3LhhsNcDmmI1VZ3v0irKvd9WZuauqloobY84zEFcDTyjn0hxGjVeYFejm4fBnvjga0yZXORuWksdNfXWLDxFk6MDDd1jF0ExRbP+OxDuU4IVyIuDL7S3cnbf2YjGhkms/8voYT2OBE7FwNlfv98Kr0NUp51zpf55Arxn9j0Rz9xTA7FiODQgCn6iQ0SDtzUNL0IKTCw26xJY5gzMxbfpvzPQGeulx/ioM= kevr@volcano +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCycoCi5yGCvSclH2wmNBUuwsYEzRZZBJaQquRc4y\ +sl+Tg+/jiDkR3Zn9fIznC4KnFoyrIHzkKuePZ3bNDYwkZxkJKoWBCh4hXKDXSm87FMN0+VDC+1QxF/\ +z0XaAGr/P6f4XukabyddypBdnHcZiplbw+YOSqcAE2TCqOlSXwNMOcF9U89UsR/Q9i9I52hlvU0q8+\ +fZVGhou1KCowFSnHYtrr5KYJ04CXkJ13DkVf3+pjQWyrByvBcf1hGEaczlgfobrrv/y96jDhgfXucx\ +liNKLdufDPPkii3LhhsNcDmmI1VZ3v0irKvd9WZuauqloobY84zEFcDTyjn0hxGjVeYFejm4fBnvjg\ +a0yZXORuWksdNfXWLDxFk6MDDd1jF0ExRbP+OxDuU4IVyIuDL7S3cnbf2YjGhkms/8voYT2OBE7FwN\ +lfv98Kr0NUp51zpf55Arxn9j0Rz9xTA7FiODQgCn6iQ0SDtzUNL0IKTCw26xJY5gzMxbfpvzPQGeul\ +x/ioM= kevr@volcano """ user = ssh_pub_key = None From 672af707ad34a014b1119a9104db4050b706678b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 05:49:08 -0800 Subject: [PATCH 1126/1891] remove C901 and E741 per-file-ignores exclusion We no longer have C901 violations and we're already ignoring E741 (short variable names) in the overall `ignore` option. Signed-off-by: Kevin Morris --- setup.cfg | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/setup.cfg b/setup.cfg index 997bf4b7..08be9186 100644 --- a/setup.cfg +++ b/setup.cfg @@ -19,19 +19,6 @@ max-complexity = 10 # do this, so we're ignoring it here. ignore = E741, W503, W504 -# aurweb/routers/accounts.py -# Ignore over-reaching complexity. -# TODO: This should actually be addressed so we do not ignore C901. -# -# test/test_ssh_pub_key.py -# E501 is detected due to our >127 width test constant. Ignore it. -# Due to this, line width should _always_ be looked at in code reviews. -# Anything like this should be questioned. -# -per-file-ignores = - aurweb/routers/accounts.py:C901 - aurweb/routers/packages.py:E741 - [isort] line_length = 127 lines_between_types = 1 From dbe5cb4a33066c90333c32aab077081fec3ba426 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Nov 2021 16:42:26 -0800 Subject: [PATCH 1127/1891] fix(fastapi): only include comment-edit.js where needed Closes: #178 Signed-off-by: Kevin Morris --- templates/account/comments.html | 3 +++ templates/packages/show.html | 3 +++ templates/partials/head.html | 3 --- templates/pkgbase.html | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/templates/account/comments.html b/templates/account/comments.html index 95585180..8dff53e4 100644 --- a/templates/account/comments.html +++ b/templates/account/comments.html @@ -17,6 +17,9 @@
    + + + {% for comment in comments %} {% include "partials/account/comment.html" %} {% endfor %} diff --git a/templates/packages/show.html b/templates/packages/show.html index fbc9c0ea..25083020 100644 --- a/templates/packages/show.html +++ b/templates/packages/show.html @@ -15,6 +15,9 @@
    + + + {% set pkgname = package.Name %} {% set pkgbase_id = pkgbase.ID %} {% include "partials/packages/comments.html" %} diff --git a/templates/partials/head.html b/templates/partials/head.html index 21c79887..8bfde020 100644 --- a/templates/partials/head.html +++ b/templates/partials/head.html @@ -15,8 +15,5 @@ - - - AUR ({{ language }}) - {{ title | tr }} diff --git a/templates/pkgbase.html b/templates/pkgbase.html index 315cdf67..cdf23c35 100644 --- a/templates/pkgbase.html +++ b/templates/pkgbase.html @@ -14,6 +14,9 @@
    + + + {% set pkgname = result.Name %} {% set pkgbase_id = result.ID %} {% set comments = comments %} From 7739b2178ec01828666daf271e8451852af22d2e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Nov 2021 16:43:10 -0800 Subject: [PATCH 1128/1891] fix(fastapi): fix comment edit image sources These were using the old comment image sources. Slipped in due to cache and not checking without cache. Fixed them to use src="/static/images/...". Signed-off-by: Kevin Morris --- templates/partials/comment_actions.html | 10 +++++----- web/html/js/comment-edit.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/partials/comment_actions.html b/templates/partials/comment_actions.html index b21b90bd..b8ccf945 100644 --- a/templates/partials/comment_actions.html +++ b/templates/partials/comment_actions.html @@ -12,7 +12,7 @@ value="{{ request.url.path }}" /> - {{ 'Edit comment' | tr }} @@ -57,7 +57,7 @@ diff --git a/web/html/js/comment-edit.js b/web/html/js/comment-edit.js index 4898c8d4..23ffdd34 100644 --- a/web/html/js/comment-edit.js +++ b/web/html/js/comment-edit.js @@ -1,6 +1,6 @@ function add_busy_indicator(sibling) { const img = document.createElement('img'); - img.src = "/images/ajax-loader.gif"; + img.src = "/static/images/ajax-loader.gif"; img.classList.add('ajax-loader'); img.style.height = 11; img.style.width = 16; From a348cdaac3a36c53ed4e9355f977cf63c4052801 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Nov 2021 16:44:13 -0800 Subject: [PATCH 1129/1891] housekeep(fastapi): cleanup unneeded jinja set statement Signed-off-by: Kevin Morris --- templates/pkgbase.html | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/pkgbase.html b/templates/pkgbase.html index cdf23c35..05583494 100644 --- a/templates/pkgbase.html +++ b/templates/pkgbase.html @@ -19,6 +19,5 @@ {% set pkgname = result.Name %} {% set pkgbase_id = result.ID %} - {% set comments = comments %} {% include "partials/packages/comments.html" %} {% endblock %} From 7f981b9ed7d0ce90d23d4051d743accd0228b515 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Nov 2021 21:15:57 -0800 Subject: [PATCH 1130/1891] fix(fastapi): utilize auto_{orphan,deletion}_age Didn't get this in when the initial request port went down; here it is. Auto-accept orphan requests when the package has been out of date for longer than auto_orphan_age. Auto-accept deletion requests by the package's maintainer if the package has been uploaded within auto_deletion_age seconds ago. Signed-off-by: Kevin Morris --- aurweb/packages/validate.py | 34 +++++++++++++++++++ aurweb/routers/packages.py | 65 ++++++++++++++++++------------------ test/test_packages_routes.py | 43 +++++++++++++++++++++++- 3 files changed, 109 insertions(+), 33 deletions(-) create mode 100644 aurweb/packages/validate.py diff --git a/aurweb/packages/validate.py b/aurweb/packages/validate.py new file mode 100644 index 00000000..e730e98b --- /dev/null +++ b/aurweb/packages/validate.py @@ -0,0 +1,34 @@ +from typing import Any, Dict + +from aurweb import db, models +from aurweb.exceptions import ValidationError + + +def request(pkgbase: models.PackageBase, + type: str, comments: str, merge_into: str, + context: Dict[str, Any]) -> None: + if not comments: + raise ValidationError(["The comment field must not be empty."]) + + if type == "merge": + # Perform merge-related checks. + if not merge_into: + # TODO: This error needs to be translated. + raise ValidationError( + ['The "Merge into" field must not be empty.']) + + target = db.query(models.PackageBase).filter( + models.PackageBase.Name == merge_into + ).first() + if not target: + # TODO: This error needs to be translated. + raise ValidationError([ + "The package base you want to merge into does not exist." + ]) + + db.refresh(target) + if target.ID == pkgbase.ID: + # TODO: This error needs to be translated. + raise ValidationError([ + "You cannot merge a package base into itself." + ]) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index c8ceb275..dfb8e108 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -11,9 +11,11 @@ import aurweb.packages.util from aurweb import db, defaults, l10n, logging, models, util from aurweb.auth import auth_required +from aurweb.exceptions import ValidationError from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.models.request_type import DELETION_ID, MERGE, MERGE_ID +from aurweb.packages import validate from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, get_pkgreq_by_id, query_notified, query_voted from aurweb.scripts import notify, popupdate @@ -153,7 +155,7 @@ def delete_package(deleter: models.User, package: models.Package): with db.begin(): pkgreq = create_request_if_missing( requests, reqtype, deleter, package) - db.refresh(pkgreq) + pkgreq.Status = ACCEPTED_ID bases_to_delete.append(package.PackageBase) @@ -707,35 +709,13 @@ async def pkgbase_request_post(request: Request, name: str, return render_template(request, "pkgbase/request.html", context, status_code=HTTPStatus.BAD_REQUEST) - if not comments: - context["errors"] = ["The comment field must not be empty."] + try: + validate.request(pkgbase, type, comments, merge_into, context) + except ValidationError as exc: + logger.error(f"Request Validation Error: {str(exc.data)}") + context["errors"] = exc.data return render_template(request, "pkgbase/request.html", context) - if type == "merge": - # Perform merge-related checks. - if not merge_into: - # TODO: This error needs to be translated. - context["errors"] = ['The "Merge into" field must not be empty.'] - return render_template(request, "pkgbase/request.html", context) - - target = db.query(models.PackageBase).filter( - models.PackageBase.Name == merge_into - ).first() - if not target: - # TODO: This error needs to be translated. - context["errors"] = [ - "The package base you want to merge into does not exist." - ] - return render_template(request, "pkgbase/request.html", context) - - db.refresh(target) - if target.ID == pkgbase.ID: - # TODO: This error needs to be translated. - context["errors"] = [ - "You cannot merge a package base into itself." - ] - return render_template(request, "pkgbase/request.html", context) - # All good. Create a new PackageRequest based on the given type. now = int(datetime.utcnow().timestamp()) reqtype = db.query(models.RequestType).filter( @@ -748,16 +728,37 @@ async def pkgbase_request_post(request: Request, name: str, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, MergeBaseName=merge_into, - Comments=comments, ClosureComment=str()) + Comments=comments, + ClosureComment=str()) - # Prepare notification object. conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - notify_ = notify.RequestOpenNotification( + # Prepare notification object. + notif = notify.RequestOpenNotification( conn, request.user.ID, pkgreq.ID, reqtype.Name, pkgreq.PackageBase.ID, merge_into=merge_into or None) # Send the notification now that we're out of the DB scope. - notify_.send() + notif.send() + + auto_orphan_age = aurweb.config.getint("options", "auto_orphan_age") + auto_delete_age = aurweb.config.getint("options", "auto_delete_age") + + flagged = pkgbase.OutOfDateTS and pkgbase.OutOfDateTS >= auto_orphan_age + is_maintainer = pkgbase.Maintainer == request.user + outdated = now - pkgbase.SubmittedTS <= auto_delete_age + + if type == "orphan" and flagged: + with db.begin(): + pkgbase.Maintainer = None + pkgreq.Status = ACCEPTED_ID + db.refresh(pkgreq) + notif = notify.RequestCloseNotification( + conn, request.user.ID, pkgreq.ID, pkgreq.status_display()) + notif.send() + elif type == "deletion" and is_maintainer and outdated: + packages = pkgbase.packages.all() + for package in packages: + delete_package(request.user, package) # Redirect the submitting user to /packages. return RedirectResponse("/packages", diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 02c22d9d..64ee38d0 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -10,7 +10,7 @@ import pytest from fastapi.testclient import TestClient from sqlalchemy import and_ -from aurweb import asgi, db, defaults +from aurweb import asgi, config, db, defaults from aurweb.models import License, PackageLicense from aurweb.models.account_type import USER_ID, AccountType from aurweb.models.dependency_type import DependencyType @@ -1536,6 +1536,24 @@ def test_pkgbase_request_post_deletion(client: TestClient, user: User, assert pkgreq.Comments == "We want to delete this." +def test_pkgbase_request_post_maintainer_deletion( + client: TestClient, maintainer: User, package: Package): + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "deletion", + "comments": "We want to delete this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + pkgreq = db.query(PackageRequest).filter( + PackageRequest.PackageBaseName == pkgbasename + ).first() + assert pkgreq.Status == ACCEPTED_ID + + def test_pkgbase_request_post_orphan(client: TestClient, user: User, package: Package): endpoint = f"/pkgbase/{package.PackageBase.Name}/request" @@ -1556,6 +1574,29 @@ def test_pkgbase_request_post_orphan(client: TestClient, user: User, assert pkgreq.Comments == "We want to disown this." +def test_pkgbase_request_post_auto_orphan(client: TestClient, user: User, + package: Package): + now = int(datetime.utcnow().timestamp()) + auto_orphan_age = config.getint("options", "auto_orphan_age") + with db.begin(): + package.PackageBase.OutOfDateTS = now - auto_orphan_age - 1 + + endpoint = f"/pkgbase/{package.PackageBase.Name}/request" + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, data={ + "type": "orphan", + "comments": "We want to disown this." + }, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + pkgreq = db.query(PackageRequest).filter( + PackageRequest.PackageBaseID == package.PackageBase.ID + ).first() + assert pkgreq is not None + assert pkgreq.Status == ACCEPTED_ID + + def test_pkgbase_request_post_merge(client: TestClient, user: User, package: Package): with db.begin(): From f897411ddf7849123a3df72ae841b27a81bd12bf Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Nov 2021 21:17:40 -0800 Subject: [PATCH 1131/1891] change(fastapi): let conftest bypass create database errors Signed-off-by: Kevin Morris --- test/conftest.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/conftest.py b/test/conftest.py index 47d9ca4b..aa44831a 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -43,6 +43,7 @@ from filelock import FileLock from sqlalchemy import create_engine from sqlalchemy.engine import URL from sqlalchemy.engine.base import Engine +from sqlalchemy.exc import OperationalError from sqlalchemy.orm import scoped_session import aurweb.config @@ -98,7 +99,10 @@ def _create_database(engine: Engine, dbname: str) -> None: :param dbname: Database name to create """ conn = engine.connect() - conn.execute(f"CREATE DATABASE {dbname}") + try: + conn.execute(f"CREATE DATABASE {dbname}") + except OperationalError: # pragma: no cover + pass conn.close() initdb.run(AlembicArgs) From 008a8824ceb7f243f58c7d228f7cd9c1152d7386 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 13:19:34 -0800 Subject: [PATCH 1132/1891] housekeep(fastapi): simplify package_base_comaintainers_post Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 88 ++++++++++++++++++++++++++++++++++++-- aurweb/routers/packages.py | 73 ++----------------------------- 2 files changed, 88 insertions(+), 73 deletions(-) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 78f5bf18..7c48f4e4 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -4,13 +4,14 @@ from typing import Dict, List, Union import orjson -from fastapi import HTTPException +from fastapi import HTTPException, Request from sqlalchemy import and_, orm -from aurweb import db, models +from aurweb import db, l10n, models, util from aurweb.models.official_provider import OFFICIAL_BASE from aurweb.models.relation_type import PROVIDES_ID from aurweb.redis import redis_connection +from aurweb.scripts import notify from aurweb.templates import register_filter @@ -223,6 +224,85 @@ def query_notified(query: List[models.Package], ).filter( models.PackageNotification.UserID == user.ID ) - for notify in notified: - output[notify.PackageBase.ID] = True + for notif in notified: + output[notif.PackageBase.ID] = True return output + + +def remove_comaintainers(pkgbase: models.PackageBase, + usernames: List[str]) -> None: + """ + Remove comaintainers from `pkgbase`. + + :param pkgbase: PackageBase instance + :param usernames: Iterable of username strings + :return: None + """ + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + notifications = [] + with db.begin(): + for username in usernames: + # We know that the users we passed here are in the DB. + # No need to check for their existence. + comaintainer = pkgbase.comaintainers.join(models.User).filter( + models.User.Username == username + ).first() + notifications.append( + notify.ComaintainerRemoveNotification( + conn, comaintainer.User.ID, pkgbase.ID + ) + ) + db.delete(comaintainer) + + # Send out notifications if need be. + util.apply_all(notifications, lambda n: n.send()) + + +def add_comaintainers(request: Request, pkgbase: models.PackageBase, + priority: int, usernames: List[str]) -> None: + """ + Add comaintainers to `pkgbase`. + + :param request: FastAPI request + :param pkgbase: PackageBase instance + :param priority: Initial priority value + :param usernames: Iterable of username strings + :return: None on success, an error string on failure + """ + + # First, perform a check against all usernames given; for each + # username, add its related User object to memo. + _ = l10n.get_translator_for_request(request) + memo = {} + for username in usernames: + user = db.query(models.User).filter( + models.User.Username == username).first() + if not user: + return _("Invalid user name: %s") % username + memo[username] = user + + # Alright, now that we got past the check, add them all to the DB. + conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + notifications = [] + with db.begin(): + for username in usernames: + user = memo.get(username) + if pkgbase.Maintainer == user: + # Already a maintainer. Move along. + continue + + # If we get here, our user model object is in the memo. + comaintainer = db.create( + models.PackageComaintainer, + PackageBase=pkgbase, + User=user, + Priority=priority) + priority += 1 + + notifications.append( + notify.ComaintainerAddNotification( + conn, comaintainer.User.ID, pkgbase.ID) + ) + + # Send out notifications. + util.apply_all(notifications, lambda n: n.send()) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index dfb8e108..23f44ee3 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -15,6 +15,7 @@ from aurweb.exceptions import ValidationError from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.models.request_type import DELETION_ID, MERGE, MERGE_ID +from aurweb.packages import util as pkgutil from aurweb.packages import validate from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment, get_pkgreq_by_id, query_notified, query_voted @@ -531,28 +532,6 @@ async def package_base_comaintainers(request: Request, name: str) -> Response: return render_template(request, "pkgbase/comaintainers.html", context) -def remove_users(pkgbase, usernames): - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - notifications = [] - with db.begin(): - for username in usernames: - # We know that the users we passed here are in the DB. - # No need to check for their existence. - comaintainer = pkgbase.comaintainers.join(models.User).filter( - models.User.Username == username - ).first() - notifications.append( - notify.ComaintainerRemoveNotification( - conn, comaintainer.User.ID, pkgbase.ID - ) - ) - db.delete(comaintainer) - - # Send out notifications if need be. - for notify_ in notifications: - notify_.send() - - @router.post("/pkgbase/{name}/comaintainers") @auth_required(True, redirect="/pkgbase/{name}/comaintainers") async def package_base_comaintainers_post( @@ -573,7 +552,7 @@ async def package_base_comaintainers_post( users.remove(str()) # Remove any empty strings from the set. records = {c.User.Username for c in pkgbase.comaintainers} - remove_users(pkgbase, records.difference(users)) + pkgutil.remove_comaintainers(pkgbase, records.difference(users)) # Default priority (lowest value; most preferred). priority = 1 @@ -590,52 +569,8 @@ async def package_base_comaintainers_post( if last_priority: priority = last_priority.Priority + 1 - def add_users(usernames): - """ Add users as comaintainers to pkgbase. - - :param usernames: An iterable of username strings - :return: None on success, an error string on failure. """ - nonlocal request, pkgbase, priority - - # First, perform a check against all usernames given; for each - # username, add its related User object to memo. - _ = l10n.get_translator_for_request(request) - memo = {} - for username in usernames: - user = db.query(models.User).filter( - models.User.Username == username).first() - if not user: - return _("Invalid user name: %s") % username - memo[username] = user - - # Alright, now that we got past the check, add them all to the DB. - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - notifications = [] - with db.begin(): - for username in usernames: - user = memo.get(username) - if pkgbase.Maintainer == user: - # Already a maintainer. Move along. - continue - - # If we get here, our user model object is in the memo. - comaintainer = db.create( - models.PackageComaintainer, - PackageBase=pkgbase, - User=user, - Priority=priority) - priority += 1 - - notifications.append( - notify.ComaintainerAddNotification( - conn, comaintainer.User.ID, pkgbase.ID) - ) - - # Send out notifications. - for notify_ in notifications: - notify_.send() - - error = add_users(users.difference(records)) + error = pkgutil.add_comaintainers(request, pkgbase, priority, + users.difference(records)) if error: context = make_context(request, "Manage Co-maintainers") context["pkgbase"] = pkgbase From 0b5d08801615c3afa604d15d0f5db4f03d600b3d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 13:18:48 -0800 Subject: [PATCH 1133/1891] fix(fastapi): catch ProgrammingError instead of OperationalError in conftest Signed-off-by: Kevin Morris --- test/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index aa44831a..db2e5997 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -43,7 +43,7 @@ from filelock import FileLock from sqlalchemy import create_engine from sqlalchemy.engine import URL from sqlalchemy.engine.base import Engine -from sqlalchemy.exc import OperationalError +from sqlalchemy.exc import ProgrammingError from sqlalchemy.orm import scoped_session import aurweb.config @@ -101,7 +101,7 @@ def _create_database(engine: Engine, dbname: str) -> None: conn = engine.connect() try: conn.execute(f"CREATE DATABASE {dbname}") - except OperationalError: # pragma: no cover + except ProgrammingError: # pragma: no cover pass conn.close() initdb.run(AlembicArgs) From 191198ca41a10358804a5d1cdc37a35ca9be7bd6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 13:31:09 -0800 Subject: [PATCH 1134/1891] housekeep(fastapi): simplify aurweb.spawn.stop() Signed-off-by: Kevin Morris --- aurweb/spawn.py | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 6d553dde..568a8a1d 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -18,6 +18,8 @@ import tempfile import time import urllib +from typing import Iterable, List + import aurweb.config import aurweb.schema @@ -127,17 +129,15 @@ def start(): spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()]) -def stop(): +def _kill_children(children: Iterable, exceptions: List[Exception] = []) \ + -> List[Exception]: """ - Stop all the child processes. + Kill each process found in `children`. - If an exception occurs during the process, the process continues anyway - because we don’t want to leave runaway processes around, and all the - exceptions are finally raised as a single ProcessExceptions. + :param children: Iterable of child processes + :param exceptions: Exception memo + :return: `exceptions` """ - global children - atexit.unregister(stop) - exceptions = [] for p in children: try: p.terminate() @@ -145,6 +145,18 @@ def stop(): print(f":: Sent SIGTERM to {p.args}", file=sys.stderr) except Exception as e: exceptions.append(e) + return exceptions + + +def _wait_for_children(children: Iterable, exceptions: List[Exception] = []) \ + -> List[Exception]: + """ + Wait for each process to end found in `children`. + + :param children: Iterable of child processes + :param exceptions: Exception memo + :return: `exceptions` + """ for p in children: try: rc = p.wait() @@ -154,6 +166,24 @@ def stop(): raise Exception(f"Process {p.args} exited with {rc}") except Exception as e: exceptions.append(e) + return exceptions + + +def stop() -> None: + """ + Stop all the child processes. + + If an exception occurs during the process, the process continues anyway + because we don’t want to leave runaway processes around, and all the + exceptions are finally raised as a single ProcessExceptions. + + :raises: ProcessException + :return: None + """ + global children + atexit.unregister(stop) + exceptions = _kill_children(children) + exceptions = _wait_for_children(children, exceptions) children = [] if exceptions: raise ProcessExceptions("Errors terminating the child processes:", From 82ca4ad9a0c399e25a2369509df005ba5a5c6860 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 15:33:19 -0800 Subject: [PATCH 1135/1891] feat: check php configuration in aurweb.spawn Signed-off-by: Kevin Morris --- aurweb/spawn.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 568a8a1d..ecb759a5 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -23,11 +23,16 @@ from typing import Iterable, List import aurweb.config import aurweb.schema +from aurweb.exceptions import AurwebException + children = [] temporary_dir = None verbosity = 0 asgi_backend = '' +PHP_BINARY = os.environ.get("PHP_BINARY", "php") +PHP_MODULES = ["pdo_mysql", "pdo_sqlite"] + class ProcessExceptions(Exception): """ @@ -42,6 +47,35 @@ class ProcessExceptions(Exception): super().__init__("\n- ".join(messages)) +def validate_php_config() -> None: + """ + Perform a validation check against PHP_BINARY's configuration. + + AurwebException is raised here if checks fail to pass. We require + the 'pdo_mysql' and 'pdo_sqlite' modules to be enabled. + + :raises: AurwebException + :return: None + """ + try: + proc = subprocess.Popen([PHP_BINARY, "-m"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, _ = proc.communicate() + except FileNotFoundError: + raise AurwebException(f"Unable to locate the '{PHP_BINARY}' " + "executable.") + + assert proc.returncode == 0, ("Received non-zero error code " + f"{proc.returncode} from '{PHP_BINARY}'.") + + modules = out.decode().splitlines() + for module in PHP_MODULES: + if module not in modules: + raise AurwebException( + f"PHP does not have the '{module}' module enabled.") + + def generate_nginx_config(): """ Generate an nginx configuration based on aurweb's configuration. @@ -199,6 +233,13 @@ if __name__ == '__main__': parser.add_argument('-b', '--backend', choices=['hypercorn', 'uvicorn'], default='hypercorn', help='asgi backend used to launch the python server') args = parser.parse_args() + + try: + validate_php_config() + except AurwebException as exc: + print(f"error: {str(exc)}") + sys.exit(1) + verbosity = args.verbose asgi_backend = args.backend with tempfile.TemporaryDirectory(prefix="aurweb-") as tmpdirname: From 47d0df76e6f377a360903f48a96bb32e54884dfc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 15:37:47 -0800 Subject: [PATCH 1136/1891] feat: support gunicorn in aurweb.spawn This also comes with a -w|--workers argument that allows the caller to set the number of gunicorn workers. Signed-off-by: Kevin Morris --- aurweb/spawn.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index ecb759a5..5b4dbe94 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -29,6 +29,7 @@ children = [] temporary_dir = None verbosity = 0 asgi_backend = '' +workers = 1 PHP_BINARY = os.environ.get("PHP_BINARY", "php") PHP_MODULES = ["pdo_mysql", "pdo_sqlite"] @@ -152,12 +153,25 @@ def start(): spawn_child(["php", "-S", php_address, "-t", htmldir]) # FastAPI - host, port = aurweb.config.get("fastapi", "bind_address").rsplit(":", 1) - if asgi_backend == "hypercorn": - portargs = ["-b", f"{host}:{port}"] - elif asgi_backend == "uvicorn": - portargs = ["--host", host, "--port", port] - spawn_child(["python", "-m", asgi_backend] + portargs + ["aurweb.asgi:app"]) + fastapi_host, fastapi_port = aurweb.config.get( + "fastapi", "bind_address").rsplit(":", 1) + + # Logging config. + aurwebdir = aurweb.config.get("options", "aurwebdir") + fastapi_log_config = os.path.join(aurwebdir, "logging.conf") + + backend_args = { + "hypercorn": ["-b", f"{fastapi_host}:{fastapi_port}"], + "uvicorn": ["--host", fastapi_host, "--port", fastapi_port], + "gunicorn": ["--bind", f"{fastapi_host}:{fastapi_port}", + "-k", "uvicorn.workers.UvicornWorker", + "-w", str(workers)] + } + backend_args = backend_args.get(asgi_backend) + spawn_child([ + "python", "-m", asgi_backend, + "--log-config", fastapi_log_config, + ] + backend_args + ["aurweb.asgi:app"]) # nginx spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()]) @@ -230,8 +244,11 @@ if __name__ == '__main__': description='Start aurweb\'s test server.') parser.add_argument('-v', '--verbose', action='count', default=0, help='increase verbosity') - parser.add_argument('-b', '--backend', choices=['hypercorn', 'uvicorn'], default='hypercorn', + choices = ['hypercorn', 'gunicorn', 'uvicorn'] + parser.add_argument('-b', '--backend', choices=choices, default='uvicorn', help='asgi backend used to launch the python server') + parser.add_argument("-w", "--workers", default=1, type=int, + help="number of workers to use in gunicorn") args = parser.parse_args() try: @@ -242,6 +259,7 @@ if __name__ == '__main__': verbosity = args.verbose asgi_backend = args.backend + workers = args.workers with tempfile.TemporaryDirectory(prefix="aurweb-") as tmpdirname: temporary_dir = tmpdirname start() From 19191fa8b56c47d256b2c8992853d96f82cabc5a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 15:38:20 -0800 Subject: [PATCH 1137/1891] fix: update nginx config in aurweb.spawn Host a specific FastAPI nginx frontend as well as a PHP nginx frontend, configurable by the (PHP|FASTAPI)_NGINX_PORT environment variables. Signed-off-by: Kevin Morris --- aurweb/spawn.py | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 5b4dbe94..46f2f021 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -16,7 +16,6 @@ import subprocess import sys import tempfile import time -import urllib from typing import Iterable, List @@ -33,6 +32,8 @@ workers = 1 PHP_BINARY = os.environ.get("PHP_BINARY", "php") PHP_MODULES = ["pdo_mysql", "pdo_sqlite"] +PHP_NGINX_PORT = int(os.environ.get("PHP_NGINX_PORT", 8001)) +FASTAPI_NGINX_PORT = int(os.environ.get("FASTAPI_NGINX_PORT", 8002)) class ProcessExceptions(Exception): @@ -83,8 +84,10 @@ def generate_nginx_config(): The file is generated under `temporary_dir`. Returns the path to the created configuration file. """ - aur_location = aurweb.config.get("options", "aur_location") - aur_location_parts = urllib.parse.urlsplit(aur_location) + php_bind = aurweb.config.get("php", "bind_address") + php_host = php_bind.split(":")[0] + fastapi_bind = aurweb.config.get("fastapi", "bind_address") + fastapi_host = fastapi_bind.split(":")[0] config_path = os.path.join(temporary_dir, "nginx.conf") config = open(config_path, "w") # We double nginx's braces because they conflict with Python's f-strings. @@ -101,12 +104,23 @@ def generate_nginx_config(): uwsgi_temp_path {os.path.join(temporary_dir, "uwsgi")}; scgi_temp_path {os.path.join(temporary_dir, "scgi")}; server {{ - listen {aur_location_parts.netloc}; + listen {php_host}:{PHP_NGINX_PORT}; location / {{ - proxy_pass http://{aurweb.config.get("php", "bind_address")}; + proxy_pass http://{php_bind}; }} - location /sso {{ - proxy_pass http://{aurweb.config.get("fastapi", "bind_address")}; + }} + server {{ + listen {fastapi_host}:{FASTAPI_NGINX_PORT}; + location / {{ + try_files $uri @proxy_to_app; + }} + location @proxy_to_app {{ + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_redirect off; + proxy_buffering off; + proxy_pass http://{fastapi_bind}; }} }} }} @@ -149,6 +163,7 @@ def start(): # PHP php_address = aurweb.config.get("php", "bind_address") + php_host = php_address.split(":")[0] htmldir = aurweb.config.get("php", "htmldir") spawn_child(["php", "-S", php_address, "-t", htmldir]) @@ -176,6 +191,18 @@ def start(): # nginx spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()]) + print(f""" + > Started nginx. + > + > PHP backend: http://{php_address} + > FastAPI backend: http://{fastapi_host}:{fastapi_port} + > + > PHP frontend: http://{php_host}:{PHP_NGINX_PORT} + > FastAPI frontend: http://{fastapi_host}:{FASTAPI_NGINX_PORT} + > + > Frontends are hosted via nginx and should be preferred. +""") + def _kill_children(children: Iterable, exceptions: List[Exception] = []) \ -> List[Exception]: From 233d25b1c3434221871a7ccb04a7897c3213c33d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 15:39:15 -0800 Subject: [PATCH 1138/1891] feat: add test_spawn, an aurweb.spawn test Signed-off-by: Kevin Morris --- test/test_spawn.py | 149 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 test/test_spawn.py diff --git a/test/test_spawn.py b/test/test_spawn.py new file mode 100644 index 00000000..195eb897 --- /dev/null +++ b/test/test_spawn.py @@ -0,0 +1,149 @@ +import os +import tempfile + +from typing import Tuple +from unittest import mock + +import pytest + +import aurweb.config +import aurweb.spawn + +from aurweb.exceptions import AurwebException + +# Some os.environ overrides we use in this suite. +TEST_ENVIRONMENT = { + "PHP_NGINX_PORT": "8001", + "FASTAPI_NGINX_PORT": "8002" +} + + +class FakeProcess: + """ Fake a subprocess.Popen return object. """ + + returncode = 0 + stdout = b'' + stderr = b'' + + def __init__(self, *args, **kwargs): + """ We need this constructor to remain compatible with Popen. """ + pass + + def communicate(self) -> Tuple[bytes, bytes]: + return (self.stdout, self.stderr) + + def terminate(self) -> None: + raise Exception("Fake termination.") + + def wait(self) -> int: + return self.returncode + + +class MockFakeProcess: + """ FakeProcess construction helper to be used in mocks. """ + + def __init__(self, return_code: int = 0, stdout: bytes = b'', + stderr: bytes = b''): + self.returncode = return_code + self.stdout = stdout + self.stderr = stderr + + def process(self, *args, **kwargs) -> FakeProcess: + proc = FakeProcess() + proc.returncode = self.returncode + proc.stdout = self.stdout + proc.stderr = self.stderr + return proc + + +@mock.patch("aurweb.spawn.PHP_BINARY", "does-not-exist") +def test_spawn(): + match = r"^Unable to locate the '.*' executable\.$" + with pytest.raises(AurwebException, match=match): + aurweb.spawn.validate_php_config() + + +@mock.patch("subprocess.Popen", side_effect=MockFakeProcess(1).process) +def test_spawn_non_zero_php_binary(fake_process: FakeProcess): + match = r"^Received non-zero error code.*$" + with pytest.raises(AssertionError, match=match): + aurweb.spawn.validate_php_config() + + +def test_spawn_missing_modules(): + side_effect = MockFakeProcess(stdout=b"pdo_sqlite").process + with mock.patch("subprocess.Popen", side_effect=side_effect): + match = r"PHP does not have the 'pdo_mysql' module enabled\.$" + with pytest.raises(AurwebException, match=match): + aurweb.spawn.validate_php_config() + + side_effect = MockFakeProcess(stdout=b"pdo_mysql").process + with mock.patch("subprocess.Popen", side_effect=side_effect): + match = r"PHP does not have the 'pdo_sqlite' module enabled\.$" + with pytest.raises(AurwebException, match=match): + aurweb.spawn.validate_php_config() + + +@mock.patch.dict("os.environ", TEST_ENVIRONMENT) +def test_spawn_generate_nginx_config(): + ctx = tempfile.TemporaryDirectory() + with ctx and mock.patch("aurweb.spawn.temporary_dir", ctx.name): + aurweb.spawn.generate_nginx_config() + nginx_config_path = os.path.join(ctx.name, "nginx.conf") + with open(nginx_config_path) as f: + nginx_config = f.read().rstrip() + + php_address = aurweb.config.get("php", "bind_address") + php_host = php_address.split(":")[0] + fastapi_address = aurweb.config.get("fastapi", "bind_address") + fastapi_host = fastapi_address.split(":")[0] + expected_content = [ + f'listen {php_host}:{TEST_ENVIRONMENT.get("PHP_NGINX_PORT")}', + f"proxy_pass http://{php_address}", + f'listen {fastapi_host}:{TEST_ENVIRONMENT.get("FASTAPI_NGINX_PORT")}', + f"proxy_pass http://{fastapi_address}" + ] + for expected in expected_content: + assert expected in nginx_config + + +@mock.patch("aurweb.spawn.asgi_backend", "uvicorn") +@mock.patch("aurweb.spawn.verbosity", 1) +@mock.patch("aurweb.spawn.workers", 1) +def test_spawn_start_stop(): + ctx = tempfile.TemporaryDirectory() + with ctx and mock.patch("aurweb.spawn.temporary_dir", ctx.name): + aurweb.spawn.start() + aurweb.spawn.stop() + + +@mock.patch("aurweb.spawn.asgi_backend", "uvicorn") +@mock.patch("aurweb.spawn.verbosity", 1) +@mock.patch("aurweb.spawn.workers", 1) +@mock.patch("aurweb.spawn.children", [MockFakeProcess().process()]) +def test_spawn_start_noop_with_children(): + aurweb.spawn.start() + + +@mock.patch("aurweb.spawn.asgi_backend", "uvicorn") +@mock.patch("aurweb.spawn.verbosity", 1) +@mock.patch("aurweb.spawn.workers", 1) +@mock.patch("aurweb.spawn.children", [MockFakeProcess().process()]) +def test_spawn_stop_terminate_failure(): + ctx = tempfile.TemporaryDirectory() + with ctx and mock.patch("aurweb.spawn.temporary_dir", ctx.name): + match = r"^Errors terminating the child processes" + with pytest.raises(aurweb.spawn.ProcessExceptions, match=match): + aurweb.spawn.stop() + + +@mock.patch("aurweb.spawn.asgi_backend", "uvicorn") +@mock.patch("aurweb.spawn.verbosity", 1) +@mock.patch("aurweb.spawn.workers", 1) +@mock.patch("aurweb.spawn.children", [MockFakeProcess(1).process()]) +def test_spawn_stop_wait_failure(): + ctx = tempfile.TemporaryDirectory() + with ctx and mock.patch("aurweb.spawn.temporary_dir", ctx.name): + match = r"^Errors terminating the child processes" + with pytest.raises(aurweb.spawn.ProcessExceptions, match=match): + aurweb.spawn.stop() From ba3ef742ceec27a2667d579ef78eb0fc36f1a364 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 18:40:32 -0800 Subject: [PATCH 1139/1891] feat(docker): allow user-customizable ssh host keys There is a new ./data bind mount used here. If ssh_host_* keys are in ./data when the git service starts, they'll override the container-generated host keys. Signed-off-by: Kevin Morris --- docker-compose.aur-dev.yml | 1 + docker/git-entrypoint.sh | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 1db306cc..484f353a 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -18,6 +18,7 @@ services: restart: always volumes: - ${GIT_DATA_DIR}:/aurweb/aur.git + - ./data:/aurweb/data - cache:/cache smartgit: diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index 296c1e47..4d15bcb9 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -60,6 +60,13 @@ sed -ri "s|^(ssh-cmdline) = .+|\1 = $ssh_cmdline|" $AUR_CONFIG_DEFAULTS # Setup SSH Keys. ssh-keygen -A +# In docker-compose.aur-dev.yml, we bind ./data to /aurweb/data. +# Production users wishing to include their own SSH keys should +# supply them in ./data. +if [ -d /aurweb/data ]; then + find /aurweb/data -type f -name 'ssh_host_*' -exec cp -vf "{}" /etc/ssh/ \; +fi + # Taken from INSTALL. mkdir -pv $GIT_REPO From a1e547c057da8a2391c94a6d51c7c04fe37ad71b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 19:03:35 -0800 Subject: [PATCH 1140/1891] feat(docker): allow configurable SSH_CMDLINE in git service Signed-off-by: Kevin Morris --- docker-compose.aur-dev.yml | 4 ++++ docker-compose.yml | 1 + docker/git-entrypoint.sh | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 484f353a..62109deb 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -16,6 +16,10 @@ services: git: restart: always + environment: + - AUR_CONFIG=/aurweb/conf/config + # SSH_CMDLINE should be updated to production's ssh cmdline. + - SSH_CMDLINE=${SSH_CMDLINE:-ssh ssh://aur@localhost:2222} volumes: - ${GIT_DATA_DIR}:/aurweb/aur.git - ./data:/aurweb/data diff --git a/docker-compose.yml b/docker-compose.yml index c39d38bf..26b7d62c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -100,6 +100,7 @@ services: init: true environment: - AUR_CONFIG=/aurweb/conf/config + - SSH_CMDLINE=${SSH_CMDLINE:-ssh ssh://aur@localhost:2222} entrypoint: /docker/git-entrypoint.sh command: /docker/scripts/run-sshd.sh ports: diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index 4d15bcb9..cfa1879b 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -54,8 +54,8 @@ fi # Set some defaults needed for pathing and ssh uris. sed -ri "s|^(repo-path) = .+|\1 = /aurweb/aur.git/|" $AUR_CONFIG_DEFAULTS -ssh_cmdline='ssh ssh://aur@localhost:2222' -sed -ri "s|^(ssh-cmdline) = .+|\1 = $ssh_cmdline|" $AUR_CONFIG_DEFAULTS +# SSH_CMDLINE can be provided via override in docker-compose.aur-dev.yml. +sed -ri "s|^(ssh-cmdline) = .+$|\1 = ${SSH_CMDLINE}|" $AUR_CONFIG_DEFAULTS # Setup SSH Keys. ssh-keygen -A From c7feecd4b83fde3aa0e1a1e392035be8fb32385e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 19:34:33 -0800 Subject: [PATCH 1141/1891] housekeep(docker): remove configuration regexes in the nginx service Signed-off-by: Kevin Morris --- docker/nginx-entrypoint.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/docker/nginx-entrypoint.sh b/docker/nginx-entrypoint.sh index 63307948..a58e67b7 100755 --- a/docker/nginx-entrypoint.sh +++ b/docker/nginx-entrypoint.sh @@ -11,17 +11,6 @@ KEY=/cache/production.key.pem DEST_CERT=/etc/ssl/certs/web.cert.pem DEST_KEY=/etc/ssl/private/web.key.pem -# Setup a config for our mysql db. -cp -vf conf/config.dev conf/config -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config -sed -ri 's/^(host) = .+/\1 = mariadb/' conf/config -sed -ri 's/^(user) = .+/\1 = aur/' conf/config -sed -ri 's/^;?(password) = .+/\1 = aur/' conf/config - -# Setup http(s) stuff. -sed -ri "s|^(aur_location) = .+|\1 = https://localhost:8444|" conf/config -sed -ri 's/^(disable_http_login) = .+/\1 = 1/' conf/config - if [ -f "$CERT" ]; then cp -vf "$CERT" "$DEST_CERT" cp -vf "$KEY" "$DEST_KEY" From 604901fe7475912705e040ab40a509c80d109289 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 20:00:53 -0800 Subject: [PATCH 1142/1891] fix(docker): fix nginx .gz match against cgit snapshots This only deals with .gz files in the root of the request_uri and now more. That is: /packages.gz goes through the nginx regex, but now /cgit/.../snapshot/package.tar.gz is served by the cgit block. Signed-off-by: Kevin Morris --- docker/config/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index c3ffd7fa..e51bd64f 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -94,7 +94,7 @@ http { ssl_certificate /etc/ssl/certs/web.cert.pem; ssl_certificate_key /etc/ssl/private/web.key.pem; - location ~ ^/.*\.gz$ { + location ~ ^/[^\/]+\.gz$ { # Override mime type to text/plain. types { text/plain gz; } default_type text/plain; From d4d9f50b8f540062a3191e254a16f2e4497b7b8f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 20 Nov 2021 20:05:04 -0800 Subject: [PATCH 1143/1891] change(docker): use ./data instead of ./cache For the `git` service, ./data is always used to provide an optional overriding of ssh host keys. In aur-dev production containers, most services which use the data mount use an internal Docker `data` volume instead. Signed-off-by: Kevin Morris --- docker-compose.aur-dev.yml | 13 ++++++------ docker-compose.override.yml | 12 +++++------ docker-compose.yml | 6 +++--- docker/ca-entrypoint.sh | 38 +++++++++++++++++------------------ docker/cgit-entrypoint.sh | 2 +- docker/nginx-entrypoint.sh | 8 ++++---- docker/scripts/run-fastapi.sh | 12 +++++------ docker/scripts/run-nginx.sh | 2 +- docker/scripts/run-pytests.sh | 10 ++++----- docker/scripts/run-tests.sh | 10 ++++----- 10 files changed, 56 insertions(+), 57 deletions(-) diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 62109deb..ab4ff124 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -3,7 +3,7 @@ version: "3.8" services: ca: volumes: - - cache:/cache + - data:/data memcached: restart: always @@ -23,13 +23,12 @@ services: volumes: - ${GIT_DATA_DIR}:/aurweb/aur.git - ./data:/aurweb/data - - cache:/cache smartgit: restart: always volumes: - ${GIT_DATA_DIR}:/aurweb/aur.git - - cache:/cache + - data:/data - smartgit_run:/var/run/smartgit cgit-php: @@ -48,7 +47,7 @@ services: - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} volumes: - - cache:/cache + - data:/data fastapi: restart: always @@ -60,13 +59,13 @@ services: - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus volumes: - - cache:/cache + - data:/data nginx: restart: always volumes: - ${GIT_DATA_DIR}:/aurweb/aur.git - - cache:/cache + - data:/data - logs:/var/log/nginx - smartgit_run:/var/run/smartgit @@ -75,5 +74,5 @@ volumes: mariadb_data: {} # Share /var/lib/mysql git_data: {} # Share aurweb/aur.git smartgit_run: {} - cache: {} + data: {} logs: {} diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 7349ac66..eae12a92 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -8,17 +8,17 @@ services: ca: volumes: - - ./cache:/cache + - ./data:/data git: volumes: - git_data:/aurweb/aur.git - - ./cache:/cache + - ./data:/aurweb/data smartgit: volumes: - git_data:/aurweb/aur.git - - ./cache:/cache + - ./data:/data - smartgit_run:/var/run/smartgit depends_on: mariadb: @@ -26,7 +26,7 @@ services: php-fpm: volumes: - - ./cache:/cache + - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test @@ -37,7 +37,7 @@ services: fastapi: volumes: - - ./cache:/cache + - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test @@ -49,7 +49,7 @@ services: nginx: volumes: - git_data:/aurweb/aur.git - - ./cache:/cache + - ./data:/data - ./logs:/var/log/nginx - ./web/html:/aurweb/web/html - ./web/template:/aurweb/web/template diff --git a/docker-compose.yml b/docker-compose.yml index 26b7d62c..e3bfacdc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -276,7 +276,7 @@ services: mariadb_test: condition: service_healthy volumes: - - ./cache:/cache + - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test @@ -304,7 +304,7 @@ services: - /tmp volumes: - mariadb_test_run:/var/run/mysqld - - ./cache:/cache + - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test @@ -330,7 +330,7 @@ services: condition: service_healthy volumes: - mariadb_test_run:/var/run/mysqld - - ./cache:/cache + - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test diff --git a/docker/ca-entrypoint.sh b/docker/ca-entrypoint.sh index e95d267c..42d8bd14 100755 --- a/docker/ca-entrypoint.sh +++ b/docker/ca-entrypoint.sh @@ -1,58 +1,58 @@ #!/bin/bash set -eou pipefail -if [ -f /cache/ca.root.pem ]; then +if [ -f /data/ca.root.pem ]; then echo "Already have certs, skipping." exit 0 fi # Generate a new 2048-bit RSA key for the Root CA. -openssl genrsa -des3 -out /cache/ca.key -passout pass:devca 2048 +openssl genrsa -des3 -out /data/ca.key -passout pass:devca 2048 # Request and self-sign a new Root CA certificate, using # the RSA key. Output Root CA PEM-format certificate and key: -# /cache/ca.root.pem and /cache/ca.key.pem +# /data/ca.root.pem and /data/ca.key.pem openssl req -x509 -new -nodes -sha256 -days 1825 \ -passin pass:devca \ -subj "/C=US/ST=California/L=Authority/O=aurweb/CN=localhost" \ - -in /cache/ca.key -out /cache/ca.root.pem -keyout /cache/ca.key.pem + -in /data/ca.key -out /data/ca.root.pem -keyout /data/ca.key.pem # Generate a new 2048-bit RSA key for a localhost server. -openssl genrsa -out /cache/localhost.key 2048 +openssl genrsa -out /data/localhost.key 2048 # Generate a Certificate Signing Request (CSR) for the localhost server # using the RSA key we generated above. -openssl req -new -key /cache/localhost.key -passout pass:devca \ +openssl req -new -key /data/localhost.key -passout pass:devca \ -subj "/C=US/ST=California/L=Server/O=aurweb/CN=localhost" \ - -out /cache/localhost.csr + -out /data/localhost.csr # Get our CSR signed by our Root CA PEM-formatted certificate and key -# to produce a fresh /cache/localhost.cert.pem PEM-formatted certificate. -openssl x509 -req -in /cache/localhost.csr \ - -CA /cache/ca.root.pem -CAkey /cache/ca.key.pem \ +# to produce a fresh /data/localhost.cert.pem PEM-formatted certificate. +openssl x509 -req -in /data/localhost.csr \ + -CA /data/ca.root.pem -CAkey /data/ca.key.pem \ -CAcreateserial \ - -out /cache/localhost.cert.pem \ + -out /data/localhost.cert.pem \ -days 825 -sha256 \ -passin pass:devca \ -extfile /docker/localhost.ext -# Convert RSA key to a PEM-formatted key: /cache/localhost.key.pem -openssl rsa -in /cache/localhost.key -text > /cache/localhost.key.pem +# Convert RSA key to a PEM-formatted key: /data/localhost.key.pem +openssl rsa -in /data/localhost.key -text > /data/localhost.key.pem # At the end here, our notable certificates and keys are: -# - /cache/ca.root.pem -# - /cache/ca.key.pem -# - /cache/localhost.key.pem -# - /cache/localhost.cert.pem +# - /data/ca.root.pem +# - /data/ca.key.pem +# - /data/localhost.key.pem +# - /data/localhost.cert.pem # # When running a server which uses the localhost certificate, a chain # should be used, starting with localhost.cert.pem: -# - cat /cache/localhost.cert.pem /cache/ca.root.pem > localhost.chain.pem +# - cat /data/localhost.cert.pem /data/ca.root.pem > localhost.chain.pem # # The Root CA (ca.root.pem) should be imported into browsers or # ca-certificates on machines wishing to verify localhost. # -chmod 666 /cache/* +chmod 666 /data/* exec "$@" diff --git a/docker/cgit-entrypoint.sh b/docker/cgit-entrypoint.sh index f9ca86c0..a44675e2 100755 --- a/docker/cgit-entrypoint.sh +++ b/docker/cgit-entrypoint.sh @@ -1,7 +1,7 @@ #!/bin/bash set -eou pipefail -mkdir -p /var/cache/cgit +mkdir -p /var/data/cgit cp -vf conf/cgitrc.proto /etc/cgitrc sed -ri "s|clone-prefix=.*|clone-prefix=${CGIT_CLONE_PREFIX}|" /etc/cgitrc diff --git a/docker/nginx-entrypoint.sh b/docker/nginx-entrypoint.sh index a58e67b7..6b9a6954 100755 --- a/docker/nginx-entrypoint.sh +++ b/docker/nginx-entrypoint.sh @@ -5,8 +5,8 @@ set -eou pipefail # user customization of the certificates that FastAPI uses. # Otherwise, fallback to localhost.{cert,key}.pem, generated by `ca`. -CERT=/cache/production.cert.pem -KEY=/cache/production.key.pem +CERT=/data/production.cert.pem +KEY=/data/production.key.pem DEST_CERT=/etc/ssl/certs/web.cert.pem DEST_KEY=/etc/ssl/private/web.key.pem @@ -15,8 +15,8 @@ if [ -f "$CERT" ]; then cp -vf "$CERT" "$DEST_CERT" cp -vf "$KEY" "$DEST_KEY" else - cat /cache/localhost.cert.pem /cache/ca.root.pem > "$DEST_CERT" - cp -vf /cache/localhost.key.pem "$DEST_KEY" + cat /data/localhost.cert.pem /data/ca.root.pem > "$DEST_CERT" + cp -vf /data/localhost.key.pem "$DEST_KEY" fi cp -vf /docker/config/nginx.conf /etc/nginx/nginx.conf diff --git a/docker/scripts/run-fastapi.sh b/docker/scripts/run-fastapi.sh index effc7fe4..ac54aedc 100755 --- a/docker/scripts/run-fastapi.sh +++ b/docker/scripts/run-fastapi.sh @@ -1,15 +1,15 @@ #!/bin/bash -CERT=/cache/localhost.cert.pem -KEY=/cache/localhost.key.pem +CERT=/data/localhost.cert.pem +KEY=/data/localhost.key.pem # If production.{cert,key}.pem exists, prefer them. This allows # user customization of the certificates that FastAPI uses. -if [ -f /cache/production.cert.pem ]; then - CERT=/cache/production.cert.pem +if [ -f /data/production.cert.pem ]; then + CERT=/data/production.cert.pem fi -if [ -f /cache/production.key.pem ]; then - KEY=/cache/production.key.pem +if [ -f /data/production.key.pem ]; then + KEY=/data/production.key.pem fi # By default, set FASTAPI_WORKERS to 2. In production, this should diff --git a/docker/scripts/run-nginx.sh b/docker/scripts/run-nginx.sh index 7780dae8..6ece3303 100755 --- a/docker/scripts/run-nginx.sh +++ b/docker/scripts/run-nginx.sh @@ -8,7 +8,7 @@ echo " (cgit) : https://localhost:8444/cgit/" echo " - PHP : https://localhost:8443/" echo " (cgit) : https://localhost:8443/cgit/" echo -echo " Note: Copy root CA (./cache/ca.root.pem) to ca-certificates or browser." +echo " Note: Copy root CA (./data/ca.root.pem) to ca-certificates or browser." echo echo " Thanks for using aurweb!" echo diff --git a/docker/scripts/run-pytests.sh b/docker/scripts/run-pytests.sh index b8f695df..2eadee42 100755 --- a/docker/scripts/run-pytests.sh +++ b/docker/scripts/run-pytests.sh @@ -32,10 +32,10 @@ pytest if [ $COVERAGE -eq 1 ]; then make -C test coverage - # /cache is mounted as a volume. Copy coverage into it. + # /data is mounted as a volume. Copy coverage into it. # Users can then sanitize the coverage locally in their - # aurweb root directory: ./util/fix-coverage ./cache/.coverage - rm -f /cache/.coverage - cp -v .coverage /cache/.coverage - chmod 666 /cache/.coverage + # aurweb root directory: ./util/fix-coverage ./data/.coverage + rm -f /data/.coverage + cp -v .coverage /data/.coverage + chmod 666 /data/.coverage fi diff --git a/docker/scripts/run-tests.sh b/docker/scripts/run-tests.sh index 45c7835f..a726c957 100755 --- a/docker/scripts/run-tests.sh +++ b/docker/scripts/run-tests.sh @@ -14,12 +14,12 @@ bash $dir/run-pytests.sh --no-coverage make -C test coverage -# /cache is mounted as a volume. Copy coverage into it. +# /data is mounted as a volume. Copy coverage into it. # Users can then sanitize the coverage locally in their -# aurweb root directory: ./util/fix-coverage ./cache/.coverage -rm -f /cache/.coverage -cp -v .coverage /cache/.coverage -chmod 666 /cache/.coverage +# aurweb root directory: ./util/fix-coverage ./data/.coverage +rm -f /data/.coverage +cp -v .coverage /data/.coverage +chmod 666 /data/.coverage # Run flake8 and isort checks. for dir in aurweb test migrations; do From e8f4c9cf69161076a2cc71fcab060f664b327045 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 21 Nov 2021 00:51:05 -0800 Subject: [PATCH 1144/1891] fix(fastapi): remove aurweb logger definition Both the root and aurweb loggers are included in output, causing repeated log messages. Now, just rely on the root logger for aurweb logging. Signed-off-by: Kevin Morris --- logging.conf | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/logging.conf b/logging.conf index ba41fb7b..310ac76e 100644 --- a/logging.conf +++ b/logging.conf @@ -1,5 +1,5 @@ [loggers] -keys=root,aurweb,test,uvicorn,hypercorn,alembic +keys=root,test,uvicorn,hypercorn,alembic [handlers] keys=simpleHandler,detailedHandler @@ -9,13 +9,7 @@ keys=simpleFormatter,detailedFormatter [logger_root] level=INFO -handlers=simpleHandler - -[logger_aurweb] -level=DEBUG handlers=detailedHandler -qualname=aurweb -propagate=1 [logger_test] level=DEBUG @@ -43,13 +37,13 @@ propagate=0 [handler_simpleHandler] class=StreamHandler -level=DEBUG +level=INFO formatter=simpleFormatter args=(sys.stdout,) [handler_detailedHandler] class=StreamHandler -level=DEBUG +level=INFO formatter=detailedFormatter args=(sys.stdout,) From bc7bf9866ad1f7b3e0ccc9c7b00ffac5d6f72524 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 21 Nov 2021 00:48:53 -0800 Subject: [PATCH 1145/1891] docker: bind ./aurweb in cron service by default Signed-off-by: Kevin Morris --- docker-compose.aur-dev.yml | 6 ++++++ docker-compose.yml | 1 + 2 files changed, 7 insertions(+) diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index ab4ff124..4b522e56 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -41,6 +41,12 @@ services: volumes: - ${GIT_DATA_DIR}:/aurweb/aur.git + cron: + volumes: + # Exclude ./aurweb:/aurweb in production. + - mariadb_run:/var/run/mysqld + - archives:/var/lib/aurweb/archives + php-fpm: restart: always environment: diff --git a/docker-compose.yml b/docker-compose.yml index e3bfacdc..ea0e8d1b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -176,6 +176,7 @@ services: mariadb_init: condition: service_started volumes: + - ./aurweb:/aurweb/aurweb - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives From 41e0eaaece5df78b4f9abbb17c4ff702e854ab8a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 21 Nov 2021 21:43:14 -0800 Subject: [PATCH 1146/1891] fix(docker): force bind ports to localhost only Signed-off-by: Kevin Morris --- docker-compose.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ea0e8d1b..5ff031e4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,7 +48,7 @@ services: test: "bash /docker/health/redis.sh" interval: 3s ports: - - "16379:6379" + - "127.0.0.1:16379:6379" mariadb: image: aurweb:latest @@ -58,7 +58,7 @@ services: ports: # This will expose mariadbd on 127.0.0.1:13306 in the host. # Ex: `mysql -uaur -paur -h 127.0.0.1 -P 13306 aurweb` - - "13306:3306" + - "127.0.0.1:13306:3306" volumes: - mariadb_run:/var/run/mysqld # Bind socket in this volume. - mariadb_data:/var/lib/mysql @@ -88,7 +88,7 @@ services: ports: # This will expose mariadbd on 127.0.0.1:13307 in the host. # Ex: `mysql -uaur -paur -h 127.0.0.1 -P 13306 aurweb` - - "13307:3306" + - "127.0.0.1:13307:3306" volumes: - mariadb_test_run:/var/run/mysqld # Bind socket in this volume. healthcheck: @@ -104,7 +104,7 @@ services: entrypoint: /docker/git-entrypoint.sh command: /docker/scripts/run-sshd.sh ports: - - "2222:2222" + - "127.0.0.1:2222:2222" healthcheck: test: "bash /docker/health/sshd.sh" interval: 3s @@ -141,7 +141,7 @@ services: git: condition: service_healthy ports: - - "13000:3000" + - "127.0.0.1:13000:3000" volumes: - git_data:/aurweb/aur.git @@ -161,7 +161,7 @@ services: git: condition: service_healthy ports: - - "13001:3000" + - "127.0.0.1:13001:3000" volumes: - git_data:/aurweb/aur.git @@ -205,7 +205,7 @@ services: - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives ports: - - "19000:9000" + - "127.0.0.1:19000:9000" fastapi: image: aurweb:latest @@ -234,7 +234,7 @@ services: volumes: - mariadb_run:/var/run/mysqld ports: - - "18000:8000" + - "127.0.0.1:18000:8000" nginx: image: aurweb:latest @@ -244,8 +244,8 @@ services: entrypoint: /docker/nginx-entrypoint.sh command: /docker/scripts/run-nginx.sh ports: - - "8443:8443" # PHP - - "8444:8444" # FastAPI + - "127.0.0.1:8443:8443" # PHP + - "127.0.0.1:8444:8444" # FastAPI healthcheck: test: "bash /docker/health/nginx.sh" interval: 3s From 34747359ba599d2dda02a404d47a720b7363d367 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 21 Nov 2021 23:11:02 -0800 Subject: [PATCH 1147/1891] fix(docker): expose git service's 2222 through 0.0.0.0 Other ports we use are locked to 127.0.0.1. The `git` service, however, already promotes security in its sshd service and can't really be abused from an external source. This simplifies the need to forward to localhost if deploy targets want the sshd to be available. Signed-off-by: Kevin Morris --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5ff031e4..acb5dd65 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -104,7 +104,7 @@ services: entrypoint: /docker/git-entrypoint.sh command: /docker/scripts/run-sshd.sh ports: - - "127.0.0.1:2222:2222" + - "2222:2222" healthcheck: test: "bash /docker/health/sshd.sh" interval: 3s From e891d7c8e86b344af705580c9049d59570bed6f3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 10:18:02 -0800 Subject: [PATCH 1148/1891] change(docker): allow run-pytests to collect coverage Additionally fix up the argument parsing to be a bit less flexible. Signed-off-by: Kevin Morris --- docker/scripts/run-pytests.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docker/scripts/run-pytests.sh b/docker/scripts/run-pytests.sh index 2eadee42..d8c093d5 100755 --- a/docker/scripts/run-pytests.sh +++ b/docker/scripts/run-pytests.sh @@ -1,5 +1,4 @@ #!/bin/bash -set -eou pipefail COVERAGE=1 PARAMS=() @@ -11,13 +10,13 @@ while [ $# -ne 0 ]; do COVERAGE=0 shift ;; - -*) - echo "usage: $0 [--no-coverage] targets ..." - exit 1 + clean) + rm -f .coverage + shift ;; *) - PARAMS+=("$key") - shift + echo "usage: $0 [--no-coverage] targets ..." + exit 1 ;; esac done @@ -30,7 +29,7 @@ pytest # By default, report coverage and move it into cache. if [ $COVERAGE -eq 1 ]; then - make -C test coverage + make -C test coverage || /bin/true # /data is mounted as a volume. Copy coverage into it. # Users can then sanitize the coverage locally in their From 39fd3b891e4c3f86dad74ea8b66b516abdcf45e7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 21 Nov 2021 01:41:10 -0800 Subject: [PATCH 1149/1891] change: set -v for sh tests Signed-off-by: Kevin Morris --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index 4a8207f8..a6abc9de 100644 --- a/test/Makefile +++ b/test/Makefile @@ -26,6 +26,6 @@ clean: rm -f ../.coverage $(T): - @echo "*** $@ ***"; $(SHELL) $@ + @echo "*** $@ ***"; $(SHELL) $@ -v .PHONY: check coverage $(FOREIGN_TARGETS) clean $(T) From 3b686c475d605309abc94d1655369ec4cf44deed Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 07:34:35 -0800 Subject: [PATCH 1150/1891] fix: default detailed loglevel to DEBUG Signed-off-by: Kevin Morris --- logging.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logging.conf b/logging.conf index 310ac76e..3b96e827 100644 --- a/logging.conf +++ b/logging.conf @@ -43,7 +43,7 @@ args=(sys.stdout,) [handler_detailedHandler] class=StreamHandler -level=INFO +level=DEBUG formatter=detailedFormatter args=(sys.stdout,) From 47d83244bbd415b769b151dc64de18c9b62568b9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 22:21:45 -0800 Subject: [PATCH 1151/1891] change(gitlab-ci): add 'fast-single-thread' tag to the test stage Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 739c9408..8980fa78 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,4 @@ image: archlinux:base-devel - cache: key: system-v1 paths: @@ -13,6 +12,8 @@ variables: test: stage: test + tags: + - fast-single-thread before_script: - export PATH="$HOME/.poetry/bin:${PATH}" - ./docker/scripts/install-deps.sh From 6bb002e70889777024384529f37907f595894bf2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 24 Nov 2021 21:23:01 -0800 Subject: [PATCH 1152/1891] fix: use correct u2f ssh key prefixes Signed-off-by: Kevin Morris --- conf/config.defaults | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conf/config.defaults b/conf/config.defaults index a04f21bc..dd9bfd2f 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -62,7 +62,9 @@ ECDSA = SHA256:L71Q91yHwmHPYYkJMDgj0xmUuw16qFOhJbBr1mzsiOI RSA = SHA256:Ju+yWiMb/2O+gKQ9RJCDqvRg7l+Q95KFAeqM5sr6l2s [auth] -valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 sk-ssh-ecdsa@openssh.com sk-ssh-ed25519@openssh.com +; For U2F key prefixes, see the following documentation from openssh: +; https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.u2f +valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 sk-ecdsa-sha2-nistp256@openssh.com sk-ecdsa-sha2-nistp256-cert-v01@openssh.com sk-ssh-ed25519@openssh.com sk-ssh-ed25519-cert-v01@openssh.com username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ git-serve-cmd = /usr/local/bin/aurweb-git-serve ssh-options = restrict From 1aab9604010e9b58c7bed8586931841751bbab68 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 24 Nov 2021 21:28:29 -0800 Subject: [PATCH 1153/1891] fix: use corrent u2f ssh key prefixes Signed-off-by: Kevin Morris --- conf/config.defaults | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conf/config.defaults b/conf/config.defaults index 68e235be..a589997b 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -72,7 +72,9 @@ ECDSA = SHA256:L71Q91yHwmHPYYkJMDgj0xmUuw16qFOhJbBr1mzsiOI RSA = SHA256:Ju+yWiMb/2O+gKQ9RJCDqvRg7l+Q95KFAeqM5sr6l2s [auth] -valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 sk-ssh-ecdsa@openssh.com sk-ssh-ed25519@openssh.com +; For U2F key prefixes, see the following documentation from openssh: +; https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.u2f +valid-keytypes = ssh-rsa ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 ssh-ed25519 sk-ecdsa-sha2-nistp256@openssh.com sk-ecdsa-sha2-nistp256-cert-v01@openssh.com sk-ssh-ed25519@openssh.com sk-ssh-ed25519-cert-v01@openssh.com username-regex = [a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$ git-serve-cmd = /usr/bin/aurweb-git-serve ssh-options = restrict From e558e979ff481148bb903ca21c7659b7ca43208d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 24 Nov 2021 21:28:49 -0800 Subject: [PATCH 1154/1891] fix(fastapi): check ssh key prefixes against configured valid-keytypes Signed-off-by: Kevin Morris --- aurweb/util.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index b95fc6a3..62575c71 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -84,9 +84,8 @@ def valid_pgp_fingerprint(fp): def valid_ssh_pubkey(pk): - valid_prefixes = ("ssh-rsa", "ecdsa-sha2-nistp256", - "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", - "ssh-ed25519") + valid_prefixes = aurweb.config.get("auth", "valid-keytypes") + valid_prefixes = set(valid_prefixes.split(" ")) has_valid_prefix = False for prefix in valid_prefixes: From b98159d5b90fe0fd609a694257bb25a4fa579b0e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 16:43:29 -0800 Subject: [PATCH 1155/1891] change(docker): use step-ca for CA + cert generation Signed-off-by: Kevin Morris --- Dockerfile | 3 +- docker-compose.aur-dev.yml | 3 +- docker-compose.override.yml | 14 --- docker-compose.yml | 14 ++- docker/ca-entrypoint.sh | 163 +++++++++++++++++++++--------- docker/health/ca.sh | 2 + docker/nginx-entrypoint.sh | 2 +- docker/scripts/install-deps.sh | 2 +- docker/scripts/run-ca.sh | 7 ++ docker/scripts/update-step-config | 19 ++++ 10 files changed, 160 insertions(+), 69 deletions(-) create mode 100755 docker/health/ca.sh create mode 100755 docker/scripts/run-ca.sh create mode 100755 docker/scripts/update-step-config diff --git a/Dockerfile b/Dockerfile index 3c12cbf8..9af78c3e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,8 @@ RUN /install-deps.sh # Copy Docker scripts COPY ./docker /docker -COPY ./docker/scripts/*.sh /usr/local/bin/ +COPY ./docker/scripts/* /usr/local/bin/ + # Copy over all aurweb files. COPY . /aurweb diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 4b522e56..f27b2b19 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -70,9 +70,8 @@ services: nginx: restart: always volumes: - - ${GIT_DATA_DIR}:/aurweb/aur.git - data:/data - - logs:/var/log/nginx + - archives:/var/lib/aurweb/archives - smartgit_run:/var/run/smartgit volumes: diff --git a/docker-compose.override.yml b/docker-compose.override.yml index eae12a92..8c74f947 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -6,10 +6,6 @@ services: mariadb: condition: service_healthy - ca: - volumes: - - ./data:/data - git: volumes: - git_data:/aurweb/aur.git @@ -45,13 +41,3 @@ services: - ./web/template:/aurweb/web/template - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates - - nginx: - volumes: - - git_data:/aurweb/aur.git - - ./data:/data - - ./logs:/var/log/nginx - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - smartgit_run:/var/run/smartgit diff --git a/docker-compose.yml b/docker-compose.yml index acb5dd65..c1f93319 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,7 +29,16 @@ services: image: aurweb:latest init: true entrypoint: /docker/ca-entrypoint.sh - command: echo + command: /docker/scripts/run-ca.sh + healthcheck: + test: "bash /docker/health/run-ca.sh" + interval: 3s + tmpfs: + - /tmp + volumes: + - ./docker:/docker + - ./data:/data + - step:/root/.step memcached: image: aurweb:latest @@ -261,7 +270,9 @@ services: php-fpm: condition: service_healthy volumes: + - ./data:/data - archives:/var/lib/aurweb/archives + - smartgit_run:/var/run/smartgit sharness: image: aurweb:latest @@ -347,3 +358,4 @@ volumes: git_data: {} # Share aurweb/aur.git smartgit_run: {} archives: {} + step: {} diff --git a/docker/ca-entrypoint.sh b/docker/ca-entrypoint.sh index 42d8bd14..d03efbbc 100755 --- a/docker/ca-entrypoint.sh +++ b/docker/ca-entrypoint.sh @@ -1,58 +1,123 @@ #!/bin/bash +# Initialize step-ca and request certificates from it. +# +# Certificates created by this service are meant to be used in +# aurweb Docker's nginx service. +# +# If ./data/root_ca.crt is present, CA generation is skipped. +# If ./data/${host}.{cert,key}.pem is available, host certificate +# generation is skipped. +# set -eou pipefail -if [ -f /data/ca.root.pem ]; then - echo "Already have certs, skipping." - exit 0 +# /data-based variables. +DATA_DIR="/data" +DATA_ROOT_CA="$DATA_DIR/root_ca.crt" +DATA_CERT="$DATA_DIR/localhost.cert.pem" +DATA_CERT_KEY="$DATA_DIR/localhost.key.pem" + +# Host certificates requested from the CA (separated by spaces). +DATA_CERT_HOSTS='localhost' + +# Local step paths and CA configuration values. +STEP_DIR="$(step-cli path)" +STEP_CA_CONFIG="$STEP_DIR/config/ca.json" +STEP_CA_ADDR='127.0.0.1:8443' +STEP_CA_URL='https://localhost:8443' +STEP_CA_PROVISIONER='admin@localhost' + +# Password file used for both --password-file and --provisioner-password-file. +STEP_PASSWD_FILE="$STEP_DIR/password.txt" + +# Hostnames supported by the CA. +STEP_CA_NAME='aurweb' +STEP_CA_DNS='localhost' + +make_password() { + # Create a random 20-length password and write it to $1. + openssl rand -hex 20 > $1 +} + +setup_step_ca() { + # Cleanup and setup step ca configuration. + rm -rf $STEP_DIR/* + + # Initialize `step` + make_password "$STEP_PASSWD_FILE" + step-cli ca init \ + --name="$STEP_CA_NAME" \ + --dns="$STEP_CA_DNS" \ + --address="$STEP_CA_ADDR" \ + --password-file="$STEP_PASSWD_FILE" \ + --provisioner="$STEP_CA_PROVISIONER" \ + --provisioner-password-file="$STEP_PASSWD_FILE" \ + --with-ca-url="$STEP_CA_URL" + + # Update ca.json max TLS certificate duration to a year. + update-step-config "$STEP_CA_CONFIG" + + # Install root_ca.crt as read/writable to /data/root_ca.crt. + install -m666 "$STEP_DIR/certs/root_ca.crt" "$DATA_ROOT_CA" +} + +start_step_ca() { + # Start the step-ca web server. + step-ca "$STEP_CA_CONFIG" \ + --password-file="$STEP_PASSWD_FILE" & + until printf "" 2>>/dev/null >>/dev/tcp/127.0.0.1/8443; do + sleep 1 + done +} + +kill_step_ca() { + # Stop the step-ca web server. + killall step-ca >/dev/null 2>&1 || /bin/true +} + +install_step_ca() { + # Install step-ca certificate authority to the system. + step-cli certificate install "$STEP_DIR/certs/root_ca.crt" +} + +step_cert_request() { + # Request a certificate from the step ca. + step-cli ca certificate \ + --not-after=8800h \ + --provisioner="$STEP_CA_PROVISIONER" \ + --provisioner-password-file="$STEP_PASSWD_FILE" \ + $1 $2 $3 + chmod 666 /data/${1}.*.pem +} + +if [ ! -f $DATA_ROOT_CA ]; then + setup_step_ca + install_step_ca fi -# Generate a new 2048-bit RSA key for the Root CA. -openssl genrsa -des3 -out /data/ca.key -passout pass:devca 2048 +# For all hosts separated by spaces in $DATA_CERT_HOSTS, perform a check +# for their existence in /data and react accordingly. +for host in $DATA_CERT_HOSTS; do + if [ -f /data/${host}.cert.pem ] && [ -f /data/${host}.key.pem ]; then + # Found an override. Move on to running the service after + # printing a notification to the user. + echo "Found '${host}.{cert,key}.pem' override, skipping..." + echo -n "Note: If you need to regenerate certificates, run " + echo '`rm -f data/*.{cert,key}.pem` before starting this service.' + exec "$@" + else + # Otherwise, we had a missing cert or key, so remove both. + rm -f /data/${host}.cert.pem + rm -f /data/${host}.key.pem + fi +done -# Request and self-sign a new Root CA certificate, using -# the RSA key. Output Root CA PEM-format certificate and key: -# /data/ca.root.pem and /data/ca.key.pem -openssl req -x509 -new -nodes -sha256 -days 1825 \ - -passin pass:devca \ - -subj "/C=US/ST=California/L=Authority/O=aurweb/CN=localhost" \ - -in /data/ca.key -out /data/ca.root.pem -keyout /data/ca.key.pem +start_step_ca +for host in $DATA_CERT_HOSTS; do + step_cert_request $host /data/${host}.cert.pem /data/${host}.key.pem +done +kill_step_ca -# Generate a new 2048-bit RSA key for a localhost server. -openssl genrsa -out /data/localhost.key 2048 - -# Generate a Certificate Signing Request (CSR) for the localhost server -# using the RSA key we generated above. -openssl req -new -key /data/localhost.key -passout pass:devca \ - -subj "/C=US/ST=California/L=Server/O=aurweb/CN=localhost" \ - -out /data/localhost.csr - -# Get our CSR signed by our Root CA PEM-formatted certificate and key -# to produce a fresh /data/localhost.cert.pem PEM-formatted certificate. -openssl x509 -req -in /data/localhost.csr \ - -CA /data/ca.root.pem -CAkey /data/ca.key.pem \ - -CAcreateserial \ - -out /data/localhost.cert.pem \ - -days 825 -sha256 \ - -passin pass:devca \ - -extfile /docker/localhost.ext - -# Convert RSA key to a PEM-formatted key: /data/localhost.key.pem -openssl rsa -in /data/localhost.key -text > /data/localhost.key.pem - -# At the end here, our notable certificates and keys are: -# - /data/ca.root.pem -# - /data/ca.key.pem -# - /data/localhost.key.pem -# - /data/localhost.cert.pem -# -# When running a server which uses the localhost certificate, a chain -# should be used, starting with localhost.cert.pem: -# - cat /data/localhost.cert.pem /data/ca.root.pem > localhost.chain.pem -# -# The Root CA (ca.root.pem) should be imported into browsers or -# ca-certificates on machines wishing to verify localhost. -# - -chmod 666 /data/* +# Set permissions to /data to rwx for everybody. +chmod 777 /data exec "$@" diff --git a/docker/health/ca.sh b/docker/health/ca.sh new file mode 100755 index 00000000..3e4bbe8e --- /dev/null +++ b/docker/health/ca.sh @@ -0,0 +1,2 @@ + +exec printf "" 2>>/dev/null >>/dev/tcp/127.0.0.1/8443 diff --git a/docker/nginx-entrypoint.sh b/docker/nginx-entrypoint.sh index 6b9a6954..1527cda7 100755 --- a/docker/nginx-entrypoint.sh +++ b/docker/nginx-entrypoint.sh @@ -15,7 +15,7 @@ if [ -f "$CERT" ]; then cp -vf "$CERT" "$DEST_CERT" cp -vf "$KEY" "$DEST_KEY" else - cat /data/localhost.cert.pem /data/ca.root.pem > "$DEST_CERT" + cat /data/localhost.cert.pem /data/root_ca.crt > "$DEST_CERT" cp -vf /data/localhost.key.pem "$DEST_KEY" fi diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index ad0157f8..372b6e0c 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -9,6 +9,6 @@ pacman -Syu --noconfirm --noprogressbar \ mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \ php php-fpm memcached php-memcached python-pip pyalpm \ python-srcinfo curl libeatmydata cronie python-poetry \ - python-poetry-core + python-poetry-core step-cli step-ca exec "$@" diff --git a/docker/scripts/run-ca.sh b/docker/scripts/run-ca.sh new file mode 100755 index 00000000..1ef45ef7 --- /dev/null +++ b/docker/scripts/run-ca.sh @@ -0,0 +1,7 @@ +#!/bin/bash +STEP_DIR="$(step-cli path)" +STEP_PASSWD_FILE="$STEP_DIR/password.txt" +STEP_CA_CONFIG="$STEP_DIR/config/ca.json" + +# Start the step-ca https server. +exec step-ca "$STEP_CA_CONFIG" --password-file="$STEP_PASSWD_FILE" diff --git a/docker/scripts/update-step-config b/docker/scripts/update-step-config new file mode 100755 index 00000000..bbdb2680 --- /dev/null +++ b/docker/scripts/update-step-config @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +import json +import sys + +CA_CONFIG = sys.argv[1] + +with open(CA_CONFIG) as f: + data = json.load(f) + +if "authority" not in data: + data["authority"] = dict() +if "claims" not in data["authority"]: + data["authority"]["claims"] = dict() + +# One year of certificate duration. +data["authority"]["claims"] = {"maxTLSCertDuration": "8800h"} + +with open(CA_CONFIG, "w") as f: + json.dump(data, f) From 759f18ea75a5581cefa5ca6fe323bdc56944f47a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 16:44:56 -0800 Subject: [PATCH 1156/1891] feat: add aurweb-config console script This can be used to update config values for the entirety of a config. When config values are set through this tool, $AUR_CONFIG is overridden with a copy of the config file with all sections and options found in $AUR_CONFIG + $AUR_CONFIG_DEFAULTS. Signed-off-by: Kevin Morris --- aurweb/config.py | 12 ++++ aurweb/scripts/config.py | 61 +++++++++++++++++++ pyproject.toml | 1 + test/test_config.py | 125 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 aurweb/scripts/config.py diff --git a/aurweb/config.py b/aurweb/config.py index aa111f15..0d0cf676 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -1,6 +1,8 @@ import configparser import os +from typing import Any + # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. @@ -52,3 +54,13 @@ def getint(section, option, fallback=None): def get_section(section): if section in _get_parser().sections(): return _get_parser()[section] + + +def replace_key(section: str, option: str, value: Any) -> Any: + _get_parser().set(section, option, value) + + +def save() -> None: + aur_config = os.environ.get("AUR_CONFIG", "/etc/aurweb/config") + with open(aur_config, "w") as fp: + _get_parser().write(fp) diff --git a/aurweb/scripts/config.py b/aurweb/scripts/config.py new file mode 100644 index 00000000..dd7bcf5f --- /dev/null +++ b/aurweb/scripts/config.py @@ -0,0 +1,61 @@ +""" +Perform an action on the aurweb config. + +When AUR_CONFIG_IMMUTABLE is set, the `set` action is noop. +""" +import argparse +import configparser +import os +import sys + +import aurweb.config + + +def action_set(args): + # If AUR_CONFIG_IMMUTABLE is defined, skip out on config setting. + if os.environ.get("AUR_CONFIG_IMMUTABLE", 0): + return + + if not args.value: + print("error: no value provided", file=sys.stderr) + return + + try: + aurweb.config.replace_key(args.section, args.option, args.value) + aurweb.config.save() + except configparser.NoSectionError: + print("error: no section found", file=sys.stderr) + + +def action_get(args): + try: + value = aurweb.config.get(args.section, args.option) + print(value) + except (configparser.NoSectionError): + print("error: no section found", file=sys.stderr) + except (configparser.NoOptionError): + print("error: no option found", file=sys.stderr) + + +def parse_args(): + fmt_cls = argparse.RawDescriptionHelpFormatter + actions = ["get", "set"] + parser = argparse.ArgumentParser( + description="aurweb configuration tool", + formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80)) + parser.add_argument("action", choices=actions, help="script action") + parser.add_argument("section", help="config section") + parser.add_argument("option", help="config option") + parser.add_argument("value", nargs="?", default=0, + help="config option value") + return parser.parse_args() + + +def main(): + args = parse_args() + action = getattr(sys.modules[__name__], f"action_{args.action}") + return action(args) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 8d14735a..82c439bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,3 +108,4 @@ aurweb-popupdate = "aurweb.scripts.popupdate:main" aurweb-rendercomment = "aurweb.scripts.rendercomment:main" aurweb-tuvotereminder = "aurweb.scripts.tuvotereminder:main" aurweb-usermaint = "aurweb.scripts.usermaint:main" +aurweb-config = "aurweb.scripts.config:main" diff --git a/test/test_config.py b/test/test_config.py index 4f10b60d..7e9d24b5 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -1,4 +1,16 @@ +import configparser +import io +import os +import re + +from unittest import mock + from aurweb import config +from aurweb.scripts.config import main + + +def noop(*args, **kwargs) -> None: + return def test_get(): @@ -11,3 +23,116 @@ def test_getboolean(): def test_getint(): assert config.getint("options", "disable_http_login") == 0 + + +def mock_config_get(): + config_get = config.get + + def _mock_config_get(section: str, option: str): + if section == "options": + if option == "salt_rounds": + return "666" + return config_get(section, option) + return _mock_config_get + + +@mock.patch("aurweb.config.get", side_effect=mock_config_get()) +def test_config_main_get(get: str): + stdout = io.StringIO() + args = ["aurweb-config", "get", "options", "salt_rounds"] + with mock.patch("sys.argv", args): + with mock.patch("sys.stdout", stdout): + main() + + expected = "666" + assert stdout.getvalue().strip() == expected + + +@mock.patch("aurweb.config.get", side_effect=mock_config_get()) +def test_config_main_get_unknown_section(get: str): + stderr = io.StringIO() + args = ["aurweb-config", "get", "fakeblahblah", "salt_rounds"] + with mock.patch("sys.argv", args): + with mock.patch("sys.stderr", stderr): + main() + + # With an invalid section, we should get a usage error. + expected = r'^error: no section found$' + assert re.match(expected, stderr.getvalue().strip()) + + +@mock.patch("aurweb.config.get", side_effect=mock_config_get()) +def test_config_main_get_unknown_option(get: str): + stderr = io.StringIO() + args = ["aurweb-config", "get", "options", "fakeblahblah"] + with mock.patch("sys.argv", args): + with mock.patch("sys.stderr", stderr): + main() + + expected = "error: no option found" + assert stderr.getvalue().strip() == expected + + +@mock.patch("aurweb.config.save", side_effect=noop) +def test_config_main_set(save: None): + data = None + + def mock_replace_key(section: str, option: str, value: str) -> None: + nonlocal data + data = value + + args = ["aurweb-config", "set", "options", "salt_rounds", "666"] + with mock.patch("sys.argv", args): + with mock.patch("aurweb.config.replace_key", + side_effect=mock_replace_key): + main() + + expected = "666" + assert data == expected + + +def test_config_main_set_immutable(): + data = None + + def mock_replace_key(section: str, option: str, value: str) -> None: + nonlocal data + data = value + + args = ["aurweb-config", "set", "options", "salt_rounds", "666"] + with mock.patch.dict(os.environ, {"AUR_CONFIG_IMMUTABLE": "1"}): + with mock.patch("sys.argv", args): + with mock.patch("aurweb.config.replace_key", + side_effect=mock_replace_key): + main() + + expected = None + assert data == expected + + +def test_config_main_set_invalid_value(): + stderr = io.StringIO() + + args = ["aurweb-config", "set", "options", "salt_rounds"] + with mock.patch("sys.argv", args): + with mock.patch("sys.stderr", stderr): + main() + + expected = "error: no value provided" + assert stderr.getvalue().strip() == expected + + +@mock.patch("aurweb.config.save", side_effect=noop) +def test_config_main_set_unknown_section(save: None): + stderr = io.StringIO() + + def mock_replace_key(section: str, option: str, value: str) -> None: + raise configparser.NoSectionError(section=section) + + args = ["aurweb-config", "set", "options", "salt_rounds", "666"] + with mock.patch("sys.argv", args): + with mock.patch("sys.stderr", stderr): + with mock.patch("aurweb.config.replace_key", + side_effect=mock_replace_key): + main() + + assert stderr.getvalue().strip() == "error: no section found" From d658627e992dd0fc16e5e2aa76d52dda76de4380 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 19:10:59 -0800 Subject: [PATCH 1157/1891] fix(fastapi): don't redirect to login on authed /login Closes #184 Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 055f0dca..c5a99419 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -24,13 +24,13 @@ async def login_template(request: Request, next: str, errors: list = None): @router.get("/login", response_class=HTMLResponse) -@auth_required(False) +@auth_required(False, login=False) async def login_get(request: Request, next: str = "/"): return await login_template(request, next) @router.post("/login", response_class=HTMLResponse) -@auth_required(False) +@auth_required(False, login=False) async def login_post(request: Request, next: str = Form(...), user: str = Form(default=str()), From 47feb72f48cb0d1c36fffff39160e48b8e870488 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 20:04:26 -0800 Subject: [PATCH 1158/1891] fix(fastapi): fix SessionID (and ResetKey) generation Signed-off-by: Kevin Morris --- aurweb/db.py | 29 +---------------------------- aurweb/models/session.py | 9 ++++----- aurweb/models/user.py | 4 ++++ aurweb/routers/accounts.py | 5 +++-- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/aurweb/db.py b/aurweb/db.py index b8b49e40..70ad58d1 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -24,42 +24,15 @@ DRIVERS = { "mysql": "mysql+mysqldb" } -# Global introspected object memo. -introspected = dict() - # Some types we don't get access to in this module. Base = NewType("Base", "aurweb.models.declarative_base.Base") -def make_random_value(table: str, column: str): +def make_random_value(table: str, column: str, length: int): """ Generate a unique, random value for a string column in a table. - This can be used to generate for example, session IDs that - align with the properties of the database column with regards - to size. - - Internally, we use SQLAlchemy introspection to look at column - to decide which length to use for random string generation. - :return: A unique string that is not in the database """ - global introspected - - # Make sure column is converted to a string for memo interaction. - scolumn = str(column) - - # If the target column is not yet introspected, store its introspection - # object into our global `introspected` memo. - if scolumn not in introspected: - from sqlalchemy import inspect - target_column = scolumn.split('.')[-1] - col = list(filter(lambda c: c.name == target_column, - inspect(table).columns))[0] - introspected[scolumn] = col - - col = introspected.get(scolumn) - length = col.type.length - string = aurweb.util.make_random_string(length) while query(table).filter(column == string).first(): string = aurweb.util.make_random_string(length) diff --git a/aurweb/models/session.py b/aurweb/models/session.py index 96f88d85..7a06eddc 100644 --- a/aurweb/models/session.py +++ b/aurweb/models/session.py @@ -1,8 +1,7 @@ from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship -from aurweb import schema -from aurweb.db import make_random_value, query +from aurweb import db, schema from aurweb.models.declarative import Base from aurweb.models.user import User as _User @@ -19,8 +18,8 @@ class Session(Base): def __init__(self, **kwargs): super().__init__(**kwargs) - user_exists = query( - query(_User).filter(_User.ID == self.UsersID).exists() + user_exists = db.query( + db.query(_User).filter(_User.ID == self.UsersID).exists() ).scalar() if not user_exists: raise IntegrityError( @@ -31,4 +30,4 @@ class Session(Base): def generate_unique_sid(): - return make_random_value(Session, Session.SessionID) + return db.make_random_value(Session, Session.SessionID, 32) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 43910db9..03634a36 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -230,3 +230,7 @@ class User(Base): def __repr__(self): return "" % ( self.ID, str(self.AccountType), self.Username) + + +def generate_unique_resetkey(): + return db.make_random_value(User, User.ResetKey, 32) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 02a7f4c6..ddee1764 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -16,6 +16,7 @@ from aurweb.exceptions import ValidationError from aurweb.l10n import get_translator_for_request from aurweb.models import account_type as at from aurweb.models.ssh_pub_key import get_fingerprint +from aurweb.models.user import generate_unique_resetkey from aurweb.scripts.notify import ResetKeyNotification, WelcomeNotification from aurweb.templates import make_context, make_variable_context, render_template from aurweb.users import update, validate @@ -92,7 +93,7 @@ async def passreset_post(request: Request, status_code=HTTPStatus.SEE_OTHER) # If we got here, we continue with issuing a resetkey for the user. - resetkey = db.make_random_value(models.User, models.User.ResetKey) + resetkey = generate_unique_resetkey() with db.begin(): user.ResetKey = resetkey @@ -291,7 +292,7 @@ async def account_register_post(request: Request, # Create a user with no password with a resetkey, then send # an email off about it. - resetkey = db.make_random_value(models.User, models.User.ResetKey) + resetkey = generate_unique_resetkey() # By default, we grab the User account type to associate with. atype = db.query(models.AccountType, From 7b0d664bc0c4d9f75abc2ed659e14ca5f66dba1c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 21:03:24 -0800 Subject: [PATCH 1159/1891] fix(docker): reorg ./data mounts Signed-off-by: Kevin Morris --- docker-compose.aur-dev.yml | 3 ++- docker-compose.override.yml | 11 +++++++++++ docker-compose.yml | 10 ---------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index f27b2b19..0b91dd93 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -4,6 +4,7 @@ services: ca: volumes: - data:/data + - step:/root/.step memcached: restart: always @@ -22,7 +23,7 @@ services: - SSH_CMDLINE=${SSH_CMDLINE:-ssh ssh://aur@localhost:2222} volumes: - ${GIT_DATA_DIR}:/aurweb/aur.git - - ./data:/aurweb/data + - data:/aurweb/data smartgit: restart: always diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 8c74f947..1e466730 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,6 +1,11 @@ version: "3.8" services: + ca: + volumes: + - ./data:/data + - step:/root/.step + mariadb_init: depends_on: mariadb: @@ -41,3 +46,9 @@ services: - ./web/template:/aurweb/web/template - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates + + nginx: + volumes: + - ./data:/data + - archives:/var/lib/aurweb/archives + - smartgit_run:/var/run/smartgit diff --git a/docker-compose.yml b/docker-compose.yml index c1f93319..5d8f7d78 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,12 +33,6 @@ services: healthcheck: test: "bash /docker/health/run-ca.sh" interval: 3s - tmpfs: - - /tmp - volumes: - - ./docker:/docker - - ./data:/data - - step:/root/.step memcached: image: aurweb:latest @@ -269,10 +263,6 @@ services: condition: service_healthy php-fpm: condition: service_healthy - volumes: - - ./data:/data - - archives:/var/lib/aurweb/archives - - smartgit_run:/var/run/smartgit sharness: image: aurweb:latest From 199622c53f65260670868ca3712d2f9e30de4461 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 21:35:35 -0800 Subject: [PATCH 1160/1891] fix(fastapi): refresh records when fetching updated packages Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 7c48f4e4..55af3a34 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -167,6 +167,7 @@ def updated_packages(limit: int = 0, for pkg in query: # For each Package returned by the query, append a dict # containing Package columns we're interested in. + db.refresh(pkg) packages.append({ "Name": pkg.Name, "Version": pkg.Version, From 0e938209afbf25748cf95bd27b32ad2814f8d77b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 22:34:15 -0800 Subject: [PATCH 1161/1891] feat(aurweb-config): add unset action and simplify Signed-off-by: Kevin Morris --- aurweb/config.py | 7 ++++- aurweb/scripts/config.py | 38 ++++++++++++++++---------- test/test_config.py | 59 +++++++++++++++++++++++++++++++++------- 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 0d0cf676..86f8ddf7 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -56,8 +56,13 @@ def get_section(section): return _get_parser()[section] -def replace_key(section: str, option: str, value: Any) -> Any: +def unset_option(section: str, option: str) -> None: + _get_parser().remove_option(section, option) + + +def set_option(section: str, option: str, value: Any) -> None: _get_parser().set(section, option, value) + return value def save() -> None: diff --git a/aurweb/scripts/config.py b/aurweb/scripts/config.py index dd7bcf5f..e7c91dd1 100644 --- a/aurweb/scripts/config.py +++ b/aurweb/scripts/config.py @@ -11,35 +11,43 @@ import sys import aurweb.config -def action_set(args): +def do_action(func, *args, save: bool = True): # If AUR_CONFIG_IMMUTABLE is defined, skip out on config setting. - if os.environ.get("AUR_CONFIG_IMMUTABLE", 0): + if int(os.environ.get("AUR_CONFIG_IMMUTABLE", 0)): return + value = None + try: + value = func(*args) + if save: + aurweb.config.save() + except configparser.NoSectionError: + print("error: no section found", file=sys.stderr) + except configparser.NoOptionError: + print("error: no option found", file=sys.stderr) + + return value + + +def action_set(args): if not args.value: print("error: no value provided", file=sys.stderr) return + do_action(aurweb.config.set_option, args.section, args.option, args.value) - try: - aurweb.config.replace_key(args.section, args.option, args.value) - aurweb.config.save() - except configparser.NoSectionError: - print("error: no section found", file=sys.stderr) + +def action_unset(args): + do_action(aurweb.config.unset_option, args.section, args.option) def action_get(args): - try: - value = aurweb.config.get(args.section, args.option) - print(value) - except (configparser.NoSectionError): - print("error: no section found", file=sys.stderr) - except (configparser.NoOptionError): - print("error: no option found", file=sys.stderr) + val = do_action(aurweb.config.get, args.section, args.option, save=False) + print(val) def parse_args(): fmt_cls = argparse.RawDescriptionHelpFormatter - actions = ["get", "set"] + actions = ["get", "set", "unset"] parser = argparse.ArgumentParser( description="aurweb configuration tool", formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80)) diff --git a/test/test_config.py b/test/test_config.py index 7e9d24b5..b78f477c 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -5,6 +5,8 @@ import re from unittest import mock +import py + from aurweb import config from aurweb.scripts.config import main @@ -77,32 +79,69 @@ def test_config_main_get_unknown_option(get: str): def test_config_main_set(save: None): data = None - def mock_replace_key(section: str, option: str, value: str) -> None: + def set_option(section: str, option: str, value: str) -> None: nonlocal data data = value args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch("sys.argv", args): - with mock.patch("aurweb.config.replace_key", - side_effect=mock_replace_key): + with mock.patch("aurweb.config.set_option", side_effect=set_option): main() expected = "666" assert data == expected +def test_config_main_set_real(tmpdir: py.path.local): + """ + Test a real set_option path. + """ + + # Copy AUR_CONFIG to {tmpdir}/aur.config. + aur_config = os.environ.get("AUR_CONFIG") + tmp_aur_config = os.path.join(str(tmpdir), "aur.config") + with open(aur_config) as f: + with open(tmp_aur_config, "w") as o: + o.write(f.read()) + + # Force reset the parser. This should NOT be done publicly. + config._parser = None + + value = 666 + args = ["aurweb-config", "set", "options", "fake-key", str(value)] + with mock.patch.dict("os.environ", {"AUR_CONFIG": tmp_aur_config}): + with mock.patch("sys.argv", args): + # Run aurweb.config.main(). + main() + + # Update the config; fake-key should be set. + config.rehash() + assert config.getint("options", "fake-key") == 666 + + # Restore config back to normal. + args = ["aurweb-config", "unset", "options", "fake-key"] + with mock.patch("sys.argv", args): + main() + + # Return the config back to normal. + config.rehash() + + # fake-key should no longer exist. + assert config.getint("options", "fake-key") is None + + def test_config_main_set_immutable(): data = None - def mock_replace_key(section: str, option: str, value: str) -> None: + def mock_set_option(section: str, option: str, value: str) -> None: nonlocal data data = value args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch.dict(os.environ, {"AUR_CONFIG_IMMUTABLE": "1"}): with mock.patch("sys.argv", args): - with mock.patch("aurweb.config.replace_key", - side_effect=mock_replace_key): + with mock.patch("aurweb.config.set_option", + side_effect=mock_set_option): main() expected = None @@ -121,18 +160,18 @@ def test_config_main_set_invalid_value(): assert stderr.getvalue().strip() == expected -@mock.patch("aurweb.config.save", side_effect=noop) +@ mock.patch("aurweb.config.save", side_effect=noop) def test_config_main_set_unknown_section(save: None): stderr = io.StringIO() - def mock_replace_key(section: str, option: str, value: str) -> None: + def mock_set_option(section: str, option: str, value: str) -> None: raise configparser.NoSectionError(section=section) args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch("sys.argv", args): with mock.patch("sys.stderr", stderr): - with mock.patch("aurweb.config.replace_key", - side_effect=mock_replace_key): + with mock.patch("aurweb.config.set_option", + side_effect=mock_set_option): main() assert stderr.getvalue().strip() == "error: no section found" From f3efc18b508d505f242426911ce22231dc182e05 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 22:42:12 -0800 Subject: [PATCH 1162/1891] feat(docker): force test db configuration Signed-off-by: Kevin Morris --- docker/test-mysql-entrypoint.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docker/test-mysql-entrypoint.sh b/docker/test-mysql-entrypoint.sh index a46b2572..262577a6 100755 --- a/docker/test-mysql-entrypoint.sh +++ b/docker/test-mysql-entrypoint.sh @@ -5,4 +5,16 @@ set -eou pipefail cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config +# We use the root user for testing in Docker. +# The test user must be able to create databases and drop them. +aurweb-config set database user 'root' +aurweb-config set database host 'localhost' +aurweb-config set database socket '/var/run/mysqld/mysqld.sock' + +# Remove possibly problematic configuration options. +# We depend on the database socket within Docker and +# being run as the root user. +aurweb-config unset database password +aurweb-config unset database port + exec "$@" From 0726a08677b589136dbfce1d59990c9c744e56b0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 17:42:04 -0800 Subject: [PATCH 1163/1891] fix(docker): remove sqlite scripts Signed-off-by: Kevin Morris --- docker/scripts/setup-sqlite.sh | 7 ------- docker/test-sqlite-entrypoint.sh | 16 ---------------- 2 files changed, 23 deletions(-) delete mode 100755 docker/scripts/setup-sqlite.sh delete mode 100755 docker/test-sqlite-entrypoint.sh diff --git a/docker/scripts/setup-sqlite.sh b/docker/scripts/setup-sqlite.sh deleted file mode 100755 index e0b8de50..00000000 --- a/docker/scripts/setup-sqlite.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# Run an sqlite test. This script really just prepares sqlite -# tests by deleting any existing databases so the test can -# initialize cleanly. -DB_NAME="$(grep 'name =' conf/config.sqlite | sed -r 's/^name = (.+)$/\1/')" -rm -vf $DB_NAME -exec "$@" diff --git a/docker/test-sqlite-entrypoint.sh b/docker/test-sqlite-entrypoint.sh deleted file mode 100755 index c26f6735..00000000 --- a/docker/test-sqlite-entrypoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -set -eou pipefail - -DB_BACKEND="sqlite" -DB_NAME="aurweb.sqlite3" - -# Create an SQLite config from the default dev config. -cp -vf conf/config.dev conf/config.sqlite -cp -vf conf/config.defaults conf/config.sqlite.defaults - -# Modify it for SQLite. -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config.sqlite -sed -ri "s/^(backend) = .+/\1 = ${DB_BACKEND}/" conf/config.sqlite -sed -ri "s/^(name) = .+/\1 = ${DB_NAME}/" conf/config.sqlite - -exec "$@" From 5b350bc3614f29794bdfb710893b76b3d40ba96d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 18:46:42 -0800 Subject: [PATCH 1164/1891] change(docker): use aurweb-config to update AUR_CONFIG Signed-off-by: Kevin Morris --- docker/fastapi-entrypoint.sh | 26 ++++++++++++++------------ docker/git-entrypoint.sh | 22 +++++++++------------- docker/mariadb-init-entrypoint.sh | 5 +++-- docker/php-entrypoint.sh | 21 +++++++++++---------- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index 9df6382d..d1519bf8 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -5,23 +5,25 @@ set -eou pipefail cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config -# Change database user/password. -sed -ri "s/^;?(user) = .*$/\1 = aur/" conf/config -sed -ri "s/^;?(password) = .*$/\1 = aur/" conf/config +# Setup database. +aurweb-config set database user 'aur' +aurweb-config set database password 'aur' +aurweb-config set database host 'localhost' +aurweb-config set database socket '/var/lib/mysqld/mysqld.sock' +aurweb-config unset database port -sed -ri "s;^(aur_location) = .+;\1 = ${AURWEB_FASTAPI_PREFIX};" conf/config - -# Setup Redis for FastAPI. -sed -ri 's/^(cache) = .+/\1 = redis/' conf/config -sed -ri 's|^(redis_address) = .+|\1 = redis://redis|' conf/config +# Setup some other options. +aurweb-config set options cache 'redis' +aurweb-config set options redis_address 'redis://redis' +aurweb-config set options aur_location "$AURWEB_FASTAPI_PREFIX" +aurweb-config set options git_clone_uri_anon "${AURWEB_FASTAPI_PREFIX}/%s.git" +aurweb-config set options git_clone_uri_priv "${AURWEB_SSHD_PREFIX}/%s.git" if [ ! -z ${COMMIT_HASH+x} ]; then - sed -ri "s/^;?(commit_hash) =.*$/\1 = $COMMIT_HASH/" conf/config + aurweb-config set devel commit_hash "$COMMIT_HASH" fi -sed -ri "s|^(git_clone_uri_anon) = .+|\1 = ${AURWEB_FASTAPI_PREFIX}/%s.git|" conf/config.defaults -sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ${AURWEB_SSHD_PREFIX}/%s.git|" conf/config.defaults - +# Setup prometheus directory. rm -rf $PROMETHEUS_MULTIPROC_DIR mkdir -p $PROMETHEUS_MULTIPROC_DIR diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index cfa1879b..96f4d112 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -42,20 +42,16 @@ EOF cp -vf conf/config.dev $AUR_CONFIG sed -i "s;YOUR_AUR_ROOT;$(pwd);g" $AUR_CONFIG -sed -ri "s/^;?(user) = .*$/\1 = aur/" $AUR_CONFIG -sed -ri "s/^;?(password) = .*$/\1 = aur/" $AUR_CONFIG +# Setup database. +aurweb-config set database user 'aur' +aurweb-config set database password 'aur' +aurweb-config set database host 'localhost' +aurweb-config set database socket '/var/lib/mysqld/mysqld.sock' +aurweb-config unset database port -AUR_CONFIG_DEFAULTS="${AUR_CONFIG}.defaults" - -if [[ "$AUR_CONFIG_DEFAULTS" != "/aurweb/conf/config.defaults" ]]; then - cp -vf conf/config.defaults $AUR_CONFIG_DEFAULTS -fi - -# Set some defaults needed for pathing and ssh uris. -sed -ri "s|^(repo-path) = .+|\1 = /aurweb/aur.git/|" $AUR_CONFIG_DEFAULTS - -# SSH_CMDLINE can be provided via override in docker-compose.aur-dev.yml. -sed -ri "s|^(ssh-cmdline) = .+$|\1 = ${SSH_CMDLINE}|" $AUR_CONFIG_DEFAULTS +# Setup some other options. +aurweb-config set serve repo-path '/aurweb/aur.git/' +aurweb-config set serve ssh-cmdline "$SSH_CMDLINE" # Setup SSH Keys. ssh-keygen -A diff --git a/docker/mariadb-init-entrypoint.sh b/docker/mariadb-init-entrypoint.sh index 6df98e4f..64e66a0f 100755 --- a/docker/mariadb-init-entrypoint.sh +++ b/docker/mariadb-init-entrypoint.sh @@ -4,8 +4,9 @@ set -eou pipefail # Setup a config for our mysql db. cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config -sed -ri "s/^;?(user) = .*$/\1 = aur/g" conf/config -sed -ri "s/^;?(password) = .*$/\1 = aur/g" conf/config + +aurweb-config set database user 'aur' +aurweb-config set database password 'aur' python -m aurweb.initdb 2>/dev/null || /bin/true diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index 05b76408..1756718d 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -9,17 +9,18 @@ done cp -vf conf/config.dev conf/config sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config -# Change database user/password. -sed -ri "s/^;?(user) = .*$/\1 = aur/" conf/config -sed -ri "s/^;?(password) = .*$/\1 = aur/" conf/config +# Setup database. +aurweb-config set database user 'aur' +aurweb-config set database password 'aur' +aurweb-config set database host 'localhost' +aurweb-config set database socket '/var/lib/mysqld/mysqld.sock' +aurweb-config unset database port -# Enable memcached. -sed -ri 's/^(cache) = .+$/\1 = memcache/' conf/config - -# Setup various location configurations. -sed -ri "s;^(aur_location) = .+;\1 = ${AURWEB_PHP_PREFIX};" conf/config -sed -ri "s|^(git_clone_uri_anon) = .+|\1 = ${AURWEB_PHP_PREFIX}/%s.git|" conf/config.defaults -sed -ri "s|^(git_clone_uri_priv) = .+|\1 = ${AURWEB_SSHD_PREFIX}/%s.git|" conf/config.defaults +# Setup some other options. +aurweb-config set options cache 'memcache' +aurweb-config set options aur_location "$AURWEB_PHP_PREFIX" +aurweb-config set options git_clone_uri_anon "${AURWEB_PHP_PREFIX}/%s.git" +aurweb-config set options git_clone_uri_priv "${AURWEB_SSHD_PREFIX}/%s.git" # Listen on :9000. sed -ri 's/^(listen).*/\1 = 0.0.0.0:9000/' /etc/php/php-fpm.d/www.conf From 84beacd4274d27bf039b691a25cae7758f7d9ac2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 18:57:08 -0800 Subject: [PATCH 1165/1891] fix(docker): supply AUR_CONFIG_IMMUTABLE for docker-compose Signed-off-by: Kevin Morris --- docker-compose.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 5d8f7d78..401193d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -72,6 +72,8 @@ services: mariadb_init: image: aurweb:latest init: true + environment: + - AUR_CONFIG_IMMUTABLE=${AUR_CONFIG_IMMUTABLE:-0} entrypoint: /docker/mariadb-init-entrypoint.sh command: echo "MariaDB tables initialized." volumes: @@ -104,6 +106,7 @@ services: environment: - AUR_CONFIG=/aurweb/conf/config - SSH_CMDLINE=${SSH_CMDLINE:-ssh ssh://aur@localhost:2222} + - AUR_CONFIG_IMMUTABLE=${AUR_CONFIG_IMMUTABLE:-0} entrypoint: /docker/git-entrypoint.sh command: /docker/scripts/run-sshd.sh ports: @@ -190,6 +193,7 @@ services: - AUR_CONFIG=/aurweb/conf/config - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} + - AUR_CONFIG_IMMUTABLE=${AUR_CONFIG_IMMUTABLE:-0} entrypoint: /docker/php-entrypoint.sh command: /docker/scripts/run-php.sh healthcheck: @@ -220,6 +224,7 @@ services: - AURWEB_FASTAPI_PREFIX=${AURWEB_FASTAPI_PREFIX} - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - PROMETHEUS_MULTIPROC_DIR=/tmp_prometheus + - AUR_CONFIG_IMMUTABLE=${AUR_CONFIG_IMMUTABLE:-0} entrypoint: /docker/fastapi-entrypoint.sh command: /docker/scripts/run-fastapi.sh "${FASTAPI_BACKEND}" healthcheck: From 343a306bb8dff96e3d7ab3227646f09f4125255d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 23:14:39 -0800 Subject: [PATCH 1166/1891] change(docker): setup AUR_CONFIG in Dockerfile Signed-off-by: Kevin Morris --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index 9af78c3e..38d3ca0e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,10 @@ COPY . /aurweb # Working directory is aurweb root @ /aurweb. WORKDIR /aurweb +# Copy initial config to conf/config. +RUN cp -vf conf/config.dev conf/config +RUN sed -i "s;YOUR_AUR_ROOT;/aurweb;g" conf/config + # Install Python dependencies. RUN /docker/scripts/install-python-deps.sh From dbeebd3b01044d508531476dc99571890e150065 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 23:15:19 -0800 Subject: [PATCH 1167/1891] change(fastapi): setup live database in mariadb-init-entrypoint.sh Centralize database setup there and remove all copying of config.dev from the entrypoint scripts (the Dockerfile now does it). Signed-off-by: Kevin Morris --- docker/cron-entrypoint.sh | 28 +++++++++++++++++++++++----- docker/fastapi-entrypoint.sh | 10 +--------- docker/git-entrypoint.sh | 10 +--------- docker/mariadb-init-entrypoint.sh | 12 ++++++++---- docker/php-entrypoint.sh | 10 +--------- docker/test-mysql-entrypoint.sh | 4 ---- 6 files changed, 34 insertions(+), 40 deletions(-) diff --git a/docker/cron-entrypoint.sh b/docker/cron-entrypoint.sh index d4173eaf..5b69ab19 100755 --- a/docker/cron-entrypoint.sh +++ b/docker/cron-entrypoint.sh @@ -1,12 +1,30 @@ #!/bin/bash set -eou pipefail -# Prepare AUR_CONFIG. -cp -vf conf/config.dev conf/config -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config +# Setup the DB. +NO_INITDB=1 /docker/mariadb-init-entrypoint.sh -# Create directories we need. -mkdir -p /aurweb/aurblup +# Create aurblup's directory. +AURBLUP_DIR="/aurweb/aurblup/" +mkdir -p $AURBLUP_DIR + +# Setup aurblup config for Docker. +AURBLUP_DBS='core extra community multilib testing community-testing' +AURBLUP_SERVER='https://mirrors.kernel.org/archlinux/%s/os/x86_64' +aurweb-config set aurblup db-path "$AURBLUP_DIR" +aurweb-config set aurblup sync-dbs "$AURBLUP_DBS" +aurweb-config set aurblup server "$AURBLUP_SERVER" + +# Setup mkpkglists config for Docker. +ARCHIVE_DIR='/var/lib/aurweb/archives' +aurweb-config set mkpkglists archivedir "$ARCHIVE_DIR" +aurweb-config set mkpkglists packagesfile "$ARCHIVE_DIR/packages.gz" +aurweb-config set mkpkglists packagesmetafile \ + "$ARCHIVE_DIR/packages-meta-v1.json.gz" +aurweb-config set mkpkglists packagesmetaextfile \ + "$ARCHIVE_DIR/packages-meta-ext-v1.json.gz" +aurweb-config set mkpkglists pkgbasefile "$ARCHIVE_DIR/pkgbase.gz" +aurweb-config set mkpkglists userfile "$ARCHIVE_DIR/users.gz" # Install the cron configuration. cp /docker/config/aurweb-cron /etc/cron.d/aurweb-cron diff --git a/docker/fastapi-entrypoint.sh b/docker/fastapi-entrypoint.sh index d1519bf8..c6597313 100755 --- a/docker/fastapi-entrypoint.sh +++ b/docker/fastapi-entrypoint.sh @@ -1,16 +1,8 @@ #!/bin/bash set -eou pipefail -# Setup a config for our mysql db. -cp -vf conf/config.dev conf/config -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config - # Setup database. -aurweb-config set database user 'aur' -aurweb-config set database password 'aur' -aurweb-config set database host 'localhost' -aurweb-config set database socket '/var/lib/mysqld/mysqld.sock' -aurweb-config unset database port +NO_INITDB=1 /docker/mariadb-init-entrypoint.sh # Setup some other options. aurweb-config set options cache 'redis' diff --git a/docker/git-entrypoint.sh b/docker/git-entrypoint.sh index 96f4d112..c9f1ec30 100755 --- a/docker/git-entrypoint.sh +++ b/docker/git-entrypoint.sh @@ -38,16 +38,8 @@ Match User aur AcceptEnv AUR_OVERWRITE EOF -# Setup a config for our mysql db. -cp -vf conf/config.dev $AUR_CONFIG -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" $AUR_CONFIG - # Setup database. -aurweb-config set database user 'aur' -aurweb-config set database password 'aur' -aurweb-config set database host 'localhost' -aurweb-config set database socket '/var/lib/mysqld/mysqld.sock' -aurweb-config unset database port +NO_INITDB=1 /docker/mariadb-init-entrypoint.sh # Setup some other options. aurweb-config set serve repo-path '/aurweb/aur.git/' diff --git a/docker/mariadb-init-entrypoint.sh b/docker/mariadb-init-entrypoint.sh index 64e66a0f..74980031 100755 --- a/docker/mariadb-init-entrypoint.sh +++ b/docker/mariadb-init-entrypoint.sh @@ -2,12 +2,16 @@ set -eou pipefail # Setup a config for our mysql db. -cp -vf conf/config.dev conf/config -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config - +aurweb-config set database name 'aurweb' aurweb-config set database user 'aur' aurweb-config set database password 'aur' +aurweb-config set database host 'localhost' +aurweb-config set database socket '/var/run/mysqld/mysqld.sock' +aurweb-config unset database port + +if [ ! -z ${NO_INITDB+x} ]; then + exec "$@" +fi python -m aurweb.initdb 2>/dev/null || /bin/true - exec "$@" diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh index 1756718d..dc1a91de 100755 --- a/docker/php-entrypoint.sh +++ b/docker/php-entrypoint.sh @@ -5,16 +5,8 @@ for archive in packages pkgbase users packages-meta-v1.json packages-meta-ext-v1 ln -vsf /var/lib/aurweb/archives/${archive}.gz /aurweb/web/html/${archive}.gz done -# Setup a config for our mysql db. -cp -vf conf/config.dev conf/config -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config - # Setup database. -aurweb-config set database user 'aur' -aurweb-config set database password 'aur' -aurweb-config set database host 'localhost' -aurweb-config set database socket '/var/lib/mysqld/mysqld.sock' -aurweb-config unset database port +NO_INITDB=1 /docker/mariadb-init-entrypoint.sh # Setup some other options. aurweb-config set options cache 'memcache' diff --git a/docker/test-mysql-entrypoint.sh b/docker/test-mysql-entrypoint.sh index 262577a6..1bf85b54 100755 --- a/docker/test-mysql-entrypoint.sh +++ b/docker/test-mysql-entrypoint.sh @@ -1,10 +1,6 @@ #!/bin/bash set -eou pipefail -# Setup a config for our mysql db. -cp -vf conf/config.dev conf/config -sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config - # We use the root user for testing in Docker. # The test user must be able to create databases and drop them. aurweb-config set database user 'root' From 3a65e33abe01e6ef6ae1a246062b0fe5ed2c8f09 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 23:34:05 -0800 Subject: [PATCH 1168/1891] fix(gitlab-ci): prepare conf/config for setup Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8980fa78..d6d49a55 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,6 +9,7 @@ variables: AUR_CONFIG: conf/config # Default MySQL config setup in before_script. DB_HOST: localhost TEST_RECURSION_LIMIT: 10000 + CURRENT_DIR: "$(pwd)" test: stage: test @@ -22,6 +23,8 @@ test: - ./docker/mariadb-entrypoint.sh - (cd '/usr' && /usr/bin/mysqld_safe --datadir='/var/lib/mysql') & - 'until : > /dev/tcp/127.0.0.1/3306; do sleep 1s; done' + - cp -v conf/config.dev conf/config + - sed -i "s;YOUR_AUR_ROOT;$(pwd);g" conf/config - ./docker/test-mysql-entrypoint.sh # Create mysql AUR_CONFIG. - make -C po all install - make -C test clean From 3efb9a57b59297fb844c75306351c2817ca2f4b0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 07:54:52 -0800 Subject: [PATCH 1169/1891] change(popupdate): converted to use aurweb.db ORM Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 9 ++-- aurweb/scripts/popupdate.py | 84 +++++++++++++++++++++++-------------- test/test_rpc.py | 5 +-- 3 files changed, 57 insertions(+), 41 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 23f44ee3..eab75e5a 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -908,8 +908,7 @@ async def pkgbase_vote(request: Request, name: str): VoteTS=now) # Update NumVotes/Popularity. - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - popupdate.run_single(conn, pkgbase) + popupdate.run_single(pkgbase) return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @@ -929,8 +928,7 @@ async def pkgbase_unvote(request: Request, name: str): db.delete(vote) # Update NumVotes/Popularity. - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - popupdate.run_single(conn, pkgbase) + popupdate.run_single(pkgbase) return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @@ -1473,8 +1471,7 @@ async def pkgbase_merge_post(request: Request, name: str, pkgbase_merge_instance(request, pkgbase, target) # Run popupdate on the target. - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - popupdate.run_single(conn, target) + popupdate.run_single(target) if not next: next = f"/pkgbase/{target.Name}" diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index db4ba170..e2d008f2 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -1,51 +1,71 @@ #!/usr/bin/env python3 from datetime import datetime +from typing import List -import aurweb.db +from sqlalchemy import and_, func +from sqlalchemy.sql.functions import coalesce +from sqlalchemy.sql.functions import sum as _sum + +from aurweb import db +from aurweb.models import PackageBase, PackageVote -def run_single(conn, pkgbase): +def run_variable(pkgbases: List[PackageBase] = []) -> None: + """ + Update popularity on a list of PackageBases. + + If no PackageBase is included, we update the popularity + of every PackageBase in the database. + + :param pkgbases: List of PackageBase instances + """ + now = int(datetime.utcnow().timestamp()) + + # NumVotes subquery. + votes_subq = db.get_session().query( + func.count("*") + ).select_from(PackageVote).filter( + PackageVote.PackageBaseID == PackageBase.ID + ) + + # Popularity subquery. + pop_subq = db.get_session().query( + coalesce(_sum(func.pow(0.98, (now - PackageVote.VoteTS) / 86400)), 0.0), + ).select_from(PackageVote).filter( + and_(PackageVote.PackageBaseID == PackageBase.ID, + PackageVote.VoteTS.isnot(None)) + ) + + with db.begin(): + query = db.query(PackageBase) + + ids = set() + if pkgbases: + ids = {pkgbase.ID for pkgbase in pkgbases} + query = query.filter(PackageBase.ID.in_(ids)) + + query.update({ + "NumVotes": votes_subq.scalar_subquery(), + "Popularity": pop_subq.scalar_subquery() + }) + + +def run_single(pkgbase: PackageBase) -> None: """ A single popupdate. The given pkgbase instance will be refreshed after the database update is done. NOTE: This function is compatible only with aurweb FastAPI. - :param conn: db.Connection[Executor] :param pkgbase: Instance of db.PackageBase """ - - conn.execute("UPDATE PackageBases SET NumVotes = (" - "SELECT COUNT(*) FROM PackageVotes " - "WHERE PackageVotes.PackageBaseID = PackageBases.ID) " - "WHERE PackageBases.ID = ?", [pkgbase.ID]) - - now = int(datetime.utcnow().timestamp()) - conn.execute("UPDATE PackageBases SET Popularity = (" - "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " - "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " - "PackageBases.ID AND NOT VoteTS IS NULL) WHERE " - "PackageBases.ID = ?", [now, pkgbase.ID]) - - conn.commit() - conn.close() - aurweb.db.refresh(pkgbase) + run_variable([pkgbase]) + db.refresh(pkgbase) def main(): - conn = aurweb.db.Connection() - conn.execute("UPDATE PackageBases SET NumVotes = (" - "SELECT COUNT(*) FROM PackageVotes " - "WHERE PackageVotes.PackageBaseID = PackageBases.ID)") - - now = int(datetime.utcnow().timestamp()) - conn.execute("UPDATE PackageBases SET Popularity = (" - "SELECT COALESCE(SUM(POWER(0.98, (? - VoteTS) / 86400)), 0.0) " - "FROM PackageVotes WHERE PackageVotes.PackageBaseID = " - "PackageBases.ID AND NOT VoteTS IS NULL)", [now]) - - conn.commit() - conn.close() + db.get_engine() + run_variable() if __name__ == '__main__': diff --git a/test/test_rpc.py b/test/test_rpc.py index a4cdb5da..b61a7e4e 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -9,7 +9,7 @@ import pytest from fastapi.testclient import TestClient from redis.client import Pipeline -from aurweb import asgi, config, db, scripts +from aurweb import asgi, config, scripts from aurweb.db import begin, create, query from aurweb.models.account_type import AccountType from aurweb.models.dependency_type import DependencyType @@ -187,8 +187,7 @@ def setup(db_test): PackageBase=pkgbase1, VoteTS=5000) - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - scripts.popupdate.run_single(conn, pkgbase1) + scripts.popupdate.run_single(pkgbase1) @pytest.fixture From 29989b7fdbb6f8a5bacfd6edef48cb66b483b722 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 08:04:33 -0800 Subject: [PATCH 1170/1891] change(aurblup): converted to use aurweb.db ORM Introduces: - aurweb.testing.alpm.AlpmDatabase - Used to mock up and manage a remote repository. - templates/testing/alpm_package.j2 - Used to generate a single ALPM package desc. - Removed aurblup sharness test Signed-off-by: Kevin Morris --- aurweb/scripts/aurblup.py | 50 ++++++++++------- aurweb/templates.py | 5 ++ aurweb/testing/alpm.py | 87 ++++++++++++++++++++++++++++++ aurweb/util.py | 17 ++++++ templates/testing/alpm_package.j2 | 16 ++++++ test/t2400-aurblup.t | 53 ------------------ test/test_aurblup.py | 90 +++++++++++++++++++++++++++++++ 7 files changed, 246 insertions(+), 72 deletions(-) create mode 100644 aurweb/testing/alpm.py create mode 100644 templates/testing/alpm_package.j2 delete mode 100755 test/t2400-aurblup.t create mode 100644 test/test_aurblup.py diff --git a/aurweb/scripts/aurblup.py b/aurweb/scripts/aurblup.py index e32937ce..9c9059ec 100755 --- a/aurweb/scripts/aurblup.py +++ b/aurweb/scripts/aurblup.py @@ -4,30 +4,34 @@ import re import pyalpm +from sqlalchemy import and_ + import aurweb.config -import aurweb.db -db_path = aurweb.config.get('aurblup', 'db-path') -sync_dbs = aurweb.config.get('aurblup', 'sync-dbs').split(' ') -server = aurweb.config.get('aurblup', 'server') +from aurweb import db, util +from aurweb.models import OfficialProvider -def main(): +def _main(force: bool = False): blacklist = set() providers = set() repomap = dict() + db_path = aurweb.config.get("aurblup", "db-path") + sync_dbs = aurweb.config.get('aurblup', 'sync-dbs').split(' ') + server = aurweb.config.get('aurblup', 'server') + h = pyalpm.Handle("/", db_path) for sync_db in sync_dbs: repo = h.register_syncdb(sync_db, pyalpm.SIG_DATABASE_OPTIONAL) repo.servers = [server.replace("%s", sync_db)] t = h.init_transaction() - repo.update(False) + repo.update(force) t.release() for pkg in repo.pkgcache: blacklist.add(pkg.name) - [blacklist.add(x) for x in pkg.replaces] + util.apply_all(pkg.replaces, blacklist.add) providers.add((pkg.name, pkg.name)) repomap[(pkg.name, pkg.name)] = repo.name for provision in pkg.provides: @@ -35,21 +39,29 @@ def main(): providers.add((pkg.name, provisionname)) repomap[(pkg.name, provisionname)] = repo.name - conn = aurweb.db.Connection() + with db.begin(): + old_providers = set( + db.query(OfficialProvider).with_entities( + OfficialProvider.Name.label("Name"), + OfficialProvider.Provides.label("Provides") + ).distinct().order_by("Name").all() + ) - cur = conn.execute("SELECT Name, Provides FROM OfficialProviders") - oldproviders = set(cur.fetchall()) + for name, provides in old_providers.difference(providers): + db.delete_all(db.query(OfficialProvider).filter( + and_(OfficialProvider.Name == name, + OfficialProvider.Provides == provides) + )) - for pkg, provides in oldproviders.difference(providers): - conn.execute("DELETE FROM OfficialProviders " - "WHERE Name = ? AND Provides = ?", [pkg, provides]) - for pkg, provides in providers.difference(oldproviders): - repo = repomap[(pkg, provides)] - conn.execute("INSERT INTO OfficialProviders (Name, Repo, Provides) " - "VALUES (?, ?, ?)", [pkg, repo, provides]) + for name, provides in providers.difference(old_providers): + repo = repomap.get((name, provides)) + db.create(OfficialProvider, Name=name, + Repo=repo, Provides=provides) - conn.commit() - conn.close() + +def main(force: bool = False): + db.get_engine() + _main(force) if __name__ == '__main__': diff --git a/aurweb/templates.py b/aurweb/templates.py index 0039535d..a7102ae1 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -125,6 +125,11 @@ async def make_variable_context(request: Request, title: str, next: str = None): return context +def base_template(path: str): + templates = copy.copy(_env) + return templates.get_template(path) + + def render_raw_template(request: Request, path: str, context: dict): """ Render a Jinja2 multi-lingual template with some context. """ # Create a deep copy of our jinja2 _environment. The _environment in diff --git a/aurweb/testing/alpm.py b/aurweb/testing/alpm.py new file mode 100644 index 00000000..6015d859 --- /dev/null +++ b/aurweb/testing/alpm.py @@ -0,0 +1,87 @@ +import hashlib +import os +import re +import shutil +import subprocess + +from typing import List + +from aurweb import logging, util +from aurweb.templates import base_template + +logger = logging.get_logger(__name__) + + +class AlpmDatabase: + """ + Fake libalpm database management class. + + This class can be used to add or remove packages from a + test repository. + """ + repo = "test" + + def __init__(self, database_root: str): + self.root = database_root + self.local = os.path.join(self.root, "local") + self.remote = os.path.join(self.root, "remote") + self.repopath = os.path.join(self.remote, self.repo) + + # Make directories. + os.makedirs(self.local) + os.makedirs(self.remote) + + def _get_pkgdir(self, pkgname: str, pkgver: str, repo: str) -> str: + pkgfile = f"{pkgname}-{pkgver}-1" + pkgdir = os.path.join(self.remote, repo, pkgfile) + os.makedirs(pkgdir) + return pkgdir + + def add(self, pkgname: str, pkgver: str, arch: str, + provides: List[str] = []) -> None: + context = { + "pkgname": pkgname, + "pkgver": pkgver, + "arch": arch, + "provides": provides + } + template = base_template("testing/alpm_package.j2") + pkgdir = self._get_pkgdir(pkgname, pkgver, self.repo) + desc = os.path.join(pkgdir, "desc") + with open(desc, "w") as f: + f.write(template.render(context)) + + self.compile() + + def remove(self, pkgname: str): + files = os.listdir(self.repopath) + logger.info(f"Files: {files}") + expr = "^" + pkgname + r"-[0-9.]+-1$" + logger.info(f"Expression: {expr}") + to_delete = filter(lambda e: re.match(expr, e), files) + + for target in to_delete: + logger.info(f"Deleting {target}") + path = os.path.join(self.repopath, target) + shutil.rmtree(path) + + self.compile() + + def clean(self) -> None: + db_file = os.path.join(self.remote, "test.db") + try: + os.remove(db_file) + except Exception: + pass + + def compile(self) -> None: + self.clean() + cmdline = ["bash", "-c", "bsdtar -czvf ../test.db *"] + proc = subprocess.run(cmdline, cwd=self.repopath) + assert proc.returncode == 0, \ + f"Bad return code while creating alpm database: {proc.returncode}" + + # Print out the md5 hash value of the new test.db. + test_db = os.path.join(self.remote, "test.db") + db_hash = util.file_hash(test_db, hashlib.md5) + logger.debug(f"{test_db}: {db_hash}") diff --git a/aurweb/util.py b/aurweb/util.py index 62575c71..bf2d6e4b 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -176,3 +176,20 @@ def strtobool(value: str) -> bool: if isinstance(value, str): return _strtobool(value) return value + + +def file_hash(filepath: str, hash_function: Callable) -> str: + """ + Return a hash of filepath contents using `hash_function`. + + `hash_function` can be any one of the hashlib module's hash + functions which implement the `hexdigest()` method -- e.g. + hashlib.sha1, hashlib.md5, etc. + + :param filepath: Path to file you want to hash + :param hash_function: hashlib hash function + :return: hash_function(filepath_content).hexdigest() + """ + with open(filepath, "rb") as f: + hash_ = hash_function(f.read()) + return hash_.hexdigest() diff --git a/templates/testing/alpm_package.j2 b/templates/testing/alpm_package.j2 new file mode 100644 index 00000000..0e741729 --- /dev/null +++ b/templates/testing/alpm_package.j2 @@ -0,0 +1,16 @@ +%FILENAME% +{{ pkgname }}-{{ pkgver }}-{{ arch }}.pkg.tar.xz + +%NAME% +{{ pkgname }} + +%VERSION% +{{ pkgver }}-1 + +%ARCH% +{{ arch }} + +{% if provides %} +%PROVIDES% +{{ provides | join("\n") }} +{% endif %} diff --git a/test/t2400-aurblup.t b/test/t2400-aurblup.t deleted file mode 100755 index 42da6791..00000000 --- a/test/t2400-aurblup.t +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -test_description='aurblup tests' - -. "$(dirname "$0")/setup.sh" - -test_expect_success 'Test official provider update script.' ' - mkdir -p remote/test/foobar-1.0-1 && - cat <<-EOD >remote/test/foobar-1.0-1/desc && - %FILENAME% - foobar-1.0-any.pkg.tar.xz - - %NAME% - foobar - - %VERSION% - 1.0-1 - - %ARCH% - any - EOD - mkdir -p remote/test/foobar2-1.0-1 && - cat <<-EOD >remote/test/foobar2-1.0-1/desc && - %FILENAME% - foobar2-1.0-any.pkg.tar.xz - - %NAME% - foobar2 - - %VERSION% - 1.0-1 - - %ARCH% - any - - %PROVIDES% - foobar3 - foobar4 - EOD - ( cd remote/test && bsdtar -czf ../test.db * ) && - mkdir sync && - cover "$AURBLUP" && - cat <<-EOD >expected && - foobar|test|foobar - foobar2|test|foobar2 - foobar2|test|foobar3 - foobar2|test|foobar4 - EOD - echo "SELECT Name, Repo, Provides FROM OfficialProviders ORDER BY Provides;" | sqlite3 aur.db >actual && - test_cmp actual expected -' - -test_done diff --git a/test/test_aurblup.py b/test/test_aurblup.py new file mode 100644 index 00000000..7eaae556 --- /dev/null +++ b/test/test_aurblup.py @@ -0,0 +1,90 @@ +import tempfile + +from unittest import mock + +import pytest + +from aurweb import config, db +from aurweb.models import OfficialProvider +from aurweb.scripts import aurblup +from aurweb.testing.alpm import AlpmDatabase + + +@pytest.fixture +def tempdir() -> str: + with tempfile.TemporaryDirectory() as name: + yield name + + +@pytest.fixture +def alpm_db(tempdir: str) -> AlpmDatabase: + yield AlpmDatabase(tempdir) + + +@pytest.fixture(autouse=True) +def setup(db_test, alpm_db: AlpmDatabase, tempdir: str) -> None: + config_get = config.get + + def mock_config_get(section: str, key: str) -> str: + value = config_get(section, key) + if section == "aurblup": + if key == "db-path": + return alpm_db.local + elif key == "server": + return f'file://{alpm_db.remote}' + elif key == "sync-dbs": + return alpm_db.repo + return value + + with mock.patch("aurweb.config.get", side_effect=mock_config_get): + config.rehash() + yield + config.rehash() + + +def test_aurblup(alpm_db: AlpmDatabase): + # Test that we can add a package. + alpm_db.add("pkg", "1.0", "x86_64", provides=["pkg2", "pkg3"]) + alpm_db.add("pkg2", "2.0", "x86_64") + aurblup.main() + + # Test that the package got added to the database. + for name in ("pkg", "pkg2"): + pkg = db.query(OfficialProvider).filter( + OfficialProvider.Name == name).first() + assert pkg is not None + + # Test that we can remove the package. + alpm_db.remove("pkg") + + # Run aurblup again with forced repository update. + aurblup.main(True) + + # Expect that the database got updated accordingly. + pkg = db.query(OfficialProvider).filter( + OfficialProvider.Name == "pkg").first() + assert pkg is None + pkg2 = db.query(OfficialProvider).filter( + OfficialProvider.Name == "pkg2").first() + assert pkg2 is not None + + +def test_aurblup_cleanup(alpm_db: AlpmDatabase): + # Add a package and sync up the database. + alpm_db.add("pkg", "1.0", "x86_64", provides=["pkg2", "pkg3"]) + aurblup.main() + + # Now, let's insert an OfficialPackage that doesn't exist, + # then exercise the old provider deletion path. + with db.begin(): + db.create(OfficialProvider, Name="fake package", + Repo="test", Provides="package") + + # Run aurblup again. + aurblup.main() + + # Expect that the fake package got deleted because it's + # not in alpm_db anymore. + providers = db.query(OfficialProvider).filter( + OfficialProvider.Name == "fake package").all() + assert len(providers) == 0 From c59acbf6d6594971b3953807256e102dd2e740e9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 21 Nov 2021 22:37:31 -0800 Subject: [PATCH 1171/1891] add noop testing utility Signed-off-by: Kevin Morris --- aurweb/testing/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py index 8261051d..99671d69 100644 --- a/aurweb/testing/__init__.py +++ b/aurweb/testing/__init__.py @@ -62,3 +62,7 @@ def setup_test_db(*args): aurweb.db.get_session().execute(f"DELETE FROM {table}") aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 1") aurweb.db.get_session().expunge_all() + + +def noop(*args, **kwargs) -> None: + return From 29c2d0de6b83a2287ffdb885d9b55aa63b1d4792 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 21 Nov 2021 00:47:48 -0800 Subject: [PATCH 1172/1891] change(mkpkglists): converted to use aurweb.db ORM - Improved speed dramatically - Removed mkpkglists sharness Signed-off-by: Kevin Morris --- aurweb/benchmark.py | 21 +++ aurweb/scripts/mkpkglists.py | 282 +++++++++++++++++++++-------------- test/t2100-mkpkglists.t | 65 -------- test/test_mkpkglists.py | 215 ++++++++++++++++++++++++++ 4 files changed, 403 insertions(+), 180 deletions(-) create mode 100644 aurweb/benchmark.py delete mode 100755 test/t2100-mkpkglists.t create mode 100644 test/test_mkpkglists.py diff --git a/aurweb/benchmark.py b/aurweb/benchmark.py new file mode 100644 index 00000000..7086fb08 --- /dev/null +++ b/aurweb/benchmark.py @@ -0,0 +1,21 @@ +from datetime import datetime + + +class Benchmark: + def __init__(self): + self.start() + + def _timestamp(self) -> float: + """ Generate a timestamp. """ + return float(datetime.utcnow().timestamp()) + + def start(self) -> int: + """ Start a benchmark. """ + self.current = self._timestamp() + return self.current + + def end(self): + """ Return the diff between now - start(). """ + n = self._timestamp() - self.current + self.current = float(0) + return n diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 307b2b12..92de7931 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -23,23 +23,28 @@ import os import sys from collections import defaultdict -from decimal import Decimal +from typing import Any, Dict import orjson +from sqlalchemy import literal, orm + import aurweb.config -import aurweb.db + +from aurweb import db, logging, models, util +from aurweb.benchmark import Benchmark +from aurweb.models import Package, PackageBase, User + +logger = logging.get_logger("aurweb.scripts.mkpkglists") archivedir = aurweb.config.get("mkpkglists", "archivedir") os.makedirs(archivedir, exist_ok=True) -packagesfile = aurweb.config.get('mkpkglists', 'packagesfile') -packagesmetafile = aurweb.config.get('mkpkglists', 'packagesmetafile') -packagesmetaextfile = aurweb.config.get('mkpkglists', 'packagesmetaextfile') - -pkgbasefile = aurweb.config.get('mkpkglists', 'pkgbasefile') - -userfile = aurweb.config.get('mkpkglists', 'userfile') +PACKAGES = aurweb.config.get('mkpkglists', 'packagesfile') +META = aurweb.config.get('mkpkglists', 'packagesmetafile') +META_EXT = aurweb.config.get('mkpkglists', 'packagesmetaextfile') +PKGBASE = aurweb.config.get('mkpkglists', 'pkgbasefile') +USERS = aurweb.config.get('mkpkglists', 'userfile') TYPE_MAP = { @@ -53,7 +58,7 @@ TYPE_MAP = { } -def get_extended_dict(query: str): +def get_extended_dict(query: orm.Query): """ Produce data in the form in a single bulk SQL query: @@ -74,61 +79,75 @@ def get_extended_dict(query: str): output[i].update(data.get(package_id)) """ - conn = aurweb.db.Connection() - - cursor = conn.execute(query) - data = defaultdict(lambda: defaultdict(list)) - for result in cursor.fetchall(): - + for result in query: pkgid = result[0] key = TYPE_MAP.get(result[1], result[1]) output = result[2] if result[3]: output += result[3] - - # In all cases, we have at least an empty License list. - if "License" not in data[pkgid]: - data[pkgid]["License"] = [] - - # In all cases, we have at least an empty Keywords list. - if "Keywords" not in data[pkgid]: - data[pkgid]["Keywords"] = [] - data[pkgid][key].append(output) - conn.close() return data def get_extended_fields(): - # Returns: [ID, Type, Name, Cond] - query = """ - SELECT PackageDepends.PackageID AS ID, DependencyTypes.Name AS Type, - PackageDepends.DepName AS Name, PackageDepends.DepCondition AS Cond - FROM PackageDepends - LEFT JOIN DependencyTypes - ON DependencyTypes.ID = PackageDepends.DepTypeID - UNION SELECT PackageRelations.PackageID AS ID, RelationTypes.Name AS Type, - PackageRelations.RelName AS Name, - PackageRelations.RelCondition AS Cond - FROM PackageRelations - LEFT JOIN RelationTypes - ON RelationTypes.ID = PackageRelations.RelTypeID - UNION SELECT PackageGroups.PackageID AS ID, 'Groups' AS Type, - Groups.Name, '' AS Cond - FROM Groups - INNER JOIN PackageGroups ON PackageGroups.GroupID = Groups.ID - UNION SELECT PackageLicenses.PackageID AS ID, 'License' AS Type, - Licenses.Name, '' as Cond - FROM Licenses - INNER JOIN PackageLicenses ON PackageLicenses.LicenseID = Licenses.ID - UNION SELECT Packages.ID AS ID, 'Keywords' AS Type, - PackageKeywords.Keyword AS Name, '' as Cond - FROM PackageKeywords - INNER JOIN Packages ON Packages.PackageBaseID = PackageKeywords.PackageBaseID - """ + subqueries = [ + # PackageDependency + db.query( + models.PackageDependency + ).join(models.DependencyType).with_entities( + models.PackageDependency.PackageID.label("ID"), + models.DependencyType.Name.label("Type"), + models.PackageDependency.DepName.label("Name"), + models.PackageDependency.DepCondition.label("Cond") + ).distinct().order_by("Name"), + + # PackageRelation + db.query( + models.PackageRelation + ).join(models.RelationType).with_entities( + models.PackageRelation.PackageID.label("ID"), + models.RelationType.Name.label("Type"), + models.PackageRelation.RelName.label("Name"), + models.PackageRelation.RelCondition.label("Cond") + ).distinct().order_by("Name"), + + # Groups + db.query(models.PackageGroup).join( + models.Group, + models.PackageGroup.GroupID == models.Group.ID + ).with_entities( + models.PackageGroup.PackageID.label("ID"), + literal("Groups").label("Type"), + models.Group.Name.label("Name"), + literal(str()).label("Cond") + ).distinct().order_by("Name"), + + # Licenses + db.query(models.PackageLicense).join( + models.License, + models.PackageLicense.LicenseID == models.License.ID + ).with_entities( + models.PackageLicense.PackageID.label("ID"), + literal("License").label("Type"), + models.License.Name.label("Name"), + literal(str()).label("Cond") + ).distinct().order_by("Name"), + + # Keywords + db.query(models.PackageKeyword).join( + models.Package, + Package.PackageBaseID == models.PackageKeyword.PackageBaseID + ).with_entities( + models.Package.ID.label("ID"), + literal("Keywords").label("Type"), + models.PackageKeyword.Keyword.label("Name"), + literal(str()).label("Cond") + ).distinct().order_by("Name") + ] + query = subqueries[0].union_all(*subqueries[1:]) return get_extended_dict(query) @@ -137,89 +156,122 @@ EXTENDED_FIELD_HANDLERS = { } -def is_decimal(column): - """ Check if an SQL column is of decimal.Decimal type. """ - if isinstance(column, Decimal): - return float(column) - return column +def as_dict(package: Package) -> Dict[str, Any]: + return { + "ID": package.ID, + "Name": package.Name, + "PackageBaseID": package.PackageBaseID, + "PackageBase": package.PackageBase, + "Version": package.Version, + "Description": package.Description, + "NumVotes": package.NumVotes, + "Popularity": float(package.Popularity), + "OutOfDate": package.OutOfDate, + "Maintainer": package.Maintainer, + "FirstSubmitted": package.FirstSubmitted, + "LastModified": package.LastModified, + } -def write_archive(archive: str, output: list): - with gzip.open(archive, "wb") as f: - f.write(b"[\n") - for i, item in enumerate(output): - f.write(orjson.dumps(item)) - if i < len(output) - 1: - f.write(b",") - f.write(b"\n") - f.write(b"]") +def _main(): + bench = Benchmark() + logger.info("Started re-creating archives, wait a while...") - -def main(): - conn = aurweb.db.Connection() - - # Query columns; copied from RPC. - columns = ("Packages.ID, Packages.Name, " - "PackageBases.ID AS PackageBaseID, " - "PackageBases.Name AS PackageBase, " - "Version, Description, URL, NumVotes, " - "Popularity, OutOfDateTS AS OutOfDate, " - "Users.UserName AS Maintainer, " - "SubmittedTS AS FirstSubmitted, " - "ModifiedTS AS LastModified") - - # Perform query. - cur = conn.execute(f"SELECT {columns} FROM Packages " - "LEFT JOIN PackageBases " - "ON PackageBases.ID = Packages.PackageBaseID " - "LEFT JOIN Users " - "ON PackageBases.MaintainerUID = Users.ID " - "WHERE PackageBases.PackagerUID IS NOT NULL") + query = db.query(Package).join( + PackageBase, + PackageBase.ID == Package.PackageBaseID + ).join( + User, + PackageBase.MaintainerUID == User.ID, + isouter=True + ).filter(PackageBase.PackagerUID.isnot(None)).with_entities( + Package.ID, + Package.Name, + PackageBase.ID.label("PackageBaseID"), + PackageBase.Name.label("PackageBase"), + Package.Version, + Package.Description, + PackageBase.NumVotes, + PackageBase.Popularity, + PackageBase.OutOfDateTS.label("OutOfDate"), + User.Username.label("Maintainer"), + PackageBase.SubmittedTS.label("FirstSubmitted"), + PackageBase.ModifiedTS.label("LastModified") + ).distinct().order_by("Name") # Produce packages-meta-v1.json.gz output = list() snapshot_uri = aurweb.config.get("options", "snapshot_uri") - for result in cur.fetchall(): - item = { - column[0]: is_decimal(result[i]) - for i, column in enumerate(cur.description) - } - item["URLPath"] = snapshot_uri % item.get("Name") - output.append(item) + gzips = { + "packages": gzip.open(PACKAGES, "wt"), + "meta": gzip.open(META, "wb"), + } - write_archive(packagesmetafile, output) + # Append list opening to the metafile. + gzips["meta"].write(b"[\n") - # Produce packages-meta-ext-v1.json.gz + # Produce packages.gz + packages-meta-ext-v1.json.gz + extended = False if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: + gzips["meta_ext"] = gzip.open(META_EXT, "wb") + # Append list opening to the meta_ext file. + gzips.get("meta_ext").write(b"[\n") f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) data = f() + extended = True - default_ = {"Groups": [], "License": [], "Keywords": []} - for i in range(len(output)): - data_ = data.get(output[i].get("ID"), default_) - output[i].update(data_) + results = query.all() + n = len(results) - 1 + for i, result in enumerate(results): + # Append to packages.gz. + gzips.get("packages").write(f"{result.Name}\n") - write_archive(packagesmetaextfile, output) + # Construct our result JSON dictionary. + item = as_dict(result) + item["URLPath"] = snapshot_uri % result.Name - # Produce packages.gz - with gzip.open(packagesfile, "wb") as f: - f.writelines([ - bytes(x.get("Name") + "\n", "UTF-8") - for x in output - ]) + # We stream out package json objects line per line, so + # we also need to include the ',' character at the end + # of package lines (excluding the last package). + suffix = b",\n" if i < n else b'\n' + + # Write out to packagesmetafile + output.append(item) + gzips.get("meta").write(orjson.dumps(output[-1]) + suffix) + + if extended: + # Write out to packagesmetaextfile. + data_ = data.get(result.ID, {}) + output[-1].update(data_) + gzips.get("meta_ext").write(orjson.dumps(output[-1]) + suffix) + + # Append the list closing to meta/meta_ext. + gzips.get("meta").write(b"]") + if extended: + gzips.get("meta_ext").write(b"]") + + # Close gzip files. + util.apply_all(gzips.values(), lambda gz: gz.close()) # Produce pkgbase.gz - with gzip.open(pkgbasefile, "w") as f: - cur = conn.execute("SELECT Name FROM PackageBases " + - "WHERE PackagerUID IS NOT NULL") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + query = db.query(PackageBase.Name).filter( + PackageBase.PackagerUID.isnot(None)).all() + with gzip.open(PKGBASE, "wt") as f: + f.writelines([f"{base.Name}\n" for i, base in enumerate(query)]) # Produce users.gz - with gzip.open(userfile, "w") as f: - cur = conn.execute("SELECT UserName FROM Users") - f.writelines([bytes(x[0] + "\n", "UTF-8") for x in cur.fetchall()]) + query = db.query(User.Username).all() + with gzip.open(USERS, "wt") as f: + f.writelines([f"{user.Username}\n" for i, user in enumerate(query)]) - conn.close() + seconds = util.number_format(bench.end(), 4) + logger.info(f"Completed in {seconds} seconds.") + + +def main(): + db.get_engine() + with db.begin(): + _main() if __name__ == '__main__': diff --git a/test/t2100-mkpkglists.t b/test/t2100-mkpkglists.t deleted file mode 100755 index d217c4f6..00000000 --- a/test/t2100-mkpkglists.t +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/sh - -test_description='mkpkglists tests' - -. "$(dirname "$0")/setup.sh" - -test_expect_success 'Test package list generation with no packages.' ' - echo "DELETE FROM Packages;" | sqlite3 aur.db && - echo "DELETE FROM PackageBases;" | sqlite3 aur.db && - cover "$MKPKGLISTS" && - test $(zcat packages.gz | wc -l) -eq 0 && - test $(zcat pkgbase.gz | wc -l) -eq 0 -' - -test_expect_success 'Test package list generation.' ' - cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, 0, 0, ""); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (2, "foobar2", 2, 0, 0, ""); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (3, "foobar3", NULL, 0, 0, ""); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (4, "foobar4", 1, 0, 0, ""); - INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (1, 1, "pkg1"); - INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (2, 1, "pkg2"); - INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (3, 1, "pkg3"); - INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (4, 2, "pkg4"); - INSERT INTO Packages (ID, PackageBaseID, Name) VALUES (5, 3, "pkg5"); - EOD - cover "$MKPKGLISTS" && - cat <<-EOD >expected && - foobar - foobar2 - foobar4 - EOD - gunzip pkgbase.gz && - sed "/^#/d" pkgbase >actual && - test_cmp actual expected && - cat <<-EOD >expected && - pkg1 - pkg2 - pkg3 - pkg4 - EOD - gunzip packages.gz && - sed "/^#/d" packages >actual && - test_cmp actual expected -' - -test_expect_success 'Test user list generation.' ' - cover "$MKPKGLISTS" && - cat <<-EOD >expected && - dev - tu - tu2 - tu3 - tu4 - user - user2 - user3 - user4 - EOD - gunzip users.gz && - sed "/^#/d" users >actual && - test_cmp actual expected -' - -test_done diff --git a/test/test_mkpkglists.py b/test/test_mkpkglists.py new file mode 100644 index 00000000..ee66e4e1 --- /dev/null +++ b/test/test_mkpkglists.py @@ -0,0 +1,215 @@ +import json + +from typing import List, Union +from unittest import mock + +import pytest + +from aurweb import config, db, util +from aurweb.models import License, Package, PackageBase, PackageDependency, PackageLicense, User +from aurweb.models.account_type import USER_ID +from aurweb.models.dependency_type import DEPENDS_ID +from aurweb.testing import noop + + +class FakeFile: + data = str() + __exit__ = noop + + def __init__(self, modes: str) -> "FakeFile": + self.modes = modes + + def __enter__(self, *args, **kwargs) -> "FakeFile": + return self + + def write(self, data: Union[str, bytes]) -> None: + if isinstance(data, bytes): + data = data.decode() + self.data += data + + def writelines(self, dataset: List[Union[str, bytes]]) -> None: + util.apply_all(dataset, self.write) + + def close(self) -> None: + return + + +class MockGzipOpen: + def __init__(self): + self.gzips = dict() + + def open(self, archive: str, modes: str): + self.gzips[archive] = FakeFile(modes) + return self.gzips.get(archive) + + def get(self, key: str) -> FakeFile: + return self.gzips.get(key) + + def __getitem__(self, key: str) -> FakeFile: + return self.get(key) + + def __contains__(self, key: str) -> bool: + return key in self.gzips + + def data(self, archive: str): + return self.get(archive).data + + +@pytest.fixture(autouse=True) +def setup(db_test): + config.rehash() + + +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create(User, Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def packages(user: User) -> List[Package]: + output = [] + with db.begin(): + lic = db.create(License, Name="GPL") + for i in range(5): + # Create the package. + pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}", + Packager=user) + pkg = db.create(Package, PackageBase=pkgbase, + Name=f"pkg_{i}") + + # Create some related records. + db.create(PackageLicense, Package=pkg, License=lic) + db.create(PackageDependency, DepTypeID=DEPENDS_ID, + Package=pkg, DepName=f"dep_{i}", + DepCondition=">=1.0") + + # Add the package to our output list. + output.append(pkg) + + # Sort output by the package name and return it. + yield sorted(output, key=lambda k: k.Name) + + +@mock.patch("os.makedirs", side_effect=noop) +def test_mkpkglists_empty(makedirs: mock.MagicMock): + gzips = MockGzipOpen() + with mock.patch("gzip.open", side_effect=gzips.open): + from aurweb.scripts import mkpkglists + mkpkglists.main() + + archives = config.get_section("mkpkglists") + archives.pop("archivedir") + archives.pop("packagesmetaextfile") + + for archive in archives.values(): + assert archive in gzips + + # Expect that packagesfile got created, but is empty because + # we have no DB records. + packages_file = archives.get("packagesfile") + assert gzips.data(packages_file) == str() + + # Expect that pkgbasefile got created, but is empty because + # we have no DB records. + users_file = archives.get("pkgbasefile") + assert gzips.data(users_file) == str() + + # Expect that userfile got created, but is empty because + # we have no DB records. + users_file = archives.get("userfile") + assert gzips.data(users_file) == str() + + # Expect that packagesmetafile got created, but is empty because + # we have no DB records; it's still a valid empty JSON list. + meta_file = archives.get("packagesmetafile") + assert gzips.data(meta_file) == "[\n]" + + +@mock.patch("sys.argv", ["mkpkglists", "--extended"]) +@mock.patch("os.makedirs", side_effect=noop) +def test_mkpkglists_extended_empty(makedirs: mock.MagicMock): + gzips = MockGzipOpen() + with mock.patch("gzip.open", side_effect=gzips.open): + from aurweb.scripts import mkpkglists + mkpkglists.main() + + archives = config.get_section("mkpkglists") + archives.pop("archivedir") + + for archive in archives.values(): + assert archive in gzips + + # Expect that packagesfile got created, but is empty because + # we have no DB records. + packages_file = archives.get("packagesfile") + assert gzips.data(packages_file) == str() + + # Expect that pkgbasefile got created, but is empty because + # we have no DB records. + users_file = archives.get("pkgbasefile") + assert gzips.data(users_file) == str() + + # Expect that userfile got created, but is empty because + # we have no DB records. + users_file = archives.get("userfile") + assert gzips.data(users_file) == str() + + # Expect that packagesmetafile got created, but is empty because + # we have no DB records; it's still a valid empty JSON list. + meta_file = archives.get("packagesmetafile") + assert gzips.data(meta_file) == "[\n]" + + # Expect that packagesmetafile got created, but is empty because + # we have no DB records; it's still a valid empty JSON list. + meta_file = archives.get("packagesmetaextfile") + assert gzips.data(meta_file) == "[\n]" + + +@mock.patch("sys.argv", ["mkpkglists", "--extended"]) +@mock.patch("os.makedirs", side_effect=noop) +def test_mkpkglists_extended(makedirs: mock.MagicMock, user: User, + packages: List[Package]): + gzips = MockGzipOpen() + with mock.patch("gzip.open", side_effect=gzips.open): + from aurweb.scripts import mkpkglists + mkpkglists.main() + + archives = config.get_section("mkpkglists") + archives.pop("archivedir") + + for archive in archives.values(): + assert archive in gzips + + # Expect that packagesfile got created, but is empty because + # we have no DB records. + packages_file = archives.get("packagesfile") + expected = "\n".join([p.Name for p in packages]) + "\n" + assert gzips.data(packages_file) == expected + + # Expect that pkgbasefile got created, but is empty because + # we have no DB records. + users_file = archives.get("pkgbasefile") + expected = "\n".join([p.PackageBase.Name for p in packages]) + "\n" + assert gzips.data(users_file) == expected + + # Expect that userfile got created, but is empty because + # we have no DB records. + users_file = archives.get("userfile") + assert gzips.data(users_file) == "test\n" + + # Expect that packagesmetafile got created, but is empty because + # we have no DB records; it's still a valid empty JSON list. + meta_file = archives.get("packagesmetafile") + data = json.loads(gzips.data(meta_file)) + assert len(data) == 5 + + # Expect that packagesmetafile got created, but is empty because + # we have no DB records; it's still a valid empty JSON list. + meta_file = archives.get("packagesmetaextfile") + data = json.loads(gzips.data(meta_file)) + assert len(data) == 5 From 8d5683d3f18004d44cb4277a67da12c0a88e7698 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 10:28:58 -0800 Subject: [PATCH 1173/1891] change(tuvotereminder): converted to use aurweb.db ORM - Removed tuvotereminder sharness test. - Added [tuvotereminder] section to config.defaults. - Added `range_start` option to config.defaults [tuvotereminder]. - Added `range_end` option to config.defaults [tuvotereminder]. Signed-off-by: Kevin Morris --- aurweb/scripts/tuvotereminder.py | 33 ++++++---- conf/config.defaults | 8 +++ test/t2200-tuvotereminder.t | 53 ---------------- test/test_tuvotereminder.py | 102 +++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 65 deletions(-) delete mode 100755 test/t2200-tuvotereminder.t create mode 100644 test/test_tuvotereminder.py diff --git a/aurweb/scripts/tuvotereminder.py b/aurweb/scripts/tuvotereminder.py index eb3874e1..5e860725 100755 --- a/aurweb/scripts/tuvotereminder.py +++ b/aurweb/scripts/tuvotereminder.py @@ -1,27 +1,36 @@ #!/usr/bin/env python3 -import subprocess -import time +from datetime import datetime + +from sqlalchemy import and_ import aurweb.config -import aurweb.db + +from aurweb import db +from aurweb.models import TUVoteInfo +from aurweb.scripts import notify notify_cmd = aurweb.config.get('notifications', 'notify-cmd') def main(): - conn = aurweb.db.Connection() + db.get_engine() - now = int(time.time()) - filter_from = now + 500 - filter_to = now + 172800 + now = int(datetime.utcnow().timestamp()) - cur = conn.execute("SELECT ID FROM TU_VoteInfo " + - "WHERE End >= ? AND End <= ?", - [filter_from, filter_to]) + start = aurweb.config.getint("tuvotereminder", "range_start") + filter_from = now + start - for vote_id in [row[0] for row in cur.fetchall()]: - subprocess.Popen((notify_cmd, 'tu-vote-reminder', str(vote_id))).wait() + end = aurweb.config.getint("tuvotereminder", "range_end") + filter_to = now + end + + query = db.query(TUVoteInfo.ID).filter( + and_(TUVoteInfo.End >= filter_from, + TUVoteInfo.End <= filter_to) + ) + for voteinfo in query: + notif = notify.TUVoteReminderNotification(voteinfo.ID) + notif.send() if __name__ == '__main__': diff --git a/conf/config.defaults b/conf/config.defaults index a589997b..082d51a5 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -121,3 +121,11 @@ commit_url = https://gitlab.archlinux.org/archlinux/aurweb/-/commits/%s ; Example deployment configuration step: ; sed -r "s/^;?(commit_hash) =.*$/\1 = $(git rev-parse HEAD)/" config ;commit_hash = 1234567 + +[tuvotereminder] +; Offsets used to determine when TUs should be reminded about +; votes that they should make. +; Reminders will be sent out for all votes that a TU has not yet +; voted on based on `now + range_start <= End <= now + range_end`. +range_start = 500 +range_end = 172800 diff --git a/test/t2200-tuvotereminder.t b/test/t2200-tuvotereminder.t deleted file mode 100755 index 2f3836de..00000000 --- a/test/t2200-tuvotereminder.t +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -test_description='tuvotereminder tests' - -. "$(dirname "$0")/setup.sh" - -test_expect_success 'Test Trusted User vote reminders.' ' - now=$(date -d now +%s) && - tomorrow=$(date -d tomorrow +%s) && - threedays=$(date -d "3 days" +%s) && - cat <<-EOD | sqlite3 aur.db && - INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (1, "Lorem ipsum.", "user", 0, $now, 0.00, 2); - INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (2, "Lorem ipsum.", "user", 0, $tomorrow, 0.00, 2); - INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (3, "Lorem ipsum.", "user", 0, $tomorrow, 0.00, 2); - INSERT INTO TU_VoteInfo (ID, Agenda, User, Submitted, End, Quorum, SubmitterID) VALUES (4, "Lorem ipsum.", "user", 0, $threedays, 0.00, 2); - EOD - >sendmail.out && - cover "$TUVOTEREMINDER" && - grep -q "Proposal 2" sendmail.out && - grep -q "Proposal 3" sendmail.out && - test_must_fail grep -q "Proposal 1" sendmail.out && - test_must_fail grep -q "Proposal 4" sendmail.out -' - -test_expect_success 'Check that only TUs who did not vote receive reminders.' ' - cat <<-EOD | sqlite3 aur.db && - INSERT INTO TU_Votes (VoteID, UserID) VALUES (1, 2); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (2, 2); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (3, 2); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (4, 2); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (1, 7); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (3, 7); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (2, 8); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (4, 8); - INSERT INTO TU_Votes (VoteID, UserID) VALUES (1, 9); - EOD - >sendmail.out && - cover "$TUVOTEREMINDER" && - cat <<-EOD >expected && - Subject: TU Vote Reminder: Proposal 2 - To: tu2@localhost - Subject: TU Vote Reminder: Proposal 2 - To: tu4@localhost - Subject: TU Vote Reminder: Proposal 3 - To: tu3@localhost - Subject: TU Vote Reminder: Proposal 3 - To: tu4@localhost - EOD - grep "^\(Subject\|To\)" sendmail.out >sendmail.parts && - test_cmp sendmail.parts expected -' - -test_done diff --git a/test/test_tuvotereminder.py b/test/test_tuvotereminder.py new file mode 100644 index 00000000..bb898e3a --- /dev/null +++ b/test/test_tuvotereminder.py @@ -0,0 +1,102 @@ +from datetime import datetime +from typing import Tuple + +import pytest + +from aurweb import config, db +from aurweb.models import TUVote, TUVoteInfo, User +from aurweb.models.account_type import TRUSTED_USER_ID +from aurweb.scripts import tuvotereminder as reminder +from aurweb.testing.email import Email + +aur_location = config.get("options", "aur_location") + + +def create_vote(user: User, voteinfo: TUVoteInfo) -> TUVote: + with db.begin(): + vote = db.create(TUVote, User=user, VoteID=voteinfo.ID) + return vote + + +def create_user(username: str, type_id: int): + with db.begin(): + user = db.create(User, AccountTypeID=type_id, Username=username, + Email=f"{username}@example.org", Passwd=str()) + return user + + +def email_pieces(voteinfo: TUVoteInfo) -> Tuple[str, str]: + """ + Return a (subject, content) tuple based on voteinfo.ID + + :param voteinfo: TUVoteInfo instance + :return: tuple(subject, content) + """ + subject = f"TU Vote Reminder: Proposal {voteinfo.ID}" + content = (f"Please remember to cast your vote on proposal {voteinfo.ID} " + f"[1]. The voting period\nends in less than 48 hours.\n\n" + f"[1] {aur_location}/tu/?id={voteinfo.ID}") + return (subject, content) + + +@pytest.fixture +def user(db_test) -> User: + yield create_user("test", TRUSTED_USER_ID) + + +@pytest.fixture +def user2() -> User: + yield create_user("test2", TRUSTED_USER_ID) + + +@pytest.fixture +def user3() -> User: + yield create_user("test3", TRUSTED_USER_ID) + + +@pytest.fixture +def voteinfo(user: User) -> TUVoteInfo: + now = int(datetime.utcnow().timestamp()) + start = config.getint("tuvotereminder", "range_start") + with db.begin(): + voteinfo = db.create(TUVoteInfo, Agenda="Lorem ipsum.", + User=user.Username, End=(now + start + 1), + Quorum=0.00, Submitter=user, Submitted=0) + yield voteinfo + + +def test_tu_vote_reminders(user: User, user2: User, user3: User, + voteinfo: TUVoteInfo): + reminder.main() + assert Email.count() == 3 + + emails = [Email(i).parse() for i in range(1, 4)] + subject, content = email_pieces(voteinfo) + expectations = [ + # (to, content) + (user.Email, subject, content), + (user2.Email, subject, content), + (user3.Email, subject, content) + ] + for i, element in enumerate(expectations): + email, subject, content = element + assert emails[i].headers.get("To") == email + assert emails[i].headers.get("Subject") == subject + assert emails[i].body == content + + +def test_tu_vote_reminders_only_unvoted(user: User, user2: User, user3: User, + voteinfo: TUVoteInfo): + # Vote with user2 and user3; leaving only user to be notified. + create_vote(user2, voteinfo) + create_vote(user3, voteinfo) + + reminder.main() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + + subject, content = email_pieces(voteinfo) + assert email.headers.get("Subject") == subject + assert email.body == content From d097799b34e5392f577db28920f8fb27b35602f3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 10:51:44 -0800 Subject: [PATCH 1174/1891] change(usermaint): converted to use aurweb.db ORM - Removed usermaint sharness test Signed-off-by: Kevin Morris --- aurweb/scripts/usermaint.py | 34 ++++++++++++------- test/t2700-usermaint.t | 49 --------------------------- test/test_usermaint.py | 67 +++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 61 deletions(-) delete mode 100755 test/t2700-usermaint.t create mode 100644 test/test_usermaint.py diff --git a/aurweb/scripts/usermaint.py b/aurweb/scripts/usermaint.py index 1621d410..aad3e8de 100755 --- a/aurweb/scripts/usermaint.py +++ b/aurweb/scripts/usermaint.py @@ -1,21 +1,31 @@ #!/usr/bin/env python3 -import time +from datetime import datetime -import aurweb.db +from sqlalchemy import update + +from aurweb import db +from aurweb.models import User + + +def _main(): + limit_to = int(datetime.utcnow().timestamp()) - 86400 * 7 + + update_ = update(User).where( + User.LastLogin < limit_to + ).values(LastLoginIPAddress=None) + db.get_session().execute(update_) + + update_ = update(User).where( + User.LastSSHLogin < limit_to + ).values(LastSSHLoginIPAddress=None) + db.get_session().execute(update_) def main(): - conn = aurweb.db.Connection() - - limit_to = int(time.time()) - 86400 * 7 - conn.execute("UPDATE Users SET LastLoginIPAddress = NULL " + - "WHERE LastLogin < ?", [limit_to]) - conn.execute("UPDATE Users SET LastSSHLoginIPAddress = NULL " + - "WHERE LastSSHLogin < ?", [limit_to]) - - conn.commit() - conn.close() + db.get_engine() + with db.begin(): + _main() if __name__ == '__main__': diff --git a/test/t2700-usermaint.t b/test/t2700-usermaint.t deleted file mode 100755 index c119e3f4..00000000 --- a/test/t2700-usermaint.t +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh - -test_description='usermaint tests' - -. "$(dirname "$0")/setup.sh" - -test_expect_success 'Test removal of login IP addresses.' ' - now=$(date -d now +%s) && - threedaysago=$(date -d "3 days ago" +%s) && - tendaysago=$(date -d "10 days ago" +%s) && - cat <<-EOD | sqlite3 aur.db && - UPDATE Users SET LastLogin = $threedaysago, LastLoginIPAddress = "1.2.3.4" WHERE ID = 1; - UPDATE Users SET LastLogin = $tendaysago, LastLoginIPAddress = "2.3.4.5" WHERE ID = 2; - UPDATE Users SET LastLogin = $now, LastLoginIPAddress = "3.4.5.6" WHERE ID = 3; - UPDATE Users SET LastLogin = 0, LastLoginIPAddress = "4.5.6.7" WHERE ID = 4; - UPDATE Users SET LastLogin = 0, LastLoginIPAddress = "5.6.7.8" WHERE ID = 5; - UPDATE Users SET LastLogin = $tendaysago, LastLoginIPAddress = "6.7.8.9" WHERE ID = 6; - EOD - cover "$USERMAINT" && - cat <<-EOD >expected && - 1.2.3.4 - 3.4.5.6 - EOD - echo "SELECT LastLoginIPAddress FROM Users WHERE LastLoginIPAddress IS NOT NULL;" | sqlite3 aur.db >actual && - test_cmp actual expected -' - -test_expect_success 'Test removal of SSH login IP addresses.' ' - now=$(date -d now +%s) && - threedaysago=$(date -d "3 days ago" +%s) && - tendaysago=$(date -d "10 days ago" +%s) && - cat <<-EOD | sqlite3 aur.db && - UPDATE Users SET LastSSHLogin = $now, LastSSHLoginIPAddress = "1.2.3.4" WHERE ID = 1; - UPDATE Users SET LastSSHLogin = $threedaysago, LastSSHLoginIPAddress = "2.3.4.5" WHERE ID = 2; - UPDATE Users SET LastSSHLogin = $tendaysago, LastSSHLoginIPAddress = "3.4.5.6" WHERE ID = 3; - UPDATE Users SET LastSSHLogin = 0, LastSSHLoginIPAddress = "4.5.6.7" WHERE ID = 4; - UPDATE Users SET LastSSHLogin = 0, LastSSHLoginIPAddress = "5.6.7.8" WHERE ID = 5; - UPDATE Users SET LastSSHLogin = $tendaysago, LastSSHLoginIPAddress = "6.7.8.9" WHERE ID = 6; - EOD - cover "$USERMAINT" && - cat <<-EOD >expected && - 1.2.3.4 - 2.3.4.5 - EOD - echo "SELECT LastSSHLoginIPAddress FROM Users WHERE LastSSHLoginIPAddress IS NOT NULL;" | sqlite3 aur.db >actual && - test_cmp actual expected -' - -test_done diff --git a/test/test_usermaint.py b/test/test_usermaint.py new file mode 100644 index 00000000..f1af59e1 --- /dev/null +++ b/test/test_usermaint.py @@ -0,0 +1,67 @@ +from datetime import datetime + +import pytest + +from aurweb import db +from aurweb.models import User +from aurweb.models.account_type import USER_ID +from aurweb.scripts import usermaint + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + Passwd="testPassword", AccountTypeID=USER_ID) + yield user + + +def test_usermaint_noop(user: User): + """ Last[SSH]Login isn't expired in this test: usermaint is noop. """ + + now = int(datetime.utcnow().timestamp()) + with db.begin(): + user.LastLoginIPAddress = "127.0.0.1" + user.LastLogin = now - 10 + user.LastSSHLoginIPAddress = "127.0.0.1" + user.LastSSHLogin = now - 10 + + usermaint.main() + + assert user.LastLoginIPAddress == "127.0.0.1" + assert user.LastSSHLoginIPAddress == "127.0.0.1" + + +def test_usermaint(user: User): + """ + In this case, we first test that only the expired record gets + updated, but the non-expired record remains untouched. After, + we update the login time on the non-expired record and exercise + its code path. + """ + + now = int(datetime.utcnow().timestamp()) + limit_to = now - 86400 * 7 + with db.begin(): + user.LastLoginIPAddress = "127.0.0.1" + user.LastLogin = limit_to - 666 + user.LastSSHLoginIPAddress = "127.0.0.1" + user.LastSSHLogin = now - 10 + + usermaint.main() + + assert user.LastLoginIPAddress is None + assert user.LastSSHLoginIPAddress == "127.0.0.1" + + with db.begin(): + user.LastSSHLogin = limit_to - 666 + + usermaint.main() + + assert user.LastLoginIPAddress is None + assert user.LastSSHLoginIPAddress is None From f4ef02fa5b744598e366930e63adec4cdbac6706 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 11:07:31 -0800 Subject: [PATCH 1175/1891] fix(fastapi): fix Package's PackageBase backref cascade Signed-off-by: Kevin Morris --- aurweb/models/package.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aurweb/models/package.py b/aurweb/models/package.py index 8f82dadd..cfb27634 100644 --- a/aurweb/models/package.py +++ b/aurweb/models/package.py @@ -12,7 +12,8 @@ class Package(Base): __mapper_args__ = {"primary_key": [__table__.c.ID]} PackageBase = relationship( - _PackageBase, backref=backref("packages", lazy="dynamic"), + _PackageBase, backref=backref("packages", lazy="dynamic", + cascade="all, delete"), foreign_keys=[__table__.c.PackageBaseID]) def __init__(self, **kwargs): From b72bd38f76ed290a4e5607dfca177dcf0c1d9864 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 11:08:15 -0800 Subject: [PATCH 1176/1891] change(pkgmaint): converted to use aurweb.db ORM - Replaced time.time() usage with datetime.utcnow().timestamp() - Removed pkgmaint sharness test Signed-off-by: Kevin Morris --- aurweb/scripts/pkgmaint.py | 28 ++++++++++------ test/t2300-pkgmaint.t | 26 --------------- test/test_pkgmaint.py | 65 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 36 deletions(-) delete mode 100755 test/t2300-pkgmaint.t create mode 100644 test/test_pkgmaint.py diff --git a/aurweb/scripts/pkgmaint.py b/aurweb/scripts/pkgmaint.py index 36da126f..b3992e5c 100755 --- a/aurweb/scripts/pkgmaint.py +++ b/aurweb/scripts/pkgmaint.py @@ -1,19 +1,27 @@ #!/usr/bin/env python3 -import time +from datetime import datetime -import aurweb.db +from sqlalchemy import and_ + +from aurweb import db +from aurweb.models import PackageBase + + +def _main(): + # One day behind. + limit_to = int(datetime.utcnow().timestamp()) - 86400 + + query = db.query(PackageBase).filter( + and_(PackageBase.SubmittedTS < limit_to, + PackageBase.PackagerUID.is_(None))) + db.delete_all(query) def main(): - conn = aurweb.db.Connection() - - limit_to = int(time.time()) - 86400 - conn.execute("DELETE FROM PackageBases WHERE " + - "SubmittedTS < ? AND PackagerUID IS NULL", [limit_to]) - - conn.commit() - conn.close() + db.get_engine() + with db.begin(): + _main() if __name__ == '__main__': diff --git a/test/t2300-pkgmaint.t b/test/t2300-pkgmaint.t deleted file mode 100755 index 997f95b0..00000000 --- a/test/t2300-pkgmaint.t +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -test_description='pkgmaint tests' - -. "$(dirname "$0")/setup.sh" - -test_expect_success 'Test package base cleanup script.' ' - now=$(date -d now +%s) && - threedaysago=$(date -d "3 days ago" +%s) && - cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, $now, 0, ""); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (2, "foobar2", 2, $threedaysago, 0, ""); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (3, "foobar3", NULL, $now, 0, ""); - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (4, "foobar4", NULL, $threedaysago, 0, ""); - EOD - cover "$PKGMAINT" && - cat <<-EOD >expected && - foobar - foobar2 - foobar3 - EOD - echo "SELECT Name FROM PackageBases;" | sqlite3 aur.db >actual && - test_cmp actual expected -' - -test_done diff --git a/test/test_pkgmaint.py b/test/test_pkgmaint.py new file mode 100644 index 00000000..921a6330 --- /dev/null +++ b/test/test_pkgmaint.py @@ -0,0 +1,65 @@ +from datetime import datetime +from typing import List + +import pytest + +from aurweb import db +from aurweb.models import Package, PackageBase, User +from aurweb.models.account_type import USER_ID +from aurweb.scripts import pkgmaint + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + Passwd="testPassword", AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def packages(user: User) -> List[Package]: + output = [] + + now = int(datetime.utcnow().timestamp()) + with db.begin(): + for i in range(5): + pkgbase = db.create(PackageBase, Name=f"pkg_{i}", + SubmittedTS=now, + ModifiedTS=now) + pkg = db.create(Package, PackageBase=pkgbase, + Name=f"pkg_{i}", Version=f"{i}.0") + output.append(pkg) + yield output + + +def test_pkgmaint_noop(packages: List[Package]): + assert len(packages) == 5 + pkgmaint.main() + packages = db.query(Package).all() + assert len(packages) == 5 + + +def test_pkgmaint(packages: List[Package]): + assert len(packages) == 5 + + # Modify the first package so it's out of date and gets deleted. + with db.begin(): + # Reduce SubmittedTS by a day + 10 seconds. + packages[0].PackageBase.SubmittedTS -= (86400 + 10) + + # Run pkgmaint. + pkgmaint.main() + + # Query package objects again and assert that the + # first package was deleted but all others are intact. + packages = db.query(Package).all() + assert len(packages) == 4 + expected = ["pkg_1", "pkg_2", "pkg_3", "pkg_4"] + for i, pkgname in enumerate(expected): + assert packages[i].Name == pkgname From 9fb1fbe32cd2d7652f4dee9df29002a36b9ff38c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 15:00:22 -0800 Subject: [PATCH 1177/1891] feat(testing): add email testing utilities Changes: - util/sendmail now populates email files in the 'test-emails' directory. - util/sendmail does this in a serialized fashion based off of the test suite and name retrieved from PYTEST_CURRENT_TEST in the format: `_.n.txt` where n is increased by one every time sendmail is run. - pytest conftest fixtures have been added for test email setup; it wipes out old emails for the particular test function being run. - New aurweb.testing.email.Email class allows developers to test against emails stored by util/sendmail. Simple pass the serial you want to test against, starting at serial = 1; e.g. Email(serial). Signed-off-by: Kevin Morris --- aurweb/testing/email.py | 120 ++++++++++++++++++++++++++++++++++++++++ test/conftest.py | 20 ++++++- util/sendmail | 23 ++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 aurweb/testing/email.py diff --git a/aurweb/testing/email.py b/aurweb/testing/email.py new file mode 100644 index 00000000..6ff9df99 --- /dev/null +++ b/aurweb/testing/email.py @@ -0,0 +1,120 @@ +import base64 +import copy +import email +import os +import re + + +class Email: + """ + An email class used for testing. + + This class targets a specific serial of emails for PYTEST_CURRENT_TEST. + As emails are sent out with util/sendmail, the serial number increases, + starting at 1. + + Email content sent out by aurweb is always base64-encoded. Email.parse() + decodes that for us and puts it into Email.body. + + Example: + + # Get the {test_suite}_{test_function}.1.txt email. + email = Email(1).parse() + print(email.body) + print(email.headers) + + """ + TEST_DIR = "test-emails" + + def __init__(self, serial: int = 1): + self.serial = serial + self.content = self._get() + + @staticmethod + def email_prefix(suite: bool = False) -> str: + """ + Get the email prefix. + + We find the email prefix by reducing PYTEST_CURRENT_TEST to + either {test_suite}_{test_function}. If `suite` is set, we + reduce it to {test_suite} only. + + :param suite: Reduce PYTEST_CURRENT_TEST to {test_suite} + :return: Email prefix with '/', '.', ',', and ':' chars replaced by '_' + """ + value = os.environ.get("PYTEST_CURRENT_TEST", "email").split(" ")[0] + if suite: + value = value.split(":")[0] + return re.sub(r'(\/|\.|,|:)', "_", value) + + @staticmethod + def count() -> int: + """ + Count the current number of emails sent from the test. + + This function is **only** supported inside of pytest functions. + Do not use it elsewhere as data races will occur. + + :return: Number of emails sent by the current test + """ + files = os.listdir(Email.TEST_DIR) + prefix = Email.email_prefix() + expr = "^" + prefix + r"\.\d+\.txt$" + subset = filter(lambda e: re.match(expr, e), files) + return len(list(subset)) + + def _email_path(self) -> str: + filename = self.email_prefix() + f".{self.serial}.txt" + return os.path.join(Email.TEST_DIR, filename) + + def _get(self) -> str: + """ + Get this email's content by reading its file. + + :return: Email content + """ + path = self._email_path() + with open(path) as f: + return f.read() + + def parse(self) -> "Email": + """ + Parse this email and base64-decode the body. + + This function populates Email.message, Email.headers and Email.body. + + Additionally, after parsing, we write over our email file with + self.glue()'d content (base64-decoded). This is done for ease + of inspection by users. + + :return: self + """ + self.message = email.message_from_string(self.content) + self.headers = dict(self.message) + + # aurweb email notifications always have base64 encoded content. + # Decode it here so self.body is human readable. + self.body = base64.b64decode(self.message.get_payload()).decode() + + path = self._email_path() + with open(path, "w") as f: + f.write(self.glue()) + + return self + + def glue(self) -> str: + """ + Glue parsed content back into a complete email document, but + base64-decoded this time. + + :return: Email document as a string + """ + headers = copy.copy(self.headers) + del headers["Content-Transfer-Encoding"] + + output = [] + for k, v in headers.items(): + output.append(f"{k}: {v}") + output.append("") + output.append(self.body) + return "\n".join(output) diff --git a/test/conftest.py b/test/conftest.py index db2e5997..01131109 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -37,6 +37,8 @@ then clears the database for each test function run in that module. It is done this way because migration has a large cost; migrating ahead of each function takes too long when compared to this method. """ +import os + import pytest from filelock import FileLock @@ -50,6 +52,7 @@ import aurweb.config import aurweb.db from aurweb import initdb, logging, testing +from aurweb.testing.email import Email logger = logging.get_logger(__name__) @@ -120,6 +123,18 @@ def _drop_database(engine: Engine, dbname: str) -> None: conn.close() +def setup_email(): + if not os.path.exists(Email.TEST_DIR): + os.makedirs(Email.TEST_DIR) + + # Cleanup all email files for this test suite. + prefix = Email.email_prefix(suite=True) + files = os.listdir(Email.TEST_DIR) + for file in files: + if file.startswith(prefix): + os.remove(os.path.join(Email.TEST_DIR, file)) + + @pytest.fixture(scope="module") def setup_database(tmp_path_factory: pytest.fixture, worker_id: pytest.fixture) -> None: @@ -129,6 +144,7 @@ def setup_database(tmp_path_factory: pytest.fixture, if worker_id == "master": # pragma: no cover # If we're not running tests through multiproc pytest-xdist. + setup_email() yield _create_database(engine, dbname) _drop_database(engine, dbname) return @@ -143,12 +159,13 @@ def setup_database(tmp_path_factory: pytest.fixture, else: # Otherwise, create the data file and create the database. fn.write_text("1") + setup_email() yield _create_database(engine, dbname) _drop_database(engine, dbname) @pytest.fixture(scope="module") -def db_session(setup_database: pytest.fixture) -> scoped_session: +def db_session(setup_database: None) -> scoped_session: """ Yield a database session based on aurweb.db.name(). @@ -158,6 +175,7 @@ def db_session(setup_database: pytest.fixture) -> scoped_session: # configured database, because PYTEST_CURRENT_TEST is removed. dbname = aurweb.db.name() session = aurweb.db.get_session() + yield session # Close the session and pop it. diff --git a/util/sendmail b/util/sendmail index 06bd9865..9356851a 100755 --- a/util/sendmail +++ b/util/sendmail @@ -1,2 +1,25 @@ #!/bin/bash +# Send email to temporary filesystem for tests. +dir='test-emails' +filename='email.txt' +if [ ! -z ${PYTEST_CURRENT_TEST+x} ]; then + filename="$(echo $PYTEST_CURRENT_TEST | cut -d ' ' -f 1 | sed -r 's/(\/|\.|,|:)/_/g')" +fi +mkdir -p "$dir" + +path="${dir}/${filename}" +serial_file="${path}.serial" +if [ ! -f $serial_file ]; then + echo 0 > $serial_file +fi + +# Increment and update $serial_file. +serial=$(($(cat $serial_file) + 1)) +echo $serial > $serial_file + +# Use the serial we're on to mark the email file. +# Emails have the format: PYTEST_CURRENT_TEST.s.txt +# where s is the current serial for PYTEST_CURRENT_TEST. +cat > "${path}.${serial}.txt" + exit 0 From d8e3ca1abbac6a897f262b1eba0695f4323a13d8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 12:03:53 -0800 Subject: [PATCH 1178/1891] change(notify): converted to use aurweb.db ORM - Removed notify sharness test Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 7 +- aurweb/routers/accounts.py | 6 +- aurweb/routers/packages.py | 30 +- aurweb/scripts/notify.py | 402 +++++++++++++---------- aurweb/testing/smtp.py | 42 +++ test/t2500-notify.t | 431 ------------------------- test/test_notify.py | 643 +++++++++++++++++++++++++++++++++++++ 7 files changed, 934 insertions(+), 627 deletions(-) create mode 100644 aurweb/testing/smtp.py delete mode 100755 test/t2500-notify.t create mode 100644 test/test_notify.py diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 55af3a34..3bb3ae5f 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -239,7 +239,6 @@ def remove_comaintainers(pkgbase: models.PackageBase, :param usernames: Iterable of username strings :return: None """ - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) notifications = [] with db.begin(): for username in usernames: @@ -250,8 +249,7 @@ def remove_comaintainers(pkgbase: models.PackageBase, ).first() notifications.append( notify.ComaintainerRemoveNotification( - conn, comaintainer.User.ID, pkgbase.ID - ) + comaintainer.User.ID, pkgbase.ID) ) db.delete(comaintainer) @@ -283,7 +281,6 @@ def add_comaintainers(request: Request, pkgbase: models.PackageBase, memo[username] = user # Alright, now that we got past the check, add them all to the DB. - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) notifications = [] with db.begin(): for username in usernames: @@ -302,7 +299,7 @@ def add_comaintainers(request: Request, pkgbase: models.PackageBase, notifications.append( notify.ComaintainerAddNotification( - conn, comaintainer.User.ID, pkgbase.ID) + comaintainer.User.ID, pkgbase.ID) ) # Send out notifications. diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index ddee1764..545811f0 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -97,8 +97,7 @@ async def passreset_post(request: Request, with db.begin(): user.ResetKey = resetkey - executor = db.ConnectionExecutor(db.get_engine().raw_connection()) - ResetKeyNotification(executor, user.ID).send() + ResetKeyNotification(user.ID).send() # Render ?step=confirm. return RedirectResponse(url="/passreset?step=confirm", @@ -323,8 +322,7 @@ async def account_register_post(request: Request, Fingerprint=fingerprint) # Send a reset key notification to the new user. - executor = db.ConnectionExecutor(db.get_engine().raw_connection()) - WelcomeNotification(executor, user.ID).send() + WelcomeNotification(user.ID).send() context["complete"] = True context["user"] = user diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index eab75e5a..b5f8478e 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -146,7 +146,6 @@ def delete_package(deleter: models.User, package: models.Package): requests = [] bases_to_delete = [] - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) # In all cases, though, just delete the Package in question. if package.PackageBase.packages.count() == 1: reqtype = db.query(models.RequestType).filter( @@ -162,7 +161,7 @@ def delete_package(deleter: models.User, package: models.Package): # Prepare DeleteNotification. notifications.append( - notify.DeleteNotification(conn, deleter.ID, package.PackageBase.ID) + notify.DeleteNotification(deleter.ID, package.PackageBase.ID) ) # For each PackageRequest created, mock up an open and close notification. @@ -170,12 +169,12 @@ def delete_package(deleter: models.User, package: models.Package): for pkgreq in requests: notifications.append( notify.RequestOpenNotification( - conn, deleter.ID, pkgreq.ID, reqtype.Name, + deleter.ID, pkgreq.ID, reqtype.Name, pkgreq.PackageBase.ID, merge_into=basename or None) ) notifications.append( notify.RequestCloseNotification( - conn, deleter.ID, pkgreq.ID, pkgreq.status_display()) + deleter.ID, pkgreq.ID, pkgreq.status_display()) ) # Perform all the deletions. @@ -666,10 +665,9 @@ async def pkgbase_request_post(request: Request, name: str, Comments=comments, ClosureComment=str()) - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) # Prepare notification object. notif = notify.RequestOpenNotification( - conn, request.user.ID, pkgreq.ID, reqtype.Name, + request.user.ID, pkgreq.ID, reqtype.Name, pkgreq.PackageBase.ID, merge_into=merge_into or None) # Send the notification now that we're out of the DB scope. @@ -688,7 +686,7 @@ async def pkgbase_request_post(request: Request, name: str, pkgreq.Status = ACCEPTED_ID db.refresh(pkgreq) notif = notify.RequestCloseNotification( - conn, request.user.ID, pkgreq.ID, pkgreq.status_display()) + request.user.ID, pkgreq.ID, pkgreq.status_display()) notif.send() elif type == "deletion" and is_maintainer and outdated: packages = pkgbase.packages.all() @@ -742,9 +740,8 @@ async def requests_close_post(request: Request, id: int, pkgreq.Status = reason pkgreq.ClosureComment = comments - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) notify_ = notify.RequestCloseNotification( - conn, request.user.ID, pkgreq.ID, pkgreq.status_display()) + request.user.ID, pkgreq.ID, pkgreq.status_display()) notify_.send() return RedirectResponse("/requests", status_code=HTTPStatus.SEE_OTHER) @@ -936,9 +933,7 @@ async def pkgbase_unvote(request: Request, name: str): def pkgbase_disown_instance(request: Request, pkgbase: models.PackageBase): disowner = request.user - - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - notif = notify.DisownNotification(conn, disowner.ID, pkgbase.ID) + notif = notify.DisownNotification(disowner.ID, pkgbase.ID) if disowner != pkgbase.Maintainer: with db.begin(): @@ -1003,8 +998,7 @@ def pkgbase_adopt_instance(request: Request, pkgbase: models.PackageBase): with db.begin(): pkgbase.Maintainer = request.user - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) - notif = notify.AdoptNotification(conn, request.user.ID, pkgbase.ID) + notif = notify.AdoptNotification(request.user.ID, pkgbase.ID) notif.send() @@ -1366,7 +1360,7 @@ def pkgbase_merge_instance(request: Request, pkgbase: models.PackageBase, f"{request.user.Username}.") rejected_closure_comment = ("Rejected because another merge request " "for the same package base was accepted.") - conn = db.ConnectionExecutor(db.get_engine().raw_connection()) + if not requests: # If there are no requests, create one owned by request.user. with db.begin(): @@ -1383,7 +1377,7 @@ def pkgbase_merge_instance(request: Request, pkgbase: models.PackageBase, # Add a notification about the opening to our notifs array. notif = notify.RequestOpenNotification( - conn, request.user.ID, pkgreq.ID, MERGE, + request.user.ID, pkgreq.ID, MERGE, pkgbase.ID, merge_into=target.Name) notifs.append(notif) @@ -1417,11 +1411,9 @@ def pkgbase_merge_instance(request: Request, pkgbase: models.PackageBase, for pkgreq in all_requests: # Create notifications for request closure. notif = notify.RequestCloseNotification( - conn, request.user.ID, pkgreq.ID, pkgreq.status_display()) + request.user.ID, pkgreq.ID, pkgreq.status_display()) notifs.append(notif) - conn.close() - # Log this out for accountability purposes. logger.info(f"Trusted User '{request.user.Username}' merged " f"'{pkgbasename}' into '{target.Name}'.") diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index ba4ec9eb..e49024d9 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -7,10 +7,16 @@ import subprocess import sys import textwrap +from sqlalchemy import and_, or_ + import aurweb.config import aurweb.db import aurweb.l10n +from aurweb import db +from aurweb.models import (PackageBase, PackageComaintainer, PackageComment, PackageNotification, PackageRequest, RequestType, + TUVote, User) + aur_location = aurweb.config.get('options', 'aur_location') @@ -22,23 +28,6 @@ def headers_reply(thread_id): return {'In-Reply-To': thread_id, 'References': thread_id} -def username_from_id(conn, uid): - cur = conn.execute('SELECT UserName FROM Users WHERE ID = ?', [uid]) - return cur.fetchone()[0] - - -def pkgbase_from_id(conn, pkgbase_id): - cur = conn.execute('SELECT Name FROM PackageBases WHERE ID = ?', - [pkgbase_id]) - return cur.fetchone()[0] - - -def pkgbase_from_pkgreq(conn, reqid): - cur = conn.execute('SELECT PackageBaseID FROM PackageRequests ' + - 'WHERE ID = ?', [reqid]) - return cur.fetchone()[0] - - class Notification: def get_refs(self): return () @@ -52,8 +41,8 @@ class Notification: def get_body_fmt(self, lang): body = '' for line in self.get_body(lang).splitlines(): - if line == '-- ': - body += '-- \n' + if line == '--': + body += '--\n' continue body += textwrap.fill(line, break_long_words=False) + '\n' for i, ref in enumerate(self.get_refs()): @@ -103,10 +92,11 @@ class Notification: user = aurweb.config.get('notifications', 'smtp-user') passwd = aurweb.config.get('notifications', 'smtp-password') - if use_ssl: - server = smtplib.SMTP_SSL(server_addr, server_port) - else: - server = smtplib.SMTP(server_addr, server_port) + classes = { + False: smtplib.SMTP, + True: smtplib.SMTP_SSL, + } + server = classes[use_ssl](server_addr, server_port) if use_starttls: server.ehlo() @@ -123,12 +113,24 @@ class Notification: class ResetKeyNotification(Notification): - def __init__(self, conn, uid): - cur = conn.execute('SELECT UserName, Email, BackupEmail, ' + - 'LangPreference, ResetKey ' + - 'FROM Users WHERE ID = ? AND Suspended = 0', [uid]) - self._username, self._to, self._backup, self._lang, self._resetkey = \ - cur.fetchone() + def __init__(self, uid): + + user = db.query(User).filter( + and_(User.ID == uid, User.Suspended == 0) + ).with_entities( + User.Username, + User.Email, + User.BackupEmail, + User.LangPreference, + User.ResetKey + ).order_by(User.Username.asc()).first() + + self._username = user.Username + self._to = user.Email + self._backup = user.BackupEmail + self._lang = user.LangPreference + self._resetkey = user.ResetKey + super().__init__() def get_recipients(self): @@ -167,21 +169,28 @@ class WelcomeNotification(ResetKeyNotification): class CommentNotification(Notification): - def __init__(self, conn, uid, pkgbase_id, comment_id): - self._user = username_from_id(conn, uid) - self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email, Users.LangPreference ' - 'FROM Users INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.CommentNotify = 1 AND ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ? AND ' + - 'Users.Suspended = 0', - [uid, pkgbase_id]) - self._recipients = cur.fetchall() - cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', - [comment_id]) - self._text = cur.fetchone()[0] + def __init__(self, uid, pkgbase_id, comment_id): + + self._user = db.query(User.Username).filter( + User.ID == uid).first().Username + self._pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == pkgbase_id).first().Name + + query = db.query(User).join(PackageNotification).filter( + and_(User.CommentNotify == 1, + PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == pkgbase_id, + User.Suspended == 0) + ).with_entities( + User.Email, + User.LangPreference + ).distinct() + self._recipients = [(u.Email, u.LangPreference) for u in query] + + pkgcomment = db.query(PackageComment.Comments).filter( + PackageComment.ID == comment_id).first() + self._text = pkgcomment.Comments + super().__init__() def get_recipients(self): @@ -196,7 +205,7 @@ class CommentNotification(Notification): body = aurweb.l10n.translator.translate( '{user} [1] added the following comment to {pkgbase} [2]:', lang).format(user=self._user, pkgbase=self._pkgbase) - body += '\n\n' + self._text + '\n\n-- \n' + body += '\n\n' + self._text + '\n\n--\n' dnlabel = aurweb.l10n.translator.translate( 'Disable notifications', lang) body += aurweb.l10n.translator.translate( @@ -216,19 +225,24 @@ class CommentNotification(Notification): class UpdateNotification(Notification): - def __init__(self, conn, uid, pkgbase_id): - self._user = username_from_id(conn, uid) - self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email, ' + - 'Users.LangPreference FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.UpdateNotify = 1 AND ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ? AND ' + - 'Users.Suspended = 0', - [uid, pkgbase_id]) - self._recipients = cur.fetchall() + def __init__(self, uid, pkgbase_id): + + self._user = db.query(User.Username).filter( + User.ID == uid).first().Username + self._pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == pkgbase_id).first().Name + + query = db.query(User).join(PackageNotification).filter( + and_(User.UpdateNotify == 1, + PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == pkgbase_id, + User.Suspended == 0) + ).with_entities( + User.Email, + User.LangPreference + ).distinct() + self._recipients = [(u.Email, u.LangPreference) for u in query] + super().__init__() def get_recipients(self): @@ -243,7 +257,7 @@ class UpdateNotification(Notification): body = aurweb.l10n.translator.translate( '{user} [1] pushed a new commit to {pkgbase} [2].', lang).format(user=self._user, pkgbase=self._pkgbase) - body += '\n\n-- \n' + body += '\n\n--\n' dnlabel = aurweb.l10n.translator.translate( 'Disable notifications', lang) body += aurweb.l10n.translator.translate( @@ -263,23 +277,30 @@ class UpdateNotification(Notification): class FlagNotification(Notification): - def __init__(self, conn, uid, pkgbase_id): - self._user = username_from_id(conn, uid) - self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute( - 'SELECT DISTINCT Users.Email, ' + - 'Users.LangPreference FROM Users ' + - 'LEFT JOIN PackageComaintainers ' + - 'ON PackageComaintainers.UsersID = Users.ID ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.MaintainerUID = Users.ID OR ' + - 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + - 'WHERE PackageBases.ID = ? AND ' + - 'Users.Suspended = 0', [pkgbase_id]) - self._recipients = cur.fetchall() - cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + - 'ID = ?', [pkgbase_id]) - self._text = cur.fetchone()[0] + def __init__(self, uid, pkgbase_id): + + self._user = db.query(User.Username).filter( + User.ID == uid).first().Username + self._pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == pkgbase_id).first().Name + + query = db.query(User).join(PackageComaintainer, isouter=True).join( + PackageBase, + or_(PackageBase.MaintainerUID == User.ID, + PackageBase.ID == PackageComaintainer.PackageBaseID) + ).filter( + and_(PackageBase.ID == pkgbase_id, + User.Suspended == 0) + ).with_entities( + User.Email, + User.LangPreference + ).distinct() + self._recipients = [(u.Email, u.LangPreference) for u in query] + + pkgbase = db.query(PackageBase.FlaggerComment).filter( + PackageBase.ID == pkgbase_id).first() + self._text = pkgbase.FlaggerComment + super().__init__() def get_recipients(self): @@ -304,22 +325,28 @@ class FlagNotification(Notification): class OwnershipEventNotification(Notification): - def __init__(self, conn, uid, pkgbase_id): - self._user = username_from_id(conn, uid) - self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email, ' + - 'Users.LangPreference FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'Users.OwnershipNotify = 1 AND ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ? AND ' + - 'Users.Suspended = 0', - [uid, pkgbase_id]) - self._recipients = cur.fetchall() - cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + - 'ID = ?', [pkgbase_id]) - self._text = cur.fetchone()[0] + def __init__(self, uid, pkgbase_id): + + self._user = db.query(User.Username).filter( + User.ID == uid).first().Username + self._pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == pkgbase_id).first().Name + + query = db.query(User).join(PackageNotification).filter( + and_(User.OwnershipNotify == 1, + PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == pkgbase_id, + User.Suspended == 0) + ).with_entities( + User.Email, + User.LangPreference + ).distinct() + self._recipients = [(u.Email, u.LangPreference) for u in query] + + pkgbase = db.query(PackageBase.FlaggerComment).filter( + PackageBase.ID == pkgbase_id).first() + self._text = pkgbase.FlaggerComment + super().__init__() def get_recipients(self): @@ -351,11 +378,22 @@ class DisownNotification(OwnershipEventNotification): class ComaintainershipEventNotification(Notification): - def __init__(self, conn, uid, pkgbase_id): - self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT Email, LangPreference FROM Users ' + - 'WHERE ID = ? AND Suspended = 0', [uid]) - self._to, self._lang = cur.fetchone() + def __init__(self, uid, pkgbase_id): + + self._pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == pkgbase_id).first().Name + + user = db.query(User).filter( + and_(User.ID == uid, + User.Suspended == 0) + ).with_entities( + User.Email, + User.LangPreference + ).first() + + self._to = user.Email + self._lang = user.LangPreference + super().__init__() def get_recipients(self): @@ -385,22 +423,28 @@ class ComaintainerRemoveNotification(ComaintainershipEventNotification): class DeleteNotification(Notification): - def __init__(self, conn, uid, old_pkgbase_id, new_pkgbase_id=None): - self._user = username_from_id(conn, uid) - self._old_pkgbase = pkgbase_from_id(conn, old_pkgbase_id) + def __init__(self, uid, old_pkgbase_id, new_pkgbase_id=None): + + self._user = db.query(User.Username).filter( + User.ID == uid).first().Username + self._old_pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == old_pkgbase_id).first().Name + + self._new_pkgbase = None if new_pkgbase_id: - self._new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id) - else: - self._new_pkgbase = None - cur = conn.execute('SELECT DISTINCT Users.Email, ' + - 'Users.LangPreference FROM Users ' + - 'INNER JOIN PackageNotifications ' + - 'ON PackageNotifications.UserID = Users.ID WHERE ' + - 'PackageNotifications.UserID != ? AND ' + - 'PackageNotifications.PackageBaseID = ? AND ' + - 'Users.Suspended = 0', - [uid, old_pkgbase_id]) - self._recipients = cur.fetchall() + self._new_pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == new_pkgbase_id).first().Name + + query = db.query(User).join(PackageNotification).filter( + and_(PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == old_pkgbase_id, + User.Suspended == 0) + ).with_entities( + User.Email, + User.LangPreference + ).distinct() + self._recipients = [(u.Email, u.LangPreference) for u in query] + super().__init__() def get_recipients(self): @@ -417,7 +461,7 @@ class DeleteNotification(Notification): 'Disable notifications', lang) return aurweb.l10n.translator.translate( '{user} [1] merged {old} [2] into {new} [3].\n\n' - '-- \n' + '--\n' 'If you no longer wish receive notifications about the ' 'new package, please go to [3] and click "{label}".', lang).format(user=self._user, old=self._old_pkgbase, @@ -438,26 +482,36 @@ class DeleteNotification(Notification): class RequestOpenNotification(Notification): - def __init__(self, conn, uid, reqid, reqtype, pkgbase_id, merge_into=None): - self._user = username_from_id(conn, uid) - self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute( - 'SELECT DISTINCT Users.Email FROM PackageRequests ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + - 'LEFT JOIN PackageComaintainers ' + - 'ON PackageComaintainers.PackageBaseID = PackageRequests.PackageBaseID ' + - 'INNER JOIN Users ' + - 'ON Users.ID = PackageRequests.UsersID ' + - 'OR Users.ID = PackageBases.MaintainerUID ' + - 'OR Users.ID = PackageComaintainers.UsersID ' + - 'WHERE PackageRequests.ID = ? AND ' + - 'Users.Suspended = 0', [reqid]) + def __init__(self, uid, reqid, reqtype, pkgbase_id, merge_into=None): + + self._user = db.query(User.Username).filter( + User.ID == uid).first().Username + self._pkgbase = db.query(PackageBase.Name).filter( + PackageBase.ID == pkgbase_id).first().Name + self._to = aurweb.config.get('options', 'aur_request_ml') - self._cc = [row[0] for row in cur.fetchall()] - cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?', - [reqid]) - self._text = cur.fetchone()[0] + + query = db.query(PackageRequest).join(PackageBase).join( + PackageComaintainer, + PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID, + isouter=True + ).join( + User, + or_(User.ID == PackageRequest.UsersID, + User.ID == PackageBase.MaintainerUID, + User.ID == PackageComaintainer.UsersID) + ).filter( + and_(PackageRequest.ID == reqid, + User.Suspended == 0) + ).with_entities( + User.Email + ).distinct() + self._cc = [u.Email for u in query] + + pkgreq = db.query(PackageRequest.Comments).filter( + PackageRequest.ID == reqid).first() + + self._text = pkgreq.Comments self._reqid = int(reqid) self._reqtype = reqtype self._merge_into = merge_into @@ -500,31 +554,41 @@ class RequestOpenNotification(Notification): class RequestCloseNotification(Notification): - def __init__(self, conn, uid, reqid, reason): - self._user = username_from_id(conn, uid) if int(uid) else None + def __init__(self, uid, reqid, reason): + user = db.query(User.Username).filter(User.ID == uid).first() + self._user = user.Username if user else None - cur = conn.execute( - 'SELECT DISTINCT Users.Email FROM PackageRequests ' + - 'INNER JOIN PackageBases ' + - 'ON PackageBases.ID = PackageRequests.PackageBaseID ' + - 'LEFT JOIN PackageComaintainers ' + - 'ON PackageComaintainers.PackageBaseID = PackageRequests.PackageBaseID ' + - 'INNER JOIN Users ' + - 'ON Users.ID = PackageRequests.UsersID ' + - 'OR Users.ID = PackageBases.MaintainerUID ' + - 'OR Users.ID = PackageComaintainers.UsersID ' + - 'WHERE PackageRequests.ID = ? AND ' + - 'Users.Suspended = 0', [reqid]) self._to = aurweb.config.get('options', 'aur_request_ml') - self._cc = [row[0] for row in cur.fetchall()] - cur = conn.execute('SELECT PackageRequests.ClosureComment, ' + - 'RequestTypes.Name, ' + - 'PackageRequests.PackageBaseName ' + - 'FROM PackageRequests ' + - 'INNER JOIN RequestTypes ' + - 'ON RequestTypes.ID = PackageRequests.ReqTypeID ' + - 'WHERE PackageRequests.ID = ?', [reqid]) - self._text, self._reqtype, self._pkgbase = cur.fetchone() + + query = db.query(PackageRequest).join(PackageBase).join( + PackageComaintainer, + PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID, + isouter=True + ).join( + User, + or_(User.ID == PackageRequest.UsersID, + User.ID == PackageBase.MaintainerUID, + User.ID == PackageComaintainer.UsersID) + ).filter( + and_(PackageRequest.ID == reqid, + User.Suspended == 0) + ).with_entities( + User.Email + ).distinct() + self._cc = [u.Email for u in query] + + pkgreq = db.query(PackageRequest).join(RequestType).filter( + PackageRequest.ID == reqid + ).with_entities( + PackageRequest.ClosureComment, + RequestType.Name, + PackageRequest.PackageBaseName + ).first() + + self._text = pkgreq.ClosureComment + self._reqtype = pkgreq.Name + self._pkgbase = pkgreq.PackageBaseName + self._reqid = int(reqid) self._reason = reason @@ -567,14 +631,19 @@ class RequestCloseNotification(Notification): class TUVoteReminderNotification(Notification): - def __init__(self, conn, vote_id): + def __init__(self, vote_id): self._vote_id = int(vote_id) - cur = conn.execute('SELECT Email, LangPreference FROM Users ' + - 'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' + - '(SELECT UserID FROM TU_Votes ' + - 'WHERE TU_Votes.VoteID = ?) AND ' + - 'Users.Suspended = 0', [vote_id]) - self._recipients = cur.fetchall() + + subquery = db.query(TUVote.UserID).filter(TUVote.VoteID == vote_id) + query = db.query(User).filter( + and_(User.AccountTypeID.in_((2, 4)), + ~User.ID.in_(subquery), + User.Suspended == 0) + ).with_entities( + User.Email, User.LangPreference + ) + self._recipients = [(u.Email, u.LangPreference) for u in query] + super().__init__() def get_recipients(self): @@ -596,6 +665,7 @@ class TUVoteReminderNotification(Notification): def main(): + db.get_engine() action = sys.argv[1] action_map = { 'send-resetkey': ResetKeyNotification, @@ -613,14 +683,10 @@ def main(): 'tu-vote-reminder': TUVoteReminderNotification, } - conn = aurweb.db.Connection() - - notification = action_map[action](conn, *sys.argv[2:]) + with db.begin(): + notification = action_map[action](*sys.argv[2:]) notification.send() - conn.commit() - conn.close() - if __name__ == '__main__': main() diff --git a/aurweb/testing/smtp.py b/aurweb/testing/smtp.py new file mode 100644 index 00000000..da64c93f --- /dev/null +++ b/aurweb/testing/smtp.py @@ -0,0 +1,42 @@ +""" Fake SMTP clients that can be used for testing. """ + + +class FakeSMTP: + """ A fake version of smtplib.SMTP used for testing. """ + + starttls_enabled = False + use_ssl = False + + def __init__(self): + self.emails = [] + self.count = 0 + self.ehlo_count = 0 + self.quit_count = 0 + self.set_debuglevel_count = 0 + self.user = None + self.passwd = None + + def ehlo(self) -> None: + self.ehlo_count += 1 + + def starttls(self) -> None: + self.starttls_enabled = True + + def set_debuglevel(self, level: int = 0) -> None: + self.set_debuglevel_count += 1 + + def login(self, user: str, passwd: str) -> None: + self.user = user + self.passwd = passwd + + def sendmail(self, sender: str, to: str, msg: bytes) -> None: + self.emails.append((sender, to, msg.decode())) + self.count += 1 + + def quit(self) -> None: + self.quit_count += 1 + + +class FakeSMTP_SSL(FakeSMTP): + """ A fake version of smtplib.SMTP_SSL used for testing. """ + use_ssl = True diff --git a/test/t2500-notify.t b/test/t2500-notify.t deleted file mode 100755 index a908f125..00000000 --- a/test/t2500-notify.t +++ /dev/null @@ -1,431 +0,0 @@ -#!/bin/sh - -test_description='notify tests' - -. "$(dirname "$0")/setup.sh" - -test_expect_success 'Test out-of-date notifications.' ' - cat <<-EOD | sqlite3 aur.db && - /* Use package base IDs which can be distinguished from user IDs. */ - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1001, "foobar", 1, 0, 0, "This is a test OOD comment."); - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1002, "foobar2", 2, 0, 0, ""); - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1003, "foobar3", NULL, 0, 0, ""); - INSERT INTO PackageBases (ID, Name, MaintainerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1004, "foobar4", 1, 0, 0, ""); - INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1001, 2, 1); - INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1001, 4, 2); - INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1002, 3, 1); - INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1002, 5, 2); - INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1003, 4, 1); - EOD - >sendmail.out && - cover "$NOTIFY" flag 1 1001 && - cat <<-EOD >expected && - Subject: AUR Out-of-date Notification for foobar - To: tu@localhost - Subject: AUR Out-of-date Notification for foobar - To: user2@localhost - Subject: AUR Out-of-date Notification for foobar - To: user@localhost - EOD - grep "^\(Subject\|To\)" sendmail.out >sendmail.parts && - test_cmp sendmail.parts expected && - cat <<-EOD | sqlite3 aur.db - DELETE FROM PackageComaintainers; - EOD -' - -test_expect_success 'Test subject and body of reset key notifications.' ' - cat <<-EOD | sqlite3 aur.db && - UPDATE Users SET ResetKey = "12345678901234567890123456789012" WHERE ID = 1; - EOD - >sendmail.out && - cover "$NOTIFY" send-resetkey 1 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Password Reset - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - A password reset request was submitted for the account user associated - with your email address. If you wish to reset your password follow the - link [1] below, otherwise ignore this message and nothing will happen. - - [1] https://aur.archlinux.org/passreset/?resetkey=12345678901234567890123456789012 - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of welcome notifications.' ' - cat <<-EOD | sqlite3 aur.db && - UPDATE Users SET ResetKey = "12345678901234567890123456789012" WHERE ID = 1; - EOD - >sendmail.out && - cover "$NOTIFY" welcome 1 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: Welcome to the Arch User Repository - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - Welcome to the Arch User Repository! In order to set an initial - password for your new account, please click the link [1] below. If the - link does not work, try copying and pasting it into your browser. - - [1] https://aur.archlinux.org/passreset/?resetkey=12345678901234567890123456789012 - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of comment notifications.' ' - cat <<-EOD | sqlite3 aur.db && - /* Use package comments IDs which can be distinguished from other IDs. */ - INSERT INTO PackageComments (ID, PackageBaseID, UsersID, Comments, RenderedComment) VALUES (2001, 1001, 1, "This is a test comment.", "This is a test comment."); - INSERT INTO PackageNotifications (PackageBaseID, UserID) VALUES (1001, 2); - UPDATE Users SET CommentNotify = 1 WHERE ID = 2; - EOD - >sendmail.out && - cover "$NOTIFY" comment 1 1001 2001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Comment for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - user [1] added the following comment to foobar [2]: - - This is a test comment. - - -- - If you no longer wish to receive notifications about this package, - please go to the package page [2] and select "Disable notifications". - - [1] https://aur.archlinux.org/account/user/ - [2] https://aur.archlinux.org/pkgbase/foobar/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of update notifications.' ' - cat <<-EOD | sqlite3 aur.db && - UPDATE Users SET UpdateNotify = 1 WHERE ID = 2; - EOD - >sendmail.out && - cover "$NOTIFY" update 1 1001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Package Update: foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - user [1] pushed a new commit to foobar [2]. - - -- - If you no longer wish to receive notifications about this package, - please go to the package page [2] and select "Disable notifications". - - [1] https://aur.archlinux.org/account/user/ - [2] https://aur.archlinux.org/pkgbase/foobar/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of out-of-date notifications.' ' - >sendmail.out && - cover "$NOTIFY" flag 1 1001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Out-of-date Notification for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - Your package foobar [1] has been flagged out-of-date by user [2]: - - This is a test OOD comment. - - [1] https://aur.archlinux.org/pkgbase/foobar/ - [2] https://aur.archlinux.org/account/user/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of adopt notifications.' ' - >sendmail.out && - cover "$NOTIFY" adopt 1 1001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Ownership Notification for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - The package foobar [1] was adopted by user [2]. - - [1] https://aur.archlinux.org/pkgbase/foobar/ - [2] https://aur.archlinux.org/account/user/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of disown notifications.' ' - >sendmail.out && - cover "$NOTIFY" disown 1 1001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Ownership Notification for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - The package foobar [1] was disowned by user [2]. - - [1] https://aur.archlinux.org/pkgbase/foobar/ - [2] https://aur.archlinux.org/account/user/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of co-maintainer addition notifications.' ' - >sendmail.out && - cover "$NOTIFY" comaintainer-add 1 1001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Co-Maintainer Notification for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - You were added to the co-maintainer list of foobar [1]. - - [1] https://aur.archlinux.org/pkgbase/foobar/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of co-maintainer removal notifications.' ' - >sendmail.out && - cover "$NOTIFY" comaintainer-remove 1 1001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Co-Maintainer Notification for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - You were removed from the co-maintainer list of foobar [1]. - - [1] https://aur.archlinux.org/pkgbase/foobar/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of delete notifications.' ' - >sendmail.out && - cover "$NOTIFY" delete 1 1001 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Package deleted: foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - user [1] deleted foobar [2]. - - You will no longer receive notifications about this package. - - [1] https://aur.archlinux.org/account/user/ - [2] https://aur.archlinux.org/pkgbase/foobar/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of merge notifications.' ' - >sendmail.out && - cover "$NOTIFY" delete 1 1001 1002 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: AUR Package deleted: foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - user [1] merged foobar [2] into foobar2 [3]. - - -- - If you no longer wish receive notifications about the new package, - please go to [3] and click "Disable notifications". - - [1] https://aur.archlinux.org/account/user/ - [2] https://aur.archlinux.org/pkgbase/foobar/ - [3] https://aur.archlinux.org/pkgbase/foobar2/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test Cc, subject and body of request open notifications.' ' - cat <<-EOD | sqlite3 aur.db && - /* Use package request IDs which can be distinguished from other IDs. */ - INSERT INTO PackageRequests (ID, PackageBaseID, PackageBaseName, UsersID, ReqTypeID, Comments, ClosureComment) VALUES (3001, 1001, "foobar", 2, 1, "This is a request test comment.", ""); - EOD - >sendmail.out && - cover "$NOTIFY" request-open 1 3001 orphan 1001 && - grep ^Cc: sendmail.out >actual && - cat <<-EOD >expected && - Cc: user@localhost, tu@localhost - EOD - test_cmp actual expected && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: [PRQ#3001] Orphan Request for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - user [1] filed an orphan request for foobar [2]: - - This is a request test comment. - - [1] https://aur.archlinux.org/account/user/ - [2] https://aur.archlinux.org/pkgbase/foobar/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of request open notifications for merge requests.' ' - >sendmail.out && - cover "$NOTIFY" request-open 1 3001 merge 1001 foobar2 && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: [PRQ#3001] Merge Request for foobar - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - user [1] filed a request to merge foobar [2] into foobar2 [3]: - - This is a request test comment. - - [1] https://aur.archlinux.org/account/user/ - [2] https://aur.archlinux.org/pkgbase/foobar/ - [3] https://aur.archlinux.org/pkgbase/foobar2/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test Cc, subject and body of request close notifications.' ' - >sendmail.out && - cover "$NOTIFY" request-close 1 3001 accepted && - grep ^Cc: sendmail.out >actual && - cat <<-EOD >expected && - Cc: user@localhost, tu@localhost - EOD - test_cmp actual expected && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: [PRQ#3001] Deletion Request for foobar Accepted - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - Request #3001 has been accepted by user [1]. - - [1] https://aur.archlinux.org/account/user/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of request close notifications (auto-accept).' ' - >sendmail.out && - cover "$NOTIFY" request-close 0 3001 accepted && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: [PRQ#3001] Deletion Request for foobar Accepted - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - Request #3001 has been accepted automatically by the Arch User - Repository package request system. - EOD - test_cmp actual expected -' - -test_expect_success 'Test Cc of request close notification with co-maintainer.' ' - cat <<-EOD | sqlite3 aur.db && - /* Use package base IDs which can be distinguished from user IDs. */ - INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (1001, 3, 1); - EOD - >sendmail.out && - "$NOTIFY" request-close 0 3001 accepted && - grep ^Cc: sendmail.out >actual && - cat <<-EOD >expected && - Cc: user@localhost, tu@localhost, dev@localhost - EOD - test_cmp actual expected && - cat <<-EOD | sqlite3 aur.db - DELETE FROM PackageComaintainers; - EOD -' - -test_expect_success 'Test subject and body of request close notifications with closure comment.' ' - cat <<-EOD | sqlite3 aur.db && - UPDATE PackageRequests SET ClosureComment = "This is a test closure comment." WHERE ID = 3001; - EOD - >sendmail.out && - cover "$NOTIFY" request-close 1 3001 accepted && - grep ^Subject: sendmail.out >actual && - cat <<-EOD >expected && - Subject: [PRQ#3001] Deletion Request for foobar Accepted - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - Request #3001 has been accepted by user [1]: - - This is a test closure comment. - - [1] https://aur.archlinux.org/account/user/ - EOD - test_cmp actual expected -' - -test_expect_success 'Test subject and body of TU vote reminders.' ' - >sendmail.out && - cover "$NOTIFY" tu-vote-reminder 1 && - grep ^Subject: sendmail.out | head -1 >actual && - cat <<-EOD >expected && - Subject: TU Vote Reminder: Proposal 1 - EOD - test_cmp actual expected && - sed -n "/^\$/,\$p" sendmail.out | head -4 | base64 -d >actual && - echo >>actual && - cat <<-EOD >expected && - Please remember to cast your vote on proposal 1 [1]. The voting period - ends in less than 48 hours. - - [1] https://aur.archlinux.org/tu/?id=1 - EOD - test_cmp actual expected -' - -test_done diff --git a/test/test_notify.py b/test/test_notify.py new file mode 100644 index 00000000..45a1df31 --- /dev/null +++ b/test/test_notify.py @@ -0,0 +1,643 @@ +from datetime import datetime +from typing import List +from unittest import mock + +import pytest + +from aurweb import config, db, models +from aurweb.models import Package, PackageBase, PackageRequest, User +from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID +from aurweb.models.request_type import ORPHAN_ID +from aurweb.scripts import notify, rendercomment +from aurweb.testing.email import Email +from aurweb.testing.smtp import FakeSMTP, FakeSMTP_SSL + +aur_location = config.get("options", "aur_location") +aur_request_ml = config.get("options", "aur_request_ml") + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + Passwd=str(), AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def user1() -> User: + with db.begin(): + user1 = db.create(User, Username="user1", Email="user1@example.org", + Passwd=str(), AccountTypeID=USER_ID) + yield user1 + + +@pytest.fixture +def user2() -> User: + with db.begin(): + user2 = db.create(User, Username="user2", Email="user2@example.org", + Passwd=str(), AccountTypeID=USER_ID) + yield user2 + + +@pytest.fixture +def pkgbases(user: User) -> List[PackageBase]: + now = int(datetime.utcnow().timestamp()) + + output = [] + with db.begin(): + for i in range(5): + output.append( + db.create(PackageBase, Name=f"pkgbase_{i}", + Maintainer=user, SubmittedTS=now, + ModifiedTS=now)) + db.create(models.PackageNotification, PackageBase=output[-1], + User=user) + yield output + + +@pytest.fixture +def pkgreq(user2: User, pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + with db.begin(): + pkgreq_ = db.create(PackageRequest, PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, User=user2, + ReqTypeID=ORPHAN_ID, + Comments="This is a request test comment.", + ClosureComment=str()) + yield pkgreq_ + + +@pytest.fixture +def packages(pkgbases: List[PackageBase]) -> List[Package]: + output = [] + with db.begin(): + for i, pkgbase in enumerate(pkgbases): + output.append( + db.create(Package, PackageBase=pkgbase, + Name=f"pkg_{i}", Version=f"{i}.0")) + yield output + + +def test_out_of_date(user: User, user1: User, user2: User, + pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + # Create two comaintainers. We'll pass the maintainer uid to + # FlagNotification, so we should expect to get two emails. + with db.begin(): + db.create(models.PackageComaintainer, + PackageBase=pkgbase, User=user1, Priority=1) + db.create(models.PackageComaintainer, + PackageBase=pkgbase, User=user2, Priority=2) + + # Send the notification for pkgbases[0]. + notif = notify.FlagNotification(user.ID, pkgbases[0].ID) + notif.send() + + # Should've gotten three emails: maintainer + the two comaintainers. + assert Email.count() == 3 + + # Comaintainer 1. + first = Email(1).parse() + assert first.headers.get("To") == user1.Email + + expected = f"AUR Out-of-date Notification for {pkgbase.Name}" + assert first.headers.get("Subject") == expected + + # Comaintainer 2. + second = Email(2).parse() + assert second.headers.get("To") == user2.Email + + # Maintainer. + third = Email(3).parse() + assert third.headers.get("To") == user.Email + + +def test_reset(user: User): + with db.begin(): + user.ResetKey = "12345678901234567890123456789012" + + notif = notify.ResetKeyNotification(user.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + expected = "AUR Password Reset" + assert email.headers.get("Subject") == expected + + expected = f"""\ +A password reset request was submitted for the account test associated +with your email address. If you wish to reset your password follow the +link [1] below, otherwise ignore this message and nothing will happen. + +[1] {aur_location}/passreset/?resetkey=12345678901234567890123456789012\ +""" + assert email.body == expected + + +def test_welcome(user: User): + with db.begin(): + user.ResetKey = "12345678901234567890123456789012" + + notif = notify.WelcomeNotification(user.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + expected = "Welcome to the Arch User Repository" + assert email.headers.get("Subject") == expected + + expected = f"""\ +Welcome to the Arch User Repository! In order to set an initial +password for your new account, please click the link [1] below. If the +link does not work, try copying and pasting it into your browser. + +[1] {aur_location}/passreset/?resetkey=12345678901234567890123456789012\ +""" + assert email.body == expected + + +def test_comment(user: User, user2: User, pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + + with db.begin(): + comment = db.create(models.PackageComment, PackageBase=pkgbase, + User=user2, Comments="This is a test comment.") + rendercomment.update_comment_render_fastapi(comment) + + notif = notify.CommentNotification(user2.ID, pkgbase.ID, comment.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Comment for {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +{user2.Username} [1] added the following comment to {pkgbase.Name} [2]: + +This is a test comment. + +-- +If you no longer wish to receive notifications about this package, +please go to the package page [2] and select "Disable notifications". + +[1] {aur_location}/account/{user2.Username}/ +[2] {aur_location}/pkgbase/{pkgbase.Name}/\ +""" + assert expected == email.body + + +def test_update(user: User, user2: User, pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + with db.begin(): + user.UpdateNotify = 1 + + notif = notify.UpdateNotification(user2.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Package Update: {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +{user2.Username} [1] pushed a new commit to {pkgbase.Name} [2]. + +-- +If you no longer wish to receive notifications about this package, +please go to the package page [2] and select "Disable notifications". + +[1] {aur_location}/account/{user2.Username}/ +[2] {aur_location}/pkgbase/{pkgbase.Name}/\ +""" + assert expected == email.body + + +def test_adopt(user: User, user2: User, pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + notif = notify.AdoptNotification(user2.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Ownership Notification for {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +The package {pkgbase.Name} [1] was adopted by {user2.Username} [2]. + +[1] {aur_location}/pkgbase/{pkgbase.Name}/ +[2] {aur_location}/account/{user2.Username}/\ +""" + assert email.body == expected + + +def test_disown(user: User, user2: User, pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + notif = notify.DisownNotification(user2.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Ownership Notification for {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +The package {pkgbase.Name} [1] was disowned by {user2.Username} [2]. + +[1] {aur_location}/pkgbase/{pkgbase.Name}/ +[2] {aur_location}/account/{user2.Username}/\ +""" + assert email.body == expected + + +def test_comaintainer_addition(user: User, pkgbases: List[PackageBase]): + # TODO: Add this in fastapi code! + pkgbase = pkgbases[0] + notif = notify.ComaintainerAddNotification(user.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Co-Maintainer Notification for {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +You were added to the co-maintainer list of {pkgbase.Name} [1]. + +[1] {aur_location}/pkgbase/{pkgbase.Name}/\ +""" + assert email.body == expected + + +def test_comaintainer_removal(user: User, pkgbases: List[PackageBase]): + # TODO: Add this in fastapi code! + pkgbase = pkgbases[0] + notif = notify.ComaintainerRemoveNotification(user.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Co-Maintainer Notification for {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +You were removed from the co-maintainer list of {pkgbase.Name} [1]. + +[1] {aur_location}/pkgbase/{pkgbase.Name}/\ +""" + assert email.body == expected + + +def test_delete(user: User, user2: User, pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + notif = notify.DeleteNotification(user2.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Package deleted: {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +{user2.Username} [1] deleted {pkgbase.Name} [2]. + +You will no longer receive notifications about this package. + +[1] {aur_location}/account/{user2.Username}/ +[2] {aur_location}/pkgbase/{pkgbase.Name}/\ +""" + assert email.body == expected + + +def test_merge(user: User, user2: User, pkgbases: List[PackageBase]): + source, target = pkgbases[:2] + notif = notify.DeleteNotification(user2.ID, source.ID, target.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"AUR Package deleted: {source.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +{user2.Username} [1] merged {source.Name} [2] into {target.Name} [3]. + +-- +If you no longer wish receive notifications about the new package, +please go to [3] and click "Disable notifications". + +[1] {aur_location}/account/{user2.Username}/ +[2] {aur_location}/pkgbase/{source.Name}/ +[3] {aur_location}/pkgbase/{target.Name}/\ +""" + assert email.body == expected + + +def set_tu(users: List[User]) -> User: + with db.begin(): + for user in users: + user.AccountTypeID = TRUSTED_USER_ID + + +def test_open_close_request(user: User, user2: User, + pkgreq: PackageRequest, + pkgbases: List[PackageBase]): + set_tu([user]) + pkgbase = pkgbases[0] + + # Send an open request notification. + notif = notify.RequestOpenNotification( + user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == aur_request_ml + assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) + expected = f"[PRQ#{pkgreq.ID}] Orphan Request for {pkgbase.Name}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +{user2.Username} [1] filed an orphan request for {pkgbase.Name} [2]: + +This is a request test comment. + +[1] {aur_location}/account/{user2.Username}/ +[2] {aur_location}/pkgbase/{pkgbase.Name}/\ +""" + assert email.body == expected + + # Now send a closure notification on the pkgbase we just opened. + notif = notify.RequestCloseNotification(user2.ID, pkgreq.ID, "rejected") + notif.send() + assert Email.count() == 2 + + email = Email(2).parse() + assert email.headers.get("To") == aur_request_ml + assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) + expected = f"[PRQ#{pkgreq.ID}] Orphan Request for {pkgbase.Name} Rejected" + assert email.headers.get("Subject") == expected + + expected = f"""\ +Request #{pkgreq.ID} has been rejected by {user2.Username} [1]. + +[1] {aur_location}/account/{user2.Username}/\ +""" + assert email.body == expected + + # Test auto-accept. + notif = notify.RequestCloseNotification(0, pkgreq.ID, "accepted") + notif.send() + assert Email.count() == 3 + + email = Email(3).parse() + assert email.headers.get("To") == aur_request_ml + assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) + expected = (f"[PRQ#{pkgreq.ID}] Orphan Request for " + f"{pkgbase.Name} Accepted") + assert email.headers.get("Subject") == expected + + expected = (f"Request #{pkgreq.ID} has been accepted automatically " + "by the Arch User Repository\npackage request system.") + assert email.body == expected + + +def test_close_request_auto_accept(): + pass + + +def test_close_request_comaintainer_cc(user: User, user2: User, + pkgreq: PackageRequest, + pkgbases: List[PackageBase]): + # TODO: Check this in fastapi code! + pkgbase = pkgbases[0] + with db.begin(): + db.create(models.PackageComaintainer, PackageBase=pkgbase, + User=user2, Priority=1) + + notif = notify.RequestCloseNotification(0, pkgreq.ID, "accepted") + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == aur_request_ml + assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) + + +def test_close_request_closure_comment(user: User, user2: User, + pkgreq: PackageRequest, + pkgbases: List[PackageBase]): + pkgbase = pkgbases[0] + with db.begin(): + pkgreq.ClosureComment = "This is a test closure comment." + + notif = notify.RequestCloseNotification(user2.ID, pkgreq.ID, "accepted") + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == aur_request_ml + assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) + expected = f"[PRQ#{pkgreq.ID}] Orphan Request for {pkgbase.Name} Accepted" + assert email.headers.get("Subject") == expected + + expected = f"""\ +Request #{pkgreq.ID} has been accepted by {user2.Username} [1]: + +This is a test closure comment. + +[1] {aur_location}/account/{user2.Username}/\ +""" + assert email.body == expected + + +def test_tu_vote_reminders(user: User): + set_tu([user]) + + vote_id = 1 + notif = notify.TUVoteReminderNotification(vote_id) + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"TU Vote Reminder: Proposal {vote_id}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +Please remember to cast your vote on proposal {vote_id} [1]. The voting period +ends in less than 48 hours. + +[1] {aur_location}/tu/?id={vote_id}\ +""" + assert email.body == expected + + +def test_notify_main(user: User): + """ Test TU vote reminder through aurweb.notify.main(). """ + set_tu([user]) + + vote_id = 1 + args = ["aurweb-notify", "tu-vote-reminder", str(vote_id)] + with mock.patch("sys.argv", args): + notify.main() + + assert Email.count() == 1 + + email = Email(1).parse() + assert email.headers.get("To") == user.Email + expected = f"TU Vote Reminder: Proposal {vote_id}" + assert email.headers.get("Subject") == expected + + expected = f"""\ +Please remember to cast your vote on proposal {vote_id} [1]. The voting period +ends in less than 48 hours. + +[1] {aur_location}/tu/?id={vote_id}\ +""" + assert email.body == expected + + +# Save original config.get; we're going to mock it and need +# to be able to fallback when we are not overriding. +config_get = config.get + + +def mock_smtp_config(cls): + def _mock_smtp_config(section: str, key: str): + if section == "notifications": + if key == "sendmail": + return cls() + elif key == "smtp-use-ssl": + return cls(0) + elif key == "smtp-use-starttls": + return cls(0) + elif key == "smtp-user": + return cls() + elif key == "smtp-password": + return cls() + return cls(config_get(section, key)) + return _mock_smtp_config + + +def test_smtp(user: User): + with db.begin(): + user.ResetKey = "12345678901234567890123456789012" + + SMTP = FakeSMTP() + + get = "aurweb.config.get" + getboolean = "aurweb.config.getboolean" + with mock.patch(get, side_effect=mock_smtp_config(str)): + with mock.patch(getboolean, side_effect=mock_smtp_config(bool)): + with mock.patch("smtplib.SMTP", side_effect=lambda a, b: SMTP): + config.rehash() + notif = notify.WelcomeNotification(user.ID) + notif.send() + config.rehash() + assert len(SMTP.emails) == 1 + + +def mock_smtp_starttls_config(cls): + def _mock_smtp_starttls_config(section: str, key: str): + if section == "notifications": + if key == "sendmail": + return cls() + elif key == "smtp-use-ssl": + return cls(0) + elif key == "smtp-use-starttls": + return cls(1) + elif key == "smtp-user": + return cls("test") + elif key == "smtp-password": + return cls("password") + return cls(config_get(section, key)) + return _mock_smtp_starttls_config + + +def test_smtp_starttls(user: User): + # This test does two things: test starttls path and test + # path where we have a backup email. + + with db.begin(): + user.ResetKey = "12345678901234567890123456789012" + user.BackupEmail = "backup@example.org" + + SMTP = FakeSMTP() + + get = "aurweb.config.get" + getboolean = "aurweb.config.getboolean" + with mock.patch(get, side_effect=mock_smtp_starttls_config(str)): + with mock.patch( + getboolean, side_effect=mock_smtp_starttls_config(bool)): + with mock.patch("smtplib.SMTP", side_effect=lambda a, b: SMTP): + notif = notify.WelcomeNotification(user.ID) + notif.send() + assert SMTP.starttls_enabled + assert SMTP.user + assert SMTP.passwd + + assert len(SMTP.emails) == 2 + to = SMTP.emails[0][1] + assert to == [user.Email] + + to = SMTP.emails[1][1] + assert to == [user.BackupEmail] + + +def mock_smtp_ssl_config(cls): + def _mock_smtp_ssl_config(section: str, key: str): + if section == "notifications": + if key == "sendmail": + return cls() + elif key == "smtp-use-ssl": + return cls(1) + elif key == "smtp-use-starttls": + return cls(0) + elif key == "smtp-user": + return cls("test") + elif key == "smtp-password": + return cls("password") + return cls(config_get(section, key)) + return _mock_smtp_ssl_config + + +def test_smtp_ssl(user: User): + with db.begin(): + user.ResetKey = "12345678901234567890123456789012" + + SMTP = FakeSMTP_SSL() + + get = "aurweb.config.get" + getboolean = "aurweb.config.getboolean" + with mock.patch(get, side_effect=mock_smtp_ssl_config(str)): + with mock.patch(getboolean, side_effect=mock_smtp_ssl_config(bool)): + with mock.patch("smtplib.SMTP_SSL", side_effect=lambda a, b: SMTP): + notif = notify.WelcomeNotification(user.ID) + notif.send() + assert len(SMTP.emails) == 1 + assert SMTP.use_ssl + assert SMTP.user + assert SMTP.passwd + + +def test_notification_defaults(): + notif = notify.Notification() + assert notif.get_refs() == tuple() + assert notif.get_headers() == dict() + assert notif.get_cc() == list() From 155aa47a1acf9143f8bce49a81f05f56f7e61042 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 25 Nov 2021 12:03:25 -0800 Subject: [PATCH 1179/1891] feat(poetry): add posix_ipc Signed-off-by: Kevin Morris --- poetry.lock | 18 +++++++++++++++++- pyproject.toml | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index ab559b77..d56ce458 100644 --- a/poetry.lock +++ b/poetry.lock @@ -619,6 +619,14 @@ dunamai = ">=1.5,<2.0" jinja2 = {version = ">=2.11.1,<4", markers = "python_version >= \"3.6\" and python_version < \"4.0\""} tomlkit = ">=0.4" +[[package]] +name = "posix-ipc" +version = "1.0.5" +description = "POSIX IPC primitives (semaphores, shared memory and message queues) for Python" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "priority" version = "2.0.0" @@ -1056,7 +1064,7 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.10" -content-hash = "ca42bd35717062d6784025ed3956423502ac66adba059ccc080bcaaa666651cd" +content-hash = "43b3dd494890ef9d419260a06ccd0190638573fdf0b92a226016f1dd5ee87579" [metadata.files] aiofiles = [ @@ -1555,6 +1563,14 @@ poetry-dynamic-versioning = [ {file = "poetry-dynamic-versioning-0.13.1.tar.gz", hash = "sha256:5c0e7b22560db76812057ef95dadad662ecc63eb270145787eabe73da7c222f9"}, {file = "poetry_dynamic_versioning-0.13.1-py3-none-any.whl", hash = "sha256:6d79f76436c624653fc06eb9bb54fb4f39b1d54362bc366ad2496855711d3a78"}, ] +posix-ipc = [ + {file = "posix_ipc-1.0.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ccb36ba90efec56a1796f1566eee9561f355a4f45babbc4d18ac46fb2d0b246b"}, + {file = "posix_ipc-1.0.5-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:613bf1afe90e84c06255ec1a6f52c9b24062492de66e5f0dbe068adf67fc3454"}, + {file = "posix_ipc-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6095bb4faa2bba8b8d0e833b804e0aedc352d5ed921edeb715010cbcd361e038"}, + {file = "posix_ipc-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:621918abe7ec68591c5839b0771d163a9809bc232bf413b9a681bf986ab68d4d"}, + {file = "posix_ipc-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f71587ad3a50e82583987f62bfd4ac2343ab6a206d1032e3fc560e8d55fe0346"}, + {file = "posix_ipc-1.0.5.tar.gz", hash = "sha256:6cddb1ce2cf4aae383f2a0079c26c69bee257fe2720f372201ef047f8ceb8b97"}, +] priority = [ {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, diff --git a/pyproject.toml b/pyproject.toml index 82c439bc..f164967c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,7 @@ mysql-connector = "^2.2.9" prometheus-fastapi-instrumentator = "^5.7.1" pytest-xdist = "^2.4.0" filelock = "^3.3.2" +posix-ipc = "^1.0.5" [tool.poetry.dev-dependencies] flake8 = "^4.0.1" From 4b0cb0721d8fc4fe2414e37a8a8fbf78949481a5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Nov 2021 20:06:50 -0800 Subject: [PATCH 1180/1891] fix(conftest): use synchronization locks for setup_database We were running into data race issues where the `fn.is_file()` check would occur twice before writing the file in the `else` clause. For this reason, a new aurweb.lock.Lock class has been added which doubles as a thread and process lock. We can use this elsewhere in the future, but we are also able to use it to solve this kind of data race issue. That being said, we still need the lock file state to tell us when the first caller acquired the lock. Signed-off-by: Kevin Morris --- aurweb/testing/filelock.py | 32 ++++++++++++++++++++ test/conftest.py | 61 +++++++++++++++++++++++--------------- test/test_filelock.py | 26 ++++++++++++++++ 3 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 aurweb/testing/filelock.py create mode 100644 test/test_filelock.py diff --git a/aurweb/testing/filelock.py b/aurweb/testing/filelock.py new file mode 100644 index 00000000..3a18c153 --- /dev/null +++ b/aurweb/testing/filelock.py @@ -0,0 +1,32 @@ +import hashlib +import os + +from typing import Callable + +from posix_ipc import O_CREAT, Semaphore + +from aurweb import logging + +logger = logging.get_logger(__name__) + + +def default_on_create(path): + logger.info(f"Filelock at {path} acquired.") + + +class FileLock: + def __init__(self, tmpdir, name: str): + self.root = tmpdir + self.path = str(self.root / name) + self._file = str(self.root / (f"{name}.1")) + + def lock(self, on_create: Callable = default_on_create): + hash = hashlib.sha1(self.path.encode()).hexdigest() + with Semaphore(f"/{hash}-lock", flags=O_CREAT, initial_value=1): + retval = os.path.exists(self._file) + if not retval: + with open(self._file, "w") as f: + f.write("1") + on_create(self.path) + + return retval diff --git a/test/conftest.py b/test/conftest.py index 01131109..80f77c9a 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -38,10 +38,14 @@ It is done this way because migration has a large cost; migrating ahead of each function takes too long when compared to this method. """ import os +import pathlib +from multiprocessing import Lock + +import py import pytest -from filelock import FileLock +from posix_ipc import O_CREAT, Semaphore from sqlalchemy import create_engine from sqlalchemy.engine import URL from sqlalchemy.engine.base import Engine @@ -53,9 +57,13 @@ import aurweb.db from aurweb import initdb, logging, testing from aurweb.testing.email import Email +from aurweb.testing.filelock import FileLock logger = logging.get_logger(__name__) +# Synchronization lock for database setup. +setup_lock = Lock() + def test_engine() -> Engine: """ @@ -105,7 +113,12 @@ def _create_database(engine: Engine, dbname: str) -> None: try: conn.execute(f"CREATE DATABASE {dbname}") except ProgrammingError: # pragma: no cover - pass + # The database most likely already existed if we hit + # a ProgrammingError. Just drop the database and try + # again. If at that point things still fail, any + # exception will be propogated up to the caller. + conn.execute(f"DROP DATABASE {dbname}") + conn.execute(f"CREATE DATABASE {dbname}") conn.close() initdb.run(AlembicArgs) @@ -124,20 +137,24 @@ def _drop_database(engine: Engine, dbname: str) -> None: def setup_email(): - if not os.path.exists(Email.TEST_DIR): - os.makedirs(Email.TEST_DIR) + # TODO: Fix this data race! This try/catch is ugly; why is it even + # racing here? Perhaps we need to multiproc + multithread lock + # inside of setup_database to block the check? + with Semaphore("/test-emails", flags=O_CREAT, initial_value=1): + if not os.path.exists(Email.TEST_DIR): + # Create the directory. + os.makedirs(Email.TEST_DIR) - # Cleanup all email files for this test suite. - prefix = Email.email_prefix(suite=True) - files = os.listdir(Email.TEST_DIR) - for file in files: - if file.startswith(prefix): - os.remove(os.path.join(Email.TEST_DIR, file)) + # Cleanup all email files for this test suite. + prefix = Email.email_prefix(suite=True) + files = os.listdir(Email.TEST_DIR) + for file in files: + if file.startswith(prefix): + os.remove(os.path.join(Email.TEST_DIR, file)) @pytest.fixture(scope="module") -def setup_database(tmp_path_factory: pytest.fixture, - worker_id: pytest.fixture) -> None: +def setup_database(tmp_path_factory: pathlib.Path, worker_id: str) -> None: """ Create and drop a database for the suite this fixture is used in. """ engine = test_engine() dbname = aurweb.db.name() @@ -149,19 +166,15 @@ def setup_database(tmp_path_factory: pytest.fixture, _drop_database(engine, dbname) return - root_tmp_dir = tmp_path_factory.getbasetemp().parent - fn = root_tmp_dir / dbname + def setup(path): + setup_email() + _create_database(engine, dbname) - with FileLock(str(fn) + ".lock"): - if fn.is_file(): - # If the data file exists, skip database creation. - yield - else: - # Otherwise, create the data file and create the database. - fn.write_text("1") - setup_email() - yield _create_database(engine, dbname) - _drop_database(engine, dbname) + tmpdir = tmp_path_factory.getbasetemp().parent + file_lock = FileLock(tmpdir, dbname) + file_lock.lock(on_create=setup) + yield # Run the test function depending on this fixture. + _drop_database(engine, dbname) # Cleanup the database. @pytest.fixture(scope="module") diff --git a/test/test_filelock.py b/test/test_filelock.py new file mode 100644 index 00000000..70aa7580 --- /dev/null +++ b/test/test_filelock.py @@ -0,0 +1,26 @@ +import py + +from _pytest.logging import LogCaptureFixture + +from aurweb.testing.filelock import FileLock + + +def test_filelock(tmpdir: py.path.local): + cb_path = None + + def setup(path: str): + nonlocal cb_path + cb_path = str(path) + + flock = FileLock(tmpdir, "test") + assert not flock.lock(on_create=setup) + assert cb_path == str(tmpdir / "test") + assert flock.lock() + + +def test_filelock_default(caplog: LogCaptureFixture, tmpdir: py.path.local): + # Test default_on_create here. + flock = FileLock(tmpdir, "test") + assert not flock.lock() + assert caplog.messages[0] == f"Filelock at {flock.path} acquired." + assert flock.lock() From 2d0e09cd63bc2a1c0baee0727aa5ede60e3475b1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Nov 2021 06:20:50 -0800 Subject: [PATCH 1181/1891] change(rendercomment): converted to use aurweb.db ORM - Added aurweb.util.git_search. - Decoupled away from rendercomment for easier testability. - Added aurweb.testing.git.GitRepository. - Added templates/testing/{PKGBUILD,SRCINFO}.j2. - Added aurweb.testing.git.GitRepository + `git` pytest fixture Signed-off-by: Kevin Morris --- aurweb/scripts/rendercomment.py | 57 ++++----- aurweb/testing/git.py | 110 +++++++++++++++++ aurweb/util.py | 17 +++ templates/testing/PKGBUILD.j2 | 14 +++ templates/testing/SRCINFO.j2 | 10 ++ test/conftest.py | 6 + test/t2600-rendercomment.t | 160 ------------------------- test/test_rendercomment.py | 202 ++++++++++++++++++++++++++++++++ test/test_util.py | 17 +++ 9 files changed, 398 insertions(+), 195 deletions(-) create mode 100644 aurweb/testing/git.py create mode 100644 templates/testing/PKGBUILD.j2 create mode 100644 templates/testing/SRCINFO.j2 delete mode 100755 test/t2600-rendercomment.t create mode 100644 test/test_rendercomment.py diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index efa5357f..33349432 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -7,13 +7,11 @@ import markdown import pygit2 import aurweb.config -import aurweb.db -from aurweb import logging +from aurweb import db, logging, util +from aurweb.models import PackageComment logger = logging.get_logger(__name__) -repo_path = aurweb.config.get('serve', 'repo-path') -commit_uri = aurweb.config.get('options', 'commit_uri') class LinkifyExtension(markdown.extensions.Extension): @@ -64,6 +62,7 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): """ def __init__(self, md, head): + repo_path = aurweb.config.get('serve', 'repo-path') self._repo = pygit2.Repository(repo_path) self._head = head super().__init__(r'\b([0-9a-f]{7,40})\b', md) @@ -74,13 +73,9 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): # Unkwown OID; preserve the orginal text. return (None, None, None) - prefixlen = 12 - while prefixlen < 40: - if oid[:prefixlen] in self._repo: - break - prefixlen += 1 - el = markdown.util.etree.Element('a') + commit_uri = aurweb.config.get("options", "commit_uri") + prefixlen = util.git_search(self._repo, oid) el.set('href', commit_uri % (self._head, oid[:prefixlen])) el.text = markdown.util.AtomicString(oid[:prefixlen]) return (el, m.start(0), m.end(0)) @@ -116,49 +111,41 @@ class HeadingExtension(markdown.extensions.Extension): md.treeprocessors.register(HeadingTreeprocessor(md), 'heading', 30) -def get_comment(conn, commentid): - cur = conn.execute('SELECT PackageComments.Comments, PackageBases.Name ' - 'FROM PackageComments INNER JOIN PackageBases ' - 'ON PackageBases.ID = PackageComments.PackageBaseID ' - 'WHERE PackageComments.ID = ?', [commentid]) - return cur.fetchone() +def save_rendered_comment(comment: PackageComment, html: str): + with db.begin(): + comment.RenderedComment = html -def save_rendered_comment(conn, commentid, html): - conn.execute('UPDATE PackageComments SET RenderedComment = ? WHERE ID = ?', - [html, commentid]) +def update_comment_render_fastapi(comment: PackageComment) -> None: + update_comment_render(comment) -def update_comment_render_fastapi(comment): - conn = aurweb.db.ConnectionExecutor( - aurweb.db.get_engine().raw_connection()) - update_comment_render(conn, comment.ID) - aurweb.db.refresh(comment) +def update_comment_render(comment: PackageComment) -> None: + text = comment.Comments + pkgbasename = comment.PackageBase.Name - -def update_comment_render(conn, commentid): - text, pkgbase = get_comment(conn, commentid) html = markdown.markdown(text, extensions=[ 'fenced_code', LinkifyExtension(), FlysprayLinksExtension(), - GitCommitsExtension(pkgbase), + GitCommitsExtension(pkgbasename), HeadingExtension() ]) allowed_tags = (bleach.sanitizer.ALLOWED_TAGS + ['p', 'pre', 'h4', 'h5', 'h6', 'br', 'hr']) html = bleach.clean(html, tags=allowed_tags) - save_rendered_comment(conn, commentid, html) - - conn.commit() - conn.close() + save_rendered_comment(comment, html) + db.refresh(comment) def main(): - commentid = int(sys.argv[1]) - conn = aurweb.db.Connection() - update_comment_render(conn, commentid) + db.get_engine() + comment_id = int(sys.argv[1]) + comment = db.query(PackageComment).filter( + PackageComment.ID == comment_id + ).first() + update_comment_render(comment) if __name__ == '__main__': diff --git a/aurweb/testing/git.py b/aurweb/testing/git.py new file mode 100644 index 00000000..019d870f --- /dev/null +++ b/aurweb/testing/git.py @@ -0,0 +1,110 @@ +import os +import shlex + +from subprocess import PIPE, Popen +from typing import Tuple + +import py + +from aurweb.models import Package +from aurweb.templates import base_template +from aurweb.testing.filelock import FileLock + + +class GitRepository: + """ + A Git repository class to be used for testing. + + Expects a `tmpdir` fixture on construction, which an 'aur.git' + git repository will be created in. After this class is constructed, + users can call GitRepository.exec for git repository operations. + """ + + def __init__(self, tmpdir: py.path.local): + self.file_lock = FileLock(tmpdir, "aur.git") + self.file_lock.lock(on_create=self._setup) + + def _exec(self, cmdline: str, cwd: str) -> Tuple[int, str, str]: + args = shlex.split(cmdline) + proc = Popen(args, cwd=cwd, stdout=PIPE, stderr=PIPE) + out, err = proc.communicate() + return (proc.returncode, out.decode().strip(), err.decode().strip()) + + def _exec_repository(self, cmdline: str) -> Tuple[int, str, str]: + return self._exec(cmdline, cwd=str(self.file_lock.path)) + + def exec(self, cmdline: str) -> Tuple[int, str, str]: + return self._exec_repository(cmdline) + + def _setup(self, path: str) -> None: + """ + Setup the git repository from scratch. + + Create the `path` directory and run the INSTALL recommended + git initialization commands inside of it. Additionally, install + aurweb.git.update to {path}/hooks/update. + + :param path: Repository path not yet created + """ + + os.makedirs(path) + + commands = [ + "git init -q", + "git config --local transfer.hideRefs '^refs/'", + "git config --local --add transfer.hideRefs '!refs/'", + "git config --local --add transfer.hideRefs '!HEAD'", + "git config --local commit.gpgsign false", + "git config --local user.name 'Test User'", + "git config --local user.email 'test@example.org'", + ] + for cmdline in commands: + return_code, out, err = self.exec(cmdline) + assert return_code == 0 + + # This is also done in the INSTALL script to give the `aur` + # ssh user permissions on the repository. We don't need it + # during testing, since our testing user will be controlling + # the repository. It is left here as a note. + # self.exec("chown -R aur .") + + def commit(self, pkg: Package, message: str): + """ + Commit a Package record to the git repository. + + This function generates a PKGBUILD and .SRCINFO based on + `pkg`, then commits them to the repository with the + `message` commit message. + + :param pkg: Package instance + :param message: Commit message + :return: Output of `git rev-parse HEAD` after committing + """ + ref = f"refs/namespaces/{pkg.Name}/refs/heads/master" + rc, out, err = self.exec(f"git checkout -q --orphan {ref}") + assert rc == 0, f"{(rc, out, err)}" + + # Path to aur.git repository. + repo = os.path.join(self.file_lock.path) + + licenses = [f"'{p.License.Name}'" for p in pkg.package_licenses] + depends = [f"'{p.DepName}'" for p in pkg.package_dependencies] + pkgbuild = base_template("testing/PKGBUILD.j2") + pkgbuild_path = os.path.join(repo, "PKGBUILD") + with open(pkgbuild_path, "w") as f: + data = pkgbuild.render(pkg=pkg, licenses=licenses, depends=depends) + f.write(data) + + srcinfo = base_template("testing/SRCINFO.j2") + srcinfo_path = os.path.join(repo, ".SRCINFO") + with open(srcinfo_path, "w") as f: + f.write(srcinfo.render(pkg=pkg)) + + rc, out, err = self.exec("git add PKGBUILD .SRCINFO") + assert rc == 0, f"{(rc, out, err)}" + + rc, out, err = self.exec(f"git commit -q -m '{message}'") + assert rc == 0, f"{(rc, out, err)}" + + # Return stdout of `git rev-parse HEAD`, which is the new commit hash. + return self.exec("git rev-parse HEAD")[1] diff --git a/aurweb/util.py b/aurweb/util.py index bf2d6e4b..f5ced259 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -13,6 +13,7 @@ from urllib.parse import urlencode, urlparse from zoneinfo import ZoneInfo import fastapi +import pygit2 from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email from jinja2 import pass_context @@ -193,3 +194,19 @@ def file_hash(filepath: str, hash_function: Callable) -> str: with open(filepath, "rb") as f: hash_ = hash_function(f.read()) return hash_.hexdigest() + + +def git_search(repo: pygit2.Repository, commit_hash: str) -> int: + """ + Return the shortest prefix length matching `commit_hash` found. + + :param repo: pygit2.Repository instance + :param commit_hash: Full length commit hash + :return: Shortest unique prefix length found + """ + prefixlen = 12 + while prefixlen < len(commit_hash): + if commit_hash[:prefixlen] in repo: + break + prefixlen += 1 + return prefixlen diff --git a/templates/testing/PKGBUILD.j2 b/templates/testing/PKGBUILD.j2 new file mode 100644 index 00000000..29d3a1d9 --- /dev/null +++ b/templates/testing/PKGBUILD.j2 @@ -0,0 +1,14 @@ +pkgname={{ pkg.PackageBase.Name }} +pkgver={{ pkg.Version }} +pkgrel=1 +pkgdesc='{{ pkg.Description }}' +url='{{ pkg.URL }}' +arch='any' +license=({{ licenses | join(" ") }}) +depends=({{ depends | join(" ") }}) +source=() +md5sums=() + +package() { + {{ body }} +} diff --git a/templates/testing/SRCINFO.j2 b/templates/testing/SRCINFO.j2 new file mode 100644 index 00000000..873b9c1b --- /dev/null +++ b/templates/testing/SRCINFO.j2 @@ -0,0 +1,10 @@ +pkgbase = {{ pkg.PackageBase.name }} + pkgver = {{ pkg.Version }} + pkgrel = 1 + pkgdesc = {{ pkg.Description }} + url = {{ pkg.URL }} + arch='any' + license = {{ pkg.package_licenses | join(", ", attribute="License.Name") }} + depends = {{ pkg.package_dependencies | join(", ", attribute="DepName") }} + +pkgname = {{ pkg.Name }} diff --git a/test/conftest.py b/test/conftest.py index 80f77c9a..fc7f77dc 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -58,6 +58,7 @@ import aurweb.db from aurweb import initdb, logging, testing from aurweb.testing.email import Email from aurweb.testing.filelock import FileLock +from aurweb.testing.git import GitRepository logger = logging.get_logger(__name__) @@ -211,3 +212,8 @@ def db_test(db_session: scoped_session) -> None: session via aurweb.db.get_session(). """ testing.setup_test_db() + + +@pytest.fixture +def git(tmpdir: py.path.local) -> GitRepository: + yield GitRepository(tmpdir) diff --git a/test/t2600-rendercomment.t b/test/t2600-rendercomment.t deleted file mode 100755 index bb84fcfe..00000000 --- a/test/t2600-rendercomment.t +++ /dev/null @@ -1,160 +0,0 @@ -#!/bin/sh - -test_description='rendercomment tests' - -. "$(dirname "$0")/setup.sh" - -test_expect_success 'Test comment rendering.' ' - cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageBases (ID, Name, PackagerUID, SubmittedTS, ModifiedTS, FlaggerComment) VALUES (1, "foobar", 1, 0, 0, ""); - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (1, 1, "Hello world! - This is a comment.", ""); - EOD - cover "$RENDERCOMMENT" 1 && - cat <<-EOD >expected && -

    Hello world! - This is a comment.

    - EOD - cat <<-EOD | sqlite3 aur.db >actual && - SELECT RenderedComment FROM PackageComments WHERE ID = 1; - EOD - test_cmp actual expected -' - -test_expect_success 'Test Markdown conversion.' ' - cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (2, 1, "*Hello* [world](https://www.archlinux.org/)!", ""); - EOD - cover "$RENDERCOMMENT" 2 && - cat <<-EOD >expected && -

    Hello world!

    - EOD - cat <<-EOD | sqlite3 aur.db >actual && - SELECT RenderedComment FROM PackageComments WHERE ID = 2; - EOD - test_cmp actual expected -' - -test_expect_success 'Test HTML sanitizing.' ' - cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (3, 1, "", ""); - EOD - cover "$RENDERCOMMENT" 3 && - cat <<-EOD >expected && - <script>alert("XSS!");</script> - EOD - cat <<-EOD | sqlite3 aur.db >actual && - SELECT RenderedComment FROM PackageComments WHERE ID = 3; - EOD - test_cmp actual expected -' - -test_expect_success 'Test link conversion.' ' - cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (4, 1, " - Visit https://www.archlinux.org/#_test_. - Visit *https://www.archlinux.org/*. - Visit . - Visit \`https://www.archlinux.org/\`. - Visit [Arch Linux](https://www.archlinux.org/). - Visit [Arch Linux][arch]. - [arch]: https://www.archlinux.org/ - ", ""); - EOD - cover "$RENDERCOMMENT" 4 && - cat <<-EOD >expected && -

    Visit https://www.archlinux.org/#_test_. - Visit https://www.archlinux.org/. - Visit https://www.archlinux.org/. - Visit https://www.archlinux.org/. - Visit Arch Linux. - Visit Arch Linux.

    - EOD - cat <<-EOD | sqlite3 aur.db >actual && - SELECT RenderedComment FROM PackageComments WHERE ID = 4; - EOD - test_cmp actual expected -' - -test_expect_success 'Test Git commit linkification.' ' - local oid=`git -C aur.git rev-parse --verify HEAD` - cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (5, 1, " - $oid - ${oid:0:7} - x.$oid.x - ${oid}x - 0123456789abcdef - \`$oid\` - http://example.com/$oid - ", ""); - EOD - cover "$RENDERCOMMENT" 5 && - cat <<-EOD >expected && -

    ${oid:0:12} - ${oid:0:7} - x.${oid:0:12}.x - ${oid}x - 0123456789abcdef - $oid - http://example.com/$oid

    - EOD - cat <<-EOD | sqlite3 aur.db >actual && - SELECT RenderedComment FROM PackageComments WHERE ID = 5; - EOD - test_cmp actual expected -' - -test_expect_success 'Test Flyspray issue linkification.' ' - sqlite3 aur.db <<-EOD && - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (6, 1, " - FS#1234567. - *FS#1234* - FS# - XFS#1 - \`FS#1234\` - https://archlinux.org/?test=FS#1234 - ", ""); - EOD - cover "$RENDERCOMMENT" 6 && - cat <<-EOD >expected && -

    FS#1234567. - FS#1234 - FS# - XFS#1 - FS#1234 - https://archlinux.org/?test=FS#1234

    - EOD - sqlite3 aur.db <<-EOD >actual && - SELECT RenderedComment FROM PackageComments WHERE ID = 6; - EOD - test_cmp actual expected -' - -test_expect_success 'Test headings lowering.' ' - sqlite3 aur.db <<-EOD && - INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (7, 1, " - # One - ## Two - ### Three - #### Four - ##### Five - ###### Six - ", ""); - EOD - cover "$RENDERCOMMENT" 7 && - cat <<-EOD >expected && -
    One
    -
    Two
    -
    Three
    -
    Four
    -
    Five
    -
    Six
    - EOD - sqlite3 aur.db <<-EOD >actual && - SELECT RenderedComment FROM PackageComments WHERE ID = 7; - EOD - test_cmp actual expected -' - -test_done diff --git a/test/test_rendercomment.py b/test/test_rendercomment.py new file mode 100644 index 00000000..c45d4235 --- /dev/null +++ b/test/test_rendercomment.py @@ -0,0 +1,202 @@ +from datetime import datetime +from unittest import mock + +import pytest + +from aurweb import config, db, logging +from aurweb.models import Package, PackageBase, PackageComment, User +from aurweb.models.account_type import USER_ID +from aurweb.scripts import rendercomment +from aurweb.scripts.rendercomment import update_comment_render +from aurweb.testing.git import GitRepository + +logger = logging.get_logger(__name__) +aur_location = config.get("options", "aur_location") + + +@pytest.fixture(autouse=True) +def setup(db_test, git: GitRepository): + config_get = config.get + + def mock_config_get(section: str, key: str) -> str: + if section == "serve" and key == "repo-path": + return git.file_lock.path + elif section == "options" and key == "commit_uri": + return "/cgit/aur.git/log/?h=%s&id=%s" + return config_get(section, key) + + with mock.patch("aurweb.config.get", side_effect=mock_config_get): + yield + + +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + Passwd=str(), AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def pkgbase(user: User) -> PackageBase: + now = int(datetime.utcnow().timestamp()) + with db.begin(): + pkgbase = db.create(PackageBase, Packager=user, Name="pkgbase_0", + SubmittedTS=now, ModifiedTS=now) + yield pkgbase + + +@pytest.fixture +def package(pkgbase: PackageBase) -> Package: + with db.begin(): + package = db.create(Package, PackageBase=pkgbase, + Name=pkgbase.Name, Version="1.0") + yield package + + +def create_comment(user: User, pkgbase: PackageBase, comments: str, + render: bool = True): + with db.begin(): + comment = db.create(PackageComment, User=user, + PackageBase=pkgbase, Comments=comments) + if render: + update_comment_render(comment) + return comment + + +def test_comment_rendering(user: User, pkgbase: PackageBase): + text = "Hello world! This is a comment." + comment = create_comment(user, pkgbase, text) + expected = f"

    {text}

    " + assert comment.RenderedComment == expected + + +def test_rendercomment_main(user: User, pkgbase: PackageBase): + text = "Hello world! This is a comment." + comment = create_comment(user, pkgbase, text, False) + + args = ["aurweb-rendercomment", str(comment.ID)] + with mock.patch("sys.argv", args): + rendercomment.main() + db.refresh(comment) + + expected = f"

    {text}

    " + assert comment.RenderedComment == expected + + +def test_markdown_conversion(user: User, pkgbase: PackageBase): + text = "*Hello* [world](https://aur.archlinux.org)!" + comment = create_comment(user, pkgbase, text) + expected = ('

    Hello ' + 'world!

    ') + assert comment.RenderedComment == expected + + +def test_html_sanitization(user: User, pkgbase: PackageBase): + text = '' + comment = create_comment(user, pkgbase, text) + expected = '<script>alert("XSS!")</script>' + assert comment.RenderedComment == expected + + +def test_link_conversion(user: User, pkgbase: PackageBase): + text = """\ +Visit https://www.archlinux.org/#_test_. +Visit *https://www.archlinux.org/*. +Visit . +Visit `https://www.archlinux.org/`. +Visit [Arch Linux](https://www.archlinux.org/). +Visit [Arch Linux][arch]. +[arch]: https://www.archlinux.org/\ +""" + comment = create_comment(user, pkgbase, text) + expected = '''\ +

    Visit \ +https://www.archlinux.org/#_test_. +Visit https://www.archlinux.org/. +Visit https://www.archlinux.org/. +Visit https://www.archlinux.org/. +Visit Arch Linux. +Visit Arch Linux.

    \ +''' + assert comment.RenderedComment == expected + + +def test_git_commit_link(git: GitRepository, user: User, package: Package): + commit_hash = git.commit(package, "Initial commit.") + logger.info(f"Created commit: {commit_hash}") + logger.info(f"Short hash: {commit_hash[:7]}") + + text = f"""\ +{commit_hash} +{commit_hash[:7]} +x.{commit_hash}.x +{commit_hash}x +0123456789abcdef +`{commit_hash}` +http://example.com/{commit_hash}\ +""" + comment = create_comment(user, package.PackageBase, text) + + pkgname = package.PackageBase.Name + cgit_path = f"/cgit/aur.git/log/?h={pkgname}&" + expected = f"""\ +

    {commit_hash[:12]} +{commit_hash[:7]} +x.{commit_hash[:12]}.x +{commit_hash}x +0123456789abcdef +{commit_hash} +\ +http://example.com/{commit_hash}\ +\ +

    \ +""" + assert comment.RenderedComment == expected + + +def test_flyspray_issue_link(user: User, pkgbase: PackageBase): + text = """\ +FS#1234567. +*FS#1234* +FS# +XFS#1 +`FS#1234` +https://archlinux.org/?test=FS#1234\ +""" + comment = create_comment(user, pkgbase, text) + + expected = """\ +

    FS#1234567. +FS#1234 +FS# +XFS#1 +FS#1234 +\ +https://archlinux.org/?test=FS#1234\ +\ +

    \ +""" + assert comment.RenderedComment == expected + + +def test_lower_headings(user: User, pkgbase: PackageBase): + text = """\ +# One +## Two +### Three +#### Four +##### Five +###### Six\ +""" + comment = create_comment(user, pkgbase, text) + + expected = """\ +
    One
    +
    Two
    +
    Three
    +
    Four
    +
    Five
    +
    Six
    \ +""" + assert comment.RenderedComment == expected diff --git a/test/test_util.py b/test/test_util.py index 99b77a78..2529ed1f 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -40,3 +40,20 @@ def test_round(): assert filters.do_round(1.3) == 1 assert filters.do_round(1.5) == 2 assert filters.do_round(2.0) == 2 + + +def test_git_search(): + """ Test that git_search matches the full commit if necessary. """ + commit_hash = "0123456789abcdef" + repo = {commit_hash} + prefixlen = util.git_search(repo, commit_hash) + assert prefixlen == 16 + + +def test_git_search_double_commit(): + """ Test that git_search matches a shorter prefix length. """ + commit_hash = "0123456789abcdef" + repo = {commit_hash[:13]} + # Locate the shortest prefix length that matches commit_hash. + prefixlen = util.git_search(repo, commit_hash) + assert prefixlen == 13 From bc1cf8b1f6089d0776dc753bc9255032aaf83a8f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 24 Nov 2021 20:30:16 -0800 Subject: [PATCH 1182/1891] fix(rendercomment): markdown.util.etree -> xml.etree.ElementTree This removes a deprecation warning. Signed-off-by: Kevin Morris --- aurweb/scripts/rendercomment.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 33349432..2af5384e 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -2,6 +2,8 @@ import sys +from xml.etree.ElementTree import Element + import bleach import markdown import pygit2 @@ -40,7 +42,7 @@ class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): """ def handleMatch(self, m, data): - el = markdown.util.etree.Element('a') + el = Element('a') el.set('href', f'https://bugs.archlinux.org/task/{m.group(1)}') el.text = markdown.util.AtomicString(m.group(0)) return (el, m.start(0), m.end(0)) @@ -73,7 +75,7 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): # Unkwown OID; preserve the orginal text. return (None, None, None) - el = markdown.util.etree.Element('a') + el = Element('a') commit_uri = aurweb.config.get("options", "commit_uri") prefixlen = util.git_search(self._repo, oid) el.set('href', commit_uri % (self._head, oid[:prefixlen])) From 67a6b8360eccb02ac4a65940fde7fa6801ac2398 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 24 Nov 2021 20:33:42 -0800 Subject: [PATCH 1183/1891] fix(docker): remove update and build steps from poetry `install` includes dependencies present in poetry.lock and we must stick to them if we wish to pin dependencies. Signed-off-by: Kevin Morris --- docker/scripts/install-python-deps.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker/scripts/install-python-deps.sh b/docker/scripts/install-python-deps.sh index 3ab87742..3d5f28f0 100755 --- a/docker/scripts/install-python-deps.sh +++ b/docker/scripts/install-python-deps.sh @@ -6,8 +6,6 @@ pip install --upgrade pip # Install the aurweb package and deps system-wide via poetry. poetry config virtualenvs.create false -poetry update -poetry build poetry install --no-interaction --no-ansi exec "$@" From 4426c639ceb59ea5d6414b70157f2c0e7cea4f6b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 24 Nov 2021 20:34:45 -0800 Subject: [PATCH 1184/1891] fix(logging): remove `test` logger definition Like the `aurweb` logger definiton was previously, the `test` logger is being redundant with the root logger. Use root for all aurweb-local logging. Signed-off-by: Kevin Morris --- logging.conf | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/logging.conf b/logging.conf index 3b96e827..deb79cf5 100644 --- a/logging.conf +++ b/logging.conf @@ -1,5 +1,5 @@ [loggers] -keys=root,test,uvicorn,hypercorn,alembic +keys=root,uvicorn,hypercorn,alembic [handlers] keys=simpleHandler,detailedHandler @@ -10,12 +10,7 @@ keys=simpleFormatter,detailedFormatter [logger_root] level=INFO handlers=detailedHandler - -[logger_test] -level=DEBUG -handlers=detailedHandler -qualname=test -propagate=1 +propogate=1 [logger_uvicorn] level=DEBUG From 436d7420179043baf4814b2d10bc1cb460132d97 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Nov 2021 14:02:47 -0800 Subject: [PATCH 1185/1891] fix(fastapi): use CRED_TU_LIST_VOTES for "Trusted User" navigation item Closes #189 Signed-off-by: Kevin Morris --- aurweb/auth.py | 2 +- templates/partials/archdev-navbar.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 98a43fd5..4d6dafc6 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -329,7 +329,7 @@ cred_filters = { CRED_PKGREQ_CLOSE: trusted_user_or_dev, CRED_PKGREQ_LIST: trusted_user_or_dev, CRED_TU_ADD_VOTE: trusted_user, - CRED_TU_LIST_VOTES: trusted_user, + CRED_TU_LIST_VOTES: trusted_user_or_dev, CRED_TU_VOTE: trusted_user, CRED_ACCOUNT_EDIT_DEV: developer, CRED_PKGBASE_MERGE: trusted_user_or_dev, diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index ead0d8e2..81695951 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -36,8 +36,8 @@ - {# Only CRED_TU_VOTE privileged users see Trusted User #} - {% if request.user.has_credential("CRED_TU_VOTE") %} + {# Only CRED_TU_LIST_VOTES privileged users see Trusted User #} + {% if request.user.has_credential("CRED_TU_LIST_VOTES") %}
  • {% trans %}Trusted User{% endtrans %}
  • From 44f2366675f0ca81af443dfa293d5251b1f2eb02 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Nov 2021 16:20:36 -0800 Subject: [PATCH 1186/1891] fix: remove TODO comments and noop tests from test_notify Signed-off-by: Kevin Morris --- test/test_notify.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/test_notify.py b/test/test_notify.py index 45a1df31..dc6e7e3e 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -262,7 +262,6 @@ The package {pkgbase.Name} [1] was disowned by {user2.Username} [2]. def test_comaintainer_addition(user: User, pkgbases: List[PackageBase]): - # TODO: Add this in fastapi code! pkgbase = pkgbases[0] notif = notify.ComaintainerAddNotification(user.ID, pkgbase.ID) notif.send() @@ -282,7 +281,6 @@ You were added to the co-maintainer list of {pkgbase.Name} [1]. def test_comaintainer_removal(user: User, pkgbases: List[PackageBase]): - # TODO: Add this in fastapi code! pkgbase = pkgbases[0] notif = notify.ComaintainerRemoveNotification(user.ID, pkgbase.ID) notif.send() @@ -417,14 +415,9 @@ Request #{pkgreq.ID} has been rejected by {user2.Username} [1]. assert email.body == expected -def test_close_request_auto_accept(): - pass - - def test_close_request_comaintainer_cc(user: User, user2: User, pkgreq: PackageRequest, pkgbases: List[PackageBase]): - # TODO: Check this in fastapi code! pkgbase = pkgbases[0] with db.begin(): db.create(models.PackageComaintainer, PackageBase=pkgbase, From 69eb17cb0d659d7de7a51715d2113e806663eb44 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Nov 2021 16:51:16 -0800 Subject: [PATCH 1187/1891] change(fastapi): remove the GET /logout route; replaced with POST Had to add some additional CSS in to style a form button the same as links are styled. Closes #188 Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 15 ++------------- templates/partials/archdev-navbar.html | 9 ++++++--- test/test_auth_routes.py | 3 ++- web/html/css/aurweb.css | 15 +++++++++++++++ 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index c5a99419..fdc421f5 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -77,14 +77,9 @@ async def login_post(request: Request, return response -@router.get("/logout") +@router.post("/logout") @auth_required() -async def logout(request: Request, next: str = "/"): - """ A GET and POST route for logging out. - - @param request FastAPI request - @param next Route to redirect to - """ +async def logout(request: Request, next: str = Form(default="/")): if request.user.is_authenticated(): request.user.logout(request) @@ -95,9 +90,3 @@ async def logout(request: Request, next: str = "/"): response.delete_cookie("AURSID") response.delete_cookie("AURTZ") return response - - -@router.post("/logout") -@auth_required() -async def logout_post(request: Request, next: str = "/"): - return await logout(request=request, next=next) diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index 81695951..2e01eeab 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -45,9 +45,12 @@ {# All logged in users see Logout #}
  • - - {% trans %}Logout{% endtrans %} - +
  • {% else %} {# All guest users see Register #} diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index a0bb8a7c..dffd1b94 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -154,8 +154,9 @@ def test_unauthenticated_logout_unauthorized(): with client as request: # Alright, let's verify that attempting to /logout when not # authenticated returns 401 Unauthorized. - response = request.get("/logout", allow_redirects=False) + response = request.post("/logout", allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location").startswith("/login") def test_login_missing_username(): diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 62179769..cd81160d 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -229,3 +229,18 @@ input#search-action-submit { .success { color: green; } + +/* Styling used to clone styles for a form.link button. */ +form.link, form.link > button { + display: inline-block; +} +form.link > button { + padding: 0 0.5em; + color: #07b; + background: none; + border: none; +} +form.link > button:hover { + cursor: pointer; + text-decoration: underline; +} From fd8d23a37937f1bab5dfffea393ea30f0656df03 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Nov 2021 19:04:55 -0800 Subject: [PATCH 1188/1891] fix(fastapi): fix new Logout nav item css Signed-off-by: Kevin Morris --- web/html/css/aurweb.css | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index cd81160d..dafa8c91 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -231,16 +231,19 @@ input#search-action-submit { } /* Styling used to clone styles for a form.link button. */ -form.link, form.link > button { +form.link, form.link button { display: inline-block; + font-family: sans-serif; } -form.link > button { +form.link button { padding: 0 0.5em; color: #07b; background: none; border: none; + font-family: inherit; + font-size: inherit; } -form.link > button:hover { +form.link button:hover { cursor: pointer; text-decoration: underline; } From 9bfe2b07ba712f1667f93a4527b6a76b0b3cfcc1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Nov 2021 19:39:27 -0800 Subject: [PATCH 1189/1891] fix(fastapi): render Logged-in as page on authenticated /login This was missed during the initial porting of the /login route. Modifications: ------------- - A form is now used for the [Logout] link and some css was needed to deal with positioning. Closes #186 Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 1 - templates/login.html | 162 +++++++++++++++++++++------------------ test/test_auth_routes.py | 10 ++- web/html/css/aurweb.css | 10 ++- 4 files changed, 104 insertions(+), 79 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index fdc421f5..1e0b026a 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -24,7 +24,6 @@ async def login_template(request: Request, next: str, errors: list = None): @router.get("/login", response_class=HTMLResponse) -@auth_required(False, login=False) async def login_get(request: Request, next: str = "/"): return await login_template(request, next) diff --git a/templates/login.html b/templates/login.html index 2c028936..c62de43e 100644 --- a/templates/login.html +++ b/templates/login.html @@ -5,81 +5,95 @@

    AUR {% trans %}Login{% endtrans %}

    - {% if request.url.scheme == "http" and config.getboolean("options", "disable_http_login") %} - {% set https_login = url_base.replace("http://", "https://") + "/login" %} -

    - {{ "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." - | tr - | format( - '' | format(https_login), - "") - | safe - }} -

    - {% elif request.user.is_authenticated() %} -

    - {{ "Logged-in as: %s" - | tr - | format("%s" | format(request.user.Username)) - | safe - }} - [{% trans %}Logout{% endtrans %}] -

    - {% else %} -
    -
    - {% trans %}Enter login credentials{% endtrans %} - - {% if errors %} -
      - {% for error in errors %} -
    • {{ error }}
    • - {% endfor %} -
    - {% endif %} - -

    - - - -

    - -

    - - -

    - -

    - - -

    - -

    - - - [{% trans %}Forgot Password{% endtrans %}] - - - -

    - -
    + {% if request.user.is_authenticated() %} + +

    + {{ + "Logged-in as: %s" | tr + | format("%s" | format(request.user.Username)) + | safe + }} + + +

    + {% else %} + {% if request.url.scheme == "http" and config.getboolean("options", "disable_http_login") %} + {% set https_login = url_base.replace("http://", "https://") + "/login" %} +

    + {{ "HTTP login is disabled. Please %sswitch to HTTPs%s if you want to login." + | tr + | format( + '' | format(https_login), + "") + | safe + }} +

    + {% elif request.user.is_authenticated() %} +

    + {{ "Logged-in as: %s" + | tr + | format("%s" | format(request.user.Username)) + | safe + }} + [{% trans %}Logout{% endtrans %}] +

    + {% else %} +
    +
    + {% trans %}Enter login credentials{% endtrans %} + + {% if errors %} +
      + {% for error in errors %} +
    • {{ error }}
    • + {% endfor %} +
    + {% endif %} + +

    + + + +

    + +

    + + +

    + +

    + + +

    + +

    + + + [{% trans %}Forgot Password{% endtrans %}] + + + +

    + +
    +
    + {% endif %} {% endif %}
    diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index dffd1b94..0157fcc8 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -131,7 +131,7 @@ def test_secure_login(mock): assert user.session == record -def test_authenticated_login_forbidden(): +def test_authenticated_login(): post_data = { "user": "test", "passwd": "testPassword", @@ -139,15 +139,19 @@ def test_authenticated_login_forbidden(): } with client as request: - # Login. + # Try to login. response = request.post("/login", data=post_data, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.headers.get("location") == "/" + # Now, let's verify that we get the logged in rendering + # when requesting GET /login as an authenticated user. # Now, let's verify that we receive 403 Forbidden when we # try to get /login as an authenticated user. response = request.get("/login", allow_redirects=False) - assert response.status_code == int(HTTPStatus.SEE_OTHER) + assert response.status_code == int(HTTPStatus.OK) + assert "Logged-in as: test" in response.text def test_unauthenticated_logout_unauthorized(): diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index dafa8c91..739ac7b7 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -232,7 +232,7 @@ input#search-action-submit { /* Styling used to clone styles for a form.link button. */ form.link, form.link button { - display: inline-block; + display: inline; font-family: sans-serif; } form.link button { @@ -247,3 +247,11 @@ form.link button:hover { cursor: pointer; text-decoration: underline; } + +/* Customize form.link when used inside of a page. */ +div.box form.link p { + margin: .33em 0 1em; +} +div.box form.link button { + padding: 0; +} From 001e86317fd19b68491e61e8fad811a89a17ad3e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Nov 2021 19:44:18 -0800 Subject: [PATCH 1190/1891] fix(rpc): fix ordering of related records They were being ordered by IDs; they should be ordered by Names. Signed-off-by: Kevin Morris --- aurweb/rpc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index c70ddf1a..7bdae638 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -193,7 +193,7 @@ class RPC: models.DependencyType.Name.label("Type"), models.PackageDependency.DepName.label("Name"), models.PackageDependency.DepCondition.label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # PackageRelation db.query( @@ -205,7 +205,7 @@ class RPC: models.RelationType.Name.label("Type"), models.PackageRelation.RelName.label("Name"), models.PackageRelation.RelCondition.label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # Groups db.query(models.PackageGroup).join( @@ -217,7 +217,7 @@ class RPC: literal("Groups").label("Type"), models.Group.Name.label("Name"), literal(str()).label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # Licenses db.query(models.PackageLicense).join( @@ -230,7 +230,7 @@ class RPC: literal("License").label("Type"), models.License.Name.label("Name"), literal(str()).label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # Keywords db.query(models.PackageKeyword).join( @@ -242,7 +242,7 @@ class RPC: literal("Keywords").label("Type"), models.PackageKeyword.Keyword.label("Name"), literal(str()).label("Cond") - ).distinct().order_by("ID") + ).distinct().order_by("Name") ] # Union all subqueries together. From a6ac5f0dbf5b2e8d0d0c55a58e7a41ee7d5ad5dc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 29 Nov 2021 19:44:18 -0800 Subject: [PATCH 1191/1891] fix(rpc): fix ordering of related records They were being ordered by IDs; they should be ordered by Names. Signed-off-by: Kevin Morris --- aurweb/rpc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index c70ddf1a..7bdae638 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -193,7 +193,7 @@ class RPC: models.DependencyType.Name.label("Type"), models.PackageDependency.DepName.label("Name"), models.PackageDependency.DepCondition.label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # PackageRelation db.query( @@ -205,7 +205,7 @@ class RPC: models.RelationType.Name.label("Type"), models.PackageRelation.RelName.label("Name"), models.PackageRelation.RelCondition.label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # Groups db.query(models.PackageGroup).join( @@ -217,7 +217,7 @@ class RPC: literal("Groups").label("Type"), models.Group.Name.label("Name"), literal(str()).label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # Licenses db.query(models.PackageLicense).join( @@ -230,7 +230,7 @@ class RPC: literal("License").label("Type"), models.License.Name.label("Name"), literal(str()).label("Cond") - ).distinct().order_by("ID"), + ).distinct().order_by("Name"), # Keywords db.query(models.PackageKeyword).join( @@ -242,7 +242,7 @@ class RPC: literal("Keywords").label("Type"), models.PackageKeyword.Keyword.label("Name"), literal(str()).label("Cond") - ).distinct().order_by("ID") + ).distinct().order_by("Name") ] # Union all subqueries together. From ecbab8546b68574c939b269dac1ac2d77e53766b Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Thu, 21 Oct 2021 17:48:29 -0400 Subject: [PATCH 1192/1891] fix(FastAPI): access AccountType ID directly Signed-off-by: Steven Guikal --- aurweb/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/auth.py b/aurweb/auth.py index 4d6dafc6..1527f0a3 100644 --- a/aurweb/auth.py +++ b/aurweb/auth.py @@ -244,7 +244,7 @@ def account_type_required(one_of: set): def decorator(func): @functools.wraps(func) async def wrapper(request: fastapi.Request, *args, **kwargs): - if request.user.AccountType.ID not in one_of: + if request.user.AccountTypeID not in one_of: return RedirectResponse("/", status_code=int(HTTPStatus.SEE_OTHER)) return await func(request, *args, **kwargs) From 125b244f4478146ae293f76ca4a53a77160feda3 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Thu, 21 Oct 2021 17:49:10 -0400 Subject: [PATCH 1193/1891] fix(FastAPI): use account type vars instead of strings Signed-off-by: Steven Guikal --- aurweb/routers/trusted_user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 7c0a0404..f0cea61e 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -228,7 +228,7 @@ async def trusted_user_proposal_post(request: Request, @router.get("/addvote") @auth_required(True, redirect="/addvote") -@account_type_required({"Trusted User", "Trusted User & Developer"}) +@account_type_required({TRUSTED_USER, TRUSTED_USER_AND_DEV}) async def trusted_user_addvote(request: Request, user: str = str(), type: str = "add_tu", From a10f8663fd9bc4ddb990f1dfba31cb3331f4c9e9 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Tue, 30 Nov 2021 15:44:18 -0500 Subject: [PATCH 1194/1891] fix(FastAPI): reorganize credential checkin into dedicated file Signed-off-by: Steven Guikal --- aurweb/{auth.py => auth/__init__.py} | 98 ------------------------ aurweb/auth/creds.py | 76 ++++++++++++++++++ aurweb/models/user.py | 9 ++- aurweb/routers/accounts.py | 6 +- aurweb/routers/packages.py | 56 +++++++------- aurweb/templates.py | 3 +- templates/partials/account/comment.html | 2 +- templates/partials/account_form.html | 2 +- templates/partials/archdev-navbar.html | 4 +- templates/partials/comment_actions.html | 8 +- templates/partials/packages/actions.html | 8 +- templates/partials/packages/comment.html | 2 +- templates/partials/packages/details.html | 4 +- test/test_auth.py | 12 +-- test/test_user.py | 25 +++--- 15 files changed, 143 insertions(+), 172 deletions(-) rename aurweb/{auth.py => auth/__init__.py} (75%) create mode 100644 aurweb/auth/creds.py diff --git a/aurweb/auth.py b/aurweb/auth/__init__.py similarity index 75% rename from aurweb/auth.py rename to aurweb/auth/__init__.py index 1527f0a3..82192cc2 100644 --- a/aurweb/auth.py +++ b/aurweb/auth/__init__.py @@ -250,101 +250,3 @@ def account_type_required(one_of: set): return await func(request, *args, **kwargs) return wrapper return decorator - - -CRED_ACCOUNT_CHANGE_TYPE = 1 -CRED_ACCOUNT_EDIT = 2 -CRED_ACCOUNT_EDIT_DEV = 3 -CRED_ACCOUNT_LAST_LOGIN = 4 -CRED_ACCOUNT_SEARCH = 5 -CRED_ACCOUNT_LIST_COMMENTS = 28 -CRED_COMMENT_DELETE = 6 -CRED_COMMENT_UNDELETE = 27 -CRED_COMMENT_VIEW_DELETED = 22 -CRED_COMMENT_EDIT = 25 -CRED_COMMENT_PIN = 26 -CRED_PKGBASE_ADOPT = 7 -CRED_PKGBASE_SET_KEYWORDS = 8 -CRED_PKGBASE_DELETE = 9 -CRED_PKGBASE_DISOWN = 10 -CRED_PKGBASE_EDIT_COMAINTAINERS = 24 -CRED_PKGBASE_FLAG = 11 -CRED_PKGBASE_LIST_VOTERS = 12 -CRED_PKGBASE_NOTIFY = 13 -CRED_PKGBASE_UNFLAG = 15 -CRED_PKGBASE_VOTE = 16 -CRED_PKGREQ_FILE = 23 -CRED_PKGREQ_CLOSE = 17 -CRED_PKGREQ_LIST = 18 -CRED_TU_ADD_VOTE = 19 -CRED_TU_LIST_VOTES = 20 -CRED_TU_VOTE = 21 -CRED_PKGBASE_MERGE = 29 - - -def has_any(user, *account_types): - return str(user.AccountType) in set(account_types) - - -def user_developer_or_trusted_user(user): - return True - - -def trusted_user(user): - return has_any(user, "Trusted User", "Trusted User & Developer") - - -def developer(user): - return has_any(user, "Developer", "Trusted User & Developer") - - -def trusted_user_or_dev(user): - return has_any(user, "Trusted User", "Developer", - "Trusted User & Developer") - - -# A mapping of functions that users must pass to have credentials. -cred_filters = { - CRED_PKGBASE_FLAG: user_developer_or_trusted_user, - CRED_PKGBASE_NOTIFY: user_developer_or_trusted_user, - CRED_PKGBASE_VOTE: user_developer_or_trusted_user, - CRED_PKGREQ_FILE: user_developer_or_trusted_user, - CRED_ACCOUNT_CHANGE_TYPE: trusted_user_or_dev, - CRED_ACCOUNT_EDIT: trusted_user_or_dev, - CRED_ACCOUNT_LAST_LOGIN: trusted_user_or_dev, - CRED_ACCOUNT_LIST_COMMENTS: trusted_user_or_dev, - CRED_ACCOUNT_SEARCH: trusted_user_or_dev, - CRED_COMMENT_DELETE: trusted_user_or_dev, - CRED_COMMENT_UNDELETE: trusted_user_or_dev, - CRED_COMMENT_VIEW_DELETED: trusted_user_or_dev, - CRED_COMMENT_EDIT: trusted_user_or_dev, - CRED_COMMENT_PIN: trusted_user_or_dev, - CRED_PKGBASE_ADOPT: trusted_user_or_dev, - CRED_PKGBASE_SET_KEYWORDS: trusted_user_or_dev, - CRED_PKGBASE_DELETE: trusted_user_or_dev, - CRED_PKGBASE_EDIT_COMAINTAINERS: trusted_user_or_dev, - CRED_PKGBASE_DISOWN: trusted_user_or_dev, - CRED_PKGBASE_LIST_VOTERS: trusted_user_or_dev, - CRED_PKGBASE_UNFLAG: trusted_user_or_dev, - CRED_PKGREQ_CLOSE: trusted_user_or_dev, - CRED_PKGREQ_LIST: trusted_user_or_dev, - CRED_TU_ADD_VOTE: trusted_user, - CRED_TU_LIST_VOTES: trusted_user_or_dev, - CRED_TU_VOTE: trusted_user, - CRED_ACCOUNT_EDIT_DEV: developer, - CRED_PKGBASE_MERGE: trusted_user_or_dev, -} - - -def has_credential(user: User, - credential: int, - approved_users: list = tuple()): - - if user in approved_users: - return True - - if credential in cred_filters: - cred_filter = cred_filters.get(credential) - return cred_filter(user) - - return False diff --git a/aurweb/auth/creds.py b/aurweb/auth/creds.py new file mode 100644 index 00000000..100aad8c --- /dev/null +++ b/aurweb/auth/creds.py @@ -0,0 +1,76 @@ +from aurweb.models.account_type import DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.models.user import User + +ACCOUNT_CHANGE_TYPE = 1 +ACCOUNT_EDIT = 2 +ACCOUNT_EDIT_DEV = 3 +ACCOUNT_LAST_LOGIN = 4 +ACCOUNT_SEARCH = 5 +ACCOUNT_LIST_COMMENTS = 28 +COMMENT_DELETE = 6 +COMMENT_UNDELETE = 27 +COMMENT_VIEW_DELETED = 22 +COMMENT_EDIT = 25 +COMMENT_PIN = 26 +PKGBASE_ADOPT = 7 +PKGBASE_SET_KEYWORDS = 8 +PKGBASE_DELETE = 9 +PKGBASE_DISOWN = 10 +PKGBASE_EDIT_COMAINTAINERS = 24 +PKGBASE_FLAG = 11 +PKGBASE_LIST_VOTERS = 12 +PKGBASE_NOTIFY = 13 +PKGBASE_UNFLAG = 15 +PKGBASE_VOTE = 16 +PKGREQ_FILE = 23 +PKGREQ_CLOSE = 17 +PKGREQ_LIST = 18 +TU_ADD_VOTE = 19 +TU_LIST_VOTES = 20 +TU_VOTE = 21 +PKGBASE_MERGE = 29 + +user_developer_or_trusted_user = set([USER_ID, TRUSTED_USER_ID, DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID]) +trusted_user_or_dev = set([TRUSTED_USER_ID, DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID]) +developer = set([DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID]) +trusted_user = set([TRUSTED_USER_ID, TRUSTED_USER_AND_DEV_ID]) + +cred_filters = { + PKGBASE_FLAG: user_developer_or_trusted_user, + PKGBASE_NOTIFY: user_developer_or_trusted_user, + PKGBASE_VOTE: user_developer_or_trusted_user, + PKGREQ_FILE: user_developer_or_trusted_user, + ACCOUNT_CHANGE_TYPE: trusted_user_or_dev, + ACCOUNT_EDIT: trusted_user_or_dev, + ACCOUNT_LAST_LOGIN: trusted_user_or_dev, + ACCOUNT_LIST_COMMENTS: trusted_user_or_dev, + ACCOUNT_SEARCH: trusted_user_or_dev, + COMMENT_DELETE: trusted_user_or_dev, + COMMENT_UNDELETE: trusted_user_or_dev, + COMMENT_VIEW_DELETED: trusted_user_or_dev, + COMMENT_EDIT: trusted_user_or_dev, + COMMENT_PIN: trusted_user_or_dev, + PKGBASE_ADOPT: trusted_user_or_dev, + PKGBASE_SET_KEYWORDS: trusted_user_or_dev, + PKGBASE_DELETE: trusted_user_or_dev, + PKGBASE_EDIT_COMAINTAINERS: trusted_user_or_dev, + PKGBASE_DISOWN: trusted_user_or_dev, + PKGBASE_LIST_VOTERS: trusted_user_or_dev, + PKGBASE_UNFLAG: trusted_user_or_dev, + PKGREQ_CLOSE: trusted_user_or_dev, + PKGREQ_LIST: trusted_user_or_dev, + TU_ADD_VOTE: trusted_user, + TU_LIST_VOTES: trusted_user_or_dev, + TU_VOTE: trusted_user, + ACCOUNT_EDIT_DEV: developer, + PKGBASE_MERGE: trusted_user_or_dev, +} + + +def has_credential(user: User, + credential: int, + approved_users: list = tuple()): + + if user in approved_users: + return True + return user.AccountTypeID in cred_filters[credential] diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 03634a36..f0724202 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -1,6 +1,7 @@ import hashlib from datetime import datetime +from typing import List, Set import bcrypt @@ -136,10 +137,10 @@ class User(Base): request.cookies["AURSID"] = self.session.SessionID return self.session.SessionID - def has_credential(self, credential: str, approved: list = tuple()): - import aurweb.auth - cred = getattr(aurweb.auth, credential) - return aurweb.auth.has_credential(self, cred, approved) + def has_credential(self, credential: Set[int], + approved: List["User"] = list()): + from aurweb.auth.creds import has_credential + return has_credential(self, credential, approved) def logout(self, request): del request.cookies["AURSID"] diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 545811f0..360857e8 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -10,7 +10,7 @@ from sqlalchemy import and_, or_ import aurweb.config from aurweb import cookies, db, l10n, logging, models, util -from aurweb.auth import account_type_required, auth_required +from aurweb.auth import account_type_required, auth_required, creds from aurweb.captcha import get_captcha_salts from aurweb.exceptions import ValidationError from aurweb.l10n import get_translator_for_request @@ -176,7 +176,7 @@ def make_account_form_context(context: dict, user_account_type_id = context.get("account_types")[0][0] - if request.user.has_credential("CRED_ACCOUNT_EDIT_DEV"): + if request.user.has_credential(creds.ACCOUNT_EDIT_DEV): context["account_types"].append((at.DEVELOPER_ID, at.DEVELOPER)) context["account_types"].append((at.TRUSTED_USER_AND_DEV_ID, at.TRUSTED_USER_AND_DEV)) @@ -332,7 +332,7 @@ async def account_register_post(request: Request, def cannot_edit(request, user): """ Return a 401 HTMLResponse if the request user doesn't have authorization, otherwise None. """ - has_dev_cred = request.user.has_credential("CRED_ACCOUNT_EDIT_DEV", + has_dev_cred = request.user.has_credential(creds.ACCOUNT_EDIT_DEV, approved=[user]) if not has_dev_cred: return HTMLResponse(status_code=HTTPStatus.UNAUTHORIZED) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index b5f8478e..2bf04949 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -10,7 +10,7 @@ import aurweb.filters import aurweb.packages.util from aurweb import db, defaults, l10n, logging, models, util -from aurweb.auth import auth_required +from aurweb.auth import auth_required, creds from aurweb.exceptions import ValidationError from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID @@ -413,7 +413,7 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, models.PackageBase) comment = get_pkgbase_comment(pkgbase, id) - authorized = request.user.has_credential("CRED_COMMENT_DELETE", + authorized = request.user.has_credential(creds.COMMENT_DELETE, [comment.User]) if not authorized: _ = l10n.get_translator_for_request(request) @@ -439,7 +439,7 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, models.PackageBase) comment = get_pkgbase_comment(pkgbase, id) - has_cred = request.user.has_credential("CRED_COMMENT_UNDELETE", + has_cred = request.user.has_credential(creds.COMMENT_UNDELETE, approved=[comment.User]) if not has_cred: _ = l10n.get_translator_for_request(request) @@ -464,7 +464,7 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, models.PackageBase) comment = get_pkgbase_comment(pkgbase, id) - has_cred = request.user.has_credential("CRED_COMMENT_PIN", + has_cred = request.user.has_credential(creds.COMMENT_PIN, approved=[pkgbase.Maintainer]) if not has_cred: _ = l10n.get_translator_for_request(request) @@ -489,7 +489,7 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, models.PackageBase) comment = get_pkgbase_comment(pkgbase, id) - has_cred = request.user.has_credential("CRED_COMMENT_PIN", + has_cred = request.user.has_credential(creds.COMMENT_PIN, approved=[pkgbase.Maintainer]) if not has_cred: _ = l10n.get_translator_for_request(request) @@ -514,7 +514,7 @@ async def package_base_comaintainers(request: Request, name: str) -> Response: # Unauthorized users (Non-TU/Dev and not the pkgbase maintainer) # get redirected to the package base's page. - has_creds = request.user.has_credential("CRED_PKGBASE_EDIT_COMAINTAINERS", + has_creds = request.user.has_credential(creds.PKGBASE_EDIT_COMAINTAINERS, approved=[pkgbase.Maintainer]) if not has_creds: return RedirectResponse(f"/pkgbase/{name}", @@ -541,7 +541,7 @@ async def package_base_comaintainers_post( # Unauthorized users (Non-TU/Dev and not the pkgbase maintainer) # get redirected to the package base's page. - has_creds = request.user.has_credential("CRED_PKGBASE_EDIT_COMAINTAINERS", + has_creds = request.user.has_credential(creds.PKGBASE_EDIT_COMAINTAINERS, approved=[pkgbase.Maintainer]) if not has_creds: return RedirectResponse(f"/pkgbase/{name}", @@ -779,7 +779,7 @@ async def pkgbase_keywords(request: Request, name: str, async def pkgbase_flag_get(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) - has_cred = request.user.has_credential("CRED_PKGBASE_FLAG") + has_cred = request.user.has_credential(creds.PKGBASE_FLAG) if not has_cred or pkgbase.Flagger is not None: return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @@ -803,7 +803,7 @@ async def pkgbase_flag_post(request: Request, name: str, return render_template(request, "packages/flag.html", context, status_code=HTTPStatus.BAD_REQUEST) - has_cred = request.user.has_credential("CRED_PKGBASE_FLAG") + has_cred = request.user.has_credential(creds.PKGBASE_FLAG) if has_cred and not pkgbase.Flagger: now = int(datetime.utcnow().timestamp()) with db.begin(): @@ -830,7 +830,7 @@ async def pkgbase_flag_comment(request: Request, name: str): def pkgbase_unflag_instance(request: Request, pkgbase: models.PackageBase): has_cred = request.user.has_credential( - "CRED_PKGBASE_UNFLAG", approved=[pkgbase.Flagger, pkgbase.Maintainer]) + creds.PKGBASE_UNFLAG, approved=[pkgbase.Flagger, pkgbase.Maintainer]) if has_cred: with db.begin(): pkgbase.OutOfDateTS = None @@ -851,7 +851,7 @@ def pkgbase_notify_instance(request: Request, pkgbase: models.PackageBase): notif = db.query(pkgbase.notifications.filter( models.PackageNotification.UserID == request.user.ID ).exists()).scalar() - has_cred = request.user.has_credential("CRED_PKGBASE_NOTIFY") + has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY) if has_cred and not notif: with db.begin(): db.create(models.PackageNotification, @@ -872,7 +872,7 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: models.PackageBase): notif = pkgbase.notifications.filter( models.PackageNotification.UserID == request.user.ID ).first() - has_cred = request.user.has_credential("CRED_PKGBASE_NOTIFY") + has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY) if has_cred and notif: with db.begin(): db.delete(notif) @@ -895,7 +895,7 @@ async def pkgbase_vote(request: Request, name: str): vote = pkgbase.package_votes.filter( models.PackageVote.UsersID == request.user.ID ).first() - has_cred = request.user.has_credential("CRED_PKGBASE_VOTE") + has_cred = request.user.has_credential(creds.PKGBASE_VOTE) if has_cred and not vote: now = int(datetime.utcnow().timestamp()) with db.begin(): @@ -919,7 +919,7 @@ async def pkgbase_unvote(request: Request, name: str): vote = pkgbase.package_votes.filter( models.PackageVote.UsersID == request.user.ID ).first() - has_cred = request.user.has_credential("CRED_PKGBASE_VOTE") + has_cred = request.user.has_credential(creds.PKGBASE_VOTE) if has_cred and vote: with db.begin(): db.delete(vote) @@ -958,7 +958,7 @@ def pkgbase_disown_instance(request: Request, pkgbase: models.PackageBase): async def pkgbase_disown_get(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) - has_cred = request.user.has_credential("CRED_PKGBASE_DISOWN", + has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer]) if not has_cred: return RedirectResponse(f"/pkgbase/{name}", @@ -975,7 +975,7 @@ async def pkgbase_disown_post(request: Request, name: str, confirm: bool = Form(default=False)): pkgbase = get_pkg_or_base(name, models.PackageBase) - has_cred = request.user.has_credential("CRED_PKGBASE_DISOWN", + has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer]) if not has_cred: return RedirectResponse(f"/pkgbase/{name}", @@ -1007,7 +1007,7 @@ def pkgbase_adopt_instance(request: Request, pkgbase: models.PackageBase): async def pkgbase_adopt_post(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) - has_cred = request.user.has_credential("CRED_PKGBASE_ADOPT") + has_cred = request.user.has_credential(creds.PKGBASE_ADOPT) if has_cred or not pkgbase.Maintainer: # If the user has credentials, they'll adopt the package regardless # of maintainership. Otherwise, we'll promote the user to maintainer @@ -1021,7 +1021,7 @@ async def pkgbase_adopt_post(request: Request, name: str): @router.get("/pkgbase/{name}/delete") @auth_required(True, redirect="/pkgbase/{name}/delete") async def pkgbase_delete_get(request: Request, name: str): - if not request.user.has_credential("CRED_PKGBASE_DELETE"): + if not request.user.has_credential(creds.PKGBASE_DELETE): return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @@ -1036,7 +1036,7 @@ async def pkgbase_delete_post(request: Request, name: str, confirm: bool = Form(default=False)): pkgbase = get_pkg_or_base(name, models.PackageBase) - if not request.user.has_credential("CRED_PKGBASE_DELETE"): + if not request.user.has_credential(creds.PKGBASE_DELETE): return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @@ -1070,7 +1070,7 @@ async def packages_unflag(request: Request, package_ids: List[int] = [], models.Package.ID.in_(package_ids)).all() for pkg in packages: has_cred = request.user.has_credential( - "CRED_PKGBASE_UNFLAG", approved=[pkg.PackageBase.Flagger]) + creds.PKGBASE_UNFLAG, approved=[pkg.PackageBase.Flagger]) if not has_cred: return (False, ["You did not select any packages to unflag."]) @@ -1106,7 +1106,7 @@ async def packages_notify(request: Request, package_ids: List[int] = [], notif = db.query(pkgbase.notifications.filter( models.PackageNotification.UserID == request.user.ID ).exists()).scalar() - has_cred = request.user.has_credential("CRED_PKGBASE_NOTIFY") + has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY) # If the request user either does not have credentials # or the notification already exists: @@ -1178,7 +1178,7 @@ async def packages_adopt(request: Request, package_ids: List[int] = [], # Check that the user has credentials for every package they selected. for pkgbase in bases: - has_cred = request.user.has_credential("CRED_PKGBASE_ADOPT") + has_cred = request.user.has_credential(creds.PKGBASE_ADOPT) if not (has_cred or not pkgbase.Maintainer): # TODO: This error needs to be translated. return (False, ["You are not allowed to adopt one of the " @@ -1211,7 +1211,7 @@ async def packages_disown(request: Request, package_ids: List[int] = [], # Check that the user has credentials for every package they selected. for pkgbase in bases: - has_cred = request.user.has_credential("CRED_PKGBASE_DISOWN", + has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer]) if not has_cred: # TODO: This error needs to be translated. @@ -1235,7 +1235,7 @@ async def packages_delete(request: Request, package_ids: List[int] = [], return (False, ["The selected packages have not been deleted, " "check the confirmation checkbox."]) - if not request.user.has_credential("CRED_PKGBASE_DELETE"): + if not request.user.has_credential(creds.PKGBASE_DELETE): return (False, ["You do not have permission to delete packages."]) # A "memo" used to store names of packages that we delete. @@ -1329,10 +1329,10 @@ async def pkgbase_merge_get(request: Request, name: str, status_code = HTTPStatus.OK # TODO: Lookup errors from credential instead of hardcoding them. - # Idea: Something like credential_errors("CRED_PKGBASE_MERGE"). - # Perhaps additionally: bad_credential_status_code("CRED_PKGBASE_MERGE"). + # Idea: Something like credential_errors(creds.PKGBASE_MERGE). + # Perhaps additionally: bad_credential_status_code(creds.PKGBASE_MERGE). # Don't take these examples verbatim. We should find good naming. - if not request.user.has_credential("CRED_PKGBASE_MERGE"): + if not request.user.has_credential(creds.PKGBASE_MERGE): context["errors"] = [ "Only Trusted Users and Developers can merge packages."] status_code = HTTPStatus.UNAUTHORIZED @@ -1434,7 +1434,7 @@ async def pkgbase_merge_post(request: Request, name: str, context["pkgbase"] = pkgbase # TODO: Lookup errors from credential instead of hardcoding them. - if not request.user.has_credential("CRED_PKGBASE_MERGE"): + if not request.user.has_credential(creds.PKGBASE_MERGE): context["errors"] = [ "Only Trusted Users and Developers can merge packages."] return render_template(request, "pkgbase/merge.html", context, diff --git a/aurweb/templates.py b/aurweb/templates.py index a7102ae1..635b22b4 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -16,7 +16,7 @@ from fastapi.responses import HTMLResponse import aurweb.config -from aurweb import captcha, cookies, l10n, time, util +from aurweb import auth, captcha, cookies, l10n, time, util # Prepare jinja2 objects. _loader = jinja2.FileSystemLoader(os.path.join( @@ -107,6 +107,7 @@ def make_context(request: Request, title: str, next: str = None): "now": datetime.now(tz=zoneinfo.ZoneInfo(timezone)), "utcnow": int(datetime.utcnow().timestamp()), "config": aurweb.config, + "creds": auth.creds, "next": next if next else request.url.path } diff --git a/templates/partials/account/comment.html b/templates/partials/account/comment.html index bc167cf7..8c310738 100644 --- a/templates/partials/account/comment.html +++ b/templates/partials/account/comment.html @@ -3,7 +3,7 @@ {% set header_cls = "%s %s" | format(header_cls, "comment-deleted") %} {% endif %} -{% if not comment.Deleter or request.user.has_credential("CRED_COMMENT_VIEW_DELETED", approved=[comment.Deleter]) %} +{% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %} {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %}

    diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 2e47a932..f3c293d8 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -53,7 +53,7 @@

    {% endif %} - {% if request.user.has_credential("CRED_ACCOUNT_CHANGE_TYPE") %} + {% if request.user.has_credential(creds.ACCOUNT_CHANGE_TYPE) %}

  • {% trans %}Accounts{% endtrans %} @@ -37,7 +37,7 @@
  • {# Only CRED_TU_LIST_VOTES privileged users see Trusted User #} - {% if request.user.has_credential("CRED_TU_LIST_VOTES") %} + {% if request.user.has_credential(creds.TU_LIST_VOTES) %}
  • {% trans %}Trusted User{% endtrans %}
  • diff --git a/templates/partials/comment_actions.html b/templates/partials/comment_actions.html index b8ccf945..78c4cc22 100644 --- a/templates/partials/comment_actions.html +++ b/templates/partials/comment_actions.html @@ -1,7 +1,7 @@ {% set pkgbasename = comment.PackageBase.Name %} {% if not comment.Deleter %} - {% if request.user.has_credential('CRED_COMMENT_DELETE', approved=[comment.User]) %} + {% if request.user.has_credential(creds.COMMENT_DELETE, approved=[comment.User]) %}
    {% endif %} - {% if request.user.has_credential('CRED_COMMENT_EDIT', approved=[comment.User]) %} + {% if request.user.has_credential(creds.COMMENT_EDIT, approved=[comment.User]) %} {% endif %} {% endif %} -{% elif request.user.has_credential("CRED_COMMENT_UNDELETE", approved=[comment.User]) %} +{% elif request.user.has_credential(creds.COMMENT_UNDELETE, approved=[comment.User]) %} {% endif %} - {% if request.user.has_credential('CRED_PKGBASE_EDIT_COMAINTAINERS', approved=[pkgbase.Maintainer]) %} + {% if request.user.has_credential(creds.PKGBASE_EDIT_COMAINTAINERS, approved=[pkgbase.Maintainer]) %}
  • {{ "Manage Co-Maintainers" | tr }} @@ -107,14 +107,14 @@ {{ "Submit Request" | tr }}
  • - {% if request.user.has_credential("CRED_PKGBASE_DELETE") %} + {% if request.user.has_credential(creds.PKGBASE_DELETE) %}
  • {{ "Delete Package" | tr }}
  • {% endif %} - {% if request.user.has_credential("CRED_PKGBASE_MERGE") %} + {% if request.user.has_credential(creds.PKGBASE_MERGE) %}
  • {{ "Merge Package" | tr }} @@ -130,7 +130,7 @@ />
  • - {% elif request.user.has_credential("CRED_PKGBASE_DISOWN", approved=[pkgbase.Maintainer]) %} + {% elif request.user.has_credential(creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer]) %}
  • {{ "Disown Package" | tr }} diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index 676a7a73..1427e0a0 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -5,7 +5,7 @@ {% set article_cls = "%s %s" | format(article_cls, "comment-deleted") %} {% endif %} -{% if not comment.Deleter or request.user.has_credential("CRED_COMMENT_VIEW_DELETED", approved=[comment.Deleter]) %} +{% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %}

    {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} {% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %} diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index dbb81c19..78e0ad1c 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -33,10 +33,10 @@ {% endif %} - {% if pkgbase.keywords.count() or request.user.has_credential("CRED_PKGBASE_SET_KEYWORDS", approved=[pkgbase.Maintainer]) %} + {% if pkgbase.keywords.count() or request.user.has_credential(creds.PKGBASE_SET_KEYWORDS, approved=[pkgbase.Maintainer]) %} {{ "Keywords" | tr }}: - {% if request.user.has_credential("CRED_PKGBASE_SET_KEYWORDS", approved=[pkgbase.Maintainer]) %} + {% if request.user.has_credential(creds.PKGBASE_SET_KEYWORDS, approved=[pkgbase.Maintainer]) %}
    Date: Thu, 18 Nov 2021 14:17:46 -0500 Subject: [PATCH 1195/1891] fix(FastAPI): remove login and redirect parameters from auth_required Signed-off-by: Steven Guikal --- aurweb/auth/__init__.py | 27 ++++++-------- aurweb/routers/accounts.py | 22 ++++++------ aurweb/routers/auth.py | 2 +- aurweb/routers/packages.py | 60 ++++++++++++++++---------------- aurweb/routers/trusted_user.py | 10 +++--- test/test_trusted_user_routes.py | 5 +-- 6 files changed, 61 insertions(+), 65 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 82192cc2..7aa4b526 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -1,5 +1,4 @@ import functools -import re from datetime import datetime from http import HTTPStatus @@ -122,17 +121,12 @@ class BasicAuthBackend(AuthenticationBackend): def auth_required(is_required: bool = True, - login: bool = True, - redirect: str = "/", template: tuple = None, status_code: HTTPStatus = HTTPStatus.UNAUTHORIZED): """ Authentication route decorator. - If redirect is given, the user will be redirected if the auth state - does not match is_required. - If template is given, it will be rendered with Unauthorized if - is_required does not match and take priority over redirect. + is_required does not match. A precondition of this function is that, if template is provided, it **must** match the following format: @@ -152,8 +146,6 @@ def auth_required(is_required: bool = True, applying any format operations. :param is_required: A boolean indicating whether the function requires auth - :param login: Redirect to `/login`, passing `next=` - :param redirect: Path to redirect to if is_required isn't True :param template: A three-element template tuple: (path, title_iterable, variable_iterable) :param status_code: An optional status_code for template render. @@ -166,14 +158,17 @@ def auth_required(is_required: bool = True, if request.user.is_authenticated() != is_required: url = "/" - if redirect: - path_params_expr = re.compile(r'\{(\w+)\}') - match = re.findall(path_params_expr, redirect) - args = {k: request.path_params.get(k) for k in match} - url = redirect.format(**args) + if is_required: + if request.method == "GET": + url = request.url.path + elif request.method == "POST" and (referer := request.headers.get("Referer")): + aur = aurweb.config.get("options", "aur_location") + "/" + if not referer.startswith(aur): + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, + detail=_("Bad Referer header.")) + url = referer[len(aur) - 1:] - if login: - url = "/login?" + util.urlencode({"next": url}) + url = "/login?" + util.urlencode({"next": url}) if template: # template=("template.html", diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 360857e8..dade92bb 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -27,14 +27,14 @@ logger = logging.get_logger(__name__) @router.get("/passreset", response_class=HTMLResponse) -@auth_required(False, login=False) +@auth_required(False) async def passreset(request: Request): context = await make_variable_context(request, "Password Reset") return render_template(request, "passreset.html", context) @router.post("/passreset", response_class=HTMLResponse) -@auth_required(False, login=False) +@auth_required(False) async def passreset_post(request: Request, user: str = Form(...), resetkey: str = Form(default=None), @@ -226,7 +226,7 @@ def make_account_form_context(context: dict, @router.get("/register", response_class=HTMLResponse) -@auth_required(False, login=False) +@auth_required(False) async def account_register(request: Request, U: str = Form(default=str()), # Username E: str = Form(default=str()), # Email @@ -252,7 +252,7 @@ async def account_register(request: Request, @router.post("/register", response_class=HTMLResponse) -@auth_required(False, login=False) +@auth_required(False) async def account_register_post(request: Request, U: str = Form(default=str()), # Username E: str = Form(default=str()), # Email @@ -340,7 +340,7 @@ def cannot_edit(request, user): @router.get("/account/{username}/edit", response_class=HTMLResponse) -@auth_required(True, redirect="/account/{username}") +@auth_required(True) async def account_edit(request: Request, username: str): user = db.query(models.User, models.User.Username == username).first() @@ -356,7 +356,7 @@ async def account_edit(request: Request, username: str): @router.post("/account/{username}/edit", response_class=HTMLResponse) -@auth_required(True, redirect="/account/{username}") +@auth_required(True) async def account_edit_post(request: Request, username: str, U: str = Form(default=str()), # Username @@ -443,7 +443,7 @@ async def account(request: Request, username: str): @router.get("/account/{username}/comments") -@auth_required(redirect="/account/{username}/comments") +@auth_required() async def account_comments(request: Request, username: str): user = get_user_by_name(username) context = make_context(request, "Accounts") @@ -454,7 +454,7 @@ async def account_comments(request: Request, username: str): @router.get("/accounts") -@auth_required(True, redirect="/accounts") +@auth_required(True) @account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) @@ -464,7 +464,7 @@ async def accounts(request: Request): @router.post("/accounts") -@auth_required(True, redirect="/accounts") +@auth_required(True) @account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) @@ -548,7 +548,7 @@ def render_terms_of_service(request: Request, @router.get("/tos") -@auth_required(True, redirect="/tos") +@auth_required(True) async def terms_of_service(request: Request): # Query the database for terms that were previously accepted, # but now have a bumped Revision that needs to be accepted. @@ -572,7 +572,7 @@ async def terms_of_service(request: Request): @router.post("/tos") -@auth_required(True, redirect="/tos") +@auth_required(True) async def terms_of_service_post(request: Request, accept: bool = Form(default=False)): # Query the database for terms that were previously accepted, diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 1e0b026a..74763667 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -29,7 +29,7 @@ async def login_get(request: Request, next: str = "/"): @router.post("/login", response_class=HTMLResponse) -@auth_required(False, login=False) +@auth_required(False) async def login_post(request: Request, next: str = Form(...), user: str = Form(default=str()), diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 2bf04949..4a2cdce3 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -295,7 +295,7 @@ async def package_base_voters(request: Request, name: str) -> Response: @router.post("/pkgbase/{name}/comments") -@auth_required(True, redirect="/pkgbase/{name}/comments") +@auth_required(True) async def pkgbase_comments_post( request: Request, name: str, comment: str = Form(default=str()), @@ -327,7 +327,7 @@ async def pkgbase_comments_post( @router.get("/pkgbase/{name}/comments/{id}/form") -@auth_required(True, login=False) +@auth_required(True) async def pkgbase_comment_form(request: Request, name: str, id: int, next: str = Query(default=None)): """ Produce a comment form for comment {id}. """ @@ -353,7 +353,7 @@ async def pkgbase_comment_form(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}") -@auth_required(True, redirect="/pkgbase/{name}/comments/{id}") +@auth_required(True) async def pkgbase_comment_post( request: Request, name: str, id: int, comment: str = Form(default=str()), @@ -392,7 +392,7 @@ async def pkgbase_comment_post( @router.get("/pkgbase/{name}/comments/{id}/edit") -@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/edit") +@auth_required(True) async def pkgbase_comment_edit(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -407,7 +407,7 @@ async def pkgbase_comment_edit(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/delete") -@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/delete") +@auth_required(True) async def pkgbase_comment_delete(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -433,7 +433,7 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/undelete") -@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/undelete") +@auth_required(True) async def pkgbase_comment_undelete(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -458,7 +458,7 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/pin") -@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/pin") +@auth_required(True) async def pkgbase_comment_pin(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -483,7 +483,7 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/unpin") -@auth_required(True, redirect="/pkgbase/{name}/comments/{id}/unpin") +@auth_required(True) async def pkgbase_comment_unpin(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -507,7 +507,7 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int, @router.get("/pkgbase/{name}/comaintainers") -@auth_required(True, redirect="/pkgbase/{name}/comaintainers") +@auth_required(True) async def package_base_comaintainers(request: Request, name: str) -> Response: # Get the PackageBase. pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -532,7 +532,7 @@ async def package_base_comaintainers(request: Request, name: str) -> Response: @router.post("/pkgbase/{name}/comaintainers") -@auth_required(True, redirect="/pkgbase/{name}/comaintainers") +@auth_required(True) async def package_base_comaintainers_post( request: Request, name: str, users: str = Form(default=str())) -> Response: @@ -584,7 +584,7 @@ async def package_base_comaintainers_post( @router.get("/requests") -@auth_required(True, redirect="/requests") +@auth_required(True) async def requests(request: Request, O: int = Query(default=defaults.O), PP: int = Query(default=defaults.PP)): @@ -618,7 +618,7 @@ async def requests(request: Request, @router.get("/pkgbase/{name}/request") -@auth_required(True, redirect="/pkgbase/{name}/request") +@auth_required(True) async def package_request(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) context = await make_variable_context(request, "Submit Request") @@ -627,7 +627,7 @@ async def package_request(request: Request, name: str): @router.post("/pkgbase/{name}/request") -@auth_required(True, redirect="/pkgbase/{name}/request") +@auth_required(True) async def pkgbase_request_post(request: Request, name: str, type: str = Form(...), merge_into: str = Form(default=None), @@ -699,7 +699,7 @@ async def pkgbase_request_post(request: Request, name: str, @router.get("/requests/{id}/close") -@auth_required(True, redirect="/requests/{id}/close") +@auth_required(True) async def requests_close(request: Request, id: int): pkgreq = get_pkgreq_by_id(id) if not request.user.is_elevated() and request.user != pkgreq.User: @@ -712,7 +712,7 @@ async def requests_close(request: Request, id: int): @router.post("/requests/{id}/close") -@auth_required(True, redirect="/requests/{id}/close") +@auth_required(True) async def requests_close_post(request: Request, id: int, reason: int = Form(default=0), comments: str = Form(default=str())): @@ -775,7 +775,7 @@ async def pkgbase_keywords(request: Request, name: str, @router.get("/pkgbase/{name}/flag") -@auth_required(True, redirect="/pkgbase/{name}/flag") +@auth_required(True) async def pkgbase_flag_get(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -790,7 +790,7 @@ async def pkgbase_flag_get(request: Request, name: str): @router.post("/pkgbase/{name}/flag") -@auth_required(True, redirect="/pkgbase/{name}/flag") +@auth_required(True) async def pkgbase_flag_post(request: Request, name: str, comments: str = Form(default=str())): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -839,7 +839,7 @@ def pkgbase_unflag_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/unflag") -@auth_required(True, redirect="/pkgbase/{name}") +@auth_required(True) async def pkgbase_unflag(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) pkgbase_unflag_instance(request, pkgbase) @@ -860,7 +860,7 @@ def pkgbase_notify_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/notify") -@auth_required(True, redirect="/pkgbase/{name}") +@auth_required(True) async def pkgbase_notify(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) pkgbase_notify_instance(request, pkgbase) @@ -879,7 +879,7 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/unnotify") -@auth_required(True, redirect="/pkgbase/{name}") +@auth_required(True) async def pkgbase_unnotify(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) pkgbase_unnotify_instance(request, pkgbase) @@ -888,7 +888,7 @@ async def pkgbase_unnotify(request: Request, name: str): @router.post("/pkgbase/{name}/vote") -@auth_required(True, redirect="/pkgbase/{name}") +@auth_required(True) async def pkgbase_vote(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -912,7 +912,7 @@ async def pkgbase_vote(request: Request, name: str): @router.post("/pkgbase/{name}/unvote") -@auth_required(True, redirect="/pkgbase/{name}") +@auth_required(True) async def pkgbase_unvote(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -954,7 +954,7 @@ def pkgbase_disown_instance(request: Request, pkgbase: models.PackageBase): @router.get("/pkgbase/{name}/disown") -@auth_required(True, redirect="/pkgbase/{name}/disown") +@auth_required(True) async def pkgbase_disown_get(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -970,7 +970,7 @@ async def pkgbase_disown_get(request: Request, name: str): @router.post("/pkgbase/{name}/disown") -@auth_required(True, redirect="/pkgbase/{name}/disown") +@auth_required(True) async def pkgbase_disown_post(request: Request, name: str, confirm: bool = Form(default=False)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -1003,7 +1003,7 @@ def pkgbase_adopt_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/adopt") -@auth_required(True, redirect="/pkgbase/{name}") +@auth_required(True) async def pkgbase_adopt_post(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -1019,7 +1019,7 @@ async def pkgbase_adopt_post(request: Request, name: str): @router.get("/pkgbase/{name}/delete") -@auth_required(True, redirect="/pkgbase/{name}/delete") +@auth_required(True) async def pkgbase_delete_get(request: Request, name: str): if not request.user.has_credential(creds.PKGBASE_DELETE): return RedirectResponse(f"/pkgbase/{name}", @@ -1031,7 +1031,7 @@ async def pkgbase_delete_get(request: Request, name: str): @router.post("/pkgbase/{name}/delete") -@auth_required(True, redirect="/pkgbase/{name}/delete") +@auth_required(True) async def pkgbase_delete_post(request: Request, name: str, confirm: bool = Form(default=False)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -1279,7 +1279,7 @@ PACKAGE_ACTIONS = { @router.post("/packages") -@auth_required(redirect="/packages") +@auth_required() async def packages_post(request: Request, IDs: List[int] = Form(default=[]), action: str = Form(default=str()), @@ -1311,7 +1311,7 @@ async def packages_post(request: Request, @router.get("/pkgbase/{name}/merge") -@auth_required(redirect="/pkgbase/{name}/merge") +@auth_required() async def pkgbase_merge_get(request: Request, name: str, into: str = Query(default=str()), next: str = Query(default=str())): @@ -1423,7 +1423,7 @@ def pkgbase_merge_instance(request: Request, pkgbase: models.PackageBase, @router.post("/pkgbase/{name}/merge") -@auth_required(redirect="/pkgbase/{name}/merge") +@auth_required() async def pkgbase_merge_post(request: Request, name: str, into: str = Form(default=str()), confirm: bool = Form(default=False), diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index f0cea61e..09de58fe 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -41,7 +41,7 @@ ADDVOTE_SPECIFICS = { @router.get("/tu") -@auth_required(True, redirect="/tu") +@auth_required(True) @account_type_required(REQUIRED_TYPES) async def trusted_user(request: Request, coff: int = 0, # current offset @@ -147,7 +147,7 @@ def render_proposal(request: Request, @router.get("/tu/{proposal}") -@auth_required(True, redirect="/tu/{proposal}") +@auth_required(True) @account_type_required(REQUIRED_TYPES) async def trusted_user_proposal(request: Request, proposal: int): context = await make_variable_context(request, "Trusted User") @@ -176,7 +176,7 @@ async def trusted_user_proposal(request: Request, proposal: int): @router.post("/tu/{proposal}") -@auth_required(True, redirect="/tu/{proposal}") +@auth_required(True) @account_type_required(REQUIRED_TYPES) async def trusted_user_proposal_post(request: Request, proposal: int, @@ -227,7 +227,7 @@ async def trusted_user_proposal_post(request: Request, @router.get("/addvote") -@auth_required(True, redirect="/addvote") +@auth_required(True) @account_type_required({TRUSTED_USER, TRUSTED_USER_AND_DEV}) async def trusted_user_addvote(request: Request, user: str = str(), @@ -247,7 +247,7 @@ async def trusted_user_addvote(request: Request, @router.post("/addvote") -@auth_required(True, redirect="/addvote") +@auth_required(True) @account_type_required({TRUSTED_USER, TRUSTED_USER_AND_DEV}) async def trusted_user_addvote_post(request: Request, user: str = Form(default=str()), diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index 43a3443b..ac7f82d5 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -9,7 +9,7 @@ import pytest from fastapi.testclient import TestClient -from aurweb import db, util +from aurweb import config, db, util from aurweb.models.account_type import AccountType from aurweb.models.tu_vote import TUVote from aurweb.models.tu_voteinfo import TUVoteInfo @@ -124,8 +124,9 @@ def proposal(user, tu_user): def test_tu_index_guest(client): + headers = {"referer": config.get("options", "aur_location") + "/tu"} with client as request: - response = request.get("/tu", allow_redirects=False) + response = request.get("/tu", allow_redirects=False, headers=headers) assert response.status_code == int(HTTPStatus.SEE_OTHER) params = util.urlencode({"next": "/tu"}) From 0b30216229f561cfdcffd27231f200c3901ce26d Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Thu, 18 Nov 2021 15:18:17 -0500 Subject: [PATCH 1196/1891] fix(FastAPI): remove unnecessary arguments to auth_required Signed-off-by: Steven Guikal --- aurweb/auth/__init__.py | 59 ++-------------------------------- aurweb/routers/accounts.py | 24 ++++++-------- aurweb/routers/packages.py | 54 +++++++++++++++---------------- aurweb/routers/trusted_user.py | 10 +++--- 4 files changed, 43 insertions(+), 104 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 7aa4b526..8ceb136c 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -5,6 +5,7 @@ from http import HTTPStatus import fastapi +from fastapi import HTTPException from fastapi.responses import RedirectResponse from sqlalchemy import and_ from starlette.authentication import AuthCredentials, AuthenticationBackend @@ -15,7 +16,6 @@ import aurweb.config from aurweb import db, l10n, util from aurweb.models import Session, User from aurweb.models.account_type import ACCOUNT_TYPE_ID -from aurweb.templates import make_variable_context, render_template class StubQuery: @@ -125,29 +125,7 @@ def auth_required(is_required: bool = True, status_code: HTTPStatus = HTTPStatus.UNAUTHORIZED): """ Authentication route decorator. - If template is given, it will be rendered with Unauthorized if - is_required does not match. - - A precondition of this function is that, if template is provided, - it **must** match the following format: - - template=("template.html", ["Some Template For", "{}"], ["username"]) - - Where `username` is a FastAPI request path parameter, fitting - a route like: `/some_route/{username}`. - - If you wish to supply a non-formatted template, just omit any Python - format strings (with the '{}' substring). The third tuple element - will not be used, and so anything can be supplied. - - template=("template.html", ["Some Page"], None) - - All title shards and format parameters will be translated before - applying any format operations. - :param is_required: A boolean indicating whether the function requires auth - :param template: A three-element template tuple: - (path, title_iterable, variable_iterable) :param status_code: An optional status_code for template render. Redirects are always SEE_OTHER. """ @@ -164,45 +142,12 @@ def auth_required(is_required: bool = True, elif request.method == "POST" and (referer := request.headers.get("Referer")): aur = aurweb.config.get("options", "aur_location") + "/" if not referer.startswith(aur): + _ = l10n.get_translator_for_request(request) raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=_("Bad Referer header.")) url = referer[len(aur) - 1:] url = "/login?" + util.urlencode({"next": url}) - - if template: - # template=("template.html", - # ["Some Title", "someFormatted {}"], - # ["variable"]) - # => render template.html with title: - # "Some Title someFormatted variables" - path, title_parts, variables = template - _ = l10n.get_translator_for_request(request) - - # Step through title_parts; for each part which contains - # a '{}' in it, apply .format(var) where var = the current - # iteration of variables. - # - # This implies that len(variables) is equal to - # len([part for part in title_parts if '{}' in part]) - # and this must always be true. - # - sanitized = [] - _variables = iter(variables) - for part in title_parts: - if "{}" in part: # If this part is formattable. - key = next(_variables) - var = request.path_params.get(key) - sanitized.append(_(part.format(var))) - else: # Otherwise, just add the translated part. - sanitized.append(_(part)) - - # Glue all title parts together, separated by spaces. - title = " ".join(sanitized) - - context = await make_variable_context(request, title) - return render_template(request, path, context, - status_code=status_code) return RedirectResponse(url, status_code=int(HTTPStatus.SEE_OTHER)) return await func(request, *args, **kwargs) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index dade92bb..388daf84 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -340,7 +340,7 @@ def cannot_edit(request, user): @router.get("/account/{username}/edit", response_class=HTMLResponse) -@auth_required(True) +@auth_required() async def account_edit(request: Request, username: str): user = db.query(models.User, models.User.Username == username).first() @@ -356,7 +356,7 @@ async def account_edit(request: Request, username: str): @router.post("/account/{username}/edit", response_class=HTMLResponse) -@auth_required(True) +@auth_required() async def account_edit_post(request: Request, username: str, U: str = Form(default=str()), # Username @@ -424,20 +424,14 @@ async def account_edit_post(request: Request, aurtz=TZ, aurlang=L) -account_template = ( - "account/show.html", - ["Account", "{}"], - ["username"] # Query parameters to replace in the title string. -) - - @router.get("/account/{username}") -@auth_required(True, template=account_template, - status_code=HTTPStatus.UNAUTHORIZED) async def account(request: Request, username: str): _ = l10n.get_translator_for_request(request) context = await make_variable_context( request, _("Account") + " " + username) + if not request.user.is_authenticated(): + return render_template(request, "account/show.html", context, + status_code=HTTPStatus.UNAUTHORIZED) context["user"] = get_user_by_name(username) return render_template(request, "account/show.html", context) @@ -454,7 +448,7 @@ async def account_comments(request: Request, username: str): @router.get("/accounts") -@auth_required(True) +@auth_required() @account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) @@ -464,7 +458,7 @@ async def accounts(request: Request): @router.post("/accounts") -@auth_required(True) +@auth_required() @account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) @@ -548,7 +542,7 @@ def render_terms_of_service(request: Request, @router.get("/tos") -@auth_required(True) +@auth_required() async def terms_of_service(request: Request): # Query the database for terms that were previously accepted, # but now have a bumped Revision that needs to be accepted. @@ -572,7 +566,7 @@ async def terms_of_service(request: Request): @router.post("/tos") -@auth_required(True) +@auth_required() async def terms_of_service_post(request: Request, accept: bool = Form(default=False)): # Query the database for terms that were previously accepted, diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 4a2cdce3..c06ec51f 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -295,7 +295,7 @@ async def package_base_voters(request: Request, name: str) -> Response: @router.post("/pkgbase/{name}/comments") -@auth_required(True) +@auth_required() async def pkgbase_comments_post( request: Request, name: str, comment: str = Form(default=str()), @@ -327,7 +327,7 @@ async def pkgbase_comments_post( @router.get("/pkgbase/{name}/comments/{id}/form") -@auth_required(True) +@auth_required() async def pkgbase_comment_form(request: Request, name: str, id: int, next: str = Query(default=None)): """ Produce a comment form for comment {id}. """ @@ -353,7 +353,7 @@ async def pkgbase_comment_form(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}") -@auth_required(True) +@auth_required() async def pkgbase_comment_post( request: Request, name: str, id: int, comment: str = Form(default=str()), @@ -392,7 +392,7 @@ async def pkgbase_comment_post( @router.get("/pkgbase/{name}/comments/{id}/edit") -@auth_required(True) +@auth_required() async def pkgbase_comment_edit(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -407,7 +407,7 @@ async def pkgbase_comment_edit(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/delete") -@auth_required(True) +@auth_required() async def pkgbase_comment_delete(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -433,7 +433,7 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/undelete") -@auth_required(True) +@auth_required() async def pkgbase_comment_undelete(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -458,7 +458,7 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/pin") -@auth_required(True) +@auth_required() async def pkgbase_comment_pin(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -483,7 +483,7 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/unpin") -@auth_required(True) +@auth_required() async def pkgbase_comment_unpin(request: Request, name: str, id: int, next: str = Form(default=None)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -507,7 +507,7 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int, @router.get("/pkgbase/{name}/comaintainers") -@auth_required(True) +@auth_required() async def package_base_comaintainers(request: Request, name: str) -> Response: # Get the PackageBase. pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -532,7 +532,7 @@ async def package_base_comaintainers(request: Request, name: str) -> Response: @router.post("/pkgbase/{name}/comaintainers") -@auth_required(True) +@auth_required() async def package_base_comaintainers_post( request: Request, name: str, users: str = Form(default=str())) -> Response: @@ -584,7 +584,7 @@ async def package_base_comaintainers_post( @router.get("/requests") -@auth_required(True) +@auth_required() async def requests(request: Request, O: int = Query(default=defaults.O), PP: int = Query(default=defaults.PP)): @@ -618,7 +618,7 @@ async def requests(request: Request, @router.get("/pkgbase/{name}/request") -@auth_required(True) +@auth_required() async def package_request(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) context = await make_variable_context(request, "Submit Request") @@ -627,7 +627,7 @@ async def package_request(request: Request, name: str): @router.post("/pkgbase/{name}/request") -@auth_required(True) +@auth_required() async def pkgbase_request_post(request: Request, name: str, type: str = Form(...), merge_into: str = Form(default=None), @@ -699,7 +699,7 @@ async def pkgbase_request_post(request: Request, name: str, @router.get("/requests/{id}/close") -@auth_required(True) +@auth_required() async def requests_close(request: Request, id: int): pkgreq = get_pkgreq_by_id(id) if not request.user.is_elevated() and request.user != pkgreq.User: @@ -712,7 +712,7 @@ async def requests_close(request: Request, id: int): @router.post("/requests/{id}/close") -@auth_required(True) +@auth_required() async def requests_close_post(request: Request, id: int, reason: int = Form(default=0), comments: str = Form(default=str())): @@ -775,7 +775,7 @@ async def pkgbase_keywords(request: Request, name: str, @router.get("/pkgbase/{name}/flag") -@auth_required(True) +@auth_required() async def pkgbase_flag_get(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -790,7 +790,7 @@ async def pkgbase_flag_get(request: Request, name: str): @router.post("/pkgbase/{name}/flag") -@auth_required(True) +@auth_required() async def pkgbase_flag_post(request: Request, name: str, comments: str = Form(default=str())): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -839,7 +839,7 @@ def pkgbase_unflag_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/unflag") -@auth_required(True) +@auth_required() async def pkgbase_unflag(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) pkgbase_unflag_instance(request, pkgbase) @@ -860,7 +860,7 @@ def pkgbase_notify_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/notify") -@auth_required(True) +@auth_required() async def pkgbase_notify(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) pkgbase_notify_instance(request, pkgbase) @@ -879,7 +879,7 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/unnotify") -@auth_required(True) +@auth_required() async def pkgbase_unnotify(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) pkgbase_unnotify_instance(request, pkgbase) @@ -888,7 +888,7 @@ async def pkgbase_unnotify(request: Request, name: str): @router.post("/pkgbase/{name}/vote") -@auth_required(True) +@auth_required() async def pkgbase_vote(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -912,7 +912,7 @@ async def pkgbase_vote(request: Request, name: str): @router.post("/pkgbase/{name}/unvote") -@auth_required(True) +@auth_required() async def pkgbase_unvote(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -954,7 +954,7 @@ def pkgbase_disown_instance(request: Request, pkgbase: models.PackageBase): @router.get("/pkgbase/{name}/disown") -@auth_required(True) +@auth_required() async def pkgbase_disown_get(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -970,7 +970,7 @@ async def pkgbase_disown_get(request: Request, name: str): @router.post("/pkgbase/{name}/disown") -@auth_required(True) +@auth_required() async def pkgbase_disown_post(request: Request, name: str, confirm: bool = Form(default=False)): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -1003,7 +1003,7 @@ def pkgbase_adopt_instance(request: Request, pkgbase: models.PackageBase): @router.post("/pkgbase/{name}/adopt") -@auth_required(True) +@auth_required() async def pkgbase_adopt_post(request: Request, name: str): pkgbase = get_pkg_or_base(name, models.PackageBase) @@ -1019,7 +1019,7 @@ async def pkgbase_adopt_post(request: Request, name: str): @router.get("/pkgbase/{name}/delete") -@auth_required(True) +@auth_required() async def pkgbase_delete_get(request: Request, name: str): if not request.user.has_credential(creds.PKGBASE_DELETE): return RedirectResponse(f"/pkgbase/{name}", @@ -1031,7 +1031,7 @@ async def pkgbase_delete_get(request: Request, name: str): @router.post("/pkgbase/{name}/delete") -@auth_required(True) +@auth_required() async def pkgbase_delete_post(request: Request, name: str, confirm: bool = Form(default=False)): pkgbase = get_pkg_or_base(name, models.PackageBase) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 09de58fe..fac68f04 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -41,7 +41,7 @@ ADDVOTE_SPECIFICS = { @router.get("/tu") -@auth_required(True) +@auth_required() @account_type_required(REQUIRED_TYPES) async def trusted_user(request: Request, coff: int = 0, # current offset @@ -147,7 +147,7 @@ def render_proposal(request: Request, @router.get("/tu/{proposal}") -@auth_required(True) +@auth_required() @account_type_required(REQUIRED_TYPES) async def trusted_user_proposal(request: Request, proposal: int): context = await make_variable_context(request, "Trusted User") @@ -176,7 +176,7 @@ async def trusted_user_proposal(request: Request, proposal: int): @router.post("/tu/{proposal}") -@auth_required(True) +@auth_required() @account_type_required(REQUIRED_TYPES) async def trusted_user_proposal_post(request: Request, proposal: int, @@ -227,7 +227,7 @@ async def trusted_user_proposal_post(request: Request, @router.get("/addvote") -@auth_required(True) +@auth_required() @account_type_required({TRUSTED_USER, TRUSTED_USER_AND_DEV}) async def trusted_user_addvote(request: Request, user: str = str(), @@ -247,7 +247,7 @@ async def trusted_user_addvote(request: Request, @router.post("/addvote") -@auth_required(True) +@auth_required() @account_type_required({TRUSTED_USER, TRUSTED_USER_AND_DEV}) async def trusted_user_addvote_post(request: Request, user: str = Form(default=str()), From 2fee6205a6d11ad6ecae4b003991fc3aea1e992f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 01:42:19 -0800 Subject: [PATCH 1197/1891] housekeep(fastapi): rewrite test_rpc with fixtures Signed-off-by: Kevin Morris --- test/test_rpc.py | 532 +++++++++++++++++++++++++++-------------------- 1 file changed, 308 insertions(+), 224 deletions(-) diff --git a/test/test_rpc.py b/test/test_rpc.py index b61a7e4e..acb82cad 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1,6 +1,8 @@ import re +from datetime import datetime from http import HTTPStatus +from typing import List from unittest import mock import orjson @@ -9,10 +11,11 @@ import pytest from fastapi.testclient import TestClient from redis.client import Pipeline -from aurweb import asgi, config, scripts -from aurweb.db import begin, create, query -from aurweb.models.account_type import AccountType -from aurweb.models.dependency_type import DependencyType +import aurweb.models.dependency_type as dt +import aurweb.models.relation_type as rt + +from aurweb import asgi, config, db, scripts +from aurweb.models.account_type import USER_ID from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -21,7 +24,6 @@ from aurweb.models.package_keyword import PackageKeyword from aurweb.models.package_license import PackageLicense from aurweb.models.package_relation import PackageRelation from aurweb.models.package_vote import PackageVote -from aurweb.models.relation_type import RelationType from aurweb.models.user import User from aurweb.redis import redis_connection @@ -31,163 +33,172 @@ def client() -> TestClient: yield TestClient(app=asgi.app) -@pytest.fixture(autouse=True) -def setup(db_test): - # TODO: Rework this into organized fixtures. +@pytest.fixture +def user(db_test) -> User: + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User 1", Passwd=str(), + AccountTypeID=USER_ID) + yield user - # Create test package details. - with begin(): - # Get ID types. - account_type = query(AccountType, AccountType.AccountType == "User").first() - dependency_depends = query(DependencyType, DependencyType.Name == "depends").first() - dependency_optdepends = query(DependencyType, DependencyType.Name == "optdepends").first() - dependency_makedepends = query(DependencyType, DependencyType.Name == "makedepends").first() - dependency_checkdepends = query(DependencyType, DependencyType.Name == "checkdepends").first() +@pytest.fixture +def user2() -> User: + with db.begin(): + user = db.create(User, Username="user2", Email="user2@example.org", + RealName="Test User 2", Passwd=str(), + AccountTypeID=USER_ID) + yield user - relation_conflicts = query(RelationType, RelationType.Name == "conflicts").first() - relation_provides = query(RelationType, RelationType.Name == "provides").first() - relation_replaces = query(RelationType, RelationType.Name == "replaces").first() - # Create database info. - user1 = create(User, - Username="user1", - Email="user1@example.com", - RealName="Test User 1", - Passwd="testPassword", - AccountType=account_type) +@pytest.fixture +def user3() -> User: + with db.begin(): + user = db.create(User, Username="user3", Email="user3@example.org", + RealName="Test User 3", Passwd=str(), + AccountTypeID=USER_ID) + yield user - user2 = create(User, - Username="user2", - Email="user2@example.com", - RealName="Test User 2", - Passwd="testPassword", - AccountType=account_type) - user3 = create(User, - Username="user3", - Email="user3@example.com", - RealName="Test User 3", - Passwd="testPassword", - AccountType=account_type) +@pytest.fixture +def packages(user: User, user2: User, user3: User) -> List[Package]: + output = [] - pkgbase1 = create(PackageBase, Name="big-chungus", - Maintainer=user1, - Packager=user1) + # Create package records used in our tests. + with db.begin(): + pkgbase = db.create(PackageBase, Name="big-chungus", + Maintainer=user, Packager=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, + Description="Bunny bunny around bunny", + URL="https://example.com/") + output.append(pkg) - pkgname1 = create(Package, - PackageBase=pkgbase1, - Name=pkgbase1.Name, - Description="Bunny bunny around bunny", - URL="https://example.com/") + pkgbase = db.create(PackageBase, Name="chungy-chungus", + Maintainer=user, Packager=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, + Description="Wubby wubby on wobba wuubu", + URL="https://example.com/") + output.append(pkg) - pkgbase2 = create(PackageBase, Name="chungy-chungus", - Maintainer=user1, - Packager=user1) + pkgbase = db.create(PackageBase, Name="gluggly-chungus", + Maintainer=user, Packager=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, + Description="glurrba glurrba gur globba", + URL="https://example.com/") + output.append(pkg) - pkgname2 = create(Package, - PackageBase=pkgbase2, - Name=pkgbase2.Name, - Description="Wubby wubby on wobba wuubu", - URL="https://example.com/") - - pkgbase3 = create(PackageBase, Name="gluggly-chungus", - Maintainer=user1, - Packager=user1) - - pkgbase4 = create(PackageBase, Name="fugly-chungus", - Maintainer=user1, - Packager=user1) + pkgbase = db.create(PackageBase, Name="fugly-chungus", + Maintainer=user, Packager=user) desc = "A Package belonging to a PackageBase with another name." - create(Package, - PackageBase=pkgbase4, - Name="other-pkg", - Description=desc, - URL="https://example.com") + pkg = db.create(Package, PackageBase=pkgbase, Name="other-pkg", + Description=desc, URL="https://example.com") + output.append(pkg) - create(Package, - PackageBase=pkgbase3, - Name=pkgbase3.Name, - Description="glurrba glurrba gur globba", - URL="https://example.com/") + pkgbase = db.create(PackageBase, Name="woogly-chungus") + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, + Description="wuggla woblabeloop shemashmoop", + URL="https://example.com/") + output.append(pkg) - pkgbase4 = create(PackageBase, Name="woogly-chungus") + # Setup a few more related records on the first package: + # a license, some keywords and some votes. + with db.begin(): + lic = db.create(License, Name="GPL") + db.create(PackageLicense, Package=output[0], License=lic) - create(Package, - PackageBase=pkgbase4, - Name=pkgbase4.Name, - Description="wuggla woblabeloop shemashmoop", - URL="https://example.com/") + for keyword in ["big-chungus", "smol-chungus", "sizeable-chungus"]: + db.create(PackageKeyword, + PackageBase=output[0].PackageBase, + Keyword=keyword) - # Dependencies. - create(PackageDependency, - Package=pkgname1, - DependencyType=dependency_depends, - DepName="chungus-depends") + now = int(datetime.utcnow().timestamp()) + for user_ in [user, user2, user3]: + db.create(PackageVote, User=user_, + PackageBase=output[0].PackageBase, VoteTS=now) + scripts.popupdate.run_single(output[0].PackageBase) - create(PackageDependency, - Package=pkgname2, - DependencyType=dependency_depends, - DepName="chungy-depends") + yield output - create(PackageDependency, - Package=pkgname1, - DependencyType=dependency_optdepends, - DepName="chungus-optdepends", - DepCondition="=50") - create(PackageDependency, - Package=pkgname1, - DependencyType=dependency_makedepends, - DepName="chungus-makedepends") +@pytest.fixture +def depends(packages: List[Package]) -> List[PackageDependency]: + output = [] - create(PackageDependency, - Package=pkgname1, - DependencyType=dependency_checkdepends, - DepName="chungus-checkdepends") + with db.begin(): + dep = db.create(PackageDependency, + Package=packages[0], + DepTypeID=dt.DEPENDS_ID, + DepName="chungus-depends") + output.append(dep) - # Relations. - create(PackageRelation, - Package=pkgname1, - RelationType=relation_conflicts, - RelName="chungus-conflicts") + dep = db.create(PackageDependency, + Package=packages[1], + DepTypeID=dt.DEPENDS_ID, + DepName="chungy-depends") + output.append(dep) - create(PackageRelation, - Package=pkgname2, - RelationType=relation_conflicts, - RelName="chungy-conflicts") + dep = db.create(PackageDependency, + Package=packages[0], + DepTypeID=dt.OPTDEPENDS_ID, + DepName="chungus-optdepends", + DepCondition="=50") + output.append(dep) - create(PackageRelation, - Package=pkgname1, - RelationType=relation_provides, - RelName="chungus-provides", - RelCondition="<=200") + dep = db.create(PackageDependency, + Package=packages[0], + DepTypeID=dt.MAKEDEPENDS_ID, + DepName="chungus-makedepends") + output.append(dep) - create(PackageRelation, - Package=pkgname1, - RelationType=relation_replaces, - RelName="chungus-replaces", - RelCondition="<=200") + dep = db.create(PackageDependency, + Package=packages[0], + DepTypeID=dt.CHECKDEPENDS_ID, + DepName="chungus-checkdepends") + output.append(dep) - license = create(License, Name="GPL") + yield output - create(PackageLicense, - Package=pkgname1, - License=license) - for i in ["big-chungus", "smol-chungus", "sizeable-chungus"]: - create(PackageKeyword, - PackageBase=pkgbase1, - Keyword=i) +@pytest.fixture +def relations(user: User, packages: List[Package]) -> List[PackageRelation]: + output = [] - for i in [user1, user2, user3]: - create(PackageVote, - User=i, - PackageBase=pkgbase1, - VoteTS=5000) + with db.begin(): + rel = db.create(PackageRelation, + Package=packages[0], + RelTypeID=rt.CONFLICTS_ID, + RelName="chungus-conflicts") + output.append(rel) - scripts.popupdate.run_single(pkgbase1) + rel = db.create(PackageRelation, + Package=packages[1], + RelTypeID=rt.CONFLICTS_ID, + RelName="chungy-conflicts") + output.append(rel) + + rel = db.create(PackageRelation, + Package=packages[0], + RelTypeID=rt.PROVIDES_ID, + RelName="chungus-provides", + RelCondition="<=200") + output.append(rel) + + rel = db.create(PackageRelation, + Package=packages[0], + RelTypeID=rt.REPLACES_ID, + RelName="chungus-replaces", + RelCondition="<=200") + output.append(rel) + + # Finally, yield the packages. + yield output + + +@pytest.fixture(autouse=True) +def setup(db_test): + # Create some extra package relationships. + pass @pytest.fixture @@ -195,28 +206,35 @@ def pipeline(): redis = redis_connection() pipeline = redis.pipeline() + # The 'testclient' host is used when requesting the app + # via fastapi.testclient.TestClient. pipeline.delete("ratelimit-ws:testclient") pipeline.delete("ratelimit:testclient") - one, two = pipeline.execute() + pipeline.execute() yield pipeline -def test_rpc_singular_info(client: TestClient): +def test_rpc_singular_info(client: TestClient, + user: User, + packages: List[Package], + depends: List[PackageDependency], + relations: List[PackageRelation]): # Define expected response. + pkg = packages[0] expected_data = { "version": 5, "results": [{ - "Name": "big-chungus", - "Version": "", - "Description": "Bunny bunny around bunny", - "URL": "https://example.com/", - "PackageBase": "big-chungus", - "NumVotes": 3, - "Popularity": 0.0, + "Name": pkg.Name, + "Version": pkg.Version, + "Description": pkg.Description, + "URL": pkg.URL, + "PackageBase": pkg.PackageBase.Name, + "NumVotes": pkg.PackageBase.NumVotes, + "Popularity": float(pkg.PackageBase.Popularity), "OutOfDate": None, - "Maintainer": "user1", - "URLPath": "/cgit/aur.git/snapshot/big-chungus.tar.gz", + "Maintainer": user.Username, + "URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz", "Depends": ["chungus-depends"], "OptDepends": ["chungus-optdepends=50"], "MakeDepends": ["chungus-makedepends"], @@ -224,7 +242,7 @@ def test_rpc_singular_info(client: TestClient): "Conflicts": ["chungus-conflicts"], "Provides": ["chungus-provides<=200"], "Replaces": ["chungus-replaces<=200"], - "License": ["GPL"], + "License": [pkg.package_licenses.first().License.Name], "Keywords": [ "big-chungus", "sizeable-chungus", @@ -237,20 +255,23 @@ def test_rpc_singular_info(client: TestClient): # Make dummy request. with client as request: - response_arg = request.get( - "/rpc/?v=5&type=info&arg=chungy-chungus&arg=big-chungus") + resp = request.get("/rpc", params={ + "v": 5, + "type": "info", + "arg": ["chungy-chungus", "big-chungus"], + }) # Load request response into Python dictionary. - response_info_arg = orjson.loads(response_arg.content.decode()) + response_data = orjson.loads(resp.text) # Remove the FirstSubmitted LastModified, ID and PackageBaseID keys from # reponse, as the key's values aren't guaranteed to match between the two # (the keys are already removed from 'expected_data'). for i in ["FirstSubmitted", "LastModified", "ID", "PackageBaseID"]: - response_info_arg["results"][0].pop(i) + response_data["results"][0].pop(i) # Validate that the new dictionaries are the same. - assert response_info_arg == expected_data + assert response_data == expected_data def test_rpc_nonexistent_package(client: TestClient): @@ -265,12 +286,13 @@ def test_rpc_nonexistent_package(client: TestClient): assert response_data["resultcount"] == 0 -def test_rpc_multiinfo(client: TestClient): +def test_rpc_multiinfo(client: TestClient, packages: List[Package]): # Make dummy request. request_packages = ["big-chungus", "chungy-chungus"] with client as request: - response = request.get( - "/rpc/?v=5&type=info&arg[]=big-chungus&arg[]=chungy-chungus") + response = request.get("/rpc", params={ + "v": 5, "type": "info", "arg[]": request_packages + }) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -282,19 +304,21 @@ def test_rpc_multiinfo(client: TestClient): assert request_packages == [] -def test_rpc_mixedargs(client: TestClient): +def test_rpc_mixedargs(client: TestClient, packages: List[Package]): # Make dummy request. response1_packages = ["gluggly-chungus"] response2_packages = ["gluggly-chungus", "chungy-chungus"] with client as request: + # Supply all of the args in the url to enforce ordering. response1 = request.get( "/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info") assert response1.status_code == int(HTTPStatus.OK) with client as request: response2 = request.get( - "/rpc?v=5&arg=big-chungus&arg[]=gluggly-chungus&type=info&arg[]=chungy-chungus") + "/rpc?v=5&arg=big-chungus&arg[]=gluggly-chungus" + "&type=info&arg[]=chungy-chungus") assert response1.status_code == int(HTTPStatus.OK) # Load request response into Python dictionary. @@ -312,22 +336,27 @@ def test_rpc_mixedargs(client: TestClient): assert i == [] -def test_rpc_no_dependencies(client: TestClient): - """This makes sure things like 'MakeDepends' get removed from JSON strings - when they don't have set values.""" - +def test_rpc_no_dependencies_omits_key(client: TestClient, user: User, + packages: List[Package], + depends: List[PackageDependency], + relations: List[PackageRelation]): + """ + This makes sure things like 'MakeDepends' get removed from JSON strings + when they don't have set values. + """ + pkg = packages[1] expected_response = { 'version': 5, 'results': [{ - 'Name': 'chungy-chungus', - 'Version': '', - 'Description': 'Wubby wubby on wobba wuubu', - 'URL': 'https://example.com/', - 'PackageBase': 'chungy-chungus', - 'NumVotes': 0, - 'Popularity': 0.0, + 'Name': pkg.Name, + 'Version': pkg.Version, + 'Description': pkg.Description, + 'URL': pkg.URL, + 'PackageBase': pkg.PackageBase.Name, + 'NumVotes': pkg.PackageBase.NumVotes, + 'Popularity': int(pkg.PackageBase.Popularity), 'OutOfDate': None, - 'Maintainer': 'user1', + 'Maintainer': user.Username, 'URLPath': '/cgit/aur.git/snapshot/chungy-chungus.tar.gz', 'Depends': ['chungy-depends'], 'Conflicts': ['chungy-conflicts'], @@ -340,7 +369,9 @@ def test_rpc_no_dependencies(client: TestClient): # Make dummy request. with client as request: - response = request.get("/rpc/?v=5&type=info&arg=chungy-chungus") + response = request.get("/rpc", params={ + "v": 5, "type": "info", "arg": "chungy-chungus" + }) response_data = orjson.loads(response.content.decode()) # Remove inconsistent keys. @@ -362,7 +393,9 @@ def test_rpc_bad_type(client: TestClient): # Make dummy request. with client as request: - response = request.get("/rpc/?v=5&type=invalid-type&arg=big-chungus") + response = request.get("/rpc", params={ + "v": 5, "type": "invalid-type", "arg": "big-chungus" + }) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -383,7 +416,9 @@ def test_rpc_bad_version(client: TestClient): # Make dummy request. with client as request: - response = request.get("/rpc/?v=0&type=info&arg=big-chungus") + response = request.get("/rpc", params={ + "v": 0, "type": "info", "arg": "big-chungus" + }) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -404,7 +439,10 @@ def test_rpc_no_version(client: TestClient): # Make dummy request. with client as request: - response = request.get("/rpc/?type=info&arg=big-chungus") + response = request.get("/rpc", params={ + "type": "info", + "arg": "big-chungus" + }) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -425,7 +463,7 @@ def test_rpc_no_type(client: TestClient): # Make dummy request. with client as request: - response = request.get("/rpc/?v=5&arg=big-chungus") + response = request.get("/rpc", params={"v": 5, "arg": "big-chungus"}) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -446,7 +484,7 @@ def test_rpc_no_args(client: TestClient): # Make dummy request. with client as request: - response = request.get("/rpc/?v=5&type=info") + response = request.get("/rpc", params={"v": 5, "type": "info"}) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -455,10 +493,12 @@ def test_rpc_no_args(client: TestClient): assert expected_data == response_data -def test_rpc_no_maintainer(client: TestClient): +def test_rpc_no_maintainer(client: TestClient, packages: List[Package]): # Make dummy request. with client as request: - response = request.get("/rpc/?v=5&type=info&arg=woogly-chungus") + response = request.get("/rpc", params={ + "v": 5, "type": "info", "arg": "woogly-chungus" + }) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -467,39 +507,45 @@ def test_rpc_no_maintainer(client: TestClient): assert response_data["results"][0]["Maintainer"] is None -def test_rpc_suggest_pkgbase(client: TestClient): +def test_rpc_suggest_pkgbase(client: TestClient, packages: List[Package]): + params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"} with client as request: - response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") + response = request.get("/rpc", params=params) data = response.json() assert data == ["big-chungus"] + params["arg"] = "chungy" with client as request: - response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=chungy") + response = request.get("/rpc", params=params) data = response.json() assert data == ["chungy-chungus"] # Test no arg supplied. + del params["arg"] with client as request: - response = request.get("/rpc?v=5&type=suggest-pkgbase") + response = request.get("/rpc", params=params) data = response.json() assert data == [] -def test_rpc_suggest(client: TestClient): +def test_rpc_suggest(client: TestClient, packages: List[Package]): + params = {"v": 5, "type": "suggest", "arg": "other"} with client as request: - response = request.get("/rpc?v=5&type=suggest&arg=other") + response = request.get("/rpc", params=params) data = response.json() assert data == ["other-pkg"] # Test non-existent Package. + params["arg"] = "nonexistent" with client as request: - response = request.get("/rpc?v=5&type=suggest&arg=nonexistent") + response = request.get("/rpc", params=params) data = response.json() assert data == [] # Test no arg supplied. + del params["arg"] with client as request: - response = request.get("/rpc?v=5&type=suggest") + response = request.get("/rpc", params=params) data = response.json() assert data == [] @@ -514,16 +560,18 @@ def mock_config_getint(section: str, key: str): @mock.patch("aurweb.config.getint", side_effect=mock_config_getint) def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient, - pipeline: Pipeline): + pipeline: Pipeline, packages: List[Package]): + params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"} + for i in range(4): # The first 4 requests should be good. with client as request: - response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") + response = request.get("/rpc", params=params) assert response.status_code == int(HTTPStatus.OK) # The fifth request should be banned. with client as request: - response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") + response = request.get("/rpc", params=params) assert response.status_code == int(HTTPStatus.TOO_MANY_REQUESTS) # Delete the cached records. @@ -534,124 +582,155 @@ def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient, # The new first request should be good. with client as request: - response = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") + response = request.get("/rpc", params=params) assert response.status_code == int(HTTPStatus.OK) -def test_rpc_etag(client: TestClient): - with client as request: - response1 = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") +def test_rpc_etag(client: TestClient, packages: List[Package]): + params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"} with client as request: - response2 = request.get("/rpc?v=5&type=suggest-pkgbase&arg=big") + response1 = request.get("/rpc", params=params) + with client as request: + response2 = request.get("/rpc", params=params) + assert response1.headers.get("ETag") is not None assert response1.headers.get("ETag") != str() assert response1.headers.get("ETag") == response2.headers.get("ETag") def test_rpc_search_arg_too_small(client: TestClient): + params = {"v": 5, "type": "search", "arg": "b"} with client as request: - response = request.get("/rpc?v=5&type=search&arg=b") + response = request.get("/rpc", params=params) assert response.status_code == int(HTTPStatus.OK) assert response.json().get("error") == "Query arg too small." -def test_rpc_search(client: TestClient): +def test_rpc_search(client: TestClient, packages: List[Package]): + params = {"v": 5, "type": "search", "arg": "big"} with client as request: - response = request.get("/rpc?v=5&type=search&arg=big") + response = request.get("/rpc", params=params) assert response.status_code == int(HTTPStatus.OK) data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] - assert result.get("Name") == "big-chungus" + assert result.get("Name") == packages[0].Name # Test the If-None-Match headers. etag = response.headers.get("ETag").strip('"') headers = {"If-None-Match": etag} - response = request.get("/rpc?v=5&type=search&arg=big", headers=headers) + response = request.get("/rpc", params=params, headers=headers) assert response.status_code == int(HTTPStatus.NOT_MODIFIED) assert response.content == b'' # No args on non-m by types return an error. - response = request.get("/rpc?v=5&type=search") + del params["arg"] + with client as request: + response = request.get("/rpc", params=params) assert response.json().get("error") == "No request type/data specified." -def test_rpc_msearch(client: TestClient): +def test_rpc_msearch(client: TestClient, user: User, packages: List[Package]): + params = {"v": 5, "type": "msearch", "arg": user.Username} with client as request: - response = request.get("/rpc?v=5&type=msearch&arg=user1") + response = request.get("/rpc", params=params) data = response.json() # user1 maintains 4 packages; assert that we got them all. assert data.get("resultcount") == 4 names = list(sorted(r.get("Name") for r in data.get("results"))) - expected_results = list(sorted([ + expected_results = [ "big-chungus", "chungy-chungus", "gluggly-chungus", "other-pkg" - ])) + ] assert names == expected_results # Search for a non-existent maintainer, giving us zero packages. - response = request.get("/rpc?v=5&type=msearch&arg=blah-blah") + params["arg"] = "blah-blah" + response = request.get("/rpc", params=params) data = response.json() assert data.get("resultcount") == 0 # A missing arg still succeeds, but it returns all orphans. # Just verify that we receive no error and the orphaned result. - response = request.get("/rpc?v=5&type=msearch") + params.pop("arg") + response = request.get("/rpc", params=params) data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] assert result.get("Name") == "woogly-chungus" -def test_rpc_search_depends(client: TestClient): +def test_rpc_search_depends(client: TestClient, packages: List[Package], + depends: List[PackageDependency]): + params = { + "v": 5, "type": "search", "by": "depends", "arg": "chungus-depends" + } with client as request: - response = request.get( - "/rpc?v=5&type=search&by=depends&arg=chungus-depends") + response = request.get("/rpc", params=params) data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] - assert result.get("Name") == "big-chungus" + assert result.get("Name") == packages[0].Name -def test_rpc_search_makedepends(client: TestClient): +def test_rpc_search_makedepends(client: TestClient, packages: List[Package], + depends: List[PackageDependency]): + params = { + "v": 5, + "type": "search", + "by": "makedepends", + "arg": "chungus-makedepends" + } with client as request: - response = request.get( - "/rpc?v=5&type=search&by=makedepends&arg=chungus-makedepends") + response = request.get("/rpc", params=params) data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] - assert result.get("Name") == "big-chungus" + assert result.get("Name") == packages[0].Name -def test_rpc_search_optdepends(client: TestClient): +def test_rpc_search_optdepends(client: TestClient, packages: List[Package], + depends: List[PackageDependency]): + params = { + "v": 5, + "type": "search", + "by": "optdepends", + "arg": "chungus-optdepends" + } with client as request: - response = request.get( - "/rpc?v=5&type=search&by=optdepends&arg=chungus-optdepends") + response = request.get("/rpc", params=params) data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] - assert result.get("Name") == "big-chungus" + assert result.get("Name") == packages[0].Name -def test_rpc_search_checkdepends(client: TestClient): +def test_rpc_search_checkdepends(client: TestClient, packages: List[Package], + depends: List[PackageDependency]): + params = { + "v": 5, + "type": "search", + "by": "checkdepends", + "arg": "chungus-checkdepends" + } with client as request: - response = request.get( - "/rpc?v=5&type=search&by=checkdepends&arg=chungus-checkdepends") + response = request.get("/rpc", params=params) data = response.json() assert data.get("resultcount") == 1 result = data.get("results")[0] - assert result.get("Name") == "big-chungus" + assert result.get("Name") == packages[0].Name def test_rpc_incorrect_by(client: TestClient): + params = {"v": 5, "type": "search", "by": "fake", "arg": "big"} with client as request: - response = request.get("/rpc?v=5&type=search&by=fake&arg=big") + response = request.get("/rpc", params=params) assert response.json().get("error") == "Incorrect by field specified." @@ -661,15 +740,20 @@ def test_rpc_jsonp_callback(client: TestClient): For end-to-end verification, the `examples/jsonp.html` file can be used to submit jsonp callback requests to the RPC. """ + params = { + "v": 5, + "type": "search", + "arg": "big", + "callback": "jsonCallback" + } with client as request: - response = request.get( - "/rpc?v=5&type=search&arg=big&callback=jsonCallback") + response = request.get("/rpc", params=params) assert response.headers.get("content-type") == "text/javascript" assert re.search(r'^/\*\*/jsonCallback\(.*\)$', response.text) is not None # Test an invalid callback name; we get an application/json error. + params["callback"] = "jsonCallback!" with client as request: - response = request.get( - "/rpc?v=5&type=search&arg=big&callback=jsonCallback!") + response = request.get("/rpc", params=params) assert response.headers.get("content-type") == "application/json" assert response.json().get("error") == "Invalid callback name." From 604df50b88ac6a1b7babfeebb7ee2ae2844fba2a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 01:49:35 -0800 Subject: [PATCH 1198/1891] housekeep(fastapi): rewrite test_package_comment with fixtures Signed-off-by: Kevin Morris --- test/test_package_comment.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/test/test_package_comment.py b/test/test_package_comment.py index b00e08c3..c89e23af 100644 --- a/test/test_package_comment.py +++ b/test/test_package_comment.py @@ -8,21 +8,29 @@ from aurweb.models.package_base import PackageBase from aurweb.models.package_comment import PackageComment from aurweb.models.user import User -user = pkgbase = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def pkgbase(user: User) -> PackageBase: + with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + yield pkgbase -def test_package_comment_creation(): +def test_package_comment_creation(user: User, pkgbase: PackageBase): with db.begin(): package_comment = db.create(PackageComment, PackageBase=pkgbase, User=user, Comments="Test comment.", @@ -30,26 +38,28 @@ def test_package_comment_creation(): assert bool(package_comment.ID) -def test_package_comment_null_package_base_raises_exception(): +def test_package_comment_null_pkgbase_raises(user: User): with pytest.raises(IntegrityError): PackageComment(User=user, Comments="Test comment.", RenderedComment="Test rendered comment.") -def test_package_comment_null_user_raises_exception(): +def test_package_comment_null_user_raises(pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageComment(PackageBase=pkgbase, Comments="Test comment.", RenderedComment="Test rendered comment.") -def test_package_comment_null_comments_raises_exception(): +def test_package_comment_null_comments_raises(user: User, + pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageComment(PackageBase=pkgbase, User=user, RenderedComment="Test rendered comment.") -def test_package_comment_null_renderedcomment_defaults(): +def test_package_comment_null_renderedcomment_defaults(user: User, + pkgbase: PackageBase): with db.begin(): record = db.create(PackageComment, PackageBase=pkgbase, User=user, Comments="Test comment.") From 012dd24fd85d24369556d4a3eb7e0675fa0c5856 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 01:53:02 -0800 Subject: [PATCH 1199/1891] housekeep(fastapi): rewrite test_tu_vote with fixtures Signed-off-by: Kevin Morris --- test/test_tu_vote.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/test/test_tu_vote.py b/test/test_tu_vote.py index 1dd33387..9bb344b1 100644 --- a/test/test_tu_vote.py +++ b/test/test_tu_vote.py @@ -10,28 +10,33 @@ from aurweb.models.tu_vote import TUVote from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User -user = tu_voteinfo = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, tu_voteinfo + return - ts = int(datetime.utcnow().timestamp()) + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=TRUSTED_USER_ID) + yield user - tu_voteinfo = db.create(TUVoteInfo, - Agenda="Blah blah.", + +@pytest.fixture +def tu_voteinfo(user: User) -> TUVoteInfo: + ts = int(datetime.utcnow().timestamp()) + with db.begin(): + tu_voteinfo = db.create(TUVoteInfo, Agenda="Blah blah.", User=user.Username, Submitted=ts, End=ts + 5, - Quorum=0.5, - Submitter=user) + Quorum=0.5, Submitter=user) + yield tu_voteinfo -def test_tu_vote_creation(): +def test_tu_vote_creation(user: User, tu_voteinfo: TUVoteInfo): with db.begin(): tu_vote = db.create(TUVote, User=user, VoteInfo=tu_voteinfo) @@ -41,11 +46,11 @@ def test_tu_vote_creation(): assert tu_vote in tu_voteinfo.tu_votes -def test_tu_vote_null_user_raises_exception(): +def test_tu_vote_null_user_raises_exception(tu_voteinfo: TUVoteInfo): with pytest.raises(IntegrityError): TUVote(VoteInfo=tu_voteinfo) -def test_tu_vote_null_voteinfo_raises_exception(): +def test_tu_vote_null_voteinfo_raises_exception(user: User): with pytest.raises(IntegrityError): TUVote(User=user) From adafa6ebc14769b8ab3d8564b3c59d6ae441b81a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 01:56:49 -0800 Subject: [PATCH 1200/1891] housekeep(fastapi): rewrite test_package_request with fixtures Signed-off-by: Kevin Morris --- test/test_package_request.py | 37 ++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/test/test_package_request.py b/test/test_package_request.py index 4b5dfb2b..1ba48e09 100644 --- a/test/test_package_request.py +++ b/test/test_package_request.py @@ -12,21 +12,29 @@ from aurweb.models.package_request import (ACCEPTED, ACCEPTED_ID, CLOSED, CLOSED from aurweb.models.request_type import MERGE_ID from aurweb.models.user import User -user = pkgbase = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def pkgbase(user: User) -> PackageBase: + with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + yield pkgbase -def test_package_request_creation(): +def test_package_request_creation(user: User, pkgbase: PackageBase): with db.begin(): package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID, User=user, PackageBase=pkgbase, @@ -45,7 +53,7 @@ def test_package_request_creation(): assert package_request in pkgbase.requests -def test_package_request_closed(): +def test_package_request_closed(user: User, pkgbase: PackageBase): ts = int(datetime.utcnow().timestamp()) with db.begin(): package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID, @@ -61,49 +69,54 @@ def test_package_request_closed(): assert package_request in user.closed_requests -def test_package_request_null_request_type_raises_exception(): +def test_package_request_null_request_type_raises(user: User, + pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageRequest(User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, Comments=str(), ClosureComment=str()) -def test_package_request_null_user_raises_exception(): +def test_package_request_null_user_raises(pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageRequest(ReqTypeID=MERGE_ID, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, Comments=str(), ClosureComment=str()) -def test_package_request_null_package_base_raises_exception(): +def test_package_request_null_package_base_raises(user: User, + pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageRequest(ReqTypeID=MERGE_ID, User=user, PackageBaseName=pkgbase.Name, Comments=str(), ClosureComment=str()) -def test_package_request_null_package_base_name_raises_exception(): +def test_package_request_null_package_base_name_raises(user: User, + pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageRequest(ReqTypeID=MERGE_ID, User=user, PackageBase=pkgbase, Comments=str(), ClosureComment=str()) -def test_package_request_null_comments_raises_exception(): +def test_package_request_null_comments_raises(user: User, + pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageRequest(ReqTypeID=MERGE_ID, User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, ClosureComment=str()) -def test_package_request_null_closure_comment_raises_exception(): +def test_package_request_null_closure_comment_raises(user: User, + pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageRequest(ReqTypeID=MERGE_ID, User=user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, Comments=str()) -def test_package_request_status_display(): +def test_package_request_status_display(user: User, pkgbase: PackageBase): """ Test status_display() based on the Status column value. """ with db.begin(): pkgreq = db.create(PackageRequest, ReqTypeID=MERGE_ID, From 735c5f57cb467174f966c5030c6f13cb5481756b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 16:25:04 -0800 Subject: [PATCH 1201/1891] housekeep(fastapi): rewrite test_package_blacklist Signed-off-by: Kevin Morris --- test/test_package_blacklist.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/test/test_package_blacklist.py b/test/test_package_blacklist.py index 6f4c36d7..427c3be4 100644 --- a/test/test_package_blacklist.py +++ b/test/test_package_blacklist.py @@ -3,21 +3,12 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.models.package_base import PackageBase from aurweb.models.package_blacklist import PackageBlacklist -from aurweb.models.user import User - -user = pkgbase = None @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase - - with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") - pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + return def test_package_blacklist_creation(): From d6cb3b9fac73d531b399ddcb86710df765260bc5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 16:30:33 -0800 Subject: [PATCH 1202/1891] housekeep(fastapi): rewrite test_auth with fixtures Signed-off-by: Kevin Morris --- test/test_auth.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/test/test_auth.py b/test/test_auth.py index 0dc26f86..b63fb96f 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -11,35 +11,40 @@ from aurweb.models.session import Session from aurweb.models.user import User from aurweb.testing.requests import Request -user = backend = request = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, backend, request + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.com", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) + yield user - backend = BasicAuthBackend() - request = Request() + +@pytest.fixture +def backend() -> BasicAuthBackend: + yield BasicAuthBackend() @pytest.mark.asyncio -async def test_auth_backend_missing_sid(): +async def test_auth_backend_missing_sid(backend: BasicAuthBackend): # The request has no AURSID cookie, so authentication fails, and # AnonymousUser is returned. - _, result = await backend.authenticate(request) + _, result = await backend.authenticate(Request()) assert not result.is_authenticated() @pytest.mark.asyncio -async def test_auth_backend_invalid_sid(): +async def test_auth_backend_invalid_sid(backend: BasicAuthBackend): # Provide a fake AURSID that won't be found in the database. # This results in our path going down the invalid sid route, # which gives us an AnonymousUser. + request = Request() request.cookies["AURSID"] = "fake" _, result = await backend.authenticate(request) assert not result.is_authenticated() @@ -55,13 +60,15 @@ async def test_auth_backend_invalid_user_id(): @pytest.mark.asyncio -async def test_basic_auth_backend(): +async def test_basic_auth_backend(user: User, backend: BasicAuthBackend): # This time, everything matches up. We expect the user to # equal the real_user. now_ts = datetime.utcnow().timestamp() with db.begin(): db.create(Session, UsersID=user.ID, SessionID="realSession", LastUpdateTS=now_ts + 5) + + request = Request() request.cookies["AURSID"] = "realSession" _, result = await backend.authenticate(request) assert result == user From 91f65911414423fc9dae8cf509beb57e3fadabea Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 16:35:52 -0800 Subject: [PATCH 1203/1891] housekeep(fastapi): rewrite test_accepted_term with fixtures Signed-off-by: Kevin Morris --- test/test_accepted_term.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/test/test_accepted_term.py b/test/test_accepted_term.py index de18c61a..2af7127b 100644 --- a/test/test_accepted_term.py +++ b/test/test_accepted_term.py @@ -8,39 +8,48 @@ from aurweb.models.account_type import USER_ID from aurweb.models.term import Term from aurweb.models.user import User -user = term = accepted_term = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, term + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) + yield user + +@pytest.fixture +def term() -> Term: + with db.begin(): term = db.create(Term, Description="Test term", URL="https://test.term") - yield term -def test_accepted_term(): +@pytest.fixture +def accepted_term(user: User, term: Term) -> AcceptedTerm: with db.begin(): accepted_term = db.create(AcceptedTerm, User=user, Term=term) + yield accepted_term + +def test_accepted_term(user: User, term: Term, accepted_term: AcceptedTerm): # Make sure our AcceptedTerm relationships got initialized properly. assert accepted_term.User == user assert accepted_term in user.accepted_terms assert accepted_term in term.accepted_terms -def test_accepted_term_null_user_raises_exception(): +def test_accepted_term_null_user_raises_exception(term: Term): with pytest.raises(IntegrityError): AcceptedTerm(Term=term) -def test_accepted_term_null_term_raises_exception(): +def test_accepted_term_null_term_raises_exception(user: User): with pytest.raises(IntegrityError): AcceptedTerm(User=user) From b20ec9925a5f92c020b8705bc733cdc4831ca5e4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 17:11:10 -0800 Subject: [PATCH 1204/1891] housekeep(fastapi): rewrite test_ssh_pub_key with fixtures Signed-off-by: Kevin Morris --- test/test_ssh_pub_key.py | 48 ++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py index e17af5a7..68b6e7a0 100644 --- a/test/test_ssh_pub_key.py +++ b/test/test_ssh_pub_key.py @@ -16,47 +16,53 @@ lfv98Kr0NUp51zpf55Arxn9j0Rz9xTA7FiODQgCn6iQ0SDtzUNL0IKTCw26xJY5gzMxbfpvzPQGeul\ x/ioM= kevr@volcano """ -user = ssh_pub_key = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, ssh_pub_key + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) + yield user + +@pytest.fixture +def pubkey(user: User) -> SSHPubKey: with db.begin(): - ssh_pub_key = db.create(SSHPubKey, UserID=user.ID, - Fingerprint="testFingerprint", - PubKey="testPubKey") + pubkey = db.create(SSHPubKey, User=user, + Fingerprint="testFingerprint", + PubKey="testPubKey") + yield pubkey -def test_ssh_pub_key(): - assert ssh_pub_key.UserID == user.ID - assert ssh_pub_key.User == user - assert ssh_pub_key.Fingerprint == "testFingerprint" - assert ssh_pub_key.PubKey == "testPubKey" +def test_pubkey(user: User, pubkey: SSHPubKey): + assert pubkey.UserID == user.ID + assert pubkey.User == user + assert pubkey.Fingerprint == "testFingerprint" + assert pubkey.PubKey == "testPubKey" -def test_ssh_pub_key_cs(): +def test_pubkey_cs(user: User): """ Test case sensitivity of the database table. """ with db.begin(): - ssh_pub_key_cs = db.create(SSHPubKey, UserID=user.ID, - Fingerprint="TESTFINGERPRINT", - PubKey="TESTPUBKEY") + pubkey_cs = db.create(SSHPubKey, User=user, + Fingerprint="TESTFINGERPRINT", + PubKey="TESTPUBKEY") - assert ssh_pub_key_cs.Fingerprint == "TESTFINGERPRINT" - assert ssh_pub_key_cs.PubKey == "TESTPUBKEY" - assert ssh_pub_key.Fingerprint == "testFingerprint" - assert ssh_pub_key.PubKey == "testPubKey" + assert pubkey_cs.Fingerprint == "TESTFINGERPRINT" + assert pubkey_cs.Fingerprint != "testFingerprint" + assert pubkey_cs.PubKey == "TESTPUBKEY" + assert pubkey_cs.PubKey != "testPubKey" -def test_ssh_pub_key_fingerprint(): +def test_pubkey_fingerprint(): assert get_fingerprint(TEST_SSH_PUBKEY) is not None -def test_ssh_pub_key_invalid_fingerprint(): +def test_pubkey_invalid_fingerprint(): assert get_fingerprint("ssh-rsa fake and invalid") is None From a082de5244f55aa4098608e2e6b3341463669c01 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 17:21:42 -0800 Subject: [PATCH 1205/1891] housekeep(fastapi): rewrite test_package_keyword with fixtures Signed-off-by: Kevin Morris --- test/test_package_keyword.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/test_package_keyword.py b/test/test_package_keyword.py index 88ccb734..ff466efc 100644 --- a/test/test_package_keyword.py +++ b/test/test_package_keyword.py @@ -8,26 +8,32 @@ from aurweb.models.package_base import PackageBase from aurweb.models.package_keyword import PackageKeyword from aurweb.models.user import User -user = pkgbase = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) - pkgbase = db.create(PackageBase, - Name="beautiful-package", - Maintainer=user) + yield user -def test_package_keyword(): +@pytest.fixture +def pkgbase(user: User) -> PackageBase: with db.begin(): - pkg_keyword = db.create(PackageKeyword, - PackageBase=pkgbase, + pkgbase = db.create(PackageBase, Name="beautiful-package", + Maintainer=user) + yield pkgbase + + +def test_package_keyword(pkgbase: PackageBase): + with db.begin(): + pkg_keyword = db.create(PackageKeyword, PackageBase=pkgbase, Keyword="test") assert pkg_keyword in pkgbase.keywords assert pkgbase == pkg_keyword.PackageBase From 655b98d19e5e82817146f3f8a00215d10fd0da0a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 17:29:03 -0800 Subject: [PATCH 1206/1891] housekeep(fastapi): rewrite test_package_license with fixtures Signed-off-by: Kevin Morris --- test/test_package_license.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/test/test_package_license.py b/test/test_package_license.py index 965d0c6f..c43423b8 100644 --- a/test/test_package_license.py +++ b/test/test_package_license.py @@ -10,25 +10,37 @@ from aurweb.models.package_base import PackageBase from aurweb.models.package_license import PackageLicense from aurweb.models.user import User -user = license = pkgbase = package = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, license, pkgbase, package + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) - license = db.create(License, Name="Test License") + yield user + +@pytest.fixture +def license() -> License: + with db.begin(): + license = db.create(License, Name="Test License") + yield license + + +@pytest.fixture +def package(user: User, license: License): with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + yield package -def test_package_license(): +def test_package_license(license: License, package: Package): with db.begin(): package_license = db.create(PackageLicense, Package=package, License=license) @@ -36,11 +48,11 @@ def test_package_license(): assert package_license.Package == package -def test_package_license_null_package_raises_exception(): +def test_package_license_null_package_raises(license: License): with pytest.raises(IntegrityError): PackageLicense(License=license) -def test_package_license_null_license_raises_exception(): +def test_package_license_null_license_raises(package: Package): with pytest.raises(IntegrityError): PackageLicense(Package=package) From ff3931e43506a466d01dde48fa647c4d13740ce3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 18:10:40 -0800 Subject: [PATCH 1207/1891] housekeep(fastapi): rewrite test_package_notification with fixtures Signed-off-by: Kevin Morris --- test/test_package_notification.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/test/test_package_notification.py b/test/test_package_notification.py index 2e505dd8..e7a72a43 100644 --- a/test/test_package_notification.py +++ b/test/test_package_notification.py @@ -7,20 +7,28 @@ from aurweb.models.package_base import PackageBase from aurweb.models.package_notification import PackageNotification from aurweb.models.user import User -user = pkgbase = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword") + yield user + + +@pytest.fixture +def pkgbase(user: User) -> PackageBase: + with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + yield pkgbase -def test_package_notification_creation(): +def test_package_notification_creation(user: User, pkgbase: PackageBase): with db.begin(): package_notification = db.create( PackageNotification, User=user, PackageBase=pkgbase) @@ -29,11 +37,11 @@ def test_package_notification_creation(): assert package_notification.PackageBase == pkgbase -def test_package_notification_null_user_raises_exception(): +def test_package_notification_null_user_raises(pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageNotification(PackageBase=pkgbase) -def test_package_notification_null_pkgbase_raises_exception(): +def test_package_notification_null_pkgbase_raises(user: User): with pytest.raises(IntegrityError): PackageNotification(User=user) From 14d80d756fe73039d7e5b7836ad1c343668a7e9f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 18:18:48 -0800 Subject: [PATCH 1208/1891] housekeep(fastapi): rewrite test_package_comaintainer with fixtures Signed-off-by: Kevin Morris --- test/test_package_comaintainer.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/test/test_package_comaintainer.py b/test/test_package_comaintainer.py index ff74cddf..e377edc0 100644 --- a/test/test_package_comaintainer.py +++ b/test/test_package_comaintainer.py @@ -3,24 +3,34 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db +from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.user import User -user = pkgbase = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def pkgbase(user: User) -> PackageBase: + with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + yield pkgbase -def test_package_comaintainer_creation(): +def test_package_comaintainer_creation(user: User, pkgbase: PackageBase): with db.begin(): package_comaintainer = db.create(PackageComaintainer, User=user, PackageBase=pkgbase, Priority=5) @@ -30,16 +40,17 @@ def test_package_comaintainer_creation(): assert package_comaintainer.Priority == 5 -def test_package_comaintainer_null_user_raises_exception(): +def test_package_comaintainer_null_user_raises(pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageComaintainer(PackageBase=pkgbase, Priority=1) -def test_package_comaintainer_null_pkgbase_raises_exception(): +def test_package_comaintainer_null_pkgbase_raises(user: User): with pytest.raises(IntegrityError): PackageComaintainer(User=user, Priority=1) -def test_package_comaintainer_null_priority_raises_exception(): +def test_package_comaintainer_null_priority_raises(user: User, + pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageComaintainer(User=user, PackageBase=pkgbase) From 31a093ba063168825595fe82d3c42d34d9d67a15 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 18:51:50 -0800 Subject: [PATCH 1209/1891] housekeep(fastapi): rewrite test_package_relation with fixtures Signed-off-by: Kevin Morris --- test/test_package_relation.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/test/test_package_relation.py b/test/test_package_relation.py index e5f7f453..6e9a5545 100644 --- a/test/test_package_relation.py +++ b/test/test_package_relation.py @@ -10,28 +10,32 @@ from aurweb.models.package_relation import PackageRelation from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.models.user import User -user = pkgbase = package = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase, package + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) - pkgbase = db.create(PackageBase, - Name="test-package", - Maintainer=user) - package = db.create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, + yield user + + +@pytest.fixture +def package(user: User) -> Package: + with db.begin(): + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, Description="Test description.", URL="https://test.package") + yield package -def test_package_relation(): +def test_package_relation(package: Package): with db.begin(): pkgrel = db.create(PackageRelation, Package=package, RelTypeID=CONFLICTS_ID, @@ -48,16 +52,16 @@ def test_package_relation(): pkgrel.RelTypeID = REPLACES_ID -def test_package_relation_null_package_raises_exception(): +def test_package_relation_null_package_raises(): with pytest.raises(IntegrityError): PackageRelation(RelTypeID=CONFLICTS_ID, RelName="test-relation") -def test_package_relation_null_relation_type_raises_exception(): +def test_package_relation_null_relation_type_raises(package: Package): with pytest.raises(IntegrityError): PackageRelation(Package=package, RelName="test-relation") -def test_package_relation_null_relname_raises_exception(): +def test_package_relation_null_relname_raises(package: Package): with pytest.raises(IntegrityError): PackageRelation(Package=package, RelTypeID=CONFLICTS_ID) From a0e1a1641d08d533b1919ffb60298476f21de237 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:12:06 -0800 Subject: [PATCH 1210/1891] fix(fastapi): support UsersID and User columns in the Session model Signed-off-by: Kevin Morris --- aurweb/models/session.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/aurweb/models/session.py b/aurweb/models/session.py index 7a06eddc..37ab4bce 100644 --- a/aurweb/models/session.py +++ b/aurweb/models/session.py @@ -18,10 +18,16 @@ class Session(Base): def __init__(self, **kwargs): super().__init__(**kwargs) - user_exists = db.query( - db.query(_User).filter(_User.ID == self.UsersID).exists() - ).scalar() - if not user_exists: + # We'll try to either use UsersID or User.ID if we can. + # If neither exist, an AttributeError is raised, in which case + # we set the uid to 0, which triggers IntegrityError below. + try: + uid = self.UsersID or self.User.ID + except AttributeError: + uid = 0 + + user_exists = db.query(_User).filter(_User.ID == uid).exists() + if not db.query(user_exists).scalar(): raise IntegrityError( statement=("Foreign key UsersID cannot be null and " "must be a valid user's ID."), From ca25595022e4a5c525ecce9de0c009bf19c6fd2c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:12:31 -0800 Subject: [PATCH 1211/1891] housekeep(fastapi): rewrite test_sesion with fixtures Also, added a new test function which tests the IntegrityError exception. Signed-off-by: Kevin Morris --- test/test_session.py | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/test/test_session.py b/test/test_session.py index 7d3037a1..67b1ada0 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -4,31 +4,37 @@ from unittest import mock import pytest +from sqlalchemy.exc import IntegrityError + from aurweb import db -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.session import Session, generate_unique_sid from aurweb.models.user import User -account_type = user = session = None - @pytest.fixture(autouse=True) def setup(db_test): - global account_type, user, session + return - account_type = db.query(AccountType, - AccountType.AccountType == "User").first() + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", ResetKey="testReset", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) + yield user + +@pytest.fixture +def session(user: User) -> Session: with db.begin(): - session = db.create(Session, UsersID=user.ID, SessionID="testSession", + session = db.create(Session, User=user, SessionID="testSession", LastUpdateTS=datetime.utcnow().timestamp()) + yield session -def test_session(): +def test_session(user: User, session: Session): assert session.SessionID == "testSession" assert session.UsersID == user.ID @@ -38,22 +44,27 @@ def test_session_cs(): with db.begin(): user2 = db.create(User, Username="test2", Email="test2@example.org", ResetKey="testReset2", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) with db.begin(): - session_cs = db.create(Session, UsersID=user2.ID, - SessionID="TESTSESSION", + session_cs = db.create(Session, User=user2, SessionID="TESTSESSION", LastUpdateTS=datetime.utcnow().timestamp()) + assert session_cs.SessionID == "TESTSESSION" - assert session.SessionID == "testSession" + assert session_cs.SessionID != "testSession" -def test_session_user_association(): +def test_session_user_association(user: User, session: Session): # Make sure that the Session user attribute is correct. assert session.User == user -def test_generate_unique_sid(): +def test_session_null_user_raises(): + with pytest.raises(IntegrityError): + Session() + + +def test_generate_unique_sid(session: Session): # Mock up aurweb.models.session.generate_sid by returning # sids[i % 2] from 0 .. n. This will swap between each sid # between each call. From ae728179506bdd39ac0c929f36324626cea53a91 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:17:14 -0800 Subject: [PATCH 1212/1891] housekeep(fastapi): rewrite test_routes with fixtures Signed-off-by: Kevin Morris --- test/test_routes.py | 46 +++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/test/test_routes.py b/test/test_routes.py index 32f507f3..85d30c02 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -14,30 +14,34 @@ from aurweb.models.account_type import USER_ID from aurweb.models.user import User from aurweb.testing.requests import Request -user = client = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, client + return + +@pytest.fixture +def client() -> TestClient: + yield TestClient(app=app) + + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) - - client = TestClient(app) + yield user -def test_index(): +def test_index(client: TestClient): """ Test the index route at '/'. """ - # Use `with` to trigger FastAPI app events. with client as req: response = req.get("/") assert response.status_code == int(HTTPStatus.OK) -def test_index_security_headers(): +def test_index_security_headers(client: TestClient): """ Check for the existence of CSP, XCTO, XFO and RP security headers. CSP: Content-Security-Policy @@ -55,15 +59,16 @@ def test_index_security_headers(): assert response.headers.get("X-Frame-Options") == "SAMEORIGIN" -def test_favicon(): +def test_favicon(client: TestClient): """ Test the favicon route at '/favicon.ico'. """ - response1 = client.get("/static/images/favicon.ico") - response2 = client.get("/favicon.ico") + with client as request: + response1 = request.get("/static/images/favicon.ico") + response2 = request.get("/favicon.ico") assert response1.status_code == int(HTTPStatus.OK) assert response1.content == response2.content -def test_language(): +def test_language(client: TestClient): """ Test the language post route as a guest user. """ post_data = { "set_lang": "de", @@ -74,7 +79,7 @@ def test_language(): assert response.status_code == int(HTTPStatus.SEE_OTHER) -def test_language_invalid_next(): +def test_language_invalid_next(client: TestClient): """ Test an invalid next route at '/language'. """ post_data = { "set_lang": "de", @@ -85,7 +90,7 @@ def test_language_invalid_next(): assert response.status_code == int(HTTPStatus.BAD_REQUEST) -def test_user_language(): +def test_user_language(client: TestClient, user: User): """ Test the language post route as an authenticated user. """ post_data = { "set_lang": "de", @@ -102,7 +107,7 @@ def test_user_language(): assert user.LangPreference == "de" -def test_language_query_params(): +def test_language_query_params(client: TestClient): """ Test the language post route with query params. """ next = urllib.parse.quote_plus("/") post_data = { @@ -117,14 +122,15 @@ def test_language_query_params(): assert response.status_code == int(HTTPStatus.SEE_OTHER) -def test_error_messages(): - response1 = client.get("/thisroutedoesnotexist") - response2 = client.get("/raisefivethree") +def test_error_messages(client: TestClient): + with client as request: + response1 = request.get("/thisroutedoesnotexist") + response2 = request.get("/raisefivethree") assert response1.status_code == int(HTTPStatus.NOT_FOUND) assert response2.status_code == int(HTTPStatus.SERVICE_UNAVAILABLE) -def test_nonce_csp(): +def test_nonce_csp(client: TestClient): with client as request: response = request.get("/") data = response.headers.get("Content-Security-Policy") @@ -146,7 +152,7 @@ def test_nonce_csp(): assert nonce_verified is True -def test_id_redirect(): +def test_id_redirect(client: TestClient): with client as request: response = request.get("/", params={ "id": "test", # This param will be rewritten into Location. From 93bc91cce252ab789493aa5d0bc0c796f5133ae2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:25:10 -0800 Subject: [PATCH 1213/1891] housekeep(fastapi): rewrite test_tu_voteinfo with fixtures Signed-off-by: Kevin Morris --- test/test_tu_voteinfo.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py index 5926fbf9..26fa9522 100644 --- a/test/test_tu_voteinfo.py +++ b/test/test_tu_voteinfo.py @@ -5,27 +5,27 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.db import create, query, rollback -from aurweb.models.account_type import AccountType +from aurweb.db import create, rollback +from aurweb.models.account_type import TRUSTED_USER_ID from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User -user = None - @pytest.fixture(autouse=True) def setup(db_test): - global user + return - tu_type = query(AccountType, - AccountType.AccountType == "Trusted User").first() + +@pytest.fixture +def user() -> User: with db.begin(): user = create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - AccountType=tu_type) + AccountTypeID=TRUSTED_USER_ID) + yield user -def test_tu_voteinfo_creation(): +def test_tu_voteinfo_creation(user: User): ts = int(datetime.utcnow().timestamp()) with db.begin(): tu_voteinfo = create(TUVoteInfo, @@ -49,7 +49,7 @@ def test_tu_voteinfo_creation(): assert tu_voteinfo in user.tu_voteinfo_set -def test_tu_voteinfo_is_running(): +def test_tu_voteinfo_is_running(user: User): ts = int(datetime.utcnow().timestamp()) with db.begin(): tu_voteinfo = create(TUVoteInfo, @@ -65,7 +65,7 @@ def test_tu_voteinfo_is_running(): assert tu_voteinfo.is_running() is False -def test_tu_voteinfo_total_votes(): +def test_tu_voteinfo_total_votes(user: User): ts = int(datetime.utcnow().timestamp()) with db.begin(): tu_voteinfo = create(TUVoteInfo, @@ -83,7 +83,7 @@ def test_tu_voteinfo_total_votes(): assert tu_voteinfo.total_votes() == 9 -def test_tu_voteinfo_null_submitter_raises_exception(): +def test_tu_voteinfo_null_submitter_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): create(TUVoteInfo, @@ -94,7 +94,7 @@ def test_tu_voteinfo_null_submitter_raises_exception(): rollback() -def test_tu_voteinfo_null_agenda_raises_exception(): +def test_tu_voteinfo_null_agenda_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): create(TUVoteInfo, @@ -105,7 +105,7 @@ def test_tu_voteinfo_null_agenda_raises_exception(): rollback() -def test_tu_voteinfo_null_user_raises_exception(): +def test_tu_voteinfo_null_user_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): create(TUVoteInfo, @@ -116,7 +116,7 @@ def test_tu_voteinfo_null_user_raises_exception(): rollback() -def test_tu_voteinfo_null_submitted_raises_exception(): +def test_tu_voteinfo_null_submitted_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): create(TUVoteInfo, @@ -128,7 +128,7 @@ def test_tu_voteinfo_null_submitted_raises_exception(): rollback() -def test_tu_voteinfo_null_end_raises_exception(): +def test_tu_voteinfo_null_end_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): create(TUVoteInfo, @@ -140,7 +140,7 @@ def test_tu_voteinfo_null_end_raises_exception(): rollback() -def test_tu_voteinfo_null_quorum_raises_exception(): +def test_tu_voteinfo_null_quorum_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): create(TUVoteInfo, From 171b347dadddf92f90e16f98fab388112174053a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:38:49 -0800 Subject: [PATCH 1214/1891] housekeep(fastapi): rewrite test_package_base with fixtures Signed-off-by: Kevin Morris --- test/test_package_base.py | 57 +++++++++++++++------------------------ 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/test/test_package_base.py b/test/test_package_base.py index 8e4b2edf..5be7e40b 100644 --- a/test/test_package_base.py +++ b/test/test_package_base.py @@ -2,35 +2,36 @@ import pytest from sqlalchemy.exc import IntegrityError -import aurweb.config - from aurweb import db -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase from aurweb.models.user import User -user = None - @pytest.fixture(autouse=True) def setup(db_test): - global user + return - account_type = db.query(AccountType, - AccountType.AccountType == "User").first() + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) + yield user -def test_package_base(): +@pytest.fixture +def pkgbase(user: User) -> PackageBase: with db.begin(): - pkgbase = db.create(PackageBase, - Name="beautiful-package", + pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user) - assert pkgbase in user.maintained_bases + yield pkgbase + +def test_package_base(user: User, pkgbase: PackageBase): + assert pkgbase in user.maintained_bases assert not pkgbase.OutOfDateTS assert pkgbase.SubmittedTS > 0 assert pkgbase.ModifiedTS > 0 @@ -42,33 +43,19 @@ def test_package_base(): assert pkgbase.Popularity == 0.0 -def test_package_base_ci(): +def test_package_base_ci(user: User, pkgbase: PackageBase): """ Test case insensitivity of the database table. """ - if aurweb.config.get("database", "backend") == "sqlite": - return None # SQLite doesn't seem handle this. - - with db.begin(): - pkgbase = db.create(PackageBase, - Name="beautiful-package", - Maintainer=user) - assert bool(pkgbase.ID) - with pytest.raises(IntegrityError): with db.begin(): - db.create(PackageBase, - Name="Beautiful-Package", - Maintainer=user) + db.create(PackageBase, Name=pkgbase.Name.upper(), Maintainer=user) db.rollback() -def test_package_base_relationships(): +def test_package_base_relationships(user: User, pkgbase: PackageBase): with db.begin(): - pkgbase = db.create(PackageBase, - Name="beautiful-package", - Flagger=user, - Maintainer=user, - Submitter=user, - Packager=user) + pkgbase.Flagger = user + pkgbase.Submitter = user + pkgbase.Packager = user assert pkgbase in user.flagged_bases assert pkgbase in user.maintained_bases assert pkgbase in user.submitted_bases @@ -77,6 +64,4 @@ def test_package_base_relationships(): def test_package_base_null_name_raises_exception(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(PackageBase) - db.rollback() + PackageBase() From df530d8a7358f71c6579e6bfd0fea1143dfc89b7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:42:50 -0800 Subject: [PATCH 1215/1891] housekeep(fastapi): rewrite test_package_source with fixtures Signed-off-by: Kevin Morris --- test/test_package_source.py | 51 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/test/test_package_source.py b/test/test_package_source.py index b83c9d48..e5797f90 100644 --- a/test/test_package_source.py +++ b/test/test_package_source.py @@ -2,46 +2,45 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb.db import begin, create, query, rollback -from aurweb.models.account_type import AccountType +from aurweb import db +from aurweb.models.account_type import USER_ID from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_source import PackageSource from aurweb.models.user import User -from aurweb.testing import setup_test_db - -user = pkgbase = package = None @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase, package - - setup_test_db("PackageSources", "Packages", "PackageBases", "Users") - - account_type = query(AccountType, - AccountType.AccountType == "User").first() - with begin(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - pkgbase = create(PackageBase, - Name="test-package", - Maintainer=user) - package = create(Package, PackageBase=pkgbase, Name="test-package") + return -def test_package_source(): - with begin(): - pkgsource = create(PackageSource, Package=package) +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create(User, Username="test", Email="test@example.org", + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def package(user: User) -> Package: + with db.begin(): + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + package = db.create(Package, PackageBase=pkgbase, Name="test-package") + yield package + + +def test_package_source(package: Package): + with db.begin(): + pkgsource = db.create(PackageSource, Package=package) assert pkgsource.Package == package # By default, PackageSources.Source assigns the string '/dev/null'. assert pkgsource.Source == "/dev/null" assert pkgsource.SourceArch is None -def test_package_source_null_package_raises_exception(): +def test_package_source_null_package_raises(): with pytest.raises(IntegrityError): - with begin(): - create(PackageSource) - rollback() + PackageSource() From 150c944758bb67f97625c566cd635500d27ef7ef Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:45:08 -0800 Subject: [PATCH 1216/1891] housekeep(fastapi): rewrite test_package_group with fixtures Signed-off-by: Kevin Morris --- test/test_package_group.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/test/test_package_group.py b/test/test_package_group.py index 2c91e0b1..0cb83ee2 100644 --- a/test/test_package_group.py +++ b/test/test_package_group.py @@ -10,36 +10,48 @@ from aurweb.models.package_base import PackageBase from aurweb.models.package_group import PackageGroup from aurweb.models.user import User -user = group = pkgbase = package = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, group, pkgbase, package + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", AccountTypeID=USER_ID) - group = db.create(Group, Name="Test Group") + yield user + +@pytest.fixture +def group() -> Group: + with db.begin(): + group = db.create(Group, Name="Test Group") + yield group + + +@pytest.fixture +def package(user: User) -> Package: with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + yield package -def test_package_group(): +def test_package_group(package: Package, group: Group): with db.begin(): package_group = db.create(PackageGroup, Package=package, Group=group) assert package_group.Group == group assert package_group.Package == package -def test_package_group_null_package_raises_exception(): +def test_package_group_null_package_raises(group: Group): with pytest.raises(IntegrityError): PackageGroup(Group=group) -def test_package_group_null_group_raises_exception(): +def test_package_group_null_group_raises(package: Package): with pytest.raises(IntegrityError): PackageGroup(Package=package) From 05bd6e9076d03006358c6862bfb2d95d78eb93b9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:48:01 -0800 Subject: [PATCH 1217/1891] housekeep(fastapi): rewrite test_package_vote with fixtures Signed-off-by: Kevin Morris --- test/test_package_vote.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/test/test_package_vote.py b/test/test_package_vote.py index d1ec203b..08edb92d 100644 --- a/test/test_package_vote.py +++ b/test/test_package_vote.py @@ -5,24 +5,34 @@ import pytest from sqlalchemy.exc import IntegrityError from aurweb import db +from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase from aurweb.models.package_vote import PackageVote from aurweb.models.user import User -user = pkgbase = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") + RealName="Test User", Passwd=str(), + AccountTypeID=USER_ID) + yield user + + +@pytest.fixture +def pkgbase(user: User) -> PackageBase: + with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + yield pkgbase -def test_package_vote_creation(): +def test_package_vote_creation(user: User, pkgbase: PackageBase): ts = int(datetime.utcnow().timestamp()) with db.begin(): @@ -34,16 +44,16 @@ def test_package_vote_creation(): assert package_vote.VoteTS == ts -def test_package_vote_null_user_raises_exception(): +def test_package_vote_null_user_raises(pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageVote(PackageBase=pkgbase, VoteTS=1) -def test_package_vote_null_pkgbase_raises_exception(): +def test_package_vote_null_pkgbase_raises(user: User): with pytest.raises(IntegrityError): PackageVote(User=user, VoteTS=1) -def test_package_vote_null_votets_raises_exception(): +def test_package_vote_null_votets_raises(user: User, pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageVote(User=user, PackageBase=pkgbase) From 140f9b1fb225e00163662290de426e8c2a064264 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 20:50:17 -0800 Subject: [PATCH 1218/1891] housekeep(fastapi): rewrite test_package_dependency with fixtures Signed-off-by: Kevin Morris --- test/test_package_dependency.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py index e6125669..7297abe4 100644 --- a/test/test_package_dependency.py +++ b/test/test_package_dependency.py @@ -10,28 +10,32 @@ from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency from aurweb.models.user import User -user = pkgbase = package = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase, package + return + +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", + RealName="Test User", Passwd=str(), AccountTypeID=USER_ID) - pkgbase = db.create(PackageBase, - Name="test-package", - Maintainer=user) - package = db.create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, + yield user + + +@pytest.fixture +def package(user: User) -> Package: + with db.begin(): + pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) + package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, Description="Test description.", URL="https://test.package") + yield package -def test_package_dependencies(): +def test_package_dependencies(user: User, package: Package): with db.begin(): pkgdep = db.create(PackageDependency, Package=package, DepTypeID=DEPENDS_ID, DepName="test-dep") @@ -57,16 +61,16 @@ def test_package_dependencies(): assert pkgdep.is_package() -def test_package_dependencies_null_package_raises_exception(): +def test_package_dependencies_null_package_raises(): with pytest.raises(IntegrityError): PackageDependency(DepTypeID=DEPENDS_ID, DepName="test-dep") -def test_package_dependencies_null_dependency_type_raises_exception(): +def test_package_dependencies_null_dependency_type_raises(package: Package): with pytest.raises(IntegrityError): PackageDependency(Package=package, DepName="test-dep") -def test_package_dependencies_null_depname_raises_exception(): +def test_package_dependencies_null_depname_raises(package: Package): with pytest.raises(IntegrityError): PackageDependency(DepTypeID=DEPENDS_ID, Package=package) From 5b14ad406560b87773b7bf81b0ef0fbb6a362898 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 21:16:49 -0800 Subject: [PATCH 1219/1891] housekeep(fastapi): rewrite test_user with fixtures Signed-off-by: Kevin Morris --- test/test_user.py | 110 +++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 66 deletions(-) diff --git a/test/test_user.py b/test/test_user.py index dbb45166..52cdc89e 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -8,10 +8,10 @@ import pytest import aurweb.auth import aurweb.config +import aurweb.models.account_type as at from aurweb import db from aurweb.auth import creds -from aurweb.models.account_type import AccountType from aurweb.models.ban import Ban from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -22,23 +22,30 @@ from aurweb.models.ssh_pub_key import SSHPubKey from aurweb.models.user import User from aurweb.testing.requests import Request -account_type = user = None - @pytest.fixture(autouse=True) def setup(db_test): - global account_type, user + return - account_type = db.query(AccountType, - AccountType.AccountType == "User").first() +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=at.USER_ID) + yield user -def test_user_login_logout(): +@pytest.fixture +def package(user: User) -> Package: + with db.begin(): + pkgbase = db.create(PackageBase, Name="pkg1", Maintainer=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + yield pkg + + +def test_user_login_logout(user: User): """ Test creating a user and reading its columns. """ # Assert that make_user created a valid user. assert bool(user.ID) @@ -47,8 +54,6 @@ def test_user_login_logout(): assert user.valid_password("testPassword") assert not user.valid_password("badPassword") - assert user in account_type.users - # Make a raw request. request = Request() assert not user.login(request, "badPassword") @@ -81,10 +86,6 @@ def test_user_login_logout(): assert result.valid_password("testPassword") assert result.is_authenticated() - # Ensure we've got the correct account type. - assert user.AccountType.ID == account_type.ID - assert user.AccountType.AccountType == account_type.AccountType - # Test out user string functions. assert repr(user) == f"" @@ -95,13 +96,13 @@ def test_user_login_logout(): assert not user.is_authenticated() -def test_user_login_twice(): +def test_user_login_twice(user: User): request = Request() assert user.login(request, "testPassword") assert user.login(request, "testPassword") -def test_user_login_banned(): +def test_user_login_banned(user: User): # Add ban for the next 30 seconds. banned_timestamp = datetime.utcnow() + timedelta(seconds=30) with db.begin(): @@ -112,13 +113,13 @@ def test_user_login_banned(): assert not user.login(request, "testPassword") -def test_user_login_suspended(): +def test_user_login_suspended(user: User): with db.begin(): user.Suspended = True assert not user.login(Request(), "testPassword") -def test_legacy_user_authentication(): +def test_legacy_user_authentication(user: User): with db.begin(): user.Salt = bcrypt.gensalt().decode() user.Passwd = hashlib.md5( @@ -132,7 +133,7 @@ def test_legacy_user_authentication(): assert not user.valid_password(None) -def test_user_login_with_outdated_sid(): +def test_user_login_with_outdated_sid(user: User): # Make a session with a LastUpdateTS 5 seconds ago, causing # user.login to update it with a new sid. with db.begin(): @@ -143,7 +144,7 @@ def test_user_login_with_outdated_sid(): assert sid != "stub" -def test_user_update_password(): +def test_user_update_password(user: User): user.update_password("secondPassword") assert not user.valid_password("testPassword") assert user.valid_password("secondPassword") @@ -154,11 +155,11 @@ def test_user_minimum_passwd_length(): assert User.minimum_passwd_length() == passwd_min_len -def test_user_has_credential(): - assert not user.has_credential(aurweb.auth.creds.ACCOUNT_CHANGE_TYPE) +def test_user_has_credential(user: User): + assert not user.has_credential(creds.ACCOUNT_CHANGE_TYPE) -def test_user_ssh_pub_key(): +def test_user_ssh_pub_key(user: User): assert user.ssh_pub_key is None with db.begin(): @@ -169,34 +170,26 @@ def test_user_ssh_pub_key(): assert user.ssh_pub_key == ssh_pub_key -def test_user_credential_types(): +def test_user_credential_types(user: User): assert user.AccountTypeID in creds.user_developer_or_trusted_user assert user.AccountTypeID not in creds.trusted_user assert user.AccountTypeID not in creds.developer assert user.AccountTypeID not in creds.trusted_user_or_dev - trusted_user_type = db.query(AccountType).filter( - AccountType.AccountType == "Trusted User" - ).first() with db.begin(): - user.AccountType = trusted_user_type + user.AccountTypeID = at.TRUSTED_USER_ID assert user.AccountTypeID in creds.trusted_user assert user.AccountTypeID in creds.trusted_user_or_dev - developer_type = db.query(AccountType, - AccountType.AccountType == "Developer").first() with db.begin(): - user.AccountType = developer_type + user.AccountTypeID = at.DEVELOPER_ID assert user.AccountTypeID in creds.developer assert user.AccountTypeID in creds.trusted_user_or_dev - type_str = "Trusted User & Developer" - elevated_type = db.query(AccountType, - AccountType.AccountType == type_str).first() with db.begin(): - user.AccountType = elevated_type + user.AccountTypeID = at.TRUSTED_USER_AND_DEV_ID assert user.AccountTypeID in creds.trusted_user assert user.AccountTypeID in creds.developer @@ -208,7 +201,7 @@ def test_user_credential_types(): assert user.is_developer() -def test_user_json(): +def test_user_json(user: User): data = json.loads(user.json()) assert data.get("ID") == user.ID assert data.get("Username") == user.Username @@ -217,7 +210,7 @@ def test_user_json(): assert isinstance(data.get("RegistrationTS"), int) -def test_user_as_dict(): +def test_user_as_dict(user: User): data = user.as_dict() assert data.get("ID") == user.ID assert data.get("Username") == user.Username @@ -226,57 +219,42 @@ def test_user_as_dict(): assert isinstance(data.get("RegistrationTS"), datetime) -def test_user_is_trusted_user(): - tu_type = db.query(AccountType, - AccountType.AccountType == "Trusted User").first() +def test_user_is_trusted_user(user: User): with db.begin(): - user.AccountType = tu_type + user.AccountTypeID = at.TRUSTED_USER_ID assert user.is_trusted_user() is True # Do it again with the combined role. - tu_type = db.query( - AccountType, - AccountType.AccountType == "Trusted User & Developer").first() with db.begin(): - user.AccountType = tu_type + user.AccountTypeID = at.TRUSTED_USER_AND_DEV_ID assert user.is_trusted_user() is True -def test_user_is_developer(): - dev_type = db.query(AccountType, - AccountType.AccountType == "Developer").first() +def test_user_is_developer(user: User): with db.begin(): - user.AccountType = dev_type + user.AccountTypeID = at.DEVELOPER_ID assert user.is_developer() is True # Do it again with the combined role. - dev_type = db.query( - AccountType, - AccountType.AccountType == "Trusted User & Developer").first() with db.begin(): - user.AccountType = dev_type + user.AccountTypeID = at.TRUSTED_USER_AND_DEV_ID assert user.is_developer() is True -def test_user_voted_for(): +def test_user_voted_for(user: User, package: Package): + pkgbase = package.PackageBase now = int(datetime.utcnow().timestamp()) with db.begin(): - pkgbase = db.create(PackageBase, Name="pkg1", Maintainer=user) - pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) db.create(PackageVote, PackageBase=pkgbase, User=user, VoteTS=now) - assert user.voted_for(pkg) + assert user.voted_for(package) -def test_user_notified(): +def test_user_notified(user: User, package: Package): + pkgbase = package.PackageBase with db.begin(): - pkgbase = db.create(PackageBase, Name="pkg1", Maintainer=user) - pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) db.create(PackageNotification, PackageBase=pkgbase, User=user) - assert user.notified(pkg) + assert user.notified(package) -def test_user_packages(): - with db.begin(): - pkgbase = db.create(PackageBase, Name="pkg1", Maintainer=user) - pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) - assert pkg in user.packages() +def test_user_packages(user: User, package: Package): + assert package in user.packages() From eb396813a89c29bfbb96d6d5f7c884d1c83117bc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 21:27:02 -0800 Subject: [PATCH 1220/1891] housekeep(fastapi): rewrite test_package with fixtures Signed-off-by: Kevin Morris --- test/test_package.py | 54 ++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/test/test_package.py b/test/test_package.py index c2afa660..1408a182 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -4,7 +4,7 @@ from sqlalchemy import and_ from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.user import User @@ -14,28 +14,30 @@ user = pkgbase = package = None @pytest.fixture(autouse=True) def setup(db_test): - global user, pkgbase, package + return - account_type = db.query(AccountType, - AccountType.AccountType == "User").first() +@pytest.fixture +def user() -> User: with db.begin(): user = db.create(User, Username="test", Email="test@example.org", RealName="Test User", Passwd="testPassword", - AccountType=account_type) + AccountTypeID=USER_ID) + yield user - pkgbase = db.create(PackageBase, - Name="beautiful-package", + +@pytest.fixture +def package(user: User) -> Package: + with db.begin(): + pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user) - package = db.create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name, + package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, Description="Test description.", URL="https://test.package") + yield package -def test_package(): - assert pkgbase == package.PackageBase +def test_package(package: Package): assert package.Name == "beautiful-package" assert package.Description == "Test description." assert package.Version == str() # Default version. @@ -46,27 +48,21 @@ def test_package(): package.Version = "1.2.3" # Make sure it got updated in the database. - record = db.query(Package, - and_(Package.ID == package.ID, - Package.Version == "1.2.3")).first() + record = db.query(Package).filter( + and_(Package.ID == package.ID, + Package.Version == "1.2.3") + ).first() assert record is not None -def test_package_null_pkgbase_raises_exception(): +def test_package_null_pkgbase_raises(): with pytest.raises(IntegrityError): - with db.begin(): - db.create(Package, - Name="some-package", - Description="Some description.", - URL="https://some.package") - db.rollback() + Package(Name="some-package", Description="Some description.", + URL="https://some.package") -def test_package_null_name_raises_exception(): +def test_package_null_name_raises(package: Package): + pkgbase = package.PackageBase with pytest.raises(IntegrityError): - with db.begin(): - db.create(Package, - PackageBase=pkgbase, - Description="Some description.", - URL="https://some.package") - db.rollback() + Package(PackageBase=pkgbase, Description="Some description.", + URL="https://some.package") From de0f9190778b160fcb05cf4a6945eb4dd56b1aa1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 22:06:32 -0800 Subject: [PATCH 1221/1891] housekeep(fastapi): rewrite test_ban with fixtures Signed-off-by: Kevin Morris --- test/test_ban.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/test_ban.py b/test/test_ban.py index 2c705410..ff49f7e2 100644 --- a/test/test_ban.py +++ b/test/test_ban.py @@ -11,20 +11,21 @@ from aurweb.db import create from aurweb.models.ban import Ban, is_banned from aurweb.testing.requests import Request -ban = request = None - @pytest.fixture(autouse=True) def setup(db_test): - global ban, request + return + +@pytest.fixture +def ban() -> Ban: ts = datetime.utcnow() + timedelta(seconds=30) with db.begin(): ban = create(Ban, IPAddress="127.0.0.1", BanTS=ts) - request = Request() + yield ban -def test_ban(): +def test_ban(ban: Ban): assert ban.IPAddress == "127.0.0.1" assert bool(ban.BanTS) @@ -45,11 +46,13 @@ def test_invalid_ban(): db.rollback() -def test_banned(): +def test_banned(ban: Ban): + request = Request() request.client.host = "127.0.0.1" assert is_banned(request) -def test_not_banned(): +def test_not_banned(ban: Ban): + request = Request() request.client.host = "192.168.0.1" assert not is_banned(request) From 7ef3e3438681b29d6a32aed54c92f3965737c7af Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 22:43:29 -0800 Subject: [PATCH 1222/1891] housekeep(fastapi): rewrite test_accounts_routes with fixtures Signed-off-by: Kevin Morris --- test/test_accounts_routes.py | 233 ++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 115 deletions(-) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index be929e97..f08efcd2 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -23,16 +23,12 @@ from aurweb.models.user import User from aurweb.testing.html import get_errors from aurweb.testing.requests import Request +logger = logging.get_logger(__name__) + # Some test global constants. TEST_USERNAME = "test" TEST_EMAIL = "test@example.org" -# Global mutables. -client = TestClient(app) -user = None - -logger = logging.get_logger(__name__) - def make_ssh_pubkey(): # Create a public key with ssh-keygen (this adds ssh-keygen as a @@ -50,29 +46,32 @@ def make_ssh_pubkey(): @pytest.fixture(autouse=True) def setup(db_test): - global user + return - account_type = query(AccountType, - AccountType.AccountType == "User").first() +@pytest.fixture +def client() -> TestClient: + yield TestClient(app=app) + + +@pytest.fixture +def user() -> User: with db.begin(): user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, RealName="Test UserZ", Passwd="testPassword", - IRCNick="testZ", AccountType=account_type) + IRCNick="testZ", AccountTypeID=USER_ID) yield user @pytest.fixture -def tu_user(): +def tu_user(user: User): with db.begin(): - user.AccountType = query(AccountType).filter( - AccountType.ID == TRUSTED_USER_AND_DEV_ID - ).first() + user.AccountTypeID = TRUSTED_USER_AND_DEV_ID yield user -def test_get_passreset_authed_redirects(): +def test_get_passreset_authed_redirects(client: TestClient, user: User): sid = user.login(Request(), "testPassword") assert sid is not None @@ -84,39 +83,39 @@ def test_get_passreset_authed_redirects(): assert response.headers.get("location") == "/" -def test_get_passreset(): +def test_get_passreset(client: TestClient): with client as request: response = request.get("/passreset") assert response.status_code == int(HTTPStatus.OK) -def test_get_passreset_translation(): +def test_get_passreset_translation(client: TestClient): # Test that translation works; set it to de. with client as request: response = request.get("/passreset", cookies={"AURLANG": "de"}) # The header title should be translated. - assert "Passwort zurücksetzen".encode("utf-8") in response.content + assert "Passwort zurücksetzen" in response.text # The form input label should be translated. - assert "Benutzername oder primäre E-Mail-Adresse eingeben:".encode( - "utf-8") in response.content + expected = "Benutzername oder primäre E-Mail-Adresse eingeben:" + assert expected in response.text # And the button. - assert "Weiter".encode("utf-8") in response.content + assert "Weiter" in response.text # Restore english. with client as request: response = request.get("/passreset", cookies={"AURLANG": "en"}) -def test_get_passreset_with_resetkey(): +def test_get_passreset_with_resetkey(client: TestClient): with client as request: response = request.get("/passreset", data={"resetkey": "abcd"}) assert response.status_code == int(HTTPStatus.OK) -def test_post_passreset_authed_redirects(): +def test_post_passreset_authed_redirects(client: TestClient, user: User): sid = user.login(Request(), "testPassword") assert sid is not None @@ -130,7 +129,7 @@ def test_post_passreset_authed_redirects(): assert response.headers.get("location") == "/" -def test_post_passreset_user(): +def test_post_passreset_user(client: TestClient, user: User): # With username. with client as request: response = request.post("/passreset", data={"user": TEST_USERNAME}) @@ -144,7 +143,7 @@ def test_post_passreset_user(): assert response.headers.get("location") == "/passreset?step=confirm" -def test_post_passreset_resetkey(): +def test_post_passreset_resetkey(client: TestClient, user: User): with db.begin(): user.session = Session(UsersID=user.ID, SessionID="blah", LastUpdateTS=datetime.utcnow().timestamp()) @@ -171,28 +170,7 @@ def test_post_passreset_resetkey(): assert response.headers.get("location") == "/passreset?step=complete" -def test_post_passreset_error_invalid_email(): - # First, test with a user that doesn't even exist. - with client as request: - response = request.post("/passreset", data={"user": "invalid"}) - assert response.status_code == int(HTTPStatus.NOT_FOUND) - - error = "Invalid e-mail." - assert error in response.content.decode("utf-8") - - # Then, test with an invalid resetkey for a real user. - _ = make_resetkey() - post_data = make_passreset_data("fake") - post_data["password"] = "abcd1234" - post_data["confirm"] = "abcd1234" - - with client as request: - response = request.post("/passreset", data=post_data) - assert response.status_code == int(HTTPStatus.NOT_FOUND) - assert error in response.content.decode("utf-8") - - -def make_resetkey(): +def make_resetkey(client: TestClient, user: User): with client as request: response = request.post("/passreset", data={"user": TEST_USERNAME}) assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -200,18 +178,37 @@ def make_resetkey(): return user.ResetKey -def make_passreset_data(resetkey): +def make_passreset_data(user: User, resetkey: str): return { "user": user.Username, "resetkey": resetkey } -def test_post_passreset_error_missing_field(): +def test_post_passreset_error_invalid_email(client: TestClient, user: User): + # First, test with a user that doesn't even exist. + with client as request: + response = request.post("/passreset", data={"user": "invalid"}) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + assert "Invalid e-mail." in response.text + + # Then, test with an invalid resetkey for a real user. + _ = make_resetkey(client, user) + post_data = make_passreset_data(user, "fake") + post_data["password"] = "abcd1234" + post_data["confirm"] = "abcd1234" + + with client as request: + response = request.post("/passreset", data=post_data) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + assert "Invalid e-mail." in response.text + + +def test_post_passreset_error_missing_field(client: TestClient, user: User): # Now that we've prepared the password reset, prepare a POST # request with the user's ResetKey. - resetkey = make_resetkey() - post_data = make_passreset_data(resetkey) + resetkey = make_resetkey(client, user) + post_data = make_passreset_data(user, resetkey) with client as request: response = request.post("/passreset", data=post_data) @@ -222,9 +219,10 @@ def test_post_passreset_error_missing_field(): assert error in response.content.decode("utf-8") -def test_post_passreset_error_password_mismatch(): - resetkey = make_resetkey() - post_data = make_passreset_data(resetkey) +def test_post_passreset_error_password_mismatch(client: TestClient, + user: User): + resetkey = make_resetkey(client, user) + post_data = make_passreset_data(user, resetkey) post_data["password"] = "abcd1234" post_data["confirm"] = "mismatched" @@ -238,9 +236,10 @@ def test_post_passreset_error_password_mismatch(): assert error in response.content.decode("utf-8") -def test_post_passreset_error_password_requirements(): - resetkey = make_resetkey() - post_data = make_passreset_data(resetkey) +def test_post_passreset_error_password_requirements(client: TestClient, + user: User): + resetkey = make_resetkey(client, user) + post_data = make_passreset_data(user, resetkey) passwd_min_len = User.minimum_passwd_length() assert passwd_min_len >= 4 @@ -257,7 +256,7 @@ def test_post_passreset_error_password_requirements(): assert error in response.content.decode("utf-8") -def test_get_register(): +def test_get_register(client: TestClient): with client as request: response = request.get("/register") assert response.status_code == int(HTTPStatus.OK) @@ -288,7 +287,7 @@ def post_register(request, **kwargs): return request.post("/register", data=data, allow_redirects=False) -def test_post_register(): +def test_post_register(client: TestClient): with client as request: response = post_register(request) assert response.status_code == int(HTTPStatus.OK) @@ -298,7 +297,7 @@ def test_post_register(): assert expected in response.content.decode() -def test_post_register_rejects_case_insensitive_spoof(): +def test_post_register_rejects_case_insensitive_spoof(client: TestClient): with client as request: response = post_register(request, U="newUser", E="newUser@example.org") assert response.status_code == int(HTTPStatus.OK) @@ -319,7 +318,7 @@ def test_post_register_rejects_case_insensitive_spoof(): assert expected in response.content.decode() -def test_post_register_error_expired_captcha(): +def test_post_register_error_expired_captcha(client: TestClient): with client as request: response = post_register(request, captcha_salt="invalid-salt") @@ -329,7 +328,7 @@ def test_post_register_error_expired_captcha(): assert "This CAPTCHA has expired. Please try again." in content -def test_post_register_error_missing_captcha(): +def test_post_register_error_missing_captcha(client: TestClient): with client as request: response = post_register(request, captcha=None) @@ -339,7 +338,7 @@ def test_post_register_error_missing_captcha(): assert "The CAPTCHA is missing." in content -def test_post_register_error_invalid_captcha(): +def test_post_register_error_invalid_captcha(client: TestClient): with client as request: response = post_register(request, captcha="invalid blah blah") @@ -349,7 +348,7 @@ def test_post_register_error_invalid_captcha(): assert "The entered CAPTCHA answer is invalid." in content -def test_post_register_error_ip_banned(): +def test_post_register_error_ip_banned(client: TestClient): # 'testclient' is used as request.client.host via FastAPI TestClient. with db.begin(): create(Ban, IPAddress="testclient", BanTS=datetime.utcnow()) @@ -365,7 +364,7 @@ def test_post_register_error_ip_banned(): "inconvenience.") in content -def test_post_register_error_missing_username(): +def test_post_register_error_missing_username(client: TestClient): with client as request: response = post_register(request, U="") @@ -375,7 +374,7 @@ def test_post_register_error_missing_username(): assert "Missing a required field." in content -def test_post_register_error_missing_email(): +def test_post_register_error_missing_email(client: TestClient): with client as request: response = post_register(request, E="") @@ -385,7 +384,7 @@ def test_post_register_error_missing_email(): assert "Missing a required field." in content -def test_post_register_error_invalid_username(): +def test_post_register_error_invalid_username(client: TestClient): with client as request: # Our test config requires at least three characters for a # valid username, so test against two characters: 'ba'. @@ -397,7 +396,7 @@ def test_post_register_error_invalid_username(): assert "The username is invalid." in content -def test_post_register_invalid_password(): +def test_post_register_invalid_password(client: TestClient): with client as request: response = post_register(request, P="abc", C="abc") @@ -408,7 +407,7 @@ def test_post_register_invalid_password(): assert re.search(expected, content) -def test_post_register_error_missing_confirm(): +def test_post_register_error_missing_confirm(client: TestClient): with client as request: response = post_register(request, C=None) @@ -418,7 +417,7 @@ def test_post_register_error_missing_confirm(): assert "Please confirm your new password." in content -def test_post_register_error_mismatched_confirm(): +def test_post_register_error_mismatched_confirm(client: TestClient): with client as request: response = post_register(request, C="mismatched") @@ -428,7 +427,7 @@ def test_post_register_error_mismatched_confirm(): assert "Password fields do not match." in content -def test_post_register_error_invalid_email(): +def test_post_register_error_invalid_email(client: TestClient): with client as request: response = post_register(request, E="bad@email") @@ -438,7 +437,7 @@ def test_post_register_error_invalid_email(): assert "The email address is invalid." in content -def test_post_register_error_undeliverable_email(): +def test_post_register_error_undeliverable_email(client: TestClient): with client as request: # At the time of writing, webchat.freenode.net does not contain # mx records; if it ever does, it'll break this test. @@ -450,7 +449,7 @@ def test_post_register_error_undeliverable_email(): assert "The email address is invalid." in content -def test_post_register_invalid_backup_email(): +def test_post_register_invalid_backup_email(client: TestClient): with client as request: response = post_register(request, BE="bad@email") @@ -460,7 +459,7 @@ def test_post_register_invalid_backup_email(): assert "The backup email address is invalid." in content -def test_post_register_error_invalid_homepage(): +def test_post_register_error_invalid_homepage(client: TestClient): with client as request: response = post_register(request, HP="bad") @@ -471,7 +470,7 @@ def test_post_register_error_invalid_homepage(): assert expected in content -def test_post_register_error_invalid_pgp_fingerprints(): +def test_post_register_error_invalid_pgp_fingerprints(client: TestClient): with client as request: response = post_register(request, K="bad") @@ -492,7 +491,7 @@ def test_post_register_error_invalid_pgp_fingerprints(): assert expected in content -def test_post_register_error_invalid_ssh_pubkeys(): +def test_post_register_error_invalid_ssh_pubkeys(client: TestClient): with client as request: response = post_register(request, PK="bad") @@ -510,7 +509,7 @@ def test_post_register_error_invalid_ssh_pubkeys(): assert "The SSH public key is invalid." in content -def test_post_register_error_unsupported_language(): +def test_post_register_error_unsupported_language(client: TestClient): with client as request: response = post_register(request, L="bad") @@ -521,7 +520,7 @@ def test_post_register_error_unsupported_language(): assert expected in content -def test_post_register_error_unsupported_timezone(): +def test_post_register_error_unsupported_timezone(client: TestClient): with client as request: response = post_register(request, TZ="ABCDEFGH") @@ -532,7 +531,7 @@ def test_post_register_error_unsupported_timezone(): assert expected in content -def test_post_register_error_username_taken(): +def test_post_register_error_username_taken(client: TestClient, user: User): with client as request: response = post_register(request, U="test") @@ -543,7 +542,7 @@ def test_post_register_error_username_taken(): assert re.search(expected, content) -def test_post_register_error_email_taken(): +def test_post_register_error_email_taken(client: TestClient, user: User): with client as request: response = post_register(request, E="test@example.org") @@ -554,7 +553,7 @@ def test_post_register_error_email_taken(): assert re.search(expected, content) -def test_post_register_error_ssh_pubkey_taken(): +def test_post_register_error_ssh_pubkey_taken(client: TestClient, user: User): pk = str() # Create a public key with ssh-keygen (this adds ssh-keygen as a @@ -584,7 +583,7 @@ def test_post_register_error_ssh_pubkey_taken(): assert re.search(expected, content) -def test_post_register_with_ssh_pubkey(): +def test_post_register_with_ssh_pubkey(client: TestClient): pk = str() # Create a public key with ssh-keygen (this adds ssh-keygen as a @@ -605,7 +604,7 @@ def test_post_register_with_ssh_pubkey(): assert response.status_code == int(HTTPStatus.OK) -def test_get_account_edit(): +def test_get_account_edit(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -617,7 +616,7 @@ def test_get_account_edit(): assert response.status_code == int(HTTPStatus.OK) -def test_get_account_edit_unauthorized(): +def test_get_account_edit_unauthorized(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -633,7 +632,7 @@ def test_get_account_edit_unauthorized(): assert response.status_code == int(HTTPStatus.UNAUTHORIZED) -def test_post_account_edit(): +def test_post_account_edit(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -655,7 +654,7 @@ def test_post_account_edit(): assert expected in response.content.decode() -def test_post_account_edit_dev(): +def test_post_account_edit_dev(client: TestClient, user: User): # Modify our user to be a "Trusted User & Developer" name = "Trusted User & Developer" tu_or_dev = query(AccountType, AccountType.AccountType == name).first() @@ -683,7 +682,7 @@ def test_post_account_edit_dev(): assert expected in response.content.decode() -def test_post_account_edit_language(): +def test_post_account_edit_language(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -710,7 +709,7 @@ def test_post_account_edit_language(): assert lang_nodes[0] == "selected" -def test_post_account_edit_timezone(): +def test_post_account_edit_timezone(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -729,7 +728,8 @@ def test_post_account_edit_timezone(): assert response.status_code == int(HTTPStatus.OK) -def test_post_account_edit_error_missing_password(): +def test_post_account_edit_error_missing_password(client: TestClient, + user: User): request = Request() sid = user.login(request, "testPassword") @@ -751,7 +751,8 @@ def test_post_account_edit_error_missing_password(): assert "Invalid password." in content -def test_post_account_edit_error_invalid_password(): +def test_post_account_edit_error_invalid_password(client: TestClient, + user: User): request = Request() sid = user.login(request, "testPassword") @@ -773,7 +774,8 @@ def test_post_account_edit_error_invalid_password(): assert "Invalid password." in content -def test_post_account_edit_inactivity_unauthorized(): +def test_post_account_edit_inactivity_unauthorized(client: TestClient, + user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} post_data = { "U": "test", @@ -791,7 +793,7 @@ def test_post_account_edit_inactivity_unauthorized(): assert errors[0].text.strip() == expected -def test_post_account_edit_inactivity(): +def test_post_account_edit_inactivity(client: TestClient, user: User): with db.begin(): user.AccountTypeID = TRUSTED_USER_ID assert not user.Suspended @@ -822,7 +824,7 @@ def test_post_account_edit_inactivity(): assert user.InactivityTS == 0 -def test_post_account_edit_error_unauthorized(): +def test_post_account_edit_error_unauthorized(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -845,7 +847,7 @@ def test_post_account_edit_error_unauthorized(): assert response.status_code == int(HTTPStatus.UNAUTHORIZED) -def test_post_account_edit_ssh_pub_key(): +def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -874,7 +876,7 @@ def test_post_account_edit_ssh_pub_key(): assert response.status_code == int(HTTPStatus.OK) -def test_post_account_edit_missing_ssh_pubkey(): +def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -907,7 +909,7 @@ def test_post_account_edit_missing_ssh_pubkey(): assert response.status_code == int(HTTPStatus.OK) -def test_post_account_edit_invalid_ssh_pubkey(): +def test_post_account_edit_invalid_ssh_pubkey(client: TestClient, user: User): pubkey = "ssh-rsa fake key" request = Request() @@ -930,7 +932,7 @@ def test_post_account_edit_invalid_ssh_pubkey(): assert response.status_code == int(HTTPStatus.BAD_REQUEST) -def test_post_account_edit_password(): +def test_post_account_edit_password(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -952,7 +954,7 @@ def test_post_account_edit_password(): assert user.valid_password("newPassword") -def test_post_account_edit_account_types(): +def test_post_account_edit_account_types(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") cookies = {"AURSID": sid} @@ -1066,7 +1068,7 @@ def test_post_account_edit_account_types(): assert user.AccountTypeID == DEVELOPER_ID -def test_get_account(): +def test_get_account(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -1077,7 +1079,7 @@ def test_get_account(): assert response.status_code == int(HTTPStatus.OK) -def test_get_account_not_found(): +def test_get_account_not_found(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -1088,7 +1090,7 @@ def test_get_account_not_found(): assert response.status_code == int(HTTPStatus.NOT_FOUND) -def test_get_account_unauthenticated(): +def test_get_account_unauthenticated(client: TestClient, user: User): with client as request: response = request.get("/account/test", allow_redirects=False) assert response.status_code == int(HTTPStatus.UNAUTHORIZED) @@ -1097,7 +1099,7 @@ def test_get_account_unauthenticated(): assert "You must log in to view user information." in content -def test_get_accounts(tu_user): +def test_get_accounts(client: TestClient, user: User, tu_user: User): """ Test that we can GET request /accounts and receive a form which can be used to POST /accounts. """ sid = user.login(Request(), "testPassword") @@ -1156,7 +1158,7 @@ def get_rows(html): return root.xpath('//table[contains(@class, "users")]/tbody/tr') -def test_post_accounts(tu_user): +def test_post_accounts(client: TestClient, user: User, tu_user: User): # Set a PGPKey. with db.begin(): user.PGPKey = "5F18B20346188419750745D7335F2CB41F253D30" @@ -1211,7 +1213,7 @@ def test_post_accounts(tu_user): % (_user.ID, _user.Username)) -def test_post_accounts_username(tu_user): +def test_post_accounts_username(client: TestClient, user: User, tu_user: User): # Test the U parameter path. sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1231,7 +1233,8 @@ def test_post_accounts_username(tu_user): assert username.text.strip() == user.Username -def test_post_accounts_account_type(tu_user): +def test_post_accounts_account_type(client: TestClient, user: User, + tu_user: User): # Check the different account type options. sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1324,7 +1327,7 @@ def test_post_accounts_account_type(tu_user): assert type.text.strip() == "Trusted User & Developer" -def test_post_accounts_status(tu_user): +def test_post_accounts_status(client: TestClient, user: User, tu_user: User): # Test the functionality of Suspended. sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1356,7 +1359,7 @@ def test_post_accounts_status(tu_user): assert status.text.strip() == "Suspended" -def test_post_accounts_email(tu_user): +def test_post_accounts_email(client: TestClient, user: User, tu_user: User): sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1370,7 +1373,7 @@ def test_post_accounts_email(tu_user): assert len(rows) == 1 -def test_post_accounts_realname(tu_user): +def test_post_accounts_realname(client: TestClient, user: User, tu_user: User): # Test the R parameter path. sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1384,7 +1387,7 @@ def test_post_accounts_realname(tu_user): assert len(rows) == 1 -def test_post_accounts_irc(tu_user): +def test_post_accounts_irc(client: TestClient, user: User, tu_user: User): # Test the I parameter path. sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1398,7 +1401,7 @@ def test_post_accounts_irc(tu_user): assert len(rows) == 1 -def test_post_accounts_sortby(tu_user): +def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): # Create a second user so we can compare sorts. account_type = query(AccountType, AccountType.ID == DEVELOPER_ID).first() @@ -1481,7 +1484,7 @@ def test_post_accounts_sortby(tu_user): assert compare_text_values(1, first_rows, reversed(rows)) -def test_post_accounts_pgp_key(tu_user): +def test_post_accounts_pgp_key(client: TestClient, user: User, tu_user: User): with db.begin(): user.PGPKey = "5F18B20346188419750745D7335F2CB41F253D30" @@ -1498,7 +1501,7 @@ def test_post_accounts_pgp_key(tu_user): assert len(rows) == 1 -def test_post_accounts_paged(tu_user): +def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): # Create 150 users. users = [user] account_type = query(AccountType, @@ -1572,7 +1575,7 @@ def test_post_accounts_paged(tu_user): assert page_next.attrib["disabled"] == "disabled" -def test_get_terms_of_service(): +def test_get_terms_of_service(client: TestClient, user: User): with db.begin(): term = create(Term, Description="Test term.", URL="http://localhost", Revision=1) @@ -1624,7 +1627,7 @@ def test_get_terms_of_service(): assert response.status_code == int(HTTPStatus.SEE_OTHER) -def test_post_terms_of_service(): +def test_post_terms_of_service(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -1682,7 +1685,7 @@ def test_post_terms_of_service(): assert response.headers.get("location") == "/" -def test_account_comments_not_found(): +def test_account_comments_not_found(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: resp = request.get("/account/non-existent/comments", cookies=cookies) From fccd8b63d271785e741cae0ec453b349ee0d6d38 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 23:07:34 -0800 Subject: [PATCH 1223/1891] housekeep(fastapi): rewrite test_auth_routes with fixtures Signed-off-by: Kevin Morris --- test/test_auth_routes.py | 95 ++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 0157fcc8..a8d0db11 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -8,11 +8,12 @@ from fastapi.testclient import TestClient import aurweb.config +from aurweb import db from aurweb.asgi import app -from aurweb.db import begin, create, query -from aurweb.models.account_type import AccountType +from aurweb.models.account_type import USER_ID from aurweb.models.session import Session from aurweb.models.user import User +from aurweb.testing.requests import Request # Some test global constants. TEST_USERNAME = "test" @@ -21,30 +22,32 @@ TEST_REFERER = { "referer": aurweb.config.get("options", "aur_location") + "/login", } -# Global mutables. -user = client = None - @pytest.fixture(autouse=True) def setup(db_test): - global user, client + return - account_type = query(AccountType, - AccountType.AccountType == "User").first() - with begin(): - user = create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, - RealName="Test User", Passwd="testPassword", - AccountType=account_type) - - client = TestClient(app) +@pytest.fixture +def client() -> TestClient: + client = TestClient(app=app) # Necessary for forged login CSRF protection on the login route. Set here # instead of only on the necessary requests for convenience. client.headers.update(TEST_REFERER) + yield client -def test_login_logout(): +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, + RealName="Test User", Passwd="testPassword", + AccountTypeID=USER_ID) + yield user + + +def test_login_logout(client: TestClient, user: User): post_data = { "user": "test", "passwd": "testPassword", @@ -83,7 +86,7 @@ def mock_getboolean(a, b): @mock.patch("aurweb.config.getboolean", side_effect=mock_getboolean) -def test_secure_login(mock): +def test_secure_login(getboolean: bool, client: TestClient, user: User): """ In this test, we check to verify the course of action taken by starlette when providing secure=True to a response cookie. This is achieved by mocking aurweb.config.getboolean to return @@ -94,11 +97,11 @@ def test_secure_login(mock): on such a request. """ # Create a local TestClient here since we mocked configuration. - client = TestClient(app) + # client = TestClient(app) # Necessary for forged login CSRF protection on the login route. Set here # instead of only on the necessary requests for convenience. - client.headers.update(TEST_REFERER) + # client.headers.update(TEST_REFERER) # Data used for our upcoming http post request. post_data = { @@ -126,18 +129,19 @@ def test_secure_login(mock): # Let's make sure we actually have a session relationship # with the AURSID we ended up with. - record = query(Session, Session.SessionID == cookie.value).first() + record = db.query(Session, Session.SessionID == cookie.value).first() assert record is not None and record.User == user assert user.session == record -def test_authenticated_login(): +def test_authenticated_login(client: TestClient, user: User): post_data = { "user": "test", "passwd": "testPassword", "next": "/" } + cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: # Try to login. response = request.post("/login", data=post_data, @@ -149,12 +153,13 @@ def test_authenticated_login(): # when requesting GET /login as an authenticated user. # Now, let's verify that we receive 403 Forbidden when we # try to get /login as an authenticated user. - response = request.get("/login", allow_redirects=False) + response = request.get("/login", cookies=cookies, + allow_redirects=False) assert response.status_code == int(HTTPStatus.OK) assert "Logged-in as: test" in response.text -def test_unauthenticated_logout_unauthorized(): +def test_unauthenticated_logout_unauthorized(client: TestClient): with client as request: # Alright, let's verify that attempting to /logout when not # authenticated returns 401 Unauthorized. @@ -163,7 +168,7 @@ def test_unauthenticated_logout_unauthorized(): assert response.headers.get("location").startswith("/login") -def test_login_missing_username(): +def test_login_missing_username(client: TestClient): post_data = { "passwd": "testPassword", "next": "/" @@ -179,7 +184,7 @@ def test_login_missing_username(): assert "checked" not in content -def test_login_remember_me(): +def test_login_remember_me(client: TestClient, user: User): post_data = { "user": "test", "passwd": "testPassword", @@ -197,16 +202,15 @@ def test_login_remember_me(): "options", "persistent_cookie_timeout") expected_ts = datetime.utcnow().timestamp() + cookie_timeout - _session = query(Session, - Session.UsersID == user.ID).first() + session = db.query(Session).filter(Session.UsersID == user.ID).first() # Expect that LastUpdateTS was within 5 seconds of the expected_ts, # which is equal to the current timestamp + persistent_cookie_timeout. - assert _session.LastUpdateTS > expected_ts - 5 - assert _session.LastUpdateTS < expected_ts + 5 + assert session.LastUpdateTS > expected_ts - 5 + assert session.LastUpdateTS < expected_ts + 5 -def test_login_incorrect_password_remember_me(): +def test_login_incorrect_password_remember_me(client: TestClient, user: User): post_data = { "user": "test", "passwd": "badPassword", @@ -218,15 +222,14 @@ def test_login_incorrect_password_remember_me(): response = request.post("/login", data=post_data) assert "AURSID" not in response.cookies - # Make sure username is prefilled, password isn't prefilled, and remember_me - # is checked. - content = response.content.decode() - assert post_data["user"] in content - assert post_data["passwd"] not in content - assert "checked" in content + # Make sure username is prefilled, password isn't prefilled, + # and remember_me is checked. + assert post_data["user"] in response.text + assert post_data["passwd"] not in response.text + assert "checked" in response.text -def test_login_missing_password(): +def test_login_missing_password(client: TestClient): post_data = { "user": "test", "next": "/" @@ -237,12 +240,11 @@ def test_login_missing_password(): assert "AURSID" not in response.cookies # Make sure username is prefilled and remember_me isn't checked. - content = response.content.decode() - assert post_data["user"] in content - assert "checked" not in content + assert post_data["user"] in response.text + assert "checked" not in response.text -def test_login_incorrect_password(): +def test_login_incorrect_password(client: TestClient): post_data = { "user": "test", "passwd": "badPassword", @@ -253,15 +255,14 @@ def test_login_incorrect_password(): response = request.post("/login", data=post_data) assert "AURSID" not in response.cookies - # Make sure username is prefilled, password isn't prefilled and remember_me - # isn't checked. - content = response.content.decode() - assert post_data["user"] in content - assert post_data["passwd"] not in content - assert "checked" not in content + # Make sure username is prefilled, password isn't prefilled + # and remember_me isn't checked. + assert post_data["user"] in response.text + assert post_data["passwd"] not in response.text + assert "checked" not in response.text -def test_login_bad_referer(): +def test_login_bad_referer(client: TestClient): post_data = { "user": "test", "passwd": "testPassword", From 043ac7fe9211b96222274fcab6797df8a48d55b1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 30 Nov 2021 23:24:42 -0800 Subject: [PATCH 1224/1891] fix(test_aurblup): use correct type hint for tmpdir Signed-off-by: Kevin Morris --- test/test_aurblup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test_aurblup.py b/test/test_aurblup.py index 7eaae556..0b499d57 100644 --- a/test/test_aurblup.py +++ b/test/test_aurblup.py @@ -2,6 +2,7 @@ import tempfile from unittest import mock +import py import pytest from aurweb import config, db @@ -17,12 +18,12 @@ def tempdir() -> str: @pytest.fixture -def alpm_db(tempdir: str) -> AlpmDatabase: +def alpm_db(tempdir: py.path.local) -> AlpmDatabase: yield AlpmDatabase(tempdir) @pytest.fixture(autouse=True) -def setup(db_test, alpm_db: AlpmDatabase, tempdir: str) -> None: +def setup(db_test, alpm_db: AlpmDatabase, tempdir: py.path.local) -> None: config_get = config.get def mock_config_get(section: str, key: str) -> str: From 112837e0e99c3d6c84660ece76240d959760dcdf Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 1 Dec 2021 11:53:43 -0800 Subject: [PATCH 1225/1891] fix(test_auth): cover mismatched referer situation Signed-off-by: Kevin Morris --- aurweb/testing/requests.py | 12 ++++++++++-- test/test_auth.py | 22 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py index a8c077db..76f7afca 100644 --- a/aurweb/testing/requests.py +++ b/aurweb/testing/requests.py @@ -1,3 +1,5 @@ +from typing import Dict + import aurweb.config @@ -27,7 +29,13 @@ class URL: class Request: """ A fake Request object which mimics a FastAPI Request for tests. """ client = Client() - cookies = dict() - headers = dict() user = User() url = URL() + + def __init__(self, + method: str = "GET", + headers: Dict[str, str] = dict(), + cookies: Dict[str, str] = dict()) -> "Request": + self.method = method.upper() + self.headers = headers + self.cookies = cookies diff --git a/test/test_auth.py b/test/test_auth.py index b63fb96f..b607a038 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -1,11 +1,13 @@ from datetime import datetime +import fastapi import pytest +from fastapi import HTTPException from sqlalchemy.exc import IntegrityError from aurweb import db -from aurweb.auth import AnonymousUser, BasicAuthBackend, account_type_required +from aurweb.auth import AnonymousUser, BasicAuthBackend, account_type_required, auth_required from aurweb.models.account_type import USER, USER_ID from aurweb.models.session import Session from aurweb.models.user import User @@ -74,6 +76,24 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend): assert result == user +@pytest.mark.asyncio +async def test_auth_required_redirection_bad_referrer(): + # Create a fake route function which can be wrapped by auth_required. + def bad_referrer_route(request: fastapi.Request): + pass + + # Get down to the nitty gritty internal wrapper. + bad_referrer_route = auth_required()(bad_referrer_route) + + # Execute the route with a "./blahblahblah" Referer, which does not + # match aur_location; `./` has been used as a prefix to attempt to + # ensure we're providing a fake referer. + with pytest.raises(HTTPException) as exc: + request = Request(method="POST", headers={"Referer": "./blahblahblah"}) + await bad_referrer_route(request) + assert exc.detail == "Bad Referer header." + + def test_account_type_required(): """ This test merely asserts that a few different paths do not raise exceptions. """ From c09784d58f600a249f321e6d2a80f9073cd12d49 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 1 Dec 2021 11:56:44 -0800 Subject: [PATCH 1226/1891] fix(auth.auth_required): remove unused keyword arguments Signed-off-by: Kevin Morris --- aurweb/auth/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 8ceb136c..18356ac2 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -120,9 +120,7 @@ class BasicAuthBackend(AuthenticationBackend): return (AuthCredentials(["authenticated"]), user) -def auth_required(is_required: bool = True, - template: tuple = None, - status_code: HTTPStatus = HTTPStatus.UNAUTHORIZED): +def auth_required(is_required: bool = True): """ Authentication route decorator. :param is_required: A boolean indicating whether the function requires auth From 0435c56a41c8e9cf3c286ffbbf4ae21ad33bd6e6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 1 Dec 2021 12:27:14 -0800 Subject: [PATCH 1227/1891] update test/README.md to be more aligned with the current state Signed-off-by: Kevin Morris --- test/README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test/README.md b/test/README.md index 13fb0a0c..0d86a879 100644 --- a/test/README.md +++ b/test/README.md @@ -117,13 +117,12 @@ To run `sharness` shell test suites (requires Arch Linux): To run `pytest` Python test suites: - $ make -C test pytest + $ pytest **Note:** For SQLite tests, users may want to use `eatmydata` to improve speed: $ eatmydata -- make -C test sh - $ eatmydata -- make -C test pytest To produce coverage reports related to Python when running tests manually, use the following method: @@ -147,11 +146,9 @@ Almost all of our `pytest` suites use the database in some way. There are a few particular testing utilities in `aurweb` that one should keep aware of to aid testing code: -- `aurweb.testing.setup_init_db(*tables)` - - Prepares test database tables to be cleared before a test - is run. Be careful not to specify any tables we depend on - for constant records, like `AccountTypes`, `DependencyTypes`, - `RelationTypes` and `RequestTypes`. +- `db_test` pytest fixture + - Prepares test databases for the module and cleans out database + tables for each test function requiring this fixture. - `aurweb.testing.requests.Request` - A fake stripped down version of `fastapi.Request` that can be passed to any functions in our codebase which use @@ -168,14 +165,16 @@ Example code: @pytest.fixture(autouse=True) - def setup(): - setup_test_db(User.__tablename__) + def setup(db_test): + return @pytest.fixture def user(): - yield db.create(User, Passwd="testPassword", ...) + with db.begin(): + user = db.create(User, Passwd="testPassword", ...) + yield user - def test_user_login(user): + def test_user_login(user: User): assert isinstance(user, User) is True fake_request = Request() From 42701514e75ac373c01d787508e092b7ed0d144d Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Wed, 1 Dec 2021 02:16:08 -0500 Subject: [PATCH 1228/1891] fix(FastAPI): Use HTTPStatus instead of raw number Signed-off-by: Steven Guikal --- aurweb/routers/errors.py | 8 ++++++-- aurweb/routers/html.py | 2 +- aurweb/routers/sso.py | 11 +++++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/aurweb/routers/errors.py b/aurweb/routers/errors.py index eb935b57..9ed1e80d 100644 --- a/aurweb/routers/errors.py +++ b/aurweb/routers/errors.py @@ -1,14 +1,18 @@ +from http import HTTPStatus + from aurweb.templates import make_context, render_template async def not_found(request, exc): context = make_context(request, "Page Not Found") - return render_template(request, "errors/404.html", context, 404) + return render_template(request, "errors/404.html", context, + HTTPStatus.NOT_FOUND) async def service_unavailable(request, exc): context = make_context(request, "Service Unavailable") - return render_template(request, "errors/503.html", context, 503) + return render_template(request, "errors/503.html", context, + HTTPStatus.SERVICE_UNAVAILABLE) # Maps HTTP errors to functions exceptions = { diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 525fb626..337acce6 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -221,4 +221,4 @@ async def metrics(request: Request): @router.get("/raisefivethree", response_class=HTMLResponse) async def raise_service_unavailable(request: Request): - raise HTTPException(status_code=503) + raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE) diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index edeb7c6b..eff1c63f 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -1,6 +1,7 @@ import time import uuid +from http import HTTPStatus from urllib.parse import urlencode import fastapi @@ -59,7 +60,8 @@ def open_session(request, conn, user_id): """ if is_account_suspended(conn, user_id): _ = get_translator_for_request(request) - raise HTTPException(status_code=403, detail=_('Account suspended')) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, + detail=_('Account suspended')) # TODO This is a terrible message because it could imply the attempt at # logging in just caused the suspension. @@ -104,7 +106,7 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw if is_ip_banned(conn, request.client.host): _ = get_translator_for_request(request) raise HTTPException( - status_code=403, + status_code=HTTPStatus.FORBIDDEN, detail=_('The login form is currently disabled for your IP address, ' 'probably due to sustained spam attacks. Sorry for the ' 'inconvenience.')) @@ -117,13 +119,14 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw # Let’s give attackers as little information as possible. _ = get_translator_for_request(request) raise HTTPException( - status_code=400, + status_code=HTTPStatus.BAD_REQUEST, detail=_('Bad OAuth token. Please retry logging in from the start.')) sub = user.get("sub") # this is the SSO account ID in JWT terminology if not sub: _ = get_translator_for_request(request) - raise HTTPException(status_code=400, detail=_("JWT is missing its `sub` field.")) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, + detail=_("JWT is missing its `sub` field.")) aur_accounts = conn.execute(select([Users.c.ID]).where(Users.c.SSOAccountID == sub)) \ .fetchall() From e1bf6dd56256eddfbed2909fd658406755ce06f2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 2 Dec 2021 17:09:37 -0800 Subject: [PATCH 1229/1891] fix(fastapi): restore stripped whitespace in archdev-navbar Signed-off-by: Kevin Morris --- templates/partials/archdev-navbar.html | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/templates/partials/archdev-navbar.html b/templates/partials/archdev-navbar.html index dc2377fe..98bb1841 100644 --- a/templates/partials/archdev-navbar.html +++ b/templates/partials/archdev-navbar.html @@ -54,17 +54,10 @@

  • {% else %} {# All guest users see Register #} -
  • - - {% trans %}Register{% endtrans %} - -
  • +
  • {% trans %}Register{% endtrans %}
  • + {# All guest users see Login #} -
  • - - {% trans %}Login{% endtrans %} - -
  • +
  • {% trans %}Login{% endtrans %}
  • {% endif %} From abfd41f31e76a11619f6aa233058aa0bb25c2dec Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 2 Dec 2021 23:22:31 -0800 Subject: [PATCH 1230/1891] change(fastapi): centralize HTTPException Signed-off-by: Kevin Morris --- aurweb/asgi.py | 24 +++++++++++++----------- aurweb/routers/errors.py | 21 --------------------- templates/errors/404.html | 8 -------- templates/errors/503.html | 8 -------- templates/errors/detail.html | 8 ++++++++ test/test_asgi.py | 10 +++++++--- 6 files changed, 28 insertions(+), 51 deletions(-) delete mode 100644 aurweb/routers/errors.py delete mode 100644 templates/errors/404.html delete mode 100644 templates/errors/503.html create mode 100644 templates/errors/detail.html diff --git a/aurweb/asgi.py b/aurweb/asgi.py index b399cfb1..ef8d5933 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -6,8 +6,8 @@ import typing from urllib.parse import quote_plus -from fastapi import FastAPI, HTTPException, Request -from fastapi.responses import HTMLResponse, RedirectResponse +from fastapi import FastAPI, HTTPException, Request, Response +from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from prometheus_client import multiprocess from sqlalchemy import and_, or_ @@ -21,10 +21,11 @@ from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine, query from aurweb.models import AcceptedTerm, Term from aurweb.prometheus import http_api_requests_total, http_requests_total, instrumentator -from aurweb.routers import accounts, auth, errors, html, packages, rpc, rss, sso, trusted_user +from aurweb.routers import accounts, auth, html, packages, rpc, rss, sso, trusted_user +from aurweb.templates import make_context, render_template # Setup the FastAPI app. -app = FastAPI(exception_handlers=errors.exceptions) +app = FastAPI() # Instrument routes with the prometheus-fastapi-instrumentator # library with custom collectors and expose /metrics. @@ -93,14 +94,15 @@ def child_exit(server, worker): # pragma: no cover @app.exception_handler(HTTPException) -async def http_exception_handler(request, exc): - """ - Dirty HTML error page to replace the default JSON error responses. - In the future this should use a proper Arch-themed HTML template. - """ +async def http_exception_handler(request: Request, exc: HTTPException) \ + -> Response: + """ Handle an HTTPException thrown in a route. """ phrase = http.HTTPStatus(exc.status_code).phrase - return HTMLResponse(f"

    {exc.status_code} {phrase}

    {exc.detail}

    ", - status_code=exc.status_code) + context = make_context(request, phrase) + context["exc"] = exc + context["phrase"] = phrase + return render_template(request, "errors/detail.html", context, + exc.status_code) @app.middleware("http") diff --git a/aurweb/routers/errors.py b/aurweb/routers/errors.py deleted file mode 100644 index 9ed1e80d..00000000 --- a/aurweb/routers/errors.py +++ /dev/null @@ -1,21 +0,0 @@ -from http import HTTPStatus - -from aurweb.templates import make_context, render_template - - -async def not_found(request, exc): - context = make_context(request, "Page Not Found") - return render_template(request, "errors/404.html", context, - HTTPStatus.NOT_FOUND) - - -async def service_unavailable(request, exc): - context = make_context(request, "Service Unavailable") - return render_template(request, "errors/503.html", context, - HTTPStatus.SERVICE_UNAVAILABLE) - -# Maps HTTP errors to functions -exceptions = { - 404: not_found, - 503: service_unavailable -} diff --git a/templates/errors/404.html b/templates/errors/404.html deleted file mode 100644 index 4926aff6..00000000 --- a/templates/errors/404.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends 'partials/layout.html' %} - -{% block pageContent %} -
    -

    404 - {% trans %}Page Not Found{% endtrans %}

    -

    {% trans %}Sorry, the page you've requested does not exist.{% endtrans %}

    -
    -{% endblock %} diff --git a/templates/errors/503.html b/templates/errors/503.html deleted file mode 100644 index 9a0ed56a..00000000 --- a/templates/errors/503.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends 'partials/layout.html' %} - -{% block pageContent %} -
    -

    503 - {% trans %}Service Unavailable{% endtrans %}

    -

    {% trans %}Don't panic! This site is down due to maintenance. We will be back soon.{% endtrans %}

    -
    -{% endblock %} diff --git a/templates/errors/detail.html b/templates/errors/detail.html new file mode 100644 index 00000000..f382a9bb --- /dev/null +++ b/templates/errors/detail.html @@ -0,0 +1,8 @@ +{% extends 'partials/layout.html' %} + +{% block pageContent %} +
    +

    {{ "%d" | format(exc.status_code) }} - {{ phrase }}

    +

    {{ exc.detail }}

    +
    +{% endblock %} diff --git a/test/test_asgi.py b/test/test_asgi.py index fa2df5a1..16b07c31 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -11,6 +11,8 @@ import aurweb.asgi import aurweb.config import aurweb.redis +from aurweb.testing.requests import Request + @pytest.mark.asyncio async def test_asgi_startup_session_secret_exception(monkeypatch): @@ -42,9 +44,11 @@ async def test_asgi_startup_exception(monkeypatch): async def test_asgi_http_exception_handler(): exc = HTTPException(status_code=422, detail="EXCEPTION!") phrase = http.HTTPStatus(exc.status_code).phrase - response = await aurweb.asgi.http_exception_handler(None, exc) - assert response.body.decode() == \ - f"

    {exc.status_code} {phrase}

    {exc.detail}

    " + response = await aurweb.asgi.http_exception_handler(Request(), exc) + assert response.status_code == 422 + content = response.body.decode() + assert f"{exc.status_code} - {phrase}" in content + assert "EXCEPTION!" in content @pytest.mark.asyncio From 806a19b91a3f2e254e1956243a2fff89b123ff4f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 2 Dec 2021 23:26:42 -0800 Subject: [PATCH 1231/1891] feat(fastapi): render a 500 html response when unique SID generation fails We've seen a bug in the past where unique SID generation fails and still ends up raising an exception. This commit reworks how we deal with database exceptions internally, tries for 36 iterations to set a fresh unique SID, and raises a 500 HTTPException if we were unable to. Signed-off-by: Kevin Morris --- aurweb/models/user.py | 67 ++++++++++++++++++++++++---------------- test/test_auth_routes.py | 45 +++++++++++++++++++++++++++ test/test_user.py | 2 -- 3 files changed, 85 insertions(+), 29 deletions(-) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index f0724202..dcf5f519 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -1,12 +1,14 @@ import hashlib from datetime import datetime +from http import HTTPStatus from typing import List, Set import bcrypt -from fastapi import Request +from fastapi import HTTPException, Request from sqlalchemy import or_ +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship import aurweb.config @@ -108,33 +110,45 @@ class User(Base): if not self.authenticated: return None - now_ts = datetime.utcnow().timestamp() - session_ts = now_ts + ( - session_time if session_time - else aurweb.config.getint("options", "login_timeout") - ) + # Maximum number of iterations where we attempt to generate + # a unique SID. In cases where the Session table has + # exhausted all possible values, this will catch exceptions + # instead of raising them and include details about failing + # generation in an HTTPException. + tries = 36 - sid = None + exc = None + for i in range(tries): + exc = None + now_ts = datetime.utcnow().timestamp() + session_ts = now_ts + ( + session_time if session_time + else aurweb.config.getint("options", "login_timeout") + ) + try: + with db.begin(): + self.LastLogin = now_ts + self.LastLoginIPAddress = request.client.host + if not self.session: + sid = generate_unique_sid() + self.session = db.create(Session, User=self, + SessionID=sid, + LastUpdateTS=session_ts) + else: + last_updated = self.session.LastUpdateTS + if last_updated and last_updated < now_ts: + self.session.SessionID = generate_unique_sid() + self.session.LastUpdateTS = session_ts + break + except IntegrityError as exc_: + exc = exc_ - with db.begin(): - self.LastLogin = now_ts - self.LastLoginIPAddress = request.client.host - if not self.session: - sid = generate_unique_sid() - self.session = Session(UsersID=self.ID, SessionID=sid, - LastUpdateTS=session_ts) - db.add(self.session) - else: - last_updated = self.session.LastUpdateTS - if last_updated and last_updated < now_ts: - self.session.SessionID = sid = generate_unique_sid() - else: - # Session is still valid; retrieve the current SID. - sid = self.session.SessionID + if exc: + detail = ("Unable to generate a unique session ID in " + f"{tries} iterations.") + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, + detail=detail) - self.session.LastUpdateTS = session_ts - - request.cookies["AURSID"] = self.session.SessionID return self.session.SessionID def has_credential(self, credential: Set[int], @@ -142,8 +156,7 @@ class User(Base): from aurweb.auth.creds import has_credential return has_credential(self, credential, approved) - def logout(self, request): - del request.cookies["AURSID"] + def logout(self, request: Request): self.authenticated = False if self.session: with db.begin(): diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index a8d0db11..3455a019 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -283,3 +283,48 @@ def test_login_bad_referer(client: TestClient): response = request.post("/login", data=post_data, headers=BAD_REFERER) assert response.status_code == int(HTTPStatus.BAD_REQUEST) assert "AURSID" not in response.cookies + + +def test_generate_unique_sid_exhausted(client: TestClient, user: User): + """ + In this test, we mock up generate_unique_sid() to infinitely return + the same SessionID given to `user`. Within that mocking, we try + to login as `user2` and expect the internal server error rendering + by our error handler. + + This exercises the bad path of /login, where we can't find a unique + SID to assign the user. + """ + now = int(datetime.utcnow().timestamp()) + with db.begin(): + # Create a second user; we'll login with this one. + user2 = db.create(User, Username="test2", Email="test2@example.org", + ResetKey="testReset", Passwd="testPassword", + AccountTypeID=USER_ID) + + # Create a session with ID == "testSession" for `user`. + db.create(Session, User=user, SessionID="testSession", + LastUpdateTS=now) + + # Mock out generate_unique_sid; always return "testSession" which + # causes us to eventually error out and raise an internal error. + def mock_generate_sid(): + return "testSession" + + # Login as `user2`; we expect an internal server error response + # with a relevent detail. + post_data = { + "user": user2.Username, + "passwd": "testPassword", + "next": "/", + } + generate_unique_sid_ = "aurweb.models.session.generate_unique_sid" + with mock.patch(generate_unique_sid_, mock_generate_sid): + with client as request: + # Set cookies = {} to remove any previous login kept by TestClient. + response = request.post("/login", data=post_data, cookies={}) + assert response.status_code == int(HTTPStatus.INTERNAL_SERVER_ERROR) + + expected = "Unable to generate a unique session ID" + assert expected in response.text + assert "500 - Internal Server Error" in response.text diff --git a/test/test_user.py b/test/test_user.py index 52cdc89e..2c8dd847 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -62,7 +62,6 @@ def test_user_login_logout(user: User): sid = user.login(request, "testPassword") assert sid is not None assert user.is_authenticated() - assert "AURSID" in request.cookies # Expect that User session relationships work right. user_session = db.query(Session, @@ -92,7 +91,6 @@ def test_user_login_logout(user: User): # Test logout. user.logout(request) - assert "AURSID" not in request.cookies assert not user.is_authenticated() From 81f8c2326566f993fcbcb2f0ef189c13657b0676 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 2 Dec 2021 23:42:13 -0800 Subject: [PATCH 1232/1891] fix(fastapi): log out IntegrityError from failed SID generation Signed-off-by: Kevin Morris --- aurweb/models/user.py | 5 ++++- test/test_auth_routes.py | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index dcf5f519..8e66b490 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -15,11 +15,13 @@ import aurweb.config import aurweb.models.account_type import aurweb.schema -from aurweb import db, schema +from aurweb import db, logging, schema from aurweb.models.account_type import AccountType as _AccountType from aurweb.models.ban import is_banned from aurweb.models.declarative import Base +logger = logging.get_logger(__name__) + SALT_ROUNDS_DEFAULT = 12 @@ -146,6 +148,7 @@ class User(Base): if exc: detail = ("Unable to generate a unique session ID in " f"{tries} iterations.") + logger.error(str(exc)) raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=detail) diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 3455a019..3ae8a56c 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -285,7 +285,8 @@ def test_login_bad_referer(client: TestClient): assert "AURSID" not in response.cookies -def test_generate_unique_sid_exhausted(client: TestClient, user: User): +def test_generate_unique_sid_exhausted(client: TestClient, user: User, + caplog: pytest.LogCaptureFixture): """ In this test, we mock up generate_unique_sid() to infinitely return the same SessionID given to `user`. Within that mocking, we try @@ -328,3 +329,6 @@ def test_generate_unique_sid_exhausted(client: TestClient, user: User): expected = "Unable to generate a unique session ID" assert expected in response.text assert "500 - Internal Server Error" in response.text + + # Make sure an IntegrityError from the DB got logged out. + assert "IntegrityError" in caplog.text From 75ad2fb53d04e5f85dc32779bfa0e373f9301e74 Mon Sep 17 00:00:00 2001 From: Steven Guikal Date: Wed, 1 Dec 2021 16:35:24 -0500 Subject: [PATCH 1233/1891] fix(FastAPI): cleanup auth_required decorator Signed-off-by: Steven Guikal --- aurweb/auth/__init__.py | 46 ++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 18356ac2..b6dd6e3f 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -120,35 +120,39 @@ class BasicAuthBackend(AuthenticationBackend): return (AuthCredentials(["authenticated"]), user) -def auth_required(is_required: bool = True): - """ Authentication route decorator. +def auth_required(auth_goal: bool = True): + """ Enforce a user's authentication status, bringing them to the login page + or homepage if their authentication status does not match the goal. - :param is_required: A boolean indicating whether the function requires auth - :param status_code: An optional status_code for template render. - Redirects are always SEE_OTHER. + :param auth_goal: Whether authentication is required or entirely disallowed + for a user to perform this request. + :return: Return the FastAPI function this decorator wraps. """ def decorator(func): @functools.wraps(func) async def wrapper(request, *args, **kwargs): - if request.user.is_authenticated() != is_required: - url = "/" + if request.user.is_authenticated() == auth_goal: + return await func(request, *args, **kwargs) - if is_required: - if request.method == "GET": - url = request.url.path - elif request.method == "POST" and (referer := request.headers.get("Referer")): - aur = aurweb.config.get("options", "aur_location") + "/" - if not referer.startswith(aur): - _ = l10n.get_translator_for_request(request) - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, - detail=_("Bad Referer header.")) - url = referer[len(aur) - 1:] + url = "/" + if auth_goal is False: + return RedirectResponse(url, status_code=int(HTTPStatus.SEE_OTHER)) - url = "/login?" + util.urlencode({"next": url}) - return RedirectResponse(url, - status_code=int(HTTPStatus.SEE_OTHER)) - return await func(request, *args, **kwargs) + # Use the request path when the user can visit a page directly but + # is not authenticated and use the Referer header if visiting the + # page itself is not directly possible (e.g. submitting a form). + if request.method in ("GET", "HEAD"): + url = request.url.path + elif (referer := request.headers.get("Referer")): + aur = aurweb.config.get("options", "aur_location") + "/" + if not referer.startswith(aur): + _ = l10n.get_translator_for_request(request) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, + detail=_("Bad Referer header.")) + url = referer[len(aur) - 1:] + url = "/login?" + util.urlencode({"next": url}) + return RedirectResponse(url, status_code=int(HTTPStatus.SEE_OTHER)) return wrapper return decorator From b0b5e4c9d10ee3c31c7e3a61286c9fdabd3c8ceb Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 3 Dec 2021 15:13:41 -0800 Subject: [PATCH 1234/1891] fix(fastapi): use `secrets` module to generate random strings Signed-off-by: Kevin Morris --- aurweb/util.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index f5ced259..542dfc2e 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -1,7 +1,6 @@ import base64 import copy import math -import random import re import secrets import string @@ -25,9 +24,9 @@ from aurweb import defaults, logging logger = logging.get_logger(__name__) -def make_random_string(length): - return ''.join(random.choices(string.ascii_lowercase - + string.digits, k=length)) +def make_random_string(length: int) -> str: + alphanumerics = string.ascii_lowercase + string.digits + return ''.join([secrets.choice(alphanumerics) for i in range(length)]) def make_nonce(length: int = 8): From aa717a4ef9d45d0b2a454a75bdd4f55dd18a2225 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 3 Dec 2021 15:41:54 -0800 Subject: [PATCH 1235/1891] change(fastapi): no longer care about ResetKey collisions Signed-off-by: Kevin Morris --- aurweb/models/user.py | 6 +++--- aurweb/routers/accounts.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 8e66b490..d0bdea30 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -15,7 +15,7 @@ import aurweb.config import aurweb.models.account_type import aurweb.schema -from aurweb import db, logging, schema +from aurweb import db, logging, schema, util from aurweb.models.account_type import AccountType as _AccountType from aurweb.models.ban import is_banned from aurweb.models.declarative import Base @@ -249,5 +249,5 @@ class User(Base): self.ID, str(self.AccountType), self.Username) -def generate_unique_resetkey(): - return db.make_random_value(User, User.ResetKey, 32) +def generate_resetkey(): + return util.make_random_string(32) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 388daf84..f61ccdd2 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -16,7 +16,7 @@ from aurweb.exceptions import ValidationError from aurweb.l10n import get_translator_for_request from aurweb.models import account_type as at from aurweb.models.ssh_pub_key import get_fingerprint -from aurweb.models.user import generate_unique_resetkey +from aurweb.models.user import generate_resetkey from aurweb.scripts.notify import ResetKeyNotification, WelcomeNotification from aurweb.templates import make_context, make_variable_context, render_template from aurweb.users import update, validate @@ -93,7 +93,7 @@ async def passreset_post(request: Request, status_code=HTTPStatus.SEE_OTHER) # If we got here, we continue with issuing a resetkey for the user. - resetkey = generate_unique_resetkey() + resetkey = generate_resetkey() with db.begin(): user.ResetKey = resetkey @@ -291,7 +291,7 @@ async def account_register_post(request: Request, # Create a user with no password with a resetkey, then send # an email off about it. - resetkey = generate_unique_resetkey() + resetkey = generate_resetkey() # By default, we grab the User account type to associate with. atype = db.query(models.AccountType, From bfa916c7b294fb82f3b935f973b649f42849557b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 3 Dec 2021 23:40:16 -0800 Subject: [PATCH 1236/1891] fix(fastapi): fix PGP Key Fingerprint display for account/show.html There's a space between every 4 characters in the fingerprint in PHP; we were missing it in FastAPI. This commit fixes that inconsistency. Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 11 ++++++++++- templates/account/show.html | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index f61ccdd2..946ffc31 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -432,7 +432,16 @@ async def account(request: Request, username: str): if not request.user.is_authenticated(): return render_template(request, "account/show.html", context, status_code=HTTPStatus.UNAUTHORIZED) - context["user"] = get_user_by_name(username) + + # Get related User record, if possible. + user = get_user_by_name(username) + context["user"] = user + + # Format PGPKey for display with a space between each 4 characters. + k = user.PGPKey or str() + context["pgp_key"] = " ".join([k[i:i + 4] for i in range(0, len(k), 4)]) + + # Render the template. return render_template(request, "account/show.html", context) diff --git a/templates/account/show.html b/templates/account/show.html index 0c99c99f..23b262b0 100644 --- a/templates/account/show.html +++ b/templates/account/show.html @@ -46,7 +46,7 @@ {% trans %}PGP Key Fingerprint{% endtrans %}: - {{ user.PGPKey or '' }} + {{ pgp_key }} {% trans %}Status{% endtrans %}: From d0fc56d53fa1232aa5d5c1b5a7bca12ad1edb773 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Dec 2021 00:14:55 -0800 Subject: [PATCH 1237/1891] fix(python): redirect when the request user can't edit target user Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 24 +++++++++++++++++------- test/test_accounts_routes.py | 30 ++++++++++++++++++------------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index f61ccdd2..ff2c3040 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -329,13 +329,23 @@ async def account_register_post(request: Request, return render_template(request, "register.html", context) -def cannot_edit(request, user): - """ Return a 401 HTMLResponse if the request user doesn't - have authorization, otherwise None. """ - has_dev_cred = request.user.has_credential(creds.ACCOUNT_EDIT_DEV, - approved=[user]) - if not has_dev_cred: - return HTMLResponse(status_code=HTTPStatus.UNAUTHORIZED) +def cannot_edit(request: Request, user: models.User) \ + -> typing.Optional[RedirectResponse]: + """ + Decide if `request.user` cannot edit `user`. + + If the request user can edit the target user, None is returned. + Otherwise, a redirect is returned to /account/{user.Username}. + + :param request: FastAPI request + :param user: Target user to be edited + :return: RedirectResponse if approval != granted else None + """ + approved = request.user.has_credential(creds.ACCOUNT_EDIT, approved=[user]) + if not approved and (to := "/"): + if user: + to = f"/account/{user.Username}" + return RedirectResponse(to, status_code=HTTPStatus.SEE_OTHER) return None diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index f08efcd2..348a6994 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -620,16 +620,19 @@ def test_get_account_edit_unauthorized(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") - create(User, Username="test2", Email="test2@example.org", - Passwd="testPassword") + with db.begin(): + user2 = create(User, Username="test2", Email="test2@example.org", + Passwd="testPassword", AccountTypeID=USER_ID) + endpoint = f"/account/{user2.Username}/edit" with client as request: # Try to edit `test2` while authenticated as `test`. - response = request.get("/account/test2/edit", cookies={ - "AURSID": sid - }, allow_redirects=False) + response = request.get(endpoint, cookies={"AURSID": sid}, + allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) - assert response.status_code == int(HTTPStatus.UNAUTHORIZED) + expected = f"/account/{user2.Username}" + assert response.headers.get("location") == expected def test_post_account_edit(client: TestClient, user: User): @@ -828,8 +831,9 @@ def test_post_account_edit_error_unauthorized(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") - create(User, Username="test2", - Email="test2@example.org", Passwd="testPassword") + with db.begin(): + user2 = create(User, Username="test2", Email="test2@example.org", + Passwd="testPassword", AccountTypeID=USER_ID) post_data = { "U": "test", @@ -838,13 +842,15 @@ def test_post_account_edit_error_unauthorized(client: TestClient, user: User): "passwd": "testPassword" } + endpoint = f"/account/{user2.Username}/edit" with client as request: # Attempt to edit 'test2' while logged in as 'test'. - response = request.post("/account/test2/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post(endpoint, cookies={"AURSID": sid}, + data=post_data, allow_redirects=False) + assert response.status_code == int(HTTPStatus.SEE_OTHER) - assert response.status_code == int(HTTPStatus.UNAUTHORIZED) + expected = f"/account/{user2.Username}" + assert response.headers.get("location") == expected def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): From 973dbf04828c1b5f475c189d12dd8c099ac8b35e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Dec 2021 00:15:34 -0800 Subject: [PATCH 1238/1891] fix(python): use creds to determine account links to display Signed-off-by: Kevin Morris --- templates/account/show.html | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/templates/account/show.html b/templates/account/show.html index 0c99c99f..14a4eccf 100644 --- a/templates/account/show.html +++ b/templates/account/show.html @@ -69,20 +69,24 @@ | safe }} -
  • - {{ "%sEdit this user's account%s" - | tr - | format('' | format(user.Username), "") - | safe - }} -
  • -
  • - {{ "%sList this user's comments%s" - | tr - | format('' | format(user.Username), "") - | safe - }} -
  • + {% if request.user.has_credential(creds.ACCOUNT_EDIT, approved=[user]) %} +
  • + {{ "%sEdit this user's account%s" + | tr + | format('' | format(user.Username), "") + | safe + }} +
  • + {% endif %} + {% if request.user.has_credential(creds.ACCOUNT_LIST_COMMENTS, approved=[user]) %} +
  • + {{ "%sList this user's comments%s" + | tr + | format('' | format(user.Username), "") + | safe + }} +
  • + {% endif %} From 2ea4559b60135b38c07b949d5905c99ec98739dc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Dec 2021 00:50:32 -0800 Subject: [PATCH 1239/1891] fix(python): use correct Status field in account/show.html Signed-off-by: Kevin Morris --- templates/account/show.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/templates/account/show.html b/templates/account/show.html index e1074394..3e36faf0 100644 --- a/templates/account/show.html +++ b/templates/account/show.html @@ -50,6 +50,17 @@ {% trans %}Status{% endtrans %}: + {% if not user.InactivityTS %} + {{ "Active" | tr }} + {% else %} + {% set inactive_ds = user.InactivityTS | dt | as_timezone(timezone) %} + + {{ + "Inactive since %s" | tr + | format(inactive_ds.strftime("%Y-%m-%d %H:%M")) + }} + + {% endif %} {{ "Active" if not user.Suspended else "Suspended" | tr }} From 224a0de784634c1ee5569e12a7f95d1e9bc1bb5f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Dec 2021 01:16:14 -0800 Subject: [PATCH 1240/1891] fix(python): add logged in date field to account/show.html Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 7 +++++++ templates/account/show.html | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index fc25a7e8..8eecaa31 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -451,6 +451,13 @@ async def account(request: Request, username: str): k = user.PGPKey or str() context["pgp_key"] = " ".join([k[i:i + 4] for i in range(0, len(k), 4)]) + login_ts = None + session = db.query(models.Session).filter( + models.Session.UsersID == user.ID).first() + if session: + login_ts = user.session.LastUpdateTS + context["login_ts"] = login_ts + # Render the template. return render_template(request, "account/show.html", context) diff --git a/templates/account/show.html b/templates/account/show.html index 3e36faf0..c6a53f4a 100644 --- a/templates/account/show.html +++ b/templates/account/show.html @@ -61,7 +61,6 @@ }} {% endif %} - {{ "Active" if not user.Suspended else "Suspended" | tr }} {% trans %}Registration date{% endtrans %}: @@ -69,6 +68,13 @@ {{ user.RegistrationTS.strftime("%Y-%m-%d") }} + {% if login_ts %} + + {% trans %}Last Login{% endtrans %}: + {% set login_ds = login_ts | dt | as_timezone(timezone) %} + {{ login_ds.strftime("%Y-%m-%d") }} + + {% endif %} {% trans %}Links{% endtrans %}: From 8501bba0ac7e6ad03f80d9f370bcd4cbd63db296 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Dec 2021 02:12:20 -0800 Subject: [PATCH 1241/1891] change(python): rework session timing Previously, we were just relying on the cookie expiration for sessions to expire. We were not cleaning up Session records either. Rework timing to depend on an AURREMEMBER cookie which is now emitted on login during BasicAuthBackend processing. If the SID does still have a session but it's expired, we now delete the session record before returning. Otherwise, we update the session's LastUpdateTS to the current time. In addition, stored the unauthenticated result value in a variable to reduce redundancy. Signed-off-by: Kevin Morris --- aurweb/auth/__init__.py | 22 +++++++++++++++------- aurweb/models/user.py | 8 ++------ aurweb/routers/auth.py | 4 ++++ test/test_auth.py | 24 +++++++++++++++++++++++- test/test_auth_routes.py | 16 ++++++---------- 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index b6dd6e3f..5f55e2fb 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -7,7 +7,6 @@ import fastapi from fastapi import HTTPException from fastapi.responses import RedirectResponse -from sqlalchemy import and_ from starlette.authentication import AuthCredentials, AuthenticationBackend from starlette.requests import HTTPConnection @@ -97,18 +96,27 @@ class AnonymousUser: class BasicAuthBackend(AuthenticationBackend): async def authenticate(self, conn: HTTPConnection): + unauthenticated = (None, AnonymousUser()) sid = conn.cookies.get("AURSID") if not sid: - return (None, AnonymousUser()) + return unauthenticated - now_ts = datetime.utcnow().timestamp() - record = db.query(Session).filter( - and_(Session.SessionID == sid, - Session.LastUpdateTS >= now_ts)).first() + timeout = aurweb.config.getint("options", "login_timeout") + remembered = ("AURREMEMBER" in conn.cookies + and bool(conn.cookies.get("AURREMEMBER"))) + if remembered: + timeout = aurweb.config.getint("options", + "persistent_cookie_timeout") # If no session with sid and a LastUpdateTS now or later exists. + now_ts = int(datetime.utcnow().timestamp()) + record = db.query(Session).filter(Session.SessionID == sid).first() if not record: - return (None, AnonymousUser()) + return unauthenticated + elif record.LastUpdateTS < (now_ts - timeout): + with db.begin(): + db.delete_all([record]) + return unauthenticated # At this point, we cannot have an invalid user if the record # exists, due to ForeignKey constraints in the schema upheld diff --git a/aurweb/models/user.py b/aurweb/models/user.py index d0bdea30..5ead606e 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -123,10 +123,6 @@ class User(Base): for i in range(tries): exc = None now_ts = datetime.utcnow().timestamp() - session_ts = now_ts + ( - session_time if session_time - else aurweb.config.getint("options", "login_timeout") - ) try: with db.begin(): self.LastLogin = now_ts @@ -135,12 +131,12 @@ class User(Base): sid = generate_unique_sid() self.session = db.create(Session, User=self, SessionID=sid, - LastUpdateTS=session_ts) + LastUpdateTS=now_ts) else: last_updated = self.session.LastUpdateTS if last_updated and last_updated < now_ts: self.session.SessionID = generate_unique_sid() - self.session.LastUpdateTS = session_ts + self.session.LastUpdateTS = now_ts break except IntegrityError as exc_: exc = exc_ diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 74763667..8815c896 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -73,6 +73,10 @@ async def login_post(request: Request, response.set_cookie("AURLANG", user.LangPreference, secure=secure, httponly=secure, samesite=cookies.samesite()) + response.set_cookie("AURREMEMBER", remember_me, + expires=expires_at, + secure=secure, httponly=secure, + samesite=cookies.samesite()) return response diff --git a/test/test_auth.py b/test/test_auth.py index b607a038..0094aa25 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -6,7 +6,7 @@ import pytest from fastapi import HTTPException from sqlalchemy.exc import IntegrityError -from aurweb import db +from aurweb import config, db from aurweb.auth import AnonymousUser, BasicAuthBackend, account_type_required, auth_required from aurweb.models.account_type import USER, USER_ID from aurweb.models.session import Session @@ -76,6 +76,28 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend): assert result == user +@pytest.mark.asyncio +async def test_expired_session(backend: BasicAuthBackend, user: User): + """ Login, expire the session manually, then authenticate. """ + # First, build a Request with a logged in user. + request = Request() + request.user = user + sid = request.user.login(Request(), "testPassword") + request.cookies["AURSID"] = sid + + # Set Session.LastUpdateTS to 20 seconds expired. + timeout = config.getint("options", "login_timeout") + now_ts = int(datetime.utcnow().timestamp()) + with db.begin(): + request.user.session.LastUpdateTS = now_ts - timeout - 20 + + # Run through authentication backend and get the session + # deleted due to its expiration. + await backend.authenticate(request) + session = db.query(Session).filter(Session.SessionID == sid).first() + assert session is None + + @pytest.mark.asyncio async def test_auth_required_redirection_bad_referrer(): # Create a fake route function which can be wrapped by auth_required. diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 3ae8a56c..f3e2a011 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -13,7 +13,6 @@ from aurweb.asgi import app from aurweb.models.account_type import USER_ID from aurweb.models.session import Session from aurweb.models.user import User -from aurweb.testing.requests import Request # Some test global constants. TEST_USERNAME = "test" @@ -136,12 +135,11 @@ def test_secure_login(getboolean: bool, client: TestClient, user: User): def test_authenticated_login(client: TestClient, user: User): post_data = { - "user": "test", + "user": user.Username, "passwd": "testPassword", "next": "/" } - cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: # Try to login. response = request.post("/login", data=post_data, @@ -153,7 +151,7 @@ def test_authenticated_login(client: TestClient, user: User): # when requesting GET /login as an authenticated user. # Now, let's verify that we receive 403 Forbidden when we # try to get /login as an authenticated user. - response = request.get("/login", cookies=cookies, + response = request.get("/login", cookies=response.cookies, allow_redirects=False) assert response.status_code == int(HTTPStatus.OK) assert "Logged-in as: test" in response.text @@ -200,14 +198,12 @@ def test_login_remember_me(client: TestClient, user: User): cookie_timeout = aurweb.config.getint( "options", "persistent_cookie_timeout") - expected_ts = datetime.utcnow().timestamp() + cookie_timeout - + now_ts = int(datetime.utcnow().timestamp()) session = db.query(Session).filter(Session.UsersID == user.ID).first() - # Expect that LastUpdateTS was within 5 seconds of the expected_ts, - # which is equal to the current timestamp + persistent_cookie_timeout. - assert session.LastUpdateTS > expected_ts - 5 - assert session.LastUpdateTS < expected_ts + 5 + # Expect that LastUpdateTS is not past the cookie timeout + # for a remembered session. + assert session.LastUpdateTS > (now_ts - cookie_timeout) def test_login_incorrect_password_remember_me(client: TestClient, user: User): From cf978e23aa787a002d66403866140cc4be2617fe Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Dec 2021 00:51:33 -0800 Subject: [PATCH 1242/1891] fix(python): use S argument to decide Suspended Signed-off-by: Kevin Morris --- aurweb/users/update.py | 4 ++-- test/test_accounts_routes.py | 30 ++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/aurweb/users/update.py b/aurweb/users/update.py index 60a6184e..fd42a194 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -12,7 +12,7 @@ def simple(U: str = str(), E: str = str(), H: bool = False, BE: str = str(), R: str = str(), HP: str = str(), I: str = str(), K: str = str(), J: bool = False, CN: bool = False, UN: bool = False, ON: bool = False, - user: models.User = None, + S: bool = False, user: models.User = None, **kwargs) -> None: now = int(datetime.utcnow().timestamp()) with db.begin(): @@ -24,7 +24,7 @@ def simple(U: str = str(), E: str = str(), H: bool = False, user.Homepage = HP or user.Homepage user.IRCNick = I or user.IRCNick user.PGPKey = K or user.PGPKey - user.Suspended = strtobool(J) + user.Suspended = strtobool(S) user.InactivityTS = now * int(strtobool(J)) user.CommentNotify = strtobool(CN) user.UpdateNotify = strtobool(UN) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 348a6994..d3435089 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -814,7 +814,6 @@ def test_post_account_edit_inactivity(client: TestClient, user: User): assert resp.status_code == int(HTTPStatus.OK) # Make sure the user record got updated correctly. - assert user.Suspended assert user.InactivityTS > 0 post_data.update({"J": False}) @@ -823,10 +822,37 @@ def test_post_account_edit_inactivity(client: TestClient, user: User): cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) - assert not user.Suspended assert user.InactivityTS == 0 +def test_post_account_edit_suspended(client: TestClient, user: User): + with db.begin(): + user.AccountTypeID = TRUSTED_USER_ID + assert not user.Suspended + + cookies = {"AURSID": user.login(Request(), "testPassword")} + post_data = { + "U": "test", + "E": "test@example.org", + "S": True, + "passwd": "testPassword" + } + endpoint = f"/account/{user.Username}/edit" + with client as request: + resp = request.post(endpoint, data=post_data, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # Make sure the user record got updated correctly. + assert user.Suspended + + post_data.update({"S": False}) + with client as request: + resp = request.post(endpoint, data=post_data, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + assert not user.Suspended + + def test_post_account_edit_error_unauthorized(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") From 27f8603dc511ad4723c8100829f458b0e5a3c719 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 4 Dec 2021 00:51:59 -0800 Subject: [PATCH 1243/1891] fix(python): fix ordering of fields in partials/account_form.html Signed-off-by: Kevin Morris --- templates/partials/account_form.html | 64 ++++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index f3c293d8..37bb85c4 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -42,6 +42,38 @@ "account is inactive." | tr }}

    + {% if request.user.has_credential(creds.ACCOUNT_CHANGE_TYPE) %} +

    + + +

    + +

    + + + +

    + {% endif %} + {% if request.user.is_elevated() %}

    @@ -53,38 +85,6 @@

    {% endif %} - {% if request.user.has_credential(creds.ACCOUNT_CHANGE_TYPE) %} -

    - - -

    - -

    - - - -

    - {% endif %} -

    +

    + + +

    +

    +

    + + +

    +

    +

    + + +

    +

    -

    - - -

    -

    +

    +

    -

    - - -

    -

    +

    + {{ + "This action will close any pending package requests " + "related to it. If %sComments%s are omitted, a closure " + "comment will be autogenerated." + | tr | format("", "") | safe + }} +

    +

    {{ "By selecting the checkbox, you confirm that you want to " @@ -38,8 +47,11 @@

    - +

    diff --git a/templates/pkgbase/merge.html b/templates/pkgbase/merge.html index b5129801..981bd649 100644 --- a/templates/pkgbase/merge.html +++ b/templates/pkgbase/merge.html @@ -28,6 +28,15 @@ {% endfor %} +

    + {{ + "This action will close any pending package requests " + "related to it. If %sComments%s are omitted, a closure " + "comment will be autogenerated." + | tr | format("", "") | safe + }} +

    +

    {{ "Once the package has been merged it cannot be reversed. " | tr }} {{ "Enter the package name you wish to merge the package into. " | tr }} @@ -37,6 +46,16 @@

    + +

    + + +

    +

    -

    - - -

    -

    +
    {% set len = comaintainers | length %} {% if comaintainers %} - ({% for co in comaintainers %}{{ co.User }}{% if loop.index < len %}, {% endif %}{% endfor %}) + ({% for co in comaintainers %}{{ co }}{% if loop.index < len %}, {% endif %}{% endfor %}) {% endif %} {% else %} {{ pkgbase.Maintainer.Username | default("None" | tr) }} diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index 03b55063..5edae592 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -534,6 +534,35 @@ def test_pkgbase_comment_undelete_not_found(client: TestClient, assert resp.status_code == int(HTTPStatus.NOT_FOUND) +def test_pkgbase_comment_pin_as_co(client: TestClient, package: Package, + comment: PackageComment): + comaint = create_user("comaint1") + + with db.begin(): + db.create(PackageComaintainer, PackageBase=package.PackageBase, + User=comaint, Priority=1) + + # Pin the comment. + pkgbasename = package.PackageBase.Name + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/pin" + cookies = {"AURSID": comaint.login(Request(), "testPassword")} + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + # Assert that PinnedTS got set. + assert comment.PinnedTS > 0 + + # Unpin the comment we just pinned. + endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/unpin" + with client as request: + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + # Let's assert that PinnedTS was unset. + assert comment.PinnedTS == 0 + + def test_pkgbase_comment_pin(client: TestClient, maintainer: User, package: Package, From 167186895625f57e8fb88713b34d3a989307f8ee Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 13 Feb 2022 17:34:33 -0800 Subject: [PATCH 1459/1891] fix: links to cgit should be url encoded Closes #283 Signed-off-by: Kevin Morris --- aurweb/scripts/rendercomment.py | 8 ++++++-- templates/partials/packages/actions.html | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 2af5384e..87f8b89f 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -2,6 +2,7 @@ import sys +from urllib.parse import quote_plus from xml.etree.ElementTree import Element import bleach @@ -72,13 +73,16 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): def handleMatch(self, m, data): oid = m.group(1) if oid not in self._repo: - # Unkwown OID; preserve the orginal text. + # Unknown OID; preserve the orginal text. return (None, None, None) el = Element('a') commit_uri = aurweb.config.get("options", "commit_uri") prefixlen = util.git_search(self._repo, oid) - el.set('href', commit_uri % (self._head, oid[:prefixlen])) + el.set('href', commit_uri % ( + quote_plus(self._head), + quote_plus(oid[:prefixlen]) + )) el.text = markdown.util.AtomicString(oid[:prefixlen]) return (el, m.start(0), m.end(0)) diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 8d024506..88420222 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -6,21 +6,21 @@

    {{ "Package Actions" | tr }}

    • - + {{ "View PKGBUILD" | tr }} / - + {{ "View Changes" | tr }}
    • - + {{ "Download snapshot" | tr }}
    • - + {{ "Search wiki" | tr }}
    • From 29061c000c2876fd00bdfdf67c0c19d19d2f983d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 14 Feb 2022 15:24:14 -0800 Subject: [PATCH 1460/1891] fix: pkgbase -> package redirection We were redirecting in some error-cases, which this commit sorts out: - package count == 1 and package base name != package name - was redirecting to {name} and not the only associated Package Now, when we have a package base name that mismatches its only package, we display the package base page. Otherwise, we redirect to the first package's page. Closes #282 Signed-off-by: Kevin Morris --- aurweb/routers/pkgbase.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 7825ad7b..845c6372 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -39,14 +39,17 @@ async def pkgbase(request: Request, name: str) -> Response: # Get the PackageBase. pkgbase = get_pkg_or_base(name, PackageBase) - # If this is not a split package, redirect to /packages/{name}. - if pkgbase.packages.count() == 1: - return RedirectResponse(f"/packages/{name}", + # Redirect to /packages if there's only one related Package + # and its name matches its PackageBase. + packages = pkgbase.packages.all() + pkg = packages[0] + if len(packages) == 1 and pkg.Name == pkgbase.Name: + return RedirectResponse(f"/packages/{pkg.Name}", status_code=int(HTTPStatus.SEE_OTHER)) # Add our base information. context = pkgbaseutil.make_context(request, pkgbase) - context["packages"] = pkgbase.packages.all() + context["packages"] = packages return render_template(request, "pkgbase/index.html", context) From 93275949261520ebc81e0b9595a56f000b623900 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 14 Feb 2022 15:42:18 -0800 Subject: [PATCH 1461/1891] upgrade: bump to v6.0.12 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 7bd7abd4..e004daef 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.11" +AURWEB_VERSION = "v6.0.12" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 5afa6d6c..50149b77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.11" +version = "v6.0.12" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 640630fafffb11f409b616f7d571f53470db5e4d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 14 Feb 2022 15:45:59 -0800 Subject: [PATCH 1462/1891] upgrade: bump to v6.0.13 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index e004daef..2a865b9b 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.12" +AURWEB_VERSION = "v6.0.13" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 50149b77..6ba0ff52 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.12" +version = "v6.0.13" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 040c9bc3e62a41dde83fa44c53fc36ec12bdcd54 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 17 Feb 2022 15:30:32 -0800 Subject: [PATCH 1463/1891] fix: send up to date flag notifications These were being produced with the db state before the flag was set, which is not what should be done for flag notifications, as the notification contains data about the comment and the current flagger. Closes #292 Signed-off-by: Kevin Morris --- aurweb/routers/pkgbase.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 845c6372..4c0b8a67 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -150,13 +150,13 @@ async def pkgbase_flag_post(request: Request, name: str, has_cred = request.user.has_credential(creds.PKGBASE_FLAG) if has_cred and not pkgbase.OutOfDateTS: - notif = notify.FlagNotification(request.user.ID, pkgbase.ID) now = time.utcnow() with db.begin(): pkgbase.OutOfDateTS = now pkgbase.Flagger = request.user pkgbase.FlaggerComment = comments - notif.send() + + notify.FlagNotification(request.user.ID, pkgbase.ID).send() return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) From 361163098f7e074ddca76c7926e69a3fa9b2eae2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 17 Feb 2022 15:48:58 -0800 Subject: [PATCH 1464/1891] fix: /packages search ordering links This was not including other parameters that should be persisted for users. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 4 ++-- templates/partials/packages/search_results.html | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 8f6cb7d6..d4e85d20 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -15,7 +15,7 @@ from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base from aurweb.pkgbase import actions as pkgbase_actions from aurweb.pkgbase import util as pkgbaseutil -from aurweb.templates import make_context, render_template +from aurweb.templates import make_context, make_variable_context, render_template logger = logging.get_logger(__name__) router = APIRouter() @@ -125,7 +125,7 @@ async def packages_get(request: Request, context: Dict[str, Any], @router.get("/packages") async def packages(request: Request) -> Response: - context = make_context(request, "Packages") + context = await make_variable_context(request, "Packages") return await packages_get(request, context) diff --git a/templates/partials/packages/search_results.html b/templates/partials/packages/search_results.html index 680891c4..c3b4427c 100644 --- a/templates/partials/packages/search_results.html +++ b/templates/partials/packages/search_results.html @@ -9,7 +9,7 @@ {% if SB == "n" %} {% set order = "d" if order == "a" else "a" %} {% endif %} - + {{ "Name" | tr }} @@ -19,7 +19,7 @@ {% if SB == "v" %} {% set order = "d" if order == "a" else "a" %} {% endif %} - + {{ "Votes" | tr }} @@ -28,7 +28,7 @@ {% if SB == "p" %} {% set order = "d" if order == "a" else "a" %} {% endif %} - {{ "Popularity" | tr }}? + {{ "Popularity" | tr }}? {% if request.user.is_authenticated() %} @@ -36,7 +36,7 @@ {% if SB == "w" %} {% set order = "d" if order == "a" else "a" %} {% endif %} - + {{ "Voted" | tr }} @@ -45,7 +45,7 @@ {% if SB == "o" %} {% set order = "d" if order == "a" else "a" %} {% endif %} - + {{ "Notify" | tr }} @@ -56,7 +56,7 @@ {% if SB == "m" %} {% set order = "d" if order == "a" else "a" %} {% endif %} - + {{ "Maintainer" | tr }} From e3864d4b7ca21d17f3faea196509e0a5b3f23f82 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 17 Feb 2022 15:54:04 -0800 Subject: [PATCH 1465/1891] fix: set RequestTS when autogenerating requests Signed-off-by: Kevin Morris --- aurweb/packages/requests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/packages/requests.py b/aurweb/packages/requests.py index 724249d4..6aaa59ab 100644 --- a/aurweb/packages/requests.py +++ b/aurweb/packages/requests.py @@ -201,9 +201,11 @@ def handle_request(request: Request, reqtype_id: int, # This is done to increase tracking of actions occurring # through the website. if not to_accept: + utcnow = time.utcnow() with db.begin(): pkgreq = db.create(PackageRequest, ReqTypeID=reqtype_id, + RequestTS=utcnow, User=request.user, PackageBase=pkgbase, PackageBaseName=pkgbase.Name, From 0bfecb984482720db1b72d47799dc86812b8bfb0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 17 Feb 2022 16:14:31 -0800 Subject: [PATCH 1466/1891] upgrade: bump to v6.0.14 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 2a865b9b..eea156f5 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.13" +AURWEB_VERSION = "v6.0.14" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 6ba0ff52..50691228 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.13" +version = "v6.0.14" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From bfd592299c08befaf24733fdbf83b156565fc958 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 17 Feb 2022 17:23:05 -0800 Subject: [PATCH 1467/1891] change: display default package search parameter values in its form The previous behavior was carried over from PHP. It has been requested that we use the true defaults when rendering the default form, making search a bit more sensible. Closes #269 Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 9 +---- templates/partials/packages/search.html | 6 +++ .../partials/packages/search_results.html | 40 +++++++++++-------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index d4e85d20..34c09d86 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -40,7 +40,7 @@ async def packages_get(request: Request, context: Dict[str, Any], search_by = context["SeB"] = request.query_params.get("SeB", "nd") # Query sort by. - sort_by = context["SB"] = request.query_params.get("SB", "p") + sort_by = request.query_params.get("SB", None) # Query sort order. sort_order = request.query_params.get("SO", None) @@ -93,13 +93,6 @@ async def packages_get(request: Request, context: Dict[str, Any], # Apply user-specified specified sort column and ordering. search.sort_by(sort_by, sort_order) - # If no SO was given, default the context SO to 'a' (Ascending). - # By default, if no SO is given, the search should sort by 'd' - # (Descending), but display "Ascending" for the Sort order select. - if sort_order is None: - sort_order = "a" - context["SO"] = sort_order - # Insert search results into the context. results = search.results().with_entities( models.Package.ID, diff --git a/templates/partials/packages/search.html b/templates/partials/packages/search.html index 33bc6132..3db5c7a4 100644 --- a/templates/partials/packages/search.html +++ b/templates/partials/packages/search.html @@ -34,6 +34,9 @@
      + {% if not SB %} + {% set SB = 'p' %} + {% endif %} diff --git a/templates/partials/packages/search_results.html b/templates/partials/packages/search_results.html index c3b4427c..84c39079 100644 --- a/templates/partials/packages/search_results.html +++ b/templates/partials/packages/search_results.html @@ -1,3 +1,5 @@ +{% set reverse_order = "d" if SO == "a" else "a" %} + @@ -5,9 +7,10 @@ {% endif %} {% if request.user.is_authenticated() %} From dcaf407536993cce9ae37482d3fbb9c699477a4b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 17 Feb 2022 17:42:24 -0800 Subject: [PATCH 1468/1891] fix: /packages search result count We need to query for this after we've applied all filters. Signed-off-by: Kevin Morris --- aurweb/routers/packages.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 34c09d86..bc12455d 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -61,11 +61,6 @@ async def packages_get(request: Request, context: Dict[str, Any], for keyword in keywords: search.search_by(search_by, keyword) - # Collect search result count here; we've applied our keywords. - # Including more query operations below, like ordering, will - # increase the amount of time required to collect a count. - num_packages = search.count() - flagged = request.query_params.get("outdated", None) if flagged: # If outdated was given, set it up in the context. @@ -90,7 +85,12 @@ async def packages_get(request: Request, context: Dict[str, Any], search.query = search.query.filter( models.PackageBase.MaintainerUID.is_(None)) - # Apply user-specified specified sort column and ordering. + # Collect search result count here; we've applied our keywords. + # Including more query operations below, like ordering, will + # increase the amount of time required to collect a count. + num_packages = search.count() + + # Apply user-specified sort column and ordering. search.sort_by(sort_by, sort_order) # Insert search results into the context. From b2508e5bf860320d3e2644c0b87bae13acdd9ca9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 17 Feb 2022 18:27:00 -0800 Subject: [PATCH 1469/1891] upgrade: bump to v6.0.15 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index eea156f5..6284f794 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.14" +AURWEB_VERSION = "v6.0.15" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 50691228..cc6e9d2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.14" +version = "v6.0.15" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 4e641d945c3f63dac69a2fff3a0c70b8afa8e60d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Feb 2022 13:53:45 -0800 Subject: [PATCH 1470/1891] fix: unset InactivityTS for users on login Signed-off-by: Kevin Morris --- aurweb/models/user.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 871ff209..c375fcbc 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -135,6 +135,10 @@ class User(Base): if last_updated and last_updated < now_ts: self.session.SessionID = generate_unique_sid() self.session.LastUpdateTS = now_ts + + # Unset InactivityTS, we've logged in! + self.InactivityTS = 0 + break except IntegrityError as exc_: exc = exc_ From 1d86b3e210e1f7eb8ba1cb4bc29c9fc9b5681fd5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Feb 2022 15:42:35 -0800 Subject: [PATCH 1471/1891] fix: use a transaction for package query; remove refresh Closes #284 Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 0a259e1e..e8569f29 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -138,20 +138,20 @@ def updated_packages(limit: int = 0, # If we already have a cache, deserialize it and return. return orjson.loads(packages) - query = db.query(models.Package).join(models.PackageBase).filter( - models.PackageBase.PackagerUID.isnot(None) - ).order_by( - models.PackageBase.ModifiedTS.desc() - ) + with db.begin(): + query = db.query(models.Package).join(models.PackageBase).filter( + models.PackageBase.PackagerUID.isnot(None) + ).order_by( + models.PackageBase.ModifiedTS.desc() + ) - if limit: - query = query.limit(limit) + if limit: + query = query.limit(limit) packages = [] for pkg in query: # For each Package returned by the query, append a dict # containing Package columns we're interested in. - db.refresh(pkg) packages.append({ "Name": pkg.Name, "Version": pkg.Version, From 8387f325f69c4505cbd94c484577f047f06594e8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Feb 2022 13:02:28 -0800 Subject: [PATCH 1472/1891] fix: resolve null VoteTS columns via migration Somehow, many aur.al records of PackageVotes do not have a valid VoteTS value. This migration fixes that issue by setting all null VoteTS columns to the epoch timestamp. Signed-off-by: Kevin Morris --- aurweb/schema.py | 2 +- .../d64e5571bc8d_fix_pkgvote_votets.py | 37 +++++++++++++++++++ schema/gendummydata.py | 27 ++++++++------ 3 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py diff --git a/aurweb/schema.py b/aurweb/schema.py index 39550ff6..d2644541 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -269,7 +269,7 @@ PackageVotes = Table( 'PackageVotes', metadata, Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), - Column('VoteTS', BIGINT(unsigned=True)), + Column('VoteTS', BIGINT(unsigned=True), nullable=False), Index('VoteUsersIDPackageID', 'UsersID', 'PackageBaseID', unique=True), Index('VotesPackageBaseID', 'PackageBaseID'), Index('VotesUsersID', 'UsersID'), diff --git a/migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py b/migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py new file mode 100644 index 00000000..a89d97ef --- /dev/null +++ b/migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py @@ -0,0 +1,37 @@ +"""fix pkgvote votets + +Revision ID: d64e5571bc8d +Revises: be7adae47ac3 +Create Date: 2022-02-18 12:47:05.322766 + +""" +from datetime import datetime + +import sqlalchemy as sa + +from alembic import op + +from aurweb import db +from aurweb.models import PackageVote + +# revision identifiers, used by Alembic. +revision = 'd64e5571bc8d' +down_revision = 'be7adae47ac3' +branch_labels = None +depends_on = None + +table = PackageVote.__tablename__ +column = 'VoteTS' +epoch = datetime(1970, 1, 1) + + +def upgrade(): + with db.begin(): + records = db.query(PackageVote).filter(PackageVote.VoteTS.is_(None)) + for record in records: + record.VoteTS = epoch.timestamp() + op.alter_column(table, column, existing_type=sa.BIGINT(), nullable=False) + + +def downgrade(): + op.alter_column(table, column, existing_type=sa.BIGINT(), nullable=True) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index 275b3601..aedfda7e 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -16,6 +16,8 @@ import random import sys import time +from datetime import datetime + import bcrypt LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output @@ -203,7 +205,7 @@ for u in user_keys: log.debug("Number of developers: %d" % len(developers)) log.debug("Number of trusted users: %d" % len(trustedusers)) -log.debug("Number of users: %d" % (MAX_USERS-len(developers)-len(trustedusers))) +log.debug("Number of users: %d" % (MAX_USERS - len(developers) - len(trustedusers))) log.debug("Number of packages: %d" % MAX_PKGS) log.debug("Gathering text from fortune file...") @@ -244,26 +246,27 @@ for p in list(seen_pkgs.keys()): # num_comments = random.randrange(PKG_CMNTS[0], PKG_CMNTS[1]) for i in range(0, num_comments): - now = NOW + random.randrange(400, 86400*3) + now = NOW + random.randrange(400, 86400 * 3) s = ("INSERT INTO PackageComments (PackageBaseID, UsersID," " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n") s = s % (seen_pkgs[p], genUID(), genFortune(), now) out.write(s) # Cast votes -# +utcnow = int(datetime.utcnow().timestamp()) + track_votes = {} log.debug("Casting votes for packages.") for u in user_keys: - num_votes = random.randrange(int(len(seen_pkgs)*VOTING[0]), - int(len(seen_pkgs)*VOTING[1])) + num_votes = random.randrange(int(len(seen_pkgs) * VOTING[0]), + int(len(seen_pkgs) * VOTING[1])) pkgvote = {} for v in range(num_votes): pkg = random.randrange(1, len(seen_pkgs) + 1) if pkg not in pkgvote: - s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID)" - " VALUES (%d, %d);\n") - s = s % (seen_users[u], pkg) + s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS)" + " VALUES (%d, %d, %d);\n") + s = s % (seen_users[u], pkg, utcnow) pkgvote[pkg] = 1 if pkg not in track_votes: track_votes[pkg] = 0 @@ -318,14 +321,14 @@ for p in seen_pkgs_keys: # log.debug("Creating SQL statements for trusted user proposals.") count = 0 -for t in range(0, OPEN_PROPOSALS+CLOSE_PROPOSALS): +for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS): now = int(time.time()) if count < CLOSE_PROPOSALS: - start = now - random.randrange(3600*24*7, 3600*24*21) - end = now - random.randrange(0, 3600*24*7) + start = now - random.randrange(3600 * 24 * 7, 3600 * 24 * 21) + end = now - random.randrange(0, 3600 * 24 * 7) else: start = now - end = now + random.randrange(3600*24, 3600*24*7) + end = now + random.randrange(3600 * 24, 3600 * 24 * 7) if count % 5 == 0: # Don't make the vote about anyone once in a while user = "" else: From 14347232fdf6c834270df23e923ca0940d7c7ba3 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Feb 2022 16:41:43 -0800 Subject: [PATCH 1473/1891] fix: treat all keywords as lowercase when updating In addition, treat package search by keywords as lowercase. Closes #296, #297, #298, #301 Signed-off-by: Kevin Morris --- aurweb/packages/search.py | 1 + aurweb/routers/pkgbase.py | 32 ++++++++++++++++++-------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index b0e1e891..4a6eb75f 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -124,6 +124,7 @@ class PackageSearch: def _search_by_keywords(self, keywords: Set[str]) -> orm.Query: self._join_user() self._join_keywords() + keywords = set(k.lower() for k in keywords) self.query = self.query.filter(PackageKeyword.Keyword.in_(keywords)) return self diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 4c0b8a67..2cef5436 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -95,24 +95,28 @@ async def pkgbase_flag_comment(request: Request, name: str): async def pkgbase_keywords(request: Request, name: str, keywords: str = Form(default=str())): pkgbase = get_pkg_or_base(name, PackageBase) - keywords = set(keywords.split(" ")) + + # Lowercase all keywords. Our database table is case insensitive, + # and providing CI duplicates of keywords is erroneous. + keywords = set(k.lower() for k in keywords.split(" ")) # Delete all keywords which are not supplied by the user. - other_keywords = pkgbase.keywords.filter( - ~PackageKeyword.Keyword.in_(keywords)) - other_keyword_strings = [kwd.Keyword for kwd in other_keywords] - - existing_keywords = set( - kwd.Keyword for kwd in - pkgbase.keywords.filter( - ~PackageKeyword.Keyword.in_(other_keyword_strings)) - ) with db.begin(): + other_keywords = pkgbase.keywords.filter( + ~PackageKeyword.Keyword.in_(keywords)) + other_keyword_strings = set( + kwd.Keyword.lower() for kwd in other_keywords) + + existing_keywords = set( + kwd.Keyword.lower() for kwd in + pkgbase.keywords.filter( + ~PackageKeyword.Keyword.in_(other_keyword_strings)) + ) + db.delete_all(other_keywords) - for keyword in keywords.difference(existing_keywords): - db.create(PackageKeyword, - PackageBase=pkgbase, - Keyword=keyword) + new_keywords = keywords.difference(existing_keywords) + for keyword in new_keywords: + db.create(PackageKeyword, PackageBase=pkgbase, Keyword=keyword) return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) From e43e1c6d2007de41d1dbc190bb859cb8c5a4c256 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Feb 2022 17:17:14 -0800 Subject: [PATCH 1474/1891] upgrade: bump to v6.0.16 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 6284f794..ba6c0aea 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.15" +AURWEB_VERSION = "v6.0.16" _parser = None diff --git a/pyproject.toml b/pyproject.toml index cc6e9d2e..955e004d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.15" +version = "v6.0.16" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 7cc20cd9a46d149d9b766642d0bd09f0e3c3a633 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Feb 2022 17:44:06 -0800 Subject: [PATCH 1475/1891] fix: suspended users should not be able to login Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 12 +++++++++--- test/test_auth_routes.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index fc5209ce..9f465388 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -46,13 +46,19 @@ async def login_post(request: Request, raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=_("Bad Referer header.")) - user = db.query(User).filter( - or_(User.Username == user, User.Email == user) - ).first() + with db.begin(): + user = db.query(User).filter( + or_(User.Username == user, User.Email == user) + ).first() + if not user: return await login_template(request, next, errors=["Bad username or password."]) + if user.Suspended: + return await login_template(request, next, + errors=["Account Suspended"]) + cookie_timeout = cookies.timeout(remember_me) sid = user.login(request, passwd, cookie_timeout) if not sid: diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 79b34b6b..8467adea 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -14,6 +14,7 @@ from aurweb.asgi import app from aurweb.models.account_type import USER_ID from aurweb.models.session import Session from aurweb.models.user import User +from aurweb.testing.html import get_errors # Some test global constants. TEST_USERNAME = "test" @@ -79,6 +80,21 @@ def test_login_logout(client: TestClient, user: User): assert "AURSID" not in response.cookies +def test_login_suspended(client: TestClient, user: User): + with db.begin(): + user.Suspended = 1 + + data = { + "user": user.Username, + "passwd": "testPassword", + "next": "/" + } + with client as request: + resp = request.post("/login", data=data) + errors = get_errors(resp.text) + assert errors[0].text.strip() == "Account Suspended" + + def test_login_email(client: TestClient, user: user): post_data = { "user": user.Email, From 388e64d0aff3a85108f9e0b0bffd4cababbbee6b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 18 Feb 2022 17:54:36 -0800 Subject: [PATCH 1476/1891] upgrade: bump to v6.0.17 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index ba6c0aea..61b60402 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.16" +AURWEB_VERSION = "v6.0.17" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 955e004d..89b149a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.16" +version = "v6.0.17" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From c83c5cdc4227b025ba74b3c5db4d06ea06b33668 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Feb 2022 11:28:16 -0800 Subject: [PATCH 1477/1891] change: log out details about PROMETHEUS_MULTIPROC_DIR Additionally, respond with a 503 if the var is not set when /metrics is requested. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 4 ++++ aurweb/routers/html.py | 10 +++++++--- test/test_asgi.py | 11 +++++++++++ test/test_html.py | 15 +++++++++++++-- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index ad0b7ca0..fa2526ed 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -74,6 +74,10 @@ async def app_startup(): if not session_secret: raise Exception("[fastapi] session_secret must not be empty") + if not os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): + logger.warning("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " + "endpoint is disabled.") + app.mount("/static/css", StaticFiles(directory="web/html/css"), name="static_css") diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index b9d291d2..d31a32c7 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -13,7 +13,7 @@ from sqlalchemy import and_, case, or_ import aurweb.config import aurweb.models.package_request -from aurweb import cookies, db, models, time, util +from aurweb import cookies, db, logging, models, time, util from aurweb.cache import db_count_cache from aurweb.exceptions import handle_form_exceptions from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID @@ -21,6 +21,7 @@ from aurweb.models.package_request import PENDING_ID from aurweb.packages.util import query_notified, query_voted, updated_packages from aurweb.templates import make_context, render_template +logger = logging.get_logger(__name__) router = APIRouter() @@ -230,9 +231,12 @@ async def archive_sha256(request: Request, archive: str): @router.get("/metrics") async def metrics(request: Request): + if not os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): + return Response("Prometheus metrics are not enabled.", + status_code=HTTPStatus.SERVICE_UNAVAILABLE) + registry = CollectorRegistry() - if os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): # pragma: no cover - multiprocess.MultiProcessCollector(registry) + multiprocess.MultiProcessCollector(registry) data = generate_latest(registry) headers = { "Content-Type": CONTENT_TYPE_LATEST, diff --git a/test/test_asgi.py b/test/test_asgi.py index 667ae871..c693a3a9 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -104,6 +104,17 @@ async def test_asgi_app_unsupported_backends(): await aurweb.asgi.app_startup() +@pytest.mark.asyncio +async def test_asgi_app_disabled_metrics(caplog: pytest.LogCaptureFixture): + env = {"PROMETHEUS_MULTIPROC_DIR": str()} + with mock.patch.dict(os.environ, env): + await aurweb.asgi.app_startup() + + expected = ("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " + "endpoint is disabled.") + assert expected in caplog.text + + @pytest.fixture def use_traceback(): config_getboolean = aurweb.config.getboolean diff --git a/test/test_html.py b/test/test_html.py index b97d3571..ffe2a9f2 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -160,12 +160,23 @@ def test_archive_sig_404(client: TestClient): def test_metrics(client: TestClient): - with client as request: - resp = request.get("/metrics") + with tempfile.TemporaryDirectory() as tmpdir: + env = {"PROMETHEUS_MULTIPROC_DIR": tmpdir} + with mock.patch.dict(os.environ, env): + with client as request: + resp = request.get("/metrics") assert resp.status_code == int(HTTPStatus.OK) assert resp.headers.get("Content-Type").startswith("text/plain") +def test_disabled_metrics(client: TestClient): + env = {"PROMETHEUS_MULTIPROC_DIR": str()} + with mock.patch.dict(os.environ, env): + with client as request: + resp = request.get("/metrics") + assert resp.status_code == int(HTTPStatus.SERVICE_UNAVAILABLE) + + def test_rtl(client: TestClient): responses = {} expected = [ From 4a4fd015635c9a392f224eba51ed588c758fa441 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Feb 2022 16:01:06 -0800 Subject: [PATCH 1478/1891] fix: blanking out particular fields when editing accounts Signed-off-by: Kevin Morris --- aurweb/users/update.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aurweb/users/update.py b/aurweb/users/update.py index 8e42765e..5a32fd01 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -19,11 +19,11 @@ def simple(U: str = str(), E: str = str(), H: bool = False, user.Username = U or user.Username user.Email = E or user.Email user.HideEmail = strtobool(H) - user.BackupEmail = BE or user.BackupEmail - user.RealName = R or user.RealName - user.Homepage = HP or user.Homepage - user.IRCNick = I or user.IRCNick - user.PGPKey = K or user.PGPKey + user.BackupEmail = user.BackupEmail if BE is None else BE + user.RealName = user.RealName if R is None else R + user.Homepage = user.Homepage if HP is None else HP + user.IRCNick = user.IRCNick if I is None else I + user.PGPKey = user.PGPKey if K is None else K user.Suspended = strtobool(S) user.InactivityTS = now * int(strtobool(J)) user.CommentNotify = strtobool(CN) From 80622cc96611d36ee8b63eb3c95d952e290668b6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Feb 2022 16:12:15 -0800 Subject: [PATCH 1479/1891] fix: suspend check should check Suspended... This was causing some false negative errors in the update process, and it clearly not correct -- oops :( Signed-off-by: Kevin Morris --- aurweb/users/validate.py | 5 +++-- test/test_accounts_routes.py | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/aurweb/users/validate.py b/aurweb/users/validate.py index 26f6eec6..de51e3ff 100644 --- a/aurweb/users/validate.py +++ b/aurweb/users/validate.py @@ -15,6 +15,7 @@ from aurweb.captcha import get_captcha_answer, get_captcha_salts, get_captcha_to from aurweb.exceptions import ValidationError from aurweb.models.account_type import ACCOUNT_TYPE_NAME from aurweb.models.ssh_pub_key import get_fingerprint +from aurweb.util import strtobool logger = logging.get_logger(__name__) @@ -26,9 +27,9 @@ def invalid_fields(E: str = str(), U: str = str(), **kwargs) -> None: def invalid_suspend_permission(request: Request = None, user: models.User = None, - J: bool = False, + S: str = "False", **kwargs) -> None: - if not request.user.is_elevated() and J != bool(user.InactivityTS): + if not request.user.is_elevated() and strtobool(S) != bool(user.Suspended): raise ValidationError([ "You do not have permission to suspend accounts."]) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index e532e341..37b3d130 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -916,13 +916,13 @@ def test_post_account_edit_error_invalid_password(client: TestClient, assert "Invalid password." in content -def test_post_account_edit_inactivity_unauthorized(client: TestClient, - user: User): +def test_post_account_edit_suspend_unauthorized(client: TestClient, + user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} post_data = { "U": "test", "E": "test@example.org", - "J": True, + "S": True, "passwd": "testPassword" } with client as request: From 1e31db47ab20d86a0b0c943299113c3daaf6089c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 19 Feb 2022 16:32:49 -0800 Subject: [PATCH 1480/1891] upgrade: bump to v6.0.18 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 61b60402..b7aa3027 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.17" +AURWEB_VERSION = "v6.0.18" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 89b149a8..0b21a643 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.17" +version = "v6.0.18" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 6e837e0c023404e0a1c43dbdfde0826acb1f3381 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 21 Feb 2022 10:25:01 +0000 Subject: [PATCH 1481/1891] fix: always provide a path https://github.com/stephenhillier/starlette_exporter/commit/891efcd142da5a13f72ec9647ad0b8aca21075a8 --- aurweb/prometheus.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index dae56320..73be3ef6 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -70,9 +70,17 @@ def http_requests_total() -> Callable[[Info], None]: if not (scope.get("endpoint", None) and scope.get("router", None)): return None + root_path = scope.get("root_path", "") + app = scope.get("app", {}) + + if hasattr(app, "root_path"): + app_root_path = getattr(app, "root_path") + if root_path.startswith(app_root_path): + root_path = root_path[len(app_root_path):] + base_scope = { "type": scope.get("type"), - "path": scope.get("root_path", "") + scope.get("path"), + "path": root_path + scope.get("path"), "path_params": scope.get("path_params", {}), "method": scope.get("method") } From 9f452a62e58ee6212e64e476c69f19dbdbfffb48 Mon Sep 17 00:00:00 2001 From: Colin Woodbury Date: Mon, 21 Feb 2022 11:56:57 -0800 Subject: [PATCH 1482/1891] docs: fix link formatting in CONTRIBUTING --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1b0da60..2deaf237 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Before sending patches, you are recommended to run `flake8` and `isort`. You can add a git hook to do this by installing `python-pre-commit` and running `pre-commit install`. -[1] https://lists.archlinux.org/listinfo/aur-dev +[1]: https://lists.archlinux.org/listinfo/aur-dev ### Coding Guidelines From 7c3637971571c1b5757d634aa627a91ff96999da Mon Sep 17 00:00:00 2001 From: Colin Woodbury Date: Mon, 21 Feb 2022 14:18:26 -0800 Subject: [PATCH 1483/1891] docs(docker): basic usage instructions --- docker/README.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 docker/README.md diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 00000000..dceee74f --- /dev/null +++ b/docker/README.md @@ -0,0 +1,39 @@ +# Aurweb and Docker + +The `INSTALL` document details a manual Aurweb setup, but Docker images are also +provided here to avoid the complications of database configuration (and so +forth). + +### Setup + +Naturally, both `docker` and `docker-compose` must be installed, and your Docker +service must be started: + +```sh +systemctl start docker.service +``` + +The main image - `aurweb` - must be built manually: + +```sh +docker compose build aurweb-image +``` + +### Starting and Stopping the Services + +With the above steps complete, you can bring up an initial cluster: + +```sh +docker compose up +``` + +Subsequent runs will be done with `start` instead of `up`. The cluster can be +stopped with `docker compose stop`. + +### Testing + +With a running cluster, execute the following in a new terminal: + +```sh +docker compose run test +``` From 27f30212e83609fafe2081f3366d376f5ecf69df Mon Sep 17 00:00:00 2001 From: Colin Woodbury Date: Mon, 21 Feb 2022 14:40:18 -0800 Subject: [PATCH 1484/1891] docs(docker): note ports and `curl` usage --- docker/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docker/README.md b/docker/README.md index dceee74f..6fa2f142 100644 --- a/docker/README.md +++ b/docker/README.md @@ -37,3 +37,14 @@ With a running cluster, execute the following in a new terminal: ```sh docker compose run test ``` + +### Querying the RPC + +The Fast (Python) API runs on Port 8444, while the legacy PHP version runs +on 8443. You can query one like so: + +```sh +curl -k "https://localhost:8444/rpc/?v=5&type=search&arg=python" +``` + +`-k` bypasses local certificate issues that `curl` will otherwise complain about. From 3aa8d523f5ee6beb13a9e981e2f8754f79c54578 Mon Sep 17 00:00:00 2001 From: Colin Woodbury Date: Mon, 21 Feb 2022 16:49:38 -0800 Subject: [PATCH 1485/1891] change(rpc): `search` module reformatting --- aurweb/packages/search.py | 93 +++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 4a6eb75f..5ba72652 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -12,7 +12,7 @@ from aurweb.models.package_vote import PackageVote class PackageSearch: - """ A Package search query builder. """ + """A Package search query builder.""" # A constant mapping of short to full name sort orderings. FULL_SORT_ORDER = {"d": "desc", "a": "asc"} @@ -24,14 +24,18 @@ class PackageSearch: if self.user: self.query = self.query.join( PackageVote, - and_(PackageVote.PackageBaseID == PackageBase.ID, - PackageVote.UsersID == self.user.ID), - isouter=True + and_( + PackageVote.PackageBaseID == PackageBase.ID, + PackageVote.UsersID == self.user.ID, + ), + isouter=True, ).join( PackageNotification, - and_(PackageNotification.PackageBaseID == PackageBase.ID, - PackageNotification.UserID == self.user.ID), - isouter=True + and_( + PackageNotification.PackageBaseID == PackageBase.ID, + PackageNotification.UserID == self.user.ID, + ), + isouter=True, ) self.ordering = "d" @@ -47,7 +51,7 @@ class PackageSearch: "m": self._search_by_maintainer, "c": self._search_by_comaintainer, "M": self._search_by_co_or_maintainer, - "s": self._search_by_submitter + "s": self._search_by_submitter, } # Setup SB (Sort By) callbacks. @@ -58,7 +62,7 @@ class PackageSearch: "w": self._sort_by_voted, "o": self._sort_by_notify, "m": self._sort_by_maintainer, - "l": self._sort_by_last_modified + "l": self._sort_by_last_modified, } self._joined_user = False @@ -66,12 +70,10 @@ class PackageSearch: self._joined_comaint = False def _join_user(self, outer: bool = True) -> orm.Query: - """ Centralized joining of a package base's maintainer. """ + """Centralized joining of a package base's maintainer.""" if not self._joined_user: self.query = self.query.join( - User, - User.ID == PackageBase.MaintainerUID, - isouter=outer + User, User.ID == PackageBase.MaintainerUID, isouter=outer ) self._joined_user = True return self.query @@ -87,7 +89,7 @@ class PackageSearch: self.query = self.query.join( PackageComaintainer, PackageComaintainer.PackageBaseID == PackageBase.ID, - isouter=isouter + isouter=isouter, ) self._joined_comaint = True return self.query @@ -95,8 +97,10 @@ class PackageSearch: def _search_by_namedesc(self, keywords: str) -> orm.Query: self._join_user() self.query = self.query.filter( - or_(Package.Name.like(f"%{keywords}%"), - Package.Description.like(f"%{keywords}%")) + or_( + Package.Name.like(f"%{keywords}%"), + Package.Description.like(f"%{keywords}%"), + ) ) return self @@ -132,8 +136,7 @@ class PackageSearch: self._join_user() if keywords: self.query = self.query.filter( - and_(User.Username == keywords, - User.ID == PackageBase.MaintainerUID) + and_(User.Username == keywords, User.ID == PackageBase.MaintainerUID) ) else: self.query = self.query.filter(PackageBase.MaintainerUID.is_(None)) @@ -197,8 +200,7 @@ class PackageSearch: # in terms of performance. We should improve this; there's no # reason it should take _longer_. column = getattr( - case([(models.PackageVote.UsersID == self.user.ID, 1)], else_=0), - order + case([(models.PackageVote.UsersID == self.user.ID, 1)], else_=0), order ) name = getattr(models.Package.Name, order) self.query = self.query.order_by(column(), name()) @@ -209,9 +211,8 @@ class PackageSearch: # in terms of performance. We should improve this; there's no # reason it should take _longer_. column = getattr( - case([(models.PackageNotification.UserID == self.user.ID, 1)], - else_=0), - order + case([(models.PackageNotification.UserID == self.user.ID, 1)], else_=0), + order, ) name = getattr(models.Package.Name, order) self.query = self.query.order_by(column(), name()) @@ -239,16 +240,16 @@ class PackageSearch: return callback(ordering) def count(self) -> int: - """ Return internal query's count. """ + """Return internal query's count.""" return self.query.count() def results(self) -> orm.Query: - """ Return internal query. """ + """Return internal query.""" return self.query class RPCSearch(PackageSearch): - """ A PackageSearch-derived RPC package search query builder. + """A PackageSearch-derived RPC package search query builder. With RPC search, we need a subset of PackageSearch's handlers, with a few additional handlers added. So, within the RPCSearch @@ -270,52 +271,60 @@ class RPCSearch(PackageSearch): # We keep: "nd", "n" and "m". We also overlay four new by params # on top: "depends", "makedepends", "optdepends" and "checkdepends". self.search_by_cb = { - k: v for k, v in self.search_by_cb.items() + k: v + for k, v in self.search_by_cb.items() if k not in RPCSearch.keys_removed } - self.search_by_cb.update({ - "depends": self._search_by_depends, - "makedepends": self._search_by_makedepends, - "optdepends": self._search_by_optdepends, - "checkdepends": self._search_by_checkdepends - }) + self.search_by_cb.update( + { + "depends": self._search_by_depends, + "makedepends": self._search_by_makedepends, + "optdepends": self._search_by_optdepends, + "checkdepends": self._search_by_checkdepends, + } + ) # We always want an optional Maintainer in the RPC. self._join_user() def _join_depends(self, dep_type_id: int) -> orm.Query: - """ Join Package with PackageDependency and filter results + """Join Package with PackageDependency and filter results based on `dep_type_id`. :param dep_type_id: DependencyType ID :returns: PackageDependency-joined orm.Query """ self.query = self.query.join(models.PackageDependency).filter( - models.PackageDependency.DepTypeID == dep_type_id) + models.PackageDependency.DepTypeID == dep_type_id + ) return self.query def _search_by_depends(self, keywords: str) -> "RPCSearch": self.query = self._join_depends(DEPENDS_ID).filter( - models.PackageDependency.DepName == keywords) + models.PackageDependency.DepName == keywords + ) return self def _search_by_makedepends(self, keywords: str) -> "RPCSearch": self.query = self._join_depends(MAKEDEPENDS_ID).filter( - models.PackageDependency.DepName == keywords) + models.PackageDependency.DepName == keywords + ) return self def _search_by_optdepends(self, keywords: str) -> "RPCSearch": self.query = self._join_depends(OPTDEPENDS_ID).filter( - models.PackageDependency.DepName == keywords) + models.PackageDependency.DepName == keywords + ) return self def _search_by_checkdepends(self, keywords: str) -> "RPCSearch": self.query = self._join_depends(CHECKDEPENDS_ID).filter( - models.PackageDependency.DepName == keywords) + models.PackageDependency.DepName == keywords + ) return self def search_by(self, by: str, keywords: str) -> "RPCSearch": - """ Override inherited search_by. In this override, we reduce the + """Override inherited search_by. In this override, we reduce the scope of what we handle within this function. We do not set `by` to a default of "nd" in the RPC, as the RPC returns an error when incorrect `by` fields are specified. @@ -329,6 +338,4 @@ class RPCSearch(PackageSearch): return result def results(self) -> orm.Query: - return self.query.filter( - models.PackageBase.PackagerUID.isnot(None) - ) + return self.query.filter(models.PackageBase.PackagerUID.isnot(None)) From 51d4b7f9935aa3bef34c151a417898985caf69f7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 23 Feb 2022 14:06:07 -0800 Subject: [PATCH 1486/1891] fix(rpc): limit Package results, not relationships ...This was an obvious bug in hindsight. Apologies :( Closes #314 Signed-off-by: Kevin Morris --- aurweb/rpc.py | 14 +++++++------- test/test_rpc.py | 12 ++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 6e2a27fe..70d8c2fd 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -202,7 +202,12 @@ class RPC: models.User.ID == models.PackageBase.MaintainerUID, isouter=True ).filter(models.Package.Name.in_(args)) - packages = self._entities(packages) + + max_results = config.getint("options", "max_rpc_results") + packages = self._entities(packages).limit(max_results + 1) + + if packages.count() > max_results: + raise RPCError("Too many package results.") ids = {pkg.ID for pkg in packages} @@ -274,12 +279,7 @@ class RPC: ] # Union all subqueries together. - max_results = config.getint("options", "max_rpc_results") - query = subqueries[0].union_all(*subqueries[1:]).limit( - max_results + 1).all() - - if len(query) > max_results: - raise RPCError("Too many package results.") + query = subqueries[0].union_all(*subqueries[1:]).all() # Store our extra information in a class-wise dictionary, # which contains package id -> extra info dict mappings. diff --git a/test/test_rpc.py b/test/test_rpc.py index a67a026e..0d6b2931 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -15,6 +15,7 @@ import aurweb.models.relation_type as rt from aurweb import asgi, config, db, rpc, scripts, time from aurweb.models.account_type import USER_ID +from aurweb.models.dependency_type import DEPENDS_ID from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -23,6 +24,7 @@ from aurweb.models.package_keyword import PackageKeyword from aurweb.models.package_license import PackageLicense from aurweb.models.package_relation import PackageRelation from aurweb.models.package_vote import PackageVote +from aurweb.models.relation_type import PROVIDES_ID from aurweb.models.user import User from aurweb.redis import redis_connection @@ -814,6 +816,16 @@ def test_rpc_too_many_search_results(client: TestClient, def test_rpc_too_many_info_results(client: TestClient, packages: List[Package]): + # Make many of these packages depend and rely on each other. + # This way, we can test to see that the exceeded limit stays true + # regardless of the number of related records. + with db.begin(): + for i in range(len(packages) - 1): + db.create(PackageDependency, DepTypeID=DEPENDS_ID, + Package=packages[i], DepName=packages[i + 1].Name) + db.create(PackageRelation, RelTypeID=PROVIDES_ID, + Package=packages[i], RelName=packages[i + 1].Name) + config_getint = config.getint def mock_config(section: str, key: str): From 07e479ab503b6e2cb2e363ccf731c3ea60281451 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 23 Feb 2022 14:37:41 -0800 Subject: [PATCH 1487/1891] upgrade: bump to v6.0.19 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index b7aa3027..c2b8be79 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.18" +AURWEB_VERSION = "v6.0.19" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 0b21a643..b5da9913 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.18" +version = "v6.0.19" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From d92f1838404b426c6e3baad103f4dccac1a40e03 Mon Sep 17 00:00:00 2001 From: Colin Woodbury Date: Wed, 23 Feb 2022 18:12:00 -0800 Subject: [PATCH 1488/1891] docs(docker): explain how to generate dummy data --- docker/README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index 6fa2f142..89dbb739 100644 --- a/docker/README.md +++ b/docker/README.md @@ -16,7 +16,7 @@ systemctl start docker.service The main image - `aurweb` - must be built manually: ```sh -docker compose build aurweb-image +docker compose build ``` ### Starting and Stopping the Services @@ -38,6 +38,21 @@ With a running cluster, execute the following in a new terminal: docker compose run test ``` +### Generating Dummy Data + +Before you can make meaningful queries to the cluster, it needs some data. +Luckily such data can be generated. First, `docker ps` to discover the ID of the +container running the FastAPI. Then: + +```sh +docker exec -it /bin/bash +./scheme/gendummydata.py dummy.sql +mysql aurweb < dummy.sql +``` + +The generation script may prompt you to install other Arch packages before it +can proceed. + ### Querying the RPC The Fast (Python) API runs on Port 8444, while the legacy PHP version runs From 1bb4daa36ac1e92e68a528727581bb781f3d9c00 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 23 Feb 2022 18:54:35 -0800 Subject: [PATCH 1489/1891] doc: merge CodingGuidelines into CONTRIBUTING.md Signed-off-by: Kevin Morris --- CONTRIBUTING.md | 17 ++++++++++---- doc/CodingGuidelines | 54 -------------------------------------------- 2 files changed, 13 insertions(+), 58 deletions(-) delete mode 100644 doc/CodingGuidelines diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2deaf237..2bb840f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,7 @@ # Contributing -Patches should be sent to the [aur-dev@lists.archlinux.org][1] mailing list. +Patches should be sent to the [aur-dev@lists.archlinux.org][1] mailing list +or included in a merge request on the [aurweb repository][2]. Before sending patches, you are recommended to run `flake8` and `isort`. @@ -8,12 +9,20 @@ You can add a git hook to do this by installing `python-pre-commit` and running `pre-commit install`. [1]: https://lists.archlinux.org/listinfo/aur-dev +[2]: https://gitlab.archlinunx.org/archlinux/aurweb ### Coding Guidelines -1. All source modified or added within a patchset **must** maintain equivalent - or increased coverage by providing tests that use the functionality. +DISCLAIMER: We realise the code doesn't necessarily follow all the rules. +This is an attempt to establish a standard coding style for future +development. -2. Please keep your source within an 80 column width. +1. All source modified or added within a patchset **must** maintain equivalent + or increased coverage by providing tests that use the functionality +2. Please keep your source within an 80 column width +3. Use four space indentation +4. Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) +5. DRY: Don't Repeat Yourself +6. All code should be tested for good _and_ bad cases Test patches that increase coverage in the codebase are always welcome. diff --git a/doc/CodingGuidelines b/doc/CodingGuidelines deleted file mode 100644 index 46537bb2..00000000 --- a/doc/CodingGuidelines +++ /dev/null @@ -1,54 +0,0 @@ -Coding Guidelines -================= - -DISCLAIMER: We realise the code doesn't necessarily follow all the rules. -This is an attempt to establish a standard coding style for future -development. - -Coding style ------------- - -Column width: 79 columns or less within reason. - -Indentation: tabs (standard eight column width) -Please don't add any mode lines. Adjust your editor to display tabs to your -preferred width. Generally code should work with the standard eight column -tabs. - -No short open tags. '' -Try embedding as little XHTML in the PHP as possible. -Consider creating templates for XHTML. - -All markup should conform to XHTML 1.0 Strict requirements. -You can use http://validator.w3.org to check the markup. - -Prevent PHP Notices by using isset() or empty() in conditionals that -reference $_GET, $_POST, or $_REQUEST variables. - -MySQL queries should generally go into functions. - -Submitting patches ------------------- - -!!! PLEASE TEST YOUR PATCHES BEFORE SUBMITTING !!! -Submit uncompressed git-formatted patches to aur-dev@archlinux.org. - -You will need to register on the mailing list before submitting: -https://mailman.archlinux.org/mailman/listinfo/aur-dev - -Base your patches on the master branch as forward development is done there. -When writing patches please keep unnecessary changes to a minimum. - -Try to keep your commits small and focused. -Smaller patches are much easier to review and have a better chance of being -pushed more quickly into the main repo. Smaller commits also makes reviewing -the commit history and tracking down specific changes much easier. - -Try to make your commit messages brief but descriptive. - -Glossary --------- -git-formatted patch: - A patch that is produced via `git format-patch` and is sent via - `git send-email` or as an inline attachment of an email. From 9204b76110daaeb582f373836696f05f9674ce94 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Feb 2022 19:24:29 -0800 Subject: [PATCH 1490/1891] fix: ...do not add to ActiveTUs when voting on a proposal Straight up bug. Closes #324 Signed-off-by: Kevin Morris --- aurweb/routers/trusted_user.py | 1 - test/test_trusted_user_routes.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 2d6ea92c..53bcecb7 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -220,7 +220,6 @@ async def trusted_user_proposal_post(request: Request, proposal: int, with db.begin(): vote = db.create(models.TUVote, User=request.user, VoteInfo=voteinfo) - voteinfo.ActiveTUs += 1 context["error"] = "You've already voted for this proposal." return render_proposal(request, context, proposal, voteinfo, voters, vote) diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index e2bf6497..a5c4c5e8 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -650,7 +650,6 @@ def test_tu_proposal_vote(client, proposal): # Store the current related values. yes = voteinfo.Yes - active_tus = voteinfo.ActiveTUs cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: @@ -661,7 +660,6 @@ def test_tu_proposal_vote(client, proposal): # Check that the proposal record got updated. assert voteinfo.Yes == yes + 1 - assert voteinfo.ActiveTUs == active_tus + 1 # Check that the new TUVote exists. vote = db.query(TUVote, TUVote.VoteInfo == voteinfo, From c7c79a152b50b5536d54332c0d45e57e0462aed6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 25 Feb 2022 19:44:10 -0800 Subject: [PATCH 1491/1891] upgrade: bump to v6.0.20 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index c2b8be79..ad8ea100 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.19" +AURWEB_VERSION = "v6.0.20" _parser = None diff --git a/pyproject.toml b/pyproject.toml index b5da9913..88f182be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.19" +version = "v6.0.20" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From b80d914cba0158a559162f1d019f836c004dee6b Mon Sep 17 00:00:00 2001 From: Matt Harrison Date: Mon, 7 Mar 2022 12:37:54 -0500 Subject: [PATCH 1492/1891] fix click to copy when there is more than one copy link on the page. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes issue reported on the mailing list here: https://lists.archlinux.org/pipermail/aur-general/2022-March/036833.html Thanks to Henry-Joseph Audéoud for diagnosing the issue https://lists.archlinux.org/pipermail/aur-general/2022-March/036836.html Also update the event variable to use the local copy instead of the deprecated global version https://stackoverflow.com/questions/58341832/event-is-deprecated-what-should-be-used-instead --- web/html/js/copy.js | 4 ++-- web/template/pkg_details.php | 4 ++-- web/template/pkgbase_details.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/html/js/copy.js b/web/html/js/copy.js index f46299b3..21324ccb 100644 --- a/web/html/js/copy.js +++ b/web/html/js/copy.js @@ -1,6 +1,6 @@ document.addEventListener('DOMContentLoaded', function() { - document.querySelector('.copy').addEventListener('click', function(e) { + document.querySelectorAll('.copy').addEventListener('click', function(e) { e.preventDefault(); - navigator.clipboard.writeText(event.target.text); + navigator.clipboard.writeText(e.target.text); }); }); diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 047de9a7..25d85b78 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -309,9 +309,9 @@ endif; diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index 35ad217a..bde29c1c 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -138,9 +138,9 @@ endif; From 6a243e90dbf08c3a9db8f757c11471661d18bcc1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 7 Mar 2022 23:23:49 -0800 Subject: [PATCH 1493/1891] fix: only reject addvote for users with running proposals This was incorrectly indiscriminately targetting _any_ proposal for a particular user. Signed-off-by: Kevin Morris --- aurweb/routers/trusted_user.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 53bcecb7..cbe3e47d 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -274,8 +274,10 @@ async def trusted_user_addvote_post(request: Request, context["error"] = "Username does not exist." return render_addvote(context, HTTPStatus.NOT_FOUND) + utcnow = time.utcnow() voteinfo = db.query(models.TUVoteInfo).filter( - models.TUVoteInfo.User == user).count() + and_(models.TUVoteInfo.User == user, + models.TUVoteInfo.End > utcnow)).count() if voteinfo: _ = l10n.get_translator_for_request(request) context["error"] = _( From f11e8de251af54e78043d8016b12feda38a9ec55 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 7 Mar 2022 23:32:14 -0800 Subject: [PATCH 1494/1891] upgrade: bump to v6.0.21 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index ad8ea100..9931e7d2 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.20" +AURWEB_VERSION = "v6.0.21" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 88f182be..ce081ce6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.20" +version = "v6.0.21" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 5045f0f3e464fc0fbb3229968cb07617ec48314f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 7 Mar 2022 23:53:57 -0800 Subject: [PATCH 1495/1891] fix: copy.js javascript initialization Not sure where this works, but it doesn't seem to work on my browser. Achieved the same by forEaching through the array returned by querySelectorAll instead. Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 1 - web/html/js/copy.js | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 22d519b9..e0eda54c 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -160,4 +160,3 @@
      - {% set order = SO %} {% if SB == "n" %} - {% set order = "d" if order == "a" else "a" %} + {% set order = reverse_order %} + {% else %} + {% set order = SO %} {% endif %} {{ "Name" | tr }} @@ -15,35 +18,39 @@ {{ "Version" | tr }} - {% set order = SO %} {% if SB == "v" %} - {% set order = "d" if order == "a" else "a" %} + {% set order = reverse_order %} + {% else %} + {% set order = SO %} {% endif %} {{ "Votes" | tr }} - {% set order = SO %} {% if SB == "p" %} - {% set order = "d" if order == "a" else "a" %} + {% set order = reverse_order %} + {% else %} + {% set order = SO %} {% endif %} {{ "Popularity" | tr }}? - {% set order = SO %} {% if SB == "w" %} - {% set order = "d" if order == "a" else "a" %} + {% set order = reverse_order %} + {% else %} + {% set order = SO %} {% endif %} {{ "Voted" | tr }} - {% set order = SO %} {% if SB == "o" %} - {% set order = "d" if order == "a" else "a" %} + {% set order = reverse_order %} + {% else %} + {% set order = SO %} {% endif %} {{ "Notify" | tr }} @@ -52,13 +59,14 @@ {% endif %} {{ "Description" | tr }} + {% if SB == "m" %} + {% set order = reverse_order %} + {% else %} {% set order = SO %} - {% if SB == "m" %} - {% set order = "d" if order == "a" else "a" %} - {% endif %} - - {{ "Maintainer" | tr }} - + {% endif %} + + {{ "Maintainer" | tr }} +
      - diff --git a/web/html/js/copy.js b/web/html/js/copy.js index 21324ccb..3b659270 100644 --- a/web/html/js/copy.js +++ b/web/html/js/copy.js @@ -1,6 +1,9 @@ document.addEventListener('DOMContentLoaded', function() { - document.querySelectorAll('.copy').addEventListener('click', function(e) { - e.preventDefault(); - navigator.clipboard.writeText(e.target.text); - }); + let elements = document.querySelectorAll('.copy'); + elements.forEach(function(el) { + el.addEventListener('click', function(e) { + e.preventDefault(); + navigator.clipboard.writeText(e.target.text); + }); + }); }); From e2a17fef95385f0a7cae4216d28b5789b84facce Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 7 Mar 2022 23:57:54 -0800 Subject: [PATCH 1496/1891] upgrade: bump to v6.0.22 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 9931e7d2..d0b095f0 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.21" +AURWEB_VERSION = "v6.0.22" _parser = None diff --git a/pyproject.toml b/pyproject.toml index ce081ce6..f2401b88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.21" +version = "v6.0.22" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 13217be939278a483e77e46fd1e1dd5081d7a829 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 17:49:21 -0800 Subject: [PATCH 1497/1891] fix: don't check suspension for ownership changes People can change comaintainer ownership to suspended users if they want to. Suspended users cannot login, so there is no breach of security here. It does make sense to allow ownership to be changed, imo. Closes #339 Signed-off-by: Kevin Morris --- aurweb/scripts/notify.py | 5 +---- aurweb/testing/email.py | 9 +++++++++ test/test_notify.py | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index c823b09e..dbef3aa5 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -399,10 +399,7 @@ class ComaintainershipEventNotification(Notification): self._pkgbase = db.query(PackageBase.Name).filter( PackageBase.ID == pkgbase_id).first().Name - user = db.query(User).filter( - and_(User.ID == uid, - User.Suspended == 0) - ).with_entities( + user = db.query(User).filter(User.ID == uid).with_entities( User.Email, User.LangPreference ).first() diff --git a/aurweb/testing/email.py b/aurweb/testing/email.py index c0be2797..b3e3990b 100644 --- a/aurweb/testing/email.py +++ b/aurweb/testing/email.py @@ -37,6 +37,15 @@ class Email: if autoparse: self._parse() + @staticmethod + def reset() -> None: + # Cleanup all email files for this test suite. + prefix = Email.email_prefix(suite=True) + files = os.listdir(Email.TEST_DIR) + for file in files: + if file.startswith(prefix): + os.remove(os.path.join(Email.TEST_DIR, file)) + @staticmethod def email_prefix(suite: bool = False) -> str: """ diff --git a/test/test_notify.py b/test/test_notify.py index a8e994c5..2009e3a8 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -299,6 +299,21 @@ You were removed from the co-maintainer list of {pkgbase.Name} [1]. assert email.body == expected +def test_suspended_ownership_change(user: User, pkgbases: List[PackageBase]): + with db.begin(): + user.Suspended = 1 + + pkgbase = pkgbases[0] + notif = notify.ComaintainerAddNotification(user.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + Email.reset() # Clear the Email pool + notif = notify.ComaintainerRemoveNotification(user.ID, pkgbase.ID) + notif.send() + assert Email.count() == 1 + + def test_delete(user: User, user2: User, pkgbases: List[PackageBase]): pkgbase = pkgbases[0] notif = notify.DeleteNotification(user2.ID, pkgbase.ID) From e00cf5f1249b522e58fb0651ae8b00e7b74c6ab2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 17:51:44 -0800 Subject: [PATCH 1498/1891] test: use smtplib.SMTP[_SSL] timeout = notifications.smtp-timeout A new option has been added for configuration of SMTP timeout: - notifications.smtp-timeout During tests, we can change this timeout to be small, so we aren't depending on hardware-based RNG to pass the timeout. Without a timeout, users can run into a long-running test for no particular reason. Signed-off-by: Kevin Morris --- aurweb/scripts/notify.py | 5 +++- aurweb/testing/smtp.py | 3 +++ conf/config.defaults | 1 + test/test_notify.py | 49 ++++++++++++++++++++++++---------------- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index dbef3aa5..6afa65ae 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -104,7 +104,10 @@ class Notification: False: smtplib.SMTP, True: smtplib.SMTP_SSL, } - server = classes[use_ssl](server_addr, server_port) + smtp_timeout = aurweb.config.getint("notifications", + "smtp-timeout") + server = classes[use_ssl](server_addr, server_port, + timeout=smtp_timeout) if use_starttls: server.ehlo() diff --git a/aurweb/testing/smtp.py b/aurweb/testing/smtp.py index da64c93f..e5d67991 100644 --- a/aurweb/testing/smtp.py +++ b/aurweb/testing/smtp.py @@ -36,6 +36,9 @@ class FakeSMTP: def quit(self) -> None: self.quit_count += 1 + def __call__(self, *args, **kwargs) -> "FakeSMTP": + return self + class FakeSMTP_SSL(FakeSMTP): """ A fake version of smtplib.SMTP_SSL used for testing. """ diff --git a/conf/config.defaults b/conf/config.defaults index 371c99b2..722802cc 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -65,6 +65,7 @@ smtp-use-ssl = 0 smtp-use-starttls = 0 smtp-user = smtp-password = +smtp-timeout = 60 sender = notify@aur.archlinux.org reply-to = noreply@aur.archlinux.org diff --git a/test/test_notify.py b/test/test_notify.py index 2009e3a8..fdec5ed7 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -547,18 +547,18 @@ def test_smtp(user: User): with db.begin(): user.ResetKey = "12345678901234567890123456789012" - SMTP = FakeSMTP() + smtp = FakeSMTP() get = "aurweb.config.get" getboolean = "aurweb.config.getboolean" with mock.patch(get, side_effect=mock_smtp_config(str)): with mock.patch(getboolean, side_effect=mock_smtp_config(bool)): - with mock.patch("smtplib.SMTP", side_effect=lambda a, b: SMTP): + with mock.patch("smtplib.SMTP", side_effect=smtp): config.rehash() notif = notify.WelcomeNotification(user.ID) notif.send() config.rehash() - assert len(SMTP.emails) == 1 + assert len(smtp.emails) == 1 def mock_smtp_starttls_config(cls): @@ -586,25 +586,25 @@ def test_smtp_starttls(user: User): user.ResetKey = "12345678901234567890123456789012" user.BackupEmail = "backup@example.org" - SMTP = FakeSMTP() + smtp = FakeSMTP() get = "aurweb.config.get" getboolean = "aurweb.config.getboolean" with mock.patch(get, side_effect=mock_smtp_starttls_config(str)): with mock.patch( getboolean, side_effect=mock_smtp_starttls_config(bool)): - with mock.patch("smtplib.SMTP", side_effect=lambda a, b: SMTP): + with mock.patch("smtplib.SMTP", side_effect=smtp): notif = notify.WelcomeNotification(user.ID) notif.send() - assert SMTP.starttls_enabled - assert SMTP.user - assert SMTP.passwd + assert smtp.starttls_enabled + assert smtp.user + assert smtp.passwd - assert len(SMTP.emails) == 2 - to = SMTP.emails[0][1] + assert len(smtp.emails) == 2 + to = smtp.emails[0][1] assert to == [user.Email] - to = SMTP.emails[1][1] + to = smtp.emails[1][1] assert to == [user.BackupEmail] @@ -629,19 +629,19 @@ def test_smtp_ssl(user: User): with db.begin(): user.ResetKey = "12345678901234567890123456789012" - SMTP = FakeSMTP_SSL() + smtp = FakeSMTP_SSL() get = "aurweb.config.get" getboolean = "aurweb.config.getboolean" with mock.patch(get, side_effect=mock_smtp_ssl_config(str)): with mock.patch(getboolean, side_effect=mock_smtp_ssl_config(bool)): - with mock.patch("smtplib.SMTP_SSL", side_effect=lambda a, b: SMTP): + with mock.patch("smtplib.SMTP_SSL", side_effect=smtp): notif = notify.WelcomeNotification(user.ID) notif.send() - assert len(SMTP.emails) == 1 - assert SMTP.use_ssl - assert SMTP.user - assert SMTP.passwd + assert len(smtp.emails) == 1 + assert smtp.use_ssl + assert smtp.user + assert smtp.passwd def test_notification_defaults(): @@ -655,6 +655,7 @@ def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture): """ Try sending a notification with a bad SMTP configuration. """ caplog.set_level(ERROR) config_get = config.get + config_getint = config.getint mocked_options = { "sendmail": str(), @@ -662,8 +663,9 @@ def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture): "smtp-port": "587", "smtp-user": "notify@server.xyz", "smtp-password": "notify_server_xyz", + "smtp-timeout": 1, "sender": "notify@server.xyz", - "reply-to": "no-reply@server.xyz" + "reply-to": "no-reply@server.xyz", } def mock_config_get(section: str, key: str) -> str: @@ -672,9 +674,16 @@ def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture): return mocked_options.get(key) return config_get(section, key) + def mock_config_getint(section: str, key: str) -> str: + if section == "notifications": + if key in mocked_options: + return mocked_options.get(key) + return config_getint(section, key) + notif = notify.WelcomeNotification(user.ID) - with mock.patch("aurweb.config.get", side_effect=mock_config_get): - notif.send() + with mock.patch("aurweb.config.getint", side_effect=mock_config_getint): + with mock.patch("aurweb.config.get", side_effect=mock_config_get): + notif.send() expected = "Unable to emit notification due to an OSError" assert expected in caplog.text From 2a393f95faa8a4952faf22b1cbcb4e0c8e8318ae Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 17:59:00 -0800 Subject: [PATCH 1499/1891] upgrade: bump to v6.0.23 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index d0b095f0..637024de 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.22" +AURWEB_VERSION = "v6.0.23" _parser = None diff --git a/pyproject.toml b/pyproject.toml index f2401b88..e930a331 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.22" +version = "v6.0.23" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From a1a88ea8729f4eafee396197d40fa8a290716bfa Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 19:00:19 -0800 Subject: [PATCH 1500/1891] fix(rpc): suggestions should only suggest based on % Previously, Python code was looking for suggestions based on `%%`. This was inconsistent with PHP's suggestion implementation and cause more records to be bundled with a suggestion, along with supplying misleading suggestions. Closes #343 Signed-off-by: Kevin Morris --- aurweb/rpc.py | 5 +++-- test/test_rpc.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 70d8c2fd..5bc6b80d 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -332,7 +332,7 @@ class RPC: models.PackageBase ).filter( and_(models.PackageBase.PackagerUID.isnot(None), - models.Package.Name.like(f"%{arg}%")) + models.Package.Name.like(f"{arg}%")) ).order_by(models.Package.Name.asc()).limit(20) return [pkg.Name for pkg in packages] @@ -341,9 +341,10 @@ class RPC: if not args: return [] + arg = args[0] packages = db.query(models.PackageBase.Name).filter( and_(models.PackageBase.PackagerUID.isnot(None), - models.PackageBase.Name.like(f"%{args[0]}%")) + models.PackageBase.Name.like(f"{arg}%")) ).order_by(models.PackageBase.Name.asc()).limit(20) return [pkg.Name for pkg in packages] diff --git a/test/test_rpc.py b/test/test_rpc.py index 0d6b2931..2f7f7860 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -551,6 +551,14 @@ def test_rpc_suggest_pkgbase(client: TestClient, packages: List[Package]): data = response.json() assert data == [] + # Test that suggestions are only given based on the beginning + # of the keyword string. + params["arg"] = "ther-pkg" + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + assert data == [] + def test_rpc_suggest(client: TestClient, packages: List[Package]): params = {"v": 5, "type": "suggest", "arg": "other"} @@ -573,6 +581,14 @@ def test_rpc_suggest(client: TestClient, packages: List[Package]): data = response.json() assert data == [] + # Test that suggestions are only given based on the beginning + # of the keyword string. + params["arg"] = "ther-pkg" + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + assert data == [] + def mock_config_getint(section: str, key: str): if key == "request_limit": From 0afa07ed3b895efd84adfba8e54a342065c54f78 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 19:16:02 -0800 Subject: [PATCH 1501/1891] upgrade: bump to v6.0.24 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 637024de..287152d4 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.23" +AURWEB_VERSION = "v6.0.24" _parser = None diff --git a/pyproject.toml b/pyproject.toml index e930a331..7a2f6ca3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.23" +version = "v6.0.24" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 49c5a3facf096e9b0a1905e5ee38fe8750a5bb63 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 20:28:09 -0800 Subject: [PATCH 1502/1891] feat: display stats about total & active TUs on proposals This patch brings in two new features: - when viewing proposal listings, there is a new Statistics section, containing the total and active number of Trusted Users found in the database. - when viewing a proposal directly, the number of active trusted users assigned when the proposal was added is now displayed in the details section. Closes #323 Signed-off-by: Kevin Morris --- aurweb/routers/trusted_user.py | 20 +++++++++ po/aurweb.pot | 4 ++ templates/partials/tu/proposal/details.html | 5 +++ templates/tu/index.html | 16 +++++++ test/test_trusted_user_routes.py | 49 +++++++++++++++++++++ web/html/css/aurweb.css | 13 ++++++ 6 files changed, 107 insertions(+) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index cbe3e47d..3f0eb836 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -2,6 +2,7 @@ import html import typing from http import HTTPStatus +from typing import Any, Dict from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import RedirectResponse, Response @@ -33,6 +34,21 @@ ADDVOTE_SPECIFICS = { } +def populate_trusted_user_counts(context: Dict[str, Any]) -> None: + tu_query = db.query(User).filter( + or_(User.AccountTypeID == TRUSTED_USER_ID, + User.AccountTypeID == TRUSTED_USER_AND_DEV_ID) + ) + context["trusted_user_count"] = tu_query.count() + + # In case any records have a None InactivityTS. + active_tu_query = tu_query.filter( + or_(User.InactivityTS.is_(None), + User.InactivityTS == 0) + ) + context["active_trusted_user_count"] = active_tu_query.count() + + @router.get("/tu") @requires_auth async def trusted_user(request: Request, @@ -40,6 +56,8 @@ async def trusted_user(request: Request, cby: str = "desc", # current by poff: int = 0, # past offset pby: str = "desc"): # past by + """ Proposal listings. """ + if not request.user.has_credential(creds.TU_LIST_VOTES): return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) @@ -102,6 +120,8 @@ async def trusted_user(request: Request, context["current_by_next"] = "asc" if current_by == "desc" else "desc" context["past_by_next"] = "asc" if past_by == "desc" else "desc" + populate_trusted_user_counts(context) + context["q"] = { "coff": current_off, "cby": current_by, diff --git a/po/aurweb.pot b/po/aurweb.pot index bec1b672..e7c632e3 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2334,3 +2334,7 @@ msgid "This action will close any pending package requests " "related to it. If %sComments%s are omitted, a closure " "comment will be autogenerated." msgstr "" + +#: templates/partials/tu/proposal/details.html +msgid "assigned" +msgstr "" diff --git a/templates/partials/tu/proposal/details.html b/templates/partials/tu/proposal/details.html index f7a55148..4cbee9ad 100644 --- a/templates/partials/tu/proposal/details.html +++ b/templates/partials/tu/proposal/details.html @@ -21,6 +21,11 @@
      +
      + {{ "Active" | tr }} {{ "Trusted Users" | tr }} {{ "assigned" | tr }}: + {{ voteinfo.ActiveTUs }} +
      + {% set submitter = voteinfo.Submitter.Username %} {% set submitter_uri = "/account/%s" | format(submitter) %} {% set submitter = '%s' | format(submitter_uri, submitter) %} diff --git a/templates/tu/index.html b/templates/tu/index.html index 5060e1f7..4c7a3c35 100644 --- a/templates/tu/index.html +++ b/templates/tu/index.html @@ -1,6 +1,22 @@ {% extends "partials/layout.html" %} {% block pageContent %} +
      +

      {{ "Statistics" | tr }}

      + + + + + + + + + + + +
      {{ "Total" | tr }} {{ "Trusted Users" | tr }}:{{ trusted_user_count }}
      {{ "Active" | tr }} {{ "Trusted Users" | tr }}:{{ active_trusted_user_count }}
      +
      + {% with table_class = "current-votes", total_votes = current_votes_count, diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index a5c4c5e8..2e7dc193 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -267,6 +267,48 @@ def test_tu_index(client, tu_user): assert int(vote_id.text.strip()) == vote_records[1].ID +def test_tu_stats(client: TestClient, tu_user: User): + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + response = request.get("/tu", cookies=cookies, allow_redirects=False) + assert response.status_code == HTTPStatus.OK + + root = parse_root(response.text) + stats = root.xpath('//table[@class="no-width"]')[0] + rows = stats.xpath("./tbody/tr") + + # We have one trusted user. + total = rows[0] + label, count = total.xpath("./td") + assert int(count.text.strip()) == 1 + + # And we have one active TU. + active = rows[1] + label, count = active.xpath("./td") + assert int(count.text.strip()) == 1 + + with db.begin(): + tu_user.InactivityTS = time.utcnow() + + with client as request: + response = request.get("/tu", cookies=cookies, allow_redirects=False) + assert response.status_code == HTTPStatus.OK + + root = parse_root(response.text) + stats = root.xpath('//table[@class="no-width"]')[0] + rows = stats.xpath("./tbody/tr") + + # We have one trusted user. + total = rows[0] + label, count = total.xpath("./td") + assert int(count.text.strip()) == 1 + + # But we have no more active TUs. + active = rows[1] + label, count = active.xpath("./td") + assert int(count.text.strip()) == 0 + + def test_tu_index_table_paging(client, tu_user): ts = time.utcnow() @@ -515,6 +557,8 @@ def test_tu_proposal_unauthorized(client: TestClient, user: User, def test_tu_running_proposal(client: TestClient, proposal: Tuple[User, User, TUVoteInfo]): tu_user, user, voteinfo = proposal + with db.begin(): + voteinfo.ActiveTUs = 1 # Initiate an authenticated GET request to /tu/{proposal_id}. proposal_id = voteinfo.ID @@ -536,6 +580,11 @@ def test_tu_running_proposal(client: TestClient, './div[contains(@class, "user")]/strong/a/text()')[0] assert username.strip() == user.Username + active = details.xpath('./div[contains(@class, "field")]')[1] + content = active.text.strip() + assert "Active Trusted Users assigned:" in content + assert "1" in content + submitted = details.xpath( './div[contains(@class, "submitted")]/text()')[0] assert re.match(r'^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$', diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 22b5ac65..59ae7216 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -282,3 +282,16 @@ pre.traceback { white-space: -o-pre-wrap; word-wrap: break-all; } + +/* A text aligning alias. */ +.text-right { + text-align: right; +} + +/* By default, tables use 100% width, which we do not always want. */ +table.no-width { + width: auto; +} +table.no-width > tbody > tr > td { + padding-right: 2px; +} From d7cb04b93dcdad64b6ea8ad081f6dad6387545d0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 8 Mar 2022 20:35:21 -0800 Subject: [PATCH 1503/1891] upgrade: bump to v6.0.25 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 287152d4..9565b70c 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.24" +AURWEB_VERSION = "v6.0.25" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 7a2f6ca3..8b7a2e93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.24" +version = "v6.0.25" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 7ddce6bb2d8a18fd9b63a23e7a022197226ef672 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 14 Mar 2022 05:55:19 -0700 Subject: [PATCH 1504/1891] doc: update CONTRIBUTING.md Signed-off-by: Kevin Morris --- CONTRIBUTING.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2bb840f5..3d99d887 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ You can add a git hook to do this by installing `python-pre-commit` and running `pre-commit install`. [1]: https://lists.archlinux.org/listinfo/aur-dev -[2]: https://gitlab.archlinunx.org/archlinux/aurweb +[2]: https://gitlab.archlinux.org/archlinux/aurweb ### Coding Guidelines @@ -23,6 +23,76 @@ development. 3. Use four space indentation 4. Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) 5. DRY: Don't Repeat Yourself -6. All code should be tested for good _and_ bad cases +6. All code should be tested for good _and_ bad cases (see [test/README.md][3]) + +[3]: https://gitlab.archlinux.org/archlinux/aurweb/-/blob/master/test/README.md Test patches that increase coverage in the codebase are always welcome. + +### Coding Style + +We use the `flake8` and `isort` tools to manage PEP-8 coherenace and +import ordering in this project. + +There are plugins for editors or IDEs which automate this process. Some +example plugins: + +- [tell-k/vim-autopep8](https://github.com/tell-k/vim-autopep8) +- [fisadev/vim-isort](https://github.com/fisadev/vim-isort) +- [prabirshrestha/vim-lsp](https://github.com/prabirshrestha/vim-lsp) + +See `setup.cfg` for flake8 and isort specific rules. + +Note: We are planning on switching to [psf/black](https://github.com/psf/black). +For now, developers should ensure that flake8 and isort passes when submitting +merge requests or patch sets. + +### Development Environment + +To get started with local development, an instance of aurweb must be +brought up. This can be done using the following sections: + +- [Using Docker](#using-docker) +- [Using INSTALL](#using-install) + +There are a number of services aurweb employs to run the application +in its entirety: + +- ssh +- cron jobs +- starlette/fastapi asgi server + +Project structure: + +- `./aurweb`: `aurweb` Python package +- `./templates`: Jinja2 templates +- `./docker`: Docker scripts and configuration files + +#### Using Docker + +Using Docker, we can run the entire infrastructure in two steps: + + # Build the aurweb:latest image + $ docker-compose build + + # Start all services in the background + $ docker-compose up -d nginx + +`docker-compose` services will generate a locally signed root certificate +at `./data/root_ca.crt`. Users can import this into ca-certificates or their +browser if desired. + +Accessible services (on the host): + +- https://localhost:8444 (python via nginx) +- https://localhost:8443 (php via nginx) +- localhost:13306 (mariadb) +- localhost:16379 (redis) + +Docker services, by default, are setup to be hot reloaded when source code +is changed. + +#### Using INSTALL + +The [INSTALL](INSTALL) file describes steps to install the application on +bare-metal systems. From 790ca4194a6360e9f47f56fe9d39aae4cbe14c25 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 14 Mar 2022 05:57:06 -0700 Subject: [PATCH 1505/1891] fix: coherenace -> coherence Signed-off-by: Kevin Morris --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3d99d887..52e182c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ Test patches that increase coverage in the codebase are always welcome. ### Coding Style -We use the `flake8` and `isort` tools to manage PEP-8 coherenace and +We use the `flake8` and `isort` tools to manage PEP-8 coherence and import ordering in this project. There are plugins for editors or IDEs which automate this process. Some From afd25c248fcee508da6724398f6c37c47bf4be5e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 14 Mar 2022 06:24:15 -0700 Subject: [PATCH 1506/1891] fix: remove HEAD and OPTIONS handling from metrics Signed-off-by: Kevin Morris --- aurweb/prometheus.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index 73be3ef6..272ee023 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -60,6 +60,9 @@ def http_requests_total() -> Callable[[Info], None]: labelnames=("method", "path", "status")) def instrumentation(info: Info) -> None: + if info.request.method.lower() in ("head", "options"): # pragma: no cover + return + scope = info.request.scope # Taken from https://github.com/stephenhillier/starlette_exporter @@ -70,8 +73,8 @@ def http_requests_total() -> Callable[[Info], None]: if not (scope.get("endpoint", None) and scope.get("router", None)): return None - root_path = scope.get("root_path", "") - app = scope.get("app", {}) + root_path = scope.get("root_path", str()) + app = scope.get("app", dict()) if hasattr(app, "root_path"): app_root_path = getattr(app, "root_path") @@ -102,6 +105,9 @@ def http_api_requests_total() -> Callable[[Info], None]: labelnames=("type", "status")) def instrumentation(info: Info) -> None: + if info.request.method.lower() in ("head", "options"): # pragma: no cover + return + if info.request.url.path.rstrip("/") == "/rpc": type = info.request.query_params.get("type", "None") if info.response: From d8564e446b744bbc7b6bd8fea22ab6b614acc5ab Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 30 Mar 2022 12:30:21 -0700 Subject: [PATCH 1507/1891] upgrade: bump to v6.0.26 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 9565b70c..53942b75 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.25" +AURWEB_VERSION = "v6.0.26" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 8b7a2e93..b15af272 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.25" +version = "v6.0.26" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From ed41a4fe1933e13d19a4e648d63011b3d2a67cc5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 30 Mar 2022 16:16:47 -0700 Subject: [PATCH 1508/1891] feat: add paging to package depends & required by This patch does not include a javascript implementating, but provides a pure HTML/HTTP method of paging through these lists. Also fixes erroneous limiting. We now use a hardcoded limit of 20 by default. Signed-off-by: Kevin Morris --- aurweb/packages/util.py | 6 +-- aurweb/pkgbase/util.py | 13 ++++- aurweb/routers/packages.py | 51 +++++++++++++++---- aurweb/templates.py | 2 + po/aurweb.pot | 8 +++ .../partials/packages/package_metadata.html | 16 +++++- test/test_packages_routes.py | 45 ++++++++++++++++ 7 files changed, 125 insertions(+), 16 deletions(-) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index e8569f29..5085ddf4 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -214,7 +214,7 @@ def query_notified(query: List[models.Package], return output -def pkg_required(pkgname: str, provides: List[str], limit: int) \ +def pkg_required(pkgname: str, provides: List[str]) \ -> List[PackageDependency]: """ Get dependencies that match a string in `[pkgname] + provides`. @@ -227,8 +227,8 @@ def pkg_required(pkgname: str, provides: List[str], limit: int) \ targets = set([pkgname] + provides) query = db.query(PackageDependency).join(Package).filter( PackageDependency.DepName.in_(targets) - ).order_by(Package.Name.asc()).limit(limit) - return query.all() + ).order_by(Package.Name.asc()) + return query @register_filter("source_uri") diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index 18af3df0..ea952dce 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -11,16 +11,25 @@ from aurweb.models.package_request import PENDING_ID, PackageRequest from aurweb.models.package_vote import PackageVote from aurweb.scripts import notify from aurweb.templates import make_context as _make_context +from aurweb.templates import make_variable_context as _make_variable_context -def make_context(request: Request, pkgbase: PackageBase) -> Dict[str, Any]: +async def make_variable_context(request: Request, pkgbase: PackageBase) \ + -> Dict[str, Any]: + ctx = await _make_variable_context(request, pkgbase.Name) + return make_context(request, pkgbase, ctx) + + +def make_context(request: Request, pkgbase: PackageBase, + context: Dict[str, Any] = None) -> Dict[str, Any]: """ Make a basic context for package or pkgbase. :param request: FastAPI request :param pkgbase: PackageBase instance :return: A pkgbase context without specific differences """ - context = _make_context(request, pkgbase.Name) + if not context: + context = _make_context(request, pkgbase.Name) context["git_clone_uri_anon"] = config.get("options", "git_clone_uri_anon") context["git_clone_uri_priv"] = config.get("options", "git_clone_uri_priv") diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index bc12455d..f14b0ad8 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -2,7 +2,7 @@ from collections import defaultdict from http import HTTPStatus from typing import Any, Dict, List -from fastapi import APIRouter, Form, Request, Response +from fastapi import APIRouter, Form, Query, Request, Response import aurweb.filters # noqa: F401 @@ -33,7 +33,7 @@ async def packages_get(request: Request, context: Dict[str, Any], context["O"] = offset # Limit PP to options.max_search_results - max_search_results = aurweb.config.getint("options", "max_search_results") + max_search_results = config.getint("options", "max_search_results") context["PP"] = per_page = min(per_page, max_search_results) # Query search by. @@ -123,7 +123,22 @@ async def packages(request: Request) -> Response: @router.get("/packages/{name}") -async def package(request: Request, name: str) -> Response: +async def package(request: Request, name: str, + all_deps: bool = Query(default=False), + all_reqs: bool = Query(default=False)) -> Response: + """ + Get a package by name. + + By default, we limit the number of depends and requires results + to 20. To bypass this and load all of them, which should be triggered + via a "Show more" link near the limited listing. + + :param name: Package.Name + :param all_deps: Boolean indicating whether we should load all depends + :param all_reqs: Boolean indicating whether we should load all requires + :return: FastAPI Response + """ + # Get the Package. pkg = get_pkg_or_base(name, models.Package) pkgbase = pkg.PackageBase @@ -139,23 +154,41 @@ async def package(request: Request, name: str) -> Response: rels_data["r"].append(rel) # Add our base information. - context = pkgbaseutil.make_context(request, pkgbase) + context = await pkgbaseutil.make_variable_context(request, pkgbase) + + context.update( + { + "all_deps": all_deps, + "all_reqs": all_reqs + } + ) + context["package"] = pkg # Package sources. context["sources"] = pkg.package_sources.order_by( models.PackageSource.Source.asc()).all() + # Listing metadata. + context["max_listing"] = max_listing = 20 + # Package dependencies. - max_depends = config.getint("options", "max_depends") - context["dependencies"] = pkg.package_dependencies.order_by( + deps = pkg.package_dependencies.order_by( models.PackageDependency.DepTypeID.asc(), models.PackageDependency.DepName.asc() - ).limit(max_depends).all() + ) + context["depends_count"] = deps.count() + if not all_deps: + deps = deps.limit(max_listing) + context["dependencies"] = deps.all() # Package requirements (other packages depend on this one). - context["required_by"] = pkgutil.pkg_required( - pkg.Name, [p.RelName for p in rels_data.get("p", [])], max_depends) + reqs = pkgutil.pkg_required( + pkg.Name, [p.RelName for p in rels_data.get("p", [])]) + context["reqs_count"] = reqs.count() + if not all_reqs: + reqs = reqs.limit(max_listing) + context["required_by"] = reqs.all() context["licenses"] = pkg.package_licenses diff --git a/aurweb/templates.py b/aurweb/templates.py index ccadb16d..6520bedf 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -100,6 +100,8 @@ async def make_variable_context(request: Request, title: str, next: str = None): for k, v in to_copy.items(): context[k] = v + context["q"] = dict(request.query_params) + return context diff --git a/po/aurweb.pot b/po/aurweb.pot index e7c632e3..bc4bab84 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2338,3 +2338,11 @@ msgstr "" #: templates/partials/tu/proposal/details.html msgid "assigned" msgstr "" + +#: templaets/partials/packages/package_metadata.html +msgid "Show %d more" +msgstr "" + +#: templates/partials/packages/package_metadata.html +msgid "dependencies" +msgstr "" diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html index 6f58c2be..123b994d 100644 --- a/templates/partials/packages/package_metadata.html +++ b/templates/partials/packages/package_metadata.html @@ -1,5 +1,5 @@
      -

      {{ "Dependencies" | tr }} ({{ dependencies | length }})

      +

      {{ "Dependencies" | tr }} ({{ depends_count }})

      -

      {{ "Required by" | tr }} ({{ required_by | length }})

      +

      {{ "Required by" | tr }} ({{ reqs_count }})

      diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index ee837912..e4c992af 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -276,6 +276,51 @@ def test_package(client: TestClient, package: Package): assert conflicts[0].text.strip() == ", ".join(expected) +def paged_depends_required(client: TestClient, package: Package): + maint = package.PackageBase.Maintainer + new_pkgs = [] + + with db.begin(): + # Create 25 new packages that'll be used to depend on our package. + for i in range(26): + base = db.create(PackageBase, Name=f"new_pkg{i}", Maintainer=maint) + new_pkgs.append(db.create(Package, Name=base.Name)) + + # Create 25 deps. + for i in range(25): + create_package_dep(package, f"dep_{i}") + + with db.begin(): + # Create depends on this package so we get some required by listings. + for new_pkg in new_pkgs: + create_package_dep(new_pkg, package.Name) + + with client as request: + resp = request.get(package_endpoint(package)) + assert resp.status_code == int(HTTPStatus.OK) + + # Test depends show link. + assert "Show 5 more" in resp.text + + # Test required by show more link, we added 26 packages. + assert "Show 6 more" in resp.text + + # Follow both links at the same time. + with client as request: + resp = request.get( + package_endpoint(package), + params={ + "all_deps": True, + "all_reqs": True, + } + ) + assert resp.status_code == int(HTTPStatus.OK) + + # We're should see everything and have no link. + assert "Show 5 more" not in resp.text + assert "Show 6 more" not in resp.text + + def test_package_comments(client: TestClient, user: User, package: Package): now = (time.utcnow()) with db.begin(): From cf4295a13e43dcc0daea9a9bb7cb54452b4c8b34 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 31 Mar 2022 17:45:39 -0700 Subject: [PATCH 1509/1891] upgrade: bump to v6.0.27 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 53942b75..69d9b31f 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.26" +AURWEB_VERSION = "v6.0.27" _parser = None diff --git a/pyproject.toml b/pyproject.toml index b15af272..c50af62b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.26" +version = "v6.0.27" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From a553d5d95adb9339ca1ba62fcb375ab34e02d013 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 31 Mar 2022 20:45:59 -0700 Subject: [PATCH 1510/1891] fix: replace distutils.util.strtobool with our own Reference from github.com/PostHog/posthog/pull/4631/commits/341c28da0f6d33d6fb12fe443766a2d822ff0097 This fixes a deprecation warning regarding distutil's strtobool. Signed-off-by: Kevin Morris --- aurweb/util.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index 6759794f..5138f7da 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -4,7 +4,6 @@ import secrets import string from datetime import datetime -from distutils.util import strtobool as _strtobool from http import HTTPStatus from subprocess import PIPE, Popen from typing import Callable, Iterable, List, Tuple, Union @@ -114,9 +113,9 @@ def sanitize_params(offset: str, per_page: str) -> Tuple[int, int]: def strtobool(value: Union[str, bool]) -> bool: - if isinstance(value, str): - return _strtobool(value or "False") - return value + if not value: + return False + return str(value).lower() in ("y", "yes", "t", "true", "on", "1") def file_hash(filepath: str, hash_function: Callable) -> str: From 7a525d769363a78c080e91b6cfee0b2e0b6df10b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 31 Mar 2022 20:47:34 -0700 Subject: [PATCH 1511/1891] change: remove poetry-dynamic-versioning We've not been using this as it is and its now warning us about strtobool deprecation changes. Removing it for now. Signed-off-by: Kevin Morris --- poetry.lock | 69 ++++++++++++++++++-------------------------------- pyproject.toml | 1 - 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/poetry.lock b/poetry.lock index c9d0b38a..7744606e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -212,17 +212,6 @@ idna = ["idna (>=2.1,<4.0)"] trio = ["trio (>=0.14,<0.20)"] wmi = ["wmi (>=1.5.1,<2.0.0)"] -[[package]] -name = "dunamai" -version = "1.8.0" -description = "Dynamic version generation" -category = "main" -optional = false -python-versions = ">=3.5,<4.0" - -[package.dependencies] -packaging = ">=20.9" - [[package]] name = "email-validator" version = "1.1.3" @@ -627,19 +616,6 @@ python-versions = ">=3.6" dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "poetry-dynamic-versioning" -version = "0.13.1" -description = "Plugin for Poetry to enable dynamic versioning based on VCS tags" -category = "main" -optional = false -python-versions = ">=3.5,<4.0" - -[package.dependencies] -dunamai = ">=1.5,<2.0" -jinja2 = {version = ">=2.11.1,<4", markers = "python_version >= \"3.6\" and python_version < \"4.0\""} -tomlkit = ">=0.4" - [[package]] name = "posix-ipc" version = "1.0.5" @@ -1029,14 +1005,6 @@ category = "dev" optional = false python-versions = ">=3.7" -[[package]] -name = "tomlkit" -version = "0.9.0" -description = "Style preserving TOML library" -category = "main" -optional = false -python-versions = ">=3.6,<4.0" - [[package]] name = "typing-extensions" version = "4.0.1" @@ -1119,7 +1087,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "1f6a0dd3780d8857ba0d5123814f299a8178a80e79c2235805623f43b8e0381f" +content-hash = "ffe7ab6733020584382d2d01950153072a46d0738f6d2fe52ac84653d0b16086" [metadata.files] aiofiles = [ @@ -1151,10 +1119,13 @@ authlib = [ {file = "Authlib-0.15.5.tar.gz", hash = "sha256:b83cf6360c8e92b0e9df0d1f32d675790bcc4e3c03977499b1eed24dcdef4252"}, ] bcrypt = [ + {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b589229207630484aefe5899122fb938a5b017b0f4349f769b8c13e78d99a8fd"}, {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a0584a92329210fcd75eb8a3250c5a941633f8bfaf2a18f81009b097732839b7"}, + {file = "bcrypt-3.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:56e5da069a76470679f312a7d3d23deb3ac4519991a0361abc11da837087b61d"}, {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, @@ -1300,10 +1271,6 @@ dnspython = [ {file = "dnspython-2.2.0-py3-none-any.whl", hash = "sha256:081649da27ced5e75709a1ee542136eaba9842a0fe4c03da4fb0a3d3ed1f3c44"}, {file = "dnspython-2.2.0.tar.gz", hash = "sha256:e79351e032d0b606b98d38a4b0e6e2275b31a5b85c873e587cc11b73aca026d6"}, ] -dunamai = [ - {file = "dunamai-1.8.0-py3-none-any.whl", hash = "sha256:846855e45d5969f6d11835d486bbf4d6ca175d4169a0ab11f619a5135cc86bdf"}, - {file = "dunamai-1.8.0.tar.gz", hash = "sha256:ff1f958af3575ec612e72c84bf96367469f418d31b9685f8311a5de2eb754a85"}, -] email-validator = [ {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"}, @@ -1343,6 +1310,7 @@ greenlet = [ {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"}, {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"}, {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"}, + {file = "greenlet-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965"}, {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"}, {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"}, {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"}, @@ -1355,6 +1323,7 @@ greenlet = [ {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"}, {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"}, {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"}, + {file = "greenlet-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f"}, {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"}, {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"}, {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"}, @@ -1363,6 +1332,7 @@ greenlet = [ {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"}, {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"}, {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"}, + {file = "greenlet-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe"}, {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"}, {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"}, {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"}, @@ -1371,6 +1341,7 @@ greenlet = [ {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"}, {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"}, {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"}, + {file = "greenlet-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2"}, {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"}, {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"}, {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"}, @@ -1379,6 +1350,7 @@ greenlet = [ {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"}, {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"}, {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"}, + {file = "greenlet-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3"}, {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"}, {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, @@ -1515,6 +1487,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, @@ -1526,6 +1501,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -1537,6 +1515,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, @@ -1549,6 +1530,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -1561,6 +1545,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, @@ -1619,10 +1606,6 @@ pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -poetry-dynamic-versioning = [ - {file = "poetry-dynamic-versioning-0.13.1.tar.gz", hash = "sha256:5c0e7b22560db76812057ef95dadad662ecc63eb270145787eabe73da7c222f9"}, - {file = "poetry_dynamic_versioning-0.13.1-py3-none-any.whl", hash = "sha256:6d79f76436c624653fc06eb9bb54fb4f39b1d54362bc366ad2496855711d3a78"}, -] posix-ipc = [ {file = "posix_ipc-1.0.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ccb36ba90efec56a1796f1566eee9561f355a4f45babbc4d18ac46fb2d0b246b"}, {file = "posix_ipc-1.0.5-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:613bf1afe90e84c06255ec1a6f52c9b24062492de66e5f0dbe068adf67fc3454"}, @@ -1876,10 +1859,6 @@ tomli = [ {file = "tomli-2.0.0-py3-none-any.whl", hash = "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224"}, {file = "tomli-2.0.0.tar.gz", hash = "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1"}, ] -tomlkit = [ - {file = "tomlkit-0.9.0-py3-none-any.whl", hash = "sha256:c1b0fc73abd4f1e77c29ea4061ca0f2e11cbfb77342e17df3d3fdd496fc3f899"}, - {file = "tomlkit-0.9.0.tar.gz", hash = "sha256:5a83672c565f78f5fc8f1e44e5f2726446cc6b765113efd21d03e9331747d9ab"}, -] typing-extensions = [ {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, diff --git a/pyproject.toml b/pyproject.toml index c50af62b..001e0287 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,6 @@ python = ">=3.9,<3.11" # poetry-dynamic-versioning is used to produce tool.poetry.version # based on git tags. -poetry-dynamic-versioning = "^0.13.1" # General aiofiles = "^0.7.0" From 02d114d575a72c0ec5038c762cddd8f1424e2c12 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 6 May 2022 18:30:29 +0100 Subject: [PATCH 1512/1891] fix: hide email when account's email hidden is set Fixes: 362 Signed-off-by: Leonidas Spyropoulos --- templates/account/show.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/account/show.html b/templates/account/show.html index a9bb3c30..a57efb77 100644 --- a/templates/account/show.html +++ b/templates/account/show.html @@ -25,7 +25,11 @@ {% trans %}Email Address{% endtrans %}: + {% if not user.HideEmail %} {{ user.Email }} + {% else %} + <{% trans %}hidden{% endtrans %}> + {% endif %} From 0b544885636fead56551b9f229400e7abacd0d73 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 12 May 2022 23:26:57 +0100 Subject: [PATCH 1513/1891] fix(poetry): remove mysql-connector dependency Reverting a8287921 Signed-off-by: Leonidas Spyropoulos --- poetry.lock | 12 ------------ pyproject.toml | 1 - 2 files changed, 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7744606e..fe1575a6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -553,14 +553,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "mysql-connector" -version = "2.2.9" -description = "MySQL driver written in Python" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "mysqlclient" version = "2.1.0" @@ -943,7 +935,6 @@ mssql_pymssql = ["pymssql"] mssql_pyodbc = ["pyodbc"] mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] -mysql_connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] postgresql = ["psycopg2 (>=2.7)"] postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] @@ -1556,9 +1547,6 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] -mysql-connector = [ - {file = "mysql-connector-2.2.9.tar.gz", hash = "sha256:1733e6ce52a049243de3264f1fbc22a852cb35458c4ad739ba88189285efdf32"}, -] mysqlclient = [ {file = "mysqlclient-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:02c8826e6add9b20f4cb12dcf016485f7b1d6e30356a1204d05431867a1b3947"}, {file = "mysqlclient-2.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b62d23c11c516cedb887377c8807628c1c65d57593b57853186a6ee18b0c6a5b"}, diff --git a/pyproject.toml b/pyproject.toml index 001e0287..9ba73c2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,6 @@ SQLAlchemy = "^1.4.26" uvicorn = "^0.15.0" gunicorn = "^20.1.0" Hypercorn = "^0.11.2" -mysql-connector = "^2.2.9" prometheus-fastapi-instrumentator = "^5.7.1" pytest-xdist = "^2.4.0" filelock = "^3.3.2" From 4ddd1dec9c1d19481593f4095ba30de7b6d22cde Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Fri, 13 May 2022 00:37:34 +0200 Subject: [PATCH 1514/1891] upgrade: bump to v6.0.28 --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 69d9b31f..6069910f 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -6,7 +6,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.27" +AURWEB_VERSION = "v6.0.28" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 9ba73c2d..41d8301f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ # [tool.poetry] name = "aurweb" -version = "v6.0.27" +version = "v6.0.28" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 8598ea6f748405de5678e4f6c17b95afaa9df886 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 27 Jun 2022 20:52:43 +0200 Subject: [PATCH 1515/1891] fix(gitlab-ci): update coverage reporting in CI Gitlab 14.10 introduced a coverage_report key which obsoletes the old way of reporting coverage data. --- .gitlab-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c5554e92..98f99ae3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,7 +53,9 @@ test: coverage: '/TOTAL.*\s+(\d+\%)/' artifacts: reports: - cobertura: coverage.xml + coverage_report: + coverage_format: cobertura + path: coverage.xml deploy: stage: deploy From 98f55879d37be1ffbdcf9861ef70410317f90af2 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Tue, 28 Jun 2022 22:07:00 +0200 Subject: [PATCH 1516/1891] fix(docker): don't run redis with protected mode For our development setup we run a redis container without a username/password. Redis recently set protected mode by default which disallows this, turn it off as it has no security implication. --- docker/redis-entrypoint.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/redis-entrypoint.sh b/docker/redis-entrypoint.sh index e92be6c5..669716d7 100755 --- a/docker/redis-entrypoint.sh +++ b/docker/redis-entrypoint.sh @@ -2,5 +2,6 @@ set -eou pipefail sed -ri 's/^bind .*$/bind 0.0.0.0 -::1/g' /etc/redis/redis.conf +sed -ri 's/protected-mode yes/protected-mode no/g' /etc/redis/redis.conf exec "$@" From ade624c215989532c9536cebc4a17000999974f3 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 27 Jun 2022 20:48:18 +0200 Subject: [PATCH 1517/1891] doc(README): update contributing guidelines --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f156455..2741efa2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Links ----- * The repository is hosted at https://gitlab.archlinux.org/archlinux/aurweb - -- see doc/CodingGuidelines for information on the patch submission process. + -- see [CONTRIBUTING.md](./CONTRIBUTING.md) for information on the patch submission process. * Bugs can (and should) be submitted to the aurweb bug tracker: https://gitlab.archlinux.org/archlinux/aurweb/-/issues/new?issuable_template=Bug From edef6cc6ac01b68d18fe8d7e7c948fc3be13b36b Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Thu, 30 Jun 2022 21:57:52 +0200 Subject: [PATCH 1518/1891] chore(css): drop old vendor prefixes All of these vendor prefixes are already supported by all browsers for quite a while. --- web/html/css/aurweb.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 59ae7216..281b8f59 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -125,13 +125,11 @@ } .rss-icon, .delete-comment, .undelete-comment, .edit-comment, .pin-comment { - -webkit-filter: grayscale(100%); filter: grayscale(100%); opacity: 0.6; } .rss-icon:hover, .delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { - -webkit-filter: none; filter: none; opacity: 1; } @@ -277,9 +275,6 @@ div.box form.link button { pre.traceback { /* https://css-tricks.com/snippets/css/make-pre-text-wrap/ */ white-space: pre-wrap; - white-space: -moz-pre-wrap; - white-space: -pre-wrap; - white-space: -o-pre-wrap; word-wrap: break-all; } From 4a58e1349cb34844c8f706cdedf902ef66adb8d8 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 4 Jul 2022 21:35:06 +0200 Subject: [PATCH 1519/1891] fix(docker): fix typo scheme -> schema --- docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index 89dbb739..81628a39 100644 --- a/docker/README.md +++ b/docker/README.md @@ -46,7 +46,7 @@ container running the FastAPI. Then: ```sh docker exec -it /bin/bash -./scheme/gendummydata.py dummy.sql +./schema/gendummydata.py dummy.sql mysql aurweb < dummy.sql ``` From 0b03a6871e288c837e273cf5577e8d81dc7b44fd Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 4 Jul 2022 21:35:41 +0200 Subject: [PATCH 1520/1891] fix(docker): document runtime deps --- docker/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/README.md b/docker/README.md index 81628a39..88fb763e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -46,6 +46,7 @@ container running the FastAPI. Then: ```sh docker exec -it /bin/bash +pacman -S words fortune-mod ./schema/gendummydata.py dummy.sql mysql aurweb < dummy.sql ``` From 034e47bc282a43b661b6d5db2759b4c8ca723a3f Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 19 May 2022 13:13:36 +0100 Subject: [PATCH 1521/1891] fix: hide Unflag package from non-maintainers Closes: #364 Signed-off-by: Leonidas Spyropoulos --- aurweb/pkgbase/actions.py | 4 ++-- aurweb/pkgbase/util.py | 3 +++ templates/partials/packages/actions.html | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 229d52b9..6fd55497 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -38,8 +38,8 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: PackageBase) -> None: def pkgbase_unflag_instance(request: Request, pkgbase: PackageBase) -> None: - has_cred = request.user.has_credential( - creds.PKGBASE_UNFLAG, approved=[pkgbase.Flagger, pkgbase.Maintainer]) + has_cred = request.user.has_credential(creds.PKGBASE_UNFLAG, approved=[ + pkgbase.Flagger, pkgbase.Maintainer] + [c.User for c in pkgbase.comaintainers]) if has_cred: with db.begin(): pkgbase.OutOfDateTS = None diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index ea952dce..55dbb022 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -39,6 +39,9 @@ def make_context(request: Request, pkgbase: PackageBase, PackageComaintainer.Priority.asc() ).all() ] + context["unflaggers"] = context["comaintainers"].copy() + context["unflaggers"].append(pkgbase.Maintainer) + context["packages_count"] = pkgbase.packages.count() context["keywords"] = pkgbase.keywords context["comments"] = pkgbase.comments.order_by( diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 88420222..2144b07a 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -41,6 +41,7 @@ + {% if request.user.has_credential(creds.PKGBASE_UNFLAG, approved=unflaggers) %}
    • + {% endif %} {% endif %}
    • {% if not voted %} From 28970ccc9179d210781fedabcf42cc04332cd1ec Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sun, 17 Jul 2022 12:19:18 +0100 Subject: [PATCH 1522/1891] fix: align text on left Closes: #368 Signed-off-by: Leonidas Spyropoulos --- templates/tu/index.html | 4 ++-- web/html/css/aurweb.css | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/templates/tu/index.html b/templates/tu/index.html index 4c7a3c35..9f5bfd50 100644 --- a/templates/tu/index.html +++ b/templates/tu/index.html @@ -6,11 +6,11 @@ - + - + diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 281b8f59..59f7ed1e 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -278,11 +278,6 @@ pre.traceback { word-wrap: break-all; } -/* A text aligning alias. */ -.text-right { - text-align: right; -} - /* By default, tables use 100% width, which we do not always want. */ table.no-width { width: auto; From d6fa4ec5a8d76b6f791bb6d855eb267661baa012 Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Tue, 19 Jul 2022 18:29:26 +0200 Subject: [PATCH 1523/1891] Explain how to populate dummy data for TESTING Signed-off-by: Hugo Osvaldo Barrera --- TESTING | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/TESTING b/TESTING index 776be2f4..cb34c0e9 100644 --- a/TESTING +++ b/TESTING @@ -31,6 +31,16 @@ docker-compose Python: https://localhost:8444/ PHP: https://localhost:8443/ +5) [Optionally] populate the database with dummy data: + + $ docker-compose up mariadb + $ docker-compose exec mariadb /bin/sh + # pacman -S --noconfirm words fortune-mod + # poetry run schema/gendummydata.py dummy_data.sql + # mysql -uaur -paur aurweb < dummy_data.sql + +Inspect `dummy_data.sql` for test credentials. Passwords match usernames. + Bare Metal ---------- From a509e4047483763316d3b06a4dfe3c2004455aff Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sun, 31 Jul 2022 20:58:39 +0200 Subject: [PATCH 1524/1891] fix(python): use standard dict/list type annotation Since Python 3.9 list/dict can be used as type hint. --- aurweb/filters.py | 20 +++++----- aurweb/models/package_dependency.py | 4 +- aurweb/models/user.py | 4 +- aurweb/packages/requests.py | 10 ++--- aurweb/packages/util.py | 18 ++++----- aurweb/pkgbase/actions.py | 4 +- aurweb/pkgbase/util.py | 10 ++--- aurweb/pkgbase/validate.py | 4 +- aurweb/prometheus.py | 4 +- aurweb/routers/accounts.py | 4 +- aurweb/routers/packages.py | 24 ++++++------ aurweb/routers/rpc.py | 8 ++-- aurweb/routers/trusted_user.py | 4 +- aurweb/rpc.py | 44 ++++++++++----------- aurweb/scripts/mkpkglists.py | 4 +- aurweb/scripts/popupdate.py | 4 +- aurweb/spawn.py | 10 ++--- aurweb/testing/alpm.py | 4 +- aurweb/testing/html.py | 5 +-- aurweb/testing/requests.py | 6 +-- aurweb/users/update.py | 8 ++-- aurweb/util.py | 4 +- test/test_adduser.py | 3 +- test/test_mkpkglists.py | 7 ++-- test/test_notify.py | 35 +++++++++-------- test/test_packages_routes.py | 31 ++++++++------- test/test_pkgbase_routes.py | 5 +-- test/test_pkgmaint.py | 8 ++-- test/test_requests.py | 11 +++--- test/test_rpc.py | 59 ++++++++++++++--------------- test/test_templates.py | 4 +- 31 files changed, 175 insertions(+), 195 deletions(-) diff --git a/aurweb/filters.py b/aurweb/filters.py index 45cb6d83..22f65024 100644 --- a/aurweb/filters.py +++ b/aurweb/filters.py @@ -2,7 +2,7 @@ import copy import math from datetime import datetime -from typing import Any, Dict, Union +from typing import Any, Union from urllib.parse import quote_plus, urlencode from zoneinfo import ZoneInfo @@ -19,7 +19,7 @@ from aurweb.templates import register_filter, register_function @register_filter("pager_nav") @pass_context -def pager_nav(context: Dict[str, Any], +def pager_nav(context: dict[str, Any], page: int, total: int, prefix: str) -> str: page = int(page) # Make sure this is an int. @@ -71,7 +71,7 @@ def do_round(f: float) -> int: @register_filter("tr") @pass_context -def tr(context: Dict[str, Any], value: str): +def tr(context: dict[str, Any], value: str): """ A translation filter; example: {{ "Hello" | tr("de") }}. """ _ = l10n.get_translator_for_request(context.get("request")) return _(value) @@ -79,7 +79,7 @@ def tr(context: Dict[str, Any], value: str): @register_filter("tn") @pass_context -def tn(context: Dict[str, Any], count: int, +def tn(context: dict[str, Any], count: int, singular: str, plural: str) -> str: """ A singular and plural translation filter. @@ -107,7 +107,7 @@ def as_timezone(dt: datetime, timezone: str): @register_filter("extend_query") -def extend_query(query: Dict[str, Any], *additions) -> Dict[str, Any]: +def extend_query(query: dict[str, Any], *additions) -> dict[str, Any]: """ Add additional key value pairs to query. """ q = copy.copy(query) for k, v in list(additions): @@ -116,7 +116,7 @@ def extend_query(query: Dict[str, Any], *additions) -> Dict[str, Any]: @register_filter("urlencode") -def to_qs(query: Dict[str, Any]) -> str: +def to_qs(query: dict[str, Any]) -> str: return urlencode(query, doseq=True) @@ -134,7 +134,7 @@ def number_format(value: float, places: int): @register_filter("account_url") @pass_context -def account_url(context: Dict[str, Any], +def account_url(context: dict[str, Any], user: "aurweb.models.user.User") -> str: base = aurweb.config.get("options", "aur_location") return f"{base}/account/{user.Username}" @@ -152,7 +152,7 @@ def ceil(*args, **kwargs) -> int: @register_function("date_strftime") @pass_context -def date_strftime(context: Dict[str, Any], dt: Union[int, datetime], fmt: str) \ +def date_strftime(context: dict[str, Any], dt: Union[int, datetime], fmt: str) \ -> str: if isinstance(dt, int): dt = timestamp_to_datetime(dt) @@ -162,11 +162,11 @@ def date_strftime(context: Dict[str, Any], dt: Union[int, datetime], fmt: str) \ @register_function("date_display") @pass_context -def date_display(context: Dict[str, Any], dt: Union[int, datetime]) -> str: +def date_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: return date_strftime(context, dt, "%Y-%m-%d (%Z)") @register_function("datetime_display") @pass_context -def datetime_display(context: Dict[str, Any], dt: Union[int, datetime]) -> str: +def datetime_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: return date_strftime(context, dt, "%Y-%m-%d %H:%M (%Z)") diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index 2fd87f2a..67a7717f 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -1,5 +1,3 @@ -from typing import List - from sqlalchemy import and_, literal from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship @@ -60,7 +58,7 @@ class PackageDependency(Base): _OfficialProvider.Name == self.DepName).exists() return db.query(pkg).scalar() or db.query(official).scalar() - def provides(self) -> List[PackageRelation]: + def provides(self) -> list[PackageRelation]: from aurweb.models.relation_type import PROVIDES_ID rels = db.query(PackageRelation).join(_Package).filter( diff --git a/aurweb/models/user.py b/aurweb/models/user.py index c375fcbc..3fa72a85 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -1,6 +1,6 @@ import hashlib -from typing import List, Set +from typing import Set import bcrypt @@ -149,7 +149,7 @@ class User(Base): return self.session.SessionID def has_credential(self, credential: Set[int], - approved: List["User"] = list()): + approved: list["User"] = list()): from aurweb.auth.creds import has_credential return has_credential(self, credential, approved) diff --git a/aurweb/packages/requests.py b/aurweb/packages/requests.py index 6aaa59ab..42026a33 100644 --- a/aurweb/packages/requests.py +++ b/aurweb/packages/requests.py @@ -1,4 +1,4 @@ -from typing import List, Optional, Set +from typing import Optional, Set from fastapi import Request from sqlalchemy import and_, orm @@ -139,7 +139,7 @@ def close_pkgreq(pkgreq: PackageRequest, closer: User, def handle_request(request: Request, reqtype_id: int, pkgbase: PackageBase, - target: PackageBase = None) -> List[notify.Notification]: + target: PackageBase = None) -> list[notify.Notification]: """ Handle package requests before performing an action. @@ -158,7 +158,7 @@ def handle_request(request: Request, reqtype_id: int, :param pkgbase: PackageBase which the request is about :param target: Optional target to merge into """ - notifs: List[notify.Notification] = [] + notifs: list[notify.Notification] = [] # If it's an orphan request, perform further verification # regarding existing requests. @@ -187,13 +187,13 @@ def handle_request(request: Request, reqtype_id: int, PackageRequest.MergeBaseName == target.Name) # Build an accept list out of `accept_query`. - to_accept: List[PackageRequest] = accept_query.all() + to_accept: list[PackageRequest] = accept_query.all() accepted_ids: Set[int] = set(p.ID for p in to_accept) # Build a reject list out of `query` filtered by IDs not found # in `to_accept`. That is, unmatched records of the same base # query properties. - to_reject: List[PackageRequest] = query.filter( + to_reject: list[PackageRequest] = query.filter( ~PackageRequest.ID.in_(accepted_ids) ).all() diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 5085ddf4..bd173065 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -1,6 +1,6 @@ from collections import defaultdict from http import HTTPStatus -from typing import Dict, List, Tuple, Union +from typing import Tuple, Union import orjson @@ -15,7 +15,7 @@ from aurweb.models.package_relation import PackageRelation from aurweb.redis import redis_connection from aurweb.templates import register_filter -Providers = List[Union[PackageRelation, OfficialProvider]] +Providers = list[Union[PackageRelation, OfficialProvider]] def dep_extra_with_arch(dep: models.PackageDependency, annotation: str) -> str: @@ -123,7 +123,7 @@ def out_of_date(packages: orm.Query) -> orm.Query: def updated_packages(limit: int = 0, - cache_ttl: int = 600) -> List[models.Package]: + cache_ttl: int = 600) -> list[models.Package]: """ Return a list of valid Package objects ordered by their ModifiedTS column in descending order from cache, after setting the cache when no key yet exists. @@ -168,8 +168,8 @@ def updated_packages(limit: int = 0, return packages -def query_voted(query: List[models.Package], - user: models.User) -> Dict[int, bool]: +def query_voted(query: list[models.Package], + user: models.User) -> dict[int, bool]: """ Produce a dictionary of package base ID keys to boolean values, which indicate whether or not the package base has a vote record related to user. @@ -191,8 +191,8 @@ def query_voted(query: List[models.Package], return output -def query_notified(query: List[models.Package], - user: models.User) -> Dict[int, bool]: +def query_notified(query: list[models.Package], + user: models.User) -> dict[int, bool]: """ Produce a dictionary of package base ID keys to boolean values, which indicate whether or not the package base has a notification record related to user. @@ -214,8 +214,8 @@ def query_notified(query: List[models.Package], return output -def pkg_required(pkgname: str, provides: List[str]) \ - -> List[PackageDependency]: +def pkg_required(pkgname: str, provides: list[str]) \ + -> list[PackageDependency]: """ Get dependencies that match a string in `[pkgname] + provides`. diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 6fd55497..46609f89 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -1,5 +1,3 @@ -from typing import List - from fastapi import Request from aurweb import db, logging, util @@ -86,7 +84,7 @@ def pkgbase_adopt_instance(request: Request, pkgbase: PackageBase) -> None: def pkgbase_delete_instance(request: Request, pkgbase: PackageBase, comments: str = str()) \ - -> List[notify.Notification]: + -> list[notify.Notification]: notifs = handle_request(request, DELETION_ID, pkgbase) + [ notify.DeleteNotification(request.user.ID, pkgbase.ID) ] diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index 55dbb022..5a7d952a 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List +from typing import Any from fastapi import Request from sqlalchemy import and_ @@ -15,13 +15,13 @@ from aurweb.templates import make_variable_context as _make_variable_context async def make_variable_context(request: Request, pkgbase: PackageBase) \ - -> Dict[str, Any]: + -> dict[str, Any]: ctx = await _make_variable_context(request, pkgbase.Name) return make_context(request, pkgbase, ctx) def make_context(request: Request, pkgbase: PackageBase, - context: Dict[str, Any] = None) -> Dict[str, Any]: + context: dict[str, Any] = None) -> dict[str, Any]: """ Make a basic context for package or pkgbase. :param request: FastAPI request @@ -89,7 +89,7 @@ def remove_comaintainer(comaint: PackageComaintainer) \ return notif -def remove_comaintainers(pkgbase: PackageBase, usernames: List[str]) -> None: +def remove_comaintainers(pkgbase: PackageBase, usernames: list[str]) -> None: """ Remove comaintainers from `pkgbase`. @@ -163,7 +163,7 @@ def add_comaintainer(pkgbase: PackageBase, comaintainer: User) \ def add_comaintainers(request: Request, pkgbase: PackageBase, - usernames: List[str]) -> None: + usernames: list[str]) -> None: """ Add comaintainers to `pkgbase`. diff --git a/aurweb/pkgbase/validate.py b/aurweb/pkgbase/validate.py index 8d05a3d7..baefc415 100644 --- a/aurweb/pkgbase/validate.py +++ b/aurweb/pkgbase/validate.py @@ -1,4 +1,4 @@ -from typing import Any, Dict +from typing import Any from aurweb import db from aurweb.exceptions import ValidationError @@ -7,7 +7,7 @@ from aurweb.models import PackageBase def request(pkgbase: PackageBase, type: str, comments: str, merge_into: str, - context: Dict[str, Any]) -> None: + context: dict[str, Any]) -> None: if not comments: raise ValidationError(["The comment field must not be empty."]) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index 272ee023..227d46ed 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -1,4 +1,4 @@ -from typing import Any, Callable, Dict, List, Optional +from typing import Any, Callable, Optional from prometheus_client import Counter from prometheus_fastapi_instrumentator import Instrumentator @@ -19,7 +19,7 @@ def instrumentator(): # Their license is included in LICENSES/starlette_exporter. # The code has been modified to remove child route checks # (since we don't have any) and to stay within an 80-width limit. -def get_matching_route_path(scope: Dict[Any, Any], routes: List[Route], +def get_matching_route_path(scope: dict[Any, Any], routes: list[Route], route_name: Optional[str] = None) -> str: """ Find a matching route and return its original path string diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index b603d22a..dcac72b0 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -2,7 +2,7 @@ import copy import typing from http import HTTPStatus -from typing import Any, Dict +from typing import Any from fastapi import APIRouter, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse @@ -108,7 +108,7 @@ async def passreset_post(request: Request, def process_account_form(request: Request, user: models.User, - args: Dict[str, Any]): + args: dict[str, Any]): """ Process an account form. All fields are optional and only checks requirements in the case they are present. diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index f14b0ad8..7bf4e3d4 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -1,6 +1,6 @@ from collections import defaultdict from http import HTTPStatus -from typing import Any, Dict, List +from typing import Any from fastapi import APIRouter, Form, Query, Request, Response @@ -21,7 +21,7 @@ logger = logging.get_logger(__name__) router = APIRouter() -async def packages_get(request: Request, context: Dict[str, Any], +async def packages_get(request: Request, context: dict[str, Any], status_code: HTTPStatus = HTTPStatus.OK): # Query parameters used in this request. context["q"] = dict(request.query_params) @@ -210,7 +210,7 @@ async def package(request: Request, name: str, return render_template(request, "packages/show.html", context) -async def packages_unflag(request: Request, package_ids: List[int] = [], +async def packages_unflag(request: Request, package_ids: list[int] = [], **kwargs): if not package_ids: return (False, ["You did not select any packages to unflag."]) @@ -236,7 +236,7 @@ async def packages_unflag(request: Request, package_ids: List[int] = [], return (True, ["The selected packages have been unflagged."]) -async def packages_notify(request: Request, package_ids: List[int] = [], +async def packages_notify(request: Request, package_ids: list[int] = [], **kwargs): # In cases where we encounter errors with the request, we'll # use this error tuple as a return value. @@ -275,7 +275,7 @@ async def packages_notify(request: Request, package_ids: List[int] = [], return (True, ["The selected packages' notifications have been enabled."]) -async def packages_unnotify(request: Request, package_ids: List[int] = [], +async def packages_unnotify(request: Request, package_ids: list[int] = [], **kwargs): if not package_ids: # TODO: This error does not yet have a translation. @@ -312,7 +312,7 @@ async def packages_unnotify(request: Request, package_ids: List[int] = [], return (True, ["The selected packages' notifications have been removed."]) -async def packages_adopt(request: Request, package_ids: List[int] = [], +async def packages_adopt(request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs): if not package_ids: return (False, ["You did not select any packages to adopt."]) @@ -345,8 +345,8 @@ async def packages_adopt(request: Request, package_ids: List[int] = [], return (True, ["The selected packages have been adopted."]) -def disown_all(request: Request, pkgbases: List[models.PackageBase]) \ - -> List[str]: +def disown_all(request: Request, pkgbases: list[models.PackageBase]) \ + -> list[str]: errors = [] for pkgbase in pkgbases: try: @@ -356,7 +356,7 @@ def disown_all(request: Request, pkgbases: List[models.PackageBase]) \ return errors -async def packages_disown(request: Request, package_ids: List[int] = [], +async def packages_disown(request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs): if not package_ids: return (False, ["You did not select any packages to disown."]) @@ -390,7 +390,7 @@ async def packages_disown(request: Request, package_ids: List[int] = [], return (True, ["The selected packages have been disowned."]) -async def packages_delete(request: Request, package_ids: List[int] = [], +async def packages_delete(request: Request, package_ids: list[int] = [], confirm: bool = False, merge_into: str = str(), **kwargs): if not package_ids: @@ -430,7 +430,7 @@ async def packages_delete(request: Request, package_ids: List[int] = [], # A mapping of action string -> callback functions used within the # `packages_post` route below. We expect any action callback to -# return a tuple in the format: (succeeded: bool, message: List[str]). +# return a tuple in the format: (succeeded: bool, message: list[str]). PACKAGE_ACTIONS = { "unflag": packages_unflag, "notify": packages_notify, @@ -445,7 +445,7 @@ PACKAGE_ACTIONS = { @handle_form_exceptions @requires_auth async def packages_post(request: Request, - IDs: List[int] = Form(default=[]), + IDs: list[int] = Form(default=[]), action: str = Form(default=str()), confirm: bool = Form(default=False)): diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 49e98f8c..ff58063f 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -2,7 +2,7 @@ import hashlib import re from http import HTTPStatus -from typing import List, Optional +from typing import Optional from urllib.parse import unquote import orjson @@ -71,7 +71,7 @@ async def rpc_request(request: Request, type: Optional[str] = None, by: Optional[str] = defaults.RPC_SEARCH_BY, arg: Optional[str] = None, - args: Optional[List[str]] = [], + args: Optional[list[str]] = [], callback: Optional[str] = None): # Create a handle to our RPC class. @@ -140,7 +140,7 @@ async def rpc(request: Request, type: Optional[str] = Query(default=None), by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), arg: Optional[str] = Query(default=None), - args: Optional[List[str]] = Query(default=[], alias="arg[]"), + args: Optional[list[str]] = Query(default=[], alias="arg[]"), callback: Optional[str] = Query(default=None)): if not request.url.query: return documentation() @@ -157,6 +157,6 @@ async def rpc_post(request: Request, type: Optional[str] = Form(default=None), by: Optional[str] = Form(default=defaults.RPC_SEARCH_BY), arg: Optional[str] = Form(default=None), - args: Optional[List[str]] = Form(default=[], alias="arg[]"), + args: Optional[list[str]] = Form(default=[], alias="arg[]"), callback: Optional[str] = Form(default=None)): return await rpc_request(request, v, type, by, arg, args, callback) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 3f0eb836..e1267409 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -2,7 +2,7 @@ import html import typing from http import HTTPStatus -from typing import Any, Dict +from typing import Any from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import RedirectResponse, Response @@ -34,7 +34,7 @@ ADDVOTE_SPECIFICS = { } -def populate_trusted_user_counts(context: Dict[str, Any]) -> None: +def populate_trusted_user_counts(context: dict[str, Any]) -> None: tu_query = db.query(User).filter( or_(User.AccountTypeID == TRUSTED_USER_ID, User.AccountTypeID == TRUSTED_USER_AND_DEV_ID) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 5bc6b80d..f04de7d6 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -1,7 +1,7 @@ import os from collections import defaultdict -from typing import Any, Callable, Dict, List, NewType, Union +from typing import Any, Callable, NewType, Union from fastapi.responses import HTMLResponse from sqlalchemy import and_, literal, orm @@ -24,7 +24,7 @@ TYPE_MAPPING = { } DataGenerator = NewType("DataGenerator", - Callable[[models.Package], Dict[str, Any]]) + Callable[[models.Package], dict[str, Any]]) def documentation(): @@ -86,7 +86,7 @@ class RPC: self.version = version self.type = RPC.TYPE_ALIASES.get(type, type) - def error(self, message: str) -> Dict[str, Any]: + def error(self, message: str) -> dict[str, Any]: return { "version": self.version, "results": [], @@ -95,7 +95,7 @@ class RPC: "error": message } - def _verify_inputs(self, by: str = [], args: List[str] = []) -> None: + def _verify_inputs(self, by: str = [], args: list[str] = []) -> None: if self.version is None: raise RPCError("Please specify an API version.") @@ -111,11 +111,11 @@ class RPC: if self.type not in RPC.EXPOSED_TYPES: raise RPCError("Incorrect request type specified.") - def _enforce_args(self, args: List[str]) -> None: + def _enforce_args(self, args: list[str]) -> None: if not args: raise RPCError("No request type/data specified.") - def _get_json_data(self, package: models.Package) -> Dict[str, Any]: + def _get_json_data(self, package: models.Package) -> dict[str, Any]: """ Produce dictionary data of one Package that can be JSON-serialized. :param package: Package instance @@ -146,7 +146,7 @@ class RPC: "LastModified": package.ModifiedTS } - def _get_info_json_data(self, package: models.Package) -> Dict[str, Any]: + def _get_info_json_data(self, package: models.Package) -> dict[str, Any]: data = self._get_json_data(package) # All info results have _at least_ an empty list of @@ -163,9 +163,9 @@ class RPC: return data - def _assemble_json_data(self, packages: List[models.Package], + def _assemble_json_data(self, packages: list[models.Package], data_generator: DataGenerator) \ - -> List[Dict[str, Any]]: + -> list[dict[str, Any]]: """ Assemble JSON data out of a list of packages. @@ -192,8 +192,8 @@ class RPC: models.User.Username.label("Maintainer"), ).group_by(models.Package.ID) - def _handle_multiinfo_type(self, args: List[str] = [], **kwargs) \ - -> List[Dict[str, Any]]: + def _handle_multiinfo_type(self, args: list[str] = [], **kwargs) \ + -> list[dict[str, Any]]: self._enforce_args(args) args = set(args) @@ -296,7 +296,7 @@ class RPC: return self._assemble_json_data(packages, self._get_info_json_data) def _handle_search_type(self, by: str = defaults.RPC_SEARCH_BY, - args: List[str] = []) -> List[Dict[str, Any]]: + args: list[str] = []) -> list[dict[str, Any]]: # If `by` isn't maintainer and we don't have any args, raise an error. # In maintainer's case, return all orphans if there are no args, # so we need args to pass through to the handler without errors. @@ -318,12 +318,12 @@ class RPC: return self._assemble_json_data(results, self._get_json_data) - def _handle_msearch_type(self, args: List[str] = [], **kwargs)\ - -> List[Dict[str, Any]]: + def _handle_msearch_type(self, args: list[str] = [], **kwargs)\ + -> list[dict[str, Any]]: return self._handle_search_type(by="m", args=args) - def _handle_suggest_type(self, args: List[str] = [], **kwargs)\ - -> List[str]: + def _handle_suggest_type(self, args: list[str] = [], **kwargs)\ + -> list[str]: if not args: return [] @@ -336,8 +336,8 @@ class RPC: ).order_by(models.Package.Name.asc()).limit(20) return [pkg.Name for pkg in packages] - def _handle_suggest_pkgbase_type(self, args: List[str] = [], **kwargs)\ - -> List[str]: + def _handle_suggest_pkgbase_type(self, args: list[str] = [], **kwargs)\ + -> list[str]: if not args: return [] @@ -351,16 +351,16 @@ class RPC: def _is_suggestion(self) -> bool: return self.type.startswith("suggest") - def _handle_callback(self, by: str, args: List[str])\ - -> Union[List[Dict[str, Any]], List[str]]: + def _handle_callback(self, by: str, args: list[str])\ + -> Union[list[dict[str, Any]], list[str]]: # Get a handle to our callback and trap an RPCError with # an empty list of results based on callback's execution. callback = getattr(self, f"_handle_{self.type.replace('-', '_')}_type") results = callback(by=by, args=args) return results - def handle(self, by: str = defaults.RPC_SEARCH_BY, args: List[str] = [])\ - -> Union[List[Dict[str, Any]], Dict[str, Any]]: + def handle(self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = [])\ + -> Union[list[dict[str, Any]], dict[str, Any]]: """ Request entrypoint. A router should pass v, type and args to this function and expect an output dictionary to be returned. diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 00096d74..888e346c 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -27,7 +27,7 @@ import sys import tempfile from collections import defaultdict -from typing import Any, Dict +from typing import Any import orjson @@ -151,7 +151,7 @@ EXTENDED_FIELD_HANDLERS = { } -def as_dict(package: Package) -> Dict[str, Any]: +def as_dict(package: Package) -> dict[str, Any]: return { "ID": package.ID, "Name": package.Name, diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index a2a796fd..637173eb 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -from typing import List - from sqlalchemy import and_, func from sqlalchemy.sql.functions import coalesce from sqlalchemy.sql.functions import sum as _sum @@ -10,7 +8,7 @@ from aurweb import db, time from aurweb.models import PackageBase, PackageVote -def run_variable(pkgbases: List[PackageBase] = []) -> None: +def run_variable(pkgbases: list[PackageBase] = []) -> None: """ Update popularity on a list of PackageBases. diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 46f2f021..c7d54c4e 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -17,7 +17,7 @@ import sys import tempfile import time -from typing import Iterable, List +from typing import Iterable import aurweb.config import aurweb.schema @@ -204,8 +204,8 @@ def start(): """) -def _kill_children(children: Iterable, exceptions: List[Exception] = []) \ - -> List[Exception]: +def _kill_children(children: Iterable, exceptions: list[Exception] = []) \ + -> list[Exception]: """ Kill each process found in `children`. @@ -223,8 +223,8 @@ def _kill_children(children: Iterable, exceptions: List[Exception] = []) \ return exceptions -def _wait_for_children(children: Iterable, exceptions: List[Exception] = []) \ - -> List[Exception]: +def _wait_for_children(children: Iterable, exceptions: list[Exception] = []) \ + -> list[Exception]: """ Wait for each process to end found in `children`. diff --git a/aurweb/testing/alpm.py b/aurweb/testing/alpm.py index 6015d859..ce30d042 100644 --- a/aurweb/testing/alpm.py +++ b/aurweb/testing/alpm.py @@ -4,8 +4,6 @@ import re import shutil import subprocess -from typing import List - from aurweb import logging, util from aurweb.templates import base_template @@ -38,7 +36,7 @@ class AlpmDatabase: return pkgdir def add(self, pkgname: str, pkgver: str, arch: str, - provides: List[str] = []) -> None: + provides: list[str] = []) -> None: context = { "pkgname": pkgname, "pkgver": pkgver, diff --git a/aurweb/testing/html.py b/aurweb/testing/html.py index f01aaf3d..8c923438 100644 --- a/aurweb/testing/html.py +++ b/aurweb/testing/html.py @@ -1,5 +1,4 @@ from io import StringIO -from typing import List from lxml import etree @@ -15,11 +14,11 @@ def parse_root(html: str) -> etree.Element: return etree.parse(StringIO(html), parser) -def get_errors(content: str) -> List[etree._Element]: +def get_errors(content: str) -> list[etree._Element]: root = parse_root(content) return root.xpath('//ul[@class="errorlist"]/li') -def get_successes(content: str) -> List[etree._Element]: +def get_successes(content: str) -> list[etree._Element]: root = parse_root(content) return root.xpath('//ul[@class="success"]/li') diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py index be13ab77..c97d1532 100644 --- a/aurweb/testing/requests.py +++ b/aurweb/testing/requests.py @@ -1,5 +1,3 @@ -from typing import Dict - import aurweb.config @@ -35,8 +33,8 @@ class Request: user: User = User(), authenticated: bool = False, method: str = "GET", - headers: Dict[str, str] = dict(), - cookies: Dict[str, str] = dict()) -> "Request": + headers: dict[str, str] = dict(), + cookies: dict[str, str] = dict()) -> "Request": self.user = user self.user.authenticated = authenticated diff --git a/aurweb/users/update.py b/aurweb/users/update.py index 5a32fd01..ffea1f2f 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -1,4 +1,4 @@ -from typing import Any, Dict +from typing import Any from fastapi import Request @@ -34,7 +34,7 @@ def simple(U: str = str(), E: str = str(), H: bool = False, def language(L: str = str(), request: Request = None, user: models.User = None, - context: Dict[str, Any] = {}, + context: dict[str, Any] = {}, **kwargs) -> None: if L and L != user.LangPreference: with db.begin(): @@ -45,7 +45,7 @@ def language(L: str = str(), def timezone(TZ: str = str(), request: Request = None, user: models.User = None, - context: Dict[str, Any] = {}, + context: dict[str, Any] = {}, **kwargs) -> None: if TZ and TZ != user.Timezone: with db.begin(): @@ -95,7 +95,7 @@ def account_type(T: int = None, def password(P: str = str(), request: Request = None, user: models.User = None, - context: Dict[str, Any] = {}, + context: dict[str, Any] = {}, **kwargs) -> None: if P and not user.valid_password(P): # Remove the fields we consumed for passwords. diff --git a/aurweb/util.py b/aurweb/util.py index 5138f7da..8291b578 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -6,7 +6,7 @@ import string from datetime import datetime from http import HTTPStatus from subprocess import PIPE, Popen -from typing import Callable, Iterable, List, Tuple, Union +from typing import Callable, Iterable, Tuple, Union from urllib.parse import urlparse import fastapi @@ -194,6 +194,6 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: return (prefix, key) -def parse_ssh_keys(string: str) -> List[Tuple[str, str]]: +def parse_ssh_keys(string: str) -> list[Tuple[str, str]]: """ Parse a list of SSH public keys. """ return [parse_ssh_key(e) for e in string.splitlines()] diff --git a/test/test_adduser.py b/test/test_adduser.py index c6210e74..65968d40 100644 --- a/test/test_adduser.py +++ b/test/test_adduser.py @@ -1,4 +1,3 @@ -from typing import List from unittest import mock import pytest @@ -21,7 +20,7 @@ def setup(db_test): return -def run_main(args: List[str] = []): +def run_main(args: list[str] = []): with mock.patch("sys.argv", ["aurweb-adduser"] + args): adduser.main() diff --git a/test/test_mkpkglists.py b/test/test_mkpkglists.py index 7b538e02..9bc1073b 100644 --- a/test/test_mkpkglists.py +++ b/test/test_mkpkglists.py @@ -2,7 +2,6 @@ import gzip import json import os -from typing import List from unittest import mock import py @@ -47,7 +46,7 @@ def user() -> User: @pytest.fixture -def packages(user: User) -> List[Package]: +def packages(user: User) -> list[Package]: output = [] with db.begin(): lic = db.create(License, Name="GPL") @@ -89,7 +88,7 @@ def config_mock(tmpdir: py.path.local) -> None: config.rehash() -def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packages: List[Package]): +def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packages: list[Package]): from aurweb.scripts import mkpkglists mkpkglists.main() @@ -168,7 +167,7 @@ def test_mkpkglists_extended_empty(config_mock: None): @mock.patch("sys.argv", ["mkpkglists", "--extended"]) def test_mkpkglists_extended(config_mock: None, user: User, - packages: List[Package]): + packages: list[Package]): from aurweb.scripts import mkpkglists mkpkglists.main() diff --git a/test/test_notify.py b/test/test_notify.py index fdec5ed7..bbcc6b5a 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -1,5 +1,4 @@ from logging import ERROR -from typing import List from unittest import mock import pytest @@ -46,7 +45,7 @@ def user2() -> User: @pytest.fixture -def pkgbases(user: User) -> List[PackageBase]: +def pkgbases(user: User) -> list[PackageBase]: now = time.utcnow() output = [] @@ -62,7 +61,7 @@ def pkgbases(user: User) -> List[PackageBase]: @pytest.fixture -def pkgreq(user2: User, pkgbases: List[PackageBase]): +def pkgreq(user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] with db.begin(): pkgreq_ = db.create(PackageRequest, PackageBase=pkgbase, @@ -74,7 +73,7 @@ def pkgreq(user2: User, pkgbases: List[PackageBase]): @pytest.fixture -def packages(pkgbases: List[PackageBase]) -> List[Package]: +def packages(pkgbases: list[PackageBase]) -> list[Package]: output = [] with db.begin(): for i, pkgbase in enumerate(pkgbases): @@ -85,7 +84,7 @@ def packages(pkgbases: List[PackageBase]) -> List[Package]: def test_out_of_date(user: User, user1: User, user2: User, - pkgbases: List[PackageBase]): + pkgbases: list[PackageBase]): pkgbase = pkgbases[0] # Create two comaintainers. We'll pass the maintainer uid to # FlagNotification, so we should expect to get two emails. @@ -162,7 +161,7 @@ link does not work, try copying and pasting it into your browser. assert email.body == expected -def test_comment(user: User, user2: User, pkgbases: List[PackageBase]): +def test_comment(user: User, user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] with db.begin(): @@ -194,7 +193,7 @@ please go to the package page [2] and select "Disable notifications". assert expected == email.body -def test_update(user: User, user2: User, pkgbases: List[PackageBase]): +def test_update(user: User, user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] with db.begin(): user.UpdateNotify = 1 @@ -221,7 +220,7 @@ please go to the package page [2] and select "Disable notifications". assert expected == email.body -def test_adopt(user: User, user2: User, pkgbases: List[PackageBase]): +def test_adopt(user: User, user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] notif = notify.AdoptNotification(user2.ID, pkgbase.ID) notif.send() @@ -241,7 +240,7 @@ The package {pkgbase.Name} [1] was adopted by {user2.Username} [2]. assert email.body == expected -def test_disown(user: User, user2: User, pkgbases: List[PackageBase]): +def test_disown(user: User, user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] notif = notify.DisownNotification(user2.ID, pkgbase.ID) notif.send() @@ -261,7 +260,7 @@ The package {pkgbase.Name} [1] was disowned by {user2.Username} [2]. assert email.body == expected -def test_comaintainer_addition(user: User, pkgbases: List[PackageBase]): +def test_comaintainer_addition(user: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] notif = notify.ComaintainerAddNotification(user.ID, pkgbase.ID) notif.send() @@ -280,7 +279,7 @@ You were added to the co-maintainer list of {pkgbase.Name} [1]. assert email.body == expected -def test_comaintainer_removal(user: User, pkgbases: List[PackageBase]): +def test_comaintainer_removal(user: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] notif = notify.ComaintainerRemoveNotification(user.ID, pkgbase.ID) notif.send() @@ -299,7 +298,7 @@ You were removed from the co-maintainer list of {pkgbase.Name} [1]. assert email.body == expected -def test_suspended_ownership_change(user: User, pkgbases: List[PackageBase]): +def test_suspended_ownership_change(user: User, pkgbases: list[PackageBase]): with db.begin(): user.Suspended = 1 @@ -314,7 +313,7 @@ def test_suspended_ownership_change(user: User, pkgbases: List[PackageBase]): assert Email.count() == 1 -def test_delete(user: User, user2: User, pkgbases: List[PackageBase]): +def test_delete(user: User, user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] notif = notify.DeleteNotification(user2.ID, pkgbase.ID) notif.send() @@ -336,7 +335,7 @@ You will no longer receive notifications about this package. assert email.body == expected -def test_merge(user: User, user2: User, pkgbases: List[PackageBase]): +def test_merge(user: User, user2: User, pkgbases: list[PackageBase]): source, target = pkgbases[:2] notif = notify.DeleteNotification(user2.ID, source.ID, target.ID) notif.send() @@ -361,7 +360,7 @@ please go to [3] and click "Disable notifications". assert email.body == expected -def set_tu(users: List[User]) -> User: +def set_tu(users: list[User]) -> User: with db.begin(): for user in users: user.AccountTypeID = TRUSTED_USER_ID @@ -369,7 +368,7 @@ def set_tu(users: List[User]) -> User: def test_open_close_request(user: User, user2: User, pkgreq: PackageRequest, - pkgbases: List[PackageBase]): + pkgbases: list[PackageBase]): set_tu([user]) pkgbase = pkgbases[0] @@ -432,7 +431,7 @@ Request #{pkgreq.ID} has been rejected by {user2.Username} [1]. def test_close_request_comaintainer_cc(user: User, user2: User, pkgreq: PackageRequest, - pkgbases: List[PackageBase]): + pkgbases: list[PackageBase]): pkgbase = pkgbases[0] with db.begin(): db.create(models.PackageComaintainer, PackageBase=pkgbase, @@ -449,7 +448,7 @@ def test_close_request_comaintainer_cc(user: User, user2: User, def test_close_request_closure_comment(user: User, user2: User, pkgreq: PackageRequest, - pkgbases: List[PackageBase]): + pkgbases: list[PackageBase]): pkgbase = pkgbases[0] with db.begin(): pkgreq.ClosureComment = "This is a test closure comment." diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index e4c992af..62f89e23 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1,7 +1,6 @@ import re from http import HTTPStatus -from typing import List from unittest import mock import pytest @@ -177,7 +176,7 @@ def comment(user: User, package: Package) -> PackageComment: @pytest.fixture -def packages(maintainer: User) -> List[Package]: +def packages(maintainer: User) -> list[Package]: """ Yield 55 packages named pkg_0 .. pkg_54. """ packages_ = [] now = time.utcnow() @@ -521,7 +520,7 @@ def test_package_dependencies(client: TestClient, maintainer: User, assert broken_node.text.strip() == broken_dep.DepName -def test_packages(client: TestClient, packages: List[Package]): +def test_packages(client: TestClient, packages: list[Package]): with client as request: response = request.get("/packages", params={ "SeB": "X", # "X" isn't valid, defaults to "nd" @@ -550,7 +549,7 @@ def test_packages_empty(client: TestClient): assert results[0].text.strip() == expected -def test_packages_search_by_name(client: TestClient, packages: List[Package]): +def test_packages_search_by_name(client: TestClient, packages: list[Package]): with client as request: response = request.get("/packages", params={ "SeB": "n", @@ -565,7 +564,7 @@ def test_packages_search_by_name(client: TestClient, packages: List[Package]): def test_packages_search_by_exact_name(client: TestClient, - packages: List[Package]): + packages: list[Package]): with client as request: response = request.get("/packages", params={ "SeB": "N", @@ -594,7 +593,7 @@ def test_packages_search_by_exact_name(client: TestClient, def test_packages_search_by_pkgbase(client: TestClient, - packages: List[Package]): + packages: list[Package]): with client as request: response = request.get("/packages", params={ "SeB": "b", @@ -609,7 +608,7 @@ def test_packages_search_by_pkgbase(client: TestClient, def test_packages_search_by_exact_pkgbase(client: TestClient, - packages: List[Package]): + packages: list[Package]): with client as request: response = request.get("/packages", params={ "SeB": "B", @@ -634,7 +633,7 @@ def test_packages_search_by_exact_pkgbase(client: TestClient, def test_packages_search_by_keywords(client: TestClient, - packages: List[Package]): + packages: list[Package]): # None of our packages have keywords, so this query should return nothing. with client as request: response = request.get("/packages", params={ @@ -791,7 +790,7 @@ def test_packages_search_by_submitter(client: TestClient, assert len(rows) == 1 -def test_packages_sort_by_name(client: TestClient, packages: List[Package]): +def test_packages_sort_by_name(client: TestClient, packages: list[Package]): with client as request: response = request.get("/packages", params={ "SB": "n", # Name @@ -820,7 +819,7 @@ def test_packages_sort_by_name(client: TestClient, packages: List[Package]): def test_packages_sort_by_votes(client: TestClient, maintainer: User, - packages: List[Package]): + packages: list[Package]): # Set the first package's NumVotes to 1. with db.begin(): packages[0].PackageBase.NumVotes = 1 @@ -855,7 +854,7 @@ def test_packages_sort_by_votes(client: TestClient, def test_packages_sort_by_popularity(client: TestClient, maintainer: User, - packages: List[Package]): + packages: list[Package]): # Set the first package's Popularity to 0.50. with db.begin(): packages[0].PackageBase.Popularity = "0.50" @@ -875,7 +874,7 @@ def test_packages_sort_by_popularity(client: TestClient, def test_packages_sort_by_voted(client: TestClient, maintainer: User, - packages: List[Package]): + packages: list[Package]): now = time.utcnow() with db.begin(): db.create(PackageVote, PackageBase=packages[0].PackageBase, @@ -902,7 +901,7 @@ def test_packages_sort_by_voted(client: TestClient, def test_packages_sort_by_notify(client: TestClient, maintainer: User, - packages: List[Package]): + packages: list[Package]): db.create(PackageNotification, PackageBase=packages[0].PackageBase, User=maintainer) @@ -970,7 +969,7 @@ def test_packages_sort_by_maintainer(client: TestClient, def test_packages_sort_by_last_modified(client: TestClient, - packages: List[Package]): + packages: list[Package]): now = time.utcnow() # Set the first package's ModifiedTS to be 1000 seconds before now. package = packages[0] @@ -996,7 +995,7 @@ def test_packages_sort_by_last_modified(client: TestClient, def test_packages_flagged(client: TestClient, maintainer: User, - packages: List[Package]): + packages: list[Package]): package = packages[0] now = time.utcnow() @@ -1029,7 +1028,7 @@ def test_packages_flagged(client: TestClient, maintainer: User, assert len(rows) == 50 -def test_packages_orphans(client: TestClient, packages: List[Package]): +def test_packages_orphans(client: TestClient, packages: list[Package]): package = packages[0] with db.begin(): package.PackageBase.Maintainer = None diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index 5edae592..3468656e 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -1,7 +1,6 @@ import re from http import HTTPStatus -from typing import List from unittest import mock import pytest @@ -176,7 +175,7 @@ def comment(user: User, package: Package) -> PackageComment: @pytest.fixture -def packages(maintainer: User) -> List[Package]: +def packages(maintainer: User) -> list[Package]: """ Yield 55 packages named pkg_0 .. pkg_54. """ packages_ = [] now = time.utcnow() @@ -197,7 +196,7 @@ def packages(maintainer: User) -> List[Package]: @pytest.fixture -def requests(user: User, packages: List[Package]) -> List[PackageRequest]: +def requests(user: User, packages: list[Package]) -> list[PackageRequest]: pkgreqs = [] deletion_type = db.query(RequestType).filter( RequestType.ID == DELETION_ID diff --git a/test/test_pkgmaint.py b/test/test_pkgmaint.py index 5d6a56de..da758c22 100644 --- a/test/test_pkgmaint.py +++ b/test/test_pkgmaint.py @@ -1,5 +1,3 @@ -from typing import List - import pytest from aurweb import db, time @@ -22,7 +20,7 @@ def user() -> User: @pytest.fixture -def packages(user: User) -> List[Package]: +def packages(user: User) -> list[Package]: output = [] now = time.utcnow() @@ -37,14 +35,14 @@ def packages(user: User) -> List[Package]: yield output -def test_pkgmaint_noop(packages: List[Package]): +def test_pkgmaint_noop(packages: list[Package]): assert len(packages) == 5 pkgmaint.main() packages = db.query(Package).all() assert len(packages) == 5 -def test_pkgmaint(packages: List[Package]): +def test_pkgmaint(packages: list[Package]): assert len(packages) == 5 # Modify the first package so it's out of date and gets deleted. diff --git a/test/test_requests.py b/test/test_requests.py index 5ac558e0..b7ab3835 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -2,7 +2,6 @@ import re from http import HTTPStatus from logging import DEBUG -from typing import List import pytest @@ -91,7 +90,7 @@ def maintainer() -> User: @pytest.fixture -def packages(maintainer: User) -> List[Package]: +def packages(maintainer: User) -> list[Package]: """ Yield 55 packages named pkg_0 .. pkg_54. """ packages_ = [] now = time.utcnow() @@ -112,7 +111,7 @@ def packages(maintainer: User) -> List[Package]: @pytest.fixture -def requests(user: User, packages: List[Package]) -> List[PackageRequest]: +def requests(user: User, packages: list[Package]) -> list[PackageRequest]: pkgreqs = [] with db.begin(): for i in range(55): @@ -660,8 +659,8 @@ def test_requests_unauthorized(client: TestClient): def test_requests(client: TestClient, tu_user: User, - packages: List[Package], - requests: List[PackageRequest]): + packages: list[Package], + requests: list[PackageRequest]): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: resp = request.get("/requests", params={ @@ -697,7 +696,7 @@ def test_requests(client: TestClient, def test_requests_selfmade(client: TestClient, user: User, - requests: List[PackageRequest]): + requests: list[PackageRequest]): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: resp = request.get("/requests", cookies=cookies) diff --git a/test/test_rpc.py b/test/test_rpc.py index 2f7f7860..0e24467a 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1,7 +1,6 @@ import re from http import HTTPStatus -from typing import List from unittest import mock import orjson @@ -62,7 +61,7 @@ def user3() -> User: @pytest.fixture -def packages(user: User, user2: User, user3: User) -> List[Package]: +def packages(user: User, user2: User, user3: User) -> list[Package]: output = [] # Create package records used in our tests. @@ -123,7 +122,7 @@ def packages(user: User, user2: User, user3: User) -> List[Package]: @pytest.fixture -def depends(packages: List[Package]) -> List[PackageDependency]: +def depends(packages: list[Package]) -> list[PackageDependency]: output = [] with db.begin(): @@ -162,7 +161,7 @@ def depends(packages: List[Package]) -> List[PackageDependency]: @pytest.fixture -def relations(user: User, packages: List[Package]) -> List[PackageRelation]: +def relations(user: User, packages: list[Package]) -> list[PackageRelation]: output = [] with db.begin(): @@ -241,9 +240,9 @@ def test_rpc_documentation_missing(): def test_rpc_singular_info(client: TestClient, user: User, - packages: List[Package], - depends: List[PackageDependency], - relations: List[PackageRelation]): + packages: list[Package], + depends: list[PackageDependency], + relations: list[PackageRelation]): # Define expected response. pkg = packages[0] expected_data = { @@ -310,7 +309,7 @@ def test_rpc_nonexistent_package(client: TestClient): assert response_data["resultcount"] == 0 -def test_rpc_multiinfo(client: TestClient, packages: List[Package]): +def test_rpc_multiinfo(client: TestClient, packages: list[Package]): # Make dummy request. request_packages = ["big-chungus", "chungy-chungus"] with client as request: @@ -328,7 +327,7 @@ def test_rpc_multiinfo(client: TestClient, packages: List[Package]): assert request_packages == [] -def test_rpc_mixedargs(client: TestClient, packages: List[Package]): +def test_rpc_mixedargs(client: TestClient, packages: list[Package]): # Make dummy request. response1_packages = ["gluggly-chungus"] response2_packages = ["gluggly-chungus", "chungy-chungus"] @@ -361,9 +360,9 @@ def test_rpc_mixedargs(client: TestClient, packages: List[Package]): def test_rpc_no_dependencies_omits_key(client: TestClient, user: User, - packages: List[Package], - depends: List[PackageDependency], - relations: List[PackageRelation]): + packages: list[Package], + depends: list[PackageDependency], + relations: list[PackageRelation]): """ This makes sure things like 'MakeDepends' get removed from JSON strings when they don't have set values. @@ -517,7 +516,7 @@ def test_rpc_no_args(client: TestClient): assert expected_data == response_data -def test_rpc_no_maintainer(client: TestClient, packages: List[Package]): +def test_rpc_no_maintainer(client: TestClient, packages: list[Package]): # Make dummy request. with client as request: response = request.get("/rpc", params={ @@ -531,7 +530,7 @@ def test_rpc_no_maintainer(client: TestClient, packages: List[Package]): assert response_data["results"][0]["Maintainer"] is None -def test_rpc_suggest_pkgbase(client: TestClient, packages: List[Package]): +def test_rpc_suggest_pkgbase(client: TestClient, packages: list[Package]): params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"} with client as request: response = request.get("/rpc", params=params) @@ -560,7 +559,7 @@ def test_rpc_suggest_pkgbase(client: TestClient, packages: List[Package]): assert data == [] -def test_rpc_suggest(client: TestClient, packages: List[Package]): +def test_rpc_suggest(client: TestClient, packages: list[Package]): params = {"v": 5, "type": "suggest", "arg": "other"} with client as request: response = request.get("/rpc", params=params) @@ -600,7 +599,7 @@ def mock_config_getint(section: str, key: str): @mock.patch("aurweb.config.getint", side_effect=mock_config_getint) def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient, - pipeline: Pipeline, packages: List[Package]): + pipeline: Pipeline, packages: list[Package]): params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"} for i in range(4): @@ -626,7 +625,7 @@ def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient, assert response.status_code == int(HTTPStatus.OK) -def test_rpc_etag(client: TestClient, packages: List[Package]): +def test_rpc_etag(client: TestClient, packages: list[Package]): params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"} with client as request: @@ -647,7 +646,7 @@ def test_rpc_search_arg_too_small(client: TestClient): assert response.json().get("error") == "Query arg too small." -def test_rpc_search(client: TestClient, packages: List[Package]): +def test_rpc_search(client: TestClient, packages: list[Package]): params = {"v": 5, "type": "search", "arg": "big"} with client as request: response = request.get("/rpc", params=params) @@ -673,7 +672,7 @@ def test_rpc_search(client: TestClient, packages: List[Package]): assert response.json().get("error") == "No request type/data specified." -def test_rpc_msearch(client: TestClient, user: User, packages: List[Package]): +def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]): params = {"v": 5, "type": "msearch", "arg": user.Username} with client as request: response = request.get("/rpc", params=params) @@ -709,8 +708,8 @@ def test_rpc_msearch(client: TestClient, user: User, packages: List[Package]): assert result.get("Name") == "big-chungus" -def test_rpc_search_depends(client: TestClient, packages: List[Package], - depends: List[PackageDependency]): +def test_rpc_search_depends(client: TestClient, packages: list[Package], + depends: list[PackageDependency]): params = { "v": 5, "type": "search", "by": "depends", "arg": "chungus-depends" } @@ -722,8 +721,8 @@ def test_rpc_search_depends(client: TestClient, packages: List[Package], assert result.get("Name") == packages[0].Name -def test_rpc_search_makedepends(client: TestClient, packages: List[Package], - depends: List[PackageDependency]): +def test_rpc_search_makedepends(client: TestClient, packages: list[Package], + depends: list[PackageDependency]): params = { "v": 5, "type": "search", @@ -738,8 +737,8 @@ def test_rpc_search_makedepends(client: TestClient, packages: List[Package], assert result.get("Name") == packages[0].Name -def test_rpc_search_optdepends(client: TestClient, packages: List[Package], - depends: List[PackageDependency]): +def test_rpc_search_optdepends(client: TestClient, packages: list[Package], + depends: list[PackageDependency]): params = { "v": 5, "type": "search", @@ -754,8 +753,8 @@ def test_rpc_search_optdepends(client: TestClient, packages: List[Package], assert result.get("Name") == packages[0].Name -def test_rpc_search_checkdepends(client: TestClient, packages: List[Package], - depends: List[PackageDependency]): +def test_rpc_search_checkdepends(client: TestClient, packages: list[Package], + depends: list[PackageDependency]): params = { "v": 5, "type": "search", @@ -802,7 +801,7 @@ def test_rpc_jsonp_callback(client: TestClient): assert response.json().get("error") == "Invalid callback name." -def test_rpc_post(client: TestClient, packages: List[Package]): +def test_rpc_post(client: TestClient, packages: list[Package]): data = { "v": 5, "type": "info", @@ -816,7 +815,7 @@ def test_rpc_post(client: TestClient, packages: List[Package]): def test_rpc_too_many_search_results(client: TestClient, - packages: List[Package]): + packages: list[Package]): config_getint = config.getint def mock_config(section: str, key: str): @@ -831,7 +830,7 @@ def test_rpc_too_many_search_results(client: TestClient, assert resp.json().get("error") == "Too many package results." -def test_rpc_too_many_info_results(client: TestClient, packages: List[Package]): +def test_rpc_too_many_info_results(client: TestClient, packages: list[Package]): # Make many of these packages depend and rely on each other. # This way, we can test to see that the exceeded limit stays true # regardless of the number of related records. diff --git a/test/test_templates.py b/test/test_templates.py index 7d6b585c..e4888127 100644 --- a/test/test_templates.py +++ b/test/test_templates.py @@ -1,6 +1,6 @@ import re -from typing import Any, Dict +from typing import Any import pytest @@ -126,7 +126,7 @@ def test_commit_hash(): assert commit_hash not in render -def pager_context(num_packages: int) -> Dict[str, Any]: +def pager_context(num_packages: int) -> dict[str, Any]: return { "request": Request(), "singular": "%d package found.", From 1d6335363c028591d72eac40c85109d435e469cb Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 1 Aug 2022 19:02:17 +0300 Subject: [PATCH 1525/1891] fix: strip whitespace when parsing package keywords Remove all extra whitespace when parsing Keywords to ensure we don't add empty keywords in the DB. Closes: #332 Signed-off-by: Leonidas Spyropoulos --- aurweb/routers/pkgbase.py | 2 +- test/test_pkgbase_routes.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 2cef5436..6cd4199d 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -98,7 +98,7 @@ async def pkgbase_keywords(request: Request, name: str, # Lowercase all keywords. Our database table is case insensitive, # and providing CI duplicates of keywords is erroneous. - keywords = set(k.lower() for k in keywords.split(" ")) + keywords = set(k.lower() for k in keywords.split()) # Delete all keywords which are not supplied by the user. with db.begin(): diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index 3468656e..a152c590 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -1396,3 +1396,33 @@ def test_pkgbase_keywords(client: TestClient, user: User, package: Package): expected = ["abc", "test"] for i, keyword in enumerate(keywords): assert keyword.text.strip() == expected[i] + + +def test_pkgbase_empty_keywords(client: TestClient, user: User, package: Package): + endpoint = f"/pkgbase/{package.PackageBase.Name}" + with client as request: + resp = request.get(endpoint) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + keywords = root.xpath('//a[@class="keyword"]') + assert len(keywords) == 0 + + cookies = {"AURSID": user.login(Request(), "testPassword")} + post_endpoint = f"{endpoint}/keywords" + with client as request: + resp = request.post(post_endpoint, data={ + "keywords": "abc test foo bar " + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + with client as request: + resp = request.get(resp.headers.get("location")) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + keywords = root.xpath('//a[@class="keyword"]') + assert len(keywords) == 4 + expected = ["abc", "bar", "foo", "test"] + for i, keyword in enumerate(keywords): + assert keyword.text.strip() == expected[i] From 2c080b2ea9a91668e6009c690e8e46826e4d05cb Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 2 Aug 2022 20:27:47 +0300 Subject: [PATCH 1526/1891] feature: add pagination on comments Fixes: #354 Signed-off-by: Leonidas Spyropoulos --- aurweb/defaults.py | 3 +++ aurweb/pkgbase/util.py | 13 +++++++++++-- templates/partials/packages/comments.html | 8 ++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/aurweb/defaults.py b/aurweb/defaults.py index 51072e8f..91ba367a 100644 --- a/aurweb/defaults.py +++ b/aurweb/defaults.py @@ -6,6 +6,9 @@ O = 0 # Default [P]er [P]age PP = 50 +# Default Comments Per Page +COMMENTS_PER_PAGE = 10 + # A whitelist of valid PP values PP_WHITELIST = {50, 100, 250} diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index 5a7d952a..5ffe490e 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -3,7 +3,7 @@ from typing import Any from fastapi import Request from sqlalchemy import and_ -from aurweb import config, db, l10n, util +from aurweb import config, db, defaults, l10n, util from aurweb.models import PackageBase, User from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_comment import PackageComment @@ -31,6 +31,12 @@ def make_context(request: Request, pkgbase: PackageBase, if not context: context = _make_context(request, pkgbase.Name) + # Per page and offset. + offset, per_page = util.sanitize_params( + request.query_params.get("O", defaults.O), + request.query_params.get("PP", defaults.COMMENTS_PER_PAGE)) + context["O"] = offset + context["PP"] = per_page context["git_clone_uri_anon"] = config.get("options", "git_clone_uri_anon") context["git_clone_uri_priv"] = config.get("options", "git_clone_uri_priv") context["pkgbase"] = pkgbase @@ -44,9 +50,12 @@ def make_context(request: Request, pkgbase: PackageBase, context["packages_count"] = pkgbase.packages.count() context["keywords"] = pkgbase.keywords + context["comments_total"] = pkgbase.comments.order_by( + PackageComment.CommentTS.desc() + ).count() context["comments"] = pkgbase.comments.order_by( PackageComment.CommentTS.desc() - ) + ).limit(per_page).offset(offset) context["pinned_comments"] = pkgbase.comments.filter( PackageComment.PinnedTS != 0 ).order_by(PackageComment.CommentTS.desc()) diff --git a/templates/partials/packages/comments.html b/templates/partials/packages/comments.html index 6e6b9a47..9d49bc86 100644 --- a/templates/partials/packages/comments.html +++ b/templates/partials/packages/comments.html @@ -33,6 +33,14 @@ {{ "Latest Comments" | tr }} + {% set page = ((O / PP) | int) %} + {% set pages = ((comments_total / PP) | ceil) %} + + {% if pages > 1 %} +

      + {{ page | pager_nav(comments_total, prefix) | safe }} +

      + {% endif %} {% for comment in comments.all() %} {% include "partials/packages/comment.html" %} From 9648628a2c29397216a609b75287a3e6643e67b2 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 9 Aug 2022 16:43:27 -0700 Subject: [PATCH 1527/1891] update: requests dependency Signed-off-by: Kevin Morris --- poetry.lock | 794 +++++++++++-------------------------------------- pyproject.toml | 2 +- 2 files changed, 175 insertions(+), 621 deletions(-) diff --git a/poetry.lock b/poetry.lock index fe1575a6..72b66638 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,11 +8,11 @@ python-versions = ">=3.6,<4.0" [[package]] name = "alembic" -version = "1.7.6" +version = "1.8.1" description = "A database migration tool for SQLAlchemy." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] Mako = "*" @@ -23,7 +23,7 @@ tz = ["python-dateutil"] [[package]] name = "anyio" -version = "3.5.0" +version = "3.6.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "main" optional = false @@ -35,12 +35,12 @@ sniffio = ">=1.1" [package.extras] doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] trio = ["trio (>=0.16)"] [[package]] name = "asgiref" -version = "3.5.0" +version = "3.5.2" description = "ASGI specs, helper code, and adapters" category = "main" optional = false @@ -51,7 +51,7 @@ tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] [[package]] name = "atomicwrites" -version = "1.4.0" +version = "1.4.1" description = "Atomic file writes." category = "main" optional = false @@ -59,17 +59,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "21.4.0" +version = "22.1.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.5" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"] [[package]] name = "authlib" @@ -87,7 +87,7 @@ client = ["requests"] [[package]] name = "bcrypt" -version = "3.2.0" +version = "3.2.2" description = "Modern password hashing for your software and your servers" category = "main" optional = false @@ -95,7 +95,6 @@ python-versions = ">=3.6" [package.dependencies] cffi = ">=1.1" -six = ">=1.4.1" [package.extras] tests = ["pytest (>=3.2.1,!=3.3.0)"] @@ -116,15 +115,15 @@ webencodings = "*" [[package]] name = "certifi" -version = "2021.10.8" +version = "2022.6.15" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "cffi" -version = "1.15.0" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -135,29 +134,29 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "2.0.11" +version = "2.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = ">=3.5.0" +python-versions = ">=3.6.0" [package.extras] unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.3" +version = "8.1.3" description = "Composable command line interface toolkit" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" -version = "0.4.4" +version = "0.4.5" description = "Cross-platform colored terminal text." category = "main" optional = false @@ -165,21 +164,21 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.3.1" +version = "6.4.3" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] -tomli = {version = "*", optional = true, markers = "extra == \"toml\""} +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] toml = ["tomli"] [[package]] name = "cryptography" -version = "36.0.1" +version = "37.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -194,11 +193,11 @@ docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] sdist = ["setuptools_rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] name = "dnspython" -version = "2.2.0" +version = "2.2.1" description = "DNS toolkit" category = "main" optional = false @@ -237,21 +236,20 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "1.7.0" +version = "1.9.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7,<4.0" [package.dependencies] -packaging = "*" -redis = "<4.1.0" -six = ">=1.12" -sortedcontainers = "*" +redis = "<4.4" +six = ">=1.16.0,<2.0.0" +sortedcontainers = ">=2.4.0,<3.0.0" [package.extras] -aioredis = ["aioredis"] -lua = ["lupa"] +aioredis = ["aioredis (>=2.0.1,<3.0.0)"] +lua = ["lupa (>=1.13,<2.0)"] [[package]] name = "fastapi" @@ -285,7 +283,7 @@ python-dateutil = "*" [[package]] name = "filelock" -version = "3.4.2" +version = "3.7.1" description = "A platform independent file lock." category = "main" optional = false @@ -436,7 +434,7 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.10.1" +version = "4.12.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -446,9 +444,9 @@ python-versions = ">=3.7" zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -474,19 +472,19 @@ plugins = ["setuptools"] [[package]] name = "itsdangerous" -version = "2.0.1" +version = "2.1.2" description = "Safely pass data to untrusted environments and back." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "jinja2" -version = "3.0.3" +version = "3.1.2" description = "A very fast and expressive template engine." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] MarkupSafe = ">=2.0" @@ -496,7 +494,7 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "lxml" -version = "4.7.1" +version = "4.9.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." category = "main" optional = false @@ -510,11 +508,11 @@ source = ["Cython (>=0.29.7)"] [[package]] name = "mako" -version = "1.1.6" -description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +version = "1.2.1" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.7" [package.dependencies] MarkupSafe = ">=0.9.2" @@ -522,14 +520,15 @@ MarkupSafe = ">=0.9.2" [package.extras] babel = ["babel"] lingua = ["lingua"] +testing = ["pytest"] [[package]] name = "markdown" -version = "3.3.6" +version = "3.4.1" description = "Python implementation of Markdown." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} @@ -539,11 +538,11 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.0.1" +version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "mccabe" @@ -555,7 +554,7 @@ python-versions = "*" [[package]] name = "mysqlclient" -version = "2.1.0" +version = "2.1.1" description = "Python interface to MySQL" category = "main" optional = false @@ -563,7 +562,7 @@ python-versions = ">=3.5" [[package]] name = "orjson" -version = "3.6.6" +version = "3.7.11" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false @@ -626,7 +625,7 @@ python-versions = ">=3.6.1" [[package]] name = "prometheus-client" -version = "0.13.1" +version = "0.14.1" description = "Python client for the Prometheus monitoring system." category = "main" optional = false @@ -637,11 +636,11 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.7.1" +version = "5.8.2" description = "Instrument your FastAPI with Prometheus metrics" category = "main" optional = false -python-versions = ">=3.6.0,<4.0.0" +python-versions = ">=3.7.0,<4.0.0" [package.dependencies] fastapi = ">=0.38.1,<1.0.0" @@ -649,11 +648,11 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "3.19.4" +version = "3.20.1" description = "Protocol Buffers" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [[package]] name = "py" @@ -689,8 +688,8 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pydantic" -version = "1.9.0" -description = "Data validation and settings management using python 3.6 type hinting" +version = "1.9.1" +description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.6.1" @@ -712,25 +711,25 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygit2" -version = "1.7.2" +version = "1.10.0" description = "Python bindings for libgit2." category = "main" optional = false python-versions = ">=3.7" [package.dependencies] -cffi = ">=1.4.0" +cffi = ">=1.9.1" [[package]] name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.8" [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pytest" @@ -859,21 +858,21 @@ hiredis = ["hiredis (>=0.1.3)"] [[package]] name = "requests" -version = "2.27.1" +version = "2.28.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7, <4" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" [package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rfc3986" @@ -915,7 +914,7 @@ python-versions = "*" [[package]] name = "sqlalchemy" -version = "1.4.31" +version = "1.4.40" description = "Database Abstraction Library" category = "main" optional = false @@ -928,17 +927,18 @@ greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platfo aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3)"] -mariadb_connector = ["mariadb (>=1.0.1)"] +asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3,!=0.2.4)"] +mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] mssql_pymssql = ["pymssql"] mssql_pyodbc = ["pyodbc"] mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] +mysql_connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] postgresql = ["psycopg2 (>=2.7)"] postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] -postgresql_pg8000 = ["pg8000 (>=1.16.6)"] +postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] postgresql_psycopg2binary = ["psycopg2-binary"] postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql (<1)", "pymysql"] @@ -990,7 +990,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" -version = "2.0.0" +version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false @@ -998,22 +998,22 @@ python-versions = ">=3.7" [[package]] name = "typing-extensions" -version = "4.0.1" -description = "Backported and Experimental Type Hints for Python 3.6+" +version = "4.3.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "urllib3" -version = "1.26.8" +version = "1.26.11" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] @@ -1043,225 +1043,76 @@ python-versions = "*" [[package]] name = "werkzeug" -version = "2.0.2" +version = "2.2.2" description = "The comprehensive WSGI web application library." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" + +[package.dependencies] +MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog"] [[package]] name = "wsproto" -version = "1.0.0" +version = "1.1.0" description = "WebSockets state-machine based protocol implementation" category = "main" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7.0" [package.dependencies] h11 = ">=0.9.0,<1" [[package]] name = "zipp" -version = "3.7.0" +version = "3.8.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "ffe7ab6733020584382d2d01950153072a46d0738f6d2fe52ac84653d0b16086" +content-hash = "7f939b59288f41a063f4a6634a61d3744b1f73e4c3bce76e97dc766b7919ffe7" [metadata.files] aiofiles = [ {file = "aiofiles-0.7.0-py3-none-any.whl", hash = "sha256:c67a6823b5f23fcab0a2595a289cec7d8c863ffcb4322fb8cd6b90400aedfdbc"}, {file = "aiofiles-0.7.0.tar.gz", hash = "sha256:a1c4fc9b2ff81568c83e21392a82f344ea9d23da906e4f6a52662764545e19d4"}, ] -alembic = [ - {file = "alembic-1.7.6-py3-none-any.whl", hash = "sha256:ad842f2c3ab5c5d4861232730779c05e33db4ba880a08b85eb505e87c01095bc"}, - {file = "alembic-1.7.6.tar.gz", hash = "sha256:6c0c05e9768a896d804387e20b299880fe01bc56484246b0dffe8075d6d3d847"}, -] -anyio = [ - {file = "anyio-3.5.0-py3-none-any.whl", hash = "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e"}, - {file = "anyio-3.5.0.tar.gz", hash = "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6"}, -] -asgiref = [ - {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"}, - {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"}, -] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] -attrs = [ - {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, - {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, -] +alembic = [] +anyio = [] +asgiref = [] +atomicwrites = [] +attrs = [] authlib = [ {file = "Authlib-0.15.5-py2.py3-none-any.whl", hash = "sha256:ecf4a7a9f2508c0bb07e93a752dd3c495cfaffc20e864ef0ffc95e3f40d2abaf"}, {file = "Authlib-0.15.5.tar.gz", hash = "sha256:b83cf6360c8e92b0e9df0d1f32d675790bcc4e3c03977499b1eed24dcdef4252"}, ] -bcrypt = [ - {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b589229207630484aefe5899122fb938a5b017b0f4349f769b8c13e78d99a8fd"}, - {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a0584a92329210fcd75eb8a3250c5a941633f8bfaf2a18f81009b097732839b7"}, - {file = "bcrypt-3.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:56e5da069a76470679f312a7d3d23deb3ac4519991a0361abc11da837087b61d"}, - {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, - {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, - {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, -] +bcrypt = [] bleach = [ {file = "bleach-4.1.0-py2.py3-none-any.whl", hash = "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"}, {file = "bleach-4.1.0.tar.gz", hash = "sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da"}, ] -certifi = [ - {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, - {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, -] -cffi = [ - {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, - {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, - {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, - {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, - {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, - {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, - {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, - {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, - {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, - {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, - {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, - {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, - {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, - {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, - {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, - {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, - {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, -] -charset-normalizer = [ - {file = "charset-normalizer-2.0.11.tar.gz", hash = "sha256:98398a9d69ee80548c762ba991a4728bfc3836768ed226b3945908d1a688371c"}, - {file = "charset_normalizer-2.0.11-py3-none-any.whl", hash = "sha256:2842d8f5e82a1f6aa437380934d5e1cd4fcf2003b06fed6940769c164a480a45"}, -] -click = [ - {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, - {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, -] +certifi = [] +cffi = [] +charset-normalizer = [] +click = [] colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] -coverage = [ - {file = "coverage-6.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525"}, - {file = "coverage-6.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e"}, - {file = "coverage-6.3.1-cp310-cp310-win32.whl", hash = "sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217"}, - {file = "coverage-6.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb"}, - {file = "coverage-6.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8"}, - {file = "coverage-6.3.1-cp37-cp37m-win32.whl", hash = "sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0"}, - {file = "coverage-6.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687"}, - {file = "coverage-6.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320"}, - {file = "coverage-6.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a"}, - {file = "coverage-6.3.1-cp38-cp38-win32.whl", hash = "sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10"}, - {file = "coverage-6.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f"}, - {file = "coverage-6.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d"}, - {file = "coverage-6.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38"}, - {file = "coverage-6.3.1-cp39-cp39-win32.whl", hash = "sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2"}, - {file = "coverage-6.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa"}, - {file = "coverage-6.3.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2"}, - {file = "coverage-6.3.1.tar.gz", hash = "sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8"}, -] -cryptography = [ - {file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b"}, - {file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3"}, - {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2"}, - {file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f"}, - {file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3"}, - {file = "cryptography-36.0.1-cp36-abi3-win32.whl", hash = "sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca"}, - {file = "cryptography-36.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf"}, - {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9"}, - {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1"}, - {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903"}, - {file = "cryptography-36.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316"}, - {file = "cryptography-36.0.1.tar.gz", hash = "sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638"}, -] -dnspython = [ - {file = "dnspython-2.2.0-py3-none-any.whl", hash = "sha256:081649da27ced5e75709a1ee542136eaba9842a0fe4c03da4fb0a3d3ed1f3c44"}, - {file = "dnspython-2.2.0.tar.gz", hash = "sha256:e79351e032d0b606b98d38a4b0e6e2275b31a5b85c873e587cc11b73aca026d6"}, + {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, + {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] +coverage = [] +cryptography = [] +dnspython = [] email-validator = [ {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"}, @@ -1270,10 +1121,7 @@ execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, ] -fakeredis = [ - {file = "fakeredis-1.7.0-py3-none-any.whl", hash = "sha256:6f1e04f64557ad3b6835bdc6e5a8d022cbace4bdc24a47ad58f6a72e0fbff760"}, - {file = "fakeredis-1.7.0.tar.gz", hash = "sha256:c9bd12e430336cbd3e189fae0e91eb99997b93e76dbfdd6ed67fa352dc684c71"}, -] +fakeredis = [] fastapi = [ {file = "fastapi-0.71.0-py3-none-any.whl", hash = "sha256:a78eca6b084de9667f2d5f37e2ae297270e5a119cd01c2f04815795da92fc87f"}, {file = "fastapi-0.71.0.tar.gz", hash = "sha256:2b5ac0ae89c80b40d1dd4b2ea0bb1f78d7c4affd3644d080bf050f084759fff2"}, @@ -1281,10 +1129,7 @@ fastapi = [ feedgen = [ {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, ] -filelock = [ - {file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"}, - {file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"}, -] +filelock = [] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, @@ -1382,10 +1227,7 @@ idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] -importlib-metadata = [ - {file = "importlib_metadata-4.10.1-py3-none-any.whl", hash = "sha256:899e2a40a8c4a1aec681feef45733de8a6c58f3f6a0dbed2eb6574b4387a77b6"}, - {file = "importlib_metadata-4.10.1.tar.gz", hash = "sha256:951f0d8a5b7260e9db5e41d429285b5f451e928479f19d80818878527d36e95e"}, -] +importlib-metadata = [] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, @@ -1394,192 +1236,62 @@ isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -itsdangerous = [ - {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, - {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"}, -] +itsdangerous = [] jinja2 = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, -] -lxml = [ - {file = "lxml-4.7.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:d546431636edb1d6a608b348dd58cc9841b81f4116745857b6cb9f8dadb2725f"}, - {file = "lxml-4.7.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6308062534323f0d3edb4e702a0e26a76ca9e0e23ff99be5d82750772df32a9e"}, - {file = "lxml-4.7.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f76dbe44e31abf516114f6347a46fa4e7c2e8bceaa4b6f7ee3a0a03c8eba3c17"}, - {file = "lxml-4.7.1-cp27-cp27m-win32.whl", hash = "sha256:d5618d49de6ba63fe4510bdada62d06a8acfca0b4b5c904956c777d28382b419"}, - {file = "lxml-4.7.1-cp27-cp27m-win_amd64.whl", hash = "sha256:9393a05b126a7e187f3e38758255e0edf948a65b22c377414002d488221fdaa2"}, - {file = "lxml-4.7.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50d3dba341f1e583265c1a808e897b4159208d814ab07530202b6036a4d86da5"}, - {file = "lxml-4.7.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:44f552e0da3c8ee3c28e2eb82b0b784200631687fc6a71277ea8ab0828780e7d"}, - {file = "lxml-4.7.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:e662c6266e3a275bdcb6bb049edc7cd77d0b0f7e119a53101d367c841afc66dc"}, - {file = "lxml-4.7.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4c093c571bc3da9ebcd484e001ba18b8452903cd428c0bc926d9b0141bcb710e"}, - {file = "lxml-4.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3e26ad9bc48d610bf6cc76c506b9e5ad9360ed7a945d9be3b5b2c8535a0145e3"}, - {file = "lxml-4.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a5f623aeaa24f71fce3177d7fee875371345eb9102b355b882243e33e04b7175"}, - {file = "lxml-4.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7b5e2acefd33c259c4a2e157119c4373c8773cf6793e225006a1649672ab47a6"}, - {file = "lxml-4.7.1-cp310-cp310-win32.whl", hash = "sha256:67fa5f028e8a01e1d7944a9fb616d1d0510d5d38b0c41708310bd1bc45ae89f6"}, - {file = "lxml-4.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:b1d381f58fcc3e63fcc0ea4f0a38335163883267f77e4c6e22d7a30877218a0e"}, - {file = "lxml-4.7.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:38d9759733aa04fb1697d717bfabbedb21398046bd07734be7cccc3d19ea8675"}, - {file = "lxml-4.7.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dfd0d464f3d86a1460683cd742306d1138b4e99b79094f4e07e1ca85ee267fe7"}, - {file = "lxml-4.7.1-cp35-cp35m-win32.whl", hash = "sha256:534e946bce61fd162af02bad7bfd2daec1521b71d27238869c23a672146c34a5"}, - {file = "lxml-4.7.1-cp35-cp35m-win_amd64.whl", hash = "sha256:6ec829058785d028f467be70cd195cd0aaf1a763e4d09822584ede8c9eaa4b03"}, - {file = "lxml-4.7.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:ade74f5e3a0fd17df5782896ddca7ddb998845a5f7cd4b0be771e1ffc3b9aa5b"}, - {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41358bfd24425c1673f184d7c26c6ae91943fe51dfecc3603b5e08187b4bcc55"}, - {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6e56521538f19c4a6690f439fefed551f0b296bd785adc67c1777c348beb943d"}, - {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5b0f782f0e03555c55e37d93d7a57454efe7495dab33ba0ccd2dbe25fc50f05d"}, - {file = "lxml-4.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:490712b91c65988012e866c411a40cc65b595929ececf75eeb4c79fcc3bc80a6"}, - {file = "lxml-4.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:34c22eb8c819d59cec4444d9eebe2e38b95d3dcdafe08965853f8799fd71161d"}, - {file = "lxml-4.7.1-cp36-cp36m-win32.whl", hash = "sha256:2a906c3890da6a63224d551c2967413b8790a6357a80bf6b257c9a7978c2c42d"}, - {file = "lxml-4.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:36b16fecb10246e599f178dd74f313cbdc9f41c56e77d52100d1361eed24f51a"}, - {file = "lxml-4.7.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a5edc58d631170de90e50adc2cc0248083541affef82f8cd93bea458e4d96db8"}, - {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:87c1b0496e8c87ec9db5383e30042357b4839b46c2d556abd49ec770ce2ad868"}, - {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:0a5f0e4747f31cff87d1eb32a6000bde1e603107f632ef4666be0dc065889c7a"}, - {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:bf6005708fc2e2c89a083f258b97709559a95f9a7a03e59f805dd23c93bc3986"}, - {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc15874816b9320581133ddc2096b644582ab870cf6a6ed63684433e7af4b0d3"}, - {file = "lxml-4.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b5e96e25e70917b28a5391c2ed3ffc6156513d3db0e1476c5253fcd50f7a944"}, - {file = "lxml-4.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ec9027d0beb785a35aa9951d14e06d48cfbf876d8ff67519403a2522b181943b"}, - {file = "lxml-4.7.1-cp37-cp37m-win32.whl", hash = "sha256:9fbc0dee7ff5f15c4428775e6fa3ed20003140560ffa22b88326669d53b3c0f4"}, - {file = "lxml-4.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1104a8d47967a414a436007c52f533e933e5d52574cab407b1e49a4e9b5ddbd1"}, - {file = "lxml-4.7.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:fc9fb11b65e7bc49f7f75aaba1b700f7181d95d4e151cf2f24d51bfd14410b77"}, - {file = "lxml-4.7.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:317bd63870b4d875af3c1be1b19202de34c32623609ec803b81c99193a788c1e"}, - {file = "lxml-4.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:610807cea990fd545b1559466971649e69302c8a9472cefe1d6d48a1dee97440"}, - {file = "lxml-4.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:09b738360af8cb2da275998a8bf79517a71225b0de41ab47339c2beebfff025f"}, - {file = "lxml-4.7.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a2ab9d089324d77bb81745b01f4aeffe4094306d939e92ba5e71e9a6b99b71e"}, - {file = "lxml-4.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eed394099a7792834f0cb4a8f615319152b9d801444c1c9e1b1a2c36d2239f9e"}, - {file = "lxml-4.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:735e3b4ce9c0616e85f302f109bdc6e425ba1670a73f962c9f6b98a6d51b77c9"}, - {file = "lxml-4.7.1-cp38-cp38-win32.whl", hash = "sha256:772057fba283c095db8c8ecde4634717a35c47061d24f889468dc67190327bcd"}, - {file = "lxml-4.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:13dbb5c7e8f3b6a2cf6e10b0948cacb2f4c9eb05029fe31c60592d08ac63180d"}, - {file = "lxml-4.7.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:718d7208b9c2d86aaf0294d9381a6acb0158b5ff0f3515902751404e318e02c9"}, - {file = "lxml-4.7.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:5bee1b0cbfdb87686a7fb0e46f1d8bd34d52d6932c0723a86de1cc532b1aa489"}, - {file = "lxml-4.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e410cf3a2272d0a85526d700782a2fa92c1e304fdcc519ba74ac80b8297adf36"}, - {file = "lxml-4.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:585ea241ee4961dc18a95e2f5581dbc26285fcf330e007459688096f76be8c42"}, - {file = "lxml-4.7.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a555e06566c6dc167fbcd0ad507ff05fd9328502aefc963cb0a0547cfe7f00db"}, - {file = "lxml-4.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:adaab25be351fff0d8a691c4f09153647804d09a87a4e4ea2c3f9fe9e8651851"}, - {file = "lxml-4.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:82d16a64236970cb93c8d63ad18c5b9f138a704331e4b916b2737ddfad14e0c4"}, - {file = "lxml-4.7.1-cp39-cp39-win32.whl", hash = "sha256:59e7da839a1238807226f7143c68a479dee09244d1b3cf8c134f2fce777d12d0"}, - {file = "lxml-4.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:a1bbc4efa99ed1310b5009ce7f3a1784698082ed2c1ef3895332f5df9b3b92c2"}, - {file = "lxml-4.7.1-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:0607ff0988ad7e173e5ddf7bf55ee65534bd18a5461183c33e8e41a59e89edf4"}, - {file = "lxml-4.7.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:6c198bfc169419c09b85ab10cb0f572744e686f40d1e7f4ed09061284fc1303f"}, - {file = "lxml-4.7.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a58d78653ae422df6837dd4ca0036610b8cb4962b5cfdbd337b7b24de9e5f98a"}, - {file = "lxml-4.7.1-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:e18281a7d80d76b66a9f9e68a98cf7e1d153182772400d9a9ce855264d7d0ce7"}, - {file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8e54945dd2eeb50925500957c7c579df3cd07c29db7810b83cf30495d79af267"}, - {file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60"}, - {file = "lxml-4.7.1.tar.gz", hash = "sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24"}, -] -mako = [ - {file = "Mako-1.1.6-py2.py3-none-any.whl", hash = "sha256:afaf8e515d075b22fad7d7b8b30e4a1c90624ff2f3733a06ec125f5a5f043a57"}, - {file = "Mako-1.1.6.tar.gz", hash = "sha256:4e9e345a41924a954251b95b4b28e14a301145b544901332e658907a7464b6b2"}, -] -markdown = [ - {file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"}, - {file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"}, + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] +lxml = [] +mako = [] +markdown = [] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] -mysqlclient = [ - {file = "mysqlclient-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:02c8826e6add9b20f4cb12dcf016485f7b1d6e30356a1204d05431867a1b3947"}, - {file = "mysqlclient-2.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b62d23c11c516cedb887377c8807628c1c65d57593b57853186a6ee18b0c6a5b"}, - {file = "mysqlclient-2.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2c8410f54492a3d2488a6a53e2d85b7e016751a1e7d116e7aea9c763f59f5e8c"}, - {file = "mysqlclient-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:e6279263d5a9feca3e0edbc2b2a52c057375bf301d47da2089c075ff76331d14"}, - {file = "mysqlclient-2.1.0.tar.gz", hash = "sha256:973235686f1b720536d417bf0a0d39b4ab3d5086b2b6ad5e6752393428c02b12"}, -] -orjson = [ - {file = "orjson-3.6.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:e4a7cad6c63306318453980d302c7c0b74c0cc290dd1f433bbd7d31a5af90cf1"}, - {file = "orjson-3.6.6-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e533941dca4a0530a876de32e54bf2fd3269cdec3751aebde7bfb5b5eba98e74"}, - {file = "orjson-3.6.6-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:9adf63be386eaa34278967512b83ff8fc4bed036a246391ae236f68d23c47452"}, - {file = "orjson-3.6.6-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:3b636753ae34d4619b11ea7d664a2f1e87e55e9738e5123e12bcce22acae9d13"}, - {file = "orjson-3.6.6-cp310-none-win_amd64.whl", hash = "sha256:78a10295ed048fd916c6584d6d27c232eae805a43e7c14be56e3745f784f0eb6"}, - {file = "orjson-3.6.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:82b4f9fb2af7799b52932a62eac484083f930d5519560d6f64b24d66a368d03f"}, - {file = "orjson-3.6.6-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:a0033d07309cc7d8b8c4bc5d42f0dd4422b53ceb91dee9f4086bb2afa70b7772"}, - {file = "orjson-3.6.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b321f99473116ab7c7c028377372f7b4adba4029aaca19cd567e83898f55579"}, - {file = "orjson-3.6.6-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:b9c98ed94f1688cc11b5c61b8eea39d854a1a2f09f71d8a5af005461b14994ed"}, - {file = "orjson-3.6.6-cp37-cp37m-manylinux_2_24_x86_64.whl", hash = "sha256:00b333a41392bd07a8603c42670547dbedf9b291485d773f90c6470eff435608"}, - {file = "orjson-3.6.6-cp37-none-win_amd64.whl", hash = "sha256:8d4fd3bdee65a81f2b79c50937d4b3c054e1e6bfa3fc72ed018a97c0c7c3d521"}, - {file = "orjson-3.6.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:954c9f8547247cd7a8c91094ff39c9fe314b5eaeaec90b7bfb7384a4108f416f"}, - {file = "orjson-3.6.6-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:74e5aed657ed0b91ef05d44d6a26d3e3e12ce4d2d71f75df41a477b05878c4a9"}, - {file = "orjson-3.6.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4008a5130e6e9c33abaa95e939e0e755175da10745740aa6968461b2f16830e2"}, - {file = "orjson-3.6.6-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:012761d5f3d186deb4f6238f15e9ea7c1aac6deebc8f5b741ba3b4fafe017460"}, - {file = "orjson-3.6.6-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:b464546718a940b48d095a98df4c04808bfa6c8706fe751fc3f9390bc2f82643"}, - {file = "orjson-3.6.6-cp38-none-win_amd64.whl", hash = "sha256:f10a800f4e5a4aab52076d4628e9e4dab9370bdd9d8ea254ebfde846b653ab25"}, - {file = "orjson-3.6.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:8010d2610cfab721725ef14d578c7071e946bbdae63322d8f7b49061cf3fde8d"}, - {file = "orjson-3.6.6-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:8dca67a4855e1e0f9a2ea0386e8db892708522e1171dc0ddf456932288fbae63"}, - {file = "orjson-3.6.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af065d60523139b99bd35b839c7a2d8c5da55df8a8c4402d2eb6cdc07fa7a624"}, - {file = "orjson-3.6.6-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:fa1f389cc9f766ae0cf7ba3533d5089836b01a5ccb3f8d904297f1fcf3d9dc34"}, - {file = "orjson-3.6.6-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:ec1221ad78f94d27b162a1d35672b62ef86f27f0e4c2b65051edb480cc86b286"}, - {file = "orjson-3.6.6-cp39-none-win_amd64.whl", hash = "sha256:afed2af55eeda1de6b3f1cbc93431981b19d380fcc04f6ed86e74c1913070304"}, - {file = "orjson-3.6.6.tar.gz", hash = "sha256:55dd988400fa7fbe0e31407c683f5aaab013b5bd967167b8fe058186773c4d6c"}, -] +mysqlclient = [] +orjson = [] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, @@ -1606,42 +1318,9 @@ priority = [ {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, ] -prometheus-client = [ - {file = "prometheus_client-0.13.1-py3-none-any.whl", hash = "sha256:357a447fd2359b0a1d2e9b311a0c5778c330cfbe186d880ad5a6b39884652316"}, - {file = "prometheus_client-0.13.1.tar.gz", hash = "sha256:ada41b891b79fca5638bd5cfe149efa86512eaa55987893becd2c6d8d0a5dfc5"}, -] -prometheus-fastapi-instrumentator = [ - {file = "prometheus-fastapi-instrumentator-5.7.1.tar.gz", hash = "sha256:5371f1b494e2b00017a02898d854119b4929025d1a203670b07b3f42dd0b5526"}, - {file = "prometheus_fastapi_instrumentator-5.7.1-py3-none-any.whl", hash = "sha256:da40ea0df14b0e95d584769747fba777522a8df6a8c47cec2edf798f1fff49b5"}, -] -protobuf = [ - {file = "protobuf-3.19.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f51d5a9f137f7a2cec2d326a74b6e3fc79d635d69ffe1b036d39fc7d75430d37"}, - {file = "protobuf-3.19.4-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:09297b7972da685ce269ec52af761743714996b4381c085205914c41fcab59fb"}, - {file = "protobuf-3.19.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072fbc78d705d3edc7ccac58a62c4c8e0cec856987da7df8aca86e647be4e35c"}, - {file = "protobuf-3.19.4-cp310-cp310-win32.whl", hash = "sha256:7bb03bc2873a2842e5ebb4801f5c7ff1bfbdf426f85d0172f7644fcda0671ae0"}, - {file = "protobuf-3.19.4-cp310-cp310-win_amd64.whl", hash = "sha256:f358aa33e03b7a84e0d91270a4d4d8f5df6921abe99a377828839e8ed0c04e07"}, - {file = "protobuf-3.19.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1c91ef4110fdd2c590effb5dca8fdbdcb3bf563eece99287019c4204f53d81a4"}, - {file = "protobuf-3.19.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c438268eebb8cf039552897d78f402d734a404f1360592fef55297285f7f953f"}, - {file = "protobuf-3.19.4-cp36-cp36m-win32.whl", hash = "sha256:835a9c949dc193953c319603b2961c5c8f4327957fe23d914ca80d982665e8ee"}, - {file = "protobuf-3.19.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4276cdec4447bd5015453e41bdc0c0c1234eda08420b7c9a18b8d647add51e4b"}, - {file = "protobuf-3.19.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6cbc312be5e71869d9d5ea25147cdf652a6781cf4d906497ca7690b7b9b5df13"}, - {file = "protobuf-3.19.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:54a1473077f3b616779ce31f477351a45b4fef8c9fd7892d6d87e287a38df368"}, - {file = "protobuf-3.19.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:435bb78b37fc386f9275a7035fe4fb1364484e38980d0dd91bc834a02c5ec909"}, - {file = "protobuf-3.19.4-cp37-cp37m-win32.whl", hash = "sha256:16f519de1313f1b7139ad70772e7db515b1420d208cb16c6d7858ea989fc64a9"}, - {file = "protobuf-3.19.4-cp37-cp37m-win_amd64.whl", hash = "sha256:cdc076c03381f5c1d9bb1abdcc5503d9ca8b53cf0a9d31a9f6754ec9e6c8af0f"}, - {file = "protobuf-3.19.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:69da7d39e39942bd52848438462674c463e23963a1fdaa84d88df7fbd7e749b2"}, - {file = "protobuf-3.19.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:48ed3877fa43e22bcacc852ca76d4775741f9709dd9575881a373bd3e85e54b2"}, - {file = "protobuf-3.19.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd95d1dfb9c4f4563e6093a9aa19d9c186bf98fa54da5252531cc0d3a07977e7"}, - {file = "protobuf-3.19.4-cp38-cp38-win32.whl", hash = "sha256:b38057450a0c566cbd04890a40edf916db890f2818e8682221611d78dc32ae26"}, - {file = "protobuf-3.19.4-cp38-cp38-win_amd64.whl", hash = "sha256:7ca7da9c339ca8890d66958f5462beabd611eca6c958691a8fe6eccbd1eb0c6e"}, - {file = "protobuf-3.19.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:36cecbabbda242915529b8ff364f2263cd4de7c46bbe361418b5ed859677ba58"}, - {file = "protobuf-3.19.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c1068287025f8ea025103e37d62ffd63fec8e9e636246b89c341aeda8a67c934"}, - {file = "protobuf-3.19.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96bd766831596d6014ca88d86dc8fe0fb2e428c0b02432fd9db3943202bf8c5e"}, - {file = "protobuf-3.19.4-cp39-cp39-win32.whl", hash = "sha256:84123274d982b9e248a143dadd1b9815049f4477dc783bf84efe6250eb4b836a"}, - {file = "protobuf-3.19.4-cp39-cp39-win_amd64.whl", hash = "sha256:3112b58aac3bac9c8be2b60a9daf6b558ca3f7681c130dcdd788ade7c9ffbdca"}, - {file = "protobuf-3.19.4-py2.py3-none-any.whl", hash = "sha256:8961c3a78ebfcd000920c9060a262f082f29838682b1f7201889300c1fbe0616"}, - {file = "protobuf-3.19.4.tar.gz", hash = "sha256:9df0c10adf3e83015ced42a9a7bd64e13d06c4cf45c340d2c63020ea04499d0a"}, -] +prometheus-client = [] +prometheus-fastapi-instrumentator = [] +protobuf = [] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, @@ -1657,82 +1336,15 @@ pycparser = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] -pydantic = [ - {file = "pydantic-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5"}, - {file = "pydantic-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4"}, - {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37"}, - {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25"}, - {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6"}, - {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c"}, - {file = "pydantic-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398"}, - {file = "pydantic-1.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65"}, - {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46"}, - {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c"}, - {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054"}, - {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed"}, - {file = "pydantic-1.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1"}, - {file = "pydantic-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070"}, - {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2"}, - {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1"}, - {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032"}, - {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6"}, - {file = "pydantic-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d"}, - {file = "pydantic-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7"}, - {file = "pydantic-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77"}, - {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9"}, - {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6"}, - {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145"}, - {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034"}, - {file = "pydantic-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f"}, - {file = "pydantic-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b"}, - {file = "pydantic-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c"}, - {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce"}, - {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3"}, - {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d"}, - {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721"}, - {file = "pydantic-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16"}, - {file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"}, - {file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"}, -] +pydantic = [] pyflakes = [ {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, ] -pygit2 = [ - {file = "pygit2-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4a9a031bb0d2c5cf964da1f6d7a193416a97664655ec43ec349d3609bbde154"}, - {file = "pygit2-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:afcfb8ba97cfedcb8f890ff1e74c4d63755234cca1ca22c2a969e91b8059ae3e"}, - {file = "pygit2-1.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f87498ce717302a7525dad1ee604badc85bdff7bd453473d601077ac58e7cae"}, - {file = "pygit2-1.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2355cf24719a35542a88075988c8e11cd155aa375a1f12d62b980986da992eb4"}, - {file = "pygit2-1.7.2-cp310-cp310-win32.whl", hash = "sha256:0d72bd05dd3cf514ea2e2df32a2d361f6f29da7d5f02cf0980ea149f49cdfb37"}, - {file = "pygit2-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:1b7ff5b656db280ca5d31ecdb17709ed7eaf4e9f419b2fa66f7ff92d8234f621"}, - {file = "pygit2-1.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6aa018c101056c2a8e1fb6467c10281afa088b3b7bc7c17defb404f66039669a"}, - {file = "pygit2-1.7.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a27f8cab6dbef912ccdd690b97948dbf978cffc2ef96ee01b1a8944bfb713f0b"}, - {file = "pygit2-1.7.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c538a0234baa091a02342895d31e5b7c29d85ada44a0b9b4a5fdf78b5607cd48"}, - {file = "pygit2-1.7.2-cp37-cp37m-win32.whl", hash = "sha256:b15579b69381ba41199f5eb7fc85f153105d535c91b8da0321aaa14fec19f09c"}, - {file = "pygit2-1.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6c2ee00048862e193b2b88267f880632735f53db0f2c7f9ebebb21a43d22e58b"}, - {file = "pygit2-1.7.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8c24f3413522c970ae46e79b645ac0978a5be98863a6c6619e8f710bb137e1cb"}, - {file = "pygit2-1.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d42a7cc4b53cc369b82266c7257fe1808ec0e30c34f1796a0b0fa12a0db9ebe"}, - {file = "pygit2-1.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b1694ad8b4702e9e83a79a97bf3f1b44674057ae9d40bc7eb92e4b4baf79d94"}, - {file = "pygit2-1.7.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a382db82ad4ba3109e74c7b82d6c6c1e451200ee379bad8a17936027c65ea98"}, - {file = "pygit2-1.7.2-cp38-cp38-win32.whl", hash = "sha256:6c168efd7e3bdaeeccfa5ccbe2718107a1fe65cda959586f88a73228217a8783"}, - {file = "pygit2-1.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:041e34f7efd96c7edbea2f478704756fc189082561611c88bc95cf2d085923b5"}, - {file = "pygit2-1.7.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ef34b881da55b6702087575ea48a90a08e1077a7f64faa909d9840e16f36c63b"}, - {file = "pygit2-1.7.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0e6368a96058cf619ad574de2b4575f58d363f3f6d4de8e172e1e5d10e1fad36"}, - {file = "pygit2-1.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0748b413966da9b3d3ca8a0a79c63f6581a89b883d2ba64355bbfdb250f2e066"}, - {file = "pygit2-1.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d34954c21f109f176d8104b253fc8ce2ca17efb43cfe228d6530c200f362b83"}, - {file = "pygit2-1.7.2-cp39-cp39-win32.whl", hash = "sha256:32979cb98ffd183ed0458c519e6615deeb6a8cc1252223396eee8f526f09989f"}, - {file = "pygit2-1.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:56d55452dc3eca844d92503d755c8e11699b7ab3b845b81cf365f85d6385d7e0"}, - {file = "pygit2-1.7.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:409c76dea47c2c678295c42f55798da7a0a9adcc6394fe75c061864254bafeef"}, - {file = "pygit2-1.7.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be038fecd27a9a7046cd45b4a6e847955dab2d6e2352ff41ab3b55f700aa0f3d"}, - {file = "pygit2-1.7.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3e91afd629b90b528b756ca2a0fbd5bf8df2cdc08ccd5ab144fbfe69bfc587d"}, - {file = "pygit2-1.7.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:17b06a1ecc16b90fa652cf5cf9698dfb16a87501b76f7001e1d4934a38a49737"}, - {file = "pygit2-1.7.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fe7cdd56d0e5a89ed7754d1aedc6516349f16072225ccfc7b9349ab6448a052"}, - {file = "pygit2-1.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2a766b5a988ab373a040d1769e0e1df4618a9f8f33464746b9b2a3c92576df4"}, - {file = "pygit2-1.7.2.tar.gz", hash = "sha256:70a4536a35452c31f823b59b6fdb665aa3778a43b73ccda3a4f79fa9962ad2bb"}, -] +pygit2 = [] pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, @@ -1769,10 +1381,7 @@ redis = [ {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, ] -requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, -] +requests = [] rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, @@ -1789,44 +1398,7 @@ sortedcontainers = [ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] -sqlalchemy = [ - {file = "SQLAlchemy-1.4.31-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c3abc34fed19fdeaead0ced8cf56dd121f08198008c033596aa6aae7cc58f59f"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8d0949b11681380b4a50ac3cd075e4816afe9fa4a8c8ae006c1ca26f0fa40ad8"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-win32.whl", hash = "sha256:f3b7ec97e68b68cb1f9ddb82eda17b418f19a034fa8380a0ac04e8fe01532875"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-win_amd64.whl", hash = "sha256:81f2dd355b57770fdf292b54f3e0a9823ec27a543f947fa2eb4ec0df44f35f0d"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4ad31cec8b49fd718470328ad9711f4dc703507d434fd45461096da0a7135ee0"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:05fa14f279d43df68964ad066f653193187909950aa0163320b728edfc400167"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dccff41478050e823271642837b904d5f9bda3f5cf7d371ce163f00a694118d6"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57205844f246bab9b666a32f59b046add8995c665d9ecb2b7b837b087df90639"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8210090a816d48a4291a47462bac750e3bc5c2442e6d64f7b8137a7c3f9ac5"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-win32.whl", hash = "sha256:2e216c13ecc7fcdcbb86bb3225425b3ed338e43a8810c7089ddb472676124b9b"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-win_amd64.whl", hash = "sha256:e3a86b59b6227ef72ffc10d4b23f0fe994bef64d4667eab4fb8cd43de4223bec"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2fd4d3ca64c41dae31228b80556ab55b6489275fb204827f6560b65f95692cf3"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f22c040d196f841168b1456e77c30a18a3dc16b336ddbc5a24ce01ab4e95ae0"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0c7171aa5a57e522a04a31b84798b6c926234cb559c0939840c3235cf068813"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d046a9aeba9bc53e88a41e58beb72b6205abb9a20f6c136161adf9128e589db5"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-win32.whl", hash = "sha256:d86132922531f0dc5a4f424c7580a472a924dd737602638e704841c9cb24aea2"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-win_amd64.whl", hash = "sha256:ca68c52e3cae491ace2bf39b35fef4ce26c192fd70b4cd90f040d419f70893b5"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:cf2cd387409b12d0a8b801610d6336ee7d24043b6dd965950eaec09b73e7262f"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb4b15fb1f0aafa65cbdc62d3c2078bea1ceecbfccc9a1f23a2113c9ac1191fa"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c317ddd7c586af350a6aef22b891e84b16bff1a27886ed5b30f15c1ed59caeaa"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c7ed6c69debaf6198fadb1c16ae1253a29a7670bbf0646f92582eb465a0b999"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-win32.whl", hash = "sha256:6a01ec49ca54ce03bc14e10de55dfc64187a2194b3b0e5ac0fdbe9b24767e79e"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-win_amd64.whl", hash = "sha256:330eb45395874cc7787214fdd4489e2afb931bc49e0a7a8f9cd56d6e9c5b1639"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:5e9c7b3567edbc2183607f7d9f3e7e89355b8f8984eec4d2cd1e1513c8f7b43f"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de85c26a5a1c72e695ab0454e92f60213b4459b8d7c502e0be7a6369690eeb1a"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:975f5c0793892c634c4920057da0de3a48bbbbd0a5c86f5fcf2f2fedf41b76da"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5c20c8415173b119762b6110af64448adccd4d11f273fb9f718a9865b88a99c"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-win32.whl", hash = "sha256:b35dca159c1c9fa8a5f9005e42133eed82705bf8e243da371a5e5826440e65ca"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-win_amd64.whl", hash = "sha256:b7b20c88873675903d6438d8b33fba027997193e274b9367421e610d9da76c08"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:85e4c244e1de056d48dae466e9baf9437980c19fcde493e0db1a0a986e6d75b4"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79e73d5ee24196d3057340e356e6254af4d10e1fc22d3207ea8342fc5ffb977"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:15a03261aa1e68f208e71ae3cd845b00063d242cbf8c87348a0c2c0fc6e1f2ac"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc5e5ccc0160e7ad190e5c61eb57560f38559e22586955f205e537cda26034"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-win32.whl", hash = "sha256:289465162b1fa1e7a982f8abe59d26a8331211cad4942e8031d2b7db1f75e649"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-win_amd64.whl", hash = "sha256:9e4fb2895b83993831ba2401b6404de953fdbfa9d7d4fa6a4756294a83bbc94f"}, - {file = "SQLAlchemy-1.4.31.tar.gz", hash = "sha256:582b59d1e5780a447aada22b461e50b404a9dc05768da1d87368ad8190468418"}, -] +sqlalchemy = [] srcinfo = [ {file = "srcinfo-0.0.8-py3-none-any.whl", hash = "sha256:0922ee4302b927d7ddea74c47e539b226a0a7738dc89f95b66404a28d07f3f6b"}, {file = "srcinfo-0.0.8.tar.gz", hash = "sha256:5ac610cf8b15d4b0a0374bd1f7ad301675c2938f0414addf3ef7d7e3fcaf5c65"}, @@ -1843,18 +1415,9 @@ toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -tomli = [ - {file = "tomli-2.0.0-py3-none-any.whl", hash = "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224"}, - {file = "tomli-2.0.0.tar.gz", hash = "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1"}, -] -typing-extensions = [ - {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, - {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, -] -urllib3 = [ - {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, - {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, -] +tomli = [] +typing-extensions = [] +urllib3 = [] uvicorn = [ {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, @@ -1863,15 +1426,6 @@ webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, ] -werkzeug = [ - {file = "Werkzeug-2.0.2-py3-none-any.whl", hash = "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f"}, - {file = "Werkzeug-2.0.2.tar.gz", hash = "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"}, -] -wsproto = [ - {file = "wsproto-1.0.0-py3-none-any.whl", hash = "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f"}, - {file = "wsproto-1.0.0.tar.gz", hash = "sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38"}, -] -zipp = [ - {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"}, - {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"}, -] +werkzeug = [] +wsproto = [] +zipp = [] diff --git a/pyproject.toml b/pyproject.toml index 41d8301f..656a854b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,7 @@ protobuf = "^3.19.0" pygit2 = "^1.7.0" python-multipart = "^0.0.5" redis = "^3.5.3" -requests = "^2.26.0" +requests = "^2.28.1" paginate = "^0.5.6" # SQL From 0e82916b0a149e81b0936eb5edcfd387798e9481 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Tue, 2 Aug 2022 16:30:45 +0200 Subject: [PATCH 1528/1891] fix(python): don't show maintainer link for non logged in users Show a plain maintainer text for non logged in users like the submitted, last packager. Closes #373 --- templates/partials/packages/details.html | 5 ++++- test/test_pkgbase_routes.py | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index e0eda54c..771b311d 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -108,7 +108,7 @@

      diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index a152c590..dae43e37 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -272,9 +272,9 @@ def test_pkgbase_maintainer(client: TestClient, user: User, maintainer: User, root = parse_root(resp.text) maint = root.xpath('//table[@id="pkginfo"]/tr[@class="pkgmaint"]/td')[0] - maint, comaint = maint.xpath('./a') - assert maint.text.strip() == maintainer.Username - assert comaint.text.strip() == user.Username + maint, comaint = maint.text.strip().split() + assert maint == maintainer.Username + assert comaint == f'({user.Username})' def test_pkgbase_voters(client: TestClient, tu_user: User, package: Package): From 913ce8a4f0cac79fcd089cb8a66a6aa1b02be601 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 12 Aug 2022 19:58:55 -0700 Subject: [PATCH 1529/1891] fix(performance): lazily load expensive modules within aurweb.db Closes #374 Signed-off-by: Kevin Morris --- aurweb/db.py | 81 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/aurweb/db.py b/aurweb/db.py index 4c53730a..94514d35 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -1,34 +1,15 @@ -import functools -import hashlib -import math -import os -import re - -from typing import Iterable, NewType - -import sqlalchemy - -from sqlalchemy import create_engine, event -from sqlalchemy.engine.base import Engine -from sqlalchemy.engine.url import URL -from sqlalchemy.orm import Query, Session, SessionTransaction, scoped_session, sessionmaker - -import aurweb.config -import aurweb.util - +# Supported database drivers. DRIVERS = { "mysql": "mysql+mysqldb" } -# Some types we don't get access to in this module. -Base = NewType("Base", "aurweb.models.declarative_base.Base") - def make_random_value(table: str, column: str, length: int): """ Generate a unique, random value for a string column in a table. :return: A unique string that is not in the database """ + import aurweb.util string = aurweb.util.make_random_string(length) while query(table).filter(column == string).first(): string = aurweb.util.make_random_string(length) @@ -52,6 +33,10 @@ def test_name() -> str: :return: Unhashed database name """ + import os + + import aurweb.config + db = os.environ.get("PYTEST_CURRENT_TEST", aurweb.config.get("database", "name")) return db.split(":")[0] @@ -70,7 +55,10 @@ def name() -> str: dbname = test_name() if not dbname.startswith("test/"): return dbname + + import hashlib sha1 = hashlib.sha1(dbname.encode()).hexdigest() + return "db" + sha1 @@ -78,12 +66,13 @@ def name() -> str: _sessions = dict() -def get_session(engine: Engine = None) -> Session: +def get_session(engine=None): """ Return aurweb.db's global session. """ dbname = name() global _sessions if dbname not in _sessions: + from sqlalchemy.orm import scoped_session, sessionmaker if not engine: # pragma: no cover engine = get_engine() @@ -106,13 +95,17 @@ def pop_session(dbname: str) -> None: _sessions.pop(dbname) -def refresh(model: Base) -> Base: - """ Refresh the session's knowledge of `model`. """ +def refresh(model): + """ + Refresh the session's knowledge of `model`. + + :returns: Passed in `model` + """ get_session().refresh(model) return model -def query(Model: Base, *args, **kwargs) -> Query: +def query(Model, *args, **kwargs): """ Perform an ORM query against the database session. @@ -124,7 +117,7 @@ def query(Model: Base, *args, **kwargs) -> Query: return get_session().query(Model).filter(*args, **kwargs) -def create(Model: Base, *args, **kwargs) -> Base: +def create(Model, *args, **kwargs): """ Create a record and add() it to the database session. @@ -135,7 +128,7 @@ def create(Model: Base, *args, **kwargs) -> Base: return add(instance) -def delete(model: Base) -> None: +def delete(model) -> None: """ Delete a set of records found by Query.filter(*args, **kwargs). @@ -144,8 +137,9 @@ def delete(model: Base) -> None: get_session().delete(model) -def delete_all(iterable: Iterable) -> None: +def delete_all(iterable) -> None: """ Delete each instance found in `iterable`. """ + import aurweb.util session_ = get_session() aurweb.util.apply_all(iterable, session_.delete) @@ -155,23 +149,29 @@ def rollback() -> None: get_session().rollback() -def add(model: Base) -> Base: +def add(model): """ Add `model` to the database session. """ get_session().add(model) return model -def begin() -> SessionTransaction: +def begin(): """ Begin an SQLAlchemy SessionTransaction. """ return get_session().begin() -def get_sqlalchemy_url() -> URL: +def get_sqlalchemy_url(): """ Build an SQLAlchemy URL for use with create_engine. :return: sqlalchemy.engine.url.URL """ + import sqlalchemy + + from sqlalchemy.engine.url import URL + + import aurweb.config + constructor = URL parts = sqlalchemy.__version__.split('.') @@ -209,13 +209,17 @@ def get_sqlalchemy_url() -> URL: def sqlite_regexp(regex, item) -> bool: # pragma: no cover """ Method which mimics SQL's REGEXP for SQLite. """ + import re return bool(re.search(regex, str(item))) -def setup_sqlite(engine: Engine) -> None: # pragma: no cover +def setup_sqlite(engine) -> None: # pragma: no cover """ Perform setup for an SQLite engine. """ + from sqlalchemy import event + @event.listens_for(engine, "connect") def do_begin(conn, record): + import functools create_deterministic_function = functools.partial( conn.create_function, deterministic=True @@ -227,7 +231,7 @@ def setup_sqlite(engine: Engine) -> None: # pragma: no cover _engines = dict() -def get_engine(dbname: str = None, echo: bool = False) -> Engine: +def get_engine(dbname: str = None, echo: bool = False): """ Return the SQLAlchemy engine for `dbname`. @@ -238,6 +242,8 @@ def get_engine(dbname: str = None, echo: bool = False) -> Engine: :param echo: Flag passed through to sqlalchemy.create_engine :return: SQLAlchemy Engine instance """ + import aurweb.config + if not dbname: dbname = name() @@ -254,6 +260,7 @@ def get_engine(dbname: str = None, echo: bool = False) -> Engine: "echo": echo, "connect_args": connect_args } + from sqlalchemy import create_engine _engines[dbname] = create_engine(get_sqlalchemy_url(), **kwargs) if is_sqlite: # pragma: no cover @@ -301,7 +308,10 @@ class ConnectionExecutor: _conn = None _paramstyle = None - def __init__(self, conn, backend=aurweb.config.get("database", "backend")): + def __init__(self, conn, backend=None): + import aurweb.config + + backend = backend or aurweb.config.get("database", "backend") self._conn = conn if backend == "mysql": self._paramstyle = "format" @@ -339,6 +349,7 @@ class Connection: _conn = None def __init__(self): + import aurweb.config aur_db_backend = aurweb.config.get('database', 'backend') if aur_db_backend == 'mysql': @@ -357,7 +368,9 @@ class Connection: elif aur_db_backend == 'sqlite': # pragma: no cover # TODO: SQLite support has been removed in FastAPI. It remains # here to fund its support for PHP until it is removed. + import math import sqlite3 + aur_db_name = aurweb.config.get('database', 'name') self._conn = sqlite3.connect(aur_db_name) self._conn.create_function("POWER", 2, math.pow) From 1a7f6e1fa9f500fead3650ef1e4ec9521884e1d8 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 12 Aug 2022 21:37:34 -0700 Subject: [PATCH 1530/1891] feat(db): add an index for SSHPubKeys.PubKey Speeds up SSHPubKeys.PubKey searches in a larger database. Signed-off-by: Kevin Morris --- aurweb/schema.py | 1 + ...d70103d2e82_add_sshpubkeys_pubkey_index.py | 28 +++++++++++++++++++ test/test_migration.py | 23 +++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py create mode 100644 test/test_migration.py diff --git a/aurweb/schema.py b/aurweb/schema.py index d2644541..e1373bf4 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -87,6 +87,7 @@ SSHPubKeys = Table( Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('Fingerprint', String(44), primary_key=True), Column('PubKey', String(4096), nullable=False), + Index('SSHPubKeysPubKey', 'PubKey'), mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', ) diff --git a/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py b/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py new file mode 100644 index 00000000..61e4dc79 --- /dev/null +++ b/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py @@ -0,0 +1,28 @@ +"""add SSHPubKeys.PubKey index + +Revision ID: dd70103d2e82 +Revises: d64e5571bc8d +Create Date: 2022-08-12 21:30:26.155465 + +""" +import traceback + +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'dd70103d2e82' +down_revision = 'd64e5571bc8d' +branch_labels = None +depends_on = None + + +def upgrade(): + try: + op.create_index("SSHPubKeysPubKey", "SSHPubKeys", ["PubKey"]) + except Exception: + traceback.print_exc() + print("failing silently...") + + +def downgrade(): + op.drop_index("SSHPubKeysPubKey", "SSHPubKeys") diff --git a/test/test_migration.py b/test/test_migration.py new file mode 100644 index 00000000..cf8702fa --- /dev/null +++ b/test/test_migration.py @@ -0,0 +1,23 @@ +import pytest + +from sqlalchemy import inspect + +from aurweb.db import get_engine +from aurweb.models.ssh_pub_key import SSHPubKey + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +def test_sshpubkeys_pubkey_index(): + insp = inspect(get_engine()) + indexes = insp.get_indexes(SSHPubKey.__tablename__) + + found_pk = False + for idx in indexes: + if idx.get("name") == "SSHPubKeysPubKey": + assert idx.get("column_names") == ["PubKey"] + found_pk = True + assert found_pk From 5abd5db313c871678bcf54e7a2c2a0fc056401b0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 13 Aug 2022 19:23:19 -0700 Subject: [PATCH 1531/1891] Revert "feat(db): add an index for SSHPubKeys.PubKey" This reverts commit 1a7f6e1fa9f500fead3650ef1e4ec9521884e1d8. This commit broke account creation in some way. We'd still like to do this, but we need to ensure it does not intrude on other facets. Extra: We should really work out how this even passed tests; it should not have. --- aurweb/schema.py | 1 - ...d70103d2e82_add_sshpubkeys_pubkey_index.py | 28 ------------------- test/test_migration.py | 23 --------------- 3 files changed, 52 deletions(-) delete mode 100644 migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py delete mode 100644 test/test_migration.py diff --git a/aurweb/schema.py b/aurweb/schema.py index e1373bf4..d2644541 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -87,7 +87,6 @@ SSHPubKeys = Table( Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('Fingerprint', String(44), primary_key=True), Column('PubKey', String(4096), nullable=False), - Index('SSHPubKeysPubKey', 'PubKey'), mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', ) diff --git a/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py b/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py deleted file mode 100644 index 61e4dc79..00000000 --- a/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py +++ /dev/null @@ -1,28 +0,0 @@ -"""add SSHPubKeys.PubKey index - -Revision ID: dd70103d2e82 -Revises: d64e5571bc8d -Create Date: 2022-08-12 21:30:26.155465 - -""" -import traceback - -from alembic import op - -# revision identifiers, used by Alembic. -revision = 'dd70103d2e82' -down_revision = 'd64e5571bc8d' -branch_labels = None -depends_on = None - - -def upgrade(): - try: - op.create_index("SSHPubKeysPubKey", "SSHPubKeys", ["PubKey"]) - except Exception: - traceback.print_exc() - print("failing silently...") - - -def downgrade(): - op.drop_index("SSHPubKeysPubKey", "SSHPubKeys") diff --git a/test/test_migration.py b/test/test_migration.py deleted file mode 100644 index cf8702fa..00000000 --- a/test/test_migration.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest - -from sqlalchemy import inspect - -from aurweb.db import get_engine -from aurweb.models.ssh_pub_key import SSHPubKey - - -@pytest.fixture(autouse=True) -def setup(db_test): - return - - -def test_sshpubkeys_pubkey_index(): - insp = inspect(get_engine()) - indexes = insp.get_indexes(SSHPubKey.__tablename__) - - found_pk = False - for idx in indexes: - if idx.get("name") == "SSHPubKeysPubKey": - assert idx.get("column_names") == ["PubKey"] - found_pk = True - assert found_pk From 6c7e2749688100a10ac7de1d422b8c4cee98f393 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 13 Aug 2022 19:52:50 -0700 Subject: [PATCH 1532/1891] feat(db): add an index for SSHPubKeys.PubKey (#2) Speeds up SSHPubKeys.PubKey searches in a larger database. Fixed form of the original commit which was reverted, 1a7f6e1fa9f500fead3650ef1e4ec9521884e1d8 Signed-off-by: Kevin Morris --- aurweb/schema.py | 2 ++ ...d70103d2e82_add_sshpubkeys_pubkey_index.py | 35 +++++++++++++++++++ test/test_migration.py | 23 ++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py create mode 100644 test/test_migration.py diff --git a/aurweb/schema.py b/aurweb/schema.py index d2644541..3d8369c9 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -87,6 +87,8 @@ SSHPubKeys = Table( Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('Fingerprint', String(44), primary_key=True), Column('PubKey', String(4096), nullable=False), + Index('SSHPubKeysUserID', 'UserID'), + Index('SSHPubKeysPubKey', 'PubKey'), mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', ) diff --git a/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py b/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py new file mode 100644 index 00000000..7d3f4b59 --- /dev/null +++ b/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py @@ -0,0 +1,35 @@ +"""add SSHPubKeys.PubKey index + +Revision ID: dd70103d2e82 +Revises: d64e5571bc8d +Create Date: 2022-08-12 21:30:26.155465 + +""" +import traceback + +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'dd70103d2e82' +down_revision = 'd64e5571bc8d' +branch_labels = None +depends_on = None + + +def upgrade(): + try: + op.create_index("SSHPubKeysUserID", "SSHPubKeys", ["UserID"]) + except Exception: + traceback.print_exc() + print("failing silently...") + + try: + op.create_index("SSHPubKeysPubKey", "SSHPubKeys", ["PubKey"]) + except Exception: + traceback.print_exc() + print("failing silently...") + + +def downgrade(): + op.drop_index("SSHPubKeysPubKey", "SSHPubKeys") + op.drop_index("SSHPubKeysUserID", "SSHPubKeys") diff --git a/test/test_migration.py b/test/test_migration.py new file mode 100644 index 00000000..cf8702fa --- /dev/null +++ b/test/test_migration.py @@ -0,0 +1,23 @@ +import pytest + +from sqlalchemy import inspect + +from aurweb.db import get_engine +from aurweb.models.ssh_pub_key import SSHPubKey + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +def test_sshpubkeys_pubkey_index(): + insp = inspect(get_engine()) + indexes = insp.get_indexes(SSHPubKey.__tablename__) + + found_pk = False + for idx in indexes: + if idx.get("name") == "SSHPubKeysPubKey": + assert idx.get("column_names") == ["PubKey"] + found_pk = True + assert found_pk From 952c24783baa6c5924c5aaf2b9d9003866284657 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 13 Aug 2022 20:12:58 -0700 Subject: [PATCH 1533/1891] fix(docker): apply chown each time sshd is started Signed-off-by: Kevin Morris --- docker/scripts/run-sshd.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker/scripts/run-sshd.sh b/docker/scripts/run-sshd.sh index d488e80d..45bd0e08 100755 --- a/docker/scripts/run-sshd.sh +++ b/docker/scripts/run-sshd.sh @@ -1,2 +1,7 @@ #!/bin/bash + +# Update this every time. +chown -R aur:aur /aurweb/aur.git + +# Start up sshd exec /usr/sbin/sshd -e -p 2222 -D From 829a8b4b813c23e2e85dad4e7aca00ffba86601d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 13 Aug 2022 20:56:43 -0700 Subject: [PATCH 1534/1891] Revert "fix(docker): apply chown each time sshd is started" This reverts commit 952c24783baa6c5924c5aaf2b9d9003866284657. The issue found was actually: - If `./aur.git` exists within the aurweb repository locally, it also ends up in the destination, stopping the aurweb_git_data volume from being mounted properly. --- docker/scripts/run-sshd.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docker/scripts/run-sshd.sh b/docker/scripts/run-sshd.sh index 45bd0e08..d488e80d 100755 --- a/docker/scripts/run-sshd.sh +++ b/docker/scripts/run-sshd.sh @@ -1,7 +1,2 @@ #!/bin/bash - -# Update this every time. -chown -R aur:aur /aurweb/aur.git - -# Start up sshd exec /usr/sbin/sshd -e -p 2222 -D From 6f7ac33166883c1c9c1b2b73c5735e46a49d3f6d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 13 Aug 2022 23:28:31 -0700 Subject: [PATCH 1535/1891] Revert "feat(db): add an index for SSHPubKeys.PubKey (#2)" This reverts commit 6c7e2749688100a10ac7de1d422b8c4cee98f393. Once again, this does actually cause issues with foreign keys. Removing it for now and will revisit this. --- aurweb/schema.py | 2 -- ...d70103d2e82_add_sshpubkeys_pubkey_index.py | 35 ------------------- test/test_migration.py | 23 ------------ 3 files changed, 60 deletions(-) delete mode 100644 migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py delete mode 100644 test/test_migration.py diff --git a/aurweb/schema.py b/aurweb/schema.py index 3d8369c9..d2644541 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -87,8 +87,6 @@ SSHPubKeys = Table( Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('Fingerprint', String(44), primary_key=True), Column('PubKey', String(4096), nullable=False), - Index('SSHPubKeysUserID', 'UserID'), - Index('SSHPubKeysPubKey', 'PubKey'), mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', ) diff --git a/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py b/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py deleted file mode 100644 index 7d3f4b59..00000000 --- a/migrations/versions/dd70103d2e82_add_sshpubkeys_pubkey_index.py +++ /dev/null @@ -1,35 +0,0 @@ -"""add SSHPubKeys.PubKey index - -Revision ID: dd70103d2e82 -Revises: d64e5571bc8d -Create Date: 2022-08-12 21:30:26.155465 - -""" -import traceback - -from alembic import op - -# revision identifiers, used by Alembic. -revision = 'dd70103d2e82' -down_revision = 'd64e5571bc8d' -branch_labels = None -depends_on = None - - -def upgrade(): - try: - op.create_index("SSHPubKeysUserID", "SSHPubKeys", ["UserID"]) - except Exception: - traceback.print_exc() - print("failing silently...") - - try: - op.create_index("SSHPubKeysPubKey", "SSHPubKeys", ["PubKey"]) - except Exception: - traceback.print_exc() - print("failing silently...") - - -def downgrade(): - op.drop_index("SSHPubKeysPubKey", "SSHPubKeys") - op.drop_index("SSHPubKeysUserID", "SSHPubKeys") diff --git a/test/test_migration.py b/test/test_migration.py deleted file mode 100644 index cf8702fa..00000000 --- a/test/test_migration.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest - -from sqlalchemy import inspect - -from aurweb.db import get_engine -from aurweb.models.ssh_pub_key import SSHPubKey - - -@pytest.fixture(autouse=True) -def setup(db_test): - return - - -def test_sshpubkeys_pubkey_index(): - insp = inspect(get_engine()) - indexes = insp.get_indexes(SSHPubKey.__tablename__) - - found_pk = False - for idx in indexes: - if idx.get("name") == "SSHPubKeysPubKey": - assert idx.get("column_names") == ["PubKey"] - found_pk = True - assert found_pk From d63615a9946c2d82af82750f09cceca441f7117c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 13 Aug 2022 23:17:53 -0700 Subject: [PATCH 1536/1891] fix(docker): fix ca entrypoint logic and healthcheck With this commit, it is advised to `rm ./data/root_ca.crt ./data/*.pem`, as new certificates and a root CA will be generated while utilizing the step volume. Closes #367 Signed-off-by: Kevin Morris --- docker-compose.yml | 30 ++++++++++++++++-------------- docker/ca-entrypoint.sh | 40 ++++++++++++++++------------------------ docker/health/ca.sh | 4 ++-- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a56cbe72..9edffeeb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,8 +31,10 @@ services: entrypoint: /docker/ca-entrypoint.sh command: /docker/scripts/run-ca.sh healthcheck: - test: "bash /docker/health/run-ca.sh" - interval: 2s + test: "bash /docker/health/ca.sh" + interval: 3s + volumes: + - step:/root/.step memcached: image: aurweb:latest @@ -40,7 +42,7 @@ services: command: /docker/scripts/run-memcached.sh healthcheck: test: "bash /docker/health/memcached.sh" - interval: 2s + interval: 3s redis: image: aurweb:latest @@ -49,7 +51,7 @@ services: command: /docker/scripts/run-redis.sh healthcheck: test: "bash /docker/health/redis.sh" - interval: 2s + interval: 3s ports: - "127.0.0.1:16379:6379" @@ -67,7 +69,7 @@ services: - mariadb_data:/var/lib/mysql healthcheck: test: "bash /docker/health/mariadb.sh" - interval: 2s + interval: 3s mariadb_init: image: aurweb:latest @@ -98,7 +100,7 @@ services: - mariadb_test_run:/var/run/mysqld # Bind socket in this volume. healthcheck: test: "bash /docker/health/mariadb.sh" - interval: 2s + interval: 3s git: image: aurweb:latest @@ -113,7 +115,7 @@ services: - "2222:2222" healthcheck: test: "bash /docker/health/sshd.sh" - interval: 2s + interval: 3s depends_on: mariadb_init: condition: service_started @@ -129,7 +131,7 @@ services: command: /docker/scripts/run-smartgit.sh healthcheck: test: "bash /docker/health/smartgit.sh" - interval: 2s + interval: 3s cgit-php: image: aurweb:latest @@ -142,7 +144,7 @@ services: command: /docker/scripts/run-cgit.sh 3000 healthcheck: test: "bash /docker/health/cgit.sh 3000" - interval: 2s + interval: 3s depends_on: git: condition: service_healthy @@ -162,7 +164,7 @@ services: command: /docker/scripts/run-cgit.sh 3000 healthcheck: test: "bash /docker/health/cgit.sh 3000" - interval: 2s + interval: 3s depends_on: git: condition: service_healthy @@ -199,7 +201,7 @@ services: command: /docker/scripts/run-php.sh healthcheck: test: "bash /docker/health/php.sh" - interval: 2s + interval: 3s depends_on: git: condition: service_healthy @@ -228,7 +230,7 @@ services: command: /docker/scripts/run-fastapi.sh "${FASTAPI_BACKEND}" healthcheck: test: "bash /docker/health/fastapi.sh ${FASTAPI_BACKEND}" - interval: 2s + interval: 3s depends_on: git: condition: service_healthy @@ -254,10 +256,10 @@ services: - "127.0.0.1:8444:8444" # FastAPI healthcheck: test: "bash /docker/health/nginx.sh" - interval: 2s + interval: 3s depends_on: ca: - condition: service_started + condition: service_healthy cgit-php: condition: service_healthy cgit-fastapi: diff --git a/docker/ca-entrypoint.sh b/docker/ca-entrypoint.sh index d03efbbc..55c7cd75 100755 --- a/docker/ca-entrypoint.sh +++ b/docker/ca-entrypoint.sh @@ -89,34 +89,26 @@ step_cert_request() { chmod 666 /data/${1}.*.pem } -if [ ! -f $DATA_ROOT_CA ]; then +if [ ! -d /root/.step/config ]; then + # Remove existing certs. + rm -vf /data/localhost.{cert,key}.pem /data/root_ca.crt + setup_step_ca install_step_ca + + start_step_ca + for host in $DATA_CERT_HOSTS; do + step_cert_request $host /data/${host}.cert.pem /data/${host}.key.pem + done + kill_step_ca + + echo -n "WARN: Your certificates are being regenerated to resolve " + echo -n "an inconsistent step-ca state. You will need to re-import " + echo "the root CA certificate into your browser." +else + exec "$@" fi -# For all hosts separated by spaces in $DATA_CERT_HOSTS, perform a check -# for their existence in /data and react accordingly. -for host in $DATA_CERT_HOSTS; do - if [ -f /data/${host}.cert.pem ] && [ -f /data/${host}.key.pem ]; then - # Found an override. Move on to running the service after - # printing a notification to the user. - echo "Found '${host}.{cert,key}.pem' override, skipping..." - echo -n "Note: If you need to regenerate certificates, run " - echo '`rm -f data/*.{cert,key}.pem` before starting this service.' - exec "$@" - else - # Otherwise, we had a missing cert or key, so remove both. - rm -f /data/${host}.cert.pem - rm -f /data/${host}.key.pem - fi -done - -start_step_ca -for host in $DATA_CERT_HOSTS; do - step_cert_request $host /data/${host}.cert.pem /data/${host}.key.pem -done -kill_step_ca - # Set permissions to /data to rwx for everybody. chmod 777 /data diff --git a/docker/health/ca.sh b/docker/health/ca.sh index 3e4bbe8e..6bf8360e 100755 --- a/docker/health/ca.sh +++ b/docker/health/ca.sh @@ -1,2 +1,2 @@ - -exec printf "" 2>>/dev/null >>/dev/tcp/127.0.0.1/8443 +#!/bin/bash +exec curl -qkiI 'https://localhost:8443/' From a82d552e1bf0892e93b2c560e0924ada67f4d89d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 12 Aug 2022 17:18:10 -0700 Subject: [PATCH 1537/1891] update: migrate new transifex client configuration Signed-off-by: Kevin Morris --- .tx/config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.tx/config b/.tx/config index e986f81c..7f53b684 100644 --- a/.tx/config +++ b/.tx/config @@ -1,7 +1,8 @@ [main] host = https://www.transifex.com -[aurweb.aurwebpot] +[o:lfleischer:p:aurweb:r:aurwebpot] file_filter = po/.po source_file = po/aurweb.pot source_lang = en + From 4565aa38cf3cc227bf34a9f8fa40ca698b12ded5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 12 Aug 2022 17:18:54 -0700 Subject: [PATCH 1538/1891] update: Swedish translations Pulled from Transifex on 08/12/2022 - 08/13/2022. Signed-off-by: Kevin Morris --- po/sv_SE.po | 109 ++++++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/po/sv_SE.po b/po/sv_SE.po index 6d09e207..6abb8452 100644 --- a/po/sv_SE.po +++ b/po/sv_SE.po @@ -4,17 +4,18 @@ # # Translators: # Johannes Löthberg , 2015-2016 +# Kevin Morris , 2022 # Kim Svensson , 2011 # Kim Svensson , 2012 -# Luna Jernberg , 2021 +# Luna Jernberg , 2021-2022 # Robin Björnsvik , 2014-2015 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Kevin Morris , 2022\n" "Language-Team: Swedish (Sweden) (http://www.transifex.com/lfleischer/aurweb/language/sv_SE/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -36,17 +37,17 @@ msgstr "Notera" #: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "" +msgstr "git clone URLs är inte avsedda att öppnas i en webbläsare." #: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "" +msgstr "För att klona Git-förrådet för %s, kör %s." #: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "" +msgstr "Klicka %shär%s för att återgå till %sdetaljsidan." #: html/503.php msgid "Service Unavailable" @@ -169,7 +170,7 @@ msgstr "Redigera kommentar" #: html/home.php template/header.php msgid "Dashboard" -msgstr "" +msgstr "Informationspanel" #: html/home.php template/header.php msgid "Home" @@ -197,7 +198,7 @@ msgstr "Sam-ansvariga paket" #: html/home.php msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Sök efter paket jag är sam-ansvarig för" #: html/home.php #, php-format @@ -459,7 +460,7 @@ msgstr "Fortsätt" msgid "" "If you have forgotten the user name and the primary e-mail address you used " "to register, please send a message to the %saur-general%s mailing list." -msgstr "" +msgstr "Om du har glömt användarnamnet och den primära e-postadress som du använde för att registrera dig, vänligen skicka ett meddelande till %saur-general%s e-postlistan." #: html/passreset.php msgid "Enter your user name or your primary e-mail address:" @@ -479,7 +480,7 @@ msgstr "De valda paketen har inte gjorts herrelösa, kryssa i konfirmationsrutan msgid "" "The selected packages have not been adopted, check the confirmation " "checkbox." -msgstr "" +msgstr "De valda paketen har inte adopteras, markera kryssrutan för bekräftelse." #: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." @@ -545,7 +546,7 @@ msgstr "Använd det här formuläret för att göra paket basen %s%s%s och de f msgid "" "By selecting the checkbox, you confirm that you want to no longer be a " "package co-maintainer." -msgstr "" +msgstr "Genom att markera kryssrutan bekräftar du att du inte längre vill vara sam-ansvarig för paket." #: html/pkgdisown.php #, php-format @@ -585,7 +586,7 @@ msgid "" " package version in the AUR does not match the most recent commit. Flagging " "this package should only be done if the sources moved or changes in the " "PKGBUILD are required because of recent upstream changes." -msgstr "" +msgstr "Detta verkar vara ett VCS-paket. Flagga den %sinte%s som inaktuell om paketversionen i AUR inte matchar den mest senaste commit. Flaggning av detta paket bör endast göras om källkoden har flyttats eller ändringar i PKGBUILD krävs på grund av de senaste uppströmsändringarna." #: html/pkgflag.php #, php-format @@ -974,7 +975,7 @@ msgstr "Paket detaljer kunde inte hittas." #: aurweb/routers/auth.py msgid "Bad Referer header." -msgstr "" +msgstr "Dåligt referenshuvud." #: aurweb/routers/packages.py msgid "You did not select any packages to be notified about." @@ -982,19 +983,19 @@ msgstr "Du har inte valt några paket att notifieras om." #: aurweb/routers/packages.py msgid "The selected packages' notifications have been enabled." -msgstr "" +msgstr "De valda paketens aviseringar har aktiverats." #: aurweb/routers/packages.py msgid "You did not select any packages for notification removal." -msgstr "" +msgstr "Du har inte valt några paket för notifieringsborttagning." #: aurweb/routers/packages.py msgid "A package you selected does not have notifications enabled." -msgstr "" +msgstr "Ett paket du valde har inga notifieringar aktiverade." #: aurweb/routers/packages.py msgid "The selected packages' notifications have been removed." -msgstr "" +msgstr "De valda paketens notifieringar har blivit borttagna." #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." @@ -1046,7 +1047,7 @@ msgstr "Du måste vara inloggad före du kan adoptera paket." #: aurweb/routers/package.py msgid "You are not allowed to adopt one of the packages you selected." -msgstr "" +msgstr "Du är inte tillåten att adoptera ett av paketen du valde." #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." @@ -1054,7 +1055,7 @@ msgstr "Du måste vara inloggad före du kan göra paket härrelösa." #: aurweb/routers/packages.py msgid "You are not allowed to disown one of the packages you selected." -msgstr "" +msgstr "Du har inte tillåtelse att göra ett av paketen du valde herrelöst." #: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." @@ -1354,7 +1355,7 @@ msgid "" "If you do not hide your email address, it is visible to all registered AUR " "users. If you hide your email address, it is visible to members of the Arch " "Linux staff only." -msgstr "" +msgstr "Om du inte döljer din e-postadress är den synlig för alla registrerade AUR-användare. Om du döljer din e-postadress är den endast synlig för medlemmar av Arch Linux-personalen." #: template/account_edit_form.php msgid "Backup Email Address" @@ -1370,14 +1371,14 @@ msgstr "Ange eventuellt en sekundär e-postadress som kan användas för att åt msgid "" "Password reset links are always sent to both your primary and your backup " "email address." -msgstr "" +msgstr "Länkar för återställning av lösenord skickas alltid till både din primära och din reserv epostadress." #: template/account_edit_form.php #, php-format msgid "" "Your backup email address is always only visible to members of the Arch " "Linux staff, independent of the %s setting." -msgstr "" +msgstr "Din backup-e-postadress är alltid endast synlig för medlemmar av Arch Linux-personalen, oberoende av %s inställningen." #: template/account_edit_form.php msgid "Language" @@ -1435,7 +1436,7 @@ msgstr "Ditt nuvarande lösenord" msgid "" "To protect the AUR against automated account creation, we kindly ask you to " "provide the output of the following command:" -msgstr "" +msgstr "För att skydda AUR mot automatiskt kontoskapande ber vi dig att tillhandahålla utdata från följande kommando:" #: template/account_edit_form.php msgid "Answer" @@ -1654,7 +1655,7 @@ msgstr "Lägg till kommentar" msgid "" "Git commit identifiers referencing commits in the AUR package repository and" " URLs are converted to links automatically." -msgstr "" +msgstr "Git commit-identifierare som refererar till commits i AUR-paketförrådet och URL:er konverteras automatiskt till länkar." #: template/pkg_comment_form.php #, php-format @@ -1829,7 +1830,7 @@ msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "" +msgstr "Genom att skicka en begäran om borttagning ber du en Trusted User att ta bort paketbasen. Denna typ av begäran bör användas för dubbletter, programvara som övergetts av uppström, såväl som olagliga och irreparabelt trasiga paket." #: template/pkgreq_form.php msgid "" @@ -1837,7 +1838,7 @@ msgid "" "base and transfer its votes and comments to another package base. Merging a " "package does not affect the corresponding Git repositories. Make sure you " "update the Git history of the target package yourself." -msgstr "" +msgstr "Genom att skicka en sammanslagningsförfrågan ber du en Trusted User att ta bort paketbasen och överföra dess röster och kommentarer till en annan paketbas. Att slå samman ett paket påverkar inte motsvarande Git-förråd. Se till att du själv uppdaterar Git-historiken för målpaketet." #: template/pkgreq_form.php msgid "" @@ -1845,7 +1846,7 @@ msgid "" "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "" +msgstr "Genom att skicka in en föräldralös begäran ber du en Trusted User att avfärda paketbasen. Vänligen gör endast detta om paketet behöver underhållsåtgärder, underhållaren är MIA och du redan försökt kontakta underhållaren tidigare." #: template/pkgreq_results.php msgid "No requests matched your search criteria." @@ -1907,7 +1908,7 @@ msgstr "Stäng" #: template/pkgreq_results.php msgid "Pending" -msgstr "" +msgstr "Väntar på" #: template/pkgreq_results.php msgid "Closed" @@ -2026,7 +2027,7 @@ msgstr "Version" msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "" +msgstr "Populäritet räknas ut som summan av alla röster, och alla röster har en vikt med en faktor av %.2f per dag sedan den skapades. " #: template/pkg_search_results.php template/tu_details.php #: template/tu_list.php @@ -2180,18 +2181,18 @@ msgid "" "A password reset request was submitted for the account {user} associated " "with your email address. If you wish to reset your password follow the link " "[1] below, otherwise ignore this message and nothing will happen." -msgstr "" +msgstr "En begäran om lösenordsåterställning skickades för kontot {user} som är kopplat till din e-postadress. Om du vill återställa ditt lösenord, följ länken [1] nedan, annars ignorera detta meddelande och ingenting kommer att hända." #: scripts/notify.py msgid "Welcome to the Arch User Repository" -msgstr "" +msgstr "Välkommen till Arch User Repository" #: scripts/notify.py msgid "" "Welcome to the Arch User Repository! In order to set an initial password for" " your new account, please click the link [1] below. If the link does not " "work, try copying and pasting it into your browser." -msgstr "" +msgstr "Välkommen till Arch User Repository! För att ställa in ett första lösenord för ditt nya konto, klicka på länken [1] nedan. Om länken inte fungerar, försök att kopiera och klistra in den i din webbläsare." #: scripts/notify.py #, python-brace-format @@ -2208,7 +2209,7 @@ msgstr "{user} [1] lade till följande kommentar till {pkgbase} [2]:" msgid "" "If you no longer wish to receive notifications about this package, please go" " to the package page [2] and select \"{label}\"." -msgstr "" +msgstr "Om du inte längre vill få meddelanden om detta paket, gå till paketsidan [2] och välj \"{label}\"." #: scripts/notify.py #, python-brace-format @@ -2218,47 +2219,47 @@ msgstr "AUR paket uppdatering: {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "{user} [1] pushed a new commit to {pkgbase} [2]." -msgstr "" +msgstr "{user} [1] knuffade en ny commit till {pkgbase} [2]." #: scripts/notify.py #, python-brace-format msgid "AUR Out-of-date Notification for {pkgbase}" -msgstr "" +msgstr "AUR inaktuell avisering för {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "Your package {pkgbase} [1] has been flagged out-of-date by {user} [2]:" -msgstr "" +msgstr "Ditt paket {pkgbase} [1] har flaggats som inaktuellt av {user} [2]:" #: scripts/notify.py #, python-brace-format msgid "AUR Ownership Notification for {pkgbase}" -msgstr "" +msgstr "AUR-ägarskapsmeddelande för {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was adopted by {user} [2]." -msgstr "" +msgstr "Paketet {pkgbase} [1] adopterades av {user} [2]." #: scripts/notify.py #, python-brace-format msgid "The package {pkgbase} [1] was disowned by {user} [2]." -msgstr "" +msgstr "Paketet {pkgbase} [1] gjordes herrelöst av {user} [2]." #: scripts/notify.py #, python-brace-format msgid "AUR Co-Maintainer Notification for {pkgbase}" -msgstr "" +msgstr "AUR sam-ansvarig meddelande för {pkgbase}" #: scripts/notify.py #, python-brace-format msgid "You were added to the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "Du blev tillagd till sam-ansvarig listan för {pkgbase} [1]." #: scripts/notify.py #, python-brace-format msgid "You were removed from the co-maintainer list of {pkgbase} [1]." -msgstr "" +msgstr "Du blev borttagen från sam-ansvarig listan för {pkgbase} [1]." #: scripts/notify.py #, python-brace-format @@ -2272,7 +2273,7 @@ msgid "" "\n" "-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "" +msgstr "{user} [1] slog ihop {old} [2] till {new} [3].\n\n--\nOm du inte längre vill få meddelanden om det nya paketet, gå till [3] och klicka på \"{label}\"." #: scripts/notify.py #, python-brace-format @@ -2280,19 +2281,19 @@ msgid "" "{user} [1] deleted {pkgbase} [2].\n" "\n" "You will no longer receive notifications about this package." -msgstr "" +msgstr "{user} [1] raderade {pkgbase} [2].\n\nDu kommer inte längre att få aviseringar om detta paket." #: scripts/notify.py #, python-brace-format msgid "TU Vote Reminder: Proposal {id}" -msgstr "" +msgstr "TU röstningspåminnelse: Förslag {id}" #: scripts/notify.py #, python-brace-format msgid "" "Please remember to cast your vote on proposal {id} [1]. The voting period " "ends in less than 48 hours." -msgstr "" +msgstr "Kom ihåg att lägga din röst på förslaget {id} [1]. Omröstningsperioden slutar om mindre än 48 timmar." #: aurweb/routers/accounts.py msgid "Invalid account type provided." @@ -2308,33 +2309,33 @@ msgstr "Du har inte behörighet att ändra den här användarens kontotyp till % #: aurweb/packages/requests.py msgid "No due existing orphan requests to accept for %s." -msgstr "" +msgstr "Inga befintliga herrelösa begäranden att acceptera för %s." #: aurweb/asgi.py msgid "Internal Server Error" -msgstr "" +msgstr "Internt serverfel" #: templates/errors/500.html msgid "A fatal error has occurred." -msgstr "" +msgstr "Ett allvarligt fel har inträffat." #: templates/errors/500.html msgid "" "Details have been logged and will be reviewed by the postmaster posthaste. " "We apologize for any inconvenience this may have caused." -msgstr "" +msgstr "Detaljer har loggats och kommer att granskas av postmästaren så snabbt som möjligt. Vi ber om ursäkt för eventuella besvär som detta kan ha orsakat." #: aurweb/scripts/notify.py msgid "AUR Server Error" -msgstr "" +msgstr "AUR serverfel" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "Relaterade paketförfrågningar stängningskommentar..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Denna åtgärd kommer att stänga alla väntande paketförfrågningar relaterade till det paketet. %sOm kommentarer%s utelämnas kommer en stängningskommentar att automatiskt genereras." From 9497f6e671dff3c742ce9a4ec7d8226bff102121 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Sun, 14 Aug 2022 15:43:13 +0200 Subject: [PATCH 1539/1891] fix(aurweb): resolve exception in ratelimit Redis's get() method can return None which makes an RPC request error out: File "/srv/http/aurweb/aurweb/ratelimit.py", line 103, in check_ratelimit requests = int(requests.decode()) AttributeError: 'NoneType' object has no attribute 'decode' --- aurweb/ratelimit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/ratelimit.py b/aurweb/ratelimit.py index 659ab6b8..86063f5d 100644 --- a/aurweb/ratelimit.py +++ b/aurweb/ratelimit.py @@ -94,7 +94,7 @@ def check_ratelimit(request: Request): # valid cache value will be returned which must be converted # to an int. Otherwise, use the database record returned # by update_ratelimit. - if not config.getboolean("ratelimit", "cache"): + if not config.getboolean("ratelimit", "cache") or requests is None: # If we got nothing from pipeline.get, we did not use # the Redis path of logic: use the DB record's count. requests = record.Requests From b4e0aea2b73e2cde6968dac72fb1b2c9fcb5a17b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 14 Aug 2022 19:25:49 -0700 Subject: [PATCH 1540/1891] Merged bugfixes Brings in: 9497f6e671dff3c742ce9a4ec7d8226bff102121 Closes #512 Thanks, jelle! Signed-off-by: Kevin Morris From 801df832e53e56bc364f73fb88a1315eea91fb55 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 15 Aug 2022 10:06:44 -0700 Subject: [PATCH 1541/1891] fix(rpc): correct URLPath in package results This was incorrectly using the particular Package record's name to format options.snapshot_uri in order to produce URLPath. It should, instead, use the PackageBase record's name, which this commit resolves. Bug reported by thomy2000 Closes #382 Signed-off-by: Kevin Morris --- aurweb/rpc.py | 2 +- test/test_rpc.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index f04de7d6..3ea7e070 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -138,7 +138,7 @@ class RPC: "Version": package.Version, "Description": package.Description, "URL": package.URL, - "URLPath": snapshot_uri % package.Name, + "URLPath": snapshot_uri % package.PackageBaseName, "NumVotes": package.NumVotes, "Popularity": pop, "OutOfDate": package.OutOfDateTS, diff --git a/test/test_rpc.py b/test/test_rpc.py index 0e24467a..c0861d3d 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -297,6 +297,28 @@ def test_rpc_singular_info(client: TestClient, assert response_data == expected_data +def test_rpc_split_package_urlpath(client: TestClient, user: User): + with db.begin(): + pkgbase = db.create(PackageBase, Name="pkg", + Maintainer=user, Packager=user) + pkgs = [ + db.create(Package, PackageBase=pkgbase, Name="pkg_1"), + db.create(Package, PackageBase=pkgbase, Name="pkg_2"), + ] + + with client as request: + response = request.get("/rpc", params={ + "v": 5, + "type": "info", + "arg": [pkgs[0].Name], + }) + + data = orjson.loads(response.text) + snapshot_uri = config.get("options", "snapshot_uri") + urlpath = data.get("results")[0].get("URLPath") + assert urlpath == (snapshot_uri % pkgbase.Name) + + def test_rpc_nonexistent_package(client: TestClient): # Make dummy request. with client as request: From 7b047578fd5b64c0f8af47130aa02e7271690f6d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 15 Aug 2022 12:10:55 -0700 Subject: [PATCH 1542/1891] fix: correct kwarg name for approved users of creds.has_credential Signed-off-by: Kevin Morris --- aurweb/auth/creds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/auth/creds.py b/aurweb/auth/creds.py index 100aad8c..05b30d5d 100644 --- a/aurweb/auth/creds.py +++ b/aurweb/auth/creds.py @@ -69,8 +69,8 @@ cred_filters = { def has_credential(user: User, credential: int, - approved_users: list = tuple()): + approved: list = tuple()): - if user in approved_users: + if user in approved: return True return user.AccountTypeID in cred_filters[credential] From 7a52da5587f3c9d751b3b88526889a3f818c9754 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 15 Aug 2022 13:57:32 -0700 Subject: [PATCH 1543/1891] fix: guard POST keywords & allow co-maintainers to see keyword form This addresses a severe security issue, which is omitted from this git message for obscurity purposes. Otherwise, it allows co-maintainers to see the keyword form when viewing a package they co-maintain. Closes #378 Signed-off-by: Kevin Morris --- aurweb/routers/pkgbase.py | 6 ++++++ templates/partials/packages/details.html | 4 ++-- test/test_pkgbase_routes.py | 19 +++++++++++++++++-- test/test_templates.py | 4 +++- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 6cd4199d..1bca5ea3 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -96,6 +96,12 @@ async def pkgbase_keywords(request: Request, name: str, keywords: str = Form(default=str())): pkgbase = get_pkg_or_base(name, PackageBase) + approved = [pkgbase.Maintainer] + [c.User for c in pkgbase.comaintainers] + has_cred = creds.has_credential(request.user, creds.PKGBASE_SET_KEYWORDS, + approved=approved) + if not has_cred: + return Response(status_code=HTTPStatus.UNAUTHORIZED) + # Lowercase all keywords. Our database table is case insensitive, # and providing CI duplicates of keywords is erroneous. keywords = set(k.lower() for k in keywords.split()) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 771b311d..ca7159be 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -33,10 +33,10 @@ {% endif %} - {% if pkgbase.keywords.count() or request.user.has_credential(creds.PKGBASE_SET_KEYWORDS, approved=[pkgbase.Maintainer]) %} + {% if pkgbase.keywords.count() or request.user.has_credential(creds.PKGBASE_SET_KEYWORDS, approved=[pkgbase.Maintainer] + comaintainers) %} - {% if request.user.has_credential(creds.PKGBASE_SET_KEYWORDS, approved=[pkgbase.Maintainer]) %} + {% if request.user.has_credential(creds.PKGBASE_SET_KEYWORDS, approved=[pkgbase.Maintainer] + comaintainers) %}
      {{ "Total" | tr }} {{ "Trusted Users" | tr }}:{{ "Total" | tr }} {{ "Trusted Users" | tr }}: {{ trusted_user_count }}
      {{ "Active" | tr }} {{ "Trusted Users" | tr }}:{{ "Active" | tr }} {{ "Trusted Users" | tr }}: {{ active_trusted_user_count }}
      {{ "Maintainer" | tr }}: - {% if pkgbase.Maintainer %} + {% if request.user.is_authenticated() and pkgbase.Maintainer %} {{ pkgbase.Maintainer.Username }} @@ -118,6 +118,9 @@ {% endif %} {% else %} {{ pkgbase.Maintainer.Username | default("None" | tr) }} + {% if comaintainers %} + ({{ comaintainers|join(', ') }}) + {% endif %} {% endif %}
      {{ "Keywords" | tr }}:
      Date: Mon, 15 Aug 2022 14:49:34 -0700 Subject: [PATCH 1544/1891] fix: secure access to comment edits to user who owns the comment Found along with the previous commit to be a security hole in our implementation. This commit resolves an issue regarding comment editing. Signed-off-by: Kevin Morris --- aurweb/routers/pkgbase.py | 2 ++ test/test_pkgbase_routes.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 1bca5ea3..c735f474 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -286,6 +286,8 @@ async def pkgbase_comment_post( if not comment: raise HTTPException(status_code=HTTPStatus.BAD_REQUEST) + elif request.user.ID != db_comment.UsersID: + raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED) # If the provided comment is different than the record's version, # update the db record. diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index 5c44ea47..f6bcf5d7 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -467,6 +467,22 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, assert "form" in data +def test_pkgbase_comment_edit_unauthorized(client: TestClient, + user: User, + maintainer: User, + package: Package, + comment: PackageComment): + pkgbase = package.PackageBase + + cookies = {"AURSID": maintainer.login(Request(), "testPassword")} + with client as request: + endp = f"/pkgbase/{pkgbase.Name}/comments/{comment.ID}" + response = request.post(endp, data={ + "comment": "abcd im trying to change this comment." + }, cookies=cookies) + assert response.status_code == HTTPStatus.UNAUTHORIZED + + def test_pkgbase_comment_delete(client: TestClient, maintainer: User, user: User, From 33bf5df236166cbbbd8ef1b611145effc5813acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20M=C3=B6ller?= Date: Fri, 12 Aug 2022 18:43:18 +0200 Subject: [PATCH 1545/1891] fix: show unflag link to flagger While the flagger is allowed to unflag a package, the link to do so is hidden from them. Fix by adding the flagger to the unflag list. Fix #380 --- aurweb/pkgbase/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index 5ffe490e..63621d63 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -46,7 +46,7 @@ def make_context(request: Request, pkgbase: PackageBase, ).all() ] context["unflaggers"] = context["comaintainers"].copy() - context["unflaggers"].append(pkgbase.Maintainer) + context["unflaggers"].extend([pkgbase.Maintainer, pkgbase.Flagger]) context["packages_count"] = pkgbase.packages.count() context["keywords"] = pkgbase.keywords From fb1fb2ef3b6ff441ce30c5fd50781376e4cd02c4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Aug 2022 09:59:56 -0700 Subject: [PATCH 1546/1891] feat: documentation for web authentication (login, verification) Signed-off-by: Kevin Morris --- doc/web-auth.md | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 doc/web-auth.md diff --git a/doc/web-auth.md b/doc/web-auth.md new file mode 100644 index 00000000..5f6679d4 --- /dev/null +++ b/doc/web-auth.md @@ -0,0 +1,111 @@ +# aurweb Web Authentication + +aurweb uses an HTTP cookie to persist user sessions across requests. +This cookie **must** be delivered with a request in order to be considered +an authenticated user. + +See [HTTP Cookie](#http-cookie) for detailed information about the cookie. + +## HTTP Cookie + +aurweb utilizes an HTTP cookie by the name of `AURSID` to track +user authentication across requests. + +This cookie's requirements changes due to aurweb's configuration +in the following ways: + +- `options.disable_http_login: 0` + - [Samesite=LAX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), Max-Age +- `options.disable_http_login: 1` + - [Secure, HttpOnly](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies), [Samesite=Strict](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), Max-Age + +### Max-Age + +The value used for the `AURSID` Max-Age attribute is decided based +off of the "Remember Me" checkbox on the login page. Both paths +use their own independent configuration for the number of seconds +that each type of session should stay alive. + +- "Remember Me" unchecked while logging in + - `options.login_timeout` is used +- "Remember Me" checked while logging in + - `options.persistent_cookie_timeout` is used + +Both `options.login_timeout` and `options.persistent_cookie_timeout` +indicate the number of seconds the session should live. + +### Notes + +At all times, aur.archlinux.org operates over HTTPS. Secure cookies will +only remain intact when subsequently requesting an aurweb route through +the HTTPS scheme at the same host as the cookie was obtained. + +## Login Process + +When a user logs in to aurweb, the following steps are taken: + +1. Was a Referer header delivered from an address starting with +`{aurweb_url}/login`? + 1. No, an HTTP 400 Bad Request response is returned + 2. Yes, move on to 2 +2. Does a Users database record exist for the given username/email? + 1. No, you are returned to the login page with `Bad username or password.` + error + 2. Yes, move on to 3 +3. Is the user suspended? + 1. Yes, you are returned to the login page with `Account Suspended` error + 2. No, move on to 4 +4. Can the user login with the given password? + 1. No, you are returned to the login page with `Bad username or password.` + error + 2. Yes, move on to 5 +5. Update the user's `LastLogin` and `LastLoginIPAddress` columns +6. Does the user have a related Sessions record? + 1. No, generate a new Sessions record with a new unique `SessionID` + 2. Yes, update the Sessions record's `SessionID` column with a new unique + string and update the Sessions record's `LastUpdateTS` column if it has + expired + 3. In both cases, set the user's `InactivityTS` column to `0` + 4. In both cases, return the new `SessionID` column value and move on to 7 +7. Return a redirect to the `next` GET variable with the +following cookies set: + 1. `AURSID` + - Unique session string matching the user's related + `Sessions.SessionID` column + 2. `AURTZ` + - User's timezone setting + 3. `AURLANG` + - User's language setting + 4. `AURREMEMBER` + - Boolean state of the "Remember Me" checkbox when login submitted + +## Auth Verification + +When a request is made toward aurweb, a middleware is responsible for +verifying the user's auth cookie. If no valid `AURSID` cookie could be +found for a user in the database, the request is considered unauthenticated. + +The following list of steps describes exactly how this verification works: +1. Was the `AURSID` cookie delivered? + 1. No, the algorithm ends, you are considered unauthenticated + 2. Yes, move on to 2 +2. Was the `AURREMEMBER` cookie delivered with a value of 1? + 1. No, set the expected session timeout **T** to `options.login_timeout` + 2. Yes, set the expected session timeout **T** to + `options.persistent_cookie_timeout` +3. Does a Sessions database record exist which matches the `AURSID`? + 1. No, the algorithm ends, you are considered unauthenticated + 2. Yes, move on to 4 +4. Does the Sessions record's LastUpdateTS column fit within `utcnow - T`? + 1. No, the Sessions record at hand is deleted, the algorithm ends, you + are considered unauthenticated + 2. Yes, move on to 5 +5. You are considered authenticated + +## aur.archlinux.org Auth-Related Configuration + +- Operates over HTTPS with a Let's Encrypt SSL certificate +- `options.disable_http_login: 1` +- `options.login_timeout: ` +- `options.persistent_cookie_timeout: ` + From f10732960cd17e680e1a8a7b420b0b15ff391099 Mon Sep 17 00:00:00 2001 From: Joakim Saario Date: Thu, 18 Aug 2022 18:35:25 +0200 Subject: [PATCH 1547/1891] fix: Use SameSite=Lax on cookies --- aurweb/cookies.py | 10 ++++---- doc/web-auth.md | 2 +- test/test_auth_routes.py | 52 ++++++++++++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/aurweb/cookies.py b/aurweb/cookies.py index 442a4c0a..58d14515 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -5,15 +5,13 @@ from aurweb import config def samesite() -> str: - """ Produce cookie SameSite value based on options.disable_http_login. + """ Produce cookie SameSite value. - When options.disable_http_login is True, "strict" is returned. Otherwise, - "lax" is returned. + Currently this is hard-coded to return "lax" - :returns "strict" if options.disable_http_login else "lax" + :returns "lax" """ - secure = config.getboolean("options", "disable_http_login") - return "strict" if secure else "lax" + return "lax" def timeout(extended: bool) -> int: diff --git a/doc/web-auth.md b/doc/web-auth.md index 5f6679d4..1161af6f 100644 --- a/doc/web-auth.md +++ b/doc/web-auth.md @@ -17,7 +17,7 @@ in the following ways: - `options.disable_http_login: 0` - [Samesite=LAX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), Max-Age - `options.disable_http_login: 1` - - [Secure, HttpOnly](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies), [Samesite=Strict](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), Max-Age + - [Samesite=LAX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), [Secure, HttpOnly](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) ### Max-Age diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 8467adea..5942edcf 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -109,14 +109,52 @@ def test_login_email(client: TestClient, user: user): assert "AURSID" in resp.cookies -def mock_getboolean(a, b): - if a == "options" and b == "disable_http_login": - return True - return bool(aurweb.config.get(a, b)) +def mock_getboolean(**overrided_configs): + mocked_config = { + tuple(config.split("__")): value + for config, value in overrided_configs.items() + } + + def side_effect(*args): + return mocked_config.get(args, bool(aurweb.config.get(*args))) + + return side_effect -@mock.patch("aurweb.config.getboolean", side_effect=mock_getboolean) -def test_secure_login(getboolean: bool, client: TestClient, user: User): +@mock.patch( + "aurweb.config.getboolean", + side_effect=mock_getboolean(options__disable_http_login=False) +) +def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User): + post_data = { + "user": user.Username, + "passwd": "testPassword", + "next": "/" + } + + # Perform a login request with the data matching our user. + with client as request: + response = request.post("/login", data=post_data, + allow_redirects=False) + + # Make sure we got the expected status out of it. + assert response.status_code == int(HTTPStatus.SEE_OTHER) + + # Let's check what we got in terms of cookies for AURSID. + # Make sure that a secure cookie got passed to us. + cookie = next(c for c in response.cookies if c.name == "AURSID") + assert cookie.secure is False + assert cookie.has_nonstandard_attr("HttpOnly") is False + assert cookie.has_nonstandard_attr("SameSite") is True + assert cookie.get_nonstandard_attr("SameSite") == "lax" + assert cookie.value is not None and len(cookie.value) > 0 + + +@mock.patch( + "aurweb.config.getboolean", + side_effect=mock_getboolean(options__disable_http_login=True) +) +def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User): """ In this test, we check to verify the course of action taken by starlette when providing secure=True to a response cookie. This is achieved by mocking aurweb.config.getboolean to return @@ -154,7 +192,7 @@ def test_secure_login(getboolean: bool, client: TestClient, user: User): assert cookie.secure is True assert cookie.has_nonstandard_attr("HttpOnly") is True assert cookie.has_nonstandard_attr("SameSite") is True - assert cookie.get_nonstandard_attr("SameSite") == "strict" + assert cookie.get_nonstandard_attr("SameSite") == "lax" assert cookie.value is not None and len(cookie.value) > 0 # Let's make sure we actually have a session relationship From 4303086c0e59d510c2f5ad28083574889340eba6 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Aug 2022 14:47:24 -0700 Subject: [PATCH 1548/1891] Merged branch 'sameorigin-lax' Closes #351 Signed-off-by: Kevin Morris From 8e43932aa6497ccf024e957687fd87120f2125cf Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Aug 2022 14:57:42 -0700 Subject: [PATCH 1549/1891] fix(doc): re-add Max-Age to list of secure cookie attributes Signed-off-by: Kevin Morris --- doc/web-auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/web-auth.md b/doc/web-auth.md index 1161af6f..17284889 100644 --- a/doc/web-auth.md +++ b/doc/web-auth.md @@ -17,7 +17,7 @@ in the following ways: - `options.disable_http_login: 0` - [Samesite=LAX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), Max-Age - `options.disable_http_login: 1` - - [Samesite=LAX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), [Secure, HttpOnly](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies) + - [Samesite=LAX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#samesite_attribute), [Secure, HttpOnly](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies), Max-Age ### Max-Age From fd4aaed208fb862c2f66edbe122f4c4e5d52c765 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 17 Aug 2022 10:01:06 -0700 Subject: [PATCH 1550/1891] fix: use max-age for all cookie expirations in addition, remove cookie expiration for AURREMEMBER -- we don't really care about a session time for this cookie, it merely acts as a flag given out on login to remember what the user selected Signed-off-by: Kevin Morris --- aurweb/routers/auth.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 9f465388..50cec419 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -6,7 +6,7 @@ from sqlalchemy import or_ import aurweb.config -from aurweb import cookies, db, time +from aurweb import cookies, db from aurweb.auth import requires_auth, requires_guest from aurweb.exceptions import handle_form_exceptions from aurweb.l10n import get_translator_for_request @@ -65,15 +65,11 @@ async def login_post(request: Request, return await login_template(request, next, errors=["Bad username or password."]) - login_timeout = aurweb.config.getint("options", "login_timeout") - - expires_at = int(time.utcnow() + max(cookie_timeout, login_timeout)) - response = RedirectResponse(url=next, status_code=HTTPStatus.SEE_OTHER) secure = aurweb.config.getboolean("options", "disable_http_login") - response.set_cookie("AURSID", sid, expires=expires_at, + response.set_cookie("AURSID", sid, max_age=cookie_timeout, secure=secure, httponly=secure, samesite=cookies.samesite()) response.set_cookie("AURTZ", user.Timezone, @@ -83,7 +79,6 @@ async def login_post(request: Request, secure=secure, httponly=secure, samesite=cookies.samesite()) response.set_cookie("AURREMEMBER", remember_me, - expires=expires_at, secure=secure, httponly=secure, samesite=cookies.samesite()) return response From ab2956eef79aed68e8da3c37b237950916f78c25 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 18 Aug 2022 16:02:03 -0700 Subject: [PATCH 1551/1891] feat: add pytest unit of independent user unflagging Signed-off-by: Kevin Morris --- test/test_pkgbase_routes.py | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index f6bcf5d7..8be08f83 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -1457,3 +1457,52 @@ def test_unauthorized_pkgbase_keywords(client: TestClient, package: Package): endp = f"/pkgbase/{pkgbase.Name}/keywords" response = request.post(endp, cookies=cookies) assert response.status_code == HTTPStatus.UNAUTHORIZED + + +def test_independent_user_unflag(client: TestClient, user: User, + package: Package): + with db.begin(): + flagger = db.create(User, Username="test_flagger", + Email="test_flagger@example.com", + Passwd="testPassword") + + pkgbase = package.PackageBase + cookies = {"AURSID": flagger.login(Request(), "testPassword")} + with client as request: + endp = f"/pkgbase/{pkgbase.Name}/flag" + response = request.post(endp, data={ + "comments": "This thing needs a flag!" + }, cookies=cookies, allow_redirects=True) + assert response.status_code == HTTPStatus.OK + + # At this point, we've flagged it as `flagger`. + # Now, we should be able to view the "Unflag package" link on the package + # page when browsing as that `flagger` user. + with client as request: + endp = f"/pkgbase/{pkgbase.Name}" + response = request.get(endp, cookies=cookies, allow_redirects=True) + assert response.status_code == HTTPStatus.OK + + # Assert that the "Unflag package" link appears in the DOM. + root = parse_root(response.text) + elems = root.xpath('//input[@name="do_UnFlag"]') + assert len(elems) == 1 + + # Now, unflag the package by "clicking" the "Unflag package" link. + with client as request: + endp = f"/pkgbase/{pkgbase.Name}/unflag" + response = request.post(endp, cookies=cookies, allow_redirects=True) + assert response.status_code == HTTPStatus.OK + + # For the last time, let's check the GET response. The package should + # not show as flagged anymore, and thus the "Unflag package" link + # should be missing. + with client as request: + endp = f"/pkgbase/{pkgbase.Name}" + response = request.get(endp, cookies=cookies, allow_redirects=True) + assert response.status_code == HTTPStatus.OK + + # Assert that the "Unflag package" link does not appear in the DOM. + root = parse_root(response.text) + elems = root.xpath('//input[@name="do_UnFlag"]') + assert len(elems) == 0 From 08d485206cc821f4b041c7ace163ac54821984ce Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 3 Aug 2022 16:50:52 +0300 Subject: [PATCH 1552/1891] feature: allow co-maintainers to disown their pkg Derived off of original work done by Leonidas Spyropoulos at https://gitlab.archlinux.org/archlinux/aurweb/-/merge_requests/503 This revision of that original work finishes off the inconsistencies mentioned in the original MR and adds a small bit of testing for more regression checks. Fixes: #360 Signed-off-by: Kevin Morris --- aurweb/pkgbase/actions.py | 11 +++ aurweb/routers/pkgbase.py | 19 +++-- templates/partials/packages/actions.html | 2 +- templates/pkgbase/disown.html | 38 +++++----- test/test_pkgbase_routes.py | 88 +++++++++++++++++++++--- 5 files changed, 123 insertions(+), 35 deletions(-) diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 46609f89..27143d51 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -50,6 +50,12 @@ def pkgbase_disown_instance(request: Request, pkgbase: PackageBase) -> None: notifs = [notify.DisownNotification(disowner.ID, pkgbase.ID)] is_maint = disowner == pkgbase.Maintainer + + comaint = pkgbase.comaintainers.filter( + PackageComaintainer.User == disowner + ).one_or_none() + is_comaint = comaint is not None + if is_maint: with db.begin(): # Comaintainer with the lowest Priority value; next-in-line. @@ -63,6 +69,11 @@ def pkgbase_disown_instance(request: Request, pkgbase: PackageBase) -> None: else: # Otherwise, just orphan the package completely. pkgbase.Maintainer = None + elif is_comaint: + # This disown request is from a Comaintainer + with db.begin(): + notif = pkgbaseutil.remove_comaintainer(comaint) + notifs.append(notif) elif request.user.has_credential(creds.PKGBASE_DISOWN): # Otherwise, the request user performing this disownage is a # Trusted User and we treat it like a standard orphan request. diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index c735f474..1f09cfc8 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -545,15 +545,18 @@ async def pkgbase_disown_get(request: Request, name: str, next: str = Query(default=str())): pkgbase = get_pkg_or_base(name, PackageBase) + comaints = {c.User for c in pkgbase.comaintainers} + approved = [pkgbase.Maintainer] + list(comaints) has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, - approved=[pkgbase.Maintainer]) + approved=approved) if not has_cred: - return RedirectResponse(f"/pkgbase/{name}", - HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", HTTPStatus.SEE_OTHER) context = templates.make_context(request, "Disown Package") context["pkgbase"] = pkgbase context["next"] = next or "/pkgbase/{name}" + context["is_maint"] = request.user == pkgbase.Maintainer + context["is_comaint"] = request.user in comaints return render_template(request, "pkgbase/disown.html", context) @@ -566,8 +569,10 @@ async def pkgbase_disown_post(request: Request, name: str, next: str = Form(default=str())): pkgbase = get_pkg_or_base(name, PackageBase) + comaints = {c.User for c in pkgbase.comaintainers} + approved = [pkgbase.Maintainer] + list(comaints) has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, - approved=[pkgbase.Maintainer]) + approved=approved) if not has_cred: return RedirectResponse(f"/pkgbase/{name}", HTTPStatus.SEE_OTHER) @@ -580,8 +585,9 @@ async def pkgbase_disown_post(request: Request, name: str, return render_template(request, "pkgbase/disown.html", context, status_code=HTTPStatus.BAD_REQUEST) - with db.begin(): - update_closure_comment(pkgbase, ORPHAN_ID, comments) + if request.user != pkgbase.Maintainer and request.user not in comaints: + with db.begin(): + update_closure_comment(pkgbase, ORPHAN_ID, comments) try: actions.pkgbase_disown_instance(request, pkgbase) @@ -862,7 +868,6 @@ async def pkgbase_merge_post(request: Request, name: str, comments: str = Form(default=str()), confirm: bool = Form(default=False), next: str = Form(default=str())): - pkgbase = get_pkg_or_base(name, PackageBase) context = await make_variable_context(request, "Package Merging") context["pkgbase"] = pkgbase diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index 2144b07a..fa8c994f 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -131,7 +131,7 @@ /> - {% elif request.user.has_credential(creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer]) %} + {% elif request.user.has_credential(creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer] + comaintainers) %}
    • {{ "Disown Package" | tr }} diff --git a/templates/pkgbase/disown.html b/templates/pkgbase/disown.html index 3cc7988d..1aedde4f 100644 --- a/templates/pkgbase/disown.html +++ b/templates/pkgbase/disown.html @@ -27,14 +27,16 @@ {% endfor %} -

      - {{ - "This action will close any pending package requests " - "related to it. If %sComments%s are omitted, a closure " - "comment will be autogenerated." - | tr | format("", "") | safe - }} -

      + {% if not is_maint and not is_comaint %} +

      + {{ + "This action will close any pending package requests " + "related to it. If %sComments%s are omitted, a closure " + "comment will be autogenerated." + | tr | format("", "") | safe + }} +

      + {% endif %}

      {{ @@ -47,14 +49,18 @@

      -

      - - -

      + {% if not is_maint and not is_comaint %} +

      + + +

      + {% else %} + + {% endif %}

      {pkg.Name}' - for pkg in provides - ]) + return ", ".join( + [f'{pkg.Name}' for pkg in provides] + ) def get_pkg_or_base( - name: str, - cls: Union[models.Package, models.PackageBase] = models.PackageBase) \ - -> Union[models.Package, models.PackageBase]: - """ Get a PackageBase instance by its name or raise a 404 if + name: str, cls: Union[models.Package, models.PackageBase] = models.PackageBase +) -> Union[models.Package, models.PackageBase]: + """Get a PackageBase instance by its name or raise a 404 if it can't be found in the database. :param name: {Package,PackageBase}.Name @@ -109,8 +106,7 @@ def get_pkg_or_base( return instance -def get_pkgbase_comment(pkgbase: models.PackageBase, id: int) \ - -> models.PackageComment: +def get_pkgbase_comment(pkgbase: models.PackageBase, id: int) -> models.PackageComment: comment = pkgbase.comments.filter(models.PackageComment.ID == id).first() if not comment: raise HTTPException(status_code=HTTPStatus.NOT_FOUND) @@ -122,9 +118,8 @@ def out_of_date(packages: orm.Query) -> orm.Query: return packages.filter(models.PackageBase.OutOfDateTS.isnot(None)) -def updated_packages(limit: int = 0, - cache_ttl: int = 600) -> list[models.Package]: - """ Return a list of valid Package objects ordered by their +def updated_packages(limit: int = 0, cache_ttl: int = 600) -> list[models.Package]: + """Return a list of valid Package objects ordered by their ModifiedTS column in descending order from cache, after setting the cache when no key yet exists. @@ -139,10 +134,11 @@ def updated_packages(limit: int = 0, return orjson.loads(packages) with db.begin(): - query = db.query(models.Package).join(models.PackageBase).filter( - models.PackageBase.PackagerUID.isnot(None) - ).order_by( - models.PackageBase.ModifiedTS.desc() + query = ( + db.query(models.Package) + .join(models.PackageBase) + .filter(models.PackageBase.PackagerUID.isnot(None)) + .order_by(models.PackageBase.ModifiedTS.desc()) ) if limit: @@ -152,13 +148,13 @@ def updated_packages(limit: int = 0, for pkg in query: # For each Package returned by the query, append a dict # containing Package columns we're interested in. - packages.append({ - "Name": pkg.Name, - "Version": pkg.Version, - "PackageBase": { - "ModifiedTS": pkg.PackageBase.ModifiedTS + packages.append( + { + "Name": pkg.Name, + "Version": pkg.Version, + "PackageBase": {"ModifiedTS": pkg.PackageBase.ModifiedTS}, } - }) + ) # Store the JSON serialization of the package_updates key into Redis. redis.set("package_updates", orjson.dumps(packages)) @@ -168,9 +164,8 @@ def updated_packages(limit: int = 0, return packages -def query_voted(query: list[models.Package], - user: models.User) -> dict[int, bool]: - """ Produce a dictionary of package base ID keys to boolean values, +def query_voted(query: list[models.Package], user: models.User) -> dict[int, bool]: + """Produce a dictionary of package base ID keys to boolean values, which indicate whether or not the package base has a vote record related to user. @@ -180,20 +175,18 @@ def query_voted(query: list[models.Package], """ output = defaultdict(bool) query_set = {pkg.PackageBaseID for pkg in query} - voted = db.query(models.PackageVote).join( - models.PackageBase, - models.PackageBase.ID.in_(query_set) - ).filter( - models.PackageVote.UsersID == user.ID + voted = ( + db.query(models.PackageVote) + .join(models.PackageBase, models.PackageBase.ID.in_(query_set)) + .filter(models.PackageVote.UsersID == user.ID) ) for vote in voted: output[vote.PackageBase.ID] = True return output -def query_notified(query: list[models.Package], - user: models.User) -> dict[int, bool]: - """ Produce a dictionary of package base ID keys to boolean values, +def query_notified(query: list[models.Package], user: models.User) -> dict[int, bool]: + """Produce a dictionary of package base ID keys to boolean values, which indicate whether or not the package base has a notification record related to user. @@ -203,19 +196,17 @@ def query_notified(query: list[models.Package], """ output = defaultdict(bool) query_set = {pkg.PackageBaseID for pkg in query} - notified = db.query(models.PackageNotification).join( - models.PackageBase, - models.PackageBase.ID.in_(query_set) - ).filter( - models.PackageNotification.UserID == user.ID + notified = ( + db.query(models.PackageNotification) + .join(models.PackageBase, models.PackageBase.ID.in_(query_set)) + .filter(models.PackageNotification.UserID == user.ID) ) for notif in notified: output[notif.PackageBase.ID] = True return output -def pkg_required(pkgname: str, provides: list[str]) \ - -> list[PackageDependency]: +def pkg_required(pkgname: str, provides: list[str]) -> list[PackageDependency]: """ Get dependencies that match a string in `[pkgname] + provides`. @@ -225,9 +216,12 @@ def pkg_required(pkgname: str, provides: list[str]) \ :return: List of PackageDependency instances """ targets = set([pkgname] + provides) - query = db.query(PackageDependency).join(Package).filter( - PackageDependency.DepName.in_(targets) - ).order_by(Package.Name.asc()) + query = ( + db.query(PackageDependency) + .join(Package) + .filter(PackageDependency.DepName.in_(targets)) + .order_by(Package.Name.asc()) + ) return query diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 27143d51..4834f8dd 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -14,15 +14,15 @@ logger = logging.get_logger(__name__) def pkgbase_notify_instance(request: Request, pkgbase: PackageBase) -> None: - notif = db.query(pkgbase.notifications.filter( - PackageNotification.UserID == request.user.ID - ).exists()).scalar() + notif = db.query( + pkgbase.notifications.filter( + PackageNotification.UserID == request.user.ID + ).exists() + ).scalar() has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY) if has_cred and not notif: with db.begin(): - db.create(PackageNotification, - PackageBase=pkgbase, - User=request.user) + db.create(PackageNotification, PackageBase=pkgbase, User=request.user) def pkgbase_unnotify_instance(request: Request, pkgbase: PackageBase) -> None: @@ -36,8 +36,11 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: PackageBase) -> None: def pkgbase_unflag_instance(request: Request, pkgbase: PackageBase) -> None: - has_cred = request.user.has_credential(creds.PKGBASE_UNFLAG, approved=[ - pkgbase.Flagger, pkgbase.Maintainer] + [c.User for c in pkgbase.comaintainers]) + has_cred = request.user.has_credential( + creds.PKGBASE_UNFLAG, + approved=[pkgbase.Flagger, pkgbase.Maintainer] + + [c.User for c in pkgbase.comaintainers], + ) if has_cred: with db.begin(): pkgbase.OutOfDateTS = None @@ -93,9 +96,9 @@ def pkgbase_adopt_instance(request: Request, pkgbase: PackageBase) -> None: notif.send() -def pkgbase_delete_instance(request: Request, pkgbase: PackageBase, - comments: str = str()) \ - -> list[notify.Notification]: +def pkgbase_delete_instance( + request: Request, pkgbase: PackageBase, comments: str = str() +) -> list[notify.Notification]: notifs = handle_request(request, DELETION_ID, pkgbase) + [ notify.DeleteNotification(request.user.ID, pkgbase.ID) ] @@ -107,8 +110,9 @@ def pkgbase_delete_instance(request: Request, pkgbase: PackageBase, return notifs -def pkgbase_merge_instance(request: Request, pkgbase: PackageBase, - target: PackageBase, comments: str = str()) -> None: +def pkgbase_merge_instance( + request: Request, pkgbase: PackageBase, target: PackageBase, comments: str = str() +) -> None: pkgbasename = str(pkgbase.Name) # Create notifications. @@ -144,8 +148,10 @@ def pkgbase_merge_instance(request: Request, pkgbase: PackageBase, db.delete(pkgbase) # Log this out for accountability purposes. - logger.info(f"Trusted User '{request.user.Username}' merged " - f"'{pkgbasename}' into '{target.Name}'.") + logger.info( + f"Trusted User '{request.user.Username}' merged " + f"'{pkgbasename}' into '{target.Name}'." + ) # Send notifications. util.apply_all(notifs, lambda n: n.send()) diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index 63621d63..223c3013 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -10,19 +10,23 @@ from aurweb.models.package_comment import PackageComment from aurweb.models.package_request import PENDING_ID, PackageRequest from aurweb.models.package_vote import PackageVote from aurweb.scripts import notify -from aurweb.templates import make_context as _make_context -from aurweb.templates import make_variable_context as _make_variable_context +from aurweb.templates import ( + make_context as _make_context, + make_variable_context as _make_variable_context, +) -async def make_variable_context(request: Request, pkgbase: PackageBase) \ - -> dict[str, Any]: +async def make_variable_context( + request: Request, pkgbase: PackageBase +) -> dict[str, Any]: ctx = await _make_variable_context(request, pkgbase.Name) return make_context(request, pkgbase, ctx) -def make_context(request: Request, pkgbase: PackageBase, - context: dict[str, Any] = None) -> dict[str, Any]: - """ Make a basic context for package or pkgbase. +def make_context( + request: Request, pkgbase: PackageBase, context: dict[str, Any] = None +) -> dict[str, Any]: + """Make a basic context for package or pkgbase. :param request: FastAPI request :param pkgbase: PackageBase instance @@ -34,14 +38,16 @@ def make_context(request: Request, pkgbase: PackageBase, # Per page and offset. offset, per_page = util.sanitize_params( request.query_params.get("O", defaults.O), - request.query_params.get("PP", defaults.COMMENTS_PER_PAGE)) + request.query_params.get("PP", defaults.COMMENTS_PER_PAGE), + ) context["O"] = offset context["PP"] = per_page context["git_clone_uri_anon"] = config.get("options", "git_clone_uri_anon") context["git_clone_uri_priv"] = config.get("options", "git_clone_uri_priv") context["pkgbase"] = pkgbase context["comaintainers"] = [ - c.User for c in pkgbase.comaintainers.order_by( + c.User + for c in pkgbase.comaintainers.order_by( PackageComaintainer.Priority.asc() ).all() ] @@ -53,9 +59,11 @@ def make_context(request: Request, pkgbase: PackageBase, context["comments_total"] = pkgbase.comments.order_by( PackageComment.CommentTS.desc() ).count() - context["comments"] = pkgbase.comments.order_by( - PackageComment.CommentTS.desc() - ).limit(per_page).offset(offset) + context["comments"] = ( + pkgbase.comments.order_by(PackageComment.CommentTS.desc()) + .limit(per_page) + .offset(offset) + ) context["pinned_comments"] = pkgbase.comments.filter( PackageComment.PinnedTS != 0 ).order_by(PackageComment.CommentTS.desc()) @@ -70,15 +78,15 @@ def make_context(request: Request, pkgbase: PackageBase, ).scalar() context["requests"] = pkgbase.requests.filter( - and_(PackageRequest.Status == PENDING_ID, - PackageRequest.ClosedTS.is_(None)) + and_(PackageRequest.Status == PENDING_ID, PackageRequest.ClosedTS.is_(None)) ).count() return context -def remove_comaintainer(comaint: PackageComaintainer) \ - -> notify.ComaintainerRemoveNotification: +def remove_comaintainer( + comaint: PackageComaintainer, +) -> notify.ComaintainerRemoveNotification: """ Remove a PackageComaintainer. @@ -107,9 +115,9 @@ def remove_comaintainers(pkgbase: PackageBase, usernames: list[str]) -> None: """ notifications = [] with db.begin(): - comaintainers = pkgbase.comaintainers.join(User).filter( - User.Username.in_(usernames) - ).all() + comaintainers = ( + pkgbase.comaintainers.join(User).filter(User.Username.in_(usernames)).all() + ) notifications = [ notify.ComaintainerRemoveNotification(co.User.ID, pkgbase.ID) for co in comaintainers @@ -133,23 +141,23 @@ def latest_priority(pkgbase: PackageBase) -> int: """ # Order comaintainers related to pkgbase by Priority DESC. - record = pkgbase.comaintainers.order_by( - PackageComaintainer.Priority.desc()).first() + record = pkgbase.comaintainers.order_by(PackageComaintainer.Priority.desc()).first() # Use Priority column if record exists, otherwise 0. return record.Priority if record else 0 class NoopComaintainerNotification: - """ A noop notification stub used as an error-state return value. """ + """A noop notification stub used as an error-state return value.""" def send(self) -> None: - """ noop """ + """noop""" return -def add_comaintainer(pkgbase: PackageBase, comaintainer: User) \ - -> notify.ComaintainerAddNotification: +def add_comaintainer( + pkgbase: PackageBase, comaintainer: User +) -> notify.ComaintainerAddNotification: """ Add a new comaintainer to `pkgbase`. @@ -165,14 +173,19 @@ def add_comaintainer(pkgbase: PackageBase, comaintainer: User) \ new_prio = latest_priority(pkgbase) + 1 with db.begin(): - db.create(PackageComaintainer, PackageBase=pkgbase, - User=comaintainer, Priority=new_prio) + db.create( + PackageComaintainer, + PackageBase=pkgbase, + User=comaintainer, + Priority=new_prio, + ) return notify.ComaintainerAddNotification(comaintainer.ID, pkgbase.ID) -def add_comaintainers(request: Request, pkgbase: PackageBase, - usernames: list[str]) -> None: +def add_comaintainers( + request: Request, pkgbase: PackageBase, usernames: list[str] +) -> None: """ Add comaintainers to `pkgbase`. @@ -216,7 +229,6 @@ def rotate_comaintainers(pkgbase: PackageBase) -> None: :param pkgbase: PackageBase instance """ - comaintainers = pkgbase.comaintainers.order_by( - PackageComaintainer.Priority.asc()) + comaintainers = pkgbase.comaintainers.order_by(PackageComaintainer.Priority.asc()) for i, comaint in enumerate(comaintainers): comaint.Priority = i + 1 diff --git a/aurweb/pkgbase/validate.py b/aurweb/pkgbase/validate.py index baefc415..3c50e578 100644 --- a/aurweb/pkgbase/validate.py +++ b/aurweb/pkgbase/validate.py @@ -5,9 +5,13 @@ from aurweb.exceptions import ValidationError from aurweb.models import PackageBase -def request(pkgbase: PackageBase, - type: str, comments: str, merge_into: str, - context: dict[str, Any]) -> None: +def request( + pkgbase: PackageBase, + type: str, + comments: str, + merge_into: str, + context: dict[str, Any], +) -> None: if not comments: raise ValidationError(["The comment field must not be empty."]) @@ -15,21 +19,16 @@ def request(pkgbase: PackageBase, # Perform merge-related checks. if not merge_into: # TODO: This error needs to be translated. - raise ValidationError( - ['The "Merge into" field must not be empty.']) + raise ValidationError(['The "Merge into" field must not be empty.']) - target = db.query(PackageBase).filter( - PackageBase.Name == merge_into - ).first() + target = db.query(PackageBase).filter(PackageBase.Name == merge_into).first() if not target: # TODO: This error needs to be translated. - raise ValidationError([ - "The package base you want to merge into does not exist." - ]) + raise ValidationError( + ["The package base you want to merge into does not exist."] + ) db.refresh(target) if target.ID == pkgbase.ID: # TODO: This error needs to be translated. - raise ValidationError([ - "You cannot merge a package base into itself." - ]) + raise ValidationError(["You cannot merge a package base into itself."]) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index 227d46ed..0bbea4be 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -19,8 +19,9 @@ def instrumentator(): # Their license is included in LICENSES/starlette_exporter. # The code has been modified to remove child route checks # (since we don't have any) and to stay within an 80-width limit. -def get_matching_route_path(scope: dict[Any, Any], routes: list[Route], - route_name: Optional[str] = None) -> str: +def get_matching_route_path( + scope: dict[Any, Any], routes: list[Route], route_name: Optional[str] = None +) -> str: """ Find a matching route and return its original path string @@ -34,7 +35,7 @@ def get_matching_route_path(scope: dict[Any, Any], routes: list[Route], if match == Match.FULL: route_name = route.path - ''' + """ # This path exists in the original function's code, but we # don't need it (currently), so it's been removed to avoid # useless test coverage. @@ -47,7 +48,7 @@ def get_matching_route_path(scope: dict[Any, Any], routes: list[Route], route_name = None else: route_name += child_route_name - ''' + """ return route_name elif match == Match.PARTIAL and route_name is None: @@ -55,9 +56,11 @@ def get_matching_route_path(scope: dict[Any, Any], routes: list[Route], def http_requests_total() -> Callable[[Info], None]: - metric = Counter("http_requests_total", - "Number of HTTP requests.", - labelnames=("method", "path", "status")) + metric = Counter( + "http_requests_total", + "Number of HTTP requests.", + labelnames=("method", "path", "status"), + ) def instrumentation(info: Info) -> None: if info.request.method.lower() in ("head", "options"): # pragma: no cover @@ -79,13 +82,13 @@ def http_requests_total() -> Callable[[Info], None]: if hasattr(app, "root_path"): app_root_path = getattr(app, "root_path") if root_path.startswith(app_root_path): - root_path = root_path[len(app_root_path):] + root_path = root_path[len(app_root_path) :] base_scope = { "type": scope.get("type"), "path": root_path + scope.get("path"), "path_params": scope.get("path_params", {}), - "method": scope.get("method") + "method": scope.get("method"), } method = scope.get("method") @@ -102,7 +105,8 @@ def http_api_requests_total() -> Callable[[Info], None]: metric = Counter( "http_api_requests", "Number of times an RPC API type has been requested.", - labelnames=("type", "status")) + labelnames=("type", "status"), + ) def instrumentation(info: Info) -> None: if info.request.method.lower() in ("head", "options"): # pragma: no cover diff --git a/aurweb/ratelimit.py b/aurweb/ratelimit.py index 86063f5d..cb08cdf5 100644 --- a/aurweb/ratelimit.py +++ b/aurweb/ratelimit.py @@ -38,8 +38,7 @@ def _update_ratelimit_db(request: Request): now = time.utcnow() time_to_delete = now - window_length - records = db.query(ApiRateLimit).filter( - ApiRateLimit.WindowStart < time_to_delete) + records = db.query(ApiRateLimit).filter(ApiRateLimit.WindowStart < time_to_delete) with db.begin(): db.delete_all(records) @@ -47,9 +46,7 @@ def _update_ratelimit_db(request: Request): record = db.query(ApiRateLimit, ApiRateLimit.IP == host).first() with db.begin(): if not record: - record = db.create(ApiRateLimit, - WindowStart=now, - IP=host, Requests=1) + record = db.create(ApiRateLimit, WindowStart=now, IP=host, Requests=1) else: record.Requests += 1 @@ -58,7 +55,7 @@ def _update_ratelimit_db(request: Request): def update_ratelimit(request: Request, pipeline: Pipeline): - """ Update the ratelimit stored in Redis or the database depending + """Update the ratelimit stored in Redis or the database depending on AUR_CONFIG's [options] cache setting. This Redis-capable function is slightly different than most. If Redis @@ -75,7 +72,7 @@ def update_ratelimit(request: Request, pipeline: Pipeline): def check_ratelimit(request: Request): - """ Increment and check to see if request has exceeded their rate limit. + """Increment and check to see if request has exceeded their rate limit. :param request: FastAPI request :returns: True if the request host has exceeded the rate limit else False diff --git a/aurweb/redis.py b/aurweb/redis.py index e29b8e37..af179b9b 100644 --- a/aurweb/redis.py +++ b/aurweb/redis.py @@ -1,9 +1,7 @@ import fakeredis - from redis import ConnectionPool, Redis import aurweb.config - from aurweb import logging logger = logging.get_logger(__name__) @@ -11,7 +9,7 @@ pool = None class FakeConnectionPool: - """ A fake ConnectionPool class which holds an internal reference + """A fake ConnectionPool class which holds an internal reference to a fakeredis handle. We normally deal with Redis by keeping its ConnectionPool globally diff --git a/aurweb/routers/__init__.py b/aurweb/routers/__init__.py index da79e38f..f77bce4f 100644 --- a/aurweb/routers/__init__.py +++ b/aurweb/routers/__init__.py @@ -3,7 +3,18 @@ API routers for FastAPI. See https://fastapi.tiangolo.com/tutorial/bigger-applications/ """ -from . import accounts, auth, html, packages, pkgbase, requests, rpc, rss, sso, trusted_user +from . import ( + accounts, + auth, + html, + packages, + pkgbase, + requests, + rpc, + rss, + sso, + trusted_user, +) """ aurweb application routes. This constant can be any iterable diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index dcac72b0..db05955a 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -1,6 +1,5 @@ import copy import typing - from http import HTTPStatus from typing import Any @@ -9,7 +8,6 @@ from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, or_ import aurweb.config - from aurweb import cookies, db, l10n, logging, models, util from aurweb.auth import account_type_required, requires_auth, requires_guest from aurweb.captcha import get_captcha_salts @@ -37,21 +35,23 @@ async def passreset(request: Request): @router.post("/passreset", response_class=HTMLResponse) @handle_form_exceptions @requires_guest -async def passreset_post(request: Request, - user: str = Form(...), - resetkey: str = Form(default=None), - password: str = Form(default=None), - confirm: str = Form(default=None)): +async def passreset_post( + request: Request, + user: str = Form(...), + resetkey: str = Form(default=None), + password: str = Form(default=None), + confirm: str = Form(default=None), +): context = await make_variable_context(request, "Password Reset") # The user parameter being required, we can match against criteria = or_(models.User.Username == user, models.User.Email == user) - db_user = db.query(models.User, - and_(criteria, models.User.Suspended == 0)).first() + db_user = db.query(models.User, and_(criteria, models.User.Suspended == 0)).first() if db_user is None: context["errors"] = ["Invalid e-mail."] - return render_template(request, "passreset.html", context, - status_code=HTTPStatus.NOT_FOUND) + return render_template( + request, "passreset.html", context, status_code=HTTPStatus.NOT_FOUND + ) db.refresh(db_user) if resetkey: @@ -59,29 +59,34 @@ async def passreset_post(request: Request, if not db_user.ResetKey or resetkey != db_user.ResetKey: context["errors"] = ["Invalid e-mail."] - return render_template(request, "passreset.html", context, - status_code=HTTPStatus.NOT_FOUND) + return render_template( + request, "passreset.html", context, status_code=HTTPStatus.NOT_FOUND + ) if not user or not password: context["errors"] = ["Missing a required field."] - return render_template(request, "passreset.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "passreset.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if password != confirm: # If the provided password does not match the provided confirm. context["errors"] = ["Password fields do not match."] - return render_template(request, "passreset.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "passreset.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if len(password) < models.User.minimum_passwd_length(): # Translate the error here, which simplifies error output # in the jinja2 template. _ = get_translator_for_request(request) - context["errors"] = [_( - "Your password must be at least %s characters.") % ( - str(models.User.minimum_passwd_length()))] - return render_template(request, "passreset.html", context, - status_code=HTTPStatus.BAD_REQUEST) + context["errors"] = [ + _("Your password must be at least %s characters.") + % (str(models.User.minimum_passwd_length())) + ] + return render_template( + request, "passreset.html", context, status_code=HTTPStatus.BAD_REQUEST + ) # We got to this point; everything matched up. Update the password # and remove the ResetKey. @@ -92,8 +97,9 @@ async def passreset_post(request: Request, db_user.update_password(password) # Render ?step=complete. - return RedirectResponse(url="/passreset?step=complete", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse( + url="/passreset?step=complete", status_code=HTTPStatus.SEE_OTHER + ) # If we got here, we continue with issuing a resetkey for the user. resetkey = generate_resetkey() @@ -103,13 +109,13 @@ async def passreset_post(request: Request, ResetKeyNotification(db_user.ID).send() # Render ?step=confirm. - return RedirectResponse(url="/passreset?step=confirm", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse( + url="/passreset?step=confirm", status_code=HTTPStatus.SEE_OTHER + ) -def process_account_form(request: Request, user: models.User, - args: dict[str, Any]): - """ Process an account form. All fields are optional and only checks +def process_account_form(request: Request, user: models.User, args: dict[str, Any]): + """Process an account form. All fields are optional and only checks requirements in the case they are present. ``` @@ -146,7 +152,7 @@ def process_account_form(request: Request, user: models.User, validate.username_in_use, validate.email_in_use, validate.invalid_account_type, - validate.invalid_captcha + validate.invalid_captcha, ] try: @@ -158,11 +164,10 @@ def process_account_form(request: Request, user: models.User, return (True, []) -def make_account_form_context(context: dict, - request: Request, - user: models.User, - args: dict): - """ Modify a FastAPI context and add attributes for the account form. +def make_account_form_context( + context: dict, request: Request, user: models.User, args: dict +): + """Modify a FastAPI context and add attributes for the account form. :param context: FastAPI context :param request: FastAPI request @@ -173,15 +178,17 @@ def make_account_form_context(context: dict, # Do not modify the original context. context = copy.copy(context) - context["account_types"] = list(filter( - lambda e: request.user.AccountTypeID >= e[0], - [ - (at.USER_ID, f"Normal {at.USER}"), - (at.TRUSTED_USER_ID, at.TRUSTED_USER), - (at.DEVELOPER_ID, at.DEVELOPER), - (at.TRUSTED_USER_AND_DEV_ID, at.TRUSTED_USER_AND_DEV) - ] - )) + context["account_types"] = list( + filter( + lambda e: request.user.AccountTypeID >= e[0], + [ + (at.USER_ID, f"Normal {at.USER}"), + (at.TRUSTED_USER_ID, at.TRUSTED_USER), + (at.DEVELOPER_ID, at.DEVELOPER), + (at.TRUSTED_USER_AND_DEV_ID, at.TRUSTED_USER_AND_DEV), + ], + ) + ) if request.user.is_authenticated(): context["username"] = args.get("U", user.Username) @@ -229,24 +236,24 @@ def make_account_form_context(context: dict, @router.get("/register", response_class=HTMLResponse) @requires_guest -async def account_register(request: Request, - U: str = Form(default=str()), # Username - E: str = Form(default=str()), # Email - H: str = Form(default=False), # Hide Email - BE: str = Form(default=None), # Backup Email - R: str = Form(default=None), # Real Name - HP: str = Form(default=None), # Homepage - I: str = Form(default=None), # IRC Nick - K: str = Form(default=None), # PGP Key FP - L: str = Form(default=aurweb.config.get( - "options", "default_lang")), - TZ: str = Form(default=aurweb.config.get( - "options", "default_timezone")), - PK: str = Form(default=None), - CN: bool = Form(default=False), # Comment Notify - CU: bool = Form(default=False), # Update Notify - CO: bool = Form(default=False), # Owner Notify - captcha: str = Form(default=str())): +async def account_register( + request: Request, + U: str = Form(default=str()), # Username + E: str = Form(default=str()), # Email + H: str = Form(default=False), # Hide Email + BE: str = Form(default=None), # Backup Email + R: str = Form(default=None), # Real Name + HP: str = Form(default=None), # Homepage + I: str = Form(default=None), # IRC Nick + K: str = Form(default=None), # PGP Key FP + L: str = Form(default=aurweb.config.get("options", "default_lang")), + TZ: str = Form(default=aurweb.config.get("options", "default_timezone")), + PK: str = Form(default=None), + CN: bool = Form(default=False), # Comment Notify + CU: bool = Form(default=False), # Update Notify + CO: bool = Form(default=False), # Owner Notify + captcha: str = Form(default=str()), +): context = await make_variable_context(request, "Register") context["captcha_salt"] = get_captcha_salts()[0] context = make_account_form_context(context, request, None, dict()) @@ -256,32 +263,32 @@ async def account_register(request: Request, @router.post("/register", response_class=HTMLResponse) @handle_form_exceptions @requires_guest -async def account_register_post(request: Request, - U: str = Form(default=str()), # Username - E: str = Form(default=str()), # Email - H: str = Form(default=False), # Hide Email - BE: str = Form(default=None), # Backup Email - R: str = Form(default=''), # Real Name - HP: str = Form(default=None), # Homepage - I: str = Form(default=None), # IRC Nick - K: str = Form(default=None), # PGP Key - L: str = Form(default=aurweb.config.get( - "options", "default_lang")), - TZ: str = Form(default=aurweb.config.get( - "options", "default_timezone")), - PK: str = Form(default=str()), # SSH PubKey - CN: bool = Form(default=False), - UN: bool = Form(default=False), - ON: bool = Form(default=False), - captcha: str = Form(default=None), - captcha_salt: str = Form(...)): +async def account_register_post( + request: Request, + U: str = Form(default=str()), # Username + E: str = Form(default=str()), # Email + H: str = Form(default=False), # Hide Email + BE: str = Form(default=None), # Backup Email + R: str = Form(default=""), # Real Name + HP: str = Form(default=None), # Homepage + I: str = Form(default=None), # IRC Nick + K: str = Form(default=None), # PGP Key + L: str = Form(default=aurweb.config.get("options", "default_lang")), + TZ: str = Form(default=aurweb.config.get("options", "default_timezone")), + PK: str = Form(default=str()), # SSH PubKey + CN: bool = Form(default=False), + UN: bool = Form(default=False), + ON: bool = Form(default=False), + captcha: str = Form(default=None), + captcha_salt: str = Form(...), +): context = await make_variable_context(request, "Register") args = dict(await request.form()) args["K"] = args.get("K", str()).replace(" ", "") K = args.get("K") # Force "H" into a boolean. - args["H"] = H = (args.get("H", str()) == "on") + args["H"] = H = args.get("H", str()) == "on" context = make_account_form_context(context, request, None, args) ok, errors = process_account_form(request, request.user, args) @@ -289,30 +296,45 @@ async def account_register_post(request: Request, # If the field values given do not meet the requirements, # return HTTP 400 with an error. context["errors"] = errors - return render_template(request, "register.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "register.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if not captcha: context["errors"] = ["The CAPTCHA is missing."] - return render_template(request, "register.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "register.html", context, status_code=HTTPStatus.BAD_REQUEST + ) # Create a user with no password with a resetkey, then send # an email off about it. resetkey = generate_resetkey() # By default, we grab the User account type to associate with. - atype = db.query(models.AccountType, - models.AccountType.AccountType == "User").first() + atype = db.query( + models.AccountType, models.AccountType.AccountType == "User" + ).first() # Create a user given all parameters available. with db.begin(): - user = db.create(models.User, Username=U, - Email=E, HideEmail=H, BackupEmail=BE, - RealName=R, Homepage=HP, IRCNick=I, PGPKey=K, - LangPreference=L, Timezone=TZ, CommentNotify=CN, - UpdateNotify=UN, OwnershipNotify=ON, - ResetKey=resetkey, AccountType=atype) + user = db.create( + models.User, + Username=U, + Email=E, + HideEmail=H, + BackupEmail=BE, + RealName=R, + Homepage=HP, + IRCNick=I, + PGPKey=K, + LangPreference=L, + Timezone=TZ, + CommentNotify=CN, + UpdateNotify=UN, + OwnershipNotify=ON, + ResetKey=resetkey, + AccountType=atype, + ) # If a PK was given and either one does not exist or the given # PK mismatches the existing user's SSHPubKey.PubKey. @@ -323,8 +345,9 @@ async def account_register_post(request: Request, pk = " ".join(k) fprint = get_fingerprint(pk) with db.begin(): - db.create(models.SSHPubKey, UserID=user.ID, - PubKey=pk, Fingerprint=fprint) + db.create( + models.SSHPubKey, UserID=user.ID, PubKey=pk, Fingerprint=fprint + ) # Send a reset key notification to the new user. WelcomeNotification(user.ID).send() @@ -334,8 +357,9 @@ async def account_register_post(request: Request, return render_template(request, "register.html", context) -def cannot_edit(request: Request, user: models.User) \ - -> typing.Optional[RedirectResponse]: +def cannot_edit( + request: Request, user: models.User +) -> typing.Optional[RedirectResponse]: """ Decide if `request.user` cannot edit `user`. @@ -373,31 +397,30 @@ async def account_edit(request: Request, username: str): @router.post("/account/{username}/edit", response_class=HTMLResponse) @handle_form_exceptions @requires_auth -async def account_edit_post(request: Request, - username: str, - U: str = Form(default=str()), # Username - J: bool = Form(default=False), - E: str = Form(default=str()), # Email - H: str = Form(default=False), # Hide Email - BE: str = Form(default=None), # Backup Email - R: str = Form(default=None), # Real Name - HP: str = Form(default=None), # Homepage - I: str = Form(default=None), # IRC Nick - K: str = Form(default=None), # PGP Key - L: str = Form(aurweb.config.get( - "options", "default_lang")), - TZ: str = Form(aurweb.config.get( - "options", "default_timezone")), - P: str = Form(default=str()), # New Password - C: str = Form(default=None), # Password Confirm - PK: str = Form(default=None), # PubKey - CN: bool = Form(default=False), # Comment Notify - UN: bool = Form(default=False), # Update Notify - ON: bool = Form(default=False), # Owner Notify - T: int = Form(default=None), - passwd: str = Form(default=str())): - user = db.query(models.User).filter( - models.User.Username == username).first() +async def account_edit_post( + request: Request, + username: str, + U: str = Form(default=str()), # Username + J: bool = Form(default=False), + E: str = Form(default=str()), # Email + H: str = Form(default=False), # Hide Email + BE: str = Form(default=None), # Backup Email + R: str = Form(default=None), # Real Name + HP: str = Form(default=None), # Homepage + I: str = Form(default=None), # IRC Nick + K: str = Form(default=None), # PGP Key + L: str = Form(aurweb.config.get("options", "default_lang")), + TZ: str = Form(aurweb.config.get("options", "default_timezone")), + P: str = Form(default=str()), # New Password + C: str = Form(default=None), # Password Confirm + PK: str = Form(default=None), # PubKey + CN: bool = Form(default=False), # Comment Notify + UN: bool = Form(default=False), # Update Notify + ON: bool = Form(default=False), # Owner Notify + T: int = Form(default=None), + passwd: str = Form(default=str()), +): + user = db.query(models.User).filter(models.User.Username == username).first() response = cannot_edit(request, user) if response: return response @@ -416,13 +439,15 @@ async def account_edit_post(request: Request, if not passwd: context["errors"] = ["Invalid password."] - return render_template(request, "account/edit.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "account/edit.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if not ok: context["errors"] = errors - return render_template(request, "account/edit.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "account/edit.html", context, status_code=HTTPStatus.BAD_REQUEST + ) updates = [ update.simple, @@ -430,7 +455,7 @@ async def account_edit_post(request: Request, update.timezone, update.ssh_pubkey, update.account_type, - update.password + update.password, ] for f in updates: @@ -441,18 +466,17 @@ async def account_edit_post(request: Request, # Update cookies with requests, in case they were changed. response = render_template(request, "account/edit.html", context) - return cookies.update_response_cookies(request, response, - aurtz=TZ, aurlang=L) + return cookies.update_response_cookies(request, response, aurtz=TZ, aurlang=L) @router.get("/account/{username}") async def account(request: Request, username: str): _ = l10n.get_translator_for_request(request) - context = await make_variable_context( - request, _("Account") + " " + username) + context = await make_variable_context(request, _("Account") + " " + username) if not request.user.is_authenticated(): - return render_template(request, "account/show.html", context, - status_code=HTTPStatus.UNAUTHORIZED) + return render_template( + request, "account/show.html", context, status_code=HTTPStatus.UNAUTHORIZED + ) # Get related User record, if possible. user = get_user_by_name(username) @@ -460,11 +484,10 @@ async def account(request: Request, username: str): # Format PGPKey for display with a space between each 4 characters. k = user.PGPKey or str() - context["pgp_key"] = " ".join([k[i:i + 4] for i in range(0, len(k), 4)]) + context["pgp_key"] = " ".join([k[i : i + 4] for i in range(0, len(k), 4)]) login_ts = None - session = db.query(models.Session).filter( - models.Session.UsersID == user.ID).first() + session = db.query(models.Session).filter(models.Session.UsersID == user.ID).first() if session: login_ts = user.session.LastUpdateTS context["login_ts"] = login_ts @@ -480,15 +503,14 @@ async def account_comments(request: Request, username: str): context = make_context(request, "Accounts") context["username"] = username context["comments"] = user.package_comments.order_by( - models.PackageComment.CommentTS.desc()) + models.PackageComment.CommentTS.desc() + ) return render_template(request, "account/comments.html", context) @router.get("/accounts") @requires_auth -@account_type_required({at.TRUSTED_USER, - at.DEVELOPER, - at.TRUSTED_USER_AND_DEV}) +@account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) async def accounts(request: Request): context = make_context(request, "Accounts") return render_template(request, "account/search.html", context) @@ -497,19 +519,19 @@ async def accounts(request: Request): @router.post("/accounts") @handle_form_exceptions @requires_auth -@account_type_required({at.TRUSTED_USER, - at.DEVELOPER, - at.TRUSTED_USER_AND_DEV}) -async def accounts_post(request: Request, - O: int = Form(default=0), # Offset - SB: str = Form(default=str()), # Sort By - U: str = Form(default=str()), # Username - T: str = Form(default=str()), # Account Type - S: bool = Form(default=False), # Suspended - E: str = Form(default=str()), # Email - R: str = Form(default=str()), # Real Name - I: str = Form(default=str()), # IRC Nick - K: str = Form(default=str())): # PGP Key +@account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) +async def accounts_post( + request: Request, + O: int = Form(default=0), # Offset + SB: str = Form(default=str()), # Sort By + U: str = Form(default=str()), # Username + T: str = Form(default=str()), # Account Type + S: bool = Form(default=False), # Suspended + E: str = Form(default=str()), # Email + R: str = Form(default=str()), # Real Name + I: str = Form(default=str()), # IRC Nick + K: str = Form(default=str()), +): # PGP Key context = await make_variable_context(request, "Accounts") context["pp"] = pp = 50 # Hits per page. @@ -534,7 +556,7 @@ async def accounts_post(request: Request, "u": at.USER_ID, "t": at.TRUSTED_USER_ID, "d": at.DEVELOPER_ID, - "td": at.TRUSTED_USER_AND_DEV_ID + "td": at.TRUSTED_USER_AND_DEV_ID, } account_type_id = account_types.get(T, None) @@ -545,7 +567,8 @@ async def accounts_post(request: Request, # Populate this list with any additional statements to # be ANDed together. statements = [ - v for k, v in [ + v + for k, v in [ (account_type_id is not None, models.AccountType.ID == account_type_id), (bool(U), models.User.Username.like(f"%{U}%")), (bool(S), models.User.Suspended == S), @@ -553,7 +576,8 @@ async def accounts_post(request: Request, (bool(R), models.User.RealName.like(f"%{R}%")), (bool(I), models.User.IRCNick.like(f"%{I}%")), (bool(K), models.User.PGPKey.like(f"%{K}%")), - ] if k + ] + if k ] # Filter the query by coe-mbining all statements added above into @@ -571,9 +595,7 @@ async def accounts_post(request: Request, return render_template(request, "account/index.html", context) -def render_terms_of_service(request: Request, - context: dict, - terms: typing.Iterable): +def render_terms_of_service(request: Request, context: dict, terms: typing.Iterable): if not terms: return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) context["unaccepted_terms"] = terms @@ -585,14 +607,21 @@ def render_terms_of_service(request: Request, async def terms_of_service(request: Request): # Query the database for terms that were previously accepted, # but now have a bumped Revision that needs to be accepted. - diffs = db.query(models.Term).join(models.AcceptedTerm).filter( - models.AcceptedTerm.Revision < models.Term.Revision).all() + diffs = ( + db.query(models.Term) + .join(models.AcceptedTerm) + .filter(models.AcceptedTerm.Revision < models.Term.Revision) + .all() + ) # Query the database for any terms that have not yet been accepted. - unaccepted = db.query(models.Term).filter( - ~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID))).all() + unaccepted = ( + db.query(models.Term) + .filter(~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID))) + .all() + ) - for record in (diffs + unaccepted): + for record in diffs + unaccepted: db.refresh(record) # Translate the 'Terms of Service' part of our page title. @@ -607,16 +636,22 @@ async def terms_of_service(request: Request): @router.post("/tos") @handle_form_exceptions @requires_auth -async def terms_of_service_post(request: Request, - accept: bool = Form(default=False)): +async def terms_of_service_post(request: Request, accept: bool = Form(default=False)): # Query the database for terms that were previously accepted, # but now have a bumped Revision that needs to be accepted. - diffs = db.query(models.Term).join(models.AcceptedTerm).filter( - models.AcceptedTerm.Revision < models.Term.Revision).all() + diffs = ( + db.query(models.Term) + .join(models.AcceptedTerm) + .filter(models.AcceptedTerm.Revision < models.Term.Revision) + .all() + ) # Query the database for any terms that have not yet been accepted. - unaccepted = db.query(models.Term).filter( - ~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID))).all() + unaccepted = ( + db.query(models.Term) + .filter(~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID))) + .all() + ) if not accept: # Translate the 'Terms of Service' part of our page title. @@ -628,7 +663,8 @@ async def terms_of_service_post(request: Request, # them instead of reiterating the process in terms_of_service. accept_needed = sorted(unaccepted + diffs) return render_terms_of_service( - request, context, util.apply_all(accept_needed, db.refresh)) + request, context, util.apply_all(accept_needed, db.refresh) + ) with db.begin(): # For each term we found, query for the matching accepted term @@ -636,13 +672,18 @@ async def terms_of_service_post(request: Request, for term in diffs: db.refresh(term) accepted_term = request.user.accepted_terms.filter( - models.AcceptedTerm.TermsID == term.ID).first() + models.AcceptedTerm.TermsID == term.ID + ).first() accepted_term.Revision = term.Revision # For each term that was never accepted, accept it! for term in unaccepted: db.refresh(term) - db.create(models.AcceptedTerm, User=request.user, - Term=term, Revision=term.Revision) + db.create( + models.AcceptedTerm, + User=request.user, + Term=term, + Revision=term.Revision, + ) return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 50cec419..3f94952e 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -5,7 +5,6 @@ from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import or_ import aurweb.config - from aurweb import cookies, db from aurweb.auth import requires_auth, requires_guest from aurweb.exceptions import handle_form_exceptions @@ -17,7 +16,7 @@ router = APIRouter() async def login_template(request: Request, next: str, errors: list = None): - """ Provide login-specific template context to render_template. """ + """Provide login-specific template context to render_template.""" context = await make_variable_context(request, "Login", next) context["errors"] = errors context["url_base"] = f"{request.url.scheme}://{request.url.netloc}" @@ -32,55 +31,73 @@ async def login_get(request: Request, next: str = "/"): @router.post("/login", response_class=HTMLResponse) @handle_form_exceptions @requires_guest -async def login_post(request: Request, - next: str = Form(...), - user: str = Form(default=str()), - passwd: str = Form(default=str()), - remember_me: bool = Form(default=False)): +async def login_post( + request: Request, + next: str = Form(...), + user: str = Form(default=str()), + passwd: str = Form(default=str()), + remember_me: bool = Form(default=False), +): # TODO: Once the Origin header gets broader adoption, this code can be # slightly simplified to use it. login_path = aurweb.config.get("options", "aur_location") + "/login" referer = request.headers.get("Referer") if not referer or not referer.startswith(login_path): _ = get_translator_for_request(request) - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, - detail=_("Bad Referer header.")) + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, detail=_("Bad Referer header.") + ) with db.begin(): - user = db.query(User).filter( - or_(User.Username == user, User.Email == user) - ).first() + user = ( + db.query(User) + .filter(or_(User.Username == user, User.Email == user)) + .first() + ) if not user: - return await login_template(request, next, - errors=["Bad username or password."]) + return await login_template(request, next, errors=["Bad username or password."]) if user.Suspended: - return await login_template(request, next, - errors=["Account Suspended"]) + return await login_template(request, next, errors=["Account Suspended"]) cookie_timeout = cookies.timeout(remember_me) sid = user.login(request, passwd, cookie_timeout) if not sid: - return await login_template(request, next, - errors=["Bad username or password."]) + return await login_template(request, next, errors=["Bad username or password."]) - response = RedirectResponse(url=next, - status_code=HTTPStatus.SEE_OTHER) + response = RedirectResponse(url=next, status_code=HTTPStatus.SEE_OTHER) secure = aurweb.config.getboolean("options", "disable_http_login") - response.set_cookie("AURSID", sid, max_age=cookie_timeout, - secure=secure, httponly=secure, - samesite=cookies.samesite()) - response.set_cookie("AURTZ", user.Timezone, - secure=secure, httponly=secure, - samesite=cookies.samesite()) - response.set_cookie("AURLANG", user.LangPreference, - secure=secure, httponly=secure, - samesite=cookies.samesite()) - response.set_cookie("AURREMEMBER", remember_me, - secure=secure, httponly=secure, - samesite=cookies.samesite()) + response.set_cookie( + "AURSID", + sid, + max_age=cookie_timeout, + secure=secure, + httponly=secure, + samesite=cookies.samesite(), + ) + response.set_cookie( + "AURTZ", + user.Timezone, + secure=secure, + httponly=secure, + samesite=cookies.samesite(), + ) + response.set_cookie( + "AURLANG", + user.LangPreference, + secure=secure, + httponly=secure, + samesite=cookies.samesite(), + ) + response.set_cookie( + "AURREMEMBER", + remember_me, + secure=secure, + httponly=secure, + samesite=cookies.samesite(), + ) return response @@ -93,8 +110,7 @@ async def logout(request: Request, next: str = Form(default="/")): # Use 303 since we may be handling a post request, that'll get it # to redirect to a get request. - response = RedirectResponse(url=next, - status_code=HTTPStatus.SEE_OTHER) + response = RedirectResponse(url=next, status_code=HTTPStatus.SEE_OTHER) response.delete_cookie("AURSID") response.delete_cookie("AURTZ") return response diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index d31a32c7..2148d535 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -2,17 +2,20 @@ decorators in some way; more complex routes should be defined in their own modules and imported here. """ import os - from http import HTTPStatus from fastapi import APIRouter, Form, HTTPException, Request, Response from fastapi.responses import HTMLResponse, RedirectResponse -from prometheus_client import CONTENT_TYPE_LATEST, CollectorRegistry, generate_latest, multiprocess +from prometheus_client import ( + CONTENT_TYPE_LATEST, + CollectorRegistry, + generate_latest, + multiprocess, +) from sqlalchemy import and_, case, or_ import aurweb.config import aurweb.models.package_request - from aurweb import cookies, db, logging, models, time, util from aurweb.cache import db_count_cache from aurweb.exceptions import handle_form_exceptions @@ -27,17 +30,19 @@ router = APIRouter() @router.get("/favicon.ico") async def favicon(request: Request): - """ Some browsers attempt to find a website's favicon via root uri at - /favicon.ico, so provide a redirection here to our static icon. """ + """Some browsers attempt to find a website's favicon via root uri at + /favicon.ico, so provide a redirection here to our static icon.""" return RedirectResponse("/static/images/favicon.ico") @router.post("/language", response_class=RedirectResponse) @handle_form_exceptions -async def language(request: Request, - set_lang: str = Form(...), - next: str = Form(...), - q: str = Form(default=None)): +async def language( + request: Request, + set_lang: str = Form(...), + next: str = Form(...), + q: str = Form(default=None), +): """ A POST route used to set a session's language. @@ -45,7 +50,7 @@ async def language(request: Request, setting the language on any page, we want to preserve query parameters across the redirect. """ - if next[0] != '/': + if next[0] != "/": return HTMLResponse(b"Invalid 'next' parameter.", status_code=400) query_string = "?" + q if q else str() @@ -56,20 +61,21 @@ async def language(request: Request, request.user.LangPreference = set_lang # In any case, set the response's AURLANG cookie that never expires. - response = RedirectResponse(url=f"{next}{query_string}", - status_code=HTTPStatus.SEE_OTHER) + response = RedirectResponse( + url=f"{next}{query_string}", status_code=HTTPStatus.SEE_OTHER + ) secure = aurweb.config.getboolean("options", "disable_http_login") - response.set_cookie("AURLANG", set_lang, - secure=secure, httponly=secure, - samesite=cookies.samesite()) + response.set_cookie( + "AURLANG", set_lang, secure=secure, httponly=secure, samesite=cookies.samesite() + ) return response @router.get("/", response_class=HTMLResponse) async def index(request: Request): - """ Homepage route. """ + """Homepage route.""" context = make_context(request, "Home") - context['ssh_fingerprints'] = util.get_ssh_fingerprints() + context["ssh_fingerprints"] = util.get_ssh_fingerprints() bases = db.query(models.PackageBase) @@ -79,24 +85,33 @@ async def index(request: Request): # Package statistics. query = bases.filter(models.PackageBase.PackagerUID.isnot(None)) context["package_count"] = await db_count_cache( - redis, "package_count", query, expire=cache_expire) + redis, "package_count", query, expire=cache_expire + ) query = bases.filter( - and_(models.PackageBase.MaintainerUID.is_(None), - models.PackageBase.PackagerUID.isnot(None)) + and_( + models.PackageBase.MaintainerUID.is_(None), + models.PackageBase.PackagerUID.isnot(None), + ) ) context["orphan_count"] = await db_count_cache( - redis, "orphan_count", query, expire=cache_expire) + redis, "orphan_count", query, expire=cache_expire + ) query = db.query(models.User) context["user_count"] = await db_count_cache( - redis, "user_count", query, expire=cache_expire) + redis, "user_count", query, expire=cache_expire + ) query = query.filter( - or_(models.User.AccountTypeID == TRUSTED_USER_ID, - models.User.AccountTypeID == TRUSTED_USER_AND_DEV_ID)) + or_( + models.User.AccountTypeID == TRUSTED_USER_ID, + models.User.AccountTypeID == TRUSTED_USER_AND_DEV_ID, + ) + ) context["trusted_user_count"] = await db_count_cache( - redis, "trusted_user_count", query, expire=cache_expire) + redis, "trusted_user_count", query, expire=cache_expire + ) # Current timestamp. now = time.utcnow() @@ -106,31 +121,40 @@ async def index(request: Request): one_hour = 3600 updated = bases.filter( - and_(models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS >= one_hour, - models.PackageBase.PackagerUID.isnot(None)) + and_( + models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS >= one_hour, + models.PackageBase.PackagerUID.isnot(None), + ) ) query = bases.filter( - and_(models.PackageBase.SubmittedTS >= seven_days_ago, - models.PackageBase.PackagerUID.isnot(None)) + and_( + models.PackageBase.SubmittedTS >= seven_days_ago, + models.PackageBase.PackagerUID.isnot(None), + ) ) context["seven_days_old_added"] = await db_count_cache( - redis, "seven_days_old_added", query, expire=cache_expire) + redis, "seven_days_old_added", query, expire=cache_expire + ) query = updated.filter(models.PackageBase.ModifiedTS >= seven_days_ago) context["seven_days_old_updated"] = await db_count_cache( - redis, "seven_days_old_updated", query, expire=cache_expire) + redis, "seven_days_old_updated", query, expire=cache_expire + ) year = seven_days * 52 # Fifty two weeks worth: one year. year_ago = now - year query = updated.filter(models.PackageBase.ModifiedTS >= year_ago) context["year_old_updated"] = await db_count_cache( - redis, "year_old_updated", query, expire=cache_expire) + redis, "year_old_updated", query, expire=cache_expire + ) query = bases.filter( - models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600) + models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600 + ) context["never_updated"] = await db_count_cache( - redis, "never_updated", query, expire=cache_expire) + redis, "never_updated", query, expire=cache_expire + ) # Get the 15 most recently updated packages. context["package_updates"] = updated_packages(15, cache_expire) @@ -140,78 +164,92 @@ async def index(request: Request): # the dashboard display. packages = db.query(models.Package).join(models.PackageBase) - maintained = packages.join( - models.PackageComaintainer, - models.PackageComaintainer.PackageBaseID == models.PackageBase.ID, - isouter=True - ).join( - models.User, - or_(models.PackageBase.MaintainerUID == models.User.ID, - models.PackageComaintainer.UsersID == models.User.ID) - ).filter( - models.User.ID == request.user.ID + maintained = ( + packages.join( + models.PackageComaintainer, + models.PackageComaintainer.PackageBaseID == models.PackageBase.ID, + isouter=True, + ) + .join( + models.User, + or_( + models.PackageBase.MaintainerUID == models.User.ID, + models.PackageComaintainer.UsersID == models.User.ID, + ), + ) + .filter(models.User.ID == request.user.ID) ) # Packages maintained by the user that have been flagged. - context["flagged_packages"] = maintained.filter( - models.PackageBase.OutOfDateTS.isnot(None) - ).order_by( - models.PackageBase.ModifiedTS.desc(), models.Package.Name.asc() - ).limit(50).all() + context["flagged_packages"] = ( + maintained.filter(models.PackageBase.OutOfDateTS.isnot(None)) + .order_by(models.PackageBase.ModifiedTS.desc(), models.Package.Name.asc()) + .limit(50) + .all() + ) # Flagged packages that request.user has voted for. context["flagged_packages_voted"] = query_voted( - context.get("flagged_packages"), request.user) + context.get("flagged_packages"), request.user + ) # Flagged packages that request.user is being notified about. context["flagged_packages_notified"] = query_notified( - context.get("flagged_packages"), request.user) + context.get("flagged_packages"), request.user + ) - archive_time = aurweb.config.getint('options', 'request_archive_time') + archive_time = aurweb.config.getint("options", "request_archive_time") start = now - archive_time # Package requests created by request.user. - context["package_requests"] = request.user.package_requests.filter( - models.PackageRequest.RequestTS >= start - ).order_by( - # Order primarily by the Status column being PENDING_ID, - # and secondarily by RequestTS; both in descending order. - case([(models.PackageRequest.Status == PENDING_ID, 1)], - else_=0).desc(), - models.PackageRequest.RequestTS.desc() - ).limit(50).all() + context["package_requests"] = ( + request.user.package_requests.filter( + models.PackageRequest.RequestTS >= start + ) + .order_by( + # Order primarily by the Status column being PENDING_ID, + # and secondarily by RequestTS; both in descending order. + case([(models.PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), + models.PackageRequest.RequestTS.desc(), + ) + .limit(50) + .all() + ) # Packages that the request user maintains or comaintains. - context["packages"] = maintained.filter( - models.User.ID == models.PackageBase.MaintainerUID - ).order_by( - models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc() - ).limit(50).all() + context["packages"] = ( + maintained.filter(models.User.ID == models.PackageBase.MaintainerUID) + .order_by(models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc()) + .limit(50) + .all() + ) # Packages that request.user has voted for. - context["packages_voted"] = query_voted( - context.get("packages"), request.user) + context["packages_voted"] = query_voted(context.get("packages"), request.user) # Packages that request.user is being notified about. context["packages_notified"] = query_notified( - context.get("packages"), request.user) + context.get("packages"), request.user + ) # Any packages that the request user comaintains. - context["comaintained"] = packages.join( - models.PackageComaintainer - ).filter( - models.PackageComaintainer.UsersID == request.user.ID - ).order_by( - models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc() - ).limit(50).all() + context["comaintained"] = ( + packages.join(models.PackageComaintainer) + .filter(models.PackageComaintainer.UsersID == request.user.ID) + .order_by(models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc()) + .limit(50) + .all() + ) # Comaintained packages that request.user has voted for. context["comaintained_voted"] = query_voted( - context.get("comaintained"), request.user) + context.get("comaintained"), request.user + ) # Comaintained packages that request.user is being notified about. context["comaintained_notified"] = query_notified( - context.get("comaintained"), request.user) + context.get("comaintained"), request.user + ) return render_template(request, "index.html", context) @@ -232,16 +270,15 @@ async def archive_sha256(request: Request, archive: str): @router.get("/metrics") async def metrics(request: Request): if not os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): - return Response("Prometheus metrics are not enabled.", - status_code=HTTPStatus.SERVICE_UNAVAILABLE) + return Response( + "Prometheus metrics are not enabled.", + status_code=HTTPStatus.SERVICE_UNAVAILABLE, + ) registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) data = generate_latest(registry) - headers = { - "Content-Type": CONTENT_TYPE_LATEST, - "Content-Length": str(len(data)) - } + headers = {"Content-Type": CONTENT_TYPE_LATEST, "Content-Length": str(len(data))} return Response(data, headers=headers) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 7bf4e3d4..55d2abf5 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -5,7 +5,6 @@ from typing import Any from fastapi import APIRouter, Form, Query, Request, Response import aurweb.filters # noqa: F401 - from aurweb import config, db, defaults, logging, models, util from aurweb.auth import creds, requires_auth from aurweb.exceptions import InvariantError, handle_form_exceptions @@ -13,23 +12,24 @@ from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.packages import util as pkgutil from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base -from aurweb.pkgbase import actions as pkgbase_actions -from aurweb.pkgbase import util as pkgbaseutil +from aurweb.pkgbase import actions as pkgbase_actions, util as pkgbaseutil from aurweb.templates import make_context, make_variable_context, render_template logger = logging.get_logger(__name__) router = APIRouter() -async def packages_get(request: Request, context: dict[str, Any], - status_code: HTTPStatus = HTTPStatus.OK): +async def packages_get( + request: Request, context: dict[str, Any], status_code: HTTPStatus = HTTPStatus.OK +): # Query parameters used in this request. context["q"] = dict(request.query_params) # Per page and offset. offset, per_page = util.sanitize_params( request.query_params.get("O", defaults.O), - request.query_params.get("PP", defaults.PP)) + request.query_params.get("PP", defaults.PP), + ) context["O"] = offset # Limit PP to options.max_search_results @@ -82,8 +82,7 @@ async def packages_get(request: Request, context: dict[str, Any], if submit == "Orphans": # If the user clicked the "Orphans" button, we only want # orphaned packages. - search.query = search.query.filter( - models.PackageBase.MaintainerUID.is_(None)) + search.query = search.query.filter(models.PackageBase.MaintainerUID.is_(None)) # Collect search result count here; we've applied our keywords. # Including more query operations below, like ordering, will @@ -94,26 +93,31 @@ async def packages_get(request: Request, context: dict[str, Any], search.sort_by(sort_by, sort_order) # Insert search results into the context. - results = search.results().with_entities( - models.Package.ID, - models.Package.Name, - models.Package.PackageBaseID, - models.Package.Version, - models.Package.Description, - models.PackageBase.Popularity, - models.PackageBase.NumVotes, - models.PackageBase.OutOfDateTS, - models.User.Username.label("Maintainer"), - models.PackageVote.PackageBaseID.label("Voted"), - models.PackageNotification.PackageBaseID.label("Notify") - ).group_by(models.Package.Name) + results = ( + search.results() + .with_entities( + models.Package.ID, + models.Package.Name, + models.Package.PackageBaseID, + models.Package.Version, + models.Package.Description, + models.PackageBase.Popularity, + models.PackageBase.NumVotes, + models.PackageBase.OutOfDateTS, + models.User.Username.label("Maintainer"), + models.PackageVote.PackageBaseID.label("Voted"), + models.PackageNotification.PackageBaseID.label("Notify"), + ) + .group_by(models.Package.Name) + ) packages = results.limit(per_page).offset(offset) context["packages"] = packages context["packages_count"] = num_packages - return render_template(request, "packages/index.html", context, - status_code=status_code) + return render_template( + request, "packages/index.html", context, status_code=status_code + ) @router.get("/packages") @@ -123,9 +127,12 @@ async def packages(request: Request) -> Response: @router.get("/packages/{name}") -async def package(request: Request, name: str, - all_deps: bool = Query(default=False), - all_reqs: bool = Query(default=False)) -> Response: +async def package( + request: Request, + name: str, + all_deps: bool = Query(default=False), + all_reqs: bool = Query(default=False), +) -> Response: """ Get a package by name. @@ -156,26 +163,21 @@ async def package(request: Request, name: str, # Add our base information. context = await pkgbaseutil.make_variable_context(request, pkgbase) - context.update( - { - "all_deps": all_deps, - "all_reqs": all_reqs - } - ) + context.update({"all_deps": all_deps, "all_reqs": all_reqs}) context["package"] = pkg # Package sources. context["sources"] = pkg.package_sources.order_by( - models.PackageSource.Source.asc()).all() + models.PackageSource.Source.asc() + ).all() # Listing metadata. context["max_listing"] = max_listing = 20 # Package dependencies. deps = pkg.package_dependencies.order_by( - models.PackageDependency.DepTypeID.asc(), - models.PackageDependency.DepName.asc() + models.PackageDependency.DepTypeID.asc(), models.PackageDependency.DepName.asc() ) context["depends_count"] = deps.count() if not all_deps: @@ -183,8 +185,7 @@ async def package(request: Request, name: str, context["dependencies"] = deps.all() # Package requirements (other packages depend on this one). - reqs = pkgutil.pkg_required( - pkg.Name, [p.RelName for p in rels_data.get("p", [])]) + reqs = pkgutil.pkg_required(pkg.Name, [p.RelName for p in rels_data.get("p", [])]) context["reqs_count"] = reqs.count() if not all_reqs: reqs = reqs.limit(max_listing) @@ -210,8 +211,7 @@ async def package(request: Request, name: str, return render_template(request, "packages/show.html", context) -async def packages_unflag(request: Request, package_ids: list[int] = [], - **kwargs): +async def packages_unflag(request: Request, package_ids: list[int] = [], **kwargs): if not package_ids: return (False, ["You did not select any packages to unflag."]) @@ -220,11 +220,11 @@ async def packages_unflag(request: Request, package_ids: list[int] = [], bases = set() package_ids = set(package_ids) # Convert this to a set for O(1). - packages = db.query(models.Package).filter( - models.Package.ID.in_(package_ids)).all() + packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all() for pkg in packages: has_cred = request.user.has_credential( - creds.PKGBASE_UNFLAG, approved=[pkg.PackageBase.Flagger]) + creds.PKGBASE_UNFLAG, approved=[pkg.PackageBase.Flagger] + ) if not has_cred: return (False, ["You did not select any packages to unflag."]) @@ -236,20 +236,17 @@ async def packages_unflag(request: Request, package_ids: list[int] = [], return (True, ["The selected packages have been unflagged."]) -async def packages_notify(request: Request, package_ids: list[int] = [], - **kwargs): +async def packages_notify(request: Request, package_ids: list[int] = [], **kwargs): # In cases where we encounter errors with the request, we'll # use this error tuple as a return value. # TODO: This error does not yet have a translation. - error_tuple = (False, - ["You did not select any packages to be notified about."]) + error_tuple = (False, ["You did not select any packages to be notified about."]) if not package_ids: return error_tuple bases = set() package_ids = set(package_ids) - packages = db.query(models.Package).filter( - models.Package.ID.in_(package_ids)).all() + packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all() for pkg in packages: if pkg.PackageBase not in bases: @@ -257,9 +254,11 @@ async def packages_notify(request: Request, package_ids: list[int] = [], # Perform some checks on what the user selected for notify. for pkgbase in bases: - notif = db.query(pkgbase.notifications.filter( - models.PackageNotification.UserID == request.user.ID - ).exists()).scalar() + notif = db.query( + pkgbase.notifications.filter( + models.PackageNotification.UserID == request.user.ID + ).exists() + ).scalar() has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY) # If the request user either does not have credentials @@ -275,23 +274,20 @@ async def packages_notify(request: Request, package_ids: list[int] = [], return (True, ["The selected packages' notifications have been enabled."]) -async def packages_unnotify(request: Request, package_ids: list[int] = [], - **kwargs): +async def packages_unnotify(request: Request, package_ids: list[int] = [], **kwargs): if not package_ids: # TODO: This error does not yet have a translation. - return (False, - ["You did not select any packages for notification removal."]) + return (False, ["You did not select any packages for notification removal."]) # TODO: This error does not yet have a translation. error_tuple = ( False, - ["A package you selected does not have notifications enabled."] + ["A package you selected does not have notifications enabled."], ) bases = set() package_ids = set(package_ids) - packages = db.query(models.Package).filter( - models.Package.ID.in_(package_ids)).all() + packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all() for pkg in packages: if pkg.PackageBase not in bases: @@ -299,9 +295,11 @@ async def packages_unnotify(request: Request, package_ids: list[int] = [], # Perform some checks on what the user selected for notify. for pkgbase in bases: - notif = db.query(pkgbase.notifications.filter( - models.PackageNotification.UserID == request.user.ID - ).exists()).scalar() + notif = db.query( + pkgbase.notifications.filter( + models.PackageNotification.UserID == request.user.ID + ).exists() + ).scalar() if not notif: return error_tuple @@ -312,19 +310,24 @@ async def packages_unnotify(request: Request, package_ids: list[int] = [], return (True, ["The selected packages' notifications have been removed."]) -async def packages_adopt(request: Request, package_ids: list[int] = [], - confirm: bool = False, **kwargs): +async def packages_adopt( + request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs +): if not package_ids: return (False, ["You did not select any packages to adopt."]) if not confirm: - return (False, ["The selected packages have not been adopted, " - "check the confirmation checkbox."]) + return ( + False, + [ + "The selected packages have not been adopted, " + "check the confirmation checkbox." + ], + ) bases = set() package_ids = set(package_ids) - packages = db.query(models.Package).filter( - models.Package.ID.in_(package_ids)).all() + packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all() for pkg in packages: if pkg.PackageBase not in bases: @@ -335,8 +338,10 @@ async def packages_adopt(request: Request, package_ids: list[int] = [], has_cred = request.user.has_credential(creds.PKGBASE_ADOPT) if not (has_cred or not pkgbase.Maintainer): # TODO: This error needs to be translated. - return (False, ["You are not allowed to adopt one of the " - "packages you selected."]) + return ( + False, + ["You are not allowed to adopt one of the " "packages you selected."], + ) # Now, really adopt the bases. for pkgbase in bases: @@ -345,8 +350,7 @@ async def packages_adopt(request: Request, package_ids: list[int] = [], return (True, ["The selected packages have been adopted."]) -def disown_all(request: Request, pkgbases: list[models.PackageBase]) \ - -> list[str]: +def disown_all(request: Request, pkgbases: list[models.PackageBase]) -> list[str]: errors = [] for pkgbase in pkgbases: try: @@ -356,19 +360,24 @@ def disown_all(request: Request, pkgbases: list[models.PackageBase]) \ return errors -async def packages_disown(request: Request, package_ids: list[int] = [], - confirm: bool = False, **kwargs): +async def packages_disown( + request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs +): if not package_ids: return (False, ["You did not select any packages to disown."]) if not confirm: - return (False, ["The selected packages have not been disowned, " - "check the confirmation checkbox."]) + return ( + False, + [ + "The selected packages have not been disowned, " + "check the confirmation checkbox." + ], + ) bases = set() package_ids = set(package_ids) - packages = db.query(models.Package).filter( - models.Package.ID.in_(package_ids)).all() + packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all() for pkg in packages: if pkg.PackageBase not in bases: @@ -376,12 +385,15 @@ async def packages_disown(request: Request, package_ids: list[int] = [], # Check that the user has credentials for every package they selected. for pkgbase in bases: - has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, - approved=[pkgbase.Maintainer]) + has_cred = request.user.has_credential( + creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer] + ) if not has_cred: # TODO: This error needs to be translated. - return (False, ["You are not allowed to disown one " - "of the packages you selected."]) + return ( + False, + ["You are not allowed to disown one " "of the packages you selected."], + ) # Now, disown all the bases if we can. if errors := disown_all(request, bases): @@ -390,23 +402,31 @@ async def packages_disown(request: Request, package_ids: list[int] = [], return (True, ["The selected packages have been disowned."]) -async def packages_delete(request: Request, package_ids: list[int] = [], - confirm: bool = False, merge_into: str = str(), - **kwargs): +async def packages_delete( + request: Request, + package_ids: list[int] = [], + confirm: bool = False, + merge_into: str = str(), + **kwargs, +): if not package_ids: return (False, ["You did not select any packages to delete."]) if not confirm: - return (False, ["The selected packages have not been deleted, " - "check the confirmation checkbox."]) + return ( + False, + [ + "The selected packages have not been deleted, " + "check the confirmation checkbox." + ], + ) if not request.user.has_credential(creds.PKGBASE_DELETE): return (False, ["You do not have permission to delete packages."]) # set-ify package_ids and query the database for related records. package_ids = set(package_ids) - packages = db.query(models.Package).filter( - models.Package.ID.in_(package_ids)).all() + packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all() if len(packages) != len(package_ids): # Let the user know there was an issue with their input: they have @@ -422,12 +442,15 @@ async def packages_delete(request: Request, package_ids: list[int] = [], notifs += pkgbase_actions.pkgbase_delete_instance(request, pkgbase) # Log out the fact that this happened for accountability. - logger.info(f"Privileged user '{request.user.Username}' deleted the " - f"following package bases: {str(deleted_bases)}.") + logger.info( + f"Privileged user '{request.user.Username}' deleted the " + f"following package bases: {str(deleted_bases)}." + ) util.apply_all(notifs, lambda n: n.send()) return (True, ["The selected packages have been deleted."]) + # A mapping of action string -> callback functions used within the # `packages_post` route below. We expect any action callback to # return a tuple in the format: (succeeded: bool, message: list[str]). @@ -444,10 +467,12 @@ PACKAGE_ACTIONS = { @router.post("/packages") @handle_form_exceptions @requires_auth -async def packages_post(request: Request, - IDs: list[int] = Form(default=[]), - action: str = Form(default=str()), - confirm: bool = Form(default=False)): +async def packages_post( + request: Request, + IDs: list[int] = Form(default=[]), + action: str = Form(default=str()), + confirm: bool = Form(default=False), +): # If an invalid action is specified, just render GET /packages # with an BAD_REQUEST status_code. diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 1f09cfc8..913e3955 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -16,9 +16,7 @@ from aurweb.models.package_vote import PackageVote from aurweb.models.request_type import DELETION_ID, MERGE_ID, ORPHAN_ID from aurweb.packages.requests import update_closure_comment from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment -from aurweb.pkgbase import actions -from aurweb.pkgbase import util as pkgbaseutil -from aurweb.pkgbase import validate +from aurweb.pkgbase import actions, util as pkgbaseutil, validate from aurweb.scripts import notify, popupdate from aurweb.scripts.rendercomment import update_comment_render_fastapi from aurweb.templates import make_variable_context, render_template @@ -44,8 +42,9 @@ async def pkgbase(request: Request, name: str) -> Response: packages = pkgbase.packages.all() pkg = packages[0] if len(packages) == 1 and pkg.Name == pkgbase.Name: - return RedirectResponse(f"/packages/{pkg.Name}", - status_code=int(HTTPStatus.SEE_OTHER)) + return RedirectResponse( + f"/packages/{pkg.Name}", status_code=int(HTTPStatus.SEE_OTHER) + ) # Add our base information. context = pkgbaseutil.make_context(request, pkgbase) @@ -69,8 +68,7 @@ async def pkgbase_voters(request: Request, name: str) -> Response: pkgbase = get_pkg_or_base(name, PackageBase) if not request.user.has_credential(creds.PKGBASE_LIST_VOTERS): - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) context = templates.make_context(request, "Voters") context["pkgbase"] = pkgbase @@ -82,8 +80,7 @@ async def pkgbase_flag_comment(request: Request, name: str): pkgbase = get_pkg_or_base(name, PackageBase) if pkgbase.OutOfDateTS is None: - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) context = templates.make_context(request, "Flag Comment") context["pkgbase"] = pkgbase @@ -92,13 +89,15 @@ async def pkgbase_flag_comment(request: Request, name: str): @router.post("/pkgbase/{name}/keywords") @handle_form_exceptions -async def pkgbase_keywords(request: Request, name: str, - keywords: str = Form(default=str())): +async def pkgbase_keywords( + request: Request, name: str, keywords: str = Form(default=str()) +): pkgbase = get_pkg_or_base(name, PackageBase) approved = [pkgbase.Maintainer] + [c.User for c in pkgbase.comaintainers] - has_cred = creds.has_credential(request.user, creds.PKGBASE_SET_KEYWORDS, - approved=approved) + has_cred = creds.has_credential( + request.user, creds.PKGBASE_SET_KEYWORDS, approved=approved + ) if not has_cred: return Response(status_code=HTTPStatus.UNAUTHORIZED) @@ -108,15 +107,14 @@ async def pkgbase_keywords(request: Request, name: str, # Delete all keywords which are not supplied by the user. with db.begin(): - other_keywords = pkgbase.keywords.filter( - ~PackageKeyword.Keyword.in_(keywords)) - other_keyword_strings = set( - kwd.Keyword.lower() for kwd in other_keywords) + other_keywords = pkgbase.keywords.filter(~PackageKeyword.Keyword.in_(keywords)) + other_keyword_strings = set(kwd.Keyword.lower() for kwd in other_keywords) existing_keywords = set( - kwd.Keyword.lower() for kwd in - pkgbase.keywords.filter( - ~PackageKeyword.Keyword.in_(other_keyword_strings)) + kwd.Keyword.lower() + for kwd in pkgbase.keywords.filter( + ~PackageKeyword.Keyword.in_(other_keyword_strings) + ) ) db.delete_all(other_keywords) @@ -124,8 +122,7 @@ async def pkgbase_keywords(request: Request, name: str, for keyword in new_keywords: db.create(PackageKeyword, PackageBase=pkgbase, Keyword=keyword) - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.get("/pkgbase/{name}/flag") @@ -135,8 +132,7 @@ async def pkgbase_flag_get(request: Request, name: str): has_cred = request.user.has_credential(creds.PKGBASE_FLAG) if not has_cred or pkgbase.OutOfDateTS is not None: - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) context = templates.make_context(request, "Flag Package Out-Of-Date") context["pkgbase"] = pkgbase @@ -146,17 +142,20 @@ async def pkgbase_flag_get(request: Request, name: str): @router.post("/pkgbase/{name}/flag") @handle_form_exceptions @requires_auth -async def pkgbase_flag_post(request: Request, name: str, - comments: str = Form(default=str())): +async def pkgbase_flag_post( + request: Request, name: str, comments: str = Form(default=str()) +): pkgbase = get_pkg_or_base(name, PackageBase) if not comments: context = templates.make_context(request, "Flag Package Out-Of-Date") context["pkgbase"] = pkgbase - context["errors"] = ["The selected packages have not been flagged, " - "please enter a comment."] - return render_template(request, "pkgbase/flag.html", context, - status_code=HTTPStatus.BAD_REQUEST) + context["errors"] = [ + "The selected packages have not been flagged, " "please enter a comment." + ] + return render_template( + request, "pkgbase/flag.html", context, status_code=HTTPStatus.BAD_REQUEST + ) has_cred = request.user.has_credential(creds.PKGBASE_FLAG) if has_cred and not pkgbase.OutOfDateTS: @@ -168,18 +167,19 @@ async def pkgbase_flag_post(request: Request, name: str, notify.FlagNotification(request.user.ID, pkgbase.ID).send() - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.post("/pkgbase/{name}/comments") @handle_form_exceptions @requires_auth async def pkgbase_comments_post( - request: Request, name: str, - comment: str = Form(default=str()), - enable_notifications: bool = Form(default=False)): - """ Add a new comment via POST request. """ + request: Request, + name: str, + comment: str = Form(default=str()), + enable_notifications: bool = Form(default=False), +): + """Add a new comment via POST request.""" pkgbase = get_pkg_or_base(name, PackageBase) if not comment: @@ -189,29 +189,34 @@ async def pkgbase_comments_post( # update the db record. now = time.utcnow() with db.begin(): - comment = db.create(PackageComment, User=request.user, - PackageBase=pkgbase, - Comments=comment, RenderedComment=str(), - CommentTS=now) + comment = db.create( + PackageComment, + User=request.user, + PackageBase=pkgbase, + Comments=comment, + RenderedComment=str(), + CommentTS=now, + ) if enable_notifications and not request.user.notified(pkgbase): - db.create(PackageNotification, - User=request.user, - PackageBase=pkgbase) + db.create(PackageNotification, User=request.user, PackageBase=pkgbase) update_comment_render_fastapi(comment) notif = notify.CommentNotification(request.user.ID, pkgbase.ID, comment.ID) notif.send() # Redirect to the pkgbase page. - return RedirectResponse(f"/pkgbase/{pkgbase.Name}#comment-{comment.ID}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse( + f"/pkgbase/{pkgbase.Name}#comment-{comment.ID}", + status_code=HTTPStatus.SEE_OTHER, + ) @router.get("/pkgbase/{name}/comments/{id}/form") @requires_auth -async def pkgbase_comment_form(request: Request, name: str, id: int, - next: str = Query(default=None)): +async def pkgbase_comment_form( + request: Request, name: str, id: int, next: str = Query(default=None) +): """ Produce a comment form for comment {id}. @@ -244,14 +249,16 @@ async def pkgbase_comment_form(request: Request, name: str, id: int, context["next"] = next form = templates.render_raw_template( - request, "partials/packages/comment_form.html", context) + request, "partials/packages/comment_form.html", context + ) return JSONResponse({"form": form}) @router.get("/pkgbase/{name}/comments/{id}/edit") @requires_auth -async def pkgbase_comment_edit(request: Request, name: str, id: int, - next: str = Form(default=None)): +async def pkgbase_comment_edit( + request: Request, name: str, id: int, next: str = Form(default=None) +): """ Render the non-javascript edit form. @@ -276,11 +283,14 @@ async def pkgbase_comment_edit(request: Request, name: str, id: int, @handle_form_exceptions @requires_auth async def pkgbase_comment_post( - request: Request, name: str, id: int, - comment: str = Form(default=str()), - enable_notifications: bool = Form(default=False), - next: str = Form(default=None)): - """ Edit an existing comment. """ + request: Request, + name: str, + id: int, + comment: str = Form(default=str()), + enable_notifications: bool = Form(default=False), + next: str = Form(default=None), +): + """Edit an existing comment.""" pkgbase = get_pkg_or_base(name, PackageBase) db_comment = get_pkgbase_comment(pkgbase, id) @@ -302,24 +312,24 @@ async def pkgbase_comment_post( PackageNotification.PackageBaseID == pkgbase.ID ).first() if enable_notifications and not db_notif: - db.create(PackageNotification, - User=request.user, - PackageBase=pkgbase) + db.create(PackageNotification, User=request.user, PackageBase=pkgbase) update_comment_render_fastapi(db_comment) if not next: next = f"/pkgbase/{pkgbase.Name}" # Redirect to the pkgbase page anchored to the updated comment. - return RedirectResponse(f"{next}#comment-{db_comment.ID}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse( + f"{next}#comment-{db_comment.ID}", status_code=HTTPStatus.SEE_OTHER + ) @router.post("/pkgbase/{name}/comments/{id}/pin") @handle_form_exceptions @requires_auth -async def pkgbase_comment_pin(request: Request, name: str, id: int, - next: str = Form(default=None)): +async def pkgbase_comment_pin( + request: Request, name: str, id: int, next: str = Form(default=None) +): """ Pin a comment. @@ -332,13 +342,15 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) - has_cred = request.user.has_credential(creds.COMMENT_PIN, - approved=comment.maintainers()) + has_cred = request.user.has_credential( + creds.COMMENT_PIN, approved=comment.maintainers() + ) if not has_cred: _ = l10n.get_translator_for_request(request) raise HTTPException( status_code=HTTPStatus.UNAUTHORIZED, - detail=_("You are not allowed to pin this comment.")) + detail=_("You are not allowed to pin this comment."), + ) now = time.utcnow() with db.begin(): @@ -353,8 +365,9 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/unpin") @handle_form_exceptions @requires_auth -async def pkgbase_comment_unpin(request: Request, name: str, id: int, - next: str = Form(default=None)): +async def pkgbase_comment_unpin( + request: Request, name: str, id: int, next: str = Form(default=None) +): """ Unpin a comment. @@ -367,13 +380,15 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) - has_cred = request.user.has_credential(creds.COMMENT_PIN, - approved=comment.maintainers()) + has_cred = request.user.has_credential( + creds.COMMENT_PIN, approved=comment.maintainers() + ) if not has_cred: _ = l10n.get_translator_for_request(request) raise HTTPException( status_code=HTTPStatus.UNAUTHORIZED, - detail=_("You are not allowed to unpin this comment.")) + detail=_("You are not allowed to unpin this comment."), + ) with db.begin(): comment.PinnedTS = 0 @@ -387,8 +402,9 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/delete") @handle_form_exceptions @requires_auth -async def pkgbase_comment_delete(request: Request, name: str, id: int, - next: str = Form(default=None)): +async def pkgbase_comment_delete( + request: Request, name: str, id: int, next: str = Form(default=None) +): """ Delete a comment. @@ -405,13 +421,13 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) - authorized = request.user.has_credential(creds.COMMENT_DELETE, - [comment.User]) + authorized = request.user.has_credential(creds.COMMENT_DELETE, [comment.User]) if not authorized: _ = l10n.get_translator_for_request(request) raise HTTPException( status_code=HTTPStatus.UNAUTHORIZED, - detail=_("You are not allowed to delete this comment.")) + detail=_("You are not allowed to delete this comment."), + ) now = time.utcnow() with db.begin(): @@ -427,8 +443,9 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int, @router.post("/pkgbase/{name}/comments/{id}/undelete") @handle_form_exceptions @requires_auth -async def pkgbase_comment_undelete(request: Request, name: str, id: int, - next: str = Form(default=None)): +async def pkgbase_comment_undelete( + request: Request, name: str, id: int, next: str = Form(default=None) +): """ Undelete a comment. @@ -445,13 +462,15 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int, pkgbase = get_pkg_or_base(name, PackageBase) comment = get_pkgbase_comment(pkgbase, id) - has_cred = request.user.has_credential(creds.COMMENT_UNDELETE, - approved=[comment.User]) + has_cred = request.user.has_credential( + creds.COMMENT_UNDELETE, approved=[comment.User] + ) if not has_cred: _ = l10n.get_translator_for_request(request) raise HTTPException( status_code=HTTPStatus.UNAUTHORIZED, - detail=_("You are not allowed to undelete this comment.")) + detail=_("You are not allowed to undelete this comment."), + ) with db.begin(): comment.Deleter = None @@ -469,23 +488,17 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int, async def pkgbase_vote(request: Request, name: str): pkgbase = get_pkg_or_base(name, PackageBase) - vote = pkgbase.package_votes.filter( - PackageVote.UsersID == request.user.ID - ).first() + vote = pkgbase.package_votes.filter(PackageVote.UsersID == request.user.ID).first() has_cred = request.user.has_credential(creds.PKGBASE_VOTE) if has_cred and not vote: now = time.utcnow() with db.begin(): - db.create(PackageVote, - User=request.user, - PackageBase=pkgbase, - VoteTS=now) + db.create(PackageVote, User=request.user, PackageBase=pkgbase, VoteTS=now) # Update NumVotes/Popularity. popupdate.run_single(pkgbase) - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.post("/pkgbase/{name}/unvote") @@ -494,9 +507,7 @@ async def pkgbase_vote(request: Request, name: str): async def pkgbase_unvote(request: Request, name: str): pkgbase = get_pkg_or_base(name, PackageBase) - vote = pkgbase.package_votes.filter( - PackageVote.UsersID == request.user.ID - ).first() + vote = pkgbase.package_votes.filter(PackageVote.UsersID == request.user.ID).first() has_cred = request.user.has_credential(creds.PKGBASE_VOTE) if has_cred and vote: with db.begin(): @@ -505,8 +516,7 @@ async def pkgbase_unvote(request: Request, name: str): # Update NumVotes/Popularity. popupdate.run_single(pkgbase) - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.post("/pkgbase/{name}/notify") @@ -515,8 +525,7 @@ async def pkgbase_unvote(request: Request, name: str): async def pkgbase_notify(request: Request, name: str): pkgbase = get_pkg_or_base(name, PackageBase) actions.pkgbase_notify_instance(request, pkgbase) - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.post("/pkgbase/{name}/unnotify") @@ -525,8 +534,7 @@ async def pkgbase_notify(request: Request, name: str): async def pkgbase_unnotify(request: Request, name: str): pkgbase = get_pkg_or_base(name, PackageBase) actions.pkgbase_unnotify_instance(request, pkgbase) - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.post("/pkgbase/{name}/unflag") @@ -535,20 +543,19 @@ async def pkgbase_unnotify(request: Request, name: str): async def pkgbase_unflag(request: Request, name: str): pkgbase = get_pkg_or_base(name, PackageBase) actions.pkgbase_unflag_instance(request, pkgbase) - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.get("/pkgbase/{name}/disown") @requires_auth -async def pkgbase_disown_get(request: Request, name: str, - next: str = Query(default=str())): +async def pkgbase_disown_get( + request: Request, name: str, next: str = Query(default=str()) +): pkgbase = get_pkg_or_base(name, PackageBase) comaints = {c.User for c in pkgbase.comaintainers} approved = [pkgbase.Maintainer] + list(comaints) - has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, - approved=approved) + has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=approved) if not has_cred: return RedirectResponse(f"/pkgbase/{name}", HTTPStatus.SEE_OTHER) @@ -563,27 +570,33 @@ async def pkgbase_disown_get(request: Request, name: str, @router.post("/pkgbase/{name}/disown") @handle_form_exceptions @requires_auth -async def pkgbase_disown_post(request: Request, name: str, - comments: str = Form(default=str()), - confirm: bool = Form(default=False), - next: str = Form(default=str())): +async def pkgbase_disown_post( + request: Request, + name: str, + comments: str = Form(default=str()), + confirm: bool = Form(default=False), + next: str = Form(default=str()), +): pkgbase = get_pkg_or_base(name, PackageBase) comaints = {c.User for c in pkgbase.comaintainers} approved = [pkgbase.Maintainer] + list(comaints) - has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, - approved=approved) + has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=approved) if not has_cred: - return RedirectResponse(f"/pkgbase/{name}", - HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", HTTPStatus.SEE_OTHER) context = templates.make_context(request, "Disown Package") context["pkgbase"] = pkgbase if not confirm: - context["errors"] = [("The selected packages have not been disowned, " - "check the confirmation checkbox.")] - return render_template(request, "pkgbase/disown.html", context, - status_code=HTTPStatus.BAD_REQUEST) + context["errors"] = [ + ( + "The selected packages have not been disowned, " + "check the confirmation checkbox." + ) + ] + return render_template( + request, "pkgbase/disown.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if request.user != pkgbase.Maintainer and request.user not in comaints: with db.begin(): @@ -593,8 +606,9 @@ async def pkgbase_disown_post(request: Request, name: str, actions.pkgbase_disown_instance(request, pkgbase) except InvariantError as exc: context["errors"] = [str(exc)] - return render_template(request, "pkgbase/disown.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "pkgbase/disown.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if not next: next = f"/pkgbase/{name}" @@ -615,8 +629,7 @@ async def pkgbase_adopt_post(request: Request, name: str): # if no maintainer currently exists. actions.pkgbase_adopt_instance(request, pkgbase) - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @router.get("/pkgbase/{name}/comaintainers") @@ -627,20 +640,20 @@ async def pkgbase_comaintainers(request: Request, name: str) -> Response: # Unauthorized users (Non-TU/Dev and not the pkgbase maintainer) # get redirected to the package base's page. - has_creds = request.user.has_credential(creds.PKGBASE_EDIT_COMAINTAINERS, - approved=[pkgbase.Maintainer]) + has_creds = request.user.has_credential( + creds.PKGBASE_EDIT_COMAINTAINERS, approved=[pkgbase.Maintainer] + ) if not has_creds: - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) # Add our base information. context = templates.make_context(request, "Manage Co-maintainers") - context.update({ - "pkgbase": pkgbase, - "comaintainers": [ - c.User.Username for c in pkgbase.comaintainers - ] - }) + context.update( + { + "pkgbase": pkgbase, + "comaintainers": [c.User.Username for c in pkgbase.comaintainers], + } + ) return render_template(request, "pkgbase/comaintainers.html", context) @@ -648,50 +661,52 @@ async def pkgbase_comaintainers(request: Request, name: str) -> Response: @router.post("/pkgbase/{name}/comaintainers") @handle_form_exceptions @requires_auth -async def pkgbase_comaintainers_post(request: Request, name: str, - users: str = Form(default=str())) \ - -> Response: +async def pkgbase_comaintainers_post( + request: Request, name: str, users: str = Form(default=str()) +) -> Response: # Get the PackageBase. pkgbase = get_pkg_or_base(name, PackageBase) # Unauthorized users (Non-TU/Dev and not the pkgbase maintainer) # get redirected to the package base's page. - has_creds = request.user.has_credential(creds.PKGBASE_EDIT_COMAINTAINERS, - approved=[pkgbase.Maintainer]) + has_creds = request.user.has_credential( + creds.PKGBASE_EDIT_COMAINTAINERS, approved=[pkgbase.Maintainer] + ) if not has_creds: - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) users = {e.strip() for e in users.split("\n") if bool(e.strip())} records = {c.User.Username for c in pkgbase.comaintainers} users_to_rm = records.difference(users) pkgbaseutil.remove_comaintainers(pkgbase, users_to_rm) - logger.debug(f"{request.user} removed comaintainers from " - f"{pkgbase.Name}: {users_to_rm}") + logger.debug( + f"{request.user} removed comaintainers from " f"{pkgbase.Name}: {users_to_rm}" + ) users_to_add = users.difference(records) error = pkgbaseutil.add_comaintainers(request, pkgbase, users_to_add) if error: context = templates.make_context(request, "Manage Co-maintainers") context["pkgbase"] = pkgbase - context["comaintainers"] = [ - c.User.Username for c in pkgbase.comaintainers - ] + context["comaintainers"] = [c.User.Username for c in pkgbase.comaintainers] context["errors"] = [error] return render_template(request, "pkgbase/comaintainers.html", context) - logger.debug(f"{request.user} added comaintainers to " - f"{pkgbase.Name}: {users_to_add}") + logger.debug( + f"{request.user} added comaintainers to " f"{pkgbase.Name}: {users_to_add}" + ) - return RedirectResponse(f"/pkgbase/{pkgbase.Name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse( + f"/pkgbase/{pkgbase.Name}", status_code=HTTPStatus.SEE_OTHER + ) @router.get("/pkgbase/{name}/request") @requires_auth -async def pkgbase_request(request: Request, name: str, - next: str = Query(default=str())): +async def pkgbase_request( + request: Request, name: str, next: str = Query(default=str()) +): pkgbase = get_pkg_or_base(name, PackageBase) context = await make_variable_context(request, "Submit Request") context["pkgbase"] = pkgbase @@ -702,28 +717,28 @@ async def pkgbase_request(request: Request, name: str, @router.post("/pkgbase/{name}/request") @handle_form_exceptions @requires_auth -async def pkgbase_request_post(request: Request, name: str, - type: str = Form(...), - merge_into: str = Form(default=None), - comments: str = Form(default=str()), - next: str = Form(default=str())): +async def pkgbase_request_post( + request: Request, + name: str, + type: str = Form(...), + merge_into: str = Form(default=None), + comments: str = Form(default=str()), + next: str = Form(default=str()), +): pkgbase = get_pkg_or_base(name, PackageBase) # Create our render context. context = await make_variable_context(request, "Submit Request") context["pkgbase"] = pkgbase - types = { - "deletion": DELETION_ID, - "merge": MERGE_ID, - "orphan": ORPHAN_ID - } + types = {"deletion": DELETION_ID, "merge": MERGE_ID, "orphan": ORPHAN_ID} if type not in types: # In the case that someone crafted a POST request with an invalid # type, just return them to the request form with BAD_REQUEST status. - return render_template(request, "pkgbase/request.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "pkgbase/request.html", context, status_code=HTTPStatus.BAD_REQUEST + ) try: validate.request(pkgbase, type, comments, merge_into, context) @@ -735,20 +750,26 @@ async def pkgbase_request_post(request: Request, name: str, # All good. Create a new PackageRequest based on the given type. now = time.utcnow() with db.begin(): - pkgreq = db.create(PackageRequest, - ReqTypeID=types.get(type), - User=request.user, - RequestTS=now, - PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - MergeBaseName=merge_into, - Comments=comments, - ClosureComment=str()) + pkgreq = db.create( + PackageRequest, + ReqTypeID=types.get(type), + User=request.user, + RequestTS=now, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + MergeBaseName=merge_into, + Comments=comments, + ClosureComment=str(), + ) # Prepare notification object. notif = notify.RequestOpenNotification( - request.user.ID, pkgreq.ID, type, - pkgreq.PackageBase.ID, merge_into=merge_into or None) + request.user.ID, + pkgreq.ID, + type, + pkgreq.PackageBase.ID, + merge_into=merge_into or None, + ) # Send the notification now that we're out of the DB scope. notif.send() @@ -767,13 +788,13 @@ async def pkgbase_request_post(request: Request, name: str, pkgbase.Maintainer = None pkgreq.Status = ACCEPTED_ID notif = notify.RequestCloseNotification( - request.user.ID, pkgreq.ID, pkgreq.status_display()) + request.user.ID, pkgreq.ID, pkgreq.status_display() + ) notif.send() logger.debug(f"New request #{pkgreq.ID} is marked for auto-orphan.") elif type == "deletion" and is_maintainer and outdated: # This request should be auto-accepted. - notifs = actions.pkgbase_delete_instance( - request, pkgbase, comments=comments) + notifs = actions.pkgbase_delete_instance(request, pkgbase, comments=comments) util.apply_all(notifs, lambda n: n.send()) logger.debug(f"New request #{pkgreq.ID} is marked for auto-deletion.") @@ -783,11 +804,11 @@ async def pkgbase_request_post(request: Request, name: str, @router.get("/pkgbase/{name}/delete") @requires_auth -async def pkgbase_delete_get(request: Request, name: str, - next: str = Query(default=str())): +async def pkgbase_delete_get( + request: Request, name: str, next: str = Query(default=str()) +): if not request.user.has_credential(creds.PKGBASE_DELETE): - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) context = templates.make_context(request, "Package Deletion") context["pkgbase"] = get_pkg_or_base(name, PackageBase) @@ -798,53 +819,60 @@ async def pkgbase_delete_get(request: Request, name: str, @router.post("/pkgbase/{name}/delete") @handle_form_exceptions @requires_auth -async def pkgbase_delete_post(request: Request, name: str, - confirm: bool = Form(default=False), - comments: str = Form(default=str()), - next: str = Form(default="/packages")): +async def pkgbase_delete_post( + request: Request, + name: str, + confirm: bool = Form(default=False), + comments: str = Form(default=str()), + next: str = Form(default="/packages"), +): pkgbase = get_pkg_or_base(name, PackageBase) if not request.user.has_credential(creds.PKGBASE_DELETE): - return RedirectResponse(f"/pkgbase/{name}", - status_code=HTTPStatus.SEE_OTHER) + return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) if not confirm: context = templates.make_context(request, "Package Deletion") context["pkgbase"] = pkgbase - context["errors"] = [("The selected packages have not been deleted, " - "check the confirmation checkbox.")] - return render_template(request, "pkgbase/delete.html", context, - status_code=HTTPStatus.BAD_REQUEST) + context["errors"] = [ + ( + "The selected packages have not been deleted, " + "check the confirmation checkbox." + ) + ] + return render_template( + request, "pkgbase/delete.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if comments: # Update any existing deletion requests' ClosureComment. with db.begin(): requests = pkgbase.requests.filter( - and_(PackageRequest.Status == PENDING_ID, - PackageRequest.ReqTypeID == DELETION_ID) + and_( + PackageRequest.Status == PENDING_ID, + PackageRequest.ReqTypeID == DELETION_ID, + ) ) for pkgreq in requests: pkgreq.ClosureComment = comments - notifs = actions.pkgbase_delete_instance( - request, pkgbase, comments=comments) + notifs = actions.pkgbase_delete_instance(request, pkgbase, comments=comments) util.apply_all(notifs, lambda n: n.send()) return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER) @router.get("/pkgbase/{name}/merge") @requires_auth -async def pkgbase_merge_get(request: Request, name: str, - into: str = Query(default=str()), - next: str = Query(default=str())): +async def pkgbase_merge_get( + request: Request, + name: str, + into: str = Query(default=str()), + next: str = Query(default=str()), +): pkgbase = get_pkg_or_base(name, PackageBase) context = templates.make_context(request, "Package Merging") - context.update({ - "pkgbase": pkgbase, - "into": into, - "next": next - }) + context.update({"pkgbase": pkgbase, "into": into, "next": next}) status_code = HTTPStatus.OK # TODO: Lookup errors from credential instead of hardcoding them. @@ -852,51 +880,58 @@ async def pkgbase_merge_get(request: Request, name: str, # Perhaps additionally: bad_credential_status_code(creds.PKGBASE_MERGE). # Don't take these examples verbatim. We should find good naming. if not request.user.has_credential(creds.PKGBASE_MERGE): - context["errors"] = [ - "Only Trusted Users and Developers can merge packages."] + context["errors"] = ["Only Trusted Users and Developers can merge packages."] status_code = HTTPStatus.UNAUTHORIZED - return render_template(request, "pkgbase/merge.html", context, - status_code=status_code) + return render_template( + request, "pkgbase/merge.html", context, status_code=status_code + ) @router.post("/pkgbase/{name}/merge") @handle_form_exceptions @requires_auth -async def pkgbase_merge_post(request: Request, name: str, - into: str = Form(default=str()), - comments: str = Form(default=str()), - confirm: bool = Form(default=False), - next: str = Form(default=str())): +async def pkgbase_merge_post( + request: Request, + name: str, + into: str = Form(default=str()), + comments: str = Form(default=str()), + confirm: bool = Form(default=False), + next: str = Form(default=str()), +): pkgbase = get_pkg_or_base(name, PackageBase) context = await make_variable_context(request, "Package Merging") context["pkgbase"] = pkgbase # TODO: Lookup errors from credential instead of hardcoding them. if not request.user.has_credential(creds.PKGBASE_MERGE): - context["errors"] = [ - "Only Trusted Users and Developers can merge packages."] - return render_template(request, "pkgbase/merge.html", context, - status_code=HTTPStatus.UNAUTHORIZED) + context["errors"] = ["Only Trusted Users and Developers can merge packages."] + return render_template( + request, "pkgbase/merge.html", context, status_code=HTTPStatus.UNAUTHORIZED + ) if not confirm: - context["errors"] = ["The selected packages have not been deleted, " - "check the confirmation checkbox."] - return render_template(request, "pkgbase/merge.html", context, - status_code=HTTPStatus.BAD_REQUEST) + context["errors"] = [ + "The selected packages have not been deleted, " + "check the confirmation checkbox." + ] + return render_template( + request, "pkgbase/merge.html", context, status_code=HTTPStatus.BAD_REQUEST + ) try: target = get_pkg_or_base(into, PackageBase) except HTTPException: - context["errors"] = [ - "Cannot find package to merge votes and comments into."] - return render_template(request, "pkgbase/merge.html", context, - status_code=HTTPStatus.BAD_REQUEST) + context["errors"] = ["Cannot find package to merge votes and comments into."] + return render_template( + request, "pkgbase/merge.html", context, status_code=HTTPStatus.BAD_REQUEST + ) if pkgbase == target: context["errors"] = ["Cannot merge a package base with itself."] - return render_template(request, "pkgbase/merge.html", context, - status_code=HTTPStatus.BAD_REQUEST) + return render_template( + request, "pkgbase/merge.html", context, status_code=HTTPStatus.BAD_REQUEST + ) with db.begin(): update_closure_comment(pkgbase, MERGE_ID, comments, target=target) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 086aa3bc..c7935575 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -18,9 +18,11 @@ router = APIRouter() @router.get("/requests") @requires_auth -async def requests(request: Request, - O: int = Query(default=defaults.O), - PP: int = Query(default=defaults.PP)): +async def requests( + request: Request, + O: int = Query(default=defaults.O), + PP: int = Query(default=defaults.PP), +): context = make_context(request, "Requests") context["q"] = dict(request.query_params) @@ -30,8 +32,7 @@ async def requests(request: Request, context["PP"] = PP # A PackageRequest query, with left inner joined User and RequestType. - query = db.query(PackageRequest).join( - User, User.ID == PackageRequest.UsersID) + query = db.query(PackageRequest).join(User, User.ID == PackageRequest.UsersID) # If the request user is not elevated (TU or Dev), then # filter PackageRequests which are owned by the request user. @@ -39,12 +40,17 @@ async def requests(request: Request, query = query.filter(PackageRequest.UsersID == request.user.ID) context["total"] = query.count() - context["results"] = query.order_by( - # Order primarily by the Status column being PENDING_ID, - # and secondarily by RequestTS; both in descending order. - case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), - PackageRequest.RequestTS.desc() - ).limit(PP).offset(O).all() + context["results"] = ( + query.order_by( + # Order primarily by the Status column being PENDING_ID, + # and secondarily by RequestTS; both in descending order. + case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), + PackageRequest.RequestTS.desc(), + ) + .limit(PP) + .offset(O) + .all() + ) return render_template(request, "requests.html", context) @@ -66,8 +72,9 @@ async def request_close(request: Request, id: int): @router.post("/requests/{id}/close") @handle_form_exceptions @requires_auth -async def request_close_post(request: Request, id: int, - comments: str = Form(default=str())): +async def request_close_post( + request: Request, id: int, comments: str = Form(default=str()) +): pkgreq = get_pkgreq_by_id(id) # `pkgreq`.User can close their own request. @@ -87,7 +94,8 @@ async def request_close_post(request: Request, id: int, pkgreq.Status = REJECTED_ID notify_ = notify.RequestCloseNotification( - request.user.ID, pkgreq.ID, pkgreq.status_display()) + request.user.ID, pkgreq.ID, pkgreq.status_display() + ) notify_.send() return RedirectResponse("/requests", status_code=HTTPStatus.SEE_OTHER) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index ff58063f..a0cf5019 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -1,12 +1,10 @@ import hashlib import re - from http import HTTPStatus from typing import Optional from urllib.parse import unquote import orjson - from fastapi import APIRouter, Form, Query, Request, Response from fastapi.responses import JSONResponse @@ -19,7 +17,7 @@ router = APIRouter() def parse_args(request: Request): - """ Handle legacy logic of 'arg' and 'arg[]' query parameter handling. + """Handle legacy logic of 'arg' and 'arg[]' query parameter handling. When 'arg' appears as the last argument given to the query string, that argument is used by itself as one single argument, regardless @@ -39,9 +37,7 @@ def parse_args(request: Request): # Create a list of (key, value) pairs of the given 'arg' and 'arg[]' # query parameters from last to first. query = list(reversed(unquote(request.url.query).split("&"))) - parts = [ - e.split("=", 1) for e in query if e.startswith(("arg=", "arg[]=")) - ] + parts = [e.split("=", 1) for e in query if e.startswith(("arg=", "arg[]="))] args = [] if parts: @@ -63,24 +59,28 @@ def parse_args(request: Request): return args -JSONP_EXPR = re.compile(r'^[a-zA-Z0-9()_.]{1,128}$') +JSONP_EXPR = re.compile(r"^[a-zA-Z0-9()_.]{1,128}$") -async def rpc_request(request: Request, - v: Optional[int] = None, - type: Optional[str] = None, - by: Optional[str] = defaults.RPC_SEARCH_BY, - arg: Optional[str] = None, - args: Optional[list[str]] = [], - callback: Optional[str] = None): +async def rpc_request( + request: Request, + v: Optional[int] = None, + type: Optional[str] = None, + by: Optional[str] = defaults.RPC_SEARCH_BY, + arg: Optional[str] = None, + args: Optional[list[str]] = [], + callback: Optional[str] = None, +): # Create a handle to our RPC class. rpc = RPC(version=v, type=type) # If ratelimit was exceeded, return a 429 Too Many Requests. if check_ratelimit(request): - return JSONResponse(rpc.error("Rate limit reached"), - status_code=int(HTTPStatus.TOO_MANY_REQUESTS)) + return JSONResponse( + rpc.error("Rate limit reached"), + status_code=int(HTTPStatus.TOO_MANY_REQUESTS), + ) # If `callback` was provided, produce a text/javascript response # valid for the jsonp callback. Otherwise, by default, return @@ -115,15 +115,11 @@ async def rpc_request(request: Request, # The ETag header expects quotes to surround any identifier. # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag - headers = { - "Content-Type": content_type, - "ETag": f'"{etag}"' - } + headers = {"Content-Type": content_type, "ETag": f'"{etag}"'} if_none_match = request.headers.get("If-None-Match", str()) - if if_none_match and if_none_match.strip("\t\n\r\" ") == etag: - return Response(headers=headers, - status_code=int(HTTPStatus.NOT_MODIFIED)) + if if_none_match and if_none_match.strip('\t\n\r" ') == etag: + return Response(headers=headers, status_code=int(HTTPStatus.NOT_MODIFIED)) if callback: content = f"/**/{callback}({content.decode()})" @@ -135,13 +131,15 @@ async def rpc_request(request: Request, @router.get("/rpc.php") # Temporary! Remove on 03/04 @router.get("/rpc/") @router.get("/rpc") -async def rpc(request: Request, - v: Optional[int] = Query(default=None), - type: Optional[str] = Query(default=None), - by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), - arg: Optional[str] = Query(default=None), - args: Optional[list[str]] = Query(default=[], alias="arg[]"), - callback: Optional[str] = Query(default=None)): +async def rpc( + request: Request, + v: Optional[int] = Query(default=None), + type: Optional[str] = Query(default=None), + by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), + arg: Optional[str] = Query(default=None), + args: Optional[list[str]] = Query(default=[], alias="arg[]"), + callback: Optional[str] = Query(default=None), +): if not request.url.query: return documentation() return await rpc_request(request, v, type, by, arg, args, callback) @@ -152,11 +150,13 @@ async def rpc(request: Request, @router.post("/rpc/") @router.post("/rpc") @handle_form_exceptions -async def rpc_post(request: Request, - v: Optional[int] = Form(default=None), - type: Optional[str] = Form(default=None), - by: Optional[str] = Form(default=defaults.RPC_SEARCH_BY), - arg: Optional[str] = Form(default=None), - args: Optional[list[str]] = Form(default=[], alias="arg[]"), - callback: Optional[str] = Form(default=None)): +async def rpc_post( + request: Request, + v: Optional[int] = Form(default=None), + type: Optional[str] = Form(default=None), + by: Optional[str] = Form(default=defaults.RPC_SEARCH_BY), + arg: Optional[str] = Form(default=None), + args: Optional[list[str]] = Form(default=[], alias="arg[]"), + callback: Optional[str] = Form(default=None), +): return await rpc_request(request, v, type, by, arg, args, callback) diff --git a/aurweb/routers/rss.py b/aurweb/routers/rss.py index 0996f3cd..ee85b738 100644 --- a/aurweb/routers/rss.py +++ b/aurweb/routers/rss.py @@ -10,9 +10,8 @@ from aurweb.models import Package, PackageBase router = APIRouter() -def make_rss_feed(request: Request, packages: list, - date_attr: str): - """ Create an RSS Feed string for some packages. +def make_rss_feed(request: Request, packages: list, date_attr: str): + """Create an RSS Feed string for some packages. :param request: A FastAPI request :param packages: A list of packages to add to the RSS feed @@ -26,10 +25,12 @@ def make_rss_feed(request: Request, packages: list, base = f"{request.url.scheme}://{request.url.netloc}" feed.link(href=base, rel="alternate") feed.link(href=f"{base}/rss", rel="self") - feed.image(title="AUR Newest Packages", - url=f"{base}/static/css/archnavbar/aurlogo.png", - link=base, - description="AUR Newest Packages Feed") + feed.image( + title="AUR Newest Packages", + url=f"{base}/static/css/archnavbar/aurlogo.png", + link=base, + description="AUR Newest Packages Feed", + ) for pkg in packages: entry = feed.add_entry(order="append") @@ -53,8 +54,12 @@ def make_rss_feed(request: Request, packages: list, @router.get("/rss/") async def rss(request: Request): - packages = db.query(Package).join(PackageBase).order_by( - PackageBase.SubmittedTS.desc()).limit(100) + packages = ( + db.query(Package) + .join(PackageBase) + .order_by(PackageBase.SubmittedTS.desc()) + .limit(100) + ) feed = make_rss_feed(request, packages, "SubmittedTS") response = Response(feed, media_type="application/rss+xml") @@ -69,8 +74,12 @@ async def rss(request: Request): @router.get("/rss/modified") async def rss_modified(request: Request): - packages = db.query(Package).join(PackageBase).order_by( - PackageBase.ModifiedTS.desc()).limit(100) + packages = ( + db.query(Package) + .join(PackageBase) + .order_by(PackageBase.ModifiedTS.desc()) + .limit(100) + ) feed = make_rss_feed(request, packages, "ModifiedTS") response = Response(feed, media_type="application/rss+xml") diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index eff1c63f..e1356cfb 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -1,11 +1,9 @@ import time import uuid - from http import HTTPStatus from urllib.parse import urlencode import fastapi - from authlib.integrations.starlette_client import OAuth, OAuthError from fastapi import Depends, HTTPException from fastapi.responses import RedirectResponse @@ -14,7 +12,6 @@ from starlette.requests import Request import aurweb.config import aurweb.db - from aurweb import util from aurweb.l10n import get_translator_for_request from aurweb.schema import Bans, Sessions, Users @@ -43,14 +40,18 @@ async def login(request: Request, redirect: str = None): The `redirect` argument is a query parameter specifying the post-login redirect URL. """ - authenticate_url = aurweb.config.get("options", "aur_location") + "/sso/authenticate" + authenticate_url = ( + aurweb.config.get("options", "aur_location") + "/sso/authenticate" + ) if redirect: authenticate_url = authenticate_url + "?" + urlencode([("redirect", redirect)]) return await oauth.sso.authorize_redirect(request, authenticate_url, prompt="login") def is_account_suspended(conn, user_id): - row = conn.execute(select([Users.c.Suspended]).where(Users.c.ID == user_id)).fetchone() + row = conn.execute( + select([Users.c.Suspended]).where(Users.c.ID == user_id) + ).fetchone() return row is not None and bool(row[0]) @@ -60,23 +61,27 @@ def open_session(request, conn, user_id): """ if is_account_suspended(conn, user_id): _ = get_translator_for_request(request) - raise HTTPException(status_code=HTTPStatus.FORBIDDEN, - detail=_('Account suspended')) + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, detail=_("Account suspended") + ) # TODO This is a terrible message because it could imply the attempt at # logging in just caused the suspension. sid = uuid.uuid4().hex - conn.execute(Sessions.insert().values( - UsersID=user_id, - SessionID=sid, - LastUpdateTS=time.time(), - )) + conn.execute( + Sessions.insert().values( + UsersID=user_id, + SessionID=sid, + LastUpdateTS=time.time(), + ) + ) # Update user’s last login information. - conn.execute(Users.update() - .where(Users.c.ID == user_id) - .values(LastLogin=int(time.time()), - LastLoginIPAddress=request.client.host)) + conn.execute( + Users.update() + .where(Users.c.ID == user_id) + .values(LastLogin=int(time.time()), LastLoginIPAddress=request.client.host) + ) return sid @@ -98,7 +103,9 @@ def is_aur_url(url): @router.get("/sso/authenticate") -async def authenticate(request: Request, redirect: str = None, conn=Depends(aurweb.db.connect)): +async def authenticate( + request: Request, redirect: str = None, conn=Depends(aurweb.db.connect) +): """ Receive an OpenID Connect ID token, validate it, then process it to create an new AUR session. @@ -107,9 +114,12 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw _ = get_translator_for_request(request) raise HTTPException( status_code=HTTPStatus.FORBIDDEN, - detail=_('The login form is currently disabled for your IP address, ' - 'probably due to sustained spam attacks. Sorry for the ' - 'inconvenience.')) + detail=_( + "The login form is currently disabled for your IP address, " + "probably due to sustained spam attacks. Sorry for the " + "inconvenience." + ), + ) try: token = await oauth.sso.authorize_access_token(request) @@ -120,30 +130,41 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw _ = get_translator_for_request(request) raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, - detail=_('Bad OAuth token. Please retry logging in from the start.')) + detail=_("Bad OAuth token. Please retry logging in from the start."), + ) sub = user.get("sub") # this is the SSO account ID in JWT terminology if not sub: _ = get_translator_for_request(request) - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, - detail=_("JWT is missing its `sub` field.")) + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=_("JWT is missing its `sub` field."), + ) - aur_accounts = conn.execute(select([Users.c.ID]).where(Users.c.SSOAccountID == sub)) \ - .fetchall() + aur_accounts = conn.execute( + select([Users.c.ID]).where(Users.c.SSOAccountID == sub) + ).fetchall() if not aur_accounts: return "Sorry, we don’t seem to know you Sir " + sub elif len(aur_accounts) == 1: sid = open_session(request, conn, aur_accounts[0][Users.c.ID]) - response = RedirectResponse(redirect if redirect and is_aur_url(redirect) else "/") + response = RedirectResponse( + redirect if redirect and is_aur_url(redirect) else "/" + ) secure_cookies = aurweb.config.getboolean("options", "disable_http_login") - response.set_cookie(key="AURSID", value=sid, httponly=True, - secure=secure_cookies) + response.set_cookie( + key="AURSID", value=sid, httponly=True, secure=secure_cookies + ) if "id_token" in token: # We save the id_token for the SSO logout. It’s not too important # though, so if we can’t find it, we can live without it. - response.set_cookie(key="SSO_ID_TOKEN", value=token["id_token"], - path="/sso/", httponly=True, - secure=secure_cookies) + response.set_cookie( + key="SSO_ID_TOKEN", + value=token["id_token"], + path="/sso/", + httponly=True, + secure=secure_cookies, + ) return util.add_samesite_fields(response, "strict") else: # We’ve got a severe integrity violation. @@ -165,8 +186,12 @@ async def logout(request: Request): return RedirectResponse("/") metadata = await oauth.sso.load_server_metadata() - query = urlencode({'post_logout_redirect_uri': aurweb.config.get('options', 'aur_location'), - 'id_token_hint': id_token}) - response = RedirectResponse(metadata["end_session_endpoint"] + '?' + query) + query = urlencode( + { + "post_logout_redirect_uri": aurweb.config.get("options", "aur_location"), + "id_token_hint": id_token, + } + ) + response = RedirectResponse(metadata["end_session_endpoint"] + "?" + query) response.delete_cookie("SSO_ID_TOKEN", path="/sso/") return response diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index e1267409..a84bb6bd 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -1,6 +1,5 @@ import html import typing - from http import HTTPStatus from typing import Any @@ -30,33 +29,36 @@ ADDVOTE_SPECIFICS = { "add_tu": (7 * 24 * 60 * 60, 0.66), "remove_tu": (7 * 24 * 60 * 60, 0.75), "remove_inactive_tu": (5 * 24 * 60 * 60, 0.66), - "bylaws": (7 * 24 * 60 * 60, 0.75) + "bylaws": (7 * 24 * 60 * 60, 0.75), } def populate_trusted_user_counts(context: dict[str, Any]) -> None: tu_query = db.query(User).filter( - or_(User.AccountTypeID == TRUSTED_USER_ID, - User.AccountTypeID == TRUSTED_USER_AND_DEV_ID) + or_( + User.AccountTypeID == TRUSTED_USER_ID, + User.AccountTypeID == TRUSTED_USER_AND_DEV_ID, + ) ) context["trusted_user_count"] = tu_query.count() # In case any records have a None InactivityTS. active_tu_query = tu_query.filter( - or_(User.InactivityTS.is_(None), - User.InactivityTS == 0) + or_(User.InactivityTS.is_(None), User.InactivityTS == 0) ) context["active_trusted_user_count"] = active_tu_query.count() @router.get("/tu") @requires_auth -async def trusted_user(request: Request, - coff: int = 0, # current offset - cby: str = "desc", # current by - poff: int = 0, # past offset - pby: str = "desc"): # past by - """ Proposal listings. """ +async def trusted_user( + request: Request, + coff: int = 0, # current offset + cby: str = "desc", # current by + poff: int = 0, # past offset + pby: str = "desc", +): # past by + """Proposal listings.""" if not request.user.has_credential(creds.TU_LIST_VOTES): return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) @@ -81,40 +83,47 @@ async def trusted_user(request: Request, past_by = "desc" context["past_by"] = past_by - current_votes = db.query(models.TUVoteInfo).filter( - models.TUVoteInfo.End > ts).order_by( - models.TUVoteInfo.Submitted.desc()) + current_votes = ( + db.query(models.TUVoteInfo) + .filter(models.TUVoteInfo.End > ts) + .order_by(models.TUVoteInfo.Submitted.desc()) + ) context["current_votes_count"] = current_votes.count() current_votes = current_votes.limit(pp).offset(current_off) - context["current_votes"] = reversed(current_votes.all()) \ - if current_by == "asc" else current_votes.all() + context["current_votes"] = ( + reversed(current_votes.all()) if current_by == "asc" else current_votes.all() + ) context["current_off"] = current_off - past_votes = db.query(models.TUVoteInfo).filter( - models.TUVoteInfo.End <= ts).order_by( - models.TUVoteInfo.Submitted.desc()) + past_votes = ( + db.query(models.TUVoteInfo) + .filter(models.TUVoteInfo.End <= ts) + .order_by(models.TUVoteInfo.Submitted.desc()) + ) context["past_votes_count"] = past_votes.count() past_votes = past_votes.limit(pp).offset(past_off) - context["past_votes"] = reversed(past_votes.all()) \ - if past_by == "asc" else past_votes.all() + context["past_votes"] = ( + reversed(past_votes.all()) if past_by == "asc" else past_votes.all() + ) context["past_off"] = past_off last_vote = func.max(models.TUVote.VoteID).label("LastVote") - last_votes_by_tu = db.query(models.TUVote).join(models.User).join( - models.TUVoteInfo, - models.TUVoteInfo.ID == models.TUVote.VoteID - ).filter( - and_(models.TUVote.VoteID == models.TUVoteInfo.ID, - models.User.ID == models.TUVote.UserID, - models.TUVoteInfo.End < ts, - or_(models.User.AccountTypeID == 2, - models.User.AccountTypeID == 4)) - ).with_entities( - models.TUVote.UserID, - last_vote, - models.User.Username - ).group_by(models.TUVote.UserID).order_by( - last_vote.desc(), models.User.Username.asc()) + last_votes_by_tu = ( + db.query(models.TUVote) + .join(models.User) + .join(models.TUVoteInfo, models.TUVoteInfo.ID == models.TUVote.VoteID) + .filter( + and_( + models.TUVote.VoteID == models.TUVoteInfo.ID, + models.User.ID == models.TUVote.UserID, + models.TUVoteInfo.End < ts, + or_(models.User.AccountTypeID == 2, models.User.AccountTypeID == 4), + ) + ) + .with_entities(models.TUVote.UserID, last_vote, models.User.Username) + .group_by(models.TUVote.UserID) + .order_by(last_vote.desc(), models.User.Username.asc()) + ) context["last_votes_by_tu"] = last_votes_by_tu.all() context["current_by_next"] = "asc" if current_by == "desc" else "desc" @@ -126,18 +135,22 @@ async def trusted_user(request: Request, "coff": current_off, "cby": current_by, "poff": past_off, - "pby": past_by + "pby": past_by, } return render_template(request, "tu/index.html", context) -def render_proposal(request: Request, context: dict, proposal: int, - voteinfo: models.TUVoteInfo, - voters: typing.Iterable[models.User], - vote: models.TUVote, - status_code: HTTPStatus = HTTPStatus.OK): - """ Render a single TU proposal. """ +def render_proposal( + request: Request, + context: dict, + proposal: int, + voteinfo: models.TUVoteInfo, + voters: typing.Iterable[models.User], + vote: models.TUVote, + status_code: HTTPStatus = HTTPStatus.OK, +): + """Render a single TU proposal.""" context["proposal"] = proposal context["voteinfo"] = voteinfo context["voters"] = voters.all() @@ -146,8 +159,9 @@ def render_proposal(request: Request, context: dict, proposal: int, participation = (total / voteinfo.ActiveTUs) if voteinfo.ActiveTUs else 0 context["participation"] = participation - accepted = (voteinfo.Yes > voteinfo.ActiveTUs / 2) or \ - (participation > voteinfo.Quorum and voteinfo.Yes > voteinfo.No) + accepted = (voteinfo.Yes > voteinfo.ActiveTUs / 2) or ( + participation > voteinfo.Quorum and voteinfo.Yes > voteinfo.No + ) context["accepted"] = accepted can_vote = voters.filter(models.TUVote.User == request.user).first() is None @@ -159,8 +173,7 @@ def render_proposal(request: Request, context: dict, proposal: int, context["vote"] = vote context["has_voted"] = vote is not None - return render_template(request, "tu/show.html", context, - status_code=status_code) + return render_template(request, "tu/show.html", context, status_code=status_code) @router.get("/tu/{proposal}") @@ -172,16 +185,27 @@ async def trusted_user_proposal(request: Request, proposal: int): context = await make_variable_context(request, "Trusted User") proposal = int(proposal) - voteinfo = db.query(models.TUVoteInfo).filter( - models.TUVoteInfo.ID == proposal).first() + voteinfo = ( + db.query(models.TUVoteInfo).filter(models.TUVoteInfo.ID == proposal).first() + ) if not voteinfo: raise HTTPException(status_code=HTTPStatus.NOT_FOUND) - voters = db.query(models.User).join(models.TUVote).filter( - models.TUVote.VoteID == voteinfo.ID) - vote = db.query(models.TUVote).filter( - and_(models.TUVote.UserID == request.user.ID, - models.TUVote.VoteID == voteinfo.ID)).first() + voters = ( + db.query(models.User) + .join(models.TUVote) + .filter(models.TUVote.VoteID == voteinfo.ID) + ) + vote = ( + db.query(models.TUVote) + .filter( + and_( + models.TUVote.UserID == request.user.ID, + models.TUVote.VoteID == voteinfo.ID, + ) + ) + .first() + ) if not request.user.has_credential(creds.TU_VOTE): context["error"] = "Only Trusted Users are allowed to vote." if voteinfo.User == request.user.Username: @@ -196,24 +220,36 @@ async def trusted_user_proposal(request: Request, proposal: int): @router.post("/tu/{proposal}") @handle_form_exceptions @requires_auth -async def trusted_user_proposal_post(request: Request, proposal: int, - decision: str = Form(...)): +async def trusted_user_proposal_post( + request: Request, proposal: int, decision: str = Form(...) +): if not request.user.has_credential(creds.TU_LIST_VOTES): return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER) context = await make_variable_context(request, "Trusted User") proposal = int(proposal) # Make sure it's an int. - voteinfo = db.query(models.TUVoteInfo).filter( - models.TUVoteInfo.ID == proposal).first() + voteinfo = ( + db.query(models.TUVoteInfo).filter(models.TUVoteInfo.ID == proposal).first() + ) if not voteinfo: raise HTTPException(status_code=HTTPStatus.NOT_FOUND) - voters = db.query(models.User).join(models.TUVote).filter( - models.TUVote.VoteID == voteinfo.ID) - vote = db.query(models.TUVote).filter( - and_(models.TUVote.UserID == request.user.ID, - models.TUVote.VoteID == voteinfo.ID)).first() + voters = ( + db.query(models.User) + .join(models.TUVote) + .filter(models.TUVote.VoteID == voteinfo.ID) + ) + vote = ( + db.query(models.TUVote) + .filter( + and_( + models.TUVote.UserID == request.user.ID, + models.TUVote.VoteID == voteinfo.ID, + ) + ) + .first() + ) status_code = HTTPStatus.OK if not request.user.has_credential(creds.TU_VOTE): @@ -227,16 +263,15 @@ async def trusted_user_proposal_post(request: Request, proposal: int, status_code = HTTPStatus.BAD_REQUEST if status_code != HTTPStatus.OK: - return render_proposal(request, context, proposal, - voteinfo, voters, vote, - status_code=status_code) + return render_proposal( + request, context, proposal, voteinfo, voters, vote, status_code=status_code + ) if decision in {"Yes", "No", "Abstain"}: # Increment whichever decision was given to us. setattr(voteinfo, decision, getattr(voteinfo, decision) + 1) else: - return Response("Invalid 'decision' value.", - status_code=HTTPStatus.BAD_REQUEST) + return Response("Invalid 'decision' value.", status_code=HTTPStatus.BAD_REQUEST) with db.begin(): vote = db.create(models.TUVote, User=request.user, VoteInfo=voteinfo) @@ -247,8 +282,9 @@ async def trusted_user_proposal_post(request: Request, proposal: int, @router.get("/addvote") @requires_auth -async def trusted_user_addvote(request: Request, user: str = str(), - type: str = "add_tu", agenda: str = str()): +async def trusted_user_addvote( + request: Request, user: str = str(), type: str = "add_tu", agenda: str = str() +): if not request.user.has_credential(creds.TU_ADD_VOTE): return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER) @@ -268,10 +304,12 @@ async def trusted_user_addvote(request: Request, user: str = str(), @router.post("/addvote") @handle_form_exceptions @requires_auth -async def trusted_user_addvote_post(request: Request, - user: str = Form(default=str()), - type: str = Form(default=str()), - agenda: str = Form(default=str())): +async def trusted_user_addvote_post( + request: Request, + user: str = Form(default=str()), + type: str = Form(default=str()), + agenda: str = Form(default=str()), +): if not request.user.has_credential(creds.TU_ADD_VOTE): return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER) @@ -283,26 +321,29 @@ async def trusted_user_addvote_post(request: Request, context["agenda"] = agenda def render_addvote(context, status_code): - """ Simplify render_template a bit for this test. """ + """Simplify render_template a bit for this test.""" return render_template(request, "addvote.html", context, status_code) # Alright, get some database records, if we can. if type != "bylaws": - user_record = db.query(models.User).filter( - models.User.Username == user).first() + user_record = db.query(models.User).filter(models.User.Username == user).first() if user_record is None: context["error"] = "Username does not exist." return render_addvote(context, HTTPStatus.NOT_FOUND) utcnow = time.utcnow() - voteinfo = db.query(models.TUVoteInfo).filter( - and_(models.TUVoteInfo.User == user, - models.TUVoteInfo.End > utcnow)).count() + voteinfo = ( + db.query(models.TUVoteInfo) + .filter( + and_(models.TUVoteInfo.User == user, models.TUVoteInfo.End > utcnow) + ) + .count() + ) if voteinfo: _ = l10n.get_translator_for_request(request) - context["error"] = _( - "%s already has proposal running for them.") % ( - html.escape(user),) + context["error"] = _("%s already has proposal running for them.") % ( + html.escape(user), + ) return render_addvote(context, HTTPStatus.BAD_REQUEST) if type not in ADDVOTE_SPECIFICS: @@ -323,16 +364,27 @@ async def trusted_user_addvote_post(request: Request, # Create a new TUVoteInfo (proposal)! with db.begin(): - active_tus = db.query(User).filter( - and_(User.Suspended == 0, - User.InactivityTS.isnot(None), - User.AccountTypeID.in_(types)) - ).count() - voteinfo = db.create(models.TUVoteInfo, User=user, - Agenda=html.escape(agenda), - Submitted=timestamp, End=(timestamp + duration), - Quorum=quorum, ActiveTUs=active_tus, - Submitter=request.user) + active_tus = ( + db.query(User) + .filter( + and_( + User.Suspended == 0, + User.InactivityTS.isnot(None), + User.AccountTypeID.in_(types), + ) + ) + .count() + ) + voteinfo = db.create( + models.TUVoteInfo, + User=user, + Agenda=html.escape(agenda), + Submitted=timestamp, + End=(timestamp + duration), + Quorum=quorum, + ActiveTUs=active_tus, + Submitter=request.user, + ) # Redirect to the new proposal. endpoint = f"/tu/{voteinfo.ID}" diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 3ea7e070..26677f80 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -1,5 +1,4 @@ import os - from collections import defaultdict from typing import Any, Callable, NewType, Union @@ -7,7 +6,6 @@ from fastapi.responses import HTMLResponse from sqlalchemy import and_, literal, orm import aurweb.config as config - from aurweb import db, defaults, models from aurweb.exceptions import RPCError from aurweb.filters import number_format @@ -23,8 +21,7 @@ TYPE_MAPPING = { "replaces": "Replaces", } -DataGenerator = NewType("DataGenerator", - Callable[[models.Package], dict[str, Any]]) +DataGenerator = NewType("DataGenerator", Callable[[models.Package], dict[str, Any]]) def documentation(): @@ -40,7 +37,7 @@ def documentation(): class RPC: - """ RPC API handler class. + """RPC API handler class. There are various pieces to RPC's process, and encapsulating them inside of a class means that external users do not abuse the @@ -66,17 +63,25 @@ class RPC: # A set of RPC types supported by this API. EXPOSED_TYPES = { - "info", "multiinfo", - "search", "msearch", - "suggest", "suggest-pkgbase" + "info", + "multiinfo", + "search", + "msearch", + "suggest", + "suggest-pkgbase", } # A mapping of type aliases. TYPE_ALIASES = {"info": "multiinfo"} EXPOSED_BYS = { - "name-desc", "name", "maintainer", - "depends", "makedepends", "optdepends", "checkdepends" + "name-desc", + "name", + "maintainer", + "depends", + "makedepends", + "optdepends", + "checkdepends", } # A mapping of by aliases. @@ -92,7 +97,7 @@ class RPC: "results": [], "resultcount": 0, "type": "error", - "error": message + "error": message, } def _verify_inputs(self, by: str = [], args: list[str] = []) -> None: @@ -116,7 +121,7 @@ class RPC: raise RPCError("No request type/data specified.") def _get_json_data(self, package: models.Package) -> dict[str, Any]: - """ Produce dictionary data of one Package that can be JSON-serialized. + """Produce dictionary data of one Package that can be JSON-serialized. :param package: Package instance :returns: JSON-serializable dictionary @@ -143,7 +148,7 @@ class RPC: "Popularity": pop, "OutOfDate": package.OutOfDateTS, "FirstSubmitted": package.SubmittedTS, - "LastModified": package.ModifiedTS + "LastModified": package.ModifiedTS, } def _get_info_json_data(self, package: models.Package) -> dict[str, Any]: @@ -151,10 +156,7 @@ class RPC: # All info results have _at least_ an empty list of # License and Keywords. - data.update({ - "License": [], - "Keywords": [] - }) + data.update({"License": [], "Keywords": []}) # If we actually got extra_info records, update data with # them for this particular package. @@ -163,9 +165,9 @@ class RPC: return data - def _assemble_json_data(self, packages: list[models.Package], - data_generator: DataGenerator) \ - -> list[dict[str, Any]]: + def _assemble_json_data( + self, packages: list[models.Package], data_generator: DataGenerator + ) -> list[dict[str, Any]]: """ Assemble JSON data out of a list of packages. @@ -175,7 +177,7 @@ class RPC: return [data_generator(pkg) for pkg in packages] def _entities(self, query: orm.Query) -> orm.Query: - """ Select specific RPC columns on `query`. """ + """Select specific RPC columns on `query`.""" return query.with_entities( models.Package.ID, models.Package.Name, @@ -192,16 +194,22 @@ class RPC: models.User.Username.label("Maintainer"), ).group_by(models.Package.ID) - def _handle_multiinfo_type(self, args: list[str] = [], **kwargs) \ - -> list[dict[str, Any]]: + def _handle_multiinfo_type( + self, args: list[str] = [], **kwargs + ) -> list[dict[str, Any]]: self._enforce_args(args) args = set(args) - packages = db.query(models.Package).join(models.PackageBase).join( - models.User, - models.User.ID == models.PackageBase.MaintainerUID, - isouter=True - ).filter(models.Package.Name.in_(args)) + packages = ( + db.query(models.Package) + .join(models.PackageBase) + .join( + models.User, + models.User.ID == models.PackageBase.MaintainerUID, + isouter=True, + ) + .filter(models.Package.Name.in_(args)) + ) max_results = config.getint("options", "max_rpc_results") packages = self._entities(packages).limit(max_results + 1) @@ -217,65 +225,75 @@ class RPC: subqueries = [ # PackageDependency - db.query( - models.PackageDependency - ).join(models.DependencyType).filter( - models.PackageDependency.PackageID.in_(ids) - ).with_entities( + db.query(models.PackageDependency) + .join(models.DependencyType) + .filter(models.PackageDependency.PackageID.in_(ids)) + .with_entities( models.PackageDependency.PackageID.label("ID"), models.DependencyType.Name.label("Type"), models.PackageDependency.DepName.label("Name"), - models.PackageDependency.DepCondition.label("Cond") - ).distinct().order_by("Name"), - + models.PackageDependency.DepCondition.label("Cond"), + ) + .distinct() + .order_by("Name"), # PackageRelation - db.query( - models.PackageRelation - ).join(models.RelationType).filter( - models.PackageRelation.PackageID.in_(ids) - ).with_entities( + db.query(models.PackageRelation) + .join(models.RelationType) + .filter(models.PackageRelation.PackageID.in_(ids)) + .with_entities( models.PackageRelation.PackageID.label("ID"), models.RelationType.Name.label("Type"), models.PackageRelation.RelName.label("Name"), - models.PackageRelation.RelCondition.label("Cond") - ).distinct().order_by("Name"), - + models.PackageRelation.RelCondition.label("Cond"), + ) + .distinct() + .order_by("Name"), # Groups - db.query(models.PackageGroup).join( + db.query(models.PackageGroup) + .join( models.Group, - and_(models.PackageGroup.GroupID == models.Group.ID, - models.PackageGroup.PackageID.in_(ids)) - ).with_entities( + and_( + models.PackageGroup.GroupID == models.Group.ID, + models.PackageGroup.PackageID.in_(ids), + ), + ) + .with_entities( models.PackageGroup.PackageID.label("ID"), literal("Groups").label("Type"), models.Group.Name.label("Name"), - literal(str()).label("Cond") - ).distinct().order_by("Name"), - + literal(str()).label("Cond"), + ) + .distinct() + .order_by("Name"), # Licenses - db.query(models.PackageLicense).join( - models.License, - models.PackageLicense.LicenseID == models.License.ID - ).filter( - models.PackageLicense.PackageID.in_(ids) - ).with_entities( + db.query(models.PackageLicense) + .join(models.License, models.PackageLicense.LicenseID == models.License.ID) + .filter(models.PackageLicense.PackageID.in_(ids)) + .with_entities( models.PackageLicense.PackageID.label("ID"), literal("License").label("Type"), models.License.Name.label("Name"), - literal(str()).label("Cond") - ).distinct().order_by("Name"), - + literal(str()).label("Cond"), + ) + .distinct() + .order_by("Name"), # Keywords - db.query(models.PackageKeyword).join( + db.query(models.PackageKeyword) + .join( models.Package, - and_(Package.PackageBaseID == PackageKeyword.PackageBaseID, - Package.ID.in_(ids)) - ).with_entities( + and_( + Package.PackageBaseID == PackageKeyword.PackageBaseID, + Package.ID.in_(ids), + ), + ) + .with_entities( models.Package.ID.label("ID"), literal("Keywords").label("Type"), models.PackageKeyword.Keyword.label("Name"), - literal(str()).label("Cond") - ).distinct().order_by("Name") + literal(str()).label("Cond"), + ) + .distinct() + .order_by("Name"), ] # Union all subqueries together. @@ -295,8 +313,9 @@ class RPC: return self._assemble_json_data(packages, self._get_info_json_data) - def _handle_search_type(self, by: str = defaults.RPC_SEARCH_BY, - args: list[str] = []) -> list[dict[str, Any]]: + def _handle_search_type( + self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = [] + ) -> list[dict[str, Any]]: # If `by` isn't maintainer and we don't have any args, raise an error. # In maintainer's case, return all orphans if there are no args, # so we need args to pass through to the handler without errors. @@ -318,50 +337,64 @@ class RPC: return self._assemble_json_data(results, self._get_json_data) - def _handle_msearch_type(self, args: list[str] = [], **kwargs)\ - -> list[dict[str, Any]]: + def _handle_msearch_type( + self, args: list[str] = [], **kwargs + ) -> list[dict[str, Any]]: return self._handle_search_type(by="m", args=args) - def _handle_suggest_type(self, args: list[str] = [], **kwargs)\ - -> list[str]: + def _handle_suggest_type(self, args: list[str] = [], **kwargs) -> list[str]: if not args: return [] arg = args[0] - packages = db.query(models.Package.Name).join( - models.PackageBase - ).filter( - and_(models.PackageBase.PackagerUID.isnot(None), - models.Package.Name.like(f"{arg}%")) - ).order_by(models.Package.Name.asc()).limit(20) + packages = ( + db.query(models.Package.Name) + .join(models.PackageBase) + .filter( + and_( + models.PackageBase.PackagerUID.isnot(None), + models.Package.Name.like(f"{arg}%"), + ) + ) + .order_by(models.Package.Name.asc()) + .limit(20) + ) return [pkg.Name for pkg in packages] - def _handle_suggest_pkgbase_type(self, args: list[str] = [], **kwargs)\ - -> list[str]: + def _handle_suggest_pkgbase_type(self, args: list[str] = [], **kwargs) -> list[str]: if not args: return [] arg = args[0] - packages = db.query(models.PackageBase.Name).filter( - and_(models.PackageBase.PackagerUID.isnot(None), - models.PackageBase.Name.like(f"{arg}%")) - ).order_by(models.PackageBase.Name.asc()).limit(20) + packages = ( + db.query(models.PackageBase.Name) + .filter( + and_( + models.PackageBase.PackagerUID.isnot(None), + models.PackageBase.Name.like(f"{arg}%"), + ) + ) + .order_by(models.PackageBase.Name.asc()) + .limit(20) + ) return [pkg.Name for pkg in packages] def _is_suggestion(self) -> bool: return self.type.startswith("suggest") - def _handle_callback(self, by: str, args: list[str])\ - -> Union[list[dict[str, Any]], list[str]]: + def _handle_callback( + self, by: str, args: list[str] + ) -> Union[list[dict[str, Any]], list[str]]: # Get a handle to our callback and trap an RPCError with # an empty list of results based on callback's execution. callback = getattr(self, f"_handle_{self.type.replace('-', '_')}_type") results = callback(by=by, args=args) return results - def handle(self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = [])\ - -> Union[list[dict[str, Any]], dict[str, Any]]: - """ Request entrypoint. A router should pass v, type and args + def handle( + self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = [] + ) -> Union[list[dict[str, Any]], dict[str, Any]]: + """Request entrypoint. A router should pass v, type and args to this function and expect an output dictionary to be returned. :param v: RPC version argument @@ -392,8 +425,5 @@ class RPC: return results # Return JSON output. - data.update({ - "resultcount": len(results), - "results": results - }) + data.update({"resultcount": len(results), "results": results}) return data diff --git a/aurweb/schema.py b/aurweb/schema.py index d2644541..b3b36195 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -6,7 +6,18 @@ usually be automatically generated. See `migrations/README` for details. """ -from sqlalchemy import CHAR, TIMESTAMP, Column, ForeignKey, Index, MetaData, String, Table, Text, text +from sqlalchemy import ( + CHAR, + TIMESTAMP, + Column, + ForeignKey, + Index, + MetaData, + String, + Table, + Text, + text, +) from sqlalchemy.dialects.mysql import BIGINT, DECIMAL, INTEGER, TINYINT from sqlalchemy.ext.compiler import compiles @@ -15,13 +26,13 @@ import aurweb.config db_backend = aurweb.config.get("database", "backend") -@compiles(TINYINT, 'sqlite') +@compiles(TINYINT, "sqlite") def compile_tinyint_sqlite(type_, compiler, **kw): # pragma: no cover """TINYINT is not supported on SQLite. Substitute it with INTEGER.""" - return 'INTEGER' + return "INTEGER" -@compiles(BIGINT, 'sqlite') +@compiles(BIGINT, "sqlite") def compile_bigint_sqlite(type_, compiler, **kw): # pragma: no cover """ For SQLite's AUTOINCREMENT to work on BIGINT columns, we need to map BIGINT @@ -29,429 +40,567 @@ def compile_bigint_sqlite(type_, compiler, **kw): # pragma: no cover See https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#allowing-autoincrement-behavior-sqlalchemy-types-other-than-integer-integer """ # noqa: E501 - return 'INTEGER' + return "INTEGER" metadata = MetaData() # Define the Account Types for the AUR. AccountTypes = Table( - 'AccountTypes', metadata, - Column('ID', TINYINT(unsigned=True), primary_key=True), - Column('AccountType', String(32), nullable=False, server_default=text("''")), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci' + "AccountTypes", + metadata, + Column("ID", TINYINT(unsigned=True), primary_key=True), + Column("AccountType", String(32), nullable=False, server_default=text("''")), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # User information for each user regardless of type. Users = Table( - 'Users', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('AccountTypeID', ForeignKey('AccountTypes.ID', ondelete="NO ACTION"), nullable=False, server_default=text("1")), - Column('Suspended', TINYINT(unsigned=True), nullable=False, server_default=text("0")), - Column('Username', String(32), nullable=False, unique=True), - Column('Email', String(254), nullable=False, unique=True), - Column('BackupEmail', String(254)), - Column('HideEmail', TINYINT(unsigned=True), nullable=False, server_default=text("0")), - Column('Passwd', String(255), nullable=False), - Column('Salt', CHAR(32), nullable=False, server_default=text("''")), - Column('ResetKey', CHAR(32), nullable=False, server_default=text("''")), - Column('RealName', String(64), nullable=False, server_default=text("''")), - Column('LangPreference', String(6), nullable=False, server_default=text("'en'")), - Column('Timezone', String(32), nullable=False, server_default=text("'UTC'")), - Column('Homepage', Text), - Column('IRCNick', String(32), nullable=False, server_default=text("''")), - Column('PGPKey', String(40)), - Column('LastLogin', BIGINT(unsigned=True), nullable=False, server_default=text("0")), - Column('LastLoginIPAddress', String(45)), - Column('LastSSHLogin', BIGINT(unsigned=True), nullable=False, server_default=text("0")), - Column('LastSSHLoginIPAddress', String(45)), - Column('InactivityTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), - Column('RegistrationTS', TIMESTAMP, nullable=False, server_default=text("CURRENT_TIMESTAMP")), - Column('CommentNotify', TINYINT(1), nullable=False, server_default=text("1")), - Column('UpdateNotify', TINYINT(1), nullable=False, server_default=text("0")), - Column('OwnershipNotify', TINYINT(1), nullable=False, server_default=text("1")), - Column('SSOAccountID', String(255), nullable=True, unique=True), - Index('UsersAccountTypeID', 'AccountTypeID'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "Users", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column( + "AccountTypeID", + ForeignKey("AccountTypes.ID", ondelete="NO ACTION"), + nullable=False, + server_default=text("1"), + ), + Column( + "Suspended", TINYINT(unsigned=True), nullable=False, server_default=text("0") + ), + Column("Username", String(32), nullable=False, unique=True), + Column("Email", String(254), nullable=False, unique=True), + Column("BackupEmail", String(254)), + Column( + "HideEmail", TINYINT(unsigned=True), nullable=False, server_default=text("0") + ), + Column("Passwd", String(255), nullable=False), + Column("Salt", CHAR(32), nullable=False, server_default=text("''")), + Column("ResetKey", CHAR(32), nullable=False, server_default=text("''")), + Column("RealName", String(64), nullable=False, server_default=text("''")), + Column("LangPreference", String(6), nullable=False, server_default=text("'en'")), + Column("Timezone", String(32), nullable=False, server_default=text("'UTC'")), + Column("Homepage", Text), + Column("IRCNick", String(32), nullable=False, server_default=text("''")), + Column("PGPKey", String(40)), + Column( + "LastLogin", BIGINT(unsigned=True), nullable=False, server_default=text("0") + ), + Column("LastLoginIPAddress", String(45)), + Column( + "LastSSHLogin", BIGINT(unsigned=True), nullable=False, server_default=text("0") + ), + Column("LastSSHLoginIPAddress", String(45)), + Column( + "InactivityTS", BIGINT(unsigned=True), nullable=False, server_default=text("0") + ), + Column( + "RegistrationTS", + TIMESTAMP, + nullable=False, + server_default=text("CURRENT_TIMESTAMP"), + ), + Column("CommentNotify", TINYINT(1), nullable=False, server_default=text("1")), + Column("UpdateNotify", TINYINT(1), nullable=False, server_default=text("0")), + Column("OwnershipNotify", TINYINT(1), nullable=False, server_default=text("1")), + Column("SSOAccountID", String(255), nullable=True, unique=True), + Index("UsersAccountTypeID", "AccountTypeID"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # SSH public keys used for the aurweb SSH/Git interface. SSHPubKeys = Table( - 'SSHPubKeys', metadata, - Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - Column('Fingerprint', String(44), primary_key=True), - Column('PubKey', String(4096), nullable=False), - mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', + "SSHPubKeys", + metadata, + Column("UserID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + Column("Fingerprint", String(44), primary_key=True), + Column("PubKey", String(4096), nullable=False), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_bin", ) # Track Users logging in/out of AUR web site. Sessions = Table( - 'Sessions', metadata, - Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - Column('SessionID', CHAR(32), nullable=False, unique=True), - Column('LastUpdateTS', BIGINT(unsigned=True), nullable=False), - mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', + "Sessions", + metadata, + Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + Column("SessionID", CHAR(32), nullable=False, unique=True), + Column("LastUpdateTS", BIGINT(unsigned=True), nullable=False), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_bin", ) # Information on package bases PackageBases = Table( - 'PackageBases', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('Name', String(255), nullable=False, unique=True), - Column('NumVotes', INTEGER(unsigned=True), nullable=False, server_default=text("0")), - Column('Popularity', - DECIMAL(10, 6, unsigned=True) - if db_backend == "mysql" else String(17), - nullable=False, server_default=text("0")), - Column('OutOfDateTS', BIGINT(unsigned=True)), - Column('FlaggerComment', Text, nullable=False), - Column('SubmittedTS', BIGINT(unsigned=True), nullable=False), - Column('ModifiedTS', BIGINT(unsigned=True), nullable=False), - Column('FlaggerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # who flagged the package out-of-date? + "PackageBases", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column("Name", String(255), nullable=False, unique=True), + Column( + "NumVotes", INTEGER(unsigned=True), nullable=False, server_default=text("0") + ), + Column( + "Popularity", + DECIMAL(10, 6, unsigned=True) if db_backend == "mysql" else String(17), + nullable=False, + server_default=text("0"), + ), + Column("OutOfDateTS", BIGINT(unsigned=True)), + Column("FlaggerComment", Text, nullable=False), + Column("SubmittedTS", BIGINT(unsigned=True), nullable=False), + Column("ModifiedTS", BIGINT(unsigned=True), nullable=False), + Column( + "FlaggerUID", ForeignKey("Users.ID", ondelete="SET NULL") + ), # who flagged the package out-of-date? # deleting a user will cause packages to be orphaned, not deleted - Column('SubmitterUID', ForeignKey('Users.ID', ondelete='SET NULL')), # who submitted it? - Column('MaintainerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # User - Column('PackagerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # Last packager - Index('BasesMaintainerUID', 'MaintainerUID'), - Index('BasesNumVotes', 'NumVotes'), - Index('BasesPackagerUID', 'PackagerUID'), - Index('BasesSubmitterUID', 'SubmitterUID'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + Column( + "SubmitterUID", ForeignKey("Users.ID", ondelete="SET NULL") + ), # who submitted it? + Column("MaintainerUID", ForeignKey("Users.ID", ondelete="SET NULL")), # User + Column("PackagerUID", ForeignKey("Users.ID", ondelete="SET NULL")), # Last packager + Index("BasesMaintainerUID", "MaintainerUID"), + Index("BasesNumVotes", "NumVotes"), + Index("BasesPackagerUID", "PackagerUID"), + Index("BasesSubmitterUID", "SubmitterUID"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Keywords of package bases PackageKeywords = Table( - 'PackageKeywords', metadata, - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), primary_key=True, nullable=True), - Column('Keyword', String(255), primary_key=True, nullable=False, server_default=text("''")), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "PackageKeywords", + metadata, + Column( + "PackageBaseID", + ForeignKey("PackageBases.ID", ondelete="CASCADE"), + primary_key=True, + nullable=True, + ), + Column( + "Keyword", + String(255), + primary_key=True, + nullable=False, + server_default=text("''"), + ), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Information about the actual packages Packages = Table( - 'Packages', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), - Column('Name', String(255), nullable=False, unique=True), - Column('Version', String(255), nullable=False, server_default=text("''")), - Column('Description', String(255)), - Column('URL', String(8000)), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "Packages", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column( + "PackageBaseID", + ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False, + ), + Column("Name", String(255), nullable=False, unique=True), + Column("Version", String(255), nullable=False, server_default=text("''")), + Column("Description", String(255)), + Column("URL", String(8000)), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Information about licenses Licenses = Table( - 'Licenses', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('Name', String(255), nullable=False, unique=True), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "Licenses", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column("Name", String(255), nullable=False, unique=True), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Information about package-license-relations PackageLicenses = Table( - 'PackageLicenses', metadata, - Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=True), - Column('LicenseID', ForeignKey('Licenses.ID', ondelete='CASCADE'), primary_key=True, nullable=True), - mysql_engine='InnoDB', + "PackageLicenses", + metadata, + Column( + "PackageID", + ForeignKey("Packages.ID", ondelete="CASCADE"), + primary_key=True, + nullable=True, + ), + Column( + "LicenseID", + ForeignKey("Licenses.ID", ondelete="CASCADE"), + primary_key=True, + nullable=True, + ), + mysql_engine="InnoDB", ) # Information about groups Groups = Table( - 'Groups', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('Name', String(255), nullable=False, unique=True), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "Groups", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column("Name", String(255), nullable=False, unique=True), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Information about package-group-relations PackageGroups = Table( - 'PackageGroups', metadata, - Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=True), - Column('GroupID', ForeignKey('Groups.ID', ondelete='CASCADE'), primary_key=True, nullable=True), - mysql_engine='InnoDB', + "PackageGroups", + metadata, + Column( + "PackageID", + ForeignKey("Packages.ID", ondelete="CASCADE"), + primary_key=True, + nullable=True, + ), + Column( + "GroupID", + ForeignKey("Groups.ID", ondelete="CASCADE"), + primary_key=True, + nullable=True, + ), + mysql_engine="InnoDB", ) # Define the package dependency types DependencyTypes = Table( - 'DependencyTypes', metadata, - Column('ID', TINYINT(unsigned=True), primary_key=True), - Column('Name', String(32), nullable=False, server_default=text("''")), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "DependencyTypes", + metadata, + Column("ID", TINYINT(unsigned=True), primary_key=True), + Column("Name", String(32), nullable=False, server_default=text("''")), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Track which dependencies a package has PackageDepends = Table( - 'PackageDepends', metadata, - Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False), - Column('DepTypeID', ForeignKey('DependencyTypes.ID', ondelete="NO ACTION"), nullable=False), - Column('DepName', String(255), nullable=False), - Column('DepDesc', String(255)), - Column('DepCondition', String(255)), - Column('DepArch', String(255)), - Index('DependsDepName', 'DepName'), - Index('DependsPackageID', 'PackageID'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "PackageDepends", + metadata, + Column("PackageID", ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False), + Column( + "DepTypeID", + ForeignKey("DependencyTypes.ID", ondelete="NO ACTION"), + nullable=False, + ), + Column("DepName", String(255), nullable=False), + Column("DepDesc", String(255)), + Column("DepCondition", String(255)), + Column("DepArch", String(255)), + Index("DependsDepName", "DepName"), + Index("DependsPackageID", "PackageID"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Define the package relation types RelationTypes = Table( - 'RelationTypes', metadata, - Column('ID', TINYINT(unsigned=True), primary_key=True), - Column('Name', String(32), nullable=False, server_default=text("''")), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "RelationTypes", + metadata, + Column("ID", TINYINT(unsigned=True), primary_key=True), + Column("Name", String(32), nullable=False, server_default=text("''")), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Track which conflicts, provides and replaces a package has PackageRelations = Table( - 'PackageRelations', metadata, - Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False), - Column('RelTypeID', ForeignKey('RelationTypes.ID', ondelete="NO ACTION"), nullable=False), - Column('RelName', String(255), nullable=False), - Column('RelCondition', String(255)), - Column('RelArch', String(255)), - Index('RelationsPackageID', 'PackageID'), - Index('RelationsRelName', 'RelName'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "PackageRelations", + metadata, + Column("PackageID", ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False), + Column( + "RelTypeID", + ForeignKey("RelationTypes.ID", ondelete="NO ACTION"), + nullable=False, + ), + Column("RelName", String(255), nullable=False), + Column("RelCondition", String(255)), + Column("RelArch", String(255)), + Index("RelationsPackageID", "PackageID"), + Index("RelationsRelName", "RelName"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Track which sources a package has PackageSources = Table( - 'PackageSources', metadata, - Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False), - Column('Source', String(8000), nullable=False, server_default=text("'/dev/null'")), - Column('SourceArch', String(255)), - Index('SourcesPackageID', 'PackageID'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "PackageSources", + metadata, + Column("PackageID", ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False), + Column("Source", String(8000), nullable=False, server_default=text("'/dev/null'")), + Column("SourceArch", String(255)), + Index("SourcesPackageID", "PackageID"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Track votes for packages PackageVotes = Table( - 'PackageVotes', metadata, - Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), - Column('VoteTS', BIGINT(unsigned=True), nullable=False), - Index('VoteUsersIDPackageID', 'UsersID', 'PackageBaseID', unique=True), - Index('VotesPackageBaseID', 'PackageBaseID'), - Index('VotesUsersID', 'UsersID'), - mysql_engine='InnoDB', + "PackageVotes", + metadata, + Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + Column( + "PackageBaseID", + ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False, + ), + Column("VoteTS", BIGINT(unsigned=True), nullable=False), + Index("VoteUsersIDPackageID", "UsersID", "PackageBaseID", unique=True), + Index("VotesPackageBaseID", "PackageBaseID"), + Index("VotesUsersID", "UsersID"), + mysql_engine="InnoDB", ) # Record comments for packages PackageComments = Table( - 'PackageComments', metadata, - Column('ID', BIGINT(unsigned=True), primary_key=True), - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), - Column('UsersID', ForeignKey('Users.ID', ondelete='SET NULL')), - Column('Comments', Text, nullable=False), - Column('RenderedComment', Text, nullable=False), - Column('CommentTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), - Column('EditedTS', BIGINT(unsigned=True)), - Column('EditedUsersID', ForeignKey('Users.ID', ondelete='SET NULL')), - Column('DelTS', BIGINT(unsigned=True)), - Column('DelUsersID', ForeignKey('Users.ID', ondelete='CASCADE')), - Column('PinnedTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), - Index('CommentsPackageBaseID', 'PackageBaseID'), - Index('CommentsUsersID', 'UsersID'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "PackageComments", + metadata, + Column("ID", BIGINT(unsigned=True), primary_key=True), + Column( + "PackageBaseID", + ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False, + ), + Column("UsersID", ForeignKey("Users.ID", ondelete="SET NULL")), + Column("Comments", Text, nullable=False), + Column("RenderedComment", Text, nullable=False), + Column( + "CommentTS", BIGINT(unsigned=True), nullable=False, server_default=text("0") + ), + Column("EditedTS", BIGINT(unsigned=True)), + Column("EditedUsersID", ForeignKey("Users.ID", ondelete="SET NULL")), + Column("DelTS", BIGINT(unsigned=True)), + Column("DelUsersID", ForeignKey("Users.ID", ondelete="CASCADE")), + Column("PinnedTS", BIGINT(unsigned=True), nullable=False, server_default=text("0")), + Index("CommentsPackageBaseID", "PackageBaseID"), + Index("CommentsUsersID", "UsersID"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Package base co-maintainers PackageComaintainers = Table( - 'PackageComaintainers', metadata, - Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), - Column('Priority', INTEGER(unsigned=True), nullable=False), - Index('ComaintainersPackageBaseID', 'PackageBaseID'), - Index('ComaintainersUsersID', 'UsersID'), - mysql_engine='InnoDB', + "PackageComaintainers", + metadata, + Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + Column( + "PackageBaseID", + ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False, + ), + Column("Priority", INTEGER(unsigned=True), nullable=False), + Index("ComaintainersPackageBaseID", "PackageBaseID"), + Index("ComaintainersUsersID", "UsersID"), + mysql_engine="InnoDB", ) # Package base notifications PackageNotifications = Table( - 'PackageNotifications', metadata, - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), - Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - Index('NotifyUserIDPkgID', 'UserID', 'PackageBaseID', unique=True), - mysql_engine='InnoDB', + "PackageNotifications", + metadata, + Column( + "PackageBaseID", + ForeignKey("PackageBases.ID", ondelete="CASCADE"), + nullable=False, + ), + Column("UserID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + Index("NotifyUserIDPkgID", "UserID", "PackageBaseID", unique=True), + mysql_engine="InnoDB", ) # Package name blacklist PackageBlacklist = Table( - 'PackageBlacklist', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('Name', String(64), nullable=False, unique=True), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "PackageBlacklist", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column("Name", String(64), nullable=False, unique=True), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Providers in the official repositories OfficialProviders = Table( - 'OfficialProviders', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('Name', String(64), nullable=False), - Column('Repo', String(64), nullable=False), - Column('Provides', String(64), nullable=False), - Index('ProviderNameProvides', 'Name', 'Provides', unique=True), - mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin', + "OfficialProviders", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column("Name", String(64), nullable=False), + Column("Repo", String(64), nullable=False), + Column("Provides", String(64), nullable=False), + Index("ProviderNameProvides", "Name", "Provides", unique=True), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_bin", ) # Define package request types RequestTypes = Table( - 'RequestTypes', metadata, - Column('ID', TINYINT(unsigned=True), primary_key=True), - Column('Name', String(32), nullable=False, server_default=text("''")), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "RequestTypes", + metadata, + Column("ID", TINYINT(unsigned=True), primary_key=True), + Column("Name", String(32), nullable=False, server_default=text("''")), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Package requests PackageRequests = Table( - 'PackageRequests', metadata, - Column('ID', BIGINT(unsigned=True), primary_key=True), - Column('ReqTypeID', ForeignKey('RequestTypes.ID', ondelete="NO ACTION"), nullable=False), - Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='SET NULL')), - Column('PackageBaseName', String(255), nullable=False), - Column('MergeBaseName', String(255)), - Column('UsersID', ForeignKey('Users.ID', ondelete='SET NULL')), - Column('Comments', Text, nullable=False), - Column('ClosureComment', Text, nullable=False), - Column('RequestTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")), - Column('ClosedTS', BIGINT(unsigned=True)), - Column('ClosedUID', ForeignKey('Users.ID', ondelete='SET NULL')), - Column('Status', TINYINT(unsigned=True), nullable=False, server_default=text("0")), - Index('RequestsPackageBaseID', 'PackageBaseID'), - Index('RequestsUsersID', 'UsersID'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "PackageRequests", + metadata, + Column("ID", BIGINT(unsigned=True), primary_key=True), + Column( + "ReqTypeID", ForeignKey("RequestTypes.ID", ondelete="NO ACTION"), nullable=False + ), + Column("PackageBaseID", ForeignKey("PackageBases.ID", ondelete="SET NULL")), + Column("PackageBaseName", String(255), nullable=False), + Column("MergeBaseName", String(255)), + Column("UsersID", ForeignKey("Users.ID", ondelete="SET NULL")), + Column("Comments", Text, nullable=False), + Column("ClosureComment", Text, nullable=False), + Column( + "RequestTS", BIGINT(unsigned=True), nullable=False, server_default=text("0") + ), + Column("ClosedTS", BIGINT(unsigned=True)), + Column("ClosedUID", ForeignKey("Users.ID", ondelete="SET NULL")), + Column("Status", TINYINT(unsigned=True), nullable=False, server_default=text("0")), + Index("RequestsPackageBaseID", "PackageBaseID"), + Index("RequestsUsersID", "UsersID"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Vote information TU_VoteInfo = Table( - 'TU_VoteInfo', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('Agenda', Text, nullable=False), - Column('User', String(32), nullable=False), - Column('Submitted', BIGINT(unsigned=True), nullable=False), - Column('End', BIGINT(unsigned=True), nullable=False), - Column('Quorum', - DECIMAL(2, 2, unsigned=True) - if db_backend == "mysql" else String(5), - nullable=False), - Column('SubmitterID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - Column('Yes', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")), - Column('No', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")), - Column('Abstain', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")), - Column('ActiveTUs', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "TU_VoteInfo", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column("Agenda", Text, nullable=False), + Column("User", String(32), nullable=False), + Column("Submitted", BIGINT(unsigned=True), nullable=False), + Column("End", BIGINT(unsigned=True), nullable=False), + Column( + "Quorum", + DECIMAL(2, 2, unsigned=True) if db_backend == "mysql" else String(5), + nullable=False, + ), + Column("SubmitterID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + Column("Yes", INTEGER(unsigned=True), nullable=False, server_default=text("'0'")), + Column("No", INTEGER(unsigned=True), nullable=False, server_default=text("'0'")), + Column( + "Abstain", INTEGER(unsigned=True), nullable=False, server_default=text("'0'") + ), + Column( + "ActiveTUs", INTEGER(unsigned=True), nullable=False, server_default=text("'0'") + ), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Individual vote records TU_Votes = Table( - 'TU_Votes', metadata, - Column('VoteID', ForeignKey('TU_VoteInfo.ID', ondelete='CASCADE'), nullable=False), - Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - mysql_engine='InnoDB', + "TU_Votes", + metadata, + Column("VoteID", ForeignKey("TU_VoteInfo.ID", ondelete="CASCADE"), nullable=False), + Column("UserID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + mysql_engine="InnoDB", ) # Malicious user banning Bans = Table( - 'Bans', metadata, - Column('IPAddress', String(45), primary_key=True), - Column('BanTS', TIMESTAMP, nullable=False), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "Bans", + metadata, + Column("IPAddress", String(45), primary_key=True), + Column("BanTS", TIMESTAMP, nullable=False), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Terms and Conditions Terms = Table( - 'Terms', metadata, - Column('ID', INTEGER(unsigned=True), primary_key=True), - Column('Description', String(255), nullable=False), - Column('URL', String(8000), nullable=False), - Column('Revision', INTEGER(unsigned=True), nullable=False, server_default=text("1")), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "Terms", + metadata, + Column("ID", INTEGER(unsigned=True), primary_key=True), + Column("Description", String(255), nullable=False), + Column("URL", String(8000), nullable=False), + Column( + "Revision", INTEGER(unsigned=True), nullable=False, server_default=text("1") + ), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) # Terms and Conditions accepted by users AcceptedTerms = Table( - 'AcceptedTerms', metadata, - Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), - Column('TermsID', ForeignKey('Terms.ID', ondelete='CASCADE'), nullable=False), - Column('Revision', INTEGER(unsigned=True), nullable=False, server_default=text("0")), - mysql_engine='InnoDB', + "AcceptedTerms", + metadata, + Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False), + Column("TermsID", ForeignKey("Terms.ID", ondelete="CASCADE"), nullable=False), + Column( + "Revision", INTEGER(unsigned=True), nullable=False, server_default=text("0") + ), + mysql_engine="InnoDB", ) # Rate limits for API ApiRateLimit = Table( - 'ApiRateLimit', metadata, - Column('IP', String(45), primary_key=True, unique=True, default=str()), - Column('Requests', INTEGER(11), nullable=False), - Column('WindowStart', BIGINT(20), nullable=False), - Index('ApiRateLimitWindowStart', 'WindowStart'), - mysql_engine='InnoDB', - mysql_charset='utf8mb4', - mysql_collate='utf8mb4_general_ci', + "ApiRateLimit", + metadata, + Column("IP", String(45), primary_key=True, unique=True, default=str()), + Column("Requests", INTEGER(11), nullable=False), + Column("WindowStart", BIGINT(20), nullable=False), + Index("ApiRateLimitWindowStart", "WindowStart"), + mysql_engine="InnoDB", + mysql_charset="utf8mb4", + mysql_collate="utf8mb4_general_ci", ) diff --git a/aurweb/scripts/adduser.py b/aurweb/scripts/adduser.py index 4cc059d1..cf933c71 100644 --- a/aurweb/scripts/adduser.py +++ b/aurweb/scripts/adduser.py @@ -11,7 +11,6 @@ import sys import traceback import aurweb.models.account_type as at - from aurweb import db from aurweb.models.account_type import AccountType from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint @@ -30,8 +29,9 @@ def parse_args(): parser.add_argument("--ssh-pubkey", help="SSH PubKey") choices = at.ACCOUNT_TYPE_NAME.values() - parser.add_argument("-t", "--type", help="Account Type", - choices=choices, default=at.USER) + parser.add_argument( + "-t", "--type", help="Account Type", choices=choices, default=at.USER + ) return parser.parse_args() @@ -40,25 +40,29 @@ def main(): args = parse_args() db.get_engine() - type = db.query(AccountType, - AccountType.AccountType == args.type).first() + type = db.query(AccountType, AccountType.AccountType == args.type).first() with db.begin(): - user = db.create(User, Username=args.username, - Email=args.email, Passwd=args.password, - RealName=args.realname, IRCNick=args.ircnick, - PGPKey=args.pgp_key, AccountType=type) + user = db.create( + User, + Username=args.username, + Email=args.email, + Passwd=args.password, + RealName=args.realname, + IRCNick=args.ircnick, + PGPKey=args.pgp_key, + AccountType=type, + ) if args.ssh_pubkey: pubkey = args.ssh_pubkey.strip() # Remove host from the pubkey if it's there. - pubkey = ' '.join(pubkey.split(' ')[:2]) + pubkey = " ".join(pubkey.split(" ")[:2]) with db.begin(): - db.create(SSHPubKey, - User=user, - PubKey=pubkey, - Fingerprint=get_fingerprint(pubkey)) + db.create( + SSHPubKey, User=user, PubKey=pubkey, Fingerprint=get_fingerprint(pubkey) + ) print(user.json()) return 0 diff --git a/aurweb/scripts/aurblup.py b/aurweb/scripts/aurblup.py index 9c9059ec..340d1ccd 100755 --- a/aurweb/scripts/aurblup.py +++ b/aurweb/scripts/aurblup.py @@ -3,11 +3,9 @@ import re import pyalpm - from sqlalchemy import and_ import aurweb.config - from aurweb import db, util from aurweb.models import OfficialProvider @@ -18,8 +16,8 @@ def _main(force: bool = False): repomap = dict() db_path = aurweb.config.get("aurblup", "db-path") - sync_dbs = aurweb.config.get('aurblup', 'sync-dbs').split(' ') - server = aurweb.config.get('aurblup', 'server') + sync_dbs = aurweb.config.get("aurblup", "sync-dbs").split(" ") + server = aurweb.config.get("aurblup", "server") h = pyalpm.Handle("/", db_path) for sync_db in sync_dbs: @@ -35,28 +33,35 @@ def _main(force: bool = False): providers.add((pkg.name, pkg.name)) repomap[(pkg.name, pkg.name)] = repo.name for provision in pkg.provides: - provisionname = re.sub(r'(<|=|>).*', '', provision) + provisionname = re.sub(r"(<|=|>).*", "", provision) providers.add((pkg.name, provisionname)) repomap[(pkg.name, provisionname)] = repo.name with db.begin(): old_providers = set( - db.query(OfficialProvider).with_entities( + db.query(OfficialProvider) + .with_entities( OfficialProvider.Name.label("Name"), - OfficialProvider.Provides.label("Provides") - ).distinct().order_by("Name").all() + OfficialProvider.Provides.label("Provides"), + ) + .distinct() + .order_by("Name") + .all() ) for name, provides in old_providers.difference(providers): - db.delete_all(db.query(OfficialProvider).filter( - and_(OfficialProvider.Name == name, - OfficialProvider.Provides == provides) - )) + db.delete_all( + db.query(OfficialProvider).filter( + and_( + OfficialProvider.Name == name, + OfficialProvider.Provides == provides, + ) + ) + ) for name, provides in providers.difference(old_providers): repo = repomap.get((name, provides)) - db.create(OfficialProvider, Name=name, - Repo=repo, Provides=provides) + db.create(OfficialProvider, Name=name, Repo=repo, Provides=provides) def main(force: bool = False): @@ -64,5 +69,5 @@ def main(force: bool = False): _main(force) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/scripts/config.py b/aurweb/scripts/config.py index e7c91dd1..1d90f525 100644 --- a/aurweb/scripts/config.py +++ b/aurweb/scripts/config.py @@ -50,12 +50,12 @@ def parse_args(): actions = ["get", "set", "unset"] parser = argparse.ArgumentParser( description="aurweb configuration tool", - formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80)) + formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80), + ) parser.add_argument("action", choices=actions, help="script action") parser.add_argument("section", help="config section") parser.add_argument("option", help="config option") - parser.add_argument("value", nargs="?", default=0, - help="config option value") + parser.add_argument("value", nargs="?", default=0, help="config option value") return parser.parse_args() diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 888e346c..7ca171ab 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -25,16 +25,13 @@ import os import shutil import sys import tempfile - from collections import defaultdict from typing import Any import orjson - from sqlalchemy import literal, orm import aurweb.config - from aurweb import db, filters, logging, models, util from aurweb.benchmark import Benchmark from aurweb.models import Package, PackageBase, User @@ -90,65 +87,68 @@ def get_extended_dict(query: orm.Query): def get_extended_fields(): subqueries = [ # PackageDependency - db.query( - models.PackageDependency - ).join(models.DependencyType).with_entities( + db.query(models.PackageDependency) + .join(models.DependencyType) + .with_entities( models.PackageDependency.PackageID.label("ID"), models.DependencyType.Name.label("Type"), models.PackageDependency.DepName.label("Name"), - models.PackageDependency.DepCondition.label("Cond") - ).distinct().order_by("Name"), - + models.PackageDependency.DepCondition.label("Cond"), + ) + .distinct() + .order_by("Name"), # PackageRelation - db.query( - models.PackageRelation - ).join(models.RelationType).with_entities( + db.query(models.PackageRelation) + .join(models.RelationType) + .with_entities( models.PackageRelation.PackageID.label("ID"), models.RelationType.Name.label("Type"), models.PackageRelation.RelName.label("Name"), - models.PackageRelation.RelCondition.label("Cond") - ).distinct().order_by("Name"), - + models.PackageRelation.RelCondition.label("Cond"), + ) + .distinct() + .order_by("Name"), # Groups - db.query(models.PackageGroup).join( - models.Group, - models.PackageGroup.GroupID == models.Group.ID - ).with_entities( + db.query(models.PackageGroup) + .join(models.Group, models.PackageGroup.GroupID == models.Group.ID) + .with_entities( models.PackageGroup.PackageID.label("ID"), literal("Groups").label("Type"), models.Group.Name.label("Name"), - literal(str()).label("Cond") - ).distinct().order_by("Name"), - + literal(str()).label("Cond"), + ) + .distinct() + .order_by("Name"), # Licenses - db.query(models.PackageLicense).join( - models.License, - models.PackageLicense.LicenseID == models.License.ID - ).with_entities( + db.query(models.PackageLicense) + .join(models.License, models.PackageLicense.LicenseID == models.License.ID) + .with_entities( models.PackageLicense.PackageID.label("ID"), literal("License").label("Type"), models.License.Name.label("Name"), - literal(str()).label("Cond") - ).distinct().order_by("Name"), - + literal(str()).label("Cond"), + ) + .distinct() + .order_by("Name"), # Keywords - db.query(models.PackageKeyword).join( - models.Package, - Package.PackageBaseID == models.PackageKeyword.PackageBaseID - ).with_entities( + db.query(models.PackageKeyword) + .join( + models.Package, Package.PackageBaseID == models.PackageKeyword.PackageBaseID + ) + .with_entities( models.Package.ID.label("ID"), literal("Keywords").label("Type"), models.PackageKeyword.Keyword.label("Name"), - literal(str()).label("Cond") - ).distinct().order_by("Name") + literal(str()).label("Cond"), + ) + .distinct() + .order_by("Name"), ] query = subqueries[0].union_all(*subqueries[1:]) return get_extended_dict(query) -EXTENDED_FIELD_HANDLERS = { - "--extended": get_extended_fields -} +EXTENDED_FIELD_HANDLERS = {"--extended": get_extended_fields} def as_dict(package: Package) -> dict[str, Any]: @@ -181,37 +181,38 @@ def _main(): archivedir = aurweb.config.get("mkpkglists", "archivedir") os.makedirs(archivedir, exist_ok=True) - PACKAGES = aurweb.config.get('mkpkglists', 'packagesfile') - META = aurweb.config.get('mkpkglists', 'packagesmetafile') - META_EXT = aurweb.config.get('mkpkglists', 'packagesmetaextfile') - PKGBASE = aurweb.config.get('mkpkglists', 'pkgbasefile') - USERS = aurweb.config.get('mkpkglists', 'userfile') + PACKAGES = aurweb.config.get("mkpkglists", "packagesfile") + META = aurweb.config.get("mkpkglists", "packagesmetafile") + META_EXT = aurweb.config.get("mkpkglists", "packagesmetaextfile") + PKGBASE = aurweb.config.get("mkpkglists", "pkgbasefile") + USERS = aurweb.config.get("mkpkglists", "userfile") bench = Benchmark() logger.info("Started re-creating archives, wait a while...") - query = db.query(Package).join( - PackageBase, - PackageBase.ID == Package.PackageBaseID - ).join( - User, - PackageBase.MaintainerUID == User.ID, - isouter=True - ).filter(PackageBase.PackagerUID.isnot(None)).with_entities( - Package.ID, - Package.Name, - PackageBase.ID.label("PackageBaseID"), - PackageBase.Name.label("PackageBase"), - Package.Version, - Package.Description, - Package.URL, - PackageBase.NumVotes, - PackageBase.Popularity, - PackageBase.OutOfDateTS.label("OutOfDate"), - User.Username.label("Maintainer"), - PackageBase.SubmittedTS.label("FirstSubmitted"), - PackageBase.ModifiedTS.label("LastModified") - ).distinct().order_by("Name") + query = ( + db.query(Package) + .join(PackageBase, PackageBase.ID == Package.PackageBaseID) + .join(User, PackageBase.MaintainerUID == User.ID, isouter=True) + .filter(PackageBase.PackagerUID.isnot(None)) + .with_entities( + Package.ID, + Package.Name, + PackageBase.ID.label("PackageBaseID"), + PackageBase.Name.label("PackageBase"), + Package.Version, + Package.Description, + Package.URL, + PackageBase.NumVotes, + PackageBase.Popularity, + PackageBase.OutOfDateTS.label("OutOfDate"), + User.Username.label("Maintainer"), + PackageBase.SubmittedTS.label("FirstSubmitted"), + PackageBase.ModifiedTS.label("LastModified"), + ) + .distinct() + .order_by("Name") + ) # Produce packages-meta-v1.json.gz output = list() @@ -252,7 +253,7 @@ def _main(): # We stream out package json objects line per line, so # we also need to include the ',' character at the end # of package lines (excluding the last package). - suffix = b",\n" if i < n else b'\n' + suffix = b",\n" if i < n else b"\n" # Write out to packagesmetafile output.append(item) @@ -273,8 +274,7 @@ def _main(): util.apply_all(gzips.values(), lambda gz: gz.close()) # Produce pkgbase.gz - query = db.query(PackageBase.Name).filter( - PackageBase.PackagerUID.isnot(None)).all() + query = db.query(PackageBase.Name).filter(PackageBase.PackagerUID.isnot(None)).all() tmp_pkgbase = os.path.join(tmpdir, os.path.basename(PKGBASE)) with gzip.open(tmp_pkgbase, "wt") as f: f.writelines([f"{base.Name}\n" for i, base in enumerate(query)]) @@ -317,5 +317,5 @@ def main(): _main() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 6afa65ae..f19438bb 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -13,7 +13,6 @@ import aurweb.config import aurweb.db import aurweb.filters import aurweb.l10n - from aurweb import db, logging from aurweb.models import PackageBase, User from aurweb.models.package_comaintainer import PackageComaintainer @@ -25,15 +24,15 @@ from aurweb.models.tu_vote import TUVote logger = logging.get_logger(__name__) -aur_location = aurweb.config.get('options', 'aur_location') +aur_location = aurweb.config.get("options", "aur_location") def headers_msgid(thread_id): - return {'Message-ID': thread_id} + return {"Message-ID": thread_id} def headers_reply(thread_id): - return {'In-Reply-To': thread_id, 'References': thread_id} + return {"In-Reply-To": thread_id, "References": thread_id} class Notification: @@ -47,67 +46,64 @@ class Notification: return [] def get_body_fmt(self, lang): - body = '' + body = "" for line in self.get_body(lang).splitlines(): - if line == '--': - body += '--\n' + if line == "--": + body += "--\n" continue - body += textwrap.fill(line, break_long_words=False) + '\n' + body += textwrap.fill(line, break_long_words=False) + "\n" for i, ref in enumerate(self.get_refs()): - body += '\n' + '[%d] %s' % (i + 1, ref) + body += "\n" + "[%d] %s" % (i + 1, ref) return body.rstrip() def _send(self) -> None: - sendmail = aurweb.config.get('notifications', 'sendmail') - sender = aurweb.config.get('notifications', 'sender') - reply_to = aurweb.config.get('notifications', 'reply-to') + sendmail = aurweb.config.get("notifications", "sendmail") + sender = aurweb.config.get("notifications", "sender") + reply_to = aurweb.config.get("notifications", "reply-to") reason = self.__class__.__name__ - if reason.endswith('Notification'): - reason = reason[:-len('Notification')] + if reason.endswith("Notification"): + reason = reason[: -len("Notification")] for recipient in self.get_recipients(): to, lang = recipient - msg = email.mime.text.MIMEText(self.get_body_fmt(lang), - 'plain', 'utf-8') - msg['Subject'] = self.get_subject(lang) - msg['From'] = sender - msg['Reply-to'] = reply_to - msg['To'] = to + msg = email.mime.text.MIMEText(self.get_body_fmt(lang), "plain", "utf-8") + msg["Subject"] = self.get_subject(lang) + msg["From"] = sender + msg["Reply-to"] = reply_to + msg["To"] = to if self.get_cc(): - msg['Cc'] = str.join(', ', self.get_cc()) - msg['X-AUR-Reason'] = reason - msg['Date'] = email.utils.formatdate(localtime=True) + msg["Cc"] = str.join(", ", self.get_cc()) + msg["X-AUR-Reason"] = reason + msg["Date"] = email.utils.formatdate(localtime=True) for key, value in self.get_headers().items(): msg[key] = value - sendmail = aurweb.config.get('notifications', 'sendmail') + sendmail = aurweb.config.get("notifications", "sendmail") if sendmail: # send email using the sendmail binary specified in the # configuration file - p = subprocess.Popen([sendmail, '-t', '-oi'], - stdin=subprocess.PIPE) + p = subprocess.Popen([sendmail, "-t", "-oi"], stdin=subprocess.PIPE) p.communicate(msg.as_bytes()) else: # send email using smtplib; no local MTA required - server_addr = aurweb.config.get('notifications', 'smtp-server') - server_port = aurweb.config.getint('notifications', - 'smtp-port') - use_ssl = aurweb.config.getboolean('notifications', - 'smtp-use-ssl') - use_starttls = aurweb.config.getboolean('notifications', - 'smtp-use-starttls') - user = aurweb.config.get('notifications', 'smtp-user') - passwd = aurweb.config.get('notifications', 'smtp-password') + server_addr = aurweb.config.get("notifications", "smtp-server") + server_port = aurweb.config.getint("notifications", "smtp-port") + use_ssl = aurweb.config.getboolean("notifications", "smtp-use-ssl") + use_starttls = aurweb.config.getboolean( + "notifications", "smtp-use-starttls" + ) + user = aurweb.config.get("notifications", "smtp-user") + passwd = aurweb.config.get("notifications", "smtp-password") classes = { False: smtplib.SMTP, True: smtplib.SMTP_SSL, } - smtp_timeout = aurweb.config.getint("notifications", - "smtp-timeout") - server = classes[use_ssl](server_addr, server_port, - timeout=smtp_timeout) + smtp_timeout = aurweb.config.getint("notifications", "smtp-timeout") + server = classes[use_ssl]( + server_addr, server_port, timeout=smtp_timeout + ) if use_starttls: server.ehlo() @@ -126,23 +122,29 @@ class Notification: try: self._send() except OSError as exc: - logger.error("Unable to emit notification due to an " - "OSError (precise exception following).") + logger.error( + "Unable to emit notification due to an " + "OSError (precise exception following)." + ) logger.error(str(exc)) class ResetKeyNotification(Notification): def __init__(self, uid): - user = db.query(User).filter( - and_(User.ID == uid, User.Suspended == 0) - ).with_entities( - User.Username, - User.Email, - User.BackupEmail, - User.LangPreference, - User.ResetKey - ).order_by(User.Username.asc()).first() + user = ( + db.query(User) + .filter(and_(User.ID == uid, User.Suspended == 0)) + .with_entities( + User.Username, + User.Email, + User.BackupEmail, + User.LangPreference, + User.ResetKey, + ) + .order_by(User.Username.asc()) + .first() + ) self._username = user.Username self._to = user.Email @@ -159,55 +161,66 @@ class ResetKeyNotification(Notification): return [(self._to, self._lang)] def get_subject(self, lang): - return aurweb.l10n.translator.translate('AUR Password Reset', lang) + return aurweb.l10n.translator.translate("AUR Password Reset", lang) def get_body(self, lang): return aurweb.l10n.translator.translate( - 'A password reset request was submitted for the account ' - '{user} associated with your email address. If you wish to ' - 'reset your password follow the link [1] below, otherwise ' - 'ignore this message and nothing will happen.', - lang).format(user=self._username) + "A password reset request was submitted for the account " + "{user} associated with your email address. If you wish to " + "reset your password follow the link [1] below, otherwise " + "ignore this message and nothing will happen.", + lang, + ).format(user=self._username) def get_refs(self): - return (aur_location + '/passreset/?resetkey=' + self._resetkey,) + return (aur_location + "/passreset/?resetkey=" + self._resetkey,) class WelcomeNotification(ResetKeyNotification): def get_subject(self, lang): return aurweb.l10n.translator.translate( - 'Welcome to the Arch User Repository', - lang) + "Welcome to the Arch User Repository", lang + ) def get_body(self, lang): return aurweb.l10n.translator.translate( - 'Welcome to the Arch User Repository! In order to set an ' - 'initial password for your new account, please click the ' - 'link [1] below. If the link does not work, try copying and ' - 'pasting it into your browser.', lang) + "Welcome to the Arch User Repository! In order to set an " + "initial password for your new account, please click the " + "link [1] below. If the link does not work, try copying and " + "pasting it into your browser.", + lang, + ) class CommentNotification(Notification): def __init__(self, uid, pkgbase_id, comment_id): - self._user = db.query(User.Username).filter( - User.ID == uid).first().Username - self._pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == pkgbase_id).first().Name + self._user = db.query(User.Username).filter(User.ID == uid).first().Username + self._pkgbase = ( + db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name + ) - query = db.query(User).join(PackageNotification).filter( - and_(User.CommentNotify == 1, - PackageNotification.UserID != uid, - PackageNotification.PackageBaseID == pkgbase_id, - User.Suspended == 0) - ).with_entities( - User.Email, - User.LangPreference - ).distinct() + query = ( + db.query(User) + .join(PackageNotification) + .filter( + and_( + User.CommentNotify == 1, + PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == pkgbase_id, + User.Suspended == 0, + ) + ) + .with_entities(User.Email, User.LangPreference) + .distinct() + ) self._recipients = [(u.Email, u.LangPreference) for u in query] - pkgcomment = db.query(PackageComment.Comments).filter( - PackageComment.ID == comment_id).first() + pkgcomment = ( + db.query(PackageComment.Comments) + .filter(PackageComment.ID == comment_id) + .first() + ) self._text = pkgcomment.Comments super().__init__() @@ -217,49 +230,56 @@ class CommentNotification(Notification): def get_subject(self, lang): return aurweb.l10n.translator.translate( - 'AUR Comment for {pkgbase}', - lang).format(pkgbase=self._pkgbase) + "AUR Comment for {pkgbase}", lang + ).format(pkgbase=self._pkgbase) def get_body(self, lang): body = aurweb.l10n.translator.translate( - '{user} [1] added the following comment to {pkgbase} [2]:', - lang).format(user=self._user, pkgbase=self._pkgbase) - body += '\n\n' + self._text + '\n\n--\n' - dnlabel = aurweb.l10n.translator.translate( - 'Disable notifications', lang) + "{user} [1] added the following comment to {pkgbase} [2]:", lang + ).format(user=self._user, pkgbase=self._pkgbase) + body += "\n\n" + self._text + "\n\n--\n" + dnlabel = aurweb.l10n.translator.translate("Disable notifications", lang) body += aurweb.l10n.translator.translate( - 'If you no longer wish to receive notifications about this ' - 'package, please go to the package page [2] and select ' - '"{label}".', lang).format(label=dnlabel) + "If you no longer wish to receive notifications about this " + "package, please go to the package page [2] and select " + '"{label}".', + lang, + ).format(label=dnlabel) return body def get_refs(self): - return (aur_location + '/account/' + self._user + '/', - aur_location + '/pkgbase/' + self._pkgbase + '/') + return ( + aur_location + "/account/" + self._user + "/", + aur_location + "/pkgbase/" + self._pkgbase + "/", + ) def get_headers(self): - thread_id = '' + thread_id = "" return headers_reply(thread_id) class UpdateNotification(Notification): def __init__(self, uid, pkgbase_id): - self._user = db.query(User.Username).filter( - User.ID == uid).first().Username - self._pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == pkgbase_id).first().Name + self._user = db.query(User.Username).filter(User.ID == uid).first().Username + self._pkgbase = ( + db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name + ) - query = db.query(User).join(PackageNotification).filter( - and_(User.UpdateNotify == 1, - PackageNotification.UserID != uid, - PackageNotification.PackageBaseID == pkgbase_id, - User.Suspended == 0) - ).with_entities( - User.Email, - User.LangPreference - ).distinct() + query = ( + db.query(User) + .join(PackageNotification) + .filter( + and_( + User.UpdateNotify == 1, + PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == pkgbase_id, + User.Suspended == 0, + ) + ) + .with_entities(User.Email, User.LangPreference) + .distinct() + ) self._recipients = [(u.Email, u.LangPreference) for u in query] super().__init__() @@ -269,55 +289,63 @@ class UpdateNotification(Notification): def get_subject(self, lang): return aurweb.l10n.translator.translate( - 'AUR Package Update: {pkgbase}', - lang).format(pkgbase=self._pkgbase) + "AUR Package Update: {pkgbase}", lang + ).format(pkgbase=self._pkgbase) def get_body(self, lang): body = aurweb.l10n.translator.translate( - '{user} [1] pushed a new commit to {pkgbase} [2].', - lang).format(user=self._user, pkgbase=self._pkgbase) - body += '\n\n--\n' - dnlabel = aurweb.l10n.translator.translate( - 'Disable notifications', lang) + "{user} [1] pushed a new commit to {pkgbase} [2].", lang + ).format(user=self._user, pkgbase=self._pkgbase) + body += "\n\n--\n" + dnlabel = aurweb.l10n.translator.translate("Disable notifications", lang) body += aurweb.l10n.translator.translate( - 'If you no longer wish to receive notifications about this ' - 'package, please go to the package page [2] and select ' - '"{label}".', lang).format(label=dnlabel) + "If you no longer wish to receive notifications about this " + "package, please go to the package page [2] and select " + '"{label}".', + lang, + ).format(label=dnlabel) return body def get_refs(self): - return (aur_location + '/account/' + self._user + '/', - aur_location + '/pkgbase/' + self._pkgbase + '/') + return ( + aur_location + "/account/" + self._user + "/", + aur_location + "/pkgbase/" + self._pkgbase + "/", + ) def get_headers(self): - thread_id = '' + thread_id = "" return headers_reply(thread_id) class FlagNotification(Notification): def __init__(self, uid, pkgbase_id): - self._user = db.query(User.Username).filter( - User.ID == uid).first().Username - self._pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == pkgbase_id).first().Name + self._user = db.query(User.Username).filter(User.ID == uid).first().Username + self._pkgbase = ( + db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name + ) - query = db.query(User).join(PackageComaintainer, isouter=True).join( - PackageBase, - or_(PackageBase.MaintainerUID == User.ID, - PackageBase.ID == PackageComaintainer.PackageBaseID) - ).filter( - and_(PackageBase.ID == pkgbase_id, - User.Suspended == 0) - ).with_entities( - User.Email, - User.LangPreference - ).distinct() + query = ( + db.query(User) + .join(PackageComaintainer, isouter=True) + .join( + PackageBase, + or_( + PackageBase.MaintainerUID == User.ID, + PackageBase.ID == PackageComaintainer.PackageBaseID, + ), + ) + .filter(and_(PackageBase.ID == pkgbase_id, User.Suspended == 0)) + .with_entities(User.Email, User.LangPreference) + .distinct() + ) self._recipients = [(u.Email, u.LangPreference) for u in query] - pkgbase = db.query(PackageBase.FlaggerComment).filter( - PackageBase.ID == pkgbase_id).first() + pkgbase = ( + db.query(PackageBase.FlaggerComment) + .filter(PackageBase.ID == pkgbase_id) + .first() + ) self._text = pkgbase.FlaggerComment super().__init__() @@ -327,43 +355,53 @@ class FlagNotification(Notification): def get_subject(self, lang): return aurweb.l10n.translator.translate( - 'AUR Out-of-date Notification for {pkgbase}', - lang).format(pkgbase=self._pkgbase) + "AUR Out-of-date Notification for {pkgbase}", lang + ).format(pkgbase=self._pkgbase) def get_body(self, lang): body = aurweb.l10n.translator.translate( - 'Your package {pkgbase} [1] has been flagged out-of-date by ' - '{user} [2]:', lang).format(pkgbase=self._pkgbase, - user=self._user) - body += '\n\n' + self._text + "Your package {pkgbase} [1] has been flagged out-of-date by " "{user} [2]:", + lang, + ).format(pkgbase=self._pkgbase, user=self._user) + body += "\n\n" + self._text return body def get_refs(self): - return (aur_location + '/pkgbase/' + self._pkgbase + '/', - aur_location + '/account/' + self._user + '/') + return ( + aur_location + "/pkgbase/" + self._pkgbase + "/", + aur_location + "/account/" + self._user + "/", + ) class OwnershipEventNotification(Notification): def __init__(self, uid, pkgbase_id): - self._user = db.query(User.Username).filter( - User.ID == uid).first().Username - self._pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == pkgbase_id).first().Name + self._user = db.query(User.Username).filter(User.ID == uid).first().Username + self._pkgbase = ( + db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name + ) - query = db.query(User).join(PackageNotification).filter( - and_(User.OwnershipNotify == 1, - PackageNotification.UserID != uid, - PackageNotification.PackageBaseID == pkgbase_id, - User.Suspended == 0) - ).with_entities( - User.Email, - User.LangPreference - ).distinct() + query = ( + db.query(User) + .join(PackageNotification) + .filter( + and_( + User.OwnershipNotify == 1, + PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == pkgbase_id, + User.Suspended == 0, + ) + ) + .with_entities(User.Email, User.LangPreference) + .distinct() + ) self._recipients = [(u.Email, u.LangPreference) for u in query] - pkgbase = db.query(PackageBase.FlaggerComment).filter( - PackageBase.ID == pkgbase_id).first() + pkgbase = ( + db.query(PackageBase.FlaggerComment) + .filter(PackageBase.ID == pkgbase_id) + .first() + ) self._text = pkgbase.FlaggerComment super().__init__() @@ -373,39 +411,43 @@ class OwnershipEventNotification(Notification): def get_subject(self, lang): return aurweb.l10n.translator.translate( - 'AUR Ownership Notification for {pkgbase}', - lang).format(pkgbase=self._pkgbase) + "AUR Ownership Notification for {pkgbase}", lang + ).format(pkgbase=self._pkgbase) def get_refs(self): - return (aur_location + '/pkgbase/' + self._pkgbase + '/', - aur_location + '/account/' + self._user + '/') + return ( + aur_location + "/pkgbase/" + self._pkgbase + "/", + aur_location + "/account/" + self._user + "/", + ) class AdoptNotification(OwnershipEventNotification): def get_body(self, lang): return aurweb.l10n.translator.translate( - 'The package {pkgbase} [1] was adopted by {user} [2].', - lang).format(pkgbase=self._pkgbase, user=self._user) + "The package {pkgbase} [1] was adopted by {user} [2].", lang + ).format(pkgbase=self._pkgbase, user=self._user) class DisownNotification(OwnershipEventNotification): def get_body(self, lang): return aurweb.l10n.translator.translate( - 'The package {pkgbase} [1] was disowned by {user} ' - '[2].', lang).format(pkgbase=self._pkgbase, - user=self._user) + "The package {pkgbase} [1] was disowned by {user} " "[2].", lang + ).format(pkgbase=self._pkgbase, user=self._user) class ComaintainershipEventNotification(Notification): def __init__(self, uid, pkgbase_id): - self._pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == pkgbase_id).first().Name + self._pkgbase = ( + db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name + ) - user = db.query(User).filter(User.ID == uid).with_entities( - User.Email, - User.LangPreference - ).first() + user = ( + db.query(User) + .filter(User.ID == uid) + .with_entities(User.Email, User.LangPreference) + .first() + ) self._to = user.Email self._lang = user.LangPreference @@ -417,247 +459,59 @@ class ComaintainershipEventNotification(Notification): def get_subject(self, lang): return aurweb.l10n.translator.translate( - 'AUR Co-Maintainer Notification for {pkgbase}', - lang).format(pkgbase=self._pkgbase) + "AUR Co-Maintainer Notification for {pkgbase}", lang + ).format(pkgbase=self._pkgbase) def get_refs(self): - return (aur_location + '/pkgbase/' + self._pkgbase + '/',) + return (aur_location + "/pkgbase/" + self._pkgbase + "/",) class ComaintainerAddNotification(ComaintainershipEventNotification): def get_body(self, lang): return aurweb.l10n.translator.translate( - 'You were added to the co-maintainer list of {pkgbase} [1].', - lang).format(pkgbase=self._pkgbase) + "You were added to the co-maintainer list of {pkgbase} [1].", lang + ).format(pkgbase=self._pkgbase) class ComaintainerRemoveNotification(ComaintainershipEventNotification): def get_body(self, lang): return aurweb.l10n.translator.translate( - 'You were removed from the co-maintainer list of {pkgbase} ' - '[1].', lang).format(pkgbase=self._pkgbase) + "You were removed from the co-maintainer list of {pkgbase} " "[1].", lang + ).format(pkgbase=self._pkgbase) class DeleteNotification(Notification): def __init__(self, uid, old_pkgbase_id, new_pkgbase_id=None): - self._user = db.query(User.Username).filter( - User.ID == uid).first().Username - self._old_pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == old_pkgbase_id).first().Name + self._user = db.query(User.Username).filter(User.ID == uid).first().Username + self._old_pkgbase = ( + db.query(PackageBase.Name) + .filter(PackageBase.ID == old_pkgbase_id) + .first() + .Name + ) self._new_pkgbase = None if new_pkgbase_id: - self._new_pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == new_pkgbase_id).first().Name + self._new_pkgbase = ( + db.query(PackageBase.Name) + .filter(PackageBase.ID == new_pkgbase_id) + .first() + .Name + ) - query = db.query(User).join(PackageNotification).filter( - and_(PackageNotification.UserID != uid, - PackageNotification.PackageBaseID == old_pkgbase_id, - User.Suspended == 0) - ).with_entities( - User.Email, - User.LangPreference - ).distinct() - self._recipients = [(u.Email, u.LangPreference) for u in query] - - super().__init__() - - def get_recipients(self): - return self._recipients - - def get_subject(self, lang): - return aurweb.l10n.translator.translate( - 'AUR Package deleted: {pkgbase}', - lang).format(pkgbase=self._old_pkgbase) - - def get_body(self, lang): - if self._new_pkgbase: - dnlabel = aurweb.l10n.translator.translate( - 'Disable notifications', lang) - return aurweb.l10n.translator.translate( - '{user} [1] merged {old} [2] into {new} [3].\n\n' - '--\n' - 'If you no longer wish receive notifications about the ' - 'new package, please go to [3] and click "{label}".', - lang).format(user=self._user, old=self._old_pkgbase, - new=self._new_pkgbase, label=dnlabel) - else: - return aurweb.l10n.translator.translate( - '{user} [1] deleted {pkgbase} [2].\n\n' - 'You will no longer receive notifications about this ' - 'package.', lang).format(user=self._user, - pkgbase=self._old_pkgbase) - - def get_refs(self): - refs = (aur_location + '/account/' + self._user + '/', - aur_location + '/pkgbase/' + self._old_pkgbase + '/') - if self._new_pkgbase: - refs += (aur_location + '/pkgbase/' + self._new_pkgbase + '/',) - return refs - - -class RequestOpenNotification(Notification): - def __init__(self, uid, reqid, reqtype, pkgbase_id, merge_into=None): - - self._user = db.query(User.Username).filter( - User.ID == uid).first().Username - self._pkgbase = db.query(PackageBase.Name).filter( - PackageBase.ID == pkgbase_id).first().Name - - self._to = aurweb.config.get('options', 'aur_request_ml') - - query = db.query(PackageRequest).join(PackageBase).join( - PackageComaintainer, - PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID, - isouter=True - ).join( - User, - or_(User.ID == PackageRequest.UsersID, - User.ID == PackageBase.MaintainerUID, - User.ID == PackageComaintainer.UsersID) - ).filter( - and_(PackageRequest.ID == reqid, - User.Suspended == 0) - ).with_entities( - User.Email - ).distinct() - self._cc = [u.Email for u in query] - - pkgreq = db.query(PackageRequest.Comments).filter( - PackageRequest.ID == reqid).first() - - self._text = pkgreq.Comments - self._reqid = int(reqid) - self._reqtype = reqtype - self._merge_into = merge_into - - def get_recipients(self): - return [(self._to, 'en')] - - def get_cc(self): - return self._cc - - def get_subject(self, lang): - return '[PRQ#%d] %s Request for %s' % \ - (self._reqid, self._reqtype.title(), self._pkgbase) - - def get_body(self, lang): - if self._merge_into: - body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \ - (self._user, self._pkgbase, self._merge_into) - body += '\n\n' + self._text - else: - an = 'an' if self._reqtype[0] in 'aeiou' else 'a' - body = '%s [1] filed %s %s request for %s [2]:' % \ - (self._user, an, self._reqtype, self._pkgbase) - body += '\n\n' + self._text - return body - - def get_refs(self): - refs = (aur_location + '/account/' + self._user + '/', - aur_location + '/pkgbase/' + self._pkgbase + '/') - if self._merge_into: - refs += (aur_location + '/pkgbase/' + self._merge_into + '/',) - return refs - - def get_headers(self): - thread_id = '' - # Use a deterministic Message-ID for the first email referencing a - # request. - headers = headers_msgid(thread_id) - return headers - - -class RequestCloseNotification(Notification): - - def __init__(self, uid, reqid, reason): - user = db.query(User.Username).filter(User.ID == uid).first() - self._user = user.Username if user else None - - self._to = aurweb.config.get('options', 'aur_request_ml') - - query = db.query(PackageRequest).join(PackageBase).join( - PackageComaintainer, - PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID, - isouter=True - ).join( - User, - or_(User.ID == PackageRequest.UsersID, - User.ID == PackageBase.MaintainerUID, - User.ID == PackageComaintainer.UsersID) - ).filter( - and_(PackageRequest.ID == reqid, - User.Suspended == 0) - ).with_entities( - User.Email - ).distinct() - self._cc = [u.Email for u in query] - - pkgreq = db.query(PackageRequest).join(RequestType).filter( - PackageRequest.ID == reqid - ).with_entities( - PackageRequest.ClosureComment, - RequestType.Name, - PackageRequest.PackageBaseName - ).first() - - self._text = pkgreq.ClosureComment - self._reqtype = pkgreq.Name - self._pkgbase = pkgreq.PackageBaseName - - self._reqid = int(reqid) - self._reason = reason - - def get_recipients(self): - return [(self._to, 'en')] - - def get_cc(self): - return self._cc - - def get_subject(self, lang): - return '[PRQ#%d] %s Request for %s %s' % (self._reqid, - self._reqtype.title(), - self._pkgbase, - self._reason.title()) - - def get_body(self, lang): - if self._user: - body = 'Request #%d has been %s by %s [1]' % \ - (self._reqid, self._reason, self._user) - else: - body = 'Request #%d has been %s automatically by the Arch User ' \ - 'Repository package request system' % \ - (self._reqid, self._reason) - if self._text.strip() == '': - body += '.' - else: - body += ':\n\n' + self._text - return body - - def get_refs(self): - if self._user: - return (aur_location + '/account/' + self._user + '/',) - else: - return () - - def get_headers(self): - thread_id = '' - headers = headers_reply(thread_id) - return headers - - -class TUVoteReminderNotification(Notification): - def __init__(self, vote_id): - self._vote_id = int(vote_id) - - subquery = db.query(TUVote.UserID).filter(TUVote.VoteID == vote_id) - query = db.query(User).filter( - and_(User.AccountTypeID.in_((2, 4)), - ~User.ID.in_(subquery), - User.Suspended == 0) - ).with_entities( - User.Email, User.LangPreference + query = ( + db.query(User) + .join(PackageNotification) + .filter( + and_( + PackageNotification.UserID != uid, + PackageNotification.PackageBaseID == old_pkgbase_id, + User.Suspended == 0, + ) + ) + .with_entities(User.Email, User.LangPreference) + .distinct() ) self._recipients = [(u.Email, u.LangPreference) for u in query] @@ -668,36 +522,280 @@ class TUVoteReminderNotification(Notification): def get_subject(self, lang): return aurweb.l10n.translator.translate( - 'TU Vote Reminder: Proposal {id}', - lang).format(id=self._vote_id) + "AUR Package deleted: {pkgbase}", lang + ).format(pkgbase=self._old_pkgbase) + + def get_body(self, lang): + if self._new_pkgbase: + dnlabel = aurweb.l10n.translator.translate("Disable notifications", lang) + return aurweb.l10n.translator.translate( + "{user} [1] merged {old} [2] into {new} [3].\n\n" + "--\n" + "If you no longer wish receive notifications about the " + 'new package, please go to [3] and click "{label}".', + lang, + ).format( + user=self._user, + old=self._old_pkgbase, + new=self._new_pkgbase, + label=dnlabel, + ) + else: + return aurweb.l10n.translator.translate( + "{user} [1] deleted {pkgbase} [2].\n\n" + "You will no longer receive notifications about this " + "package.", + lang, + ).format(user=self._user, pkgbase=self._old_pkgbase) + + def get_refs(self): + refs = ( + aur_location + "/account/" + self._user + "/", + aur_location + "/pkgbase/" + self._old_pkgbase + "/", + ) + if self._new_pkgbase: + refs += (aur_location + "/pkgbase/" + self._new_pkgbase + "/",) + return refs + + +class RequestOpenNotification(Notification): + def __init__(self, uid, reqid, reqtype, pkgbase_id, merge_into=None): + + self._user = db.query(User.Username).filter(User.ID == uid).first().Username + self._pkgbase = ( + db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name + ) + + self._to = aurweb.config.get("options", "aur_request_ml") + + query = ( + db.query(PackageRequest) + .join(PackageBase) + .join( + PackageComaintainer, + PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID, + isouter=True, + ) + .join( + User, + or_( + User.ID == PackageRequest.UsersID, + User.ID == PackageBase.MaintainerUID, + User.ID == PackageComaintainer.UsersID, + ), + ) + .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0)) + .with_entities(User.Email) + .distinct() + ) + self._cc = [u.Email for u in query] + + pkgreq = ( + db.query(PackageRequest.Comments).filter(PackageRequest.ID == reqid).first() + ) + + self._text = pkgreq.Comments + self._reqid = int(reqid) + self._reqtype = reqtype + self._merge_into = merge_into + + def get_recipients(self): + return [(self._to, "en")] + + def get_cc(self): + return self._cc + + def get_subject(self, lang): + return "[PRQ#%d] %s Request for %s" % ( + self._reqid, + self._reqtype.title(), + self._pkgbase, + ) + + def get_body(self, lang): + if self._merge_into: + body = "%s [1] filed a request to merge %s [2] into %s [3]:" % ( + self._user, + self._pkgbase, + self._merge_into, + ) + body += "\n\n" + self._text + else: + an = "an" if self._reqtype[0] in "aeiou" else "a" + body = "%s [1] filed %s %s request for %s [2]:" % ( + self._user, + an, + self._reqtype, + self._pkgbase, + ) + body += "\n\n" + self._text + return body + + def get_refs(self): + refs = ( + aur_location + "/account/" + self._user + "/", + aur_location + "/pkgbase/" + self._pkgbase + "/", + ) + if self._merge_into: + refs += (aur_location + "/pkgbase/" + self._merge_into + "/",) + return refs + + def get_headers(self): + thread_id = "" + # Use a deterministic Message-ID for the first email referencing a + # request. + headers = headers_msgid(thread_id) + return headers + + +class RequestCloseNotification(Notification): + def __init__(self, uid, reqid, reason): + user = db.query(User.Username).filter(User.ID == uid).first() + self._user = user.Username if user else None + + self._to = aurweb.config.get("options", "aur_request_ml") + + query = ( + db.query(PackageRequest) + .join(PackageBase) + .join( + PackageComaintainer, + PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID, + isouter=True, + ) + .join( + User, + or_( + User.ID == PackageRequest.UsersID, + User.ID == PackageBase.MaintainerUID, + User.ID == PackageComaintainer.UsersID, + ), + ) + .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0)) + .with_entities(User.Email) + .distinct() + ) + self._cc = [u.Email for u in query] + + pkgreq = ( + db.query(PackageRequest) + .join(RequestType) + .filter(PackageRequest.ID == reqid) + .with_entities( + PackageRequest.ClosureComment, + RequestType.Name, + PackageRequest.PackageBaseName, + ) + .first() + ) + + self._text = pkgreq.ClosureComment + self._reqtype = pkgreq.Name + self._pkgbase = pkgreq.PackageBaseName + + self._reqid = int(reqid) + self._reason = reason + + def get_recipients(self): + return [(self._to, "en")] + + def get_cc(self): + return self._cc + + def get_subject(self, lang): + return "[PRQ#%d] %s Request for %s %s" % ( + self._reqid, + self._reqtype.title(), + self._pkgbase, + self._reason.title(), + ) + + def get_body(self, lang): + if self._user: + body = "Request #%d has been %s by %s [1]" % ( + self._reqid, + self._reason, + self._user, + ) + else: + body = ( + "Request #%d has been %s automatically by the Arch User " + "Repository package request system" % (self._reqid, self._reason) + ) + if self._text.strip() == "": + body += "." + else: + body += ":\n\n" + self._text + return body + + def get_refs(self): + if self._user: + return (aur_location + "/account/" + self._user + "/",) + else: + return () + + def get_headers(self): + thread_id = "" + headers = headers_reply(thread_id) + return headers + + +class TUVoteReminderNotification(Notification): + def __init__(self, vote_id): + self._vote_id = int(vote_id) + + subquery = db.query(TUVote.UserID).filter(TUVote.VoteID == vote_id) + query = ( + db.query(User) + .filter( + and_( + User.AccountTypeID.in_((2, 4)), + ~User.ID.in_(subquery), + User.Suspended == 0, + ) + ) + .with_entities(User.Email, User.LangPreference) + ) + self._recipients = [(u.Email, u.LangPreference) for u in query] + + super().__init__() + + def get_recipients(self): + return self._recipients + + def get_subject(self, lang): + return aurweb.l10n.translator.translate( + "TU Vote Reminder: Proposal {id}", lang + ).format(id=self._vote_id) def get_body(self, lang): return aurweb.l10n.translator.translate( - 'Please remember to cast your vote on proposal {id} [1]. ' - 'The voting period ends in less than 48 hours.', - lang).format(id=self._vote_id) + "Please remember to cast your vote on proposal {id} [1]. " + "The voting period ends in less than 48 hours.", + lang, + ).format(id=self._vote_id) def get_refs(self): - return (aur_location + '/tu/?id=' + str(self._vote_id),) + return (aur_location + "/tu/?id=" + str(self._vote_id),) def main(): db.get_engine() action = sys.argv[1] action_map = { - 'send-resetkey': ResetKeyNotification, - 'welcome': WelcomeNotification, - 'comment': CommentNotification, - 'update': UpdateNotification, - 'flag': FlagNotification, - 'adopt': AdoptNotification, - 'disown': DisownNotification, - 'comaintainer-add': ComaintainerAddNotification, - 'comaintainer-remove': ComaintainerRemoveNotification, - 'delete': DeleteNotification, - 'request-open': RequestOpenNotification, - 'request-close': RequestCloseNotification, - 'tu-vote-reminder': TUVoteReminderNotification, + "send-resetkey": ResetKeyNotification, + "welcome": WelcomeNotification, + "comment": CommentNotification, + "update": UpdateNotification, + "flag": FlagNotification, + "adopt": AdoptNotification, + "disown": DisownNotification, + "comaintainer-add": ComaintainerAddNotification, + "comaintainer-remove": ComaintainerRemoveNotification, + "delete": DeleteNotification, + "request-open": RequestOpenNotification, + "request-close": RequestCloseNotification, + "tu-vote-reminder": TUVoteReminderNotification, } with db.begin(): @@ -705,5 +803,5 @@ def main(): notification.send() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/scripts/pkgmaint.py b/aurweb/scripts/pkgmaint.py index 2a2c638a..9d7cf53b 100755 --- a/aurweb/scripts/pkgmaint.py +++ b/aurweb/scripts/pkgmaint.py @@ -11,8 +11,8 @@ def _main(): limit_to = time.utcnow() - 86400 query = db.query(PackageBase).filter( - and_(PackageBase.SubmittedTS < limit_to, - PackageBase.PackagerUID.is_(None))) + and_(PackageBase.SubmittedTS < limit_to, PackageBase.PackagerUID.is_(None)) + ) db.delete_all(query) @@ -22,5 +22,5 @@ def main(): _main() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index 637173eb..aa163be1 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 from sqlalchemy import and_, func -from sqlalchemy.sql.functions import coalesce -from sqlalchemy.sql.functions import sum as _sum +from sqlalchemy.sql.functions import coalesce, sum as _sum from aurweb import db, time from aurweb.models import PackageBase, PackageVote @@ -20,18 +19,26 @@ def run_variable(pkgbases: list[PackageBase] = []) -> None: now = time.utcnow() # NumVotes subquery. - votes_subq = db.get_session().query( - func.count("*") - ).select_from(PackageVote).filter( - PackageVote.PackageBaseID == PackageBase.ID + votes_subq = ( + db.get_session() + .query(func.count("*")) + .select_from(PackageVote) + .filter(PackageVote.PackageBaseID == PackageBase.ID) ) # Popularity subquery. - pop_subq = db.get_session().query( - coalesce(_sum(func.pow(0.98, (now - PackageVote.VoteTS) / 86400)), 0.0), - ).select_from(PackageVote).filter( - and_(PackageVote.PackageBaseID == PackageBase.ID, - PackageVote.VoteTS.isnot(None)) + pop_subq = ( + db.get_session() + .query( + coalesce(_sum(func.pow(0.98, (now - PackageVote.VoteTS) / 86400)), 0.0), + ) + .select_from(PackageVote) + .filter( + and_( + PackageVote.PackageBaseID == PackageBase.ID, + PackageVote.VoteTS.isnot(None), + ) + ) ) with db.begin(): @@ -42,14 +49,16 @@ def run_variable(pkgbases: list[PackageBase] = []) -> None: ids = {pkgbase.ID for pkgbase in pkgbases} query = query.filter(PackageBase.ID.in_(ids)) - query.update({ - "NumVotes": votes_subq.scalar_subquery(), - "Popularity": pop_subq.scalar_subquery() - }) + query.update( + { + "NumVotes": votes_subq.scalar_subquery(), + "Popularity": pop_subq.scalar_subquery(), + } + ) def run_single(pkgbase: PackageBase) -> None: - """ A single popupdate. The given pkgbase instance will be + """A single popupdate. The given pkgbase instance will be refreshed after the database update is done. NOTE: This function is compatible only with aurweb FastAPI. @@ -65,5 +74,5 @@ def main(): run_variable() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 87f8b89f..ff6fe09c 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import sys - from urllib.parse import quote_plus from xml.etree.ElementTree import Element @@ -10,7 +9,6 @@ import markdown import pygit2 import aurweb.config - from aurweb import db, logging, util from aurweb.models import PackageComment @@ -25,13 +23,15 @@ class LinkifyExtension(markdown.extensions.Extension): # Captures http(s) and ftp URLs until the first non URL-ish character. # Excludes trailing punctuation. - _urlre = (r'(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' - r'(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))') + _urlre = ( + r"(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?" + r"(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))" + ) def extendMarkdown(self, md): processor = markdown.inlinepatterns.AutolinkInlineProcessor(self._urlre, md) # Register it right after the default <>-link processor (priority 120). - md.inlinePatterns.register(processor, 'linkify', 119) + md.inlinePatterns.register(processor, "linkify", 119) class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): @@ -43,16 +43,16 @@ class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): """ def handleMatch(self, m, data): - el = Element('a') - el.set('href', f'https://bugs.archlinux.org/task/{m.group(1)}') + el = Element("a") + el.set("href", f"https://bugs.archlinux.org/task/{m.group(1)}") el.text = markdown.util.AtomicString(m.group(0)) return (el, m.start(0), m.end(0)) class FlysprayLinksExtension(markdown.extensions.Extension): def extendMarkdown(self, md): - processor = FlysprayLinksInlineProcessor(r'\bFS#(\d+)\b', md) - md.inlinePatterns.register(processor, 'flyspray-links', 118) + processor = FlysprayLinksInlineProcessor(r"\bFS#(\d+)\b", md) + md.inlinePatterns.register(processor, "flyspray-links", 118) class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): @@ -65,10 +65,10 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): """ def __init__(self, md, head): - repo_path = aurweb.config.get('serve', 'repo-path') + repo_path = aurweb.config.get("serve", "repo-path") self._repo = pygit2.Repository(repo_path) self._head = head - super().__init__(r'\b([0-9a-f]{7,40})\b', md) + super().__init__(r"\b([0-9a-f]{7,40})\b", md) def handleMatch(self, m, data): oid = m.group(1) @@ -76,13 +76,12 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): # Unknown OID; preserve the orginal text. return (None, None, None) - el = Element('a') + el = Element("a") commit_uri = aurweb.config.get("options", "commit_uri") prefixlen = util.git_search(self._repo, oid) - el.set('href', commit_uri % ( - quote_plus(self._head), - quote_plus(oid[:prefixlen]) - )) + el.set( + "href", commit_uri % (quote_plus(self._head), quote_plus(oid[:prefixlen])) + ) el.text = markdown.util.AtomicString(oid[:prefixlen]) return (el, m.start(0), m.end(0)) @@ -97,7 +96,7 @@ class GitCommitsExtension(markdown.extensions.Extension): def extendMarkdown(self, md): try: processor = GitCommitsInlineProcessor(md, self._head) - md.inlinePatterns.register(processor, 'git-commits', 117) + md.inlinePatterns.register(processor, "git-commits", 117) except pygit2.GitError: logger.error(f"No git repository found for '{self._head}'.") @@ -105,16 +104,16 @@ class GitCommitsExtension(markdown.extensions.Extension): class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor): def run(self, doc): for elem in doc: - if elem.tag == 'h1': - elem.tag = 'h5' - elif elem.tag in ['h2', 'h3', 'h4', 'h5']: - elem.tag = 'h6' + if elem.tag == "h1": + elem.tag = "h5" + elif elem.tag in ["h2", "h3", "h4", "h5"]: + elem.tag = "h6" class HeadingExtension(markdown.extensions.Extension): def extendMarkdown(self, md): # Priority doesn't matter since we don't conflict with other processors. - md.treeprocessors.register(HeadingTreeprocessor(md), 'heading', 30) + md.treeprocessors.register(HeadingTreeprocessor(md), "heading", 30) def save_rendered_comment(comment: PackageComment, html: str): @@ -130,16 +129,26 @@ def update_comment_render(comment: PackageComment) -> None: text = comment.Comments pkgbasename = comment.PackageBase.Name - html = markdown.markdown(text, extensions=[ - 'fenced_code', - LinkifyExtension(), - FlysprayLinksExtension(), - GitCommitsExtension(pkgbasename), - HeadingExtension() - ]) + html = markdown.markdown( + text, + extensions=[ + "fenced_code", + LinkifyExtension(), + FlysprayLinksExtension(), + GitCommitsExtension(pkgbasename), + HeadingExtension(), + ], + ) - allowed_tags = (bleach.sanitizer.ALLOWED_TAGS - + ['p', 'pre', 'h4', 'h5', 'h6', 'br', 'hr']) + allowed_tags = bleach.sanitizer.ALLOWED_TAGS + [ + "p", + "pre", + "h4", + "h5", + "h6", + "br", + "hr", + ] html = bleach.clean(html, tags=allowed_tags) save_rendered_comment(comment, html) db.refresh(comment) @@ -148,11 +157,9 @@ def update_comment_render(comment: PackageComment) -> None: def main(): db.get_engine() comment_id = int(sys.argv[1]) - comment = db.query(PackageComment).filter( - PackageComment.ID == comment_id - ).first() + comment = db.query(PackageComment).filter(PackageComment.ID == comment_id).first() update_comment_render(comment) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/scripts/tuvotereminder.py b/aurweb/scripts/tuvotereminder.py index 742fa6d4..aa59d911 100755 --- a/aurweb/scripts/tuvotereminder.py +++ b/aurweb/scripts/tuvotereminder.py @@ -3,12 +3,11 @@ from sqlalchemy import and_ import aurweb.config - from aurweb import db, time from aurweb.models import TUVoteInfo from aurweb.scripts import notify -notify_cmd = aurweb.config.get('notifications', 'notify-cmd') +notify_cmd = aurweb.config.get("notifications", "notify-cmd") def main(): @@ -23,13 +22,12 @@ def main(): filter_to = now + end query = db.query(TUVoteInfo.ID).filter( - and_(TUVoteInfo.End >= filter_from, - TUVoteInfo.End <= filter_to) + and_(TUVoteInfo.End >= filter_from, TUVoteInfo.End <= filter_to) ) for voteinfo in query: notif = notify.TUVoteReminderNotification(voteinfo.ID) notif.send() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/scripts/usermaint.py b/aurweb/scripts/usermaint.py index 69f9db04..fb79aeaf 100755 --- a/aurweb/scripts/usermaint.py +++ b/aurweb/scripts/usermaint.py @@ -9,14 +9,16 @@ from aurweb.models import User def _main(): limit_to = time.utcnow() - 86400 * 7 - update_ = update(User).where( - User.LastLogin < limit_to - ).values(LastLoginIPAddress=None) + update_ = ( + update(User).where(User.LastLogin < limit_to).values(LastLoginIPAddress=None) + ) db.get_session().execute(update_) - update_ = update(User).where( - User.LastSSHLogin < limit_to - ).values(LastSSHLoginIPAddress=None) + update_ = ( + update(User) + .where(User.LastSSHLogin < limit_to) + .values(LastSSHLoginIPAddress=None) + ) db.get_session().execute(update_) @@ -26,5 +28,5 @@ def main(): _main() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/aurweb/spawn.py b/aurweb/spawn.py index c7d54c4e..29162f33 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -16,18 +16,16 @@ import subprocess import sys import tempfile import time - from typing import Iterable import aurweb.config import aurweb.schema - from aurweb.exceptions import AurwebException children = [] temporary_dir = None verbosity = 0 -asgi_backend = '' +asgi_backend = "" workers = 1 PHP_BINARY = os.environ.get("PHP_BINARY", "php") @@ -60,22 +58,21 @@ def validate_php_config() -> None: :return: None """ try: - proc = subprocess.Popen([PHP_BINARY, "-m"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + proc = subprocess.Popen( + [PHP_BINARY, "-m"], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) out, _ = proc.communicate() except FileNotFoundError: - raise AurwebException(f"Unable to locate the '{PHP_BINARY}' " - "executable.") + raise AurwebException(f"Unable to locate the '{PHP_BINARY}' " "executable.") - assert proc.returncode == 0, ("Received non-zero error code " - f"{proc.returncode} from '{PHP_BINARY}'.") + assert proc.returncode == 0, ( + "Received non-zero error code " f"{proc.returncode} from '{PHP_BINARY}'." + ) modules = out.decode().splitlines() for module in PHP_MODULES: if module not in modules: - raise AurwebException( - f"PHP does not have the '{module}' module enabled.") + raise AurwebException(f"PHP does not have the '{module}' module enabled.") def generate_nginx_config(): @@ -91,7 +88,8 @@ def generate_nginx_config(): config_path = os.path.join(temporary_dir, "nginx.conf") config = open(config_path, "w") # We double nginx's braces because they conflict with Python's f-strings. - config.write(f""" + config.write( + f""" events {{}} daemon off; error_log /dev/stderr info; @@ -124,7 +122,8 @@ def generate_nginx_config(): }} }} }} - """) + """ + ) return config_path @@ -146,20 +145,23 @@ def start(): return atexit.register(stop) - if 'AUR_CONFIG' in os.environ: - os.environ['AUR_CONFIG'] = os.path.realpath(os.environ['AUR_CONFIG']) + if "AUR_CONFIG" in os.environ: + os.environ["AUR_CONFIG"] = os.path.realpath(os.environ["AUR_CONFIG"]) try: terminal_width = os.get_terminal_size().columns except OSError: terminal_width = 80 - print("{ruler}\n" - "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n" - "Check out {aur_location}\n" - "Hit ^C to terminate everything.\n" - "{ruler}" - .format(ruler=("-" * terminal_width), - aur_location=aurweb.config.get('options', 'aur_location'))) + print( + "{ruler}\n" + "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n" + "Check out {aur_location}\n" + "Hit ^C to terminate everything.\n" + "{ruler}".format( + ruler=("-" * terminal_width), + aur_location=aurweb.config.get("options", "aur_location"), + ) + ) # PHP php_address = aurweb.config.get("php", "bind_address") @@ -168,8 +170,9 @@ def start(): spawn_child(["php", "-S", php_address, "-t", htmldir]) # FastAPI - fastapi_host, fastapi_port = aurweb.config.get( - "fastapi", "bind_address").rsplit(":", 1) + fastapi_host, fastapi_port = aurweb.config.get("fastapi", "bind_address").rsplit( + ":", 1 + ) # Logging config. aurwebdir = aurweb.config.get("options", "aurwebdir") @@ -178,20 +181,33 @@ def start(): backend_args = { "hypercorn": ["-b", f"{fastapi_host}:{fastapi_port}"], "uvicorn": ["--host", fastapi_host, "--port", fastapi_port], - "gunicorn": ["--bind", f"{fastapi_host}:{fastapi_port}", - "-k", "uvicorn.workers.UvicornWorker", - "-w", str(workers)] + "gunicorn": [ + "--bind", + f"{fastapi_host}:{fastapi_port}", + "-k", + "uvicorn.workers.UvicornWorker", + "-w", + str(workers), + ], } backend_args = backend_args.get(asgi_backend) - spawn_child([ - "python", "-m", asgi_backend, - "--log-config", fastapi_log_config, - ] + backend_args + ["aurweb.asgi:app"]) + spawn_child( + [ + "python", + "-m", + asgi_backend, + "--log-config", + fastapi_log_config, + ] + + backend_args + + ["aurweb.asgi:app"] + ) # nginx spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()]) - print(f""" + print( + f""" > Started nginx. > > PHP backend: http://{php_address} @@ -201,11 +217,13 @@ def start(): > FastAPI frontend: http://{fastapi_host}:{FASTAPI_NGINX_PORT} > > Frontends are hosted via nginx and should be preferred. -""") +""" + ) -def _kill_children(children: Iterable, exceptions: list[Exception] = []) \ - -> list[Exception]: +def _kill_children( + children: Iterable, exceptions: list[Exception] = [] +) -> list[Exception]: """ Kill each process found in `children`. @@ -223,8 +241,9 @@ def _kill_children(children: Iterable, exceptions: list[Exception] = []) \ return exceptions -def _wait_for_children(children: Iterable, exceptions: list[Exception] = []) \ - -> list[Exception]: +def _wait_for_children( + children: Iterable, exceptions: list[Exception] = [] +) -> list[Exception]: """ Wait for each process to end found in `children`. @@ -261,21 +280,31 @@ def stop() -> None: exceptions = _wait_for_children(children, exceptions) children = [] if exceptions: - raise ProcessExceptions("Errors terminating the child processes:", - exceptions) + raise ProcessExceptions("Errors terminating the child processes:", exceptions) -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser( - prog='python -m aurweb.spawn', - description='Start aurweb\'s test server.') - parser.add_argument('-v', '--verbose', action='count', default=0, - help='increase verbosity') - choices = ['hypercorn', 'gunicorn', 'uvicorn'] - parser.add_argument('-b', '--backend', choices=choices, default='uvicorn', - help='asgi backend used to launch the python server') - parser.add_argument("-w", "--workers", default=1, type=int, - help="number of workers to use in gunicorn") + prog="python -m aurweb.spawn", description="Start aurweb's test server." + ) + parser.add_argument( + "-v", "--verbose", action="count", default=0, help="increase verbosity" + ) + choices = ["hypercorn", "gunicorn", "uvicorn"] + parser.add_argument( + "-b", + "--backend", + choices=choices, + default="uvicorn", + help="asgi backend used to launch the python server", + ) + parser.add_argument( + "-w", + "--workers", + default=1, + type=int, + help="number of workers to use in gunicorn", + ) args = parser.parse_args() try: diff --git a/aurweb/templates.py b/aurweb/templates.py index 6520bedf..781826ea 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -1,28 +1,27 @@ import copy import functools import os - from http import HTTPStatus from typing import Callable import jinja2 - from fastapi import Request from fastapi.responses import HTMLResponse import aurweb.config - from aurweb import cookies, l10n, time # Prepare jinja2 objects. -_loader = jinja2.FileSystemLoader(os.path.join( - aurweb.config.get("options", "aurwebdir"), "templates")) -_env = jinja2.Environment(loader=_loader, autoescape=True, - extensions=["jinja2.ext.i18n"]) +_loader = jinja2.FileSystemLoader( + os.path.join(aurweb.config.get("options", "aurwebdir"), "templates") +) +_env = jinja2.Environment( + loader=_loader, autoescape=True, extensions=["jinja2.ext.i18n"] +) def register_filter(name: str) -> Callable: - """ A decorator that can be used to register a filter. + """A decorator that can be used to register a filter. Example @register_filter("some_filter") @@ -35,31 +34,36 @@ def register_filter(name: str) -> Callable: :param name: Filter name :return: Callable used for filter """ + def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) + _env.filters[name] = wrapper return wrapper + return decorator def register_function(name: str) -> Callable: - """ A decorator that can be used to register a function. - """ + """A decorator that can be used to register a function.""" + def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) + if name in _env.globals: raise KeyError(f"Jinja already has a function named '{name}'") _env.globals[name] = wrapper return wrapper + return decorator def make_context(request: Request, title: str, next: str = None): - """ Create a context for a jinja2 TemplateResponse. """ + """Create a context for a jinja2 TemplateResponse.""" import aurweb.auth.creds commit_url = aurweb.config.get_with_fallback("devel", "commit_url", None) @@ -85,17 +89,19 @@ def make_context(request: Request, title: str, next: str = None): "config": aurweb.config, "creds": aurweb.auth.creds, "next": next if next else request.url.path, - "version": os.environ.get("COMMIT_HASH", aurweb.config.AURWEB_VERSION) + "version": os.environ.get("COMMIT_HASH", aurweb.config.AURWEB_VERSION), } async def make_variable_context(request: Request, title: str, next: str = None): - """ Make a context with variables provided by the user - (query params via GET or form data via POST). """ + """Make a context with variables provided by the user + (query params via GET or form data via POST).""" context = make_context(request, title, next) - to_copy = dict(request.query_params) \ - if request.method.lower() == "get" \ + to_copy = ( + dict(request.query_params) + if request.method.lower() == "get" else dict(await request.form()) + ) for k, v in to_copy.items(): context[k] = v @@ -111,7 +117,7 @@ def base_template(path: str): def render_raw_template(request: Request, path: str, context: dict): - """ Render a Jinja2 multi-lingual template with some context. """ + """Render a Jinja2 multi-lingual template with some context.""" # Create a deep copy of our jinja2 _environment. The _environment in # total by itself is 48 bytes large (according to sys.getsizeof). # This is done so we can install gettext translations on the template @@ -126,11 +132,10 @@ def render_raw_template(request: Request, path: str, context: dict): return template.render(context) -def render_template(request: Request, - path: str, - context: dict, - status_code: HTTPStatus = HTTPStatus.OK): - """ Render a template as an HTMLResponse. """ +def render_template( + request: Request, path: str, context: dict, status_code: HTTPStatus = HTTPStatus.OK +): + """Render a template as an HTMLResponse.""" rendered = render_raw_template(request, path, context) response = HTMLResponse(rendered, status_code=int(status_code)) diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py index 8261051d..4451eb3a 100644 --- a/aurweb/testing/__init__.py +++ b/aurweb/testing/__init__.py @@ -1,10 +1,9 @@ import aurweb.db - from aurweb import models def setup_test_db(*args): - """ This function is to be used to setup a test database before + """This function is to be used to setup a test database before using it. It takes a variable number of table strings, and for each table in that set of table strings, it deletes all records. diff --git a/aurweb/testing/alpm.py b/aurweb/testing/alpm.py index ce30d042..ddafb710 100644 --- a/aurweb/testing/alpm.py +++ b/aurweb/testing/alpm.py @@ -17,6 +17,7 @@ class AlpmDatabase: This class can be used to add or remove packages from a test repository. """ + repo = "test" def __init__(self, database_root: str): @@ -35,13 +36,14 @@ class AlpmDatabase: os.makedirs(pkgdir) return pkgdir - def add(self, pkgname: str, pkgver: str, arch: str, - provides: list[str] = []) -> None: + def add( + self, pkgname: str, pkgver: str, arch: str, provides: list[str] = [] + ) -> None: context = { "pkgname": pkgname, "pkgver": pkgver, "arch": arch, - "provides": provides + "provides": provides, } template = base_template("testing/alpm_package.j2") pkgdir = self._get_pkgdir(pkgname, pkgver, self.repo) @@ -76,8 +78,9 @@ class AlpmDatabase: self.clean() cmdline = ["bash", "-c", "bsdtar -czvf ../test.db *"] proc = subprocess.run(cmdline, cwd=self.repopath) - assert proc.returncode == 0, \ - f"Bad return code while creating alpm database: {proc.returncode}" + assert ( + proc.returncode == 0 + ), f"Bad return code while creating alpm database: {proc.returncode}" # Print out the md5 hash value of the new test.db. test_db = os.path.join(self.remote, "test.db") diff --git a/aurweb/testing/email.py b/aurweb/testing/email.py index b3e3990b..057ff792 100644 --- a/aurweb/testing/email.py +++ b/aurweb/testing/email.py @@ -5,7 +5,6 @@ import email import os import re import sys - from typing import TextIO @@ -28,6 +27,7 @@ class Email: print(email.headers) """ + TEST_DIR = "test-emails" def __init__(self, serial: int = 1, autoparse: bool = True): @@ -61,7 +61,7 @@ class Email: value = os.environ.get("PYTEST_CURRENT_TEST", "email").split(" ")[0] if suite: value = value.split(":")[0] - return re.sub(r'(\/|\.|,|:)', "_", value) + return re.sub(r"(\/|\.|,|:)", "_", value) @staticmethod def count() -> int: @@ -159,6 +159,6 @@ class Email: lines += [ f"== Email #{i + 1} ==", email.glue(), - f"== End of Email #{i + 1}" + f"== End of Email #{i + 1}", ] print("\n".join(lines), file=file) diff --git a/aurweb/testing/filelock.py b/aurweb/testing/filelock.py index 3a18c153..33b42cb3 100644 --- a/aurweb/testing/filelock.py +++ b/aurweb/testing/filelock.py @@ -1,6 +1,5 @@ import hashlib import os - from typing import Callable from posix_ipc import O_CREAT, Semaphore diff --git a/aurweb/testing/git.py b/aurweb/testing/git.py index 019d870f..216515c8 100644 --- a/aurweb/testing/git.py +++ b/aurweb/testing/git.py @@ -1,6 +1,5 @@ import os import shlex - from subprocess import PIPE, Popen from typing import Tuple diff --git a/aurweb/testing/html.py b/aurweb/testing/html.py index 8c923438..16b7322b 100644 --- a/aurweb/testing/html.py +++ b/aurweb/testing/html.py @@ -6,7 +6,7 @@ parser = etree.HTMLParser() def parse_root(html: str) -> etree.Element: - """ Parse an lxml.etree.ElementTree root from html content. + """Parse an lxml.etree.ElementTree root from html content. :param html: HTML markup :return: etree.Element diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py index c97d1532..98312e9e 100644 --- a/aurweb/testing/requests.py +++ b/aurweb/testing/requests.py @@ -2,7 +2,8 @@ import aurweb.config class User: - """ A fake User model. """ + """A fake User model.""" + # Fake columns. LangPreference = aurweb.config.get("options", "default_lang") Timezone = aurweb.config.get("options", "default_timezone") @@ -15,7 +16,8 @@ class User: class Client: - """ A fake FastAPI Request.client object. """ + """A fake FastAPI Request.client object.""" + # A fake host. host = "127.0.0.1" @@ -25,16 +27,19 @@ class URL: class Request: - """ A fake Request object which mimics a FastAPI Request for tests. """ + """A fake Request object which mimics a FastAPI Request for tests.""" + client = Client() url = URL() - def __init__(self, - user: User = User(), - authenticated: bool = False, - method: str = "GET", - headers: dict[str, str] = dict(), - cookies: dict[str, str] = dict()) -> "Request": + def __init__( + self, + user: User = User(), + authenticated: bool = False, + method: str = "GET", + headers: dict[str, str] = dict(), + cookies: dict[str, str] = dict(), + ) -> "Request": self.user = user self.user.authenticated = authenticated diff --git a/aurweb/testing/smtp.py b/aurweb/testing/smtp.py index e5d67991..7596fbe9 100644 --- a/aurweb/testing/smtp.py +++ b/aurweb/testing/smtp.py @@ -2,7 +2,7 @@ class FakeSMTP: - """ A fake version of smtplib.SMTP used for testing. """ + """A fake version of smtplib.SMTP used for testing.""" starttls_enabled = False use_ssl = False @@ -41,5 +41,6 @@ class FakeSMTP: class FakeSMTP_SSL(FakeSMTP): - """ A fake version of smtplib.SMTP_SSL used for testing. """ + """A fake version of smtplib.SMTP_SSL used for testing.""" + use_ssl = True diff --git a/aurweb/time.py b/aurweb/time.py index a97ca986..505f17f5 100644 --- a/aurweb/time.py +++ b/aurweb/time.py @@ -1,5 +1,4 @@ import zoneinfo - from collections import OrderedDict from datetime import datetime from urllib.parse import unquote @@ -11,7 +10,7 @@ import aurweb.config def tz_offset(name: str): - """ Get a timezone offset in the form "+00:00" by its name. + """Get a timezone offset in the form "+00:00" by its name. Example: tz_offset('America/Los_Angeles') @@ -24,7 +23,7 @@ def tz_offset(name: str): offset = dt.utcoffset().total_seconds() / 60 / 60 # Prefix the offset string with a - or +. - offset_string = '-' if offset < 0 else '+' + offset_string = "-" if offset < 0 else "+" # Remove any negativity from the offset. We want a good offset. :) offset = abs(offset) @@ -42,19 +41,25 @@ def tz_offset(name: str): return offset_string -SUPPORTED_TIMEZONES = OrderedDict({ - # Flatten out the list of tuples into an OrderedDict. - timezone: offset for timezone, offset in sorted([ - # Comprehend a list of tuples (timezone, offset display string) - # and sort them by (offset, timezone). - (tz, "(UTC%s) %s" % (tz_offset(tz), tz)) - for tz in zoneinfo.available_timezones() - ], key=lambda element: (tz_offset(element[0]), element[0])) -}) +SUPPORTED_TIMEZONES = OrderedDict( + { + # Flatten out the list of tuples into an OrderedDict. + timezone: offset + for timezone, offset in sorted( + [ + # Comprehend a list of tuples (timezone, offset display string) + # and sort them by (offset, timezone). + (tz, "(UTC%s) %s" % (tz_offset(tz), tz)) + for tz in zoneinfo.available_timezones() + ], + key=lambda element: (tz_offset(element[0]), element[0]), + ) + } +) def get_request_timezone(request: Request): - """ Get a request's timezone by its AURTZ cookie. We use the + """Get a request's timezone by its AURTZ cookie. We use the configuration's [options] default_timezone otherwise. @param request FastAPI request diff --git a/aurweb/users/update.py b/aurweb/users/update.py index ffea1f2f..51f2d2e0 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -8,12 +8,23 @@ from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.util import strtobool -def simple(U: str = str(), E: str = str(), H: bool = False, - BE: str = str(), R: str = str(), HP: str = str(), - I: str = str(), K: str = str(), J: bool = False, - CN: bool = False, UN: bool = False, ON: bool = False, - S: bool = False, user: models.User = None, - **kwargs) -> None: +def simple( + U: str = str(), + E: str = str(), + H: bool = False, + BE: str = str(), + R: str = str(), + HP: str = str(), + I: str = str(), + K: str = str(), + J: bool = False, + CN: bool = False, + UN: bool = False, + ON: bool = False, + S: bool = False, + user: models.User = None, + **kwargs, +) -> None: now = time.utcnow() with db.begin(): user.Username = U or user.Username @@ -31,22 +42,26 @@ def simple(U: str = str(), E: str = str(), H: bool = False, user.OwnershipNotify = strtobool(ON) -def language(L: str = str(), - request: Request = None, - user: models.User = None, - context: dict[str, Any] = {}, - **kwargs) -> None: +def language( + L: str = str(), + request: Request = None, + user: models.User = None, + context: dict[str, Any] = {}, + **kwargs, +) -> None: if L and L != user.LangPreference: with db.begin(): user.LangPreference = L context["language"] = L -def timezone(TZ: str = str(), - request: Request = None, - user: models.User = None, - context: dict[str, Any] = {}, - **kwargs) -> None: +def timezone( + TZ: str = str(), + request: Request = None, + user: models.User = None, + context: dict[str, Any] = {}, + **kwargs, +) -> None: if TZ and TZ != user.Timezone: with db.begin(): user.Timezone = TZ @@ -67,8 +82,7 @@ def ssh_pubkey(PK: str = str(), user: models.User = None, **kwargs) -> None: with db.begin(): # Delete any existing keys we can't find. - to_remove = user.ssh_pub_keys.filter( - ~SSHPubKey.Fingerprint.in_(fprints)) + to_remove = user.ssh_pub_keys.filter(~SSHPubKey.Fingerprint.in_(fprints)) db.delete_all(to_remove) # For each key, if it does not yet exist, create it. @@ -79,24 +93,27 @@ def ssh_pubkey(PK: str = str(), user: models.User = None, **kwargs) -> None: ).exists() if not db.query(exists).scalar(): # No public key exists, create one. - db.create(models.SSHPubKey, UserID=user.ID, - PubKey=" ".join([prefix, key]), - Fingerprint=fprints[i]) + db.create( + models.SSHPubKey, + UserID=user.ID, + PubKey=" ".join([prefix, key]), + Fingerprint=fprints[i], + ) -def account_type(T: int = None, - user: models.User = None, - **kwargs) -> None: +def account_type(T: int = None, user: models.User = None, **kwargs) -> None: if T is not None and (T := int(T)) != user.AccountTypeID: with db.begin(): user.AccountTypeID = T -def password(P: str = str(), - request: Request = None, - user: models.User = None, - context: dict[str, Any] = {}, - **kwargs) -> None: +def password( + P: str = str(), + request: Request = None, + user: models.User = None, + context: dict[str, Any] = {}, + **kwargs, +) -> None: if P and not user.valid_password(P): # Remove the fields we consumed for passwords. context["P"] = context["C"] = str() diff --git a/aurweb/users/validate.py b/aurweb/users/validate.py index de51e3ff..6c27a0b7 100644 --- a/aurweb/users/validate.py +++ b/aurweb/users/validate.py @@ -25,42 +25,44 @@ def invalid_fields(E: str = str(), U: str = str(), **kwargs) -> None: raise ValidationError(["Missing a required field."]) -def invalid_suspend_permission(request: Request = None, - user: models.User = None, - S: str = "False", - **kwargs) -> None: +def invalid_suspend_permission( + request: Request = None, user: models.User = None, S: str = "False", **kwargs +) -> None: if not request.user.is_elevated() and strtobool(S) != bool(user.Suspended): - raise ValidationError([ - "You do not have permission to suspend accounts."]) + raise ValidationError(["You do not have permission to suspend accounts."]) -def invalid_username(request: Request = None, U: str = str(), - _: l10n.Translator = None, - **kwargs) -> None: +def invalid_username( + request: Request = None, U: str = str(), _: l10n.Translator = None, **kwargs +) -> None: if not util.valid_username(U): username_min_len = config.getint("options", "username_min_len") username_max_len = config.getint("options", "username_max_len") - raise ValidationError([ - "The username is invalid.", + raise ValidationError( [ - _("It must be between %s and %s characters long") % ( - username_min_len, username_max_len), - "Start and end with a letter or number", - "Can contain only one period, underscore or hyphen.", + "The username is invalid.", + [ + _("It must be between %s and %s characters long") + % (username_min_len, username_max_len), + "Start and end with a letter or number", + "Can contain only one period, underscore or hyphen.", + ], ] - ]) + ) -def invalid_password(P: str = str(), C: str = str(), - _: l10n.Translator = None, **kwargs) -> None: +def invalid_password( + P: str = str(), C: str = str(), _: l10n.Translator = None, **kwargs +) -> None: if P: if not util.valid_password(P): - username_min_len = config.getint( - "options", "username_min_len") - raise ValidationError([ - _("Your password must be at least %s characters.") % ( - username_min_len) - ]) + username_min_len = config.getint("options", "username_min_len") + raise ValidationError( + [ + _("Your password must be at least %s characters.") + % (username_min_len) + ] + ) elif not C: raise ValidationError(["Please confirm your new password."]) elif P != C: @@ -71,15 +73,18 @@ def is_banned(request: Request = None, **kwargs) -> None: host = request.client.host exists = db.query(models.Ban, models.Ban.IPAddress == host).exists() if db.query(exists).scalar(): - raise ValidationError([ - "Account registration has been disabled for your " - "IP address, probably due to sustained spam attacks. " - "Sorry for the inconvenience." - ]) + raise ValidationError( + [ + "Account registration has been disabled for your " + "IP address, probably due to sustained spam attacks. " + "Sorry for the inconvenience." + ] + ) -def invalid_user_password(request: Request = None, passwd: str = str(), - **kwargs) -> None: +def invalid_user_password( + request: Request = None, passwd: str = str(), **kwargs +) -> None: if request.user.is_authenticated(): if not request.user.valid_password(passwd): raise ValidationError(["Invalid password."]) @@ -97,8 +102,9 @@ def invalid_backup_email(BE: str = str(), **kwargs) -> None: def invalid_homepage(HP: str = str(), **kwargs) -> None: if HP and not util.valid_homepage(HP): - raise ValidationError([ - "The home page is invalid, please specify the full HTTP(s) URL."]) + raise ValidationError( + ["The home page is invalid, please specify the full HTTP(s) URL."] + ) def invalid_pgp_key(K: str = str(), **kwargs) -> None: @@ -106,8 +112,9 @@ def invalid_pgp_key(K: str = str(), **kwargs) -> None: raise ValidationError(["The PGP key fingerprint is invalid."]) -def invalid_ssh_pubkey(PK: str = str(), user: models.User = None, - _: l10n.Translator = None, **kwargs) -> None: +def invalid_ssh_pubkey( + PK: str = str(), user: models.User = None, _: l10n.Translator = None, **kwargs +) -> None: if not PK: return @@ -119,15 +126,23 @@ def invalid_ssh_pubkey(PK: str = str(), user: models.User = None, for prefix, key in keys: fingerprint = get_fingerprint(f"{prefix} {key}") - exists = db.query(models.SSHPubKey).filter( - and_(models.SSHPubKey.UserID != user.ID, - models.SSHPubKey.Fingerprint == fingerprint) - ).exists() + exists = ( + db.query(models.SSHPubKey) + .filter( + and_( + models.SSHPubKey.UserID != user.ID, + models.SSHPubKey.Fingerprint == fingerprint, + ) + ) + .exists() + ) if db.query(exists).scalar(): - raise ValidationError([ - _("The SSH public key, %s%s%s, is already in use.") % ( - "", fingerprint, "") - ]) + raise ValidationError( + [ + _("The SSH public key, %s%s%s, is already in use.") + % ("", fingerprint, "") + ] + ) def invalid_language(L: str = str(), **kwargs) -> None: @@ -140,60 +155,78 @@ def invalid_timezone(TZ: str = str(), **kwargs) -> None: raise ValidationError(["Timezone is not currently supported."]) -def username_in_use(U: str = str(), user: models.User = None, - _: l10n.Translator = None, **kwargs) -> None: - exists = db.query(models.User).filter( - and_(models.User.ID != user.ID, - models.User.Username == U) - ).exists() +def username_in_use( + U: str = str(), user: models.User = None, _: l10n.Translator = None, **kwargs +) -> None: + exists = ( + db.query(models.User) + .filter(and_(models.User.ID != user.ID, models.User.Username == U)) + .exists() + ) if db.query(exists).scalar(): # If the username already exists... - raise ValidationError([ - _("The username, %s%s%s, is already in use.") % ( - "", U, "") - ]) + raise ValidationError( + [ + _("The username, %s%s%s, is already in use.") + % ("", U, "") + ] + ) -def email_in_use(E: str = str(), user: models.User = None, - _: l10n.Translator = None, **kwargs) -> None: - exists = db.query(models.User).filter( - and_(models.User.ID != user.ID, - models.User.Email == E) - ).exists() +def email_in_use( + E: str = str(), user: models.User = None, _: l10n.Translator = None, **kwargs +) -> None: + exists = ( + db.query(models.User) + .filter(and_(models.User.ID != user.ID, models.User.Email == E)) + .exists() + ) if db.query(exists).scalar(): # If the email already exists... - raise ValidationError([ - _("The address, %s%s%s, is already in use.") % ( - "", E, "") - ]) + raise ValidationError( + [ + _("The address, %s%s%s, is already in use.") + % ("", E, "") + ] + ) -def invalid_account_type(T: int = None, request: Request = None, - user: models.User = None, - _: l10n.Translator = None, - **kwargs) -> None: +def invalid_account_type( + T: int = None, + request: Request = None, + user: models.User = None, + _: l10n.Translator = None, + **kwargs, +) -> None: if T is not None and (T := int(T)) != user.AccountTypeID: name = ACCOUNT_TYPE_NAME.get(T, None) has_cred = request.user.has_credential(creds.ACCOUNT_CHANGE_TYPE) if name is None: raise ValidationError(["Invalid account type provided."]) elif not has_cred: - raise ValidationError([ - "You do not have permission to change account types."]) + raise ValidationError( + ["You do not have permission to change account types."] + ) elif T > request.user.AccountTypeID: # If the chosen account type is higher than the editor's account # type, the editor doesn't have permission to set the new type. - error = _("You do not have permission to change " - "this user's account type to %s.") % name + error = ( + _( + "You do not have permission to change " + "this user's account type to %s." + ) + % name + ) raise ValidationError([error]) - logger.debug(f"Trusted User '{request.user.Username}' has " - f"modified '{user.Username}' account's type to" - f" {name}.") + logger.debug( + f"Trusted User '{request.user.Username}' has " + f"modified '{user.Username}' account's type to" + f" {name}." + ) -def invalid_captcha(captcha_salt: str = None, captcha: str = None, - **kwargs) -> None: +def invalid_captcha(captcha_salt: str = None, captcha: str = None, **kwargs) -> None: if captcha_salt and captcha_salt not in get_captcha_salts(): raise ValidationError(["This CAPTCHA has expired. Please try again."]) diff --git a/aurweb/util.py b/aurweb/util.py index 8291b578..4f1bd64e 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -2,7 +2,6 @@ import math import re import secrets import string - from datetime import datetime from http import HTTPStatus from subprocess import PIPE, Popen @@ -11,12 +10,10 @@ from urllib.parse import urlparse import fastapi import pygit2 - from email_validator import EmailSyntaxError, validate_email from fastapi.responses import JSONResponse import aurweb.config - from aurweb import defaults, logging logger = logging.get_logger(__name__) @@ -24,15 +21,15 @@ logger = logging.get_logger(__name__) def make_random_string(length: int) -> str: alphanumerics = string.ascii_lowercase + string.digits - return ''.join([secrets.choice(alphanumerics) for i in range(length)]) + return "".join([secrets.choice(alphanumerics) for i in range(length)]) def make_nonce(length: int = 8): - """ Generate a single random nonce. Here, token_hex generates a hex + """Generate a single random nonce. Here, token_hex generates a hex string of 2 hex characters per byte, where the length give is nbytes. This means that to get our proper string length, we need to cut it in half and truncate off any remaining (in the case that - length was uneven). """ + length was uneven).""" return secrets.token_hex(math.ceil(length / 2))[:length] @@ -45,7 +42,7 @@ def valid_username(username): # Check that username contains: one or more alphanumeric # characters, an optional separator of '.', '-' or '_', followed # by alphanumeric characters. - return re.match(r'^[a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$', username) + return re.match(r"^[a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$", username) def valid_email(email): @@ -82,7 +79,7 @@ def valid_pgp_fingerprint(fp): def jsonify(obj): - """ Perform a conversion on obj if it's needed. """ + """Perform a conversion on obj if it's needed.""" if isinstance(obj, datetime): obj = int(obj.timestamp()) return obj @@ -151,8 +148,7 @@ def git_search(repo: pygit2.Repository, commit_hash: str) -> int: return prefixlen -async def error_or_result(next: Callable, *args, **kwargs) \ - -> fastapi.Response: +async def error_or_result(next: Callable, *args, **kwargs) -> fastapi.Response: """ Try to return a response from `next`. @@ -174,9 +170,9 @@ async def error_or_result(next: Callable, *args, **kwargs) \ def parse_ssh_key(string: str) -> Tuple[str, str]: - """ Parse an SSH public key. """ + """Parse an SSH public key.""" invalid_exc = ValueError("The SSH public key is invalid.") - parts = re.sub(r'\s\s+', ' ', string.strip()).split() + parts = re.sub(r"\s\s+", " ", string.strip()).split() if len(parts) < 2: raise invalid_exc @@ -185,8 +181,7 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: if prefix not in prefixes: raise invalid_exc - proc = Popen(["ssh-keygen", "-l", "-f", "-"], stdin=PIPE, stdout=PIPE, - stderr=PIPE) + proc = Popen(["ssh-keygen", "-l", "-f", "-"], stdin=PIPE, stdout=PIPE, stderr=PIPE) out, _ = proc.communicate(f"{prefix} {key}".encode()) if proc.returncode: raise invalid_exc @@ -195,5 +190,5 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: def parse_ssh_keys(string: str) -> list[Tuple[str, str]]: - """ Parse a list of SSH public keys. """ + """Parse a list of SSH public keys.""" return [parse_ssh_key(e) for e in string.splitlines()] diff --git a/doc/web-auth.md b/doc/web-auth.md index 17284889..dbb4403d 100644 --- a/doc/web-auth.md +++ b/doc/web-auth.md @@ -108,4 +108,3 @@ The following list of steps describes exactly how this verification works: - `options.disable_http_login: 1` - `options.login_timeout: ` - `options.persistent_cookie_timeout: ` - diff --git a/docker-compose.yml b/docker-compose.yml index 9edffeeb..a1c2bb42 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,7 +43,7 @@ services: healthcheck: test: "bash /docker/health/memcached.sh" interval: 3s - + redis: image: aurweb:latest init: true diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index 9fdf6015..99804d1d 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -147,4 +147,3 @@ http { '' close; } } - diff --git a/migrations/env.py b/migrations/env.py index 774ecdeb..dcc0329d 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -2,7 +2,6 @@ import logging import logging.config import sqlalchemy - from alembic import context import aurweb.db @@ -69,9 +68,7 @@ def run_migrations_online(): ) with connectable.connect() as connection: - context.configure( - connection=connection, target_metadata=target_metadata - ) + context.configure(connection=connection, target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() diff --git a/po/ar.po b/po/ar.po index 676a5025..ea0e03cf 100644 --- a/po/ar.po +++ b/po/ar.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # safa1996alfulaij , 2015 # صفا الفليج , 2015-2016 diff --git a/po/ast.po b/po/ast.po index 16c363a6..2075edc1 100644 --- a/po/ast.po +++ b/po/ast.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # enolp , 2014-2015,2017 # Ḷḷumex03 , 2014 diff --git a/po/az.po b/po/az.po index 7e534b4c..1c7ca207 100644 --- a/po/az.po +++ b/po/az.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/az_AZ.po b/po/az_AZ.po index e903027b..2f5ceabd 100644 --- a/po/az_AZ.po +++ b/po/az_AZ.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/bg.po b/po/bg.po index 7864f5dc..c7c70021 100644 --- a/po/bg.po +++ b/po/bg.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/ca.po b/po/ca.po index 391dd146..d43c84dc 100644 --- a/po/ca.po +++ b/po/ca.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Adolfo Jayme-Barrientos, 2014 # Hector Mtz-Seara , 2011,2013 diff --git a/po/ca_ES.po b/po/ca_ES.po index bad69bd1..aac7b03f 100644 --- a/po/ca_ES.po +++ b/po/ca_ES.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/cs.po b/po/cs.po index b9bd739a..59a24007 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Daniel Milde , 2017 # Daniel Peukert , 2021 diff --git a/po/da.po b/po/da.po index a6f290ea..822b5506 100644 --- a/po/da.po +++ b/po/da.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Linuxbruger , 2018 # Louis Tim Larsen , 2015 diff --git a/po/de.po b/po/de.po index ec0a0fbe..a0f8fb0f 100644 --- a/po/de.po +++ b/po/de.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # 9d91e189c22376bb4ee81489bc27fc28, 2013 # 9d91e189c22376bb4ee81489bc27fc28, 2013-2014 diff --git a/po/el.po b/po/el.po index f1fe704e..37db785c 100644 --- a/po/el.po +++ b/po/el.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Achilleas Pipinellis, 2014 # Achilleas Pipinellis, 2013 diff --git a/po/es.po b/po/es.po index ea7ac099..9cbe98a6 100644 --- a/po/es.po +++ b/po/es.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Adolfo Jayme-Barrientos, 2015 # Angel Velasquez , 2011 diff --git a/po/es_419.po b/po/es_419.po index 444eccb7..e2b96ae6 100644 --- a/po/es_419.po +++ b/po/es_419.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Angel Velasquez , 2011 # juantascon , 2011 diff --git a/po/et.po b/po/et.po index 9b6493b5..44f2b3a0 100644 --- a/po/et.po +++ b/po/et.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/fi.po b/po/fi.po index 39cfe626..636681b7 100644 --- a/po/fi.po +++ b/po/fi.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Elias Autio, 2016 # Jesse Jaara , 2011-2012,2015 diff --git a/po/fi_FI.po b/po/fi_FI.po index f3253433..17a58b4a 100644 --- a/po/fi_FI.po +++ b/po/fi_FI.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/fr.po b/po/fr.po index 99d01460..03192d48 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Alexandre Macabies , 2018 # Antoine Lubineau , 2012 diff --git a/po/he.po b/po/he.po index cd4a0f87..936e93a1 100644 --- a/po/he.po +++ b/po/he.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # GenghisKhan , 2016 # Lukas Fleischer , 2011 diff --git a/po/hi_IN.po b/po/hi_IN.po index 37fd082e..114c9461 100644 --- a/po/hi_IN.po +++ b/po/hi_IN.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Panwar108 , 2018,2020-2021 msgid "" diff --git a/po/hr.po b/po/hr.po index 4932bd7e..fe1857c1 100644 --- a/po/hr.po +++ b/po/hr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 msgid "" diff --git a/po/hu.po b/po/hu.po index 51894457..e6ebd451 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Balló György , 2013 # Balló György , 2011,2013-2016 diff --git a/po/id.po b/po/id.po index 75a6c98b..103c47e6 100644 --- a/po/id.po +++ b/po/id.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # se7entime , 2013 # se7entime , 2016 diff --git a/po/id_ID.po b/po/id_ID.po index d01294c8..c3acb167 100644 --- a/po/id_ID.po +++ b/po/id_ID.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/is.po b/po/is.po index a7a88b04..aee80ce5 100644 --- a/po/is.po +++ b/po/is.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/it.po b/po/it.po index 436b6459..f583cb2f 100644 --- a/po/it.po +++ b/po/it.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Fanfurlio Farolfi , 2021-2022 # Giovanni Scafora , 2011-2015 diff --git a/po/ja.po b/po/ja.po index 55d056bf..280edb46 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # kusakata, 2013 # kusakata, 2013 diff --git a/po/ko.po b/po/ko.po index 808ffe27..6da57759 100644 --- a/po/ko.po +++ b/po/ko.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/lt.po b/po/lt.po index d126f193..c9f55632 100644 --- a/po/lt.po +++ b/po/lt.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/nb.po b/po/nb.po index 1cc090f1..307a80d6 100644 --- a/po/nb.po +++ b/po/nb.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Alexander F. Rødseth , 2015,2017-2019 # Alexander F. Rødseth , 2011,2013-2014 diff --git a/po/nb_NO.po b/po/nb_NO.po index 74af6936..5d958172 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Kim Nordmo , 2017,2019 # Lukas Fleischer , 2011 diff --git a/po/nl.po b/po/nl.po index 282b5b40..54519d21 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Heimen Stoffels , 2021-2022 # Heimen Stoffels , 2015,2021 diff --git a/po/pl.po b/po/pl.po index 4856f22b..94a6fb67 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Bartłomiej Piotrowski , 2011 # Bartłomiej Piotrowski , 2014 diff --git a/po/pt.po b/po/pt.po index b2cf86b2..aed32031 100644 --- a/po/pt.po +++ b/po/pt.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 msgid "" diff --git a/po/pt_BR.po b/po/pt_BR.po index c9c15d72..d29a9448 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Albino Biasutti Neto Bino , 2011 # Fábio Nogueira , 2016 diff --git a/po/pt_PT.po b/po/pt_PT.po index 3518cb7b..7f6ea67a 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Christophe Silva , 2018 # Gaspar Santos , 2011 diff --git a/po/ro.po b/po/ro.po index fa159928..4409b698 100644 --- a/po/ro.po +++ b/po/ro.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Arthur Țițeică , 2013-2015 # Lukas Fleischer , 2011 diff --git a/po/ru.po b/po/ru.po index 75550c8c..44f000dd 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Alex , 2021 # Evgeniy Alekseev , 2014-2015 diff --git a/po/sk.po b/po/sk.po index 76d3d1a8..853fc198 100644 --- a/po/sk.po +++ b/po/sk.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # archetyp , 2013-2016 # Jose Riha , 2018 diff --git a/po/sr.po b/po/sr.po index dae37bcd..426ce599 100644 --- a/po/sr.po +++ b/po/sr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 # Slobodan Terzić , 2011-2012,2015-2017 diff --git a/po/sr_RS.po b/po/sr_RS.po index 985ee007..b7560965 100644 --- a/po/sr_RS.po +++ b/po/sr_RS.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Nikola Stojković , 2013 msgid "" diff --git a/po/sv_SE.po b/po/sv_SE.po index 6abb8452..4887fdde 100644 --- a/po/sv_SE.po +++ b/po/sv_SE.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Johannes Löthberg , 2015-2016 # Kevin Morris , 2022 diff --git a/po/tr.po b/po/tr.po index 83b1e4df..559a0008 100644 --- a/po/tr.po +++ b/po/tr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # tarakbumba , 2011,2013-2015 # tarakbumba , 2012,2014 diff --git a/po/uk.po b/po/uk.po index a4410185..3bffe4f6 100644 --- a/po/uk.po +++ b/po/uk.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 # Rax Garfield , 2012 diff --git a/po/vi.po b/po/vi.po index 3ea5bad3..87f7faac 100644 --- a/po/vi.po +++ b/po/vi.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/zh.po b/po/zh.po index 04fe06f3..c932df9c 100644 --- a/po/zh.po +++ b/po/zh.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 53d42bc8..675d15a3 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Feng Chao , 2015-2016 # dongfengweixiao , 2015 diff --git a/po/zh_TW.po b/po/zh_TW.po index e7399a19..1526b4a9 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # pan93412 , 2018 # 黃柏諺 , 2014-2017 diff --git a/schema/gendummydata.py b/schema/gendummydata.py index aedfda7e..fa59855f 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -15,27 +15,26 @@ import os import random import sys import time - from datetime import datetime import bcrypt LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output SEED_FILE = "/usr/share/dict/words" -USER_ID = 5 # Users.ID of first bogus user -PKG_ID = 1 # Packages.ID of first package +USER_ID = 5 # Users.ID of first bogus user +PKG_ID = 1 # Packages.ID of first package # how many users to 'register' MAX_USERS = int(os.environ.get("MAX_USERS", 38000)) -MAX_DEVS = .1 # what percentage of MAX_USERS are Developers -MAX_TUS = .2 # what percentage of MAX_USERS are Trusted Users +MAX_DEVS = 0.1 # what percentage of MAX_USERS are Developers +MAX_TUS = 0.2 # what percentage of MAX_USERS are Trusted Users # how many packages to load MAX_PKGS = int(os.environ.get("MAX_PKGS", 32000)) -PKG_DEPS = (1, 15) # min/max depends a package has -PKG_RELS = (1, 5) # min/max relations a package has -PKG_SRC = (1, 3) # min/max sources a package has -PKG_CMNTS = (1, 5) # min/max number of comments a package has +PKG_DEPS = (1, 15) # min/max depends a package has +PKG_RELS = (1, 5) # min/max relations a package has +PKG_SRC = (1, 3) # min/max sources a package has +PKG_CMNTS = (1, 5) # min/max number of comments a package has CATEGORIES_COUNT = 17 # the number of categories from aur-schema -VOTING = (0, .001) # percentage range for package voting +VOTING = (0, 0.001) # percentage range for package voting # number of open trusted user proposals OPEN_PROPOSALS = int(os.environ.get("OPEN_PROPOSALS", 15)) # number of closed trusted user proposals @@ -113,10 +112,10 @@ if not len(contents) - MAX_USERS > MAX_PKGS: def normalize(unicode_data): - """ We only accept ascii for usernames. Also use this to normalize + """We only accept ascii for usernames. Also use this to normalize package names; our database utf8mb4 collations compare with Unicode - Equivalence. """ - return unicode_data.encode('ascii', 'ignore').decode('ascii') + Equivalence.""" + return unicode_data.encode("ascii", "ignore").decode("ascii") # select random usernames @@ -196,10 +195,12 @@ for u in user_keys: # "{salt}{username}" to_hash = f"{salt}{u}" - h = hashlib.new('md5') + h = hashlib.new("md5") h.update(to_hash.encode()) - s = ("INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd, Salt)" - " VALUES (%d, %d, '%s', '%s@example.com', '%s', '%s');\n") + s = ( + "INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd, Salt)" + " VALUES (%d, %d, '%s', '%s@example.com', '%s', '%s');\n" + ) s = s % (seen_users[u], account_type, u, u, h.hexdigest(), salt) out.write(s) @@ -230,13 +231,17 @@ for p in list(seen_pkgs.keys()): uuid = genUID() # the submitter/user - s = ("INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, " - "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', '', %d, %d, %d, %s, %s);\n") + s = ( + "INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, " + "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', '', %d, %d, %d, %s, %s);\n" + ) s = s % (seen_pkgs[p], p, NOW, NOW, uuid, muid, puid) out.write(s) - s = ("INSERT INTO Packages (ID, PackageBaseID, Name, Version) VALUES " - "(%d, %d, '%s', '%s');\n") + s = ( + "INSERT INTO Packages (ID, PackageBaseID, Name, Version) VALUES " + "(%d, %d, '%s', '%s');\n" + ) s = s % (seen_pkgs[p], seen_pkgs[p], p, genVersion()) out.write(s) @@ -247,8 +252,10 @@ for p in list(seen_pkgs.keys()): num_comments = random.randrange(PKG_CMNTS[0], PKG_CMNTS[1]) for i in range(0, num_comments): now = NOW + random.randrange(400, 86400 * 3) - s = ("INSERT INTO PackageComments (PackageBaseID, UsersID," - " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n") + s = ( + "INSERT INTO PackageComments (PackageBaseID, UsersID," + " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n" + ) s = s % (seen_pkgs[p], genUID(), genFortune(), now) out.write(s) @@ -258,14 +265,17 @@ utcnow = int(datetime.utcnow().timestamp()) track_votes = {} log.debug("Casting votes for packages.") for u in user_keys: - num_votes = random.randrange(int(len(seen_pkgs) * VOTING[0]), - int(len(seen_pkgs) * VOTING[1])) + num_votes = random.randrange( + int(len(seen_pkgs) * VOTING[0]), int(len(seen_pkgs) * VOTING[1]) + ) pkgvote = {} for v in range(num_votes): pkg = random.randrange(1, len(seen_pkgs) + 1) if pkg not in pkgvote: - s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS)" - " VALUES (%d, %d, %d);\n") + s = ( + "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS)" + " VALUES (%d, %d, %d);\n" + ) s = s % (seen_users[u], pkg, utcnow) pkgvote[pkg] = 1 if pkg not in track_votes: @@ -310,9 +320,12 @@ for p in seen_pkgs_keys: src_file = user_keys[random.randrange(0, len(user_keys))] src = "%s%s.%s/%s/%s-%s.tar.gz" % ( RANDOM_URL[random.randrange(0, len(RANDOM_URL))], - p, RANDOM_TLDS[random.randrange(0, len(RANDOM_TLDS))], + p, + RANDOM_TLDS[random.randrange(0, len(RANDOM_TLDS))], RANDOM_LOCS[random.randrange(0, len(RANDOM_LOCS))], - src_file, genVersion()) + src_file, + genVersion(), + ) s = "INSERT INTO PackageSources(PackageID, Source) VALUES (%d, '%s');\n" s = s % (seen_pkgs[p], src) out.write(s) @@ -334,8 +347,10 @@ for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS): else: user = user_keys[random.randrange(0, len(user_keys))] suid = trustedusers[random.randrange(0, len(trustedusers))] - s = ("INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End," - " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n") + s = ( + "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End," + " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n" + ) s = s % (genFortune(), user, start, end, suid) out.write(s) count += 1 diff --git a/templates/addvote.html b/templates/addvote.html index 4d2b0292..8777cbf3 100644 --- a/templates/addvote.html +++ b/templates/addvote.html @@ -65,4 +65,3 @@ {% endblock %} - diff --git a/templates/home.html b/templates/home.html index c1f172f4..6a5fca69 100644 --- a/templates/home.html +++ b/templates/home.html @@ -5,7 +5,7 @@ | tr | format('', "", '', "") - | safe + | safe }} {{ "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s otherwise they will be deleted!" | tr @@ -61,7 +61,7 @@ {% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %}

        - {% for keytype in ssh_fingerprints %} + {% for keytype in ssh_fingerprints %}
      • {{ keytype }}: {{ ssh_fingerprints[keytype] }} {% endfor %}
      @@ -85,7 +85,7 @@ | tr | format('', "", "", "") - | safe + | safe }}

      diff --git a/templates/packages/index.html b/templates/packages/index.html index 6034d2f6..58ce8648 100644 --- a/templates/packages/index.html +++ b/templates/packages/index.html @@ -12,7 +12,7 @@ {% elif not packages_count %} - {% include "partials/packages/search.html" %} + {% include "partials/packages/search.html" %}

      {{ "No packages matched your search criteria." | tr }}

      diff --git a/templates/partials/account/results.html b/templates/partials/account/results.html index 1c398ce1..ef8d927a 100644 --- a/templates/partials/account/results.html +++ b/templates/partials/account/results.html @@ -79,4 +79,3 @@
    • - diff --git a/templates/tu/show.html b/templates/tu/show.html index c36a3e8f..f4214018 100644 --- a/templates/tu/show.html +++ b/templates/tu/show.html @@ -4,7 +4,7 @@
      {% include "partials/tu/proposal/details.html" %}
      - + {% if utcnow >= voteinfo.End %}
      {% include "partials/tu/proposal/voters.html" %} diff --git a/test/conftest.py b/test/conftest.py index 283c979a..aac221f7 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -39,12 +39,10 @@ ahead of each function takes too long when compared to this method. """ import os import pathlib - from multiprocessing import Lock import py import pytest - from posix_ipc import O_CREAT, Semaphore from sqlalchemy import create_engine from sqlalchemy.engine import URL @@ -54,7 +52,6 @@ from sqlalchemy.orm import scoped_session import aurweb.config import aurweb.db - from aurweb import initdb, logging, testing from aurweb.testing.email import Email from aurweb.testing.filelock import FileLock @@ -78,13 +75,10 @@ def test_engine() -> Engine: unix_socket = aurweb.config.get_with_fallback("database", "socket", None) kwargs = { "username": aurweb.config.get("database", "user"), - "password": aurweb.config.get_with_fallback( - "database", "password", None), + "password": aurweb.config.get_with_fallback("database", "password", None), "host": aurweb.config.get("database", "host"), "port": aurweb.config.get_with_fallback("database", "port", None), - "query": { - "unix_socket": unix_socket - } + "query": {"unix_socket": unix_socket}, } backend = aurweb.config.get("database", "backend") @@ -99,6 +93,7 @@ class AlembicArgs: This structure is needed to pass conftest-specific arguments to initdb.run duration database creation. """ + verbose = False use_alembic = True @@ -156,7 +151,7 @@ def setup_email(): @pytest.fixture(scope="module") def setup_database(tmp_path_factory: pathlib.Path, worker_id: str) -> None: - """ Create and drop a database for the suite this fixture is used in. """ + """Create and drop a database for the suite this fixture is used in.""" engine = test_engine() dbname = aurweb.db.name() diff --git a/test/test_accepted_term.py b/test/test_accepted_term.py index 2af7127b..9af19105 100644 --- a/test/test_accepted_term.py +++ b/test/test_accepted_term.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -17,17 +16,21 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def term() -> Term: with db.begin(): - term = db.create(Term, Description="Test term", - URL="https://test.term") + term = db.create(Term, Description="Test term", URL="https://test.term") yield term diff --git a/test/test_account_type.py b/test/test_account_type.py index 1d71f878..4b56b7ff 100644 --- a/test/test_account_type.py +++ b/test/test_account_type.py @@ -22,26 +22,30 @@ def account_type() -> AccountType: def test_account_type(account_type): - """ Test creating an AccountType, and reading its columns. """ + """Test creating an AccountType, and reading its columns.""" # Make sure it got db.created and was given an ID. assert bool(account_type.ID) # Next, test our string functions. assert str(account_type) == "TestUser" - assert repr(account_type) == \ - "" % ( - account_type.ID) + assert repr(account_type) == "" % ( + account_type.ID + ) - record = db.query(AccountType, - AccountType.AccountType == "TestUser").first() + record = db.query(AccountType, AccountType.AccountType == "TestUser").first() assert account_type == record def test_user_account_type_relationship(account_type): with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=account_type) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountType=account_type, + ) assert user.AccountType == account_type diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 37b3d130..eab8fa4f 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -1,6 +1,5 @@ import re import tempfile - from datetime import datetime from http import HTTPStatus from logging import DEBUG @@ -8,17 +7,21 @@ from subprocess import Popen import lxml.html import pytest - from fastapi.testclient import TestClient import aurweb.models.account_type as at - from aurweb import captcha, db, logging, time from aurweb.asgi import app from aurweb.db import create, query from aurweb.models.accepted_term import AcceptedTerm -from aurweb.models.account_type import (DEVELOPER_ID, TRUSTED_USER, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID, - AccountType) +from aurweb.models.account_type import ( + DEVELOPER_ID, + TRUSTED_USER, + TRUSTED_USER_AND_DEV_ID, + TRUSTED_USER_ID, + USER_ID, + AccountType, +) from aurweb.models.ban import Ban from aurweb.models.session import Session from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint @@ -39,8 +42,11 @@ def make_ssh_pubkey(): # dependency to passing this test). with tempfile.TemporaryDirectory() as tmpdir: with open("/dev/null", "w") as null: - proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], - stdout=null, stderr=null) + proc = Popen( + ["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, + stderr=null, + ) proc.wait() assert proc.returncode == 0 @@ -60,9 +66,13 @@ def client() -> TestClient: def create_user(username: str) -> User: email = f"{username}@example.org" - user = create(User, Username=username, Email=email, - Passwd="testPassword", - AccountTypeID=USER_ID) + user = create( + User, + Username=username, + Email=email, + Passwd="testPassword", + AccountTypeID=USER_ID, + ) return user @@ -85,8 +95,9 @@ def test_get_passreset_authed_redirects(client: TestClient, user: User): assert sid is not None with client as request: - response = request.get("/passreset", cookies={"AURSID": sid}, - allow_redirects=False) + response = request.get( + "/passreset", cookies={"AURSID": sid}, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -129,10 +140,12 @@ def test_post_passreset_authed_redirects(client: TestClient, user: User): assert sid is not None with client as request: - response = request.post("/passreset", - cookies={"AURSID": sid}, - data={"user": "blah"}, - allow_redirects=False) + response = request.post( + "/passreset", + cookies={"AURSID": sid}, + data={"user": "blah"}, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -166,8 +179,9 @@ def test_post_passreset_user_suspended(client: TestClient, user: User): def test_post_passreset_resetkey(client: TestClient, user: User): with db.begin(): - user.session = Session(UsersID=user.ID, SessionID="blah", - LastUpdateTS=time.utcnow()) + user.session = Session( + UsersID=user.ID, SessionID="blah", LastUpdateTS=time.utcnow() + ) # Prepare a password reset. with client as request: @@ -182,7 +196,7 @@ def test_post_passreset_resetkey(client: TestClient, user: User): "user": TEST_USERNAME, "resetkey": resetkey, "password": "abcd1234", - "confirm": "abcd1234" + "confirm": "abcd1234", } with client as request: @@ -200,10 +214,7 @@ def make_resetkey(client: TestClient, user: User): def make_passreset_data(user: User, resetkey: str): - return { - "user": user.Username, - "resetkey": resetkey - } + return {"user": user.Username, "resetkey": resetkey} def test_post_passreset_error_invalid_email(client: TestClient, user: User): @@ -240,8 +251,7 @@ def test_post_passreset_error_missing_field(client: TestClient, user: User): assert error in response.content.decode("utf-8") -def test_post_passreset_error_password_mismatch(client: TestClient, - user: User): +def test_post_passreset_error_password_mismatch(client: TestClient, user: User): resetkey = make_resetkey(client, user) post_data = make_passreset_data(user, resetkey) @@ -257,8 +267,7 @@ def test_post_passreset_error_password_mismatch(client: TestClient, assert error in response.content.decode("utf-8") -def test_post_passreset_error_password_requirements(client: TestClient, - user: User): +def test_post_passreset_error_password_requirements(client: TestClient, user: User): resetkey = make_resetkey(client, user) post_data = make_passreset_data(user, resetkey) @@ -284,7 +293,7 @@ def test_get_register(client: TestClient): def post_register(request, **kwargs): - """ A simple helper that allows overrides to test defaults. """ + """A simple helper that allows overrides to test defaults.""" salt = captcha.get_captcha_salts()[0] token = captcha.get_captcha_token(salt) answer = captcha.get_captcha_answer(token) @@ -297,7 +306,7 @@ def post_register(request, **kwargs): "L": "en", "TZ": "UTC", "captcha": answer, - "captcha_salt": salt + "captcha_salt": salt, } # For any kwargs given, override their k:v pairs in data. @@ -380,9 +389,11 @@ def test_post_register_error_ip_banned(client: TestClient): assert response.status_code == int(HTTPStatus.BAD_REQUEST) content = response.content.decode() - assert ("Account registration has been disabled for your IP address, " + - "probably due to sustained spam attacks. Sorry for the " + - "inconvenience.") in content + assert ( + "Account registration has been disabled for your IP address, " + + "probably due to sustained spam attacks. Sorry for the " + + "inconvenience." + ) in content def test_post_register_error_missing_username(client: TestClient): @@ -489,7 +500,7 @@ def test_post_register_error_invalid_pgp_fingerprints(client: TestClient): expected = "The PGP key fingerprint is invalid." assert expected in content - pk = 'z' + ('a' * 39) + pk = "z" + ("a" * 39) with client as request: response = post_register(request, K=pk) @@ -569,8 +580,11 @@ def test_post_register_error_ssh_pubkey_taken(client: TestClient, user: User): # dependency to passing this test). with tempfile.TemporaryDirectory() as tmpdir: with open("/dev/null", "w") as null: - proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], - stdout=null, stderr=null) + proc = Popen( + ["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, + stderr=null, + ) proc.wait() assert proc.returncode == 0 @@ -602,8 +616,11 @@ def test_post_register_with_ssh_pubkey(client: TestClient): # dependency to passing this test). with tempfile.TemporaryDirectory() as tmpdir: with open("/dev/null", "w") as null: - proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], - stdout=null, stderr=null) + proc = Popen( + ["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""], + stdout=null, + stderr=null, + ) proc.wait() assert proc.returncode == 0 @@ -617,7 +634,7 @@ def test_post_register_with_ssh_pubkey(client: TestClient): def test_get_account_edit_tu_as_tu(client: TestClient, tu_user: User): - """ Test edit get route of another TU as a TU. """ + """Test edit get route of another TU as a TU.""" with db.begin(): user2 = create_user("test2") user2.AccountTypeID = at.TRUSTED_USER_ID @@ -643,7 +660,7 @@ def test_get_account_edit_tu_as_tu(client: TestClient, tu_user: User): def test_get_account_edit_as_tu(client: TestClient, tu_user: User): - """ Test edit get route of another user as a TU. """ + """Test edit get route of another user as a TU.""" with db.begin(): user2 = create_user("test2") @@ -669,7 +686,7 @@ def test_get_account_edit_as_tu(client: TestClient, tu_user: User): def test_get_account_edit_type(client: TestClient, user: User): - """ Test that users do not have an Account Type field. """ + """Test that users do not have an Account Type field.""" cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/account/{user.Username}/edit" @@ -700,14 +717,18 @@ def test_get_account_edit_unauthorized(client: TestClient, user: User): sid = user.login(request, "testPassword") with db.begin(): - user2 = create(User, Username="test2", Email="test2@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + user2 = create( + User, + Username="test2", + Email="test2@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) endpoint = f"/account/{user2.Username}/edit" with client as request: # Try to edit `test2` while authenticated as `test`. - response = request.get(endpoint, cookies={"AURSID": sid}, - allow_redirects=False) + response = request.get(endpoint, cookies={"AURSID": sid}, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) expected = f"/account/{user2.Username}" @@ -718,16 +739,15 @@ def test_post_account_edit(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") - post_data = { - "U": "test", - "E": "test666@example.org", - "passwd": "testPassword" - } + post_data = {"U": "test", "E": "test666@example.org", "passwd": "testPassword"} with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) @@ -772,8 +792,7 @@ def test_post_account_edit_type_as_dev(client: TestClient, tu_user: User): assert user2.AccountTypeID == at.DEVELOPER_ID -def test_post_account_edit_invalid_type_as_tu(client: TestClient, - tu_user: User): +def test_post_account_edit_invalid_type_as_tu(client: TestClient, tu_user: User): with db.begin(): user2 = create_user("test_tu") tu_user.AccountTypeID = at.TRUSTED_USER_ID @@ -792,8 +811,10 @@ def test_post_account_edit_invalid_type_as_tu(client: TestClient, assert user2.AccountTypeID == at.USER_ID errors = get_errors(resp.text) - expected = ("You do not have permission to change this user's " - f"account type to {at.DEVELOPER}.") + expected = ( + "You do not have permission to change this user's " + f"account type to {at.DEVELOPER}." + ) assert errors[0].text.strip() == expected @@ -807,16 +828,13 @@ def test_post_account_edit_dev(client: TestClient, tu_user: User): request = Request() sid = tu_user.login(request, "testPassword") - post_data = { - "U": "test", - "E": "test666@example.org", - "passwd": "testPassword" - } + post_data = {"U": "test", "E": "test666@example.org", "passwd": "testPassword"} endpoint = f"/account/{tu_user.Username}/edit" with client as request: - response = request.post(endpoint, cookies={"AURSID": sid}, - data=post_data, allow_redirects=False) + response = request.post( + endpoint, cookies={"AURSID": sid}, data=post_data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) expected = "The account, test, " @@ -832,13 +850,16 @@ def test_post_account_edit_language(client: TestClient, user: User): "U": "test", "E": "test@example.org", "L": "de", # German - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) @@ -859,33 +880,33 @@ def test_post_account_edit_timezone(client: TestClient, user: User): "U": "test", "E": "test@example.org", "TZ": "CET", - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) -def test_post_account_edit_error_missing_password(client: TestClient, - user: User): +def test_post_account_edit_error_missing_password(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") - post_data = { - "U": "test", - "E": "test@example.org", - "TZ": "CET", - "passwd": "" - } + post_data = {"U": "test", "E": "test@example.org", "TZ": "CET", "passwd": ""} with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -893,22 +914,19 @@ def test_post_account_edit_error_missing_password(client: TestClient, assert "Invalid password." in content -def test_post_account_edit_error_invalid_password(client: TestClient, - user: User): +def test_post_account_edit_error_invalid_password(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") - post_data = { - "U": "test", - "E": "test@example.org", - "TZ": "CET", - "passwd": "invalid" - } + post_data = {"U": "test", "E": "test@example.org", "TZ": "CET", "passwd": "invalid"} with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -916,18 +934,18 @@ def test_post_account_edit_error_invalid_password(client: TestClient, assert "Invalid password." in content -def test_post_account_edit_suspend_unauthorized(client: TestClient, - user: User): +def test_post_account_edit_suspend_unauthorized(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} post_data = { "U": "test", "E": "test@example.org", "S": True, - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - resp = request.post(f"/account/{user.Username}/edit", data=post_data, - cookies=cookies) + resp = request.post( + f"/account/{user.Username}/edit", data=post_data, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -945,11 +963,12 @@ def test_post_account_edit_inactivity(client: TestClient, user: User): "U": "test", "E": "test@example.org", "J": True, - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - resp = request.post(f"/account/{user.Username}/edit", data=post_data, - cookies=cookies) + resp = request.post( + f"/account/{user.Username}/edit", data=post_data, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.OK) # Make sure the user record got updated correctly. @@ -957,8 +976,9 @@ def test_post_account_edit_inactivity(client: TestClient, user: User): post_data.update({"J": False}) with client as request: - resp = request.post(f"/account/{user.Username}/edit", data=post_data, - cookies=cookies) + resp = request.post( + f"/account/{user.Username}/edit", data=post_data, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.OK) assert user.InactivityTS == 0 @@ -974,7 +994,7 @@ def test_post_account_edit_suspended(client: TestClient, user: User): "U": "test", "E": "test@example.org", "S": True, - "passwd": "testPassword" + "passwd": "testPassword", } endpoint = f"/account/{user.Username}/edit" with client as request: @@ -997,21 +1017,27 @@ def test_post_account_edit_error_unauthorized(client: TestClient, user: User): sid = user.login(request, "testPassword") with db.begin(): - user2 = create(User, Username="test2", Email="test2@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + user2 = create( + User, + Username="test2", + Email="test2@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) post_data = { "U": "test", "E": "test@example.org", "TZ": "CET", - "passwd": "testPassword" + "passwd": "testPassword", } endpoint = f"/account/{user2.Username}/edit" with client as request: # Attempt to edit 'test2' while logged in as 'test'. - response = request.post(endpoint, cookies={"AURSID": sid}, - data=post_data, allow_redirects=False) + response = request.post( + endpoint, cookies={"AURSID": sid}, data=post_data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.SEE_OTHER) expected = f"/account/{user2.Username}" @@ -1026,13 +1052,16 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): "U": "test", "E": "test@example.org", "PK": make_ssh_pubkey(), - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) @@ -1040,9 +1069,12 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): post_data["PK"] = make_ssh_pubkey() with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) @@ -1055,13 +1087,16 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): "U": user.Username, "E": user.Email, "PK": make_ssh_pubkey(), - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) @@ -1069,13 +1104,16 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): "U": user.Username, "E": user.Email, "PK": str(), # Pass an empty string now to walk the delete path. - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) @@ -1087,12 +1125,13 @@ def test_post_account_edit_invalid_ssh_pubkey(client: TestClient, user: User): "U": "test", "E": "test@example.org", "PK": pubkey, - "passwd": "testPassword" + "passwd": "testPassword", } cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.post("/account/test/edit", data=data, - cookies=cookies, allow_redirects=False) + response = request.post( + "/account/test/edit", data=data, cookies=cookies, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1106,13 +1145,16 @@ def test_post_account_edit_password(client: TestClient, user: User): "E": "test@example.org", "P": "newPassword", "C": "newPassword", - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: - response = request.post("/account/test/edit", cookies={ - "AURSID": sid - }, data=post_data, allow_redirects=False) + response = request.post( + "/account/test/edit", + cookies={"AURSID": sid}, + data=post_data, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) @@ -1132,7 +1174,7 @@ def test_post_account_edit_self_type_as_user(client: TestClient, user: User): "U": user.Username, "E": user.Email, "T": TRUSTED_USER_ID, - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: resp = request.post(endpoint, data=data, cookies=cookies) @@ -1151,8 +1193,7 @@ def test_post_account_edit_other_user_as_user(client: TestClient, user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: - resp = request.get(endpoint, cookies=cookies, - allow_redirects=False) + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/account/{user2.Username}" @@ -1172,7 +1213,7 @@ def test_post_account_edit_self_type_as_tu(client: TestClient, tu_user: User): "U": tu_user.Username, "E": tu_user.Email, "T": USER_ID, - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: resp = request.post(endpoint, data=data, cookies=cookies) @@ -1182,7 +1223,8 @@ def test_post_account_edit_self_type_as_tu(client: TestClient, tu_user: User): def test_post_account_edit_other_user_type_as_tu( - client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture): + client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture +): caplog.set_level(DEBUG) with db.begin(): @@ -1202,7 +1244,7 @@ def test_post_account_edit_other_user_type_as_tu( "U": user2.Username, "E": user2.Email, "T": TRUSTED_USER_ID, - "passwd": "testPassword" + "passwd": "testPassword", } with client as request: resp = request.post(endpoint, data=data, cookies=cookies) @@ -1212,14 +1254,17 @@ def test_post_account_edit_other_user_type_as_tu( assert user2.AccountTypeID == TRUSTED_USER_ID # and also that this got logged out at DEBUG level. - expected = (f"Trusted User '{tu_user.Username}' has " - f"modified '{user2.Username}' account's type to" - f" {TRUSTED_USER}.") + expected = ( + f"Trusted User '{tu_user.Username}' has " + f"modified '{user2.Username}' account's type to" + f" {TRUSTED_USER}." + ) assert expected in caplog.text def test_post_account_edit_other_user_type_as_tu_invalid_type( - client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture): + client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture +): with db.begin(): user2 = create_user("test2") @@ -1227,12 +1272,7 @@ def test_post_account_edit_other_user_type_as_tu_invalid_type( endpoint = f"/account/{user2.Username}/edit" # As a TU, we can modify other user's account types. - data = { - "U": user2.Username, - "E": user2.Email, - "T": 0, - "passwd": "testPassword" - } + data = {"U": user2.Username, "E": user2.Email, "T": 0, "passwd": "testPassword"} with client as request: resp = request.post(endpoint, data=data, cookies=cookies) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1247,8 +1287,9 @@ def test_get_account(client: TestClient, user: User): sid = user.login(request, "testPassword") with client as request: - response = request.get("/account/test", cookies={"AURSID": sid}, - allow_redirects=False) + response = request.get( + "/account/test", cookies={"AURSID": sid}, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) @@ -1258,8 +1299,9 @@ def test_get_account_not_found(client: TestClient, user: User): sid = user.login(request, "testPassword") with client as request: - response = request.get("/account/not_found", cookies={"AURSID": sid}, - allow_redirects=False) + response = request.get( + "/account/not_found", cookies={"AURSID": sid}, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -1274,8 +1316,8 @@ def test_get_account_unauthenticated(client: TestClient, user: User): def test_get_accounts(client: TestClient, user: User, tu_user: User): - """ Test that we can GET request /accounts and receive - a form which can be used to POST /accounts. """ + """Test that we can GET request /accounts and receive + a form which can be used to POST /accounts.""" sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} @@ -1296,8 +1338,8 @@ def test_get_accounts(client: TestClient, user: User, tu_user: User): assert form.attrib.get("action") == "/accounts" def field(element): - """ Return the given element string as a valid - selector in the form. """ + """Return the given element string as a valid + selector in the form.""" return f"./fieldset/p/{element}" username = form.xpath(field('input[@id="id_username"]')) @@ -1360,8 +1402,7 @@ def test_post_accounts(client: TestClient, user: User, tu_user: User): columns = rows[i].xpath("./td") assert len(columns) == 7 - username, atype, suspended, real_name, \ - irc_nick, pgp_key, edit = columns + username, atype, suspended, real_name, irc_nick, pgp_key, edit = columns username = next(iter(username.xpath("./a"))) assert username.text.strip() == _user.Username @@ -1379,8 +1420,10 @@ def test_post_accounts(client: TestClient, user: User, tu_user: User): else: assert not edit - logger.debug('Checked user row {"id": %s, "username": "%s"}.' - % (_user.ID, _user.Username)) + logger.debug( + 'Checked user row {"id": %s, "username": "%s"}.' + % (_user.ID, _user.Username) + ) def test_post_accounts_username(client: TestClient, user: User, tu_user: User): @@ -1389,8 +1432,7 @@ def test_post_accounts_username(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies, - data={"U": user.Username}) + response = request.post("/accounts", cookies=cookies, data={"U": user.Username}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1403,34 +1445,33 @@ def test_post_accounts_username(client: TestClient, user: User, tu_user: User): assert username.text.strip() == user.Username -def test_post_accounts_account_type(client: TestClient, user: User, - tu_user: User): +def test_post_accounts_account_type(client: TestClient, user: User, tu_user: User): # Check the different account type options. sid = user.login(Request(), "testPassword") cookies = {"AURSID": sid} # Make a user with the "User" role here so we can # test the `u` parameter. - account_type = query(AccountType, - AccountType.AccountType == "User").first() + account_type = query(AccountType, AccountType.AccountType == "User").first() with db.begin(): - create(User, Username="test_2", - Email="test_2@example.org", - RealName="Test User 2", - Passwd="testPassword", - AccountType=account_type) + create( + User, + Username="test_2", + Email="test_2@example.org", + RealName="Test User 2", + Passwd="testPassword", + AccountType=account_type, + ) # Expect no entries; we marked our only user as a User type. with client as request: - response = request.post("/accounts", cookies=cookies, - data={"T": "t"}) + response = request.post("/accounts", cookies=cookies, data={"T": "t"}) assert response.status_code == int(HTTPStatus.OK) assert len(get_rows(response.text)) == 0 # So, let's also ensure that specifying "u" returns our user. with client as request: - response = request.post("/accounts", cookies=cookies, - data={"T": "u"}) + response = request.post("/accounts", cookies=cookies, data={"T": "u"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1443,13 +1484,12 @@ def test_post_accounts_account_type(client: TestClient, user: User, # Set our only user to a Trusted User. with db.begin(): - user.AccountType = query(AccountType).filter( - AccountType.ID == TRUSTED_USER_ID - ).first() + user.AccountType = ( + query(AccountType).filter(AccountType.ID == TRUSTED_USER_ID).first() + ) with client as request: - response = request.post("/accounts", cookies=cookies, - data={"T": "t"}) + response = request.post("/accounts", cookies=cookies, data={"T": "t"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1461,13 +1501,12 @@ def test_post_accounts_account_type(client: TestClient, user: User, assert type.text.strip() == "Trusted User" with db.begin(): - user.AccountType = query(AccountType).filter( - AccountType.ID == DEVELOPER_ID - ).first() + user.AccountType = ( + query(AccountType).filter(AccountType.ID == DEVELOPER_ID).first() + ) with client as request: - response = request.post("/accounts", cookies=cookies, - data={"T": "d"}) + response = request.post("/accounts", cookies=cookies, data={"T": "d"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1479,13 +1518,12 @@ def test_post_accounts_account_type(client: TestClient, user: User, assert type.text.strip() == "Developer" with db.begin(): - user.AccountType = query(AccountType).filter( - AccountType.ID == TRUSTED_USER_AND_DEV_ID - ).first() + user.AccountType = ( + query(AccountType).filter(AccountType.ID == TRUSTED_USER_AND_DEV_ID).first() + ) with client as request: - response = request.post("/accounts", cookies=cookies, - data={"T": "td"}) + response = request.post("/accounts", cookies=cookies, data={"T": "td"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1517,8 +1555,7 @@ def test_post_accounts_status(client: TestClient, user: User, tu_user: User): user.Suspended = True with client as request: - response = request.post("/accounts", cookies=cookies, - data={"S": True}) + response = request.post("/accounts", cookies=cookies, data={"S": True}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1535,8 +1572,7 @@ def test_post_accounts_email(client: TestClient, user: User, tu_user: User): # Search via email. with client as request: - response = request.post("/accounts", cookies=cookies, - data={"E": user.Email}) + response = request.post("/accounts", cookies=cookies, data={"E": user.Email}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1549,8 +1585,7 @@ def test_post_accounts_realname(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies, - data={"R": user.RealName}) + response = request.post("/accounts", cookies=cookies, data={"R": user.RealName}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1563,8 +1598,7 @@ def test_post_accounts_irc(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies, - data={"I": user.IRCNick}) + response = request.post("/accounts", cookies=cookies, data={"I": user.IRCNick}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1589,22 +1623,19 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): first_rows = rows with client as request: - response = request.post("/accounts", cookies=cookies, - data={"SB": "u"}) + response = request.post("/accounts", cookies=cookies, data={"SB": "u"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 def compare_text_values(column, lhs, rhs): - return [row[column].text for row in lhs] \ - == [row[column].text for row in rhs] + return [row[column].text for row in lhs] == [row[column].text for row in rhs] # Test the username rows are ordered the same. assert compare_text_values(0, first_rows, rows) is True with client as request: - response = request.post("/accounts", cookies=cookies, - data={"SB": "i"}) + response = request.post("/accounts", cookies=cookies, data={"SB": "i"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1614,8 +1645,7 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): # Sort by "i" -> RealName. with client as request: - response = request.post("/accounts", cookies=cookies, - data={"SB": "r"}) + response = request.post("/accounts", cookies=cookies, data={"SB": "r"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1624,9 +1654,9 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): assert compare_text_values(4, first_rows, reversed(rows)) is True with db.begin(): - user.AccountType = query(AccountType).filter( - AccountType.ID == TRUSTED_USER_AND_DEV_ID - ).first() + user.AccountType = ( + query(AccountType).filter(AccountType.ID == TRUSTED_USER_AND_DEV_ID).first() + ) # Fetch first_rows again with our new AccountType ordering. with client as request: @@ -1638,8 +1668,7 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): # Sort by "t" -> AccountType. with client as request: - response = request.post("/accounts", cookies=cookies, - data={"SB": "t"}) + response = request.post("/accounts", cookies=cookies, data={"SB": "t"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1657,8 +1686,7 @@ def test_post_accounts_pgp_key(client: TestClient, user: User, tu_user: User): # Search via PGPKey. with client as request: - response = request.post("/accounts", cookies=cookies, - data={"K": user.PGPKey}) + response = request.post("/accounts", cookies=cookies, data={"K": user.PGPKey}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1668,15 +1696,17 @@ def test_post_accounts_pgp_key(client: TestClient, user: User, tu_user: User): def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): # Create 150 users. users = [user] - account_type = query(AccountType, - AccountType.AccountType == "User").first() + account_type = query(AccountType, AccountType.AccountType == "User").first() with db.begin(): for i in range(150): - _user = create(User, Username=f"test_#{i}", - Email=f"test_#{i}@example.org", - RealName=f"Test User #{i}", - Passwd="testPassword", - AccountType=account_type) + _user = create( + User, + Username=f"test_#{i}", + Email=f"test_#{i}@example.org", + RealName=f"Test User #{i}", + Passwd="testPassword", + AccountType=account_type, + ) users.append(_user) sid = user.login(Request(), "testPassword") @@ -1709,8 +1739,9 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): assert "disabled" not in page_next.attrib with client as request: - response = request.post("/accounts", cookies=cookies, - data={"O": 50}) # +50 offset. + response = request.post( + "/accounts", cookies=cookies, data={"O": 50} + ) # +50 offset. assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1724,8 +1755,9 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): assert username.text.strip() == _user.Username with client as request: - response = request.post("/accounts", cookies=cookies, - data={"O": 101}) # Last page. + response = request.post( + "/accounts", cookies=cookies, data={"O": 101} + ) # Last page. assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1741,8 +1773,9 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): def test_get_terms_of_service(client: TestClient, user: User): with db.begin(): - term = create(Term, Description="Test term.", - URL="http://localhost", Revision=1) + term = create( + Term, Description="Test term.", URL="http://localhost", Revision=1 + ) with client as request: response = request.get("/tos", allow_redirects=False) @@ -1764,8 +1797,9 @@ def test_get_terms_of_service(client: TestClient, user: User): assert response.status_code == int(HTTPStatus.OK) with db.begin(): - accepted_term = create(AcceptedTerm, User=user, - Term=term, Revision=term.Revision) + accepted_term = create( + AcceptedTerm, User=user, Term=term, Revision=term.Revision + ) with client as request: response = request.get("/tos", cookies=cookies, allow_redirects=False) @@ -1800,8 +1834,9 @@ def test_post_terms_of_service(client: TestClient, user: User): # Create a fresh Term. with db.begin(): - term = create(Term, Description="Test term.", - URL="http://localhost", Revision=1) + term = create( + Term, Description="Test term.", URL="http://localhost", Revision=1 + ) # Test that the term we just created is listed. with client as request: @@ -1810,8 +1845,7 @@ def test_post_terms_of_service(client: TestClient, user: User): # Make a POST request to /tos with the agree checkbox disabled (False). with client as request: - response = request.post("/tos", data={"accept": False}, - cookies=cookies) + response = request.post("/tos", data={"accept": False}, cookies=cookies) assert response.status_code == int(HTTPStatus.OK) # Make a POST request to /tos with the agree checkbox enabled (True). @@ -1820,8 +1854,7 @@ def test_post_terms_of_service(client: TestClient, user: User): assert response.status_code == int(HTTPStatus.SEE_OTHER) # Query the db for the record created by the post request. - accepted_term = query(AcceptedTerm, - AcceptedTerm.TermsID == term.ID).first() + accepted_term = query(AcceptedTerm, AcceptedTerm.TermsID == term.ID).first() assert accepted_term.User == user assert accepted_term.Term == term diff --git a/test/test_adduser.py b/test/test_adduser.py index 65968d40..2cb71f3b 100644 --- a/test/test_adduser.py +++ b/test/test_adduser.py @@ -3,16 +3,17 @@ from unittest import mock import pytest import aurweb.models.account_type as at - from aurweb import db from aurweb.models import User from aurweb.scripts import adduser from aurweb.testing.requests import Request -TEST_SSH_PUBKEY = ("ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAI" - "bmlzdHAyNTYAAABBBEURnkiY6JoLyqDE8Li1XuAW+LHmkmLDMW/GL5wY" - "7k4/A+Ta7bjA3MOKrF9j4EuUTvCuNXULxvpfSqheTFWZc+g= " - "kevr@volcano") +TEST_SSH_PUBKEY = ( + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAI" + "bmlzdHAyNTYAAABBBEURnkiY6JoLyqDE8Li1XuAW+LHmkmLDMW/GL5wY" + "7k4/A+Ta7bjA3MOKrF9j4EuUTvCuNXULxvpfSqheTFWZc+g= " + "kevr@volcano" +) @pytest.fixture(autouse=True) @@ -38,18 +39,36 @@ def test_adduser(): def test_adduser_tu(): - run_main([ - "-u", "test", "-e", "test@example.org", "-p", "abcd1234", - "-t", at.TRUSTED_USER - ]) + run_main( + [ + "-u", + "test", + "-e", + "test@example.org", + "-p", + "abcd1234", + "-t", + at.TRUSTED_USER, + ] + ) test = db.query(User).filter(User.Username == "test").first() assert test is not None assert test.AccountTypeID == at.TRUSTED_USER_ID def test_adduser_ssh_pk(): - run_main(["-u", "test", "-e", "test@example.org", "-p", "abcd1234", - "--ssh-pubkey", TEST_SSH_PUBKEY]) + run_main( + [ + "-u", + "test", + "-e", + "test@example.org", + "-p", + "abcd1234", + "--ssh-pubkey", + TEST_SSH_PUBKEY, + ] + ) test = db.query(User).filter(User.Username == "test").first() assert test is not None assert TEST_SSH_PUBKEY.startswith(test.ssh_pub_keys.first().PubKey) diff --git a/test/test_api_rate_limit.py b/test/test_api_rate_limit.py index 82805ecf..c67aa57d 100644 --- a/test/test_api_rate_limit.py +++ b/test/test_api_rate_limit.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -13,8 +12,7 @@ def setup(db_test): def test_api_rate_key_creation(): with db.begin(): - rate = db.create(ApiRateLimit, IP="127.0.0.1", Requests=10, - WindowStart=1) + rate = db.create(ApiRateLimit, IP="127.0.0.1", Requests=10, WindowStart=1) assert rate.IP == "127.0.0.1" assert rate.Requests == 10 assert rate.WindowStart == 1 diff --git a/test/test_asgi.py b/test/test_asgi.py index c693a3a9..6ff80fa3 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -1,20 +1,17 @@ import http import os import re - from typing import Callable from unittest import mock import fastapi import pytest - from fastapi import HTTPException from fastapi.testclient import TestClient import aurweb.asgi import aurweb.config import aurweb.redis - from aurweb.exceptions import handle_form_exceptions from aurweb.testing.requests import Request @@ -33,7 +30,9 @@ def mock_glab_request(monkeypatch): if side_effect: return side_effect # pragma: no cover return return_value + monkeypatch.setattr("requests.post", what_to_return) + return wrapped @@ -47,13 +46,14 @@ def mock_glab_config(project: str = "test/project", token: str = "test-token"): elif key == "error-token": return token return config_get(section, key) + return wrapper @pytest.mark.asyncio async def test_asgi_startup_session_secret_exception(monkeypatch): - """ Test that we get an IOError on app_startup when we cannot - connect to options.redis_address. """ + """Test that we get an IOError on app_startup when we cannot + connect to options.redis_address.""" redis_addr = aurweb.config.get("options", "redis_address") @@ -110,8 +110,9 @@ async def test_asgi_app_disabled_metrics(caplog: pytest.LogCaptureFixture): with mock.patch.dict(os.environ, env): await aurweb.asgi.app_startup() - expected = ("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " - "endpoint is disabled.") + expected = ( + "$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " "endpoint is disabled." + ) assert expected in caplog.text @@ -134,9 +135,12 @@ class FakeResponse: self.text = text -def test_internal_server_error_bad_glab(setup: None, use_traceback: None, - mock_glab_request: Callable, - caplog: pytest.LogCaptureFixture): +def test_internal_server_error_bad_glab( + setup: None, + use_traceback: None, + mock_glab_request: Callable, + caplog: pytest.LogCaptureFixture, +): @aurweb.asgi.app.get("/internal_server_error") async def internal_server_error(request: fastapi.Request): raise ValueError("test exception") @@ -154,9 +158,12 @@ def test_internal_server_error_bad_glab(setup: None, use_traceback: None, assert re.search(expr, caplog.text) -def test_internal_server_error_no_token(setup: None, use_traceback: None, - mock_glab_request: Callable, - caplog: pytest.LogCaptureFixture): +def test_internal_server_error_no_token( + setup: None, + use_traceback: None, + mock_glab_request: Callable, + caplog: pytest.LogCaptureFixture, +): @aurweb.asgi.app.get("/internal_server_error") async def internal_server_error(request: fastapi.Request): raise ValueError("test exception") @@ -175,9 +182,12 @@ def test_internal_server_error_no_token(setup: None, use_traceback: None, assert re.search(expr, caplog.text) -def test_internal_server_error(setup: None, use_traceback: None, - mock_glab_request: Callable, - caplog: pytest.LogCaptureFixture): +def test_internal_server_error( + setup: None, + use_traceback: None, + mock_glab_request: Callable, + caplog: pytest.LogCaptureFixture, +): @aurweb.asgi.app.get("/internal_server_error") async def internal_server_error(request: fastapi.Request): raise ValueError("test exception") @@ -203,9 +213,12 @@ def test_internal_server_error(setup: None, use_traceback: None, assert "FATAL" not in caplog.text -def test_internal_server_error_post(setup: None, use_traceback: None, - mock_glab_request: Callable, - caplog: pytest.LogCaptureFixture): +def test_internal_server_error_post( + setup: None, + use_traceback: None, + mock_glab_request: Callable, + caplog: pytest.LogCaptureFixture, +): @aurweb.asgi.app.post("/internal_server_error") @handle_form_exceptions async def internal_server_error(request: fastapi.Request): diff --git a/test/test_aurblup.py b/test/test_aurblup.py index 0b499d57..93a832f9 100644 --- a/test/test_aurblup.py +++ b/test/test_aurblup.py @@ -1,5 +1,4 @@ import tempfile - from unittest import mock import py @@ -32,7 +31,7 @@ def setup(db_test, alpm_db: AlpmDatabase, tempdir: py.path.local) -> None: if key == "db-path": return alpm_db.local elif key == "server": - return f'file://{alpm_db.remote}' + return f"file://{alpm_db.remote}" elif key == "sync-dbs": return alpm_db.repo return value @@ -51,8 +50,7 @@ def test_aurblup(alpm_db: AlpmDatabase): # Test that the package got added to the database. for name in ("pkg", "pkg2"): - pkg = db.query(OfficialProvider).filter( - OfficialProvider.Name == name).first() + pkg = db.query(OfficialProvider).filter(OfficialProvider.Name == name).first() assert pkg is not None # Test that we can remove the package. @@ -62,11 +60,9 @@ def test_aurblup(alpm_db: AlpmDatabase): aurblup.main(True) # Expect that the database got updated accordingly. - pkg = db.query(OfficialProvider).filter( - OfficialProvider.Name == "pkg").first() + pkg = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg").first() assert pkg is None - pkg2 = db.query(OfficialProvider).filter( - OfficialProvider.Name == "pkg2").first() + pkg2 = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg2").first() assert pkg2 is not None @@ -78,14 +74,16 @@ def test_aurblup_cleanup(alpm_db: AlpmDatabase): # Now, let's insert an OfficialPackage that doesn't exist, # then exercise the old provider deletion path. with db.begin(): - db.create(OfficialProvider, Name="fake package", - Repo="test", Provides="package") + db.create( + OfficialProvider, Name="fake package", Repo="test", Provides="package" + ) # Run aurblup again. aurblup.main() # Expect that the fake package got deleted because it's # not in alpm_db anymore. - providers = db.query(OfficialProvider).filter( - OfficialProvider.Name == "fake package").all() + providers = ( + db.query(OfficialProvider).filter(OfficialProvider.Name == "fake package").all() + ) assert len(providers) == 0 diff --git a/test/test_auth.py b/test/test_auth.py index b8221c19..4a4318e8 100644 --- a/test/test_auth.py +++ b/test/test_auth.py @@ -1,11 +1,15 @@ import fastapi import pytest - from fastapi import HTTPException from sqlalchemy.exc import IntegrityError from aurweb import config, db, time -from aurweb.auth import AnonymousUser, BasicAuthBackend, _auth_required, account_type_required +from aurweb.auth import ( + AnonymousUser, + BasicAuthBackend, + _auth_required, + account_type_required, +) from aurweb.models.account_type import USER, USER_ID from aurweb.models.session import Session from aurweb.models.user import User @@ -20,9 +24,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.com", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.com", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -55,8 +64,7 @@ async def test_auth_backend_invalid_user_id(): # Create a new session with a fake user id. now_ts = time.utcnow() with pytest.raises(IntegrityError): - Session(UsersID=666, SessionID="realSession", - LastUpdateTS=now_ts + 5) + Session(UsersID=666, SessionID="realSession", LastUpdateTS=now_ts + 5) @pytest.mark.asyncio @@ -65,8 +73,9 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend): # equal the real_user. now_ts = time.utcnow() with db.begin(): - db.create(Session, UsersID=user.ID, SessionID="realSession", - LastUpdateTS=now_ts + 5) + db.create( + Session, UsersID=user.ID, SessionID="realSession", LastUpdateTS=now_ts + 5 + ) request = Request() request.cookies["AURSID"] = "realSession" @@ -76,7 +85,7 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend): @pytest.mark.asyncio async def test_expired_session(backend: BasicAuthBackend, user: User): - """ Login, expire the session manually, then authenticate. """ + """Login, expire the session manually, then authenticate.""" # First, build a Request with a logged in user. request = Request() request.user = user @@ -115,8 +124,8 @@ async def test_auth_required_redirection_bad_referrer(): def test_account_type_required(): - """ This test merely asserts that a few different paths - do not raise exceptions. """ + """This test merely asserts that a few different paths + do not raise exceptions.""" # This one shouldn't raise. account_type_required({USER}) @@ -125,7 +134,7 @@ def test_account_type_required(): # But this one should! We have no "FAKE" key. with pytest.raises(KeyError): - account_type_required({'FAKE'}) + account_type_required({"FAKE"}) def test_is_trusted_user(): diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 5942edcf..87ad86f6 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -1,14 +1,11 @@ import re - from http import HTTPStatus from unittest import mock import pytest - from fastapi.testclient import TestClient import aurweb.config - from aurweb import db, time from aurweb.asgi import app from aurweb.models.account_type import USER_ID @@ -42,39 +39,41 @@ def client() -> TestClient: @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username=TEST_USERNAME, Email=TEST_EMAIL, - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username=TEST_USERNAME, + Email=TEST_EMAIL, + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user def test_login_logout(client: TestClient, user: User): - post_data = { - "user": "test", - "passwd": "testPassword", - "next": "/" - } + post_data = {"user": "test", "passwd": "testPassword", "next": "/"} with client as request: # First, let's test get /login. response = request.get("/login") assert response.status_code == int(HTTPStatus.OK) - response = request.post("/login", data=post_data, - allow_redirects=False) + response = request.post("/login", data=post_data, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) # Simulate following the redirect location from above's response. response = request.get(response.headers.get("location")) assert response.status_code == int(HTTPStatus.OK) - response = request.post("/logout", data=post_data, - allow_redirects=False) + response = request.post("/logout", data=post_data, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) - response = request.post("/logout", data=post_data, cookies={ - "AURSID": response.cookies.get("AURSID") - }, allow_redirects=False) + response = request.post( + "/logout", + data=post_data, + cookies={"AURSID": response.cookies.get("AURSID")}, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert "AURSID" not in response.cookies @@ -84,11 +83,7 @@ def test_login_suspended(client: TestClient, user: User): with db.begin(): user.Suspended = 1 - data = { - "user": user.Username, - "passwd": "testPassword", - "next": "/" - } + data = {"user": user.Username, "passwd": "testPassword", "next": "/"} with client as request: resp = request.post("/login", data=data) errors = get_errors(resp.text) @@ -96,23 +91,17 @@ def test_login_suspended(client: TestClient, user: User): def test_login_email(client: TestClient, user: user): - post_data = { - "user": user.Email, - "passwd": "testPassword", - "next": "/" - } + post_data = {"user": user.Email, "passwd": "testPassword", "next": "/"} with client as request: - resp = request.post("/login", data=post_data, - allow_redirects=False) + resp = request.post("/login", data=post_data, allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert "AURSID" in resp.cookies def mock_getboolean(**overrided_configs): mocked_config = { - tuple(config.split("__")): value - for config, value in overrided_configs.items() + tuple(config.split("__")): value for config, value in overrided_configs.items() } def side_effect(*args): @@ -123,19 +112,14 @@ def mock_getboolean(**overrided_configs): @mock.patch( "aurweb.config.getboolean", - side_effect=mock_getboolean(options__disable_http_login=False) + side_effect=mock_getboolean(options__disable_http_login=False), ) def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User): - post_data = { - "user": user.Username, - "passwd": "testPassword", - "next": "/" - } + post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"} # Perform a login request with the data matching our user. with client as request: - response = request.post("/login", data=post_data, - allow_redirects=False) + response = request.post("/login", data=post_data, allow_redirects=False) # Make sure we got the expected status out of it. assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -152,17 +136,17 @@ def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User): @mock.patch( "aurweb.config.getboolean", - side_effect=mock_getboolean(options__disable_http_login=True) + side_effect=mock_getboolean(options__disable_http_login=True), ) def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User): - """ In this test, we check to verify the course of action taken + """In this test, we check to verify the course of action taken by starlette when providing secure=True to a response cookie. This is achieved by mocking aurweb.config.getboolean to return True (or 1) when looking for `options.disable_http_login`. When we receive a response with `disable_http_login` enabled, we check the fields in cookies received for the secure and httponly fields, in addition to the rest of the fields given - on such a request. """ + on such a request.""" # Create a local TestClient here since we mocked configuration. # client = TestClient(app) @@ -172,16 +156,11 @@ def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User): # client.headers.update(TEST_REFERER) # Data used for our upcoming http post request. - post_data = { - "user": user.Username, - "passwd": "testPassword", - "next": "/" - } + post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"} # Perform a login request with the data matching our user. with client as request: - response = request.post("/login", data=post_data, - allow_redirects=False) + response = request.post("/login", data=post_data, allow_redirects=False) # Make sure we got the expected status out of it. assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -203,16 +182,11 @@ def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User): def test_authenticated_login(client: TestClient, user: User): - post_data = { - "user": user.Username, - "passwd": "testPassword", - "next": "/" - } + post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"} with client as request: # Try to login. - response = request.post("/login", data=post_data, - allow_redirects=False) + response = request.post("/login", data=post_data, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -220,8 +194,9 @@ def test_authenticated_login(client: TestClient, user: User): # when requesting GET /login as an authenticated user. # Now, let's verify that we receive 403 Forbidden when we # try to get /login as an authenticated user. - response = request.get("/login", cookies=response.cookies, - allow_redirects=False) + response = request.get( + "/login", cookies=response.cookies, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) assert "Logged-in as: test" in response.text @@ -236,10 +211,7 @@ def test_unauthenticated_logout_unauthorized(client: TestClient): def test_login_missing_username(client: TestClient): - post_data = { - "passwd": "testPassword", - "next": "/" - } + post_data = {"passwd": "testPassword", "next": "/"} with client as request: response = request.post("/login", data=post_data) @@ -256,17 +228,15 @@ def test_login_remember_me(client: TestClient, user: User): "user": "test", "passwd": "testPassword", "next": "/", - "remember_me": True + "remember_me": True, } with client as request: - response = request.post("/login", data=post_data, - allow_redirects=False) + response = request.post("/login", data=post_data, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert "AURSID" in response.cookies - cookie_timeout = aurweb.config.getint( - "options", "persistent_cookie_timeout") + cookie_timeout = aurweb.config.getint("options", "persistent_cookie_timeout") now_ts = time.utcnow() session = db.query(Session).filter(Session.UsersID == user.ID).first() @@ -280,7 +250,7 @@ def test_login_incorrect_password_remember_me(client: TestClient, user: User): "user": "test", "passwd": "badPassword", "next": "/", - "remember_me": "on" + "remember_me": "on", } with client as request: @@ -295,10 +265,7 @@ def test_login_incorrect_password_remember_me(client: TestClient, user: User): def test_login_missing_password(client: TestClient): - post_data = { - "user": "test", - "next": "/" - } + post_data = {"user": "test", "next": "/"} with client as request: response = request.post("/login", data=post_data) @@ -310,11 +277,7 @@ def test_login_missing_password(client: TestClient): def test_login_incorrect_password(client: TestClient): - post_data = { - "user": "test", - "passwd": "badPassword", - "next": "/" - } + post_data = {"user": "test", "passwd": "badPassword", "next": "/"} with client as request: response = request.post("/login", data=post_data) @@ -350,8 +313,9 @@ def test_login_bad_referer(client: TestClient): assert "AURSID" not in response.cookies -def test_generate_unique_sid_exhausted(client: TestClient, user: User, - caplog: pytest.LogCaptureFixture): +def test_generate_unique_sid_exhausted( + client: TestClient, user: User, caplog: pytest.LogCaptureFixture +): """ In this test, we mock up generate_unique_sid() to infinitely return the same SessionID given to `user`. Within that mocking, we try @@ -364,13 +328,17 @@ def test_generate_unique_sid_exhausted(client: TestClient, user: User, now = time.utcnow() with db.begin(): # Create a second user; we'll login with this one. - user2 = db.create(User, Username="test2", Email="test2@example.org", - ResetKey="testReset", Passwd="testPassword", - AccountTypeID=USER_ID) + user2 = db.create( + User, + Username="test2", + Email="test2@example.org", + ResetKey="testReset", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) # Create a session with ID == "testSession" for `user`. - db.create(Session, User=user, SessionID="testSession", - LastUpdateTS=now) + db.create(Session, User=user, SessionID="testSession", LastUpdateTS=now) # Mock out generate_unique_sid; always return "testSession" which # causes us to eventually error out and raise an internal error. diff --git a/test/test_ban.py b/test/test_ban.py index ff49f7e2..9db62296 100644 --- a/test/test_ban.py +++ b/test/test_ban.py @@ -1,9 +1,7 @@ import warnings - from datetime import datetime, timedelta import pytest - from sqlalchemy import exc as sa_exc from aurweb import db diff --git a/test/test_cache.py b/test/test_cache.py index b49ee386..83a9755a 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -11,7 +11,7 @@ def setup(db_test): class StubRedis: - """ A class which acts as a RedisConnection without using Redis. """ + """A class which acts as a RedisConnection without using Redis.""" cache = dict() expires = dict() @@ -39,10 +39,13 @@ def redis(): @pytest.mark.asyncio async def test_db_count_cache(redis): - db.create(User, Username="user1", - Email="user1@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + db.create( + User, + Username="user1", + Email="user1@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) query = db.query(User) @@ -57,10 +60,13 @@ async def test_db_count_cache(redis): @pytest.mark.asyncio async def test_db_count_cache_expires(redis): - db.create(User, Username="user1", - Email="user1@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + db.create( + User, + Username="user1", + Email="user1@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) query = db.query(User) diff --git a/test/test_captcha.py b/test/test_captcha.py index e5f8c71a..fa6fcbcc 100644 --- a/test/test_captcha.py +++ b/test/test_captcha.py @@ -11,14 +11,14 @@ def setup(db_test): def test_captcha_salts(): - """ Make sure we can get some captcha salts. """ + """Make sure we can get some captcha salts.""" salts = captcha.get_captcha_salts() assert len(salts) == 6 def test_captcha_token(): - """ Make sure getting a captcha salt's token matches up against - the first three digits of the md5 hash of the salt. """ + """Make sure getting a captcha salt's token matches up against + the first three digits of the md5 hash of the salt.""" salts = captcha.get_captcha_salts() salt = salts[0] @@ -29,9 +29,9 @@ def test_captcha_token(): def test_captcha_challenge_answer(): - """ Make sure that executing the captcha challenge via shell + """Make sure that executing the captcha challenge via shell produces the correct result by comparing it against a straight - up token conversion. """ + up token conversion.""" salts = captcha.get_captcha_salts() salt = salts[0] @@ -44,7 +44,7 @@ def test_captcha_challenge_answer(): def test_captcha_salt_filter(): - """ Make sure captcha_salt_filter returns the first salt from + """Make sure captcha_salt_filter returns the first salt from get_captcha_salts(). Example usage: @@ -55,7 +55,7 @@ def test_captcha_salt_filter(): def test_captcha_cmdline_filter(): - """ Make sure that the captcha_cmdline filter gives us the + """Make sure that the captcha_cmdline filter gives us the same challenge that get_captcha_challenge does. Example usage: diff --git a/test/test_config.py b/test/test_config.py index f451d8b3..c7a3610e 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -2,7 +2,6 @@ import configparser import io import os import re - from unittest import mock import py @@ -35,6 +34,7 @@ def mock_config_get(): if option == "salt_rounds": return "666" return config_get(section, option) + return _mock_config_get @@ -59,7 +59,7 @@ def test_config_main_get_unknown_section(get: str): main() # With an invalid section, we should get a usage error. - expected = r'^error: no section found$' + expected = r"^error: no section found$" assert re.match(expected, stderr.getvalue().strip()) @@ -140,8 +140,7 @@ def test_config_main_set_immutable(): args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch.dict(os.environ, {"AUR_CONFIG_IMMUTABLE": "1"}): with mock.patch("sys.argv", args): - with mock.patch("aurweb.config.set_option", - side_effect=mock_set_option): + with mock.patch("aurweb.config.set_option", side_effect=mock_set_option): main() expected = None @@ -170,8 +169,7 @@ def test_config_main_set_unknown_section(save: None): args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch("sys.argv", args): with mock.patch("sys.stderr", stderr): - with mock.patch("aurweb.config.set_option", - side_effect=mock_set_option): + with mock.patch("aurweb.config.set_option", side_effect=mock_set_option): main() assert stderr.getvalue().strip() == "error: no section found" diff --git a/test/test_db.py b/test/test_db.py index f36fff2c..8ac5607d 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -2,26 +2,26 @@ import os import re import sqlite3 import tempfile - from unittest import mock import pytest import aurweb.config import aurweb.initdb - from aurweb import db from aurweb.models.account_type import AccountType class Args: - """ Stub arguments used for running aurweb.initdb. """ + """Stub arguments used for running aurweb.initdb.""" + use_alembic = True verbose = True class DBCursor: - """ A fake database cursor object used in tests. """ + """A fake database cursor object used in tests.""" + items = [] def execute(self, *args, **kwargs): @@ -33,7 +33,8 @@ class DBCursor: class DBConnection: - """ A fake database connection object used in tests. """ + """A fake database connection object used in tests.""" + @staticmethod def cursor(): return DBCursor() @@ -44,7 +45,7 @@ class DBConnection: def make_temp_config(*replacements): - """ Generate a temporary config file with a set of replacements. + """Generate a temporary config file with a set of replacements. :param *replacements: A variable number of tuple regex replacement pairs :return: A tuple containing (temp directory, temp config file) @@ -85,13 +86,16 @@ def make_temp_config(*replacements): def make_temp_sqlite_config(): - return make_temp_config((r"backend = .*", "backend = sqlite"), - (r"name = .*", "name = /tmp/aurweb.sqlite3")) + return make_temp_config( + (r"backend = .*", "backend = sqlite"), + (r"name = .*", "name = /tmp/aurweb.sqlite3"), + ) def make_temp_mysql_config(): - return make_temp_config((r"backend = .*", "backend = mysql"), - (r"name = .*", "name = aurweb_test")) + return make_temp_config( + (r"backend = .*", "backend = mysql"), (r"name = .*", "name = aurweb_test") + ) @pytest.fixture(autouse=True) @@ -150,7 +154,7 @@ def test_sqlalchemy_unknown_backend(): def test_db_connects_without_fail(): - """ This only tests the actual config supplied to pytest. """ + """This only tests the actual config supplied to pytest.""" db.connect() diff --git a/test/test_dependency_type.py b/test/test_dependency_type.py index c5afd38d..e172782b 100644 --- a/test/test_dependency_type.py +++ b/test/test_dependency_type.py @@ -12,8 +12,7 @@ def setup(db_test): def test_dependency_types(): dep_types = ["depends", "makedepends", "checkdepends", "optdepends"] for dep_type in dep_types: - dependency_type = query(DependencyType, - DependencyType.Name == dep_type).first() + dependency_type = query(DependencyType, DependencyType.Name == dep_type).first() assert dependency_type is not None diff --git a/test/test_email.py b/test/test_email.py index 873feffe..81abd507 100644 --- a/test/test_email.py +++ b/test/test_email.py @@ -1,5 +1,4 @@ import io - from subprocess import PIPE, Popen import pytest @@ -23,7 +22,7 @@ def sendmail(from_: str, to_: str, content: str) -> Email: def test_email_glue(): - """ Test that Email.glue() decodes both base64 and decoded content. """ + """Test that Email.glue() decodes both base64 and decoded content.""" body = "Test email." sendmail("test@example.org", "test@example.org", body) assert Email.count() == 1 @@ -34,7 +33,7 @@ def test_email_glue(): def test_email_dump(): - """ Test that Email.dump() dumps a single email. """ + """Test that Email.dump() dumps a single email.""" body = "Test email." sendmail("test@example.org", "test@example.org", body) assert Email.count() == 1 @@ -46,7 +45,7 @@ def test_email_dump(): def test_email_dump_multiple(): - """ Test that Email.dump() dumps multiple emails. """ + """Test that Email.dump() dumps multiple emails.""" body = "Test email." sendmail("test@example.org", "test@example.org", body) sendmail("test2@example.org", "test2@example.org", body) diff --git a/test/test_filelock.py b/test/test_filelock.py index 70aa7580..c0580642 100644 --- a/test/test_filelock.py +++ b/test/test_filelock.py @@ -1,5 +1,4 @@ import py - from _pytest.logging import LogCaptureFixture from aurweb.testing.filelock import FileLock diff --git a/test/test_filters.py b/test/test_filters.py index 558911f5..e74ddb87 100644 --- a/test/test_filters.py +++ b/test/test_filters.py @@ -22,7 +22,7 @@ def test_number_format(): def test_extend_query(): - """ Test extension of a query via extend_query. """ + """Test extension of a query via extend_query.""" query = {"a": "b"} extended = filters.extend_query(query, ("a", "c"), ("b", "d")) assert extended.get("a") == "c" @@ -30,7 +30,7 @@ def test_extend_query(): def test_to_qs(): - """ Test conversion from a query dictionary to a query string. """ + """Test conversion from a query dictionary to a query string.""" query = {"a": "b", "c": [1, 2, 3]} qs = filters.to_qs(query) assert qs == "a=b&c=1&c=2&c=3" diff --git a/test/test_group.py b/test/test_group.py index 82b82464..a1c563b6 100644 --- a/test/test_group.py +++ b/test/test_group.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db diff --git a/test/test_homepage.py b/test/test_homepage.py index 63b832e3..5490a244 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -1,10 +1,8 @@ import re - from http import HTTPStatus from unittest.mock import patch import pytest - from fastapi.testclient import TestClient from aurweb import db, time @@ -31,16 +29,26 @@ def setup(db_test): @pytest.fixture def user(): with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def user2(): with db.begin(): - user = db.create(User, Username="test2", Email="test2@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + user = db.create( + User, + Username="test2", + Email="test2@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -50,10 +58,17 @@ def redis(): def delete_keys(): # Cleanup keys if they exist. - for key in ("package_count", "orphan_count", "user_count", - "trusted_user_count", "seven_days_old_added", - "seven_days_old_updated", "year_old_updated", - "never_updated", "package_updates"): + for key in ( + "package_count", + "orphan_count", + "user_count", + "trusted_user_count", + "seven_days_old_added", + "seven_days_old_updated", + "year_old_updated", + "never_updated", + "package_updates", + ): if redis.get(key) is not None: redis.delete(key) @@ -66,16 +81,21 @@ def redis(): def package(user: User) -> Package: now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, Name="test-pkg", - Maintainer=user, Packager=user, - SubmittedTS=now, ModifiedTS=now) + pkgbase = db.create( + PackageBase, + Name="test-pkg", + Maintainer=user, + Packager=user, + SubmittedTS=now, + ModifiedTS=now, + ) pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) yield pkg @pytest.fixture def packages(user): - """ Yield a list of num_packages Package objects maintained by user. """ + """Yield a list of num_packages Package objects maintained by user.""" num_packages = 50 # Tunable # For i..num_packages, create a package named pkg_{i}. @@ -83,9 +103,14 @@ def packages(user): now = time.utcnow() with db.begin(): for i in range(num_packages): - pkgbase = db.create(PackageBase, Name=f"pkg_{i}", - Maintainer=user, Packager=user, - SubmittedTS=now, ModifiedTS=now) + pkgbase = db.create( + PackageBase, + Name=f"pkg_{i}", + Maintainer=user, + Packager=user, + SubmittedTS=now, + ModifiedTS=now, + ) pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) pkgs.append(pkg) now += 1 @@ -99,9 +124,9 @@ def test_homepage(): assert response.status_code == int(HTTPStatus.OK) -@patch('aurweb.util.get_ssh_fingerprints') +@patch("aurweb.util.get_ssh_fingerprints") def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock): - fingerprints = {'Ed25519': "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"} + fingerprints = {"Ed25519": "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"} get_ssh_fingerprints_mock.return_value = fingerprints with client as request: @@ -110,17 +135,23 @@ def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock): for key, value in fingerprints.items(): assert key in response.content.decode() assert value in response.content.decode() - assert 'The following SSH fingerprints are used for the AUR' in response.content.decode() + assert ( + "The following SSH fingerprints are used for the AUR" + in response.content.decode() + ) -@patch('aurweb.util.get_ssh_fingerprints') +@patch("aurweb.util.get_ssh_fingerprints") def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock): get_ssh_fingerprints_mock.return_value = {} with client as request: response = request.get("/") - assert 'The following SSH fingerprints are used for the AUR' not in response.content.decode() + assert ( + "The following SSH fingerprints are used for the AUR" + not in response.content.decode() + ) def test_homepage_stats(redis, packages): @@ -131,20 +162,20 @@ def test_homepage_stats(redis, packages): root = parse_root(response.text) expectations = [ - ("Packages", r'\d+'), - ("Orphan Packages", r'\d+'), - ("Packages added in the past 7 days", r'\d+'), - ("Packages updated in the past 7 days", r'\d+'), - ("Packages updated in the past year", r'\d+'), - ("Packages never updated", r'\d+'), - ("Registered Users", r'\d+'), - ("Trusted Users", r'\d+') + ("Packages", r"\d+"), + ("Orphan Packages", r"\d+"), + ("Packages added in the past 7 days", r"\d+"), + ("Packages updated in the past 7 days", r"\d+"), + ("Packages updated in the past year", r"\d+"), + ("Packages never updated", r"\d+"), + ("Registered Users", r"\d+"), + ("Trusted Users", r"\d+"), ] stats = root.xpath('//div[@id="pkg-stats"]//tr') for i, expected in enumerate(expectations): expected_key, expected_regex = expected - key, value = stats[i].xpath('./td') + key, value = stats[i].xpath("./td") assert key.text.strip() == expected_key assert re.match(expected_regex, value.text.strip()) @@ -165,7 +196,7 @@ def test_homepage_updates(redis, packages): expectations = [f"pkg_{i}" for i in range(50 - 1, 50 - 1 - 15, -1)] updates = root.xpath('//div[@id="pkg-updates"]/table/tbody/tr') for i, expected in enumerate(expectations): - pkgname = updates[i].xpath('./td/a').pop(0) + pkgname = updates[i].xpath("./td/a").pop(0) assert pkgname.text.strip() == expected @@ -173,9 +204,9 @@ def test_homepage_dashboard(redis, packages, user): # Create Comaintainer records for all of the packages. with db.begin(): for pkg in packages: - db.create(PackageComaintainer, - PackageBase=pkg.PackageBase, - User=user, Priority=1) + db.create( + PackageComaintainer, PackageBase=pkg.PackageBase, User=user, Priority=1 + ) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -189,16 +220,18 @@ def test_homepage_dashboard(redis, packages, user): expectations = [f"pkg_{i}" for i in range(50 - 1, 0, -1)] my_packages = root.xpath('//table[@id="my-packages"]/tbody/tr') for i, expected in enumerate(expectations): - name, version, votes, pop, voted, notify, desc, maint \ - = my_packages[i].xpath('./td') - assert name.xpath('./a').pop(0).text.strip() == expected + name, version, votes, pop, voted, notify, desc, maint = my_packages[i].xpath( + "./td" + ) + assert name.xpath("./a").pop(0).text.strip() == expected # Do the same for the Comaintained Packages table. my_packages = root.xpath('//table[@id="comaintained-packages"]/tbody/tr') for i, expected in enumerate(expectations): - name, version, votes, pop, voted, notify, desc, maint \ - = my_packages[i].xpath('./td') - assert name.xpath('./a').pop(0).text.strip() == expected + name, version, votes, pop, voted, notify, desc, maint = my_packages[i].xpath( + "./td" + ) + assert name.xpath("./a").pop(0).text.strip() == expected def test_homepage_dashboard_requests(redis, packages, user): @@ -207,11 +240,16 @@ def test_homepage_dashboard_requests(redis, packages, user): pkg = packages[0] reqtype = db.query(RequestType, RequestType.ID == DELETION_ID).first() with db.begin(): - pkgreq = db.create(PackageRequest, PackageBase=pkg.PackageBase, - PackageBaseName=pkg.PackageBase.Name, - User=user, Comments=str(), - ClosureComment=str(), RequestTS=now, - RequestType=reqtype) + pkgreq = db.create( + PackageRequest, + PackageBase=pkg.PackageBase, + PackageBaseName=pkg.PackageBase.Name, + User=user, + Comments=str(), + ClosureComment=str(), + RequestTS=now, + RequestType=reqtype, + ) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -220,7 +258,7 @@ def test_homepage_dashboard_requests(redis, packages, user): root = parse_root(response.text) request = root.xpath('//table[@id="pkgreq-results"]/tbody/tr').pop(0) - pkgname = request.xpath('./td/a').pop(0) + pkgname = request.xpath("./td/a").pop(0) assert pkgname.text.strip() == pkgreq.PackageBaseName @@ -238,7 +276,7 @@ def test_homepage_dashboard_flagged_packages(redis, packages, user): # Check to see that the package showed up in the Flagged Packages table. root = parse_root(response.text) flagged_pkg = root.xpath('//table[@id="flagged-packages"]/tbody/tr').pop(0) - flagged_name = flagged_pkg.xpath('./td/a').pop(0) + flagged_name = flagged_pkg.xpath("./td/a").pop(0) assert flagged_name.text.strip() == pkg.Name @@ -247,8 +285,7 @@ def test_homepage_dashboard_flagged(user: User, user2: User, package: Package): now = time.utcnow() with db.begin(): - db.create(PackageComaintainer, User=user2, - PackageBase=pkgbase, Priority=1) + db.create(PackageComaintainer, User=user2, PackageBase=pkgbase, Priority=1) pkgbase.OutOfDateTS = now - 5 pkgbase.Flagger = user diff --git a/test/test_html.py b/test/test_html.py index ffe2a9f2..88c75a7c 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -2,13 +2,11 @@ import hashlib import os import tempfile - from http import HTTPStatus from unittest import mock import fastapi import pytest - from fastapi import HTTPException from fastapi.testclient import TestClient @@ -33,8 +31,13 @@ def client() -> TestClient: @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -53,12 +56,7 @@ def pkgbase(user: User) -> PackageBase: def test_archdev_navbar(client: TestClient): - expected = [ - "AUR Home", - "Packages", - "Register", - "Login" - ] + expected = ["AUR Home", "Packages", "Register", "Login"] with client as request: resp = request.get("/") assert resp.status_code == int(HTTPStatus.OK) @@ -70,13 +68,7 @@ def test_archdev_navbar(client: TestClient): def test_archdev_navbar_authenticated(client: TestClient, user: User): - expected = [ - "Dashboard", - "Packages", - "Requests", - "My Account", - "Logout" - ] + expected = ["Dashboard", "Packages", "Requests", "My Account", "Logout"] cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: resp = request.get("/", cookies=cookies) @@ -88,8 +80,7 @@ def test_archdev_navbar_authenticated(client: TestClient, user: User): assert item.text.strip() == expected[i] -def test_archdev_navbar_authenticated_tu(client: TestClient, - trusted_user: User): +def test_archdev_navbar_authenticated_tu(client: TestClient, trusted_user: User): expected = [ "Dashboard", "Packages", @@ -97,7 +88,7 @@ def test_archdev_navbar_authenticated_tu(client: TestClient, "Accounts", "My Account", "Trusted User", - "Logout" + "Logout", ] cookies = {"AURSID": trusted_user.login(Request(), "testPassword")} with client as request: @@ -131,7 +122,7 @@ def test_get_successes(): def test_archive_sig(client: TestClient): - hash_value = hashlib.sha256(b'test').hexdigest() + hash_value = hashlib.sha256(b"test").hexdigest() with tempfile.TemporaryDirectory() as tmpdir: packages_sha256 = os.path.join(tmpdir, "packages.gz.sha256") @@ -179,12 +170,7 @@ def test_disabled_metrics(client: TestClient): def test_rtl(client: TestClient): responses = {} - expected = [ - [], - [], - ['rtl'], - ['rtl'] - ] + expected = [[], [], ["rtl"], ["rtl"]] with client as request: responses["default"] = request.get("/") responses["de"] = request.get("/", cookies={"AURLANG": "de"}) @@ -193,11 +179,11 @@ def test_rtl(client: TestClient): for i, (lang, resp) in enumerate(responses.items()): assert resp.status_code == int(HTTPStatus.OK) t = parse_root(resp.text) - assert t.xpath('//html/@dir') == expected[i] + assert t.xpath("//html/@dir") == expected[i] def test_404_with_valid_pkgbase(client: TestClient, pkgbase: PackageBase): - """ Test HTTPException with status_code == 404 and valid pkgbase. """ + """Test HTTPException with status_code == 404 and valid pkgbase.""" endpoint = f"/{pkgbase.Name}" with client as request: response = request.get(endpoint) @@ -209,7 +195,7 @@ def test_404_with_valid_pkgbase(client: TestClient, pkgbase: PackageBase): def test_404(client: TestClient): - """ Test HTTPException with status_code == 404 without a valid pkgbase. """ + """Test HTTPException with status_code == 404 without a valid pkgbase.""" with client as request: response = request.get("/nonexistentroute") assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -221,7 +207,8 @@ def test_404(client: TestClient): def test_503(client: TestClient): - """ Test HTTPException with status_code == 503 (Service Unavailable). """ + """Test HTTPException with status_code == 503 (Service Unavailable).""" + @asgi.app.get("/raise-503") async def raise_503(request: fastapi.Request): raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE) diff --git a/test/test_initdb.py b/test/test_initdb.py index 44681d8e..db5edf74 100644 --- a/test/test_initdb.py +++ b/test/test_initdb.py @@ -3,7 +3,6 @@ import pytest import aurweb.config import aurweb.db import aurweb.initdb - from aurweb.models.account_type import AccountType @@ -19,11 +18,11 @@ class Args: def test_run(): from aurweb.schema import metadata + aurweb.db.kill_engine() metadata.drop_all(aurweb.db.get_engine()) aurweb.initdb.run(Args()) # Check that constant table rows got added via initdb. - record = aurweb.db.query(AccountType, - AccountType.AccountType == "User").first() + record = aurweb.db.query(AccountType, AccountType.AccountType == "User").first() assert record is not None diff --git a/test/test_l10n.py b/test/test_l10n.py index c24c5f55..818d517f 100644 --- a/test/test_l10n.py +++ b/test/test_l10n.py @@ -4,13 +4,13 @@ from aurweb.testing.requests import Request def test_translator(): - """ Test creating l10n translation tools. """ + """Test creating l10n translation tools.""" de_home = l10n.translator.translate("Home", "de") assert de_home == "Startseite" def test_get_request_language(): - """ First, tests default_lang, then tests a modified AURLANG cookie. """ + """First, tests default_lang, then tests a modified AURLANG cookie.""" request = Request() assert l10n.get_request_language(request) == "en" @@ -19,18 +19,17 @@ def test_get_request_language(): def test_get_raw_translator_for_request(): - """ Make sure that get_raw_translator_for_request is giving us - the translator we expect. """ + """Make sure that get_raw_translator_for_request is giving us + the translator we expect.""" request = Request() request.cookies["AURLANG"] = "de" translator = l10n.get_raw_translator_for_request(request) - assert translator.gettext("Home") == \ - l10n.translator.translate("Home", "de") + assert translator.gettext("Home") == l10n.translator.translate("Home", "de") def test_get_translator_for_request(): - """ Make sure that get_translator_for_request is giving us back - our expected translation function. """ + """Make sure that get_translator_for_request is giving us back + our expected translation function.""" request = Request() request.cookies["AURLANG"] = "de" @@ -43,10 +42,8 @@ def test_tn_filter(): request.cookies["AURLANG"] = "en" context = {"language": "en", "request": request} - translated = filters.tn(context, 1, "%d package found.", - "%d packages found.") + translated = filters.tn(context, 1, "%d package found.", "%d packages found.") assert translated == "%d package found." - translated = filters.tn(context, 2, "%d package found.", - "%d packages found.") + translated = filters.tn(context, 2, "%d package found.", "%d packages found.") assert translated == "%d packages found." diff --git a/test/test_license.py b/test/test_license.py index b34bd260..cea76e7d 100644 --- a/test/test_license.py +++ b/test/test_license.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db diff --git a/test/test_mkpkglists.py b/test/test_mkpkglists.py index 9bc1073b..3c105817 100644 --- a/test/test_mkpkglists.py +++ b/test/test_mkpkglists.py @@ -1,14 +1,20 @@ import gzip import json import os - from unittest import mock import py import pytest from aurweb import config, db -from aurweb.models import License, Package, PackageBase, PackageDependency, PackageLicense, User +from aurweb.models import ( + License, + Package, + PackageBase, + PackageDependency, + PackageLicense, + User, +) from aurweb.models.account_type import USER_ID from aurweb.models.dependency_type import DEPENDS_ID @@ -38,10 +44,13 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", - Email="test@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -52,16 +61,18 @@ def packages(user: User) -> list[Package]: lic = db.create(License, Name="GPL") for i in range(5): # Create the package. - pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}", - Packager=user) - pkg = db.create(Package, PackageBase=pkgbase, - Name=f"pkg_{i}") + pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}", Packager=user) + pkg = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}") # Create some related records. db.create(PackageLicense, Package=pkg, License=lic) - db.create(PackageDependency, DepTypeID=DEPENDS_ID, - Package=pkg, DepName=f"dep_{i}", - DepCondition=">=1.0") + db.create( + PackageDependency, + DepTypeID=DEPENDS_ID, + Package=pkg, + DepName=f"dep_{i}", + DepCondition=">=1.0", + ) # Add the package to our output list. output.append(pkg) @@ -88,8 +99,11 @@ def config_mock(tmpdir: py.path.local) -> None: config.rehash() -def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packages: list[Package]): +def test_mkpkglists( + tmpdir: py.path.local, config_mock: None, user: User, packages: list[Package] +): from aurweb.scripts import mkpkglists + mkpkglists.main() PACKAGES = config.get("mkpkglists", "packagesfile") @@ -106,10 +120,7 @@ def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packag PKGBASE, "pkgbase_0\npkgbase_1\npkgbase_2\npkgbase_3\npkgbase_4\n", ), - ( - USERS, - "test\n" - ), + (USERS, "test\n"), ] for (file, expected_content) in expectations: @@ -136,6 +147,7 @@ def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packag @mock.patch("sys.argv", ["mkpkglists", "--extended"]) def test_mkpkglists_extended_empty(config_mock: None): from aurweb.scripts import mkpkglists + mkpkglists.main() PACKAGES = config.get("mkpkglists", "packagesfile") @@ -166,9 +178,9 @@ def test_mkpkglists_extended_empty(config_mock: None): @mock.patch("sys.argv", ["mkpkglists", "--extended"]) -def test_mkpkglists_extended(config_mock: None, user: User, - packages: list[Package]): +def test_mkpkglists_extended(config_mock: None, user: User, packages: list[Package]): from aurweb.scripts import mkpkglists + mkpkglists.main() PACKAGES = config.get("mkpkglists", "packagesfile") @@ -186,10 +198,7 @@ def test_mkpkglists_extended(config_mock: None, user: User, PKGBASE, "pkgbase_0\npkgbase_1\npkgbase_2\npkgbase_3\npkgbase_4\n", ), - ( - USERS, - "test\n" - ), + (USERS, "test\n"), ] for (file, expected_content) in expectations: diff --git a/test/test_notify.py b/test/test_notify.py index bbcc6b5a..9e61d9ee 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -23,24 +23,39 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - Passwd=str(), AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def user1() -> User: with db.begin(): - user1 = db.create(User, Username="user1", Email="user1@example.org", - Passwd=str(), AccountTypeID=USER_ID) + user1 = db.create( + User, + Username="user1", + Email="user1@example.org", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user1 @pytest.fixture def user2() -> User: with db.begin(): - user2 = db.create(User, Username="user2", Email="user2@example.org", - Passwd=str(), AccountTypeID=USER_ID) + user2 = db.create( + User, + Username="user2", + Email="user2@example.org", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user2 @@ -52,11 +67,15 @@ def pkgbases(user: User) -> list[PackageBase]: with db.begin(): for i in range(5): output.append( - db.create(PackageBase, Name=f"pkgbase_{i}", - Maintainer=user, SubmittedTS=now, - ModifiedTS=now)) - db.create(models.PackageNotification, PackageBase=output[-1], - User=user) + db.create( + PackageBase, + Name=f"pkgbase_{i}", + Maintainer=user, + SubmittedTS=now, + ModifiedTS=now, + ) + ) + db.create(models.PackageNotification, PackageBase=output[-1], User=user) yield output @@ -64,11 +83,15 @@ def pkgbases(user: User) -> list[PackageBase]: def pkgreq(user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] with db.begin(): - pkgreq_ = db.create(PackageRequest, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, User=user2, - ReqTypeID=ORPHAN_ID, - Comments="This is a request test comment.", - ClosureComment=str()) + pkgreq_ = db.create( + PackageRequest, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + User=user2, + ReqTypeID=ORPHAN_ID, + Comments="This is a request test comment.", + ClosureComment=str(), + ) yield pkgreq_ @@ -78,21 +101,24 @@ def packages(pkgbases: list[PackageBase]) -> list[Package]: with db.begin(): for i, pkgbase in enumerate(pkgbases): output.append( - db.create(Package, PackageBase=pkgbase, - Name=f"pkg_{i}", Version=f"{i}.0")) + db.create( + Package, PackageBase=pkgbase, Name=f"pkg_{i}", Version=f"{i}.0" + ) + ) yield output -def test_out_of_date(user: User, user1: User, user2: User, - pkgbases: list[PackageBase]): +def test_out_of_date(user: User, user1: User, user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] # Create two comaintainers. We'll pass the maintainer uid to # FlagNotification, so we should expect to get two emails. with db.begin(): - db.create(models.PackageComaintainer, - PackageBase=pkgbase, User=user1, Priority=1) - db.create(models.PackageComaintainer, - PackageBase=pkgbase, User=user2, Priority=2) + db.create( + models.PackageComaintainer, PackageBase=pkgbase, User=user1, Priority=1 + ) + db.create( + models.PackageComaintainer, PackageBase=pkgbase, User=user2, Priority=2 + ) # Send the notification for pkgbases[0]. notif = notify.FlagNotification(user.ID, pkgbases[0].ID) @@ -165,8 +191,12 @@ def test_comment(user: User, user2: User, pkgbases: list[PackageBase]): pkgbase = pkgbases[0] with db.begin(): - comment = db.create(models.PackageComment, PackageBase=pkgbase, - User=user2, Comments="This is a test comment.") + comment = db.create( + models.PackageComment, + PackageBase=pkgbase, + User=user2, + Comments="This is a test comment.", + ) rendercomment.update_comment_render_fastapi(comment) notif = notify.CommentNotification(user2.ID, pkgbase.ID, comment.ID) @@ -366,15 +396,16 @@ def set_tu(users: list[User]) -> User: user.AccountTypeID = TRUSTED_USER_ID -def test_open_close_request(user: User, user2: User, - pkgreq: PackageRequest, - pkgbases: list[PackageBase]): +def test_open_close_request( + user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase] +): set_tu([user]) pkgbase = pkgbases[0] # Send an open request notification. notif = notify.RequestOpenNotification( - user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID) + user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID + ) notif.send() assert Email.count() == 1 @@ -420,22 +451,24 @@ Request #{pkgreq.ID} has been rejected by {user2.Username} [1]. email = Email(3).parse() assert email.headers.get("To") == aur_request_ml assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) - expected = (f"[PRQ#{pkgreq.ID}] Orphan Request for " - f"{pkgbase.Name} Accepted") + expected = f"[PRQ#{pkgreq.ID}] Orphan Request for " f"{pkgbase.Name} Accepted" assert email.headers.get("Subject") == expected - expected = (f"Request #{pkgreq.ID} has been accepted automatically " - "by the Arch User Repository\npackage request system.") + expected = ( + f"Request #{pkgreq.ID} has been accepted automatically " + "by the Arch User Repository\npackage request system." + ) assert email.body == expected -def test_close_request_comaintainer_cc(user: User, user2: User, - pkgreq: PackageRequest, - pkgbases: list[PackageBase]): +def test_close_request_comaintainer_cc( + user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase] +): pkgbase = pkgbases[0] with db.begin(): - db.create(models.PackageComaintainer, PackageBase=pkgbase, - User=user2, Priority=1) + db.create( + models.PackageComaintainer, PackageBase=pkgbase, User=user2, Priority=1 + ) notif = notify.RequestCloseNotification(0, pkgreq.ID, "accepted") notif.send() @@ -446,9 +479,9 @@ def test_close_request_comaintainer_cc(user: User, user2: User, assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) -def test_close_request_closure_comment(user: User, user2: User, - pkgreq: PackageRequest, - pkgbases: list[PackageBase]): +def test_close_request_closure_comment( + user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase] +): pkgbase = pkgbases[0] with db.begin(): pkgreq.ClosureComment = "This is a test closure comment." @@ -496,7 +529,7 @@ ends in less than 48 hours. def test_notify_main(user: User): - """ Test TU vote reminder through aurweb.notify.main(). """ + """Test TU vote reminder through aurweb.notify.main().""" set_tu([user]) vote_id = 1 @@ -539,6 +572,7 @@ def mock_smtp_config(cls): elif key == "smtp-password": return cls() return cls(config_get(section, key)) + return _mock_smtp_config @@ -574,6 +608,7 @@ def mock_smtp_starttls_config(cls): elif key == "smtp-password": return cls("password") return cls(config_get(section, key)) + return _mock_smtp_starttls_config @@ -590,8 +625,7 @@ def test_smtp_starttls(user: User): get = "aurweb.config.get" getboolean = "aurweb.config.getboolean" with mock.patch(get, side_effect=mock_smtp_starttls_config(str)): - with mock.patch( - getboolean, side_effect=mock_smtp_starttls_config(bool)): + with mock.patch(getboolean, side_effect=mock_smtp_starttls_config(bool)): with mock.patch("smtplib.SMTP", side_effect=smtp): notif = notify.WelcomeNotification(user.ID) notif.send() @@ -621,6 +655,7 @@ def mock_smtp_ssl_config(cls): elif key == "smtp-password": return cls("password") return cls(config_get(section, key)) + return _mock_smtp_ssl_config @@ -651,7 +686,7 @@ def test_notification_defaults(): def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture): - """ Try sending a notification with a bad SMTP configuration. """ + """Try sending a notification with a bad SMTP configuration.""" caplog.set_level(ERROR) config_get = config.get config_getint = config.getint diff --git a/test/test_official_provider.py b/test/test_official_provider.py index 9287ea2d..b36fff5a 100644 --- a/test/test_official_provider.py +++ b/test/test_official_provider.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -13,10 +12,12 @@ def setup(db_test): def test_official_provider_creation(): with db.begin(): - oprovider = db.create(OfficialProvider, - Name="some-name", - Repo="some-repo", - Provides="some-provides") + oprovider = db.create( + OfficialProvider, + Name="some-name", + Repo="some-repo", + Provides="some-provides", + ) assert bool(oprovider.ID) assert oprovider.Name == "some-name" assert oprovider.Repo == "some-repo" @@ -24,19 +25,23 @@ def test_official_provider_creation(): def test_official_provider_cs(): - """ Test case sensitivity of the database table. """ + """Test case sensitivity of the database table.""" with db.begin(): - oprovider = db.create(OfficialProvider, - Name="some-name", - Repo="some-repo", - Provides="some-provides") + oprovider = db.create( + OfficialProvider, + Name="some-name", + Repo="some-repo", + Provides="some-provides", + ) assert bool(oprovider.ID) with db.begin(): - oprovider_cs = db.create(OfficialProvider, - Name="SOME-NAME", - Repo="SOME-REPO", - Provides="SOME-PROVIDES") + oprovider_cs = db.create( + OfficialProvider, + Name="SOME-NAME", + Repo="SOME-REPO", + Provides="SOME-PROVIDES", + ) assert bool(oprovider_cs.ID) assert oprovider.ID != oprovider_cs.ID diff --git a/test/test_package.py b/test/test_package.py index 1408a182..2a9df483 100644 --- a/test/test_package.py +++ b/test/test_package.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy import and_ from sqlalchemy.exc import IntegrityError @@ -20,20 +19,28 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def package(user: User) -> Package: with db.begin(): - pkgbase = db.create(PackageBase, Name="beautiful-package", - Maintainer=user) - package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user) + package = db.create( + Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package", + ) yield package @@ -48,21 +55,28 @@ def test_package(package: Package): package.Version = "1.2.3" # Make sure it got updated in the database. - record = db.query(Package).filter( - and_(Package.ID == package.ID, - Package.Version == "1.2.3") - ).first() + record = ( + db.query(Package) + .filter(and_(Package.ID == package.ID, Package.Version == "1.2.3")) + .first() + ) assert record is not None def test_package_null_pkgbase_raises(): with pytest.raises(IntegrityError): - Package(Name="some-package", Description="Some description.", - URL="https://some.package") + Package( + Name="some-package", + Description="Some description.", + URL="https://some.package", + ) def test_package_null_name_raises(package: Package): pkgbase = package.PackageBase with pytest.raises(IntegrityError): - Package(PackageBase=pkgbase, Description="Some description.", - URL="https://some.package") + Package( + PackageBase=pkgbase, + Description="Some description.", + URL="https://some.package", + ) diff --git a/test/test_package_base.py b/test/test_package_base.py index 5be7e40b..feea8183 100644 --- a/test/test_package_base.py +++ b/test/test_package_base.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -16,17 +15,21 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def pkgbase(user: User) -> PackageBase: with db.begin(): - pkgbase = db.create(PackageBase, Name="beautiful-package", - Maintainer=user) + pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user) yield pkgbase @@ -44,7 +47,7 @@ def test_package_base(user: User, pkgbase: PackageBase): def test_package_base_ci(user: User, pkgbase: PackageBase): - """ Test case insensitivity of the database table. """ + """Test case insensitivity of the database table.""" with pytest.raises(IntegrityError): with db.begin(): db.create(PackageBase, Name=pkgbase.Name.upper(), Maintainer=user) diff --git a/test/test_package_blacklist.py b/test/test_package_blacklist.py index 427c3be4..44de1830 100644 --- a/test/test_package_blacklist.py +++ b/test/test_package_blacklist.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db diff --git a/test/test_package_comaintainer.py b/test/test_package_comaintainer.py index e377edc0..52075887 100644 --- a/test/test_package_comaintainer.py +++ b/test/test_package_comaintainer.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -17,9 +16,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -32,8 +36,9 @@ def pkgbase(user: User) -> PackageBase: def test_package_comaintainer_creation(user: User, pkgbase: PackageBase): with db.begin(): - package_comaintainer = db.create(PackageComaintainer, User=user, - PackageBase=pkgbase, Priority=5) + package_comaintainer = db.create( + PackageComaintainer, User=user, PackageBase=pkgbase, Priority=5 + ) assert bool(package_comaintainer) assert package_comaintainer.User == user assert package_comaintainer.PackageBase == pkgbase @@ -50,7 +55,6 @@ def test_package_comaintainer_null_pkgbase_raises(user: User): PackageComaintainer(User=user, Priority=1) -def test_package_comaintainer_null_priority_raises(user: User, - pkgbase: PackageBase): +def test_package_comaintainer_null_priority_raises(user: User, pkgbase: PackageBase): with pytest.raises(IntegrityError): PackageComaintainer(User=user, PackageBase=pkgbase) diff --git a/test/test_package_comment.py b/test/test_package_comment.py index c89e23af..74f2895d 100644 --- a/test/test_package_comment.py +++ b/test/test_package_comment.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -17,9 +16,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -32,35 +36,46 @@ def pkgbase(user: User) -> PackageBase: def test_package_comment_creation(user: User, pkgbase: PackageBase): with db.begin(): - package_comment = db.create(PackageComment, PackageBase=pkgbase, - User=user, Comments="Test comment.", - RenderedComment="Test rendered comment.") + package_comment = db.create( + PackageComment, + PackageBase=pkgbase, + User=user, + Comments="Test comment.", + RenderedComment="Test rendered comment.", + ) assert bool(package_comment.ID) def test_package_comment_null_pkgbase_raises(user: User): with pytest.raises(IntegrityError): - PackageComment(User=user, Comments="Test comment.", - RenderedComment="Test rendered comment.") + PackageComment( + User=user, + Comments="Test comment.", + RenderedComment="Test rendered comment.", + ) def test_package_comment_null_user_raises(pkgbase: PackageBase): with pytest.raises(IntegrityError): - PackageComment(PackageBase=pkgbase, - Comments="Test comment.", - RenderedComment="Test rendered comment.") + PackageComment( + PackageBase=pkgbase, + Comments="Test comment.", + RenderedComment="Test rendered comment.", + ) -def test_package_comment_null_comments_raises(user: User, - pkgbase: PackageBase): +def test_package_comment_null_comments_raises(user: User, pkgbase: PackageBase): with pytest.raises(IntegrityError): - PackageComment(PackageBase=pkgbase, User=user, - RenderedComment="Test rendered comment.") + PackageComment( + PackageBase=pkgbase, User=user, RenderedComment="Test rendered comment." + ) -def test_package_comment_null_renderedcomment_defaults(user: User, - pkgbase: PackageBase): +def test_package_comment_null_renderedcomment_defaults( + user: User, pkgbase: PackageBase +): with db.begin(): - record = db.create(PackageComment, PackageBase=pkgbase, - User=user, Comments="Test comment.") + record = db.create( + PackageComment, PackageBase=pkgbase, User=user, Comments="Test comment." + ) assert record.RenderedComment == str() diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py index 2afbc1e3..9366bb55 100644 --- a/test/test_package_dependency.py +++ b/test/test_package_dependency.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -19,9 +18,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd=str(), - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user @@ -29,16 +33,21 @@ def user() -> User: def package(user: User) -> Package: with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) - package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + package = db.create( + Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package", + ) yield package def test_package_dependencies(user: User, package: Package): with db.begin(): - pkgdep = db.create(PackageDependency, Package=package, - DepTypeID=DEPENDS_ID, DepName="test-dep") + pkgdep = db.create( + PackageDependency, Package=package, DepTypeID=DEPENDS_ID, DepName="test-dep" + ) assert pkgdep.DepName == "test-dep" assert pkgdep.Package == package assert pkgdep in package.package_dependencies diff --git a/test/test_package_group.py b/test/test_package_group.py index 0cb83ee2..163f693d 100644 --- a/test/test_package_group.py +++ b/test/test_package_group.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -19,9 +18,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user diff --git a/test/test_package_keyword.py b/test/test_package_keyword.py index ff466efc..b52547f9 100644 --- a/test/test_package_keyword.py +++ b/test/test_package_keyword.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -17,24 +16,27 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def pkgbase(user: User) -> PackageBase: with db.begin(): - pkgbase = db.create(PackageBase, Name="beautiful-package", - Maintainer=user) + pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user) yield pkgbase def test_package_keyword(pkgbase: PackageBase): with db.begin(): - pkg_keyword = db.create(PackageKeyword, PackageBase=pkgbase, - Keyword="test") + pkg_keyword = db.create(PackageKeyword, PackageBase=pkgbase, Keyword="test") assert pkg_keyword in pkgbase.keywords assert pkgbase == pkg_keyword.PackageBase diff --git a/test/test_package_license.py b/test/test_package_license.py index c43423b8..b9242647 100644 --- a/test/test_package_license.py +++ b/test/test_package_license.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -19,9 +18,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -42,8 +46,7 @@ def package(user: User, license: License): def test_package_license(license: License, package: Package): with db.begin(): - package_license = db.create(PackageLicense, Package=package, - License=license) + package_license = db.create(PackageLicense, Package=package, License=license) assert package_license.License == license assert package_license.Package == package diff --git a/test/test_package_notification.py b/test/test_package_notification.py index e7a72a43..27a03e84 100644 --- a/test/test_package_notification.py +++ b/test/test_package_notification.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -16,8 +15,13 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword") + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + ) yield user @@ -31,7 +35,8 @@ def pkgbase(user: User) -> PackageBase: def test_package_notification_creation(user: User, pkgbase: PackageBase): with db.begin(): package_notification = db.create( - PackageNotification, User=user, PackageBase=pkgbase) + PackageNotification, User=user, PackageBase=pkgbase + ) assert bool(package_notification) assert package_notification.User == user assert package_notification.PackageBase == pkgbase diff --git a/test/test_package_relation.py b/test/test_package_relation.py index 6e9a5545..c20b1394 100644 --- a/test/test_package_relation.py +++ b/test/test_package_relation.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -19,9 +18,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -29,17 +33,24 @@ def user() -> User: def package(user: User) -> Package: with db.begin(): pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user) - package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, - Description="Test description.", - URL="https://test.package") + package = db.create( + Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Test description.", + URL="https://test.package", + ) yield package def test_package_relation(package: Package): with db.begin(): - pkgrel = db.create(PackageRelation, Package=package, - RelTypeID=CONFLICTS_ID, - RelName="test-relation") + pkgrel = db.create( + PackageRelation, + Package=package, + RelTypeID=CONFLICTS_ID, + RelName="test-relation", + ) assert pkgrel.RelName == "test-relation" assert pkgrel.Package == package diff --git a/test/test_package_request.py b/test/test_package_request.py index 3474c565..a69a0617 100644 --- a/test/test_package_request.py +++ b/test/test_package_request.py @@ -1,12 +1,20 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db, time from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase -from aurweb.models.package_request import (ACCEPTED, ACCEPTED_ID, CLOSED, CLOSED_ID, PENDING, PENDING_ID, REJECTED, - REJECTED_ID, PackageRequest) +from aurweb.models.package_request import ( + ACCEPTED, + ACCEPTED_ID, + CLOSED, + CLOSED_ID, + PENDING, + PENDING_ID, + REJECTED, + REJECTED_ID, + PackageRequest, +) from aurweb.models.request_type import MERGE_ID from aurweb.models.user import User @@ -19,9 +27,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -34,10 +47,15 @@ def pkgbase(user: User) -> PackageBase: def test_package_request_creation(user: User, pkgbase: PackageBase): with db.begin(): - package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + package_request = db.create( + PackageRequest, + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), + ClosureComment=str(), + ) assert bool(package_request.ID) assert package_request.User == user @@ -54,11 +72,17 @@ def test_package_request_creation(user: User, pkgbase: PackageBase): def test_package_request_closed(user: User, pkgbase: PackageBase): ts = time.utcnow() with db.begin(): - package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Closer=user, ClosedTS=ts, - Comments=str(), ClosureComment=str()) + package_request = db.create( + PackageRequest, + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Closer=user, + ClosedTS=ts, + Comments=str(), + ClosureComment=str(), + ) assert package_request.Closer == user assert package_request.ClosedTS == ts @@ -67,61 +91,87 @@ def test_package_request_closed(user: User, pkgbase: PackageBase): assert package_request in user.closed_requests -def test_package_request_null_request_type_raises(user: User, - pkgbase: PackageBase): +def test_package_request_null_request_type_raises(user: User, pkgbase: PackageBase): with pytest.raises(IntegrityError): - PackageRequest(User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + PackageRequest( + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), + ClosureComment=str(), + ) def test_package_request_null_user_raises(pkgbase: PackageBase): with pytest.raises(IntegrityError): - PackageRequest(ReqTypeID=MERGE_ID, - PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + PackageRequest( + ReqTypeID=MERGE_ID, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), + ClosureComment=str(), + ) -def test_package_request_null_package_base_raises(user: User, - pkgbase: PackageBase): +def test_package_request_null_package_base_raises(user: User, pkgbase: PackageBase): with pytest.raises(IntegrityError): - PackageRequest(ReqTypeID=MERGE_ID, - User=user, PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str()) + PackageRequest( + ReqTypeID=MERGE_ID, + User=user, + PackageBaseName=pkgbase.Name, + Comments=str(), + ClosureComment=str(), + ) -def test_package_request_null_package_base_name_raises(user: User, - pkgbase: PackageBase): +def test_package_request_null_package_base_name_raises( + user: User, pkgbase: PackageBase +): with pytest.raises(IntegrityError): - PackageRequest(ReqTypeID=MERGE_ID, - User=user, PackageBase=pkgbase, - Comments=str(), ClosureComment=str()) + PackageRequest( + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + Comments=str(), + ClosureComment=str(), + ) -def test_package_request_null_comments_raises(user: User, - pkgbase: PackageBase): +def test_package_request_null_comments_raises(user: User, pkgbase: PackageBase): with pytest.raises(IntegrityError): - PackageRequest(ReqTypeID=MERGE_ID, User=user, - PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - ClosureComment=str()) + PackageRequest( + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + ClosureComment=str(), + ) -def test_package_request_null_closure_comment_raises(user: User, - pkgbase: PackageBase): +def test_package_request_null_closure_comment_raises(user: User, pkgbase: PackageBase): with pytest.raises(IntegrityError): - PackageRequest(ReqTypeID=MERGE_ID, User=user, - PackageBase=pkgbase, PackageBaseName=pkgbase.Name, - Comments=str()) + PackageRequest( + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), + ) def test_package_request_status_display(user: User, pkgbase: PackageBase): - """ Test status_display() based on the Status column value. """ + """Test status_display() based on the Status column value.""" with db.begin(): - pkgreq = db.create(PackageRequest, ReqTypeID=MERGE_ID, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=str(), ClosureComment=str(), - Status=PENDING_ID) + pkgreq = db.create( + PackageRequest, + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), + ClosureComment=str(), + Status=PENDING_ID, + ) assert pkgreq.status_display() == PENDING with db.begin(): diff --git a/test/test_package_source.py b/test/test_package_source.py index e5797f90..06230580 100644 --- a/test/test_package_source.py +++ b/test/test_package_source.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -18,9 +17,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user diff --git a/test/test_package_vote.py b/test/test_package_vote.py index 24d2fdd2..9a868262 100644 --- a/test/test_package_vote.py +++ b/test/test_package_vote.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db, time @@ -17,9 +16,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd=str(), - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user @@ -34,8 +38,7 @@ def test_package_vote_creation(user: User, pkgbase: PackageBase): ts = time.utcnow() with db.begin(): - package_vote = db.create(PackageVote, User=user, - PackageBase=pkgbase, VoteTS=ts) + package_vote = db.create(PackageVote, User=user, PackageBase=pkgbase, VoteTS=ts) assert bool(package_vote) assert package_vote.User == user assert package_vote.PackageBase == pkgbase diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 62f89e23..a707bbac 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1,10 +1,8 @@ import re - from http import HTTPStatus from unittest import mock import pytest - from fastapi.testclient import TestClient from aurweb import asgi, db, time @@ -22,7 +20,12 @@ from aurweb.models.package_notification import PackageNotification from aurweb.models.package_relation import PackageRelation from aurweb.models.package_request import PackageRequest from aurweb.models.package_vote import PackageVote -from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID, RelationType +from aurweb.models.relation_type import ( + CONFLICTS_ID, + PROVIDES_ID, + REPLACES_ID, + RelationType, +) from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User from aurweb.testing.html import get_errors, get_successes, parse_root @@ -34,30 +37,24 @@ def package_endpoint(package: Package) -> str: def create_package(pkgname: str, maintainer: User) -> Package: - pkgbase = db.create(PackageBase, - Name=pkgname, - Maintainer=maintainer) + pkgbase = db.create(PackageBase, Name=pkgname, Maintainer=maintainer) return db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) -def create_package_dep(package: Package, depname: str, - dep_type_name: str = "depends") -> PackageDependency: - dep_type = db.query(DependencyType, - DependencyType.Name == dep_type_name).first() - return db.create(PackageDependency, - DependencyType=dep_type, - Package=package, - DepName=depname) +def create_package_dep( + package: Package, depname: str, dep_type_name: str = "depends" +) -> PackageDependency: + dep_type = db.query(DependencyType, DependencyType.Name == dep_type_name).first() + return db.create( + PackageDependency, DependencyType=dep_type, Package=package, DepName=depname + ) -def create_package_rel(package: Package, - relname: str) -> PackageRelation: - rel_type = db.query(RelationType, - RelationType.ID == PROVIDES_ID).first() - return db.create(PackageRelation, - RelationType=rel_type, - Package=package, - RelName=relname) +def create_package_rel(package: Package, relname: str) -> PackageRelation: + rel_type = db.query(RelationType, RelationType.ID == PROVIDES_ID).first() + return db.create( + PackageRelation, RelationType=rel_type, Package=package, RelName=relname + ) @pytest.fixture(autouse=True) @@ -67,64 +64,73 @@ def setup(db_test): @pytest.fixture def client() -> TestClient: - """ Yield a FastAPI TestClient. """ + """Yield a FastAPI TestClient.""" yield TestClient(app=asgi.app) def create_user(username: str) -> User: with db.begin(): - user = db.create(User, Username=username, - Email=f"{username}@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username=username, + Email=f"{username}@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) return user @pytest.fixture def user() -> User: - """ Yield a user. """ + """Yield a user.""" user = create_user("test") yield user @pytest.fixture def maintainer() -> User: - """ Yield a specific User used to maintain packages. """ + """Yield a specific User used to maintain packages.""" account_type = db.query(AccountType, AccountType.ID == USER_ID).first() with db.begin(): - maintainer = db.create(User, Username="test_maintainer", - Email="test_maintainer@example.org", - Passwd="testPassword", - AccountType=account_type) + maintainer = db.create( + User, + Username="test_maintainer", + Email="test_maintainer@example.org", + Passwd="testPassword", + AccountType=account_type, + ) yield maintainer @pytest.fixture def tu_user(): - tu_type = db.query(AccountType, - AccountType.AccountType == "Trusted User").first() + tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first() with db.begin(): - tu_user = db.create(User, Username="test_tu", - Email="test_tu@example.org", - RealName="Test TU", Passwd="testPassword", - AccountType=tu_type) + tu_user = db.create( + User, + Username="test_tu", + Email="test_tu@example.org", + RealName="Test TU", + Passwd="testPassword", + AccountType=tu_type, + ) yield tu_user @pytest.fixture def package(maintainer: User) -> Package: - """ Yield a Package created by user. """ + """Yield a Package created by user.""" now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, - Name="test-package", - Maintainer=maintainer, - Packager=maintainer, - Submitter=maintainer, - ModifiedTS=now) - package = db.create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name) + pkgbase = db.create( + PackageBase, + Name="test-package", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now, + ) + package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) yield package @@ -135,29 +141,34 @@ def pkgbase(package: Package) -> PackageBase: @pytest.fixture def target(maintainer: User) -> PackageBase: - """ Merge target. """ + """Merge target.""" now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, Name="target-package", - Maintainer=maintainer, - Packager=maintainer, - Submitter=maintainer, - ModifiedTS=now) + pkgbase = db.create( + PackageBase, + Name="target-package", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now, + ) db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) yield pkgbase @pytest.fixture def pkgreq(user: User, pkgbase: PackageBase) -> PackageRequest: - """ Yield a PackageRequest related to `pkgbase`. """ + """Yield a PackageRequest related to `pkgbase`.""" with db.begin(): - pkgreq = db.create(PackageRequest, - ReqTypeID=DELETION_ID, - User=user, - PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=f"Deletion request for {pkgbase.Name}", - ClosureComment=str()) + pkgreq = db.create( + PackageRequest, + ReqTypeID=DELETION_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=f"Deletion request for {pkgbase.Name}", + ClosureComment=str(), + ) yield pkgreq @@ -166,31 +177,33 @@ def comment(user: User, package: Package) -> PackageComment: pkgbase = package.PackageBase now = time.utcnow() with db.begin(): - comment = db.create(PackageComment, - User=user, - PackageBase=pkgbase, - Comments="Test comment.", - RenderedComment=str(), - CommentTS=now) + comment = db.create( + PackageComment, + User=user, + PackageBase=pkgbase, + Comments="Test comment.", + RenderedComment=str(), + CommentTS=now, + ) yield comment @pytest.fixture def packages(maintainer: User) -> list[Package]: - """ Yield 55 packages named pkg_0 .. pkg_54. """ + """Yield 55 packages named pkg_0 .. pkg_54.""" packages_ = [] now = time.utcnow() with db.begin(): for i in range(55): - pkgbase = db.create(PackageBase, - Name=f"pkg_{i}", - Maintainer=maintainer, - Packager=maintainer, - Submitter=maintainer, - ModifiedTS=now) - package = db.create(Package, - PackageBase=pkgbase, - Name=f"pkg_{i}") + pkgbase = db.create( + PackageBase, + Name=f"pkg_{i}", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now, + ) + package = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}") packages_.append(package) yield packages_ @@ -203,40 +216,56 @@ def test_package_not_found(client: TestClient): def test_package(client: TestClient, package: Package): - """ Test a single / packages / {name} route. """ + """Test a single / packages / {name} route.""" with db.begin(): - db.create(PackageRelation, PackageID=package.ID, - RelTypeID=PROVIDES_ID, - RelName="test_provider1") - db.create(PackageRelation, PackageID=package.ID, - RelTypeID=PROVIDES_ID, - RelName="test_provider2") + db.create( + PackageRelation, + PackageID=package.ID, + RelTypeID=PROVIDES_ID, + RelName="test_provider1", + ) + db.create( + PackageRelation, + PackageID=package.ID, + RelTypeID=PROVIDES_ID, + RelName="test_provider2", + ) - db.create(PackageRelation, PackageID=package.ID, - RelTypeID=REPLACES_ID, - RelName="test_replacer1") - db.create(PackageRelation, PackageID=package.ID, - RelTypeID=REPLACES_ID, - RelName="test_replacer2") + db.create( + PackageRelation, + PackageID=package.ID, + RelTypeID=REPLACES_ID, + RelName="test_replacer1", + ) + db.create( + PackageRelation, + PackageID=package.ID, + RelTypeID=REPLACES_ID, + RelName="test_replacer2", + ) - db.create(PackageRelation, PackageID=package.ID, - RelTypeID=CONFLICTS_ID, - RelName="test_conflict1") - db.create(PackageRelation, PackageID=package.ID, - RelTypeID=CONFLICTS_ID, - RelName="test_conflict2") + db.create( + PackageRelation, + PackageID=package.ID, + RelTypeID=CONFLICTS_ID, + RelName="test_conflict1", + ) + db.create( + PackageRelation, + PackageID=package.ID, + RelTypeID=CONFLICTS_ID, + RelName="test_conflict2", + ) # Create some licenses. licenses = [ db.create(License, Name="test_license1"), - db.create(License, Name="test_license2") + db.create(License, Name="test_license2"), ] - db.create(PackageLicense, PackageID=package.ID, - License=licenses[0]) - db.create(PackageLicense, PackageID=package.ID, - License=licenses[1]) + db.create(PackageLicense, PackageID=package.ID, License=licenses[0]) + db.create(PackageLicense, PackageID=package.ID, License=licenses[1]) with client as request: resp = request.get(package_endpoint(package)) @@ -311,7 +340,7 @@ def paged_depends_required(client: TestClient, package: Package): params={ "all_deps": True, "all_reqs": True, - } + }, ) assert resp.status_code == int(HTTPStatus.OK) @@ -321,10 +350,15 @@ def paged_depends_required(client: TestClient, package: Package): def test_package_comments(client: TestClient, user: User, package: Package): - now = (time.utcnow()) + now = time.utcnow() with db.begin(): - comment = db.create(PackageComment, PackageBase=package.PackageBase, - User=user, Comments="Test comment", CommentTS=now) + comment = db.create( + PackageComment, + PackageBase=package.PackageBase, + User=user, + Comments="Test comment", + CommentTS=now, + ) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -332,17 +366,18 @@ def test_package_comments(client: TestClient, user: User, package: Package): assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) - expected = [ - comment.Comments - ] - comments = root.xpath('.//div[contains(@class, "package-comments")]' - '/div[@class="article-content"]/div/text()') + expected = [comment.Comments] + comments = root.xpath( + './/div[contains(@class, "package-comments")]' + '/div[@class="article-content"]/div/text()' + ) for i, row in enumerate(expected): assert comments[i].strip() == row -def test_package_requests_display(client: TestClient, user: User, - package: Package, pkgreq: PackageRequest): +def test_package_requests_display( + client: TestClient, user: User, package: Package, pkgreq: PackageRequest +): # Test that a single request displays "1 pending request". with client as request: resp = request.get(package_endpoint(package)) @@ -355,11 +390,15 @@ def test_package_requests_display(client: TestClient, user: User, type_ = db.query(RequestType, RequestType.ID == DELETION_ID).first() with db.begin(): - db.create(PackageRequest, PackageBase=package.PackageBase, - PackageBaseName=package.PackageBase.Name, - User=user, RequestType=type_, - Comments="Test comment2.", - ClosureComment=str()) + db.create( + PackageRequest, + PackageBase=package.PackageBase, + PackageBaseName=package.PackageBase.Name, + User=user, + RequestType=type_, + Comments="Test comment2.", + ClosureComment=str(), + ) # Test that a two requests display "2 pending requests". with client as request: @@ -372,11 +411,10 @@ def test_package_requests_display(client: TestClient, user: User, assert target.text.strip() == "2 pending requests" -def test_package_authenticated(client: TestClient, user: User, - package: Package): - """ We get the same here for either authenticated or not +def test_package_authenticated(client: TestClient, user: User, package: Package): + """We get the same here for either authenticated or not authenticated. Form inputs are presented to maintainers. - This process also occurs when pkgbase.html is rendered. """ + This process also occurs when pkgbase.html is rendered.""" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: resp = request.get(package_endpoint(package), cookies=cookies) @@ -390,7 +428,7 @@ def test_package_authenticated(client: TestClient, user: User, "Flag package out-of-date", "Vote for this package", "Enable notifications", - "Submit Request" + "Submit Request", ] for expected_text in expected: assert expected_text in resp.text @@ -402,9 +440,9 @@ def test_package_authenticated(client: TestClient, user: User, assert len(target) == 0 -def test_package_authenticated_maintainer(client: TestClient, - maintainer: User, - package: Package): +def test_package_authenticated_maintainer( + client: TestClient, maintainer: User, package: Package +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: resp = request.get(package_endpoint(package), cookies=cookies) @@ -420,15 +458,13 @@ def test_package_authenticated_maintainer(client: TestClient, "Enable notifications", "Manage Co-Maintainers", "Submit Request", - "Disown Package" + "Disown Package", ] for expected_text in expected: assert expected_text in resp.text -def test_package_authenticated_tu(client: TestClient, - tu_user: User, - package: Package): +def test_package_authenticated_tu(client: TestClient, tu_user: User, package: Package): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: resp = request.get(package_endpoint(package), cookies=cookies) @@ -446,14 +482,13 @@ def test_package_authenticated_tu(client: TestClient, "Submit Request", "Delete Package", "Merge Package", - "Disown Package" + "Disown Package", ] for expected_text in expected: assert expected_text in resp.text -def test_package_dependencies(client: TestClient, maintainer: User, - package: Package): +def test_package_dependencies(client: TestClient, maintainer: User, package: Package): # Create a normal dependency of type depends. with db.begin(): dep_pkg = create_package("test-dep-1", maintainer) @@ -461,32 +496,32 @@ def test_package_dependencies(client: TestClient, maintainer: User, # Also, create a makedepends. make_dep_pkg = create_package("test-dep-2", maintainer) - make_dep = create_package_dep(package, make_dep_pkg.Name, - dep_type_name="makedepends") + make_dep = create_package_dep( + package, make_dep_pkg.Name, dep_type_name="makedepends" + ) make_dep.DepArch = "x86_64" # And... a checkdepends! check_dep_pkg = create_package("test-dep-3", maintainer) - create_package_dep(package, check_dep_pkg.Name, - dep_type_name="checkdepends") + create_package_dep(package, check_dep_pkg.Name, dep_type_name="checkdepends") # Geez. Just stop. This is optdepends. opt_dep_pkg = create_package("test-dep-4", maintainer) - create_package_dep(package, opt_dep_pkg.Name, - dep_type_name="optdepends") + create_package_dep(package, opt_dep_pkg.Name, dep_type_name="optdepends") # Heh. Another optdepends to test one with a description. opt_desc_dep_pkg = create_package("test-dep-5", maintainer) - opt_desc_dep = create_package_dep(package, opt_desc_dep_pkg.Name, - dep_type_name="optdepends") + opt_desc_dep = create_package_dep( + package, opt_desc_dep_pkg.Name, dep_type_name="optdepends" + ) opt_desc_dep.DepDesc = "Test description." - broken_dep = create_package_dep(package, "test-dep-6", - dep_type_name="depends") + broken_dep = create_package_dep(package, "test-dep-6", dep_type_name="depends") # Create an official provider record. - db.create(OfficialProvider, Name="test-dep-99", - Repo="core", Provides="test-dep-99") + db.create( + OfficialProvider, Name="test-dep-99", Repo="core", Provides="test-dep-99" + ) create_package_dep(package, "test-dep-99") # Also, create a provider who provides our test-dep-99. @@ -498,13 +533,14 @@ def test_package_dependencies(client: TestClient, maintainer: User, assert resp.status_code == int(HTTPStatus.OK) # Let's make sure all the non-broken deps are ordered as we expect. - expected = list(filter( - lambda e: e.is_package(), - package.package_dependencies.order_by( - PackageDependency.DepTypeID.asc(), - PackageDependency.DepName.asc() - ).all() - )) + expected = list( + filter( + lambda e: e.is_package(), + package.package_dependencies.order_by( + PackageDependency.DepTypeID.asc(), PackageDependency.DepName.asc() + ).all(), + ) + ) root = parse_root(resp.text) pkgdeps = root.findall('.//ul[@id="pkgdepslist"]/li/a') for i, expectation in enumerate(expected): @@ -512,7 +548,7 @@ def test_package_dependencies(client: TestClient, maintainer: User, # Let's make sure the DepArch was displayed for our target make dep. arch = root.findall('.//ul[@id="pkgdepslist"]/li')[3] - arch = arch.xpath('./em')[0] + arch = arch.xpath("./em")[0] assert arch.text.strip() == "(make, x86_64)" # And let's make sure that the broken package was displayed. @@ -522,16 +558,19 @@ def test_package_dependencies(client: TestClient, maintainer: User, def test_packages(client: TestClient, packages: list[Package]): with client as request: - response = request.get("/packages", params={ - "SeB": "X", # "X" isn't valid, defaults to "nd" - "PP": "1 or 1", - "O": "0 or 0" - }) + response = request.get( + "/packages", + params={ + "SeB": "X", # "X" isn't valid, defaults to "nd" + "PP": "1 or 1", + "O": "0 or 0", + }, + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) stats = root.xpath('//div[@class="pkglist-stats"]/p')[0] - pager_text = re.sub(r'\s+', " ", stats.text.replace("\n", "").strip()) + pager_text = re.sub(r"\s+", " ", stats.text.replace("\n", "").strip()) assert pager_text == "55 packages found. Page 1 of 2." rows = root.xpath('//table[@class="results"]/tbody/tr') @@ -551,10 +590,7 @@ def test_packages_empty(client: TestClient): def test_packages_search_by_name(client: TestClient, packages: list[Package]): with client as request: - response = request.get("/packages", params={ - "SeB": "n", - "K": "pkg_" - }) + response = request.get("/packages", params={"SeB": "n", "K": "pkg_"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -563,13 +599,9 @@ def test_packages_search_by_name(client: TestClient, packages: list[Package]): assert len(rows) == 50 # Default per-page -def test_packages_search_by_exact_name(client: TestClient, - packages: list[Package]): +def test_packages_search_by_exact_name(client: TestClient, packages: list[Package]): with client as request: - response = request.get("/packages", params={ - "SeB": "N", - "K": "pkg_" - }) + response = request.get("/packages", params={"SeB": "N", "K": "pkg_"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -579,10 +611,7 @@ def test_packages_search_by_exact_name(client: TestClient, assert len(rows) == 0 with client as request: - response = request.get("/packages", params={ - "SeB": "N", - "K": "pkg_1" - }) + response = request.get("/packages", params={"SeB": "N", "K": "pkg_1"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -592,13 +621,9 @@ def test_packages_search_by_exact_name(client: TestClient, assert len(rows) == 1 -def test_packages_search_by_pkgbase(client: TestClient, - packages: list[Package]): +def test_packages_search_by_pkgbase(client: TestClient, packages: list[Package]): with client as request: - response = request.get("/packages", params={ - "SeB": "b", - "K": "pkg_" - }) + response = request.get("/packages", params={"SeB": "b", "K": "pkg_"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -607,13 +632,9 @@ def test_packages_search_by_pkgbase(client: TestClient, assert len(rows) == 50 -def test_packages_search_by_exact_pkgbase(client: TestClient, - packages: list[Package]): +def test_packages_search_by_exact_pkgbase(client: TestClient, packages: list[Package]): with client as request: - response = request.get("/packages", params={ - "SeB": "B", - "K": "pkg_" - }) + response = request.get("/packages", params={"SeB": "B", "K": "pkg_"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -621,10 +642,7 @@ def test_packages_search_by_exact_pkgbase(client: TestClient, assert len(rows) == 0 with client as request: - response = request.get("/packages", params={ - "SeB": "B", - "K": "pkg_1" - }) + response = request.get("/packages", params={"SeB": "B", "K": "pkg_1"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -632,14 +650,10 @@ def test_packages_search_by_exact_pkgbase(client: TestClient, assert len(rows) == 1 -def test_packages_search_by_keywords(client: TestClient, - packages: list[Package]): +def test_packages_search_by_keywords(client: TestClient, packages: list[Package]): # None of our packages have keywords, so this query should return nothing. with client as request: - response = request.get("/packages", params={ - "SeB": "k", - "K": "testKeyword" - }) + response = request.get("/packages", params={"SeB": "k", "K": "testKeyword"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -649,16 +663,13 @@ def test_packages_search_by_keywords(client: TestClient, # But now, let's create the keyword for the first package. package = packages[0] with db.begin(): - db.create(PackageKeyword, - PackageBase=package.PackageBase, - Keyword="testKeyword") + db.create( + PackageKeyword, PackageBase=package.PackageBase, Keyword="testKeyword" + ) # And request packages with that keyword, we should get 1 result. with client as request: - response = request.get("/packages", params={ - "SeB": "k", - "K": "testKeyword" - }) + response = request.get("/packages", params={"SeB": "k", "K": "testKeyword"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -666,16 +677,15 @@ def test_packages_search_by_keywords(client: TestClient, assert len(rows) == 1 -def test_packages_search_by_maintainer(client: TestClient, - maintainer: User, - package: Package): +def test_packages_search_by_maintainer( + client: TestClient, maintainer: User, package: Package +): # We should expect that searching by `package`'s maintainer # returns `package` in the results. with client as request: - response = request.get("/packages", params={ - "SeB": "m", - "K": maintainer.Username - }) + response = request.get( + "/packages", params={"SeB": "m", "K": maintainer.Username} + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') @@ -704,15 +714,14 @@ def test_packages_search_by_maintainer(client: TestClient, assert len(rows) == 1 -def test_packages_search_by_comaintainer(client: TestClient, - maintainer: User, - package: Package): +def test_packages_search_by_comaintainer( + client: TestClient, maintainer: User, package: Package +): # Nobody's a comaintainer yet. with client as request: - response = request.get("/packages", params={ - "SeB": "c", - "K": maintainer.Username - }) + response = request.get( + "/packages", params={"SeB": "c", "K": maintainer.Username} + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -721,17 +730,18 @@ def test_packages_search_by_comaintainer(client: TestClient, # Now, we create a comaintainer. with db.begin(): - db.create(PackageComaintainer, - PackageBase=package.PackageBase, - User=maintainer, - Priority=1) + db.create( + PackageComaintainer, + PackageBase=package.PackageBase, + User=maintainer, + Priority=1, + ) # Then test that it's returned by our search. with client as request: - response = request.get("/packages", params={ - "SeB": "c", - "K": maintainer.Username - }) + response = request.get( + "/packages", params={"SeB": "c", "K": maintainer.Username} + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -739,15 +749,18 @@ def test_packages_search_by_comaintainer(client: TestClient, assert len(rows) == 1 -def test_packages_search_by_co_or_maintainer(client: TestClient, - maintainer: User, - package: Package): +def test_packages_search_by_co_or_maintainer( + client: TestClient, maintainer: User, package: Package +): with client as request: - response = request.get("/packages", params={ - "SeB": "M", - "SB": "BLAH", # Invalid SB; gets reset to default "n". - "K": maintainer.Username - }) + response = request.get( + "/packages", + params={ + "SeB": "M", + "SB": "BLAH", # Invalid SB; gets reset to default "n". + "K": maintainer.Username, + }, + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -755,19 +768,18 @@ def test_packages_search_by_co_or_maintainer(client: TestClient, assert len(rows) == 1 with db.begin(): - user = db.create(User, Username="comaintainer", - Email="comaintainer@example.org", - Passwd="testPassword") - db.create(PackageComaintainer, - PackageBase=package.PackageBase, - User=user, - Priority=1) + user = db.create( + User, + Username="comaintainer", + Email="comaintainer@example.org", + Passwd="testPassword", + ) + db.create( + PackageComaintainer, PackageBase=package.PackageBase, User=user, Priority=1 + ) with client as request: - response = request.get("/packages", params={ - "SeB": "M", - "K": user.Username - }) + response = request.get("/packages", params={"SeB": "M", "K": user.Username}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -775,14 +787,13 @@ def test_packages_search_by_co_or_maintainer(client: TestClient, assert len(rows) == 1 -def test_packages_search_by_submitter(client: TestClient, - maintainer: User, - package: Package): +def test_packages_search_by_submitter( + client: TestClient, maintainer: User, package: Package +): with client as request: - response = request.get("/packages", params={ - "SeB": "s", - "K": maintainer.Username - }) + response = request.get( + "/packages", params={"SeB": "s", "K": maintainer.Username} + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -792,184 +803,184 @@ def test_packages_search_by_submitter(client: TestClient, def test_packages_sort_by_name(client: TestClient, packages: list[Package]): with client as request: - response = request.get("/packages", params={ - "SB": "n", # Name - "SO": "a", # Ascending - "PP": "150" - }) + response = request.get( + "/packages", params={"SB": "n", "SO": "a", "PP": "150"} # Name # Ascending + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - rows = [row.xpath('./td/a')[0].text.strip() for row in rows] + rows = [row.xpath("./td/a")[0].text.strip() for row in rows] with client as request: - response2 = request.get("/packages", params={ - "SB": "n", # Name - "SO": "d", # Ascending - "PP": "150" - }) + response2 = request.get( + "/packages", params={"SB": "n", "SO": "d", "PP": "150"} # Name # Ascending + ) assert response2.status_code == int(HTTPStatus.OK) root = parse_root(response2.text) rows2 = root.xpath('//table[@class="results"]/tbody/tr') - rows2 = [row.xpath('./td/a')[0].text.strip() for row in rows2] + rows2 = [row.xpath("./td/a")[0].text.strip() for row in rows2] assert rows == list(reversed(rows2)) -def test_packages_sort_by_votes(client: TestClient, - maintainer: User, - packages: list[Package]): +def test_packages_sort_by_votes( + client: TestClient, maintainer: User, packages: list[Package] +): # Set the first package's NumVotes to 1. with db.begin(): packages[0].PackageBase.NumVotes = 1 # Test that, by default, the first result is what we just set above. with client as request: - response = request.get("/packages", params={ - "SB": "v" # Votes. - }) + response = request.get("/packages", params={"SB": "v"}) # Votes. assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - votes = rows[0].xpath('./td')[2] # The third column of the first row. + votes = rows[0].xpath("./td")[2] # The third column of the first row. assert votes.text.strip() == "1" # Now, test that with an ascending order, the last result is # the one we set, since the default (above) is descending. with client as request: - response = request.get("/packages", params={ - "SB": "v", # Votes. - "SO": "a", # Ascending. - "O": "50" # Second page. - }) + response = request.get( + "/packages", + params={ + "SB": "v", # Votes. + "SO": "a", # Ascending. + "O": "50", # Second page. + }, + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - votes = rows[-1].xpath('./td')[2] # The third column of the last row. + votes = rows[-1].xpath("./td")[2] # The third column of the last row. assert votes.text.strip() == "1" -def test_packages_sort_by_popularity(client: TestClient, - maintainer: User, - packages: list[Package]): +def test_packages_sort_by_popularity( + client: TestClient, maintainer: User, packages: list[Package] +): # Set the first package's Popularity to 0.50. with db.begin(): packages[0].PackageBase.Popularity = "0.50" # Test that, by default, the first result is what we just set above. with client as request: - response = request.get("/packages", params={ - "SB": "p" # Popularity - }) + response = request.get("/packages", params={"SB": "p"}) # Popularity assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - pop = rows[0].xpath('./td')[3] # The fourth column of the first row. + pop = rows[0].xpath("./td")[3] # The fourth column of the first row. assert pop.text.strip() == "0.50" -def test_packages_sort_by_voted(client: TestClient, - maintainer: User, - packages: list[Package]): +def test_packages_sort_by_voted( + client: TestClient, maintainer: User, packages: list[Package] +): now = time.utcnow() with db.begin(): - db.create(PackageVote, PackageBase=packages[0].PackageBase, - User=maintainer, VoteTS=now) + db.create( + PackageVote, + PackageBase=packages[0].PackageBase, + User=maintainer, + VoteTS=now, + ) # Test that, by default, the first result is what we just set above. cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - response = request.get("/packages", params={ - "SB": "w", # Voted - "SO": "d" # Descending, Voted first. - }, cookies=cookies) + response = request.get( + "/packages", + params={"SB": "w", "SO": "d"}, # Voted # Descending, Voted first. + cookies=cookies, + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - voted = rows[0].xpath('./td')[5] # The sixth column of the first row. + voted = rows[0].xpath("./td")[5] # The sixth column of the first row. assert voted.text.strip() == "Yes" # Conversely, everything else was not voted on. - voted = rows[1].xpath('./td')[5] # The sixth column of the second row. + voted = rows[1].xpath("./td")[5] # The sixth column of the second row. assert voted.text.strip() == str() # Empty. -def test_packages_sort_by_notify(client: TestClient, - maintainer: User, - packages: list[Package]): - db.create(PackageNotification, - PackageBase=packages[0].PackageBase, - User=maintainer) +def test_packages_sort_by_notify( + client: TestClient, maintainer: User, packages: list[Package] +): + db.create(PackageNotification, PackageBase=packages[0].PackageBase, User=maintainer) # Test that, by default, the first result is what we just set above. cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - response = request.get("/packages", params={ - "SB": "o", # Voted - "SO": "d" # Descending, Voted first. - }, cookies=cookies) + response = request.get( + "/packages", + params={"SB": "o", "SO": "d"}, # Voted # Descending, Voted first. + cookies=cookies, + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - notify = rows[0].xpath('./td')[6] # The sixth column of the first row. + notify = rows[0].xpath("./td")[6] # The sixth column of the first row. assert notify.text.strip() == "Yes" # Conversely, everything else was not voted on. - notify = rows[1].xpath('./td')[6] # The sixth column of the second row. + notify = rows[1].xpath("./td")[6] # The sixth column of the second row. assert notify.text.strip() == str() # Empty. -def test_packages_sort_by_maintainer(client: TestClient, - maintainer: User, - package: Package): - """ Sort a package search by the maintainer column. """ +def test_packages_sort_by_maintainer( + client: TestClient, maintainer: User, package: Package +): + """Sort a package search by the maintainer column.""" # Create a second package, so the two can be ordered and checked. with db.begin(): - maintainer2 = db.create(User, Username="maintainer2", - Email="maintainer2@example.org", - Passwd="testPassword") - base2 = db.create(PackageBase, Name="pkg_2", Maintainer=maintainer2, - Submitter=maintainer2, Packager=maintainer2) + maintainer2 = db.create( + User, + Username="maintainer2", + Email="maintainer2@example.org", + Passwd="testPassword", + ) + base2 = db.create( + PackageBase, + Name="pkg_2", + Maintainer=maintainer2, + Submitter=maintainer2, + Packager=maintainer2, + ) db.create(Package, Name="pkg_2", PackageBase=base2) # Check the descending order route. with client as request: - response = request.get("/packages", params={ - "SB": "m", - "SO": "d" - }) + response = request.get("/packages", params={"SB": "m", "SO": "d"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - col = rows[0].xpath('./td')[5].xpath('./a')[0] # Last column. + col = rows[0].xpath("./td")[5].xpath("./a")[0] # Last column. assert col.text.strip() == maintainer.Username # On the other hand, with ascending, we should get reverse ordering. with client as request: - response = request.get("/packages", params={ - "SB": "m", - "SO": "a" - }) + response = request.get("/packages", params={"SB": "m", "SO": "a"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - col = rows[0].xpath('./td')[5].xpath('./a')[0] # Last column. + col = rows[0].xpath("./td")[5].xpath("./a")[0] # Last column. assert col.text.strip() == maintainer2.Username -def test_packages_sort_by_last_modified(client: TestClient, - packages: list[Package]): +def test_packages_sort_by_last_modified(client: TestClient, packages: list[Package]): now = time.utcnow() # Set the first package's ModifiedTS to be 1000 seconds before now. package = packages[0] @@ -977,10 +988,10 @@ def test_packages_sort_by_last_modified(client: TestClient, package.PackageBase.ModifiedTS = now - 1000 with client as request: - response = request.get("/packages", params={ - "SB": "l", - "SO": "a" # Ascending; oldest modification first. - }) + response = request.get( + "/packages", + params={"SB": "l", "SO": "a"}, # Ascending; oldest modification first. + ) assert response.status_code == int(HTTPStatus.OK) # We should have 50 (default per page) results. @@ -990,12 +1001,13 @@ def test_packages_sort_by_last_modified(client: TestClient, # Let's assert that the first item returned was the one we modified above. row = rows[0] - col = row.xpath('./td')[0].xpath('./a')[0] + col = row.xpath("./td")[0].xpath("./a")[0] assert col.text.strip() == package.Name -def test_packages_flagged(client: TestClient, maintainer: User, - packages: list[Package]): +def test_packages_flagged( + client: TestClient, maintainer: User, packages: list[Package] +): package = packages[0] now = time.utcnow() @@ -1005,9 +1017,7 @@ def test_packages_flagged(client: TestClient, maintainer: User, package.PackageBase.Flagger = maintainer with client as request: - response = request.get("/packages", params={ - "outdated": "on" - }) + response = request.get("/packages", params={"outdated": "on"}) assert response.status_code == int(HTTPStatus.OK) # We should only get one result from this query; the package we flagged. @@ -1016,9 +1026,7 @@ def test_packages_flagged(client: TestClient, maintainer: User, assert len(rows) == 1 with client as request: - response = request.get("/packages", params={ - "outdated": "off" - }) + response = request.get("/packages", params={"outdated": "off"}) assert response.status_code == int(HTTPStatus.OK) # In this case, we should get 54 results, which means that the first @@ -1044,14 +1052,17 @@ def test_packages_orphans(client: TestClient, packages: list[Package]): def test_packages_per_page(client: TestClient, maintainer: User): - """ Test the ability for /packages to deal with the PP query - argument specifications (50, 100, 250; default: 50). """ + """Test the ability for /packages to deal with the PP query + argument specifications (50, 100, 250; default: 50).""" with db.begin(): for i in range(255): - base = db.create(PackageBase, Name=f"pkg_{i}", - Maintainer=maintainer, - Submitter=maintainer, - Packager=maintainer) + base = db.create( + PackageBase, + Name=f"pkg_{i}", + Maintainer=maintainer, + Submitter=maintainer, + Packager=maintainer, + ) db.create(Package, PackageBase=base, Name=base.Name) # Test default case, PP of 50. @@ -1079,18 +1090,20 @@ def test_packages_per_page(client: TestClient, maintainer: User): assert len(rows) == 250 -def test_packages_post_unknown_action(client: TestClient, user: User, - package: Package): +def test_packages_post_unknown_action(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "unknown"}, - cookies=cookies, allow_redirects=False) + resp = request.post( + "/packages", + data={"action": "unknown"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) def test_packages_post_error(client: TestClient, user: User, package: Package): - async def stub_action(request: Request, **kwargs): return (False, ["Some error."]) @@ -1098,8 +1111,12 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "stub"}, - cookies=cookies, allow_redirects=False) + resp = request.post( + "/packages", + data={"action": "stub"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1108,7 +1125,6 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): def test_packages_post(client: TestClient, user: User, package: Package): - async def stub_action(request: Request, **kwargs): return (True, ["Some success."]) @@ -1116,8 +1132,12 @@ def test_packages_post(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "stub"}, - cookies=cookies, allow_redirects=False) + resp = request.post( + "/packages", + data={"action": "stub"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.OK) errors = get_successes(resp.text) @@ -1125,8 +1145,9 @@ def test_packages_post(client: TestClient, user: User, package: Package): assert errors[0].text.strip() == expected -def test_packages_post_unflag(client: TestClient, user: User, - maintainer: User, package: Package): +def test_packages_post_unflag( + client: TestClient, user: User, maintainer: User, package: Package +): # Flag `package` as `user`. now = time.utcnow() with db.begin(): @@ -1181,8 +1202,7 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package): # an error to be rendered. cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "notify"}, - cookies=cookies) + resp = request.post("/packages", data={"action": "notify"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to be notified about." @@ -1190,10 +1210,9 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package): # Now let's actually enable notifications on `package`. with client as request: - resp = request.post("/packages", data={ - "action": "notify", - "IDs": [package.ID] - }, cookies=cookies) + resp = request.post( + "/packages", data={"action": "notify", "IDs": [package.ID]}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.OK) expected = "The selected packages' notifications have been enabled." successes = get_successes(resp.text) @@ -1202,31 +1221,27 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package): # Try to enable notifications when they're already enabled, # causing an error to be rendered. with client as request: - resp = request.post("/packages", data={ - "action": "notify", - "IDs": [package.ID] - }, cookies=cookies) + resp = request.post( + "/packages", data={"action": "notify", "IDs": [package.ID]}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to be notified about." assert errors[0].text.strip() == expected -def test_packages_post_unnotify(client: TestClient, user: User, - package: Package): +def test_packages_post_unnotify(client: TestClient, user: User, package: Package): # Create a notification record. with db.begin(): - notif = db.create(PackageNotification, - PackageBase=package.PackageBase, - User=user) + notif = db.create( + PackageNotification, PackageBase=package.PackageBase, User=user + ) assert notif is not None # Request removal of the notification without any IDs. cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={ - "action": "unnotify" - }, cookies=cookies) + resp = request.post("/packages", data={"action": "unnotify"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages for notification removal." @@ -1234,10 +1249,11 @@ def test_packages_post_unnotify(client: TestClient, user: User, # Request removal of the notification; really. with client as request: - resp = request.post("/packages", data={ - "action": "unnotify", - "IDs": [package.ID] - }, cookies=cookies) + resp = request.post( + "/packages", + data={"action": "unnotify", "IDs": [package.ID]}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.OK) successes = get_successes(resp.text) expected = "The selected packages' notifications have been removed." @@ -1251,25 +1267,23 @@ def test_packages_post_unnotify(client: TestClient, user: User, # Try it again. The notif no longer exists. with client as request: - resp = request.post("/packages", data={ - "action": "unnotify", - "IDs": [package.ID] - }, cookies=cookies) + resp = request.post( + "/packages", + data={"action": "unnotify", "IDs": [package.ID]}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "A package you selected does not have notifications enabled." assert errors[0].text.strip() == expected -def test_packages_post_adopt(client: TestClient, user: User, - package: Package): +def test_packages_post_adopt(client: TestClient, user: User, package: Package): # Try to adopt an empty list of packages. cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={ - "action": "adopt" - }, cookies=cookies) + resp = request.post("/packages", data={"action": "adopt"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to adopt." @@ -1277,11 +1291,11 @@ def test_packages_post_adopt(client: TestClient, user: User, # Now, let's try to adopt a package that's already maintained. with client as request: - resp = request.post("/packages", data={ - "action": "adopt", - "IDs": [package.ID], - "confirm": True - }, cookies=cookies) + resp = request.post( + "/packages", + data={"action": "adopt", "IDs": [package.ID], "confirm": True}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You are not allowed to adopt one of the packages you selected." @@ -1294,33 +1308,34 @@ def test_packages_post_adopt(client: TestClient, user: User, # Now, let's try to adopt without confirming. with client as request: - resp = request.post("/packages", data={ - "action": "adopt", - "IDs": [package.ID] - }, cookies=cookies) + resp = request.post( + "/packages", data={"action": "adopt", "IDs": [package.ID]}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) - expected = ("The selected packages have not been adopted, " - "check the confirmation checkbox.") + expected = ( + "The selected packages have not been adopted, " + "check the confirmation checkbox." + ) assert errors[0].text.strip() == expected # Let's do it again now that there is no maintainer. with client as request: - resp = request.post("/packages", data={ - "action": "adopt", - "IDs": [package.ID], - "confirm": True - }, cookies=cookies) + resp = request.post( + "/packages", + data={"action": "adopt", "IDs": [package.ID], "confirm": True}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.OK) successes = get_successes(resp.text) expected = "The selected packages have been adopted." assert successes[0].text.strip() == expected -def test_packages_post_disown_as_maintainer(client: TestClient, user: User, - maintainer: User, - package: Package): - """ Disown packages as a maintainer. """ +def test_packages_post_disown_as_maintainer( + client: TestClient, user: User, maintainer: User, package: Package +): + """Disown packages as a maintainer.""" # Initially prove that we have a maintainer. assert package.PackageBase.Maintainer is not None assert package.PackageBase.Maintainer == maintainer @@ -1328,9 +1343,7 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User, # Try to run the disown action with no IDs; get an error. cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={ - "action": "disown" - }, cookies=cookies) + resp = request.post("/packages", data={"action": "disown"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to disown." @@ -1339,25 +1352,26 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User, # Try to disown `package` without giving the confirm argument. with client as request: - resp = request.post("/packages", data={ - "action": "disown", - "IDs": [package.ID] - }, cookies=cookies) + resp = request.post( + "/packages", data={"action": "disown", "IDs": [package.ID]}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) assert package.PackageBase.Maintainer is not None errors = get_errors(resp.text) - expected = ("The selected packages have not been disowned, " - "check the confirmation checkbox.") + expected = ( + "The selected packages have not been disowned, " + "check the confirmation checkbox." + ) assert errors[0].text.strip() == expected # Now, try to disown `package` without credentials (as `user`). user_cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={ - "action": "disown", - "IDs": [package.ID], - "confirm": True - }, cookies=user_cookies) + resp = request.post( + "/packages", + data={"action": "disown", "IDs": [package.ID], "confirm": True}, + cookies=user_cookies, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) assert package.PackageBase.Maintainer is not None errors = get_errors(resp.text) @@ -1366,11 +1380,11 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User, # Now, let's really disown `package` as `maintainer`. with client as request: - resp = request.post("/packages", data={ - "action": "disown", - "IDs": [package.ID], - "confirm": True - }, cookies=cookies) + resp = request.post( + "/packages", + data={"action": "disown", "IDs": [package.ID], "confirm": True}, + cookies=cookies, + ) assert package.PackageBase.Maintainer is None successes = get_successes(resp.text) @@ -1378,30 +1392,36 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User, assert successes[0].text.strip() == expected -def test_packages_post_disown(client: TestClient, tu_user: User, - maintainer: User, package: Package): - """ Disown packages as a Trusted User, which cannot bypass idle time. """ +def test_packages_post_disown( + client: TestClient, tu_user: User, maintainer: User, package: Package +): + """Disown packages as a Trusted User, which cannot bypass idle time.""" cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={ - "action": "disown", - "IDs": [package.ID], - "confirm": True - }, cookies=cookies) + resp = request.post( + "/packages", + data={"action": "disown", "IDs": [package.ID], "confirm": True}, + cookies=cookies, + ) errors = get_errors(resp.text) expected = r"^No due existing orphan requests to accept for .+\.$" assert re.match(expected, errors[0].text.strip()) -def test_packages_post_delete(caplog: pytest.fixture, client: TestClient, - user: User, tu_user: User, package: Package): +def test_packages_post_delete( + caplog: pytest.fixture, + client: TestClient, + user: User, + tu_user: User, + package: Package, +): # First, let's try to use the delete action with no packages IDs. user_cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={ - "action": "delete" - }, cookies=user_cookies) + resp = request.post( + "/packages", data={"action": "delete"}, cookies=user_cookies + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to delete." @@ -1409,23 +1429,26 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient, # Now, let's try to delete real packages without supplying "confirm". with client as request: - resp = request.post("/packages", data={ - "action": "delete", - "IDs": [package.ID] - }, cookies=user_cookies) + resp = request.post( + "/packages", + data={"action": "delete", "IDs": [package.ID]}, + cookies=user_cookies, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) - expected = ("The selected packages have not been deleted, " - "check the confirmation checkbox.") + expected = ( + "The selected packages have not been deleted, " + "check the confirmation checkbox." + ) assert errors[0].text.strip() == expected # And again, with everything, but `user` doesn't have permissions. with client as request: - resp = request.post("/packages", data={ - "action": "delete", - "IDs": [package.ID], - "confirm": True - }, cookies=user_cookies) + resp = request.post( + "/packages", + data={"action": "delete", "IDs": [package.ID], "confirm": True}, + cookies=user_cookies, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You do not have permission to delete packages." @@ -1436,11 +1459,11 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient, # an invalid package ID. tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={ - "action": "delete", - "IDs": [0], - "confirm": True - }, cookies=tu_cookies) + resp = request.post( + "/packages", + data={"action": "delete", "IDs": [0], "confirm": True}, + cookies=tu_cookies, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "One of the packages you selected does not exist." @@ -1449,11 +1472,11 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient, # Whoo. Now, let's finally make a valid request as `tu_user` # to delete `package`. with client as request: - resp = request.post("/packages", data={ - "action": "delete", - "IDs": [package.ID], - "confirm": True - }, cookies=tu_cookies) + resp = request.post( + "/packages", + data={"action": "delete", "IDs": [package.ID], "confirm": True}, + cookies=tu_cookies, + ) assert resp.status_code == int(HTTPStatus.OK) successes = get_successes(resp.text) expected = "The selected packages have been deleted." @@ -1461,15 +1484,17 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient, # Expect that the package deletion was logged. pkgbases = [package.PackageBase.Name] - expected = (f"Privileged user '{tu_user.Username}' deleted the " - f"following package bases: {str(pkgbases)}.") + expected = ( + f"Privileged user '{tu_user.Username}' deleted the " + f"following package bases: {str(pkgbases)}." + ) assert expected in caplog.text def test_account_comments_unauthorized(client: TestClient, user: User): - """ This test may seem out of place, but it requires packages, + """This test may seem out of place, but it requires packages, so its being included in the packages routes test suite to - leverage existing fixtures. """ + leverage existing fixtures.""" endpoint = f"/account/{user.Username}/comments" with client as request: resp = request.get(endpoint, allow_redirects=False) @@ -1478,22 +1503,28 @@ def test_account_comments_unauthorized(client: TestClient, user: User): def test_account_comments(client: TestClient, user: User, package: Package): - """ This test may seem out of place, but it requires packages, + """This test may seem out of place, but it requires packages, so its being included in the packages routes test suite to - leverage existing fixtures. """ + leverage existing fixtures.""" now = time.utcnow() with db.begin(): # This comment's CommentTS is `now + 1`, so it is found in rendered # HTML before the rendered_comment, which has a CommentTS of `now`. - comment = db.create(PackageComment, - PackageBase=package.PackageBase, - User=user, Comments="Test comment", - CommentTS=now + 1) - rendered_comment = db.create(PackageComment, - PackageBase=package.PackageBase, - User=user, Comments="Test comment", - RenderedComment="

      Test comment

      ", - CommentTS=now) + comment = db.create( + PackageComment, + PackageBase=package.PackageBase, + User=user, + Comments="Test comment", + CommentTS=now + 1, + ) + rendered_comment = db.create( + PackageComment, + PackageBase=package.PackageBase, + User=user, + Comments="Test comment", + RenderedComment="

      Test comment

      ", + CommentTS=now, + ) cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/account/{user.Username}/comments" @@ -1508,7 +1539,6 @@ def test_account_comments(client: TestClient, user: User, package: Package): assert comments[0].text.strip() == comment.Comments # And from the second, we have rendered content. - rendered = comments[1].xpath('./p') - expected = rendered_comment.RenderedComment.replace( - "

      ", "").replace("

      ", "") + rendered = comments[1].xpath("./p") + expected = rendered_comment.RenderedComment.replace("

      ", "").replace("

      ", "") assert rendered[0].text.strip() == expected diff --git a/test/test_packages_util.py b/test/test_packages_util.py index 02f84601..0042cd71 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -1,5 +1,4 @@ import pytest - from fastapi.testclient import TestClient from aurweb import asgi, config, db, time @@ -23,18 +22,22 @@ def setup(db_test): @pytest.fixture def maintainer() -> User: with db.begin(): - maintainer = db.create(User, Username="test_maintainer", - Email="test_maintainer@examepl.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + maintainer = db.create( + User, + Username="test_maintainer", + Email="test_maintainer@examepl.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield maintainer @pytest.fixture def package(maintainer: User) -> Package: with db.begin(): - pkgbase = db.create(PackageBase, Name="test-pkg", - Packager=maintainer, Maintainer=maintainer) + pkgbase = db.create( + PackageBase, Name="test-pkg", Packager=maintainer, Maintainer=maintainer + ) package = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) yield package @@ -51,10 +54,9 @@ def test_package_link(client: TestClient, package: Package): def test_official_package_link(client: TestClient, package: Package): with db.begin(): - provider = db.create(OfficialProvider, - Name=package.Name, - Repo="core", - Provides=package.Name) + provider = db.create( + OfficialProvider, Name=package.Name, Repo="core", Provides=package.Name + ) expected = f"{OFFICIAL_BASE}/packages/?q={package.Name}" assert util.package_link(provider) == expected @@ -63,9 +65,7 @@ def test_updated_packages(maintainer: User, package: Package): expected = { "Name": package.Name, "Version": package.Version, - "PackageBase": { - "ModifiedTS": package.PackageBase.ModifiedTS - } + "PackageBase": {"ModifiedTS": package.PackageBase.ModifiedTS}, } kill_redis() # Kill it here to ensure we're on a fake instance. @@ -77,8 +77,9 @@ def test_updated_packages(maintainer: User, package: Package): def test_query_voted(maintainer: User, package: Package): now = time.utcnow() with db.begin(): - db.create(PackageVote, User=maintainer, VoteTS=now, - PackageBase=package.PackageBase) + db.create( + PackageVote, User=maintainer, VoteTS=now, PackageBase=package.PackageBase + ) query = db.query(Package).filter(Package.ID == package.ID).all() query_voted = util.query_voted(query, maintainer) @@ -87,8 +88,7 @@ def test_query_voted(maintainer: User, package: Package): def test_query_notified(maintainer: User, package: Package): with db.begin(): - db.create(PackageNotification, User=maintainer, - PackageBase=package.PackageBase) + db.create(PackageNotification, User=maintainer, PackageBase=package.PackageBase) query = db.query(Package).filter(Package.ID == package.ID).all() query_notified = util.query_notified(query, maintainer) @@ -99,8 +99,9 @@ def test_source_uri_file(package: Package): FILE = "test_file" with db.begin(): - pkgsrc = db.create(PackageSource, Source=FILE, - Package=package, SourceArch="x86_64") + pkgsrc = db.create( + PackageSource, Source=FILE, Package=package, SourceArch="x86_64" + ) source_file_uri = config.get("options", "source_file_uri") file, uri = util.source_uri(pkgsrc) expected = source_file_uri % (pkgsrc.Source, package.PackageBase.Name) @@ -112,8 +113,9 @@ def test_source_uri_named_uri(package: Package): URL = "https://test.xyz" with db.begin(): - pkgsrc = db.create(PackageSource, Source=f"{FILE}::{URL}", - Package=package, SourceArch="x86_64") + pkgsrc = db.create( + PackageSource, Source=f"{FILE}::{URL}", Package=package, SourceArch="x86_64" + ) file, uri = util.source_uri(pkgsrc) assert (file, uri) == (FILE, URL) @@ -122,7 +124,8 @@ def test_source_uri_unnamed_uri(package: Package): URL = "https://test.xyz" with db.begin(): - pkgsrc = db.create(PackageSource, Source=f"{URL}", - Package=package, SourceArch="x86_64") + pkgsrc = db.create( + PackageSource, Source=f"{URL}", Package=package, SourceArch="x86_64" + ) file, uri = util.source_uri(pkgsrc) assert (file, uri) == (URL, URL) diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index 52241b9e..bfdb0c37 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -1,10 +1,8 @@ import re - from http import HTTPStatus from unittest import mock import pytest - from fastapi.testclient import TestClient from sqlalchemy import and_ @@ -33,30 +31,24 @@ def package_endpoint(package: Package) -> str: def create_package(pkgname: str, maintainer: User) -> Package: - pkgbase = db.create(PackageBase, - Name=pkgname, - Maintainer=maintainer) + pkgbase = db.create(PackageBase, Name=pkgname, Maintainer=maintainer) return db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) -def create_package_dep(package: Package, depname: str, - dep_type_name: str = "depends") -> PackageDependency: - dep_type = db.query(DependencyType, - DependencyType.Name == dep_type_name).first() - return db.create(PackageDependency, - DependencyType=dep_type, - Package=package, - DepName=depname) +def create_package_dep( + package: Package, depname: str, dep_type_name: str = "depends" +) -> PackageDependency: + dep_type = db.query(DependencyType, DependencyType.Name == dep_type_name).first() + return db.create( + PackageDependency, DependencyType=dep_type, Package=package, DepName=depname + ) -def create_package_rel(package: Package, - relname: str) -> PackageRelation: - rel_type = db.query(RelationType, - RelationType.ID == PROVIDES_ID).first() - return db.create(PackageRelation, - RelationType=rel_type, - Package=package, - RelName=relname) +def create_package_rel(package: Package, relname: str) -> PackageRelation: + rel_type = db.query(RelationType, RelationType.ID == PROVIDES_ID).first() + return db.create( + PackageRelation, RelationType=rel_type, Package=package, RelName=relname + ) @pytest.fixture(autouse=True) @@ -66,76 +58,88 @@ def setup(db_test): @pytest.fixture def client() -> TestClient: - """ Yield a FastAPI TestClient. """ + """Yield a FastAPI TestClient.""" yield TestClient(app=asgi.app) def create_user(username: str) -> User: with db.begin(): - user = db.create(User, Username=username, - Email=f"{username}@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username=username, + Email=f"{username}@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) return user @pytest.fixture def user() -> User: - """ Yield a user. """ + """Yield a user.""" user = create_user("test") yield user @pytest.fixture def maintainer() -> User: - """ Yield a specific User used to maintain packages. """ + """Yield a specific User used to maintain packages.""" account_type = db.query(AccountType, AccountType.ID == USER_ID).first() with db.begin(): - maintainer = db.create(User, Username="test_maintainer", - Email="test_maintainer@example.org", - Passwd="testPassword", - AccountType=account_type) + maintainer = db.create( + User, + Username="test_maintainer", + Email="test_maintainer@example.org", + Passwd="testPassword", + AccountType=account_type, + ) yield maintainer @pytest.fixture def comaintainer() -> User: - """ Yield a specific User used to maintain packages. """ + """Yield a specific User used to maintain packages.""" account_type = db.query(AccountType, AccountType.ID == USER_ID).first() with db.begin(): - comaintainer = db.create(User, Username="test_comaintainer", - Email="test_comaintainer@example.org", - Passwd="testPassword", - AccountType=account_type) + comaintainer = db.create( + User, + Username="test_comaintainer", + Email="test_comaintainer@example.org", + Passwd="testPassword", + AccountType=account_type, + ) yield comaintainer @pytest.fixture def tu_user(): - tu_type = db.query(AccountType, - AccountType.AccountType == "Trusted User").first() + tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first() with db.begin(): - tu_user = db.create(User, Username="test_tu", - Email="test_tu@example.org", - RealName="Test TU", Passwd="testPassword", - AccountType=tu_type) + tu_user = db.create( + User, + Username="test_tu", + Email="test_tu@example.org", + RealName="Test TU", + Passwd="testPassword", + AccountType=tu_type, + ) yield tu_user @pytest.fixture def package(maintainer: User) -> Package: - """ Yield a Package created by user. """ + """Yield a Package created by user.""" now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, - Name="test-package", - Maintainer=maintainer, - Packager=maintainer, - Submitter=maintainer, - ModifiedTS=now) - package = db.create(Package, - PackageBase=pkgbase, - Name=pkgbase.Name) + pkgbase = db.create( + PackageBase, + Name="test-package", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now, + ) + package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) yield package @@ -146,29 +150,34 @@ def pkgbase(package: Package) -> PackageBase: @pytest.fixture def target(maintainer: User) -> PackageBase: - """ Merge target. """ + """Merge target.""" now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, Name="target-package", - Maintainer=maintainer, - Packager=maintainer, - Submitter=maintainer, - ModifiedTS=now) + pkgbase = db.create( + PackageBase, + Name="target-package", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now, + ) db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) yield pkgbase @pytest.fixture def pkgreq(user: User, pkgbase: PackageBase) -> PackageRequest: - """ Yield a PackageRequest related to `pkgbase`. """ + """Yield a PackageRequest related to `pkgbase`.""" with db.begin(): - pkgreq = db.create(PackageRequest, - ReqTypeID=DELETION_ID, - User=user, - PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - Comments=f"Deletion request for {pkgbase.Name}", - ClosureComment=str()) + pkgreq = db.create( + PackageRequest, + ReqTypeID=DELETION_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=f"Deletion request for {pkgbase.Name}", + ClosureComment=str(), + ) yield pkgreq @@ -177,31 +186,33 @@ def comment(user: User, package: Package) -> PackageComment: pkgbase = package.PackageBase now = time.utcnow() with db.begin(): - comment = db.create(PackageComment, - User=user, - PackageBase=pkgbase, - Comments="Test comment.", - RenderedComment=str(), - CommentTS=now) + comment = db.create( + PackageComment, + User=user, + PackageBase=pkgbase, + Comments="Test comment.", + RenderedComment=str(), + CommentTS=now, + ) yield comment @pytest.fixture def packages(maintainer: User) -> list[Package]: - """ Yield 55 packages named pkg_0 .. pkg_54. """ + """Yield 55 packages named pkg_0 .. pkg_54.""" packages_ = [] now = time.utcnow() with db.begin(): for i in range(55): - pkgbase = db.create(PackageBase, - Name=f"pkg_{i}", - Maintainer=maintainer, - Packager=maintainer, - Submitter=maintainer, - ModifiedTS=now) - package = db.create(Package, - PackageBase=pkgbase, - Name=f"pkg_{i}") + pkgbase = db.create( + PackageBase, + Name=f"pkg_{i}", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now, + ) + package = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}") packages_.append(package) yield packages_ @@ -210,18 +221,18 @@ def packages(maintainer: User) -> list[Package]: @pytest.fixture def requests(user: User, packages: list[Package]) -> list[PackageRequest]: pkgreqs = [] - deletion_type = db.query(RequestType).filter( - RequestType.ID == DELETION_ID - ).first() + deletion_type = db.query(RequestType).filter(RequestType.ID == DELETION_ID).first() with db.begin(): for i in range(55): - pkgreq = db.create(PackageRequest, - RequestType=deletion_type, - User=user, - PackageBase=packages[i].PackageBase, - PackageBaseName=packages[i].Name, - Comments=f"Deletion request for pkg_{i}", - ClosureComment=str()) + pkgreq = db.create( + PackageRequest, + RequestType=deletion_type, + User=user, + PackageBase=packages[i].PackageBase, + PackageBaseName=packages[i].Name, + Comments=f"Deletion request for pkg_{i}", + ClosureComment=str(), + ) pkgreqs.append(pkgreq) yield pkgreqs @@ -234,21 +245,18 @@ def test_pkgbase_not_found(client: TestClient): def test_pkgbase_redirect(client: TestClient, package: Package): with client as request: - resp = request.get(f"/pkgbase/{package.Name}", - allow_redirects=False) + resp = request.get(f"/pkgbase/{package.Name}", allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/packages/{package.Name}" def test_pkgbase(client: TestClient, package: Package): with db.begin(): - second = db.create(Package, Name="second-pkg", - PackageBase=package.PackageBase) + second = db.create(Package, Name="second-pkg", PackageBase=package.PackageBase) expected = [package.Name, second.Name] with client as request: - resp = request.get(f"/pkgbase/{package.Name}", - allow_redirects=False) + resp = request.get(f"/pkgbase/{package.Name}", allow_redirects=False) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -264,8 +272,9 @@ def test_pkgbase(client: TestClient, package: Package): assert pkgs[i].text.strip() == name -def test_pkgbase_maintainer(client: TestClient, user: User, maintainer: User, - package: Package): +def test_pkgbase_maintainer( + client: TestClient, user: User, maintainer: User, package: Package +): """ Test that the Maintainer field is beind displayed correctly. @@ -273,9 +282,9 @@ def test_pkgbase_maintainer(client: TestClient, user: User, maintainer: User, the maintainer. """ with db.begin(): - db.create(PackageComaintainer, User=user, - PackageBase=package.PackageBase, - Priority=1) + db.create( + PackageComaintainer, User=user, PackageBase=package.PackageBase, Priority=1 + ) with client as request: resp = request.get(f"/pkgbase/{package.Name}") @@ -286,7 +295,7 @@ def test_pkgbase_maintainer(client: TestClient, user: User, maintainer: User, maint = root.xpath('//table[@id="pkginfo"]/tr[@class="pkgmaint"]/td')[0] maint, comaint = maint.text.strip().split() assert maint == maintainer.Username - assert comaint == f'({user.Username})' + assert comaint == f"({user.Username})" def test_pkgbase_voters(client: TestClient, tu_user: User, package: Package): @@ -309,8 +318,7 @@ def test_pkgbase_voters(client: TestClient, tu_user: User, package: Package): assert rows[0].text.strip() == tu_user.Username -def test_pkgbase_voters_unauthorized(client: TestClient, user: User, - package: Package): +def test_pkgbase_voters_unauthorized(client: TestClient, user: User, package: Package): pkgbase = package.PackageBase endpoint = f"/pkgbase/{pkgbase.Name}/voters" @@ -324,25 +332,30 @@ def test_pkgbase_voters_unauthorized(client: TestClient, user: User, assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" -def test_pkgbase_comment_not_found(client: TestClient, maintainer: User, - package: Package): +def test_pkgbase_comment_not_found( + client: TestClient, maintainer: User, package: Package +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} comment_id = 12345 # A non-existing comment. endpoint = f"/pkgbase/{package.PackageBase.Name}/comments/{comment_id}" with client as request: - resp = request.post(endpoint, data={ - "comment": "Failure" - }, cookies=cookies) + resp = request.post(endpoint, data={"comment": "Failure"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.NOT_FOUND) -def test_pkgbase_comment_form_unauthorized(client: TestClient, user: User, - maintainer: User, package: Package): +def test_pkgbase_comment_form_unauthorized( + client: TestClient, user: User, maintainer: User, package: Package +): now = time.utcnow() with db.begin(): - comment = db.create(PackageComment, PackageBase=package.PackageBase, - User=maintainer, Comments="Test", - RenderedComment=str(), CommentTS=now) + comment = db.create( + PackageComment, + PackageBase=package.PackageBase, + User=maintainer, + Comments="Test", + RenderedComment=str(), + CommentTS=now, + ) cookies = {"AURSID": user.login(Request(), "testPassword")} pkgbasename = package.PackageBase.Name @@ -352,8 +365,9 @@ def test_pkgbase_comment_form_unauthorized(client: TestClient, user: User, assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) -def test_pkgbase_comment_form_not_found(client: TestClient, maintainer: User, - package: Package): +def test_pkgbase_comment_form_not_found( + client: TestClient, maintainer: User, package: Package +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} comment_id = 12345 # A non-existing comment. pkgbasename = package.PackageBase.Name @@ -363,8 +377,9 @@ def test_pkgbase_comment_form_not_found(client: TestClient, maintainer: User, assert resp.status_code == int(HTTPStatus.NOT_FOUND) -def test_pkgbase_comments_missing_comment(client: TestClient, maintainer: User, - package: Package): +def test_pkgbase_comments_missing_comment( + client: TestClient, maintainer: User, package: Package +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/comments" with client as request: @@ -372,9 +387,10 @@ def test_pkgbase_comments_missing_comment(client: TestClient, maintainer: User, assert resp.status_code == int(HTTPStatus.BAD_REQUEST) -def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, - package: Package): - """ This test includes tests against the following routes: +def test_pkgbase_comments( + client: TestClient, maintainer: User, user: User, package: Package +): + """This test includes tests against the following routes: - POST /pkgbase/{name}/comments - GET /pkgbase/{name} (to check comments) - Tested against a comment created with the POST route @@ -383,18 +399,17 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, """ with db.begin(): user.CommentNotify = 1 - db.create(PackageNotification, - PackageBase=package.PackageBase, - User=user) + db.create(PackageNotification, PackageBase=package.PackageBase, User=user) cookies = {"AURSID": maintainer.login(Request(), "testPassword")} pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments" with client as request: - resp = request.post(endpoint, data={ - "comment": "Test comment.", - "enable_notifications": True - }, cookies=cookies) + resp = request.post( + endpoint, + data={"comment": "Test comment.", "enable_notifications": True}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # user should've gotten a CommentNotification email. @@ -438,10 +453,11 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, comment_id = int(headers[0].attrib["id"].split("-")[-1]) endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}" with client as request: - resp = request.post(endpoint, data={ - "comment": "Edited comment.", - "enable_notifications": True - }, cookies=cookies) + resp = request.post( + endpoint, + data={"comment": "Edited comment.", "enable_notifications": True}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) with client as request: @@ -479,27 +495,33 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User, assert "form" in data -def test_pkgbase_comment_edit_unauthorized(client: TestClient, - user: User, - maintainer: User, - package: Package, - comment: PackageComment): +def test_pkgbase_comment_edit_unauthorized( + client: TestClient, + user: User, + maintainer: User, + package: Package, + comment: PackageComment, +): pkgbase = package.PackageBase cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: endp = f"/pkgbase/{pkgbase.Name}/comments/{comment.ID}" - response = request.post(endp, data={ - "comment": "abcd im trying to change this comment." - }, cookies=cookies) + response = request.post( + endp, + data={"comment": "abcd im trying to change this comment."}, + cookies=cookies, + ) assert response.status_code == HTTPStatus.UNAUTHORIZED -def test_pkgbase_comment_delete(client: TestClient, - maintainer: User, - user: User, - package: Package, - comment: PackageComment): +def test_pkgbase_comment_delete( + client: TestClient, + maintainer: User, + user: User, + package: Package, + comment: PackageComment, +): # Test the unauthorized case of comment deletion. cookies = {"AURSID": user.login(Request(), "testPassword")} pkgbasename = package.PackageBase.Name @@ -524,10 +546,9 @@ def test_pkgbase_comment_delete(client: TestClient, assert resp.status_code == int(HTTPStatus.SEE_OTHER) -def test_pkgbase_comment_delete_unauthorized(client: TestClient, - maintainer: User, - package: Package, - comment: PackageComment): +def test_pkgbase_comment_delete_unauthorized( + client: TestClient, maintainer: User, package: Package, comment: PackageComment +): # Test the unauthorized case of comment deletion. cookies = {"AURSID": maintainer.login(Request(), "testPassword")} pkgbasename = package.PackageBase.Name @@ -537,9 +558,9 @@ def test_pkgbase_comment_delete_unauthorized(client: TestClient, assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) -def test_pkgbase_comment_delete_not_found(client: TestClient, - maintainer: User, - package: Package): +def test_pkgbase_comment_delete_not_found( + client: TestClient, maintainer: User, package: Package +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} comment_id = 12345 # Non-existing comment. pkgbasename = package.PackageBase.Name @@ -549,9 +570,9 @@ def test_pkgbase_comment_delete_not_found(client: TestClient, assert resp.status_code == int(HTTPStatus.NOT_FOUND) -def test_pkgbase_comment_undelete_not_found(client: TestClient, - maintainer: User, - package: Package): +def test_pkgbase_comment_undelete_not_found( + client: TestClient, maintainer: User, package: Package +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} comment_id = 12345 # Non-existing comment. pkgbasename = package.PackageBase.Name @@ -561,13 +582,18 @@ def test_pkgbase_comment_undelete_not_found(client: TestClient, assert resp.status_code == int(HTTPStatus.NOT_FOUND) -def test_pkgbase_comment_pin_as_co(client: TestClient, package: Package, - comment: PackageComment): +def test_pkgbase_comment_pin_as_co( + client: TestClient, package: Package, comment: PackageComment +): comaint = create_user("comaint1") with db.begin(): - db.create(PackageComaintainer, PackageBase=package.PackageBase, - User=comaint, Priority=1) + db.create( + PackageComaintainer, + PackageBase=package.PackageBase, + User=comaint, + Priority=1, + ) # Pin the comment. pkgbasename = package.PackageBase.Name @@ -590,10 +616,9 @@ def test_pkgbase_comment_pin_as_co(client: TestClient, package: Package, assert comment.PinnedTS == 0 -def test_pkgbase_comment_pin(client: TestClient, - maintainer: User, - package: Package, - comment: PackageComment): +def test_pkgbase_comment_pin( + client: TestClient, maintainer: User, package: Package, comment: PackageComment +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} comment_id = comment.ID pkgbasename = package.PackageBase.Name @@ -617,10 +642,9 @@ def test_pkgbase_comment_pin(client: TestClient, assert comment.PinnedTS == 0 -def test_pkgbase_comment_pin_unauthorized(client: TestClient, - user: User, - package: Package, - comment: PackageComment): +def test_pkgbase_comment_pin_unauthorized( + client: TestClient, user: User, package: Package, comment: PackageComment +): cookies = {"AURSID": user.login(Request(), "testPassword")} comment_id = comment.ID pkgbasename = package.PackageBase.Name @@ -630,10 +654,9 @@ def test_pkgbase_comment_pin_unauthorized(client: TestClient, assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) -def test_pkgbase_comment_unpin_unauthorized(client: TestClient, - user: User, - package: Package, - comment: PackageComment): +def test_pkgbase_comment_unpin_unauthorized( + client: TestClient, user: User, package: Package, comment: PackageComment +): cookies = {"AURSID": user.login(Request(), "testPassword")} comment_id = comment.ID pkgbasename = package.PackageBase.Name @@ -651,8 +674,7 @@ def test_pkgbase_comaintainers_not_found(client: TestClient, maintainer: User): assert resp.status_code == int(HTTPStatus.NOT_FOUND) -def test_pkgbase_comaintainers_post_not_found(client: TestClient, - maintainer: User): +def test_pkgbase_comaintainers_post_not_found(client: TestClient, maintainer: User): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = "/pkgbase/fake/comaintainers" with client as request: @@ -660,8 +682,9 @@ def test_pkgbase_comaintainers_post_not_found(client: TestClient, assert resp.status_code == int(HTTPStatus.NOT_FOUND) -def test_pkgbase_comaintainers_unauthorized(client: TestClient, user: User, - package: Package): +def test_pkgbase_comaintainers_unauthorized( + client: TestClient, user: User, package: Package +): pkgbase = package.PackageBase endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": user.login(Request(), "testPassword")} @@ -671,9 +694,9 @@ def test_pkgbase_comaintainers_unauthorized(client: TestClient, user: User, assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" -def test_pkgbase_comaintainers_post_unauthorized(client: TestClient, - user: User, - package: Package): +def test_pkgbase_comaintainers_post_unauthorized( + client: TestClient, user: User, package: Package +): pkgbase = package.PackageBase endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": user.login(Request(), "testPassword")} @@ -683,16 +706,16 @@ def test_pkgbase_comaintainers_post_unauthorized(client: TestClient, assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" -def test_pkgbase_comaintainers_post_invalid_user(client: TestClient, - maintainer: User, - package: Package): +def test_pkgbase_comaintainers_post_invalid_user( + client: TestClient, maintainer: User, package: Package +): pkgbase = package.PackageBase endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, data={ - "users": "\nfake\n" - }, cookies=cookies, allow_redirects=False) + resp = request.post( + endpoint, data={"users": "\nfake\n"}, cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -700,8 +723,9 @@ def test_pkgbase_comaintainers_post_invalid_user(client: TestClient, assert error.text.strip() == "Invalid user name: fake" -def test_pkgbase_comaintainers(client: TestClient, user: User, - maintainer: User, package: Package): +def test_pkgbase_comaintainers( + client: TestClient, user: User, maintainer: User, package: Package +): pkgbase = package.PackageBase endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": maintainer.login(Request(), "testPassword")} @@ -709,17 +733,23 @@ def test_pkgbase_comaintainers(client: TestClient, user: User, # Start off by adding user as a comaintainer to package. # The maintainer username given should be ignored. with client as request: - resp = request.post(endpoint, data={ - "users": f"\n{user.Username}\n{maintainer.Username}\n" - }, cookies=cookies, allow_redirects=False) + resp = request.post( + endpoint, + data={"users": f"\n{user.Username}\n{maintainer.Username}\n"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" # Do it again to exercise the last_priority bump path. with client as request: - resp = request.post(endpoint, data={ - "users": f"\n{user.Username}\n{maintainer.Username}\n" - }, cookies=cookies, allow_redirects=False) + resp = request.post( + endpoint, + data={"users": f"\n{user.Username}\n{maintainer.Username}\n"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -736,9 +766,9 @@ def test_pkgbase_comaintainers(client: TestClient, user: User, # Finish off by removing all the comaintainers. with client as request: - resp = request.post(endpoint, data={ - "users": str() - }, cookies=cookies, allow_redirects=False) + resp = request.post( + endpoint, data={"users": str()}, cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -774,15 +804,15 @@ def test_pkgbase_request(client: TestClient, user: User, package: Package): def test_pkgbase_request_post_not_found(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/pkgbase/fake/request", data={ - "type": "fake" - }, cookies=cookies) + resp = request.post( + "/pkgbase/fake/request", data={"type": "fake"}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.NOT_FOUND) -def test_pkgbase_request_post_invalid_type(client: TestClient, - user: User, - package: Package): +def test_pkgbase_request_post_invalid_type( + client: TestClient, user: User, package: Package +): endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -790,16 +820,20 @@ def test_pkgbase_request_post_invalid_type(client: TestClient, assert resp.status_code == int(HTTPStatus.BAD_REQUEST) -def test_pkgbase_request_post_no_comment_error(client: TestClient, - user: User, - package: Package): +def test_pkgbase_request_post_no_comment_error( + client: TestClient, user: User, package: Package +): endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, data={ - "type": "deletion", - "comments": "" # An empty comment field causes an error. - }, cookies=cookies) + resp = request.post( + endpoint, + data={ + "type": "deletion", + "comments": "", # An empty comment field causes an error. + }, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -808,17 +842,22 @@ def test_pkgbase_request_post_no_comment_error(client: TestClient, assert error.text.strip() == expected -def test_pkgbase_request_post_merge_not_found_error(client: TestClient, - user: User, - package: Package): +def test_pkgbase_request_post_merge_not_found_error( + client: TestClient, user: User, package: Package +): endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, data={ - "type": "merge", - "merge_into": "fake", # There is no PackageBase.Name "fake" - "comments": "We want to merge this." - }, cookies=cookies, allow_redirects=False) + resp = request.post( + endpoint, + data={ + "type": "merge", + "merge_into": "fake", # There is no PackageBase.Name "fake" + "comments": "We want to merge this.", + }, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -827,17 +866,22 @@ def test_pkgbase_request_post_merge_not_found_error(client: TestClient, assert error.text.strip() == expected -def test_pkgbase_request_post_merge_no_merge_into_error(client: TestClient, - user: User, - package: Package): +def test_pkgbase_request_post_merge_no_merge_into_error( + client: TestClient, user: User, package: Package +): endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, data={ - "type": "merge", - "merge_into": "", # There is no PackageBase.Name "fake" - "comments": "We want to merge this." - }, cookies=cookies, allow_redirects=False) + resp = request.post( + endpoint, + data={ + "type": "merge", + "merge_into": "", # There is no PackageBase.Name "fake" + "comments": "We want to merge this.", + }, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -846,16 +890,22 @@ def test_pkgbase_request_post_merge_no_merge_into_error(client: TestClient, assert error.text.strip() == expected -def test_pkgbase_request_post_merge_self_error(client: TestClient, user: User, - package: Package): +def test_pkgbase_request_post_merge_self_error( + client: TestClient, user: User, package: Package +): endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, data={ - "type": "merge", - "merge_into": package.PackageBase.Name, - "comments": "We want to merge this." - }, cookies=cookies, allow_redirects=False) + resp = request.post( + endpoint, + data={ + "type": "merge", + "merge_into": package.PackageBase.Name, + "comments": "We want to merge this.", + }, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -864,8 +914,9 @@ def test_pkgbase_request_post_merge_self_error(client: TestClient, user: User, assert error.text.strip() == expected -def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, - package: Package): +def test_pkgbase_flag( + client: TestClient, user: User, maintainer: User, package: Package +): pkgbase = package.PackageBase # We shouldn't have flagged the package yet; assert so. @@ -882,8 +933,9 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, # Now, let's check the /pkgbase/{name}/flag-comment route. flag_comment_endpoint = f"/pkgbase/{pkgbase.Name}/flag-comment" with client as request: - resp = request.get(flag_comment_endpoint, cookies=cookies, - allow_redirects=False) + resp = request.get( + flag_comment_endpoint, cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -894,9 +946,7 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, # Flag it with a valid comment. with client as request: - resp = request.post(endpoint, data={ - "comments": "Test" - }, cookies=cookies) + resp = request.post(endpoint, data={"comments": "Test"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger == user assert pkgbase.FlaggerComment == "Test" @@ -907,8 +957,9 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, # Now, let's check the /pkgbase/{name}/flag-comment route. flag_comment_endpoint = f"/pkgbase/{pkgbase.Name}/flag-comment" with client as request: - resp = request.get(flag_comment_endpoint, cookies=cookies, - allow_redirects=False) + resp = request.get( + flag_comment_endpoint, cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.OK) # Now try to perform a get; we should be redirected because @@ -918,10 +969,13 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, assert resp.status_code == int(HTTPStatus.SEE_OTHER) with db.begin(): - user2 = db.create(User, Username="test2", - Email="test2@example.org", - Passwd="testPassword", - AccountType=user.AccountType) + user2 = db.create( + User, + Username="test2", + Email="test2@example.org", + Passwd="testPassword", + AccountType=user.AccountType, + ) # Now, test that the 'user2' user can't unflag it, because they # didn't flag it to begin with. @@ -941,9 +995,9 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User, # Flag it again. with client as request: - resp = request.post(f"/pkgbase/{pkgbase.Name}/flag", data={ - "comments": "Test" - }, cookies=cookies) + resp = request.post( + f"/pkgbase/{pkgbase.Name}/flag", data={"comments": "Test"}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Now, unflag it for real. @@ -961,16 +1015,17 @@ def test_pkgbase_flag_vcs(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(f"/pkgbase/{package.PackageBase.Name}/flag", - cookies=cookies) + resp = request.get(f"/pkgbase/{package.PackageBase.Name}/flag", cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) - expected = ("This seems to be a VCS package. Please do " - "not flag it out-of-date if the package " - "version in the AUR does not match the most recent commit. " - "Flagging this package should only be done if the sources " - "moved or changes in the PKGBUILD are required because of " - "recent upstream changes.") + expected = ( + "This seems to be a VCS package. Please do " + "not flag it out-of-date if the package " + "version in the AUR does not match the most recent commit. " + "Flagging this package should only be done if the sources " + "moved or changes in the PKGBUILD are required because of " + "recent upstream changes." + ) assert expected in resp.text @@ -978,9 +1033,7 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package): pkgbase = package.PackageBase # We have no notif record yet; assert that. - notif = pkgbase.notifications.filter( - PackageNotification.UserID == user.ID - ).first() + notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first() assert notif is None # Enable notifications. @@ -990,9 +1043,7 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package): resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) - notif = pkgbase.notifications.filter( - PackageNotification.UserID == user.ID - ).first() + notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first() assert notif is not None # Disable notifications. @@ -1001,9 +1052,7 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package): resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) - notif = pkgbase.notifications.filter( - PackageNotification.UserID == user.ID - ).first() + notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first() assert notif is None @@ -1036,9 +1085,9 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package): assert pkgbase.NumVotes == 0 -def test_pkgbase_disown_as_sole_maintainer(client: TestClient, - maintainer: User, - package: Package): +def test_pkgbase_disown_as_sole_maintainer( + client: TestClient, maintainer: User, package: Package +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} pkgbase = package.PackageBase endpoint = f"/pkgbase/{pkgbase.Name}/disown" @@ -1049,26 +1098,23 @@ def test_pkgbase_disown_as_sole_maintainer(client: TestClient, assert resp.status_code == int(HTTPStatus.SEE_OTHER) -def test_pkgbase_disown_as_maint_with_comaint(client: TestClient, - user: User, - maintainer: User, - package: Package): - """ When disowning as a maintainer, the lowest priority comaintainer - is promoted to maintainer. """ +def test_pkgbase_disown_as_maint_with_comaint( + client: TestClient, user: User, maintainer: User, package: Package +): + """When disowning as a maintainer, the lowest priority comaintainer + is promoted to maintainer.""" pkgbase = package.PackageBase endp = f"/pkgbase/{pkgbase.Name}/disown" post_data = {"confirm": True} with db.begin(): - db.create(PackageComaintainer, - PackageBase=pkgbase, - User=user, - Priority=1) + db.create(PackageComaintainer, PackageBase=pkgbase, User=user, Priority=1) maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post(endp, data=post_data, cookies=maint_cookies, - allow_redirects=True) + resp = request.post( + endp, data=post_data, cookies=maint_cookies, allow_redirects=True + ) assert resp.status_code == int(HTTPStatus.OK) package = db.refresh(package) @@ -1078,8 +1124,13 @@ def test_pkgbase_disown_as_maint_with_comaint(client: TestClient, assert pkgbase.comaintainers.count() == 0 -def test_pkgbase_disown(client: TestClient, user: User, maintainer: User, - comaintainer: User, package: Package): +def test_pkgbase_disown( + client: TestClient, + user: User, + maintainer: User, + comaintainer: User, + package: Package, +): maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} comaint_cookies = {"AURSID": comaintainer.login(Request(), "testPassword")} user_cookies = {"AURSID": user.login(Request(), "testPassword")} @@ -1088,21 +1139,18 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User, endpoint = f"{pkgbase_endp}/disown" with db.begin(): - db.create(PackageComaintainer, - User=comaintainer, - PackageBase=pkgbase, - Priority=1) + db.create( + PackageComaintainer, User=comaintainer, PackageBase=pkgbase, Priority=1 + ) # GET as a normal user, which is rejected for lack of credentials. with client as request: - resp = request.get(endpoint, cookies=user_cookies, - allow_redirects=False) + resp = request.get(endpoint, cookies=user_cookies, allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # GET as a comaintainer. with client as request: - resp = request.get(endpoint, cookies=comaint_cookies, - allow_redirects=False) + resp = request.get(endpoint, cookies=comaint_cookies, allow_redirects=False) assert resp.status_code == int(HTTPStatus.OK) # Ensure that the comaintainer can see "Disown Package" link @@ -1146,8 +1194,9 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User, assert resp.status_code == int(HTTPStatus.SEE_OTHER) -def test_pkgbase_adopt(client: TestClient, user: User, tu_user: User, - maintainer: User, package: Package): +def test_pkgbase_adopt( + client: TestClient, user: User, tu_user: User, maintainer: User, package: Package +): # Unset the maintainer as if package is orphaned. with db.begin(): package.PackageBase.Maintainer = None @@ -1165,22 +1214,19 @@ def test_pkgbase_adopt(client: TestClient, user: User, tu_user: User, # Try to adopt it when it already has a maintainer; nothing changes. user_cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=user_cookies, - allow_redirects=False) + resp = request.post(endpoint, cookies=user_cookies, allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == maintainer # Steal the package as a TU. tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=tu_cookies, - allow_redirects=False) + resp = request.post(endpoint, cookies=tu_cookies, allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == tu_user -def test_pkgbase_delete_unauthorized(client: TestClient, user: User, - package: Package): +def test_pkgbase_delete_unauthorized(client: TestClient, user: User, package: Package): pkgbase = package.PackageBase cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/delete" @@ -1219,9 +1265,7 @@ def test_pkgbase_delete(client: TestClient, tu_user: User, package: Package): assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Let's assert that the package base record got removed. - record = db.query(PackageBase).filter( - PackageBase.Name == pkgbase.Name - ).first() + record = db.query(PackageBase).filter(PackageBase.Name == pkgbase.Name).first() assert record is None # Two emails should've been sent out; an autogenerated @@ -1234,9 +1278,9 @@ def test_pkgbase_delete(client: TestClient, tu_user: User, package: Package): assert re.match(expr, subject) -def test_pkgbase_delete_with_request(client: TestClient, tu_user: User, - pkgbase: PackageBase, - pkgreq: PackageRequest): +def test_pkgbase_delete_with_request( + client: TestClient, tu_user: User, pkgbase: PackageBase, pkgreq: PackageRequest +): # TODO: Test that a previously existing request gets Accepted when # a TU deleted the package. @@ -1257,12 +1301,15 @@ def test_pkgbase_delete_with_request(client: TestClient, tu_user: User, assert re.match(expr, email.headers.get("Subject")) -def test_packages_post_unknown_action(client: TestClient, user: User, - package: Package): +def test_packages_post_unknown_action(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "unknown"}, - cookies=cookies, allow_redirects=False) + resp = request.post( + "/packages", + data={"action": "unknown"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1274,8 +1321,12 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "stub"}, - cookies=cookies, allow_redirects=False) + resp = request.post( + "/packages", + data={"action": "stub"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1291,8 +1342,12 @@ def test_packages_post(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "stub"}, - cookies=cookies, allow_redirects=False) + resp = request.post( + "/packages", + data={"action": "stub"}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.OK) errors = get_successes(resp.text) @@ -1300,8 +1355,7 @@ def test_packages_post(client: TestClient, user: User, package: Package): assert errors[0].text.strip() == expected -def test_pkgbase_merge_unauthorized(client: TestClient, user: User, - package: Package): +def test_pkgbase_merge_unauthorized(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: @@ -1318,8 +1372,9 @@ def test_pkgbase_merge(client: TestClient, tu_user: User, package: Package): assert not get_errors(resp.text) -def test_pkgbase_merge_post_unauthorized(client: TestClient, user: User, - package: Package): +def test_pkgbase_merge_post_unauthorized( + client: TestClient, user: User, package: Package +): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: @@ -1327,54 +1382,62 @@ def test_pkgbase_merge_post_unauthorized(client: TestClient, user: User, assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) -def test_pkgbase_merge_post_unconfirmed(client: TestClient, tu_user: User, - package: Package): +def test_pkgbase_merge_post_unconfirmed( + client: TestClient, tu_user: User, package: Package +): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) - expected = ("The selected packages have not been deleted, " - "check the confirmation checkbox.") + expected = ( + "The selected packages have not been deleted, " + "check the confirmation checkbox." + ) assert errors[0].text.strip() == expected -def test_pkgbase_merge_post_invalid_into(client: TestClient, tu_user: User, - package: Package): +def test_pkgbase_merge_post_invalid_into( + client: TestClient, tu_user: User, package: Package +): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.post(endpoint, data={ - "into": "not_real", - "confirm": True - }, cookies=cookies) + resp = request.post( + endpoint, data={"into": "not_real", "confirm": True}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "Cannot find package to merge votes and comments into." assert errors[0].text.strip() == expected -def test_pkgbase_merge_post_self_invalid(client: TestClient, tu_user: User, - package: Package): +def test_pkgbase_merge_post_self_invalid( + client: TestClient, tu_user: User, package: Package +): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.post(endpoint, data={ - "into": package.PackageBase.Name, - "confirm": True - }, cookies=cookies) + resp = request.post( + endpoint, + data={"into": package.PackageBase.Name, "confirm": True}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "Cannot merge a package base with itself." assert errors[0].text.strip() == expected -def test_pkgbase_merge_post(client: TestClient, tu_user: User, - package: Package, - pkgbase: PackageBase, - target: PackageBase, - pkgreq: PackageRequest): +def test_pkgbase_merge_post( + client: TestClient, + tu_user: User, + package: Package, + pkgbase: PackageBase, + target: PackageBase, + pkgreq: PackageRequest, +): pkgname = package.Name pkgbasename = pkgbase.Name @@ -1401,9 +1464,9 @@ def test_pkgbase_merge_post(client: TestClient, tu_user: User, # Comment on the package. endpoint = f"/pkgbase/{package.PackageBase.Name}/comments" with client as request: - resp = request.post(endpoint, data={ - "comment": "Test comment." - }, cookies=cookies) + resp = request.post( + endpoint, data={"comment": "Test comment."}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Save these relationships for later comparison. @@ -1414,10 +1477,9 @@ def test_pkgbase_merge_post(client: TestClient, tu_user: User, # Merge the package into target. endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.post(endpoint, data={ - "into": target.Name, - "confirm": True - }, cookies=cookies) + resp = request.post( + endpoint, data={"into": target.Name, "confirm": True}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) loc = resp.headers.get("location") assert loc == f"/pkgbase/{target.Name}" @@ -1442,11 +1504,17 @@ def test_pkgbase_merge_post(client: TestClient, tu_user: User, assert pkgreq.Closer is not None # A PackageRequest is always created when merging this way. - pkgreq = db.query(PackageRequest).filter( - and_(PackageRequest.ReqTypeID == MERGE_ID, - PackageRequest.PackageBaseName == pkgbasename, - PackageRequest.MergeBaseName == target.Name) - ).first() + pkgreq = ( + db.query(PackageRequest) + .filter( + and_( + PackageRequest.ReqTypeID == MERGE_ID, + PackageRequest.PackageBaseName == pkgbasename, + PackageRequest.MergeBaseName == target.Name, + ) + ) + .first() + ) assert pkgreq is not None @@ -1464,9 +1532,9 @@ def test_pkgbase_keywords(client: TestClient, user: User, package: Package): cookies = {"AURSID": maint.login(Request(), "testPassword")} post_endpoint = f"{endpoint}/keywords" with client as request: - resp = request.post(post_endpoint, data={ - "keywords": "abc test" - }, cookies=cookies) + resp = request.post( + post_endpoint, data={"keywords": "abc test"}, cookies=cookies + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) with client as request: @@ -1495,9 +1563,11 @@ def test_pkgbase_empty_keywords(client: TestClient, user: User, package: Package cookies = {"AURSID": maint.login(Request(), "testPassword")} post_endpoint = f"{endpoint}/keywords" with client as request: - resp = request.post(post_endpoint, data={ - "keywords": "abc test foo bar " - }, cookies=cookies) + resp = request.post( + post_endpoint, + data={"keywords": "abc test foo bar "}, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) with client as request: @@ -1514,8 +1584,9 @@ def test_pkgbase_empty_keywords(client: TestClient, user: User, package: Package def test_unauthorized_pkgbase_keywords(client: TestClient, package: Package): with db.begin(): - user = db.create(User, Username="random_user", Email="random_user", - Passwd="testPassword") + user = db.create( + User, Username="random_user", Email="random_user", Passwd="testPassword" + ) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -1525,20 +1596,25 @@ def test_unauthorized_pkgbase_keywords(client: TestClient, package: Package): assert response.status_code == HTTPStatus.UNAUTHORIZED -def test_independent_user_unflag(client: TestClient, user: User, - package: Package): +def test_independent_user_unflag(client: TestClient, user: User, package: Package): with db.begin(): - flagger = db.create(User, Username="test_flagger", - Email="test_flagger@example.com", - Passwd="testPassword") + flagger = db.create( + User, + Username="test_flagger", + Email="test_flagger@example.com", + Passwd="testPassword", + ) pkgbase = package.PackageBase cookies = {"AURSID": flagger.login(Request(), "testPassword")} with client as request: endp = f"/pkgbase/{pkgbase.Name}/flag" - response = request.post(endp, data={ - "comments": "This thing needs a flag!" - }, cookies=cookies, allow_redirects=True) + response = request.post( + endp, + data={"comments": "This thing needs a flag!"}, + cookies=cookies, + allow_redirects=True, + ) assert response.status_code == HTTPStatus.OK # At this point, we've flagged it as `flagger`. diff --git a/test/test_pkgmaint.py b/test/test_pkgmaint.py index da758c22..a0fece78 100644 --- a/test/test_pkgmaint.py +++ b/test/test_pkgmaint.py @@ -14,8 +14,13 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @@ -26,11 +31,12 @@ def packages(user: User) -> list[Package]: now = time.utcnow() with db.begin(): for i in range(5): - pkgbase = db.create(PackageBase, Name=f"pkg_{i}", - SubmittedTS=now, - ModifiedTS=now) - pkg = db.create(Package, PackageBase=pkgbase, - Name=f"pkg_{i}", Version=f"{i}.0") + pkgbase = db.create( + PackageBase, Name=f"pkg_{i}", SubmittedTS=now, ModifiedTS=now + ) + pkg = db.create( + Package, PackageBase=pkgbase, Name=f"pkg_{i}", Version=f"{i}.0" + ) output.append(pkg) yield output @@ -48,7 +54,7 @@ def test_pkgmaint(packages: list[Package]): # Modify the first package so it's out of date and gets deleted. with db.begin(): # Reduce SubmittedTS by a day + 10 seconds. - packages[0].PackageBase.SubmittedTS -= (86400 + 10) + packages[0].PackageBase.SubmittedTS -= 86400 + 10 # Run pkgmaint. pkgmaint.main() diff --git a/test/test_ratelimit.py b/test/test_ratelimit.py index 859adea9..20528847 100644 --- a/test/test_ratelimit.py +++ b/test/test_ratelimit.py @@ -1,7 +1,6 @@ from unittest import mock import pytest - from redis.client import Pipeline from aurweb import config, db, logging @@ -49,6 +48,7 @@ def mock_config_getboolean(return_value: int = 0): if section == "ratelimit" and key == "cache": return return_value return config_getboolean(section, key) + return fn @@ -60,17 +60,22 @@ def mock_config_get(return_value: str = "none"): if section == "options" and key == "cache": return return_value return config_get(section, key) + return fn @mock.patch("aurweb.config.getint", side_effect=mock_config_getint) @mock.patch("aurweb.config.getboolean", side_effect=mock_config_getboolean(1)) @mock.patch("aurweb.config.get", side_effect=mock_config_get("none")) -def test_ratelimit_redis(get: mock.MagicMock, getboolean: mock.MagicMock, - getint: mock.MagicMock, pipeline: Pipeline): - """ This test will only cover aurweb.ratelimit's Redis +def test_ratelimit_redis( + get: mock.MagicMock, + getboolean: mock.MagicMock, + getint: mock.MagicMock, + pipeline: Pipeline, +): + """This test will only cover aurweb.ratelimit's Redis path if a real Redis server is configured. Otherwise, - it'll use the database. """ + it'll use the database.""" # We'll need a Request for everything here. request = Request() @@ -96,8 +101,12 @@ def test_ratelimit_redis(get: mock.MagicMock, getboolean: mock.MagicMock, @mock.patch("aurweb.config.getint", side_effect=mock_config_getint) @mock.patch("aurweb.config.getboolean", side_effect=mock_config_getboolean(0)) @mock.patch("aurweb.config.get", side_effect=mock_config_get("none")) -def test_ratelimit_db(get: mock.MagicMock, getboolean: mock.MagicMock, - getint: mock.MagicMock, pipeline: Pipeline): +def test_ratelimit_db( + get: mock.MagicMock, + getboolean: mock.MagicMock, + getint: mock.MagicMock, + pipeline: Pipeline, +): # We'll need a Request for everything here. request = Request() diff --git a/test/test_redis.py b/test/test_redis.py index 82aebb57..a66cd204 100644 --- a/test/test_redis.py +++ b/test/test_redis.py @@ -3,13 +3,13 @@ from unittest import mock import pytest import aurweb.config - from aurweb.redis import redis_connection @pytest.fixture def rediss(): - """ Create a RedisStub. """ + """Create a RedisStub.""" + def mock_get(section, key): return "none" diff --git a/test/test_rendercomment.py b/test/test_rendercomment.py index bf4009fd..5b7ff5ac 100644 --- a/test/test_rendercomment.py +++ b/test/test_rendercomment.py @@ -31,8 +31,13 @@ def setup(db_test, git: GitRepository): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - Passwd=str(), AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user @@ -40,24 +45,32 @@ def user() -> User: def pkgbase(user: User) -> PackageBase: now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, Packager=user, Name="pkgbase_0", - SubmittedTS=now, ModifiedTS=now) + pkgbase = db.create( + PackageBase, + Packager=user, + Name="pkgbase_0", + SubmittedTS=now, + ModifiedTS=now, + ) yield pkgbase @pytest.fixture def package(pkgbase: PackageBase) -> Package: with db.begin(): - package = db.create(Package, PackageBase=pkgbase, - Name=pkgbase.Name, Version="1.0") + package = db.create( + Package, PackageBase=pkgbase, Name=pkgbase.Name, Version="1.0" + ) yield package -def create_comment(user: User, pkgbase: PackageBase, comments: str, - render: bool = True): +def create_comment( + user: User, pkgbase: PackageBase, comments: str, render: bool = True +): with db.begin(): - comment = db.create(PackageComment, User=user, - PackageBase=pkgbase, Comments=comments) + comment = db.create( + PackageComment, User=user, PackageBase=pkgbase, Comments=comments + ) if render: update_comment_render(comment) return comment @@ -86,8 +99,7 @@ def test_rendercomment_main(user: User, pkgbase: PackageBase): def test_markdown_conversion(user: User, pkgbase: PackageBase): text = "*Hello* [world](https://aur.archlinux.org)!" comment = create_comment(user, pkgbase, text) - expected = ('

      Hello ' - 'world!

      ') + expected = "

      Hello " 'world!

      ' assert comment.RenderedComment == expected @@ -109,7 +121,7 @@ Visit [Arch Linux][arch]. [arch]: https://www.archlinux.org/\ """ comment = create_comment(user, pkgbase, text) - expected = '''\ + expected = """\

      Visit \ https://www.archlinux.org/#_test_. Visit https://www.archlinux.org/. @@ -117,7 +129,7 @@ Visit https://www.archlinux.org/. Visit https://www.archlinux.org/. Visit Arch Linux. Visit Arch Linux.

      \ -''' +""" assert comment.RenderedComment == expected diff --git a/test/test_requests.py b/test/test_requests.py index b7ab3835..fd831674 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -1,10 +1,8 @@ import re - from http import HTTPStatus from logging import DEBUG import pytest - from fastapi import HTTPException from fastapi.testclient import TestClient @@ -24,13 +22,13 @@ from aurweb.testing.requests import Request @pytest.fixture(autouse=True) def setup(db_test) -> None: - """ Setup the database. """ + """Setup the database.""" return @pytest.fixture def client() -> TestClient: - """ Yield a TestClient. """ + """Yield a TestClient.""" yield TestClient(app=asgi.app) @@ -43,21 +41,26 @@ def create_user(username: str, email: str) -> User: :return: User instance """ with db.begin(): - user = db.create(User, Username=username, Email=email, - Passwd="testPassword", AccountTypeID=USER_ID) + user = db.create( + User, + Username=username, + Email=email, + Passwd="testPassword", + AccountTypeID=USER_ID, + ) return user @pytest.fixture def user() -> User: - """ Yield a User instance. """ + """Yield a User instance.""" user = create_user("test", "test@example.org") yield user @pytest.fixture def auser(user: User) -> User: - """ Yield an authenticated User instance. """ + """Yield an authenticated User instance.""" cookies = {"AURSID": user.login(Request(), "testPassword")} user.cookies = cookies yield user @@ -65,14 +68,14 @@ def auser(user: User) -> User: @pytest.fixture def user2() -> User: - """ Yield a secondary non-maintainer User instance. """ + """Yield a secondary non-maintainer User instance.""" user = create_user("test2", "test2@example.org") yield user @pytest.fixture def auser2(user2: User) -> User: - """ Yield an authenticated secondary non-maintainer User instance. """ + """Yield an authenticated secondary non-maintainer User instance.""" cookies = {"AURSID": user2.login(Request(), "testPassword")} user2.cookies = cookies yield user2 @@ -80,31 +83,34 @@ def auser2(user2: User) -> User: @pytest.fixture def maintainer() -> User: - """ Yield a specific User used to maintain packages. """ + """Yield a specific User used to maintain packages.""" with db.begin(): - maintainer = db.create(User, Username="test_maintainer", - Email="test_maintainer@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + maintainer = db.create( + User, + Username="test_maintainer", + Email="test_maintainer@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield maintainer @pytest.fixture def packages(maintainer: User) -> list[Package]: - """ Yield 55 packages named pkg_0 .. pkg_54. """ + """Yield 55 packages named pkg_0 .. pkg_54.""" packages_ = [] now = time.utcnow() with db.begin(): for i in range(55): - pkgbase = db.create(PackageBase, - Name=f"pkg_{i}", - Maintainer=maintainer, - Packager=maintainer, - Submitter=maintainer, - ModifiedTS=now) - package = db.create(Package, - PackageBase=pkgbase, - Name=f"pkg_{i}") + pkgbase = db.create( + PackageBase, + Name=f"pkg_{i}", + Maintainer=maintainer, + Packager=maintainer, + Submitter=maintainer, + ModifiedTS=now, + ) + package = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}") packages_.append(package) yield packages_ @@ -115,20 +121,22 @@ def requests(user: User, packages: list[Package]) -> list[PackageRequest]: pkgreqs = [] with db.begin(): for i in range(55): - pkgreq = db.create(PackageRequest, - ReqTypeID=DELETION_ID, - User=user, - PackageBase=packages[i].PackageBase, - PackageBaseName=packages[i].Name, - Comments=f"Deletion request for pkg_{i}", - ClosureComment=str()) + pkgreq = db.create( + PackageRequest, + ReqTypeID=DELETION_ID, + User=user, + PackageBase=packages[i].PackageBase, + PackageBaseName=packages[i].Name, + Comments=f"Deletion request for pkg_{i}", + ClosureComment=str(), + ) pkgreqs.append(pkgreq) yield pkgreqs @pytest.fixture def tu_user() -> User: - """ Yield an authenticated Trusted User instance. """ + """Yield an authenticated Trusted User instance.""" user = create_user("test_tu", "test_tu@example.org") with db.begin(): user.AccountTypeID = TRUSTED_USER_ID @@ -149,31 +157,38 @@ def create_pkgbase(user: User, name: str) -> PackageBase: """ now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, Name=name, - Maintainer=user, Packager=user, - SubmittedTS=now, ModifiedTS=now) + pkgbase = db.create( + PackageBase, + Name=name, + Maintainer=user, + Packager=user, + SubmittedTS=now, + ModifiedTS=now, + ) db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) return pkgbase @pytest.fixture def pkgbase(user: User) -> PackageBase: - """ Yield a package base. """ + """Yield a package base.""" pkgbase = create_pkgbase(user, "test-package") yield pkgbase @pytest.fixture def target(user: User) -> PackageBase: - """ Yield a merge target (package base). """ + """Yield a merge target (package base).""" with db.begin(): - target = db.create(PackageBase, Name="target-package", - Maintainer=user, Packager=user) + target = db.create( + PackageBase, Name="target-package", Maintainer=user, Packager=user + ) yield target -def create_request(reqtype_id: int, user: User, pkgbase: PackageBase, - comments: str) -> PackageRequest: +def create_request( + reqtype_id: int, user: User, pkgbase: PackageBase, comments: str +) -> PackageRequest: """ Create a package request based on `reqtype_id`, `user`, `pkgbase` and `comments`. @@ -186,40 +201,43 @@ def create_request(reqtype_id: int, user: User, pkgbase: PackageBase, """ now = time.utcnow() with db.begin(): - pkgreq = db.create(PackageRequest, ReqTypeID=reqtype_id, - User=user, PackageBase=pkgbase, - PackageBaseName=pkgbase.Name, - RequestTS=now, - Comments=comments, - ClosureComment=str()) + pkgreq = db.create( + PackageRequest, + ReqTypeID=reqtype_id, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + RequestTS=now, + Comments=comments, + ClosureComment=str(), + ) return pkgreq @pytest.fixture def pkgreq(user: User, pkgbase: PackageBase): - """ Yield a package request. """ + """Yield a package request.""" pkgreq = create_request(DELETION_ID, user, pkgbase, "Test request.") yield pkgreq def create_notification(user: User, pkgbase: PackageBase): - """ Create a notification for a `user` on `pkgbase`. """ + """Create a notification for a `user` on `pkgbase`.""" with db.begin(): notif = db.create(PackageNotification, User=user, PackageBase=pkgbase) return notif def test_request(client: TestClient, auser: User, pkgbase: PackageBase): - """ Test the standard pkgbase request route GET method. """ + """Test the standard pkgbase request route GET method.""" endpoint = f"/pkgbase/{pkgbase.Name}/request" with client as request: resp = request.get(endpoint, cookies=auser.cookies) assert resp.status_code == int(HTTPStatus.OK) -def test_request_post_deletion(client: TestClient, auser2: User, - pkgbase: PackageBase): - """ Test the POST route for creating a deletion request works. """ +def test_request_post_deletion(client: TestClient, auser2: User, pkgbase: PackageBase): + """Test the POST route for creating a deletion request works.""" endpoint = f"/pkgbase/{pkgbase.Name}/request" data = {"comments": "Test request.", "type": "deletion"} with client as request: @@ -238,9 +256,10 @@ def test_request_post_deletion(client: TestClient, auser2: User, assert re.match(expr, email.headers.get("Subject")) -def test_request_post_deletion_as_maintainer(client: TestClient, auser: User, - pkgbase: PackageBase): - """ Test the POST route for creating a deletion request as maint works. """ +def test_request_post_deletion_as_maintainer( + client: TestClient, auser: User, pkgbase: PackageBase +): + """Test the POST route for creating a deletion request as maint works.""" endpoint = f"/pkgbase/{pkgbase.Name}/request" data = {"comments": "Test request.", "type": "deletion"} with client as request: @@ -267,10 +286,13 @@ def test_request_post_deletion_as_maintainer(client: TestClient, auser: User, assert re.match(expr, email.headers.get("Subject")) -def test_request_post_deletion_autoaccept(client: TestClient, auser: User, - pkgbase: PackageBase, - caplog: pytest.LogCaptureFixture): - """ Test the request route for deletion as maintainer. """ +def test_request_post_deletion_autoaccept( + client: TestClient, + auser: User, + pkgbase: PackageBase, + caplog: pytest.LogCaptureFixture, +): + """Test the request route for deletion as maintainer.""" caplog.set_level(DEBUG) now = time.utcnow() @@ -284,9 +306,11 @@ def test_request_post_deletion_autoaccept(client: TestClient, auser: User, resp = request.post(endpoint, data=data, cookies=auser.cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) - pkgreq = db.query(PackageRequest).filter( - PackageRequest.PackageBaseName == pkgbase.Name - ).first() + pkgreq = ( + db.query(PackageRequest) + .filter(PackageRequest.PackageBaseName == pkgbase.Name) + .first() + ) assert pkgreq is not None assert pkgreq.ReqTypeID == DELETION_ID assert pkgreq.Status == ACCEPTED_ID @@ -310,9 +334,10 @@ def test_request_post_deletion_autoaccept(client: TestClient, auser: User, assert re.search(expr, caplog.text) -def test_request_post_merge(client: TestClient, auser: User, - pkgbase: PackageBase, target: PackageBase): - """ Test the request route for merge as maintainer. """ +def test_request_post_merge( + client: TestClient, auser: User, pkgbase: PackageBase, target: PackageBase +): + """Test the request route for merge as maintainer.""" endpoint = f"/pkgbase/{pkgbase.Name}/request" data = { "type": "merge", @@ -336,9 +361,8 @@ def test_request_post_merge(client: TestClient, auser: User, assert re.match(expr, email.headers.get("Subject")) -def test_request_post_orphan(client: TestClient, auser: User, - pkgbase: PackageBase): - """ Test the POST route for creating an orphan request works. """ +def test_request_post_orphan(client: TestClient, auser: User, pkgbase: PackageBase): + """Test the POST route for creating an orphan request works.""" endpoint = f"/pkgbase/{pkgbase.Name}/request" data = { "type": "orphan", @@ -361,9 +385,14 @@ def test_request_post_orphan(client: TestClient, auser: User, assert re.match(expr, email.headers.get("Subject")) -def test_deletion_request(client: TestClient, user: User, tu_user: User, - pkgbase: PackageBase, pkgreq: PackageRequest): - """ Test deleting a package with a preexisting request. """ +def test_deletion_request( + client: TestClient, + user: User, + tu_user: User, + pkgbase: PackageBase, + pkgreq: PackageRequest, +): + """Test deleting a package with a preexisting request.""" # `pkgreq`.ReqTypeID is already DELETION_ID. create_request(DELETION_ID, user, pkgbase, "Other request.") @@ -402,9 +431,8 @@ def test_deletion_request(client: TestClient, user: User, tu_user: User, assert body in email.body -def test_deletion_autorequest(client: TestClient, tu_user: User, - pkgbase: PackageBase): - """ Test deleting a package without a request. """ +def test_deletion_autorequest(client: TestClient, tu_user: User, pkgbase: PackageBase): + """Test deleting a package without a request.""" # `pkgreq`.ReqTypeID is already DELETION_ID. endpoint = f"/pkgbase/{pkgbase.Name}/delete" data = {"confirm": True} @@ -421,10 +449,15 @@ def test_deletion_autorequest(client: TestClient, tu_user: User, assert "[Autogenerated]" in email.body -def test_merge_request(client: TestClient, user: User, tu_user: User, - pkgbase: PackageBase, target: PackageBase, - pkgreq: PackageRequest): - """ Test merging a package with a pre - existing request. """ +def test_merge_request( + client: TestClient, + user: User, + tu_user: User, + pkgbase: PackageBase, + target: PackageBase, + pkgreq: PackageRequest, +): + """Test merging a package with a pre - existing request.""" with db.begin(): pkgreq.ReqTypeID = MERGE_ID pkgreq.MergeBaseName = target.Name @@ -473,9 +506,14 @@ def test_merge_request(client: TestClient, user: User, tu_user: User, assert "[Autogenerated]" in rejected.body -def test_merge_autorequest(client: TestClient, user: User, tu_user: User, - pkgbase: PackageBase, target: PackageBase): - """ Test merging a package without a request. """ +def test_merge_autorequest( + client: TestClient, + user: User, + tu_user: User, + pkgbase: PackageBase, + target: PackageBase, +): + """Test merging a package without a request.""" with db.begin(): pkgreq.ReqTypeID = MERGE_ID pkgreq.MergeBaseName = target.Name @@ -498,13 +536,17 @@ def test_merge_autorequest(client: TestClient, user: User, tu_user: User, assert "[Autogenerated]" in email.body -def test_orphan_request(client: TestClient, user: User, tu_user: User, - pkgbase: PackageBase, pkgreq: PackageRequest): - """ Test the standard orphan request route. """ +def test_orphan_request( + client: TestClient, + user: User, + tu_user: User, + pkgbase: PackageBase, + pkgreq: PackageRequest, +): + """Test the standard orphan request route.""" user2 = create_user("user2", "user2@example.org") with db.begin(): - db.create(PackageComaintainer, User=user2, - PackageBase=pkgbase, Priority=1) + db.create(PackageComaintainer, User=user2, PackageBase=pkgbase, Priority=1) idle_time = config.getint("options", "request_idle_time") now = time.utcnow() @@ -537,10 +579,9 @@ def test_orphan_request(client: TestClient, user: User, tu_user: User, assert re.match(subj, email.headers.get("Subject")) -def test_request_post_orphan_autogenerated_closure(client: TestClient, - tu_user: User, - pkgbase: PackageBase, - pkgreq: PackageRequest): +def test_request_post_orphan_autogenerated_closure( + client: TestClient, tu_user: User, pkgbase: PackageBase, pkgreq: PackageRequest +): idle_time = config.getint("options", "request_idle_time") now = time.utcnow() with db.begin(): @@ -564,10 +605,13 @@ def test_request_post_orphan_autogenerated_closure(client: TestClient, assert re.search(expr, email.body) -def test_request_post_orphan_autoaccept(client: TestClient, auser: User, - pkgbase: PackageBase, - caplog: pytest.LogCaptureFixture): - """ Test the standard pkgbase request route GET method. """ +def test_request_post_orphan_autoaccept( + client: TestClient, + auser: User, + pkgbase: PackageBase, + caplog: pytest.LogCaptureFixture, +): + """Test the standard pkgbase request route GET method.""" caplog.set_level(DEBUG) now = time.utcnow() auto_orphan_age = config.getint("options", "auto_orphan_age") @@ -605,8 +649,7 @@ def test_request_post_orphan_autoaccept(client: TestClient, auser: User, assert re.search(expr, caplog.text) -def test_orphan_as_maintainer(client: TestClient, auser: User, - pkgbase: PackageBase): +def test_orphan_as_maintainer(client: TestClient, auser: User, pkgbase: PackageBase): endpoint = f"/pkgbase/{pkgbase.Name}/disown" data = {"confirm": True} with client as request: @@ -620,9 +663,10 @@ def test_orphan_as_maintainer(client: TestClient, auser: User, assert pkgbase.Maintainer is None -def test_orphan_without_requests(client: TestClient, tu_user: User, - pkgbase: PackageBase): - """ Test orphans are automatically accepted past a certain date. """ +def test_orphan_without_requests( + client: TestClient, tu_user: User, pkgbase: PackageBase +): + """Test orphans are automatically accepted past a certain date.""" endpoint = f"/pkgbase/{pkgbase.Name}/disown" data = {"confirm": True} with client as request: @@ -637,7 +681,7 @@ def test_orphan_without_requests(client: TestClient, tu_user: User, def test_closure_factory_invalid_reqtype_id(): - """ Test providing an invalid reqtype_id raises NotImplementedError. """ + """Test providing an invalid reqtype_id raises NotImplementedError.""" automated = ClosureFactory() match = r"^Unsupported '.+' value\.$" with pytest.raises(NotImplementedError, match=match): @@ -657,19 +701,25 @@ def test_requests_unauthorized(client: TestClient): assert resp.status_code == int(HTTPStatus.SEE_OTHER) -def test_requests(client: TestClient, - tu_user: User, - packages: list[Package], - requests: list[PackageRequest]): +def test_requests( + client: TestClient, + tu_user: User, + packages: list[Package], + requests: list[PackageRequest], +): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.get("/requests", params={ - # Pass in url query parameters O, SeB and SB to exercise - # their paths inside of the pager_nav used in this request. - "O": 0, # Page 1 - "SeB": "nd", - "SB": "n" - }, cookies=cookies) + resp = request.get( + "/requests", + params={ + # Pass in url query parameters O, SeB and SB to exercise + # their paths inside of the pager_nav used in this request. + "O": 0, # Page 1 + "SeB": "nd", + "SB": "n", + }, + cookies=cookies, + ) assert resp.status_code == int(HTTPStatus.OK) assert "Next ›" in resp.text @@ -682,9 +732,7 @@ def test_requests(client: TestClient, # Request page 2 of the requests page. with client as request: - resp = request.get("/requests", params={ - "O": 50 # Page 2 - }, cookies=cookies) + resp = request.get("/requests", params={"O": 50}, cookies=cookies) # Page 2 assert resp.status_code == int(HTTPStatus.OK) assert "‹ Previous" in resp.text @@ -695,8 +743,9 @@ def test_requests(client: TestClient, assert len(rows) == 5 # There are five records left on the second page. -def test_requests_selfmade(client: TestClient, user: User, - requests: list[PackageRequest]): +def test_requests_selfmade( + client: TestClient, user: User, requests: list[PackageRequest] +): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: resp = request.get("/requests", cookies=cookies) @@ -710,46 +759,52 @@ def test_requests_selfmade(client: TestClient, user: User, # Our first and only link in the last row should be "Close". for row in rows: - last_row = row.xpath('./td')[-1].xpath('./a')[0] + last_row = row.xpath("./td")[-1].xpath("./a")[0] assert last_row.text.strip() == "Close" -def test_requests_close(client: TestClient, user: User, - pkgreq: PackageRequest): +def test_requests_close(client: TestClient, user: User, pkgreq: PackageRequest): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies, - allow_redirects=False) + resp = request.get( + f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.OK) -def test_requests_close_unauthorized(client: TestClient, maintainer: User, - pkgreq: PackageRequest): +def test_requests_close_unauthorized( + client: TestClient, maintainer: User, pkgreq: PackageRequest +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies, - allow_redirects=False) + resp = request.get( + f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" -def test_requests_close_post_unauthorized(client: TestClient, maintainer: User, - pkgreq: PackageRequest): +def test_requests_close_post_unauthorized( + client: TestClient, maintainer: User, pkgreq: PackageRequest +): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post(f"/requests/{pkgreq.ID}/close", data={ - "reason": ACCEPTED_ID - }, cookies=cookies, allow_redirects=False) + resp = request.post( + f"/requests/{pkgreq.ID}/close", + data={"reason": ACCEPTED_ID}, + cookies=cookies, + allow_redirects=False, + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" -def test_requests_close_post(client: TestClient, user: User, - pkgreq: PackageRequest): +def test_requests_close_post(client: TestClient, user: User, pkgreq: PackageRequest): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(f"/requests/{pkgreq.ID}/close", - cookies=cookies, allow_redirects=False) + resp = request.post( + f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgreq.Status == REJECTED_ID @@ -757,12 +812,14 @@ def test_requests_close_post(client: TestClient, user: User, assert pkgreq.ClosureComment == str() -def test_requests_close_post_rejected(client: TestClient, user: User, - pkgreq: PackageRequest): +def test_requests_close_post_rejected( + client: TestClient, user: User, pkgreq: PackageRequest +): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(f"/requests/{pkgreq.ID}/close", - cookies=cookies, allow_redirects=False) + resp = request.post( + f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgreq.Status == REJECTED_ID diff --git a/test/test_routes.py b/test/test_routes.py index 85d30c02..78b0a65b 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -1,11 +1,9 @@ import re import urllib.parse - from http import HTTPStatus import lxml.etree import pytest - from fastapi.testclient import TestClient from aurweb import db @@ -28,21 +26,26 @@ def client() -> TestClient: @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user def test_index(client: TestClient): - """ Test the index route at '/'. """ + """Test the index route at '/'.""" with client as req: response = req.get("/") assert response.status_code == int(HTTPStatus.OK) def test_index_security_headers(client: TestClient): - """ Check for the existence of CSP, XCTO, XFO and RP security headers. + """Check for the existence of CSP, XCTO, XFO and RP security headers. CSP: Content-Security-Policy XCTO: X-Content-Type-Options @@ -60,7 +63,7 @@ def test_index_security_headers(client: TestClient): def test_favicon(client: TestClient): - """ Test the favicon route at '/favicon.ico'. """ + """Test the favicon route at '/favicon.ico'.""" with client as request: response1 = request.get("/static/images/favicon.ico") response2 = request.get("/favicon.ico") @@ -69,52 +72,38 @@ def test_favicon(client: TestClient): def test_language(client: TestClient): - """ Test the language post route as a guest user. """ - post_data = { - "set_lang": "de", - "next": "/" - } + """Test the language post route as a guest user.""" + post_data = {"set_lang": "de", "next": "/"} with client as req: response = req.post("/language", data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) def test_language_invalid_next(client: TestClient): - """ Test an invalid next route at '/language'. """ - post_data = { - "set_lang": "de", - "next": "https://evil.net" - } + """Test an invalid next route at '/language'.""" + post_data = {"set_lang": "de", "next": "https://evil.net"} with client as req: response = req.post("/language", data=post_data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) def test_user_language(client: TestClient, user: User): - """ Test the language post route as an authenticated user. """ - post_data = { - "set_lang": "de", - "next": "/" - } + """Test the language post route as an authenticated user.""" + post_data = {"set_lang": "de", "next": "/"} sid = user.login(Request(), "testPassword") assert sid is not None with client as req: - response = req.post("/language", data=post_data, - cookies={"AURSID": sid}) + response = req.post("/language", data=post_data, cookies={"AURSID": sid}) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert user.LangPreference == "de" def test_language_query_params(client: TestClient): - """ Test the language post route with query params. """ + """Test the language post route with query params.""" next = urllib.parse.quote_plus("/") - post_data = { - "set_lang": "de", - "next": "/", - "q": f"next={next}" - } + post_data = {"set_lang": "de", "next": "/", "q": f"next={next}"} q = post_data.get("q") with client as req: response = req.post("/language", data=post_data) @@ -154,9 +143,13 @@ def test_nonce_csp(client: TestClient): def test_id_redirect(client: TestClient): with client as request: - response = request.get("/", params={ - "id": "test", # This param will be rewritten into Location. - "key": "value", # Test that this param persists. - "key2": "value2" # And this one. - }, allow_redirects=False) + response = request.get( + "/", + params={ + "id": "test", # This param will be rewritten into Location. + "key": "value", # Test that this param persists. + "key2": "value2", # And this one. + }, + allow_redirects=False, + ) assert response.headers.get("location") == "/test?key=value&key2=value2" diff --git a/test/test_rpc.py b/test/test_rpc.py index c0861d3d..ed7e8894 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1,17 +1,14 @@ import re - from http import HTTPStatus from unittest import mock import orjson import pytest - from fastapi.testclient import TestClient from redis.client import Pipeline import aurweb.models.dependency_type as dt import aurweb.models.relation_type as rt - from aurweb import asgi, config, db, rpc, scripts, time from aurweb.models.account_type import USER_ID from aurweb.models.dependency_type import DEPENDS_ID @@ -36,27 +33,42 @@ def client() -> TestClient: @pytest.fixture def user(db_test) -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User 1", Passwd=str(), - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User 1", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def user2() -> User: with db.begin(): - user = db.create(User, Username="user2", Email="user2@example.org", - RealName="Test User 2", Passwd=str(), - AccountTypeID=USER_ID) + user = db.create( + User, + Username="user2", + Email="user2@example.org", + RealName="Test User 2", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def user3() -> User: with db.begin(): - user = db.create(User, Username="user3", Email="user3@example.org", - RealName="Test User 3", Passwd=str(), - AccountTypeID=USER_ID) + user = db.create( + User, + Username="user3", + Email="user3@example.org", + RealName="Test User 3", + Passwd=str(), + AccountTypeID=USER_ID, + ) yield user @@ -66,39 +78,64 @@ def packages(user: User, user2: User, user3: User) -> list[Package]: # Create package records used in our tests. with db.begin(): - pkgbase = db.create(PackageBase, Name="big-chungus", - Maintainer=user, Packager=user) - pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, - Description="Bunny bunny around bunny", - URL="https://example.com/") + pkgbase = db.create( + PackageBase, Name="big-chungus", Maintainer=user, Packager=user + ) + pkg = db.create( + Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Bunny bunny around bunny", + URL="https://example.com/", + ) output.append(pkg) - pkgbase = db.create(PackageBase, Name="chungy-chungus", - Maintainer=user, Packager=user) - pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, - Description="Wubby wubby on wobba wuubu", - URL="https://example.com/") + pkgbase = db.create( + PackageBase, Name="chungy-chungus", Maintainer=user, Packager=user + ) + pkg = db.create( + Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="Wubby wubby on wobba wuubu", + URL="https://example.com/", + ) output.append(pkg) - pkgbase = db.create(PackageBase, Name="gluggly-chungus", - Maintainer=user, Packager=user) - pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, - Description="glurrba glurrba gur globba", - URL="https://example.com/") + pkgbase = db.create( + PackageBase, Name="gluggly-chungus", Maintainer=user, Packager=user + ) + pkg = db.create( + Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="glurrba glurrba gur globba", + URL="https://example.com/", + ) output.append(pkg) - pkgbase = db.create(PackageBase, Name="fugly-chungus", - Maintainer=user, Packager=user) + pkgbase = db.create( + PackageBase, Name="fugly-chungus", Maintainer=user, Packager=user + ) desc = "A Package belonging to a PackageBase with another name." - pkg = db.create(Package, PackageBase=pkgbase, Name="other-pkg", - Description=desc, URL="https://example.com") + pkg = db.create( + Package, + PackageBase=pkgbase, + Name="other-pkg", + Description=desc, + URL="https://example.com", + ) output.append(pkg) pkgbase = db.create(PackageBase, Name="woogly-chungus") - pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name, - Description="wuggla woblabeloop shemashmoop", - URL="https://example.com/") + pkg = db.create( + Package, + PackageBase=pkgbase, + Name=pkgbase.Name, + Description="wuggla woblabeloop shemashmoop", + URL="https://example.com/", + ) output.append(pkg) # Setup a few more related records on the first package: @@ -108,14 +145,15 @@ def packages(user: User, user2: User, user3: User) -> list[Package]: db.create(PackageLicense, Package=output[0], License=lic) for keyword in ["big-chungus", "smol-chungus", "sizeable-chungus"]: - db.create(PackageKeyword, - PackageBase=output[0].PackageBase, - Keyword=keyword) + db.create( + PackageKeyword, PackageBase=output[0].PackageBase, Keyword=keyword + ) now = time.utcnow() for user_ in [user, user2, user3]: - db.create(PackageVote, User=user_, - PackageBase=output[0].PackageBase, VoteTS=now) + db.create( + PackageVote, User=user_, PackageBase=output[0].PackageBase, VoteTS=now + ) scripts.popupdate.run_single(output[0].PackageBase) yield output @@ -126,35 +164,45 @@ def depends(packages: list[Package]) -> list[PackageDependency]: output = [] with db.begin(): - dep = db.create(PackageDependency, - Package=packages[0], - DepTypeID=dt.DEPENDS_ID, - DepName="chungus-depends") + dep = db.create( + PackageDependency, + Package=packages[0], + DepTypeID=dt.DEPENDS_ID, + DepName="chungus-depends", + ) output.append(dep) - dep = db.create(PackageDependency, - Package=packages[1], - DepTypeID=dt.DEPENDS_ID, - DepName="chungy-depends") + dep = db.create( + PackageDependency, + Package=packages[1], + DepTypeID=dt.DEPENDS_ID, + DepName="chungy-depends", + ) output.append(dep) - dep = db.create(PackageDependency, - Package=packages[0], - DepTypeID=dt.OPTDEPENDS_ID, - DepName="chungus-optdepends", - DepCondition="=50") + dep = db.create( + PackageDependency, + Package=packages[0], + DepTypeID=dt.OPTDEPENDS_ID, + DepName="chungus-optdepends", + DepCondition="=50", + ) output.append(dep) - dep = db.create(PackageDependency, - Package=packages[0], - DepTypeID=dt.MAKEDEPENDS_ID, - DepName="chungus-makedepends") + dep = db.create( + PackageDependency, + Package=packages[0], + DepTypeID=dt.MAKEDEPENDS_ID, + DepName="chungus-makedepends", + ) output.append(dep) - dep = db.create(PackageDependency, - Package=packages[0], - DepTypeID=dt.CHECKDEPENDS_ID, - DepName="chungus-checkdepends") + dep = db.create( + PackageDependency, + Package=packages[0], + DepTypeID=dt.CHECKDEPENDS_ID, + DepName="chungus-checkdepends", + ) output.append(dep) yield output @@ -165,30 +213,38 @@ def relations(user: User, packages: list[Package]) -> list[PackageRelation]: output = [] with db.begin(): - rel = db.create(PackageRelation, - Package=packages[0], - RelTypeID=rt.CONFLICTS_ID, - RelName="chungus-conflicts") + rel = db.create( + PackageRelation, + Package=packages[0], + RelTypeID=rt.CONFLICTS_ID, + RelName="chungus-conflicts", + ) output.append(rel) - rel = db.create(PackageRelation, - Package=packages[1], - RelTypeID=rt.CONFLICTS_ID, - RelName="chungy-conflicts") + rel = db.create( + PackageRelation, + Package=packages[1], + RelTypeID=rt.CONFLICTS_ID, + RelName="chungy-conflicts", + ) output.append(rel) - rel = db.create(PackageRelation, - Package=packages[0], - RelTypeID=rt.PROVIDES_ID, - RelName="chungus-provides", - RelCondition="<=200") + rel = db.create( + PackageRelation, + Package=packages[0], + RelTypeID=rt.PROVIDES_ID, + RelName="chungus-provides", + RelCondition="<=200", + ) output.append(rel) - rel = db.create(PackageRelation, - Package=packages[0], - RelTypeID=rt.REPLACES_ID, - RelName="chungus-replaces", - RelCondition="<=200") + rel = db.create( + PackageRelation, + Package=packages[0], + RelTypeID=rt.REPLACES_ID, + RelName="chungus-replaces", + RelCondition="<=200", + ) output.append(rel) # Finally, yield the packages. @@ -238,51 +294,54 @@ def test_rpc_documentation_missing(): config.rehash() -def test_rpc_singular_info(client: TestClient, - user: User, - packages: list[Package], - depends: list[PackageDependency], - relations: list[PackageRelation]): +def test_rpc_singular_info( + client: TestClient, + user: User, + packages: list[Package], + depends: list[PackageDependency], + relations: list[PackageRelation], +): # Define expected response. pkg = packages[0] expected_data = { "version": 5, - "results": [{ - "Name": pkg.Name, - "Version": pkg.Version, - "Description": pkg.Description, - "URL": pkg.URL, - "PackageBase": pkg.PackageBase.Name, - "NumVotes": pkg.PackageBase.NumVotes, - "Popularity": float(pkg.PackageBase.Popularity), - "OutOfDate": None, - "Maintainer": user.Username, - "URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz", - "Depends": ["chungus-depends"], - "OptDepends": ["chungus-optdepends=50"], - "MakeDepends": ["chungus-makedepends"], - "CheckDepends": ["chungus-checkdepends"], - "Conflicts": ["chungus-conflicts"], - "Provides": ["chungus-provides<=200"], - "Replaces": ["chungus-replaces<=200"], - "License": [pkg.package_licenses.first().License.Name], - "Keywords": [ - "big-chungus", - "sizeable-chungus", - "smol-chungus" - ] - }], + "results": [ + { + "Name": pkg.Name, + "Version": pkg.Version, + "Description": pkg.Description, + "URL": pkg.URL, + "PackageBase": pkg.PackageBase.Name, + "NumVotes": pkg.PackageBase.NumVotes, + "Popularity": float(pkg.PackageBase.Popularity), + "OutOfDate": None, + "Maintainer": user.Username, + "URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz", + "Depends": ["chungus-depends"], + "OptDepends": ["chungus-optdepends=50"], + "MakeDepends": ["chungus-makedepends"], + "CheckDepends": ["chungus-checkdepends"], + "Conflicts": ["chungus-conflicts"], + "Provides": ["chungus-provides<=200"], + "Replaces": ["chungus-replaces<=200"], + "License": [pkg.package_licenses.first().License.Name], + "Keywords": ["big-chungus", "sizeable-chungus", "smol-chungus"], + } + ], "resultcount": 1, - "type": "multiinfo" + "type": "multiinfo", } # Make dummy request. with client as request: - resp = request.get("/rpc", params={ - "v": 5, - "type": "info", - "arg": ["chungy-chungus", "big-chungus"], - }) + resp = request.get( + "/rpc", + params={ + "v": 5, + "type": "info", + "arg": ["chungy-chungus", "big-chungus"], + }, + ) # Load request response into Python dictionary. response_data = orjson.loads(resp.text) @@ -299,19 +358,21 @@ def test_rpc_singular_info(client: TestClient, def test_rpc_split_package_urlpath(client: TestClient, user: User): with db.begin(): - pkgbase = db.create(PackageBase, Name="pkg", - Maintainer=user, Packager=user) + pkgbase = db.create(PackageBase, Name="pkg", Maintainer=user, Packager=user) pkgs = [ db.create(Package, PackageBase=pkgbase, Name="pkg_1"), db.create(Package, PackageBase=pkgbase, Name="pkg_2"), ] with client as request: - response = request.get("/rpc", params={ - "v": 5, - "type": "info", - "arg": [pkgs[0].Name], - }) + response = request.get( + "/rpc", + params={ + "v": 5, + "type": "info", + "arg": [pkgs[0].Name], + }, + ) data = orjson.loads(response.text) snapshot_uri = config.get("options", "snapshot_uri") @@ -335,9 +396,9 @@ def test_rpc_multiinfo(client: TestClient, packages: list[Package]): # Make dummy request. request_packages = ["big-chungus", "chungy-chungus"] with client as request: - response = request.get("/rpc", params={ - "v": 5, "type": "info", "arg[]": request_packages - }) + response = request.get( + "/rpc", params={"v": 5, "type": "info", "arg[]": request_packages} + ) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -357,13 +418,15 @@ def test_rpc_mixedargs(client: TestClient, packages: list[Package]): with client as request: # Supply all of the args in the url to enforce ordering. response1 = request.get( - "/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info") + "/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info" + ) assert response1.status_code == int(HTTPStatus.OK) with client as request: response2 = request.get( "/rpc?v=5&arg=big-chungus&arg[]=gluggly-chungus" - "&type=info&arg[]=chungy-chungus") + "&type=info&arg[]=chungy-chungus" + ) assert response1.status_code == int(HTTPStatus.OK) # Load request response into Python dictionary. @@ -381,42 +444,47 @@ def test_rpc_mixedargs(client: TestClient, packages: list[Package]): assert i == [] -def test_rpc_no_dependencies_omits_key(client: TestClient, user: User, - packages: list[Package], - depends: list[PackageDependency], - relations: list[PackageRelation]): +def test_rpc_no_dependencies_omits_key( + client: TestClient, + user: User, + packages: list[Package], + depends: list[PackageDependency], + relations: list[PackageRelation], +): """ This makes sure things like 'MakeDepends' get removed from JSON strings when they don't have set values. """ pkg = packages[1] expected_response = { - 'version': 5, - 'results': [{ - 'Name': pkg.Name, - 'Version': pkg.Version, - 'Description': pkg.Description, - 'URL': pkg.URL, - 'PackageBase': pkg.PackageBase.Name, - 'NumVotes': pkg.PackageBase.NumVotes, - 'Popularity': int(pkg.PackageBase.Popularity), - 'OutOfDate': None, - 'Maintainer': user.Username, - 'URLPath': '/cgit/aur.git/snapshot/chungy-chungus.tar.gz', - 'Depends': ['chungy-depends'], - 'Conflicts': ['chungy-conflicts'], - 'License': [], - 'Keywords': [] - }], - 'resultcount': 1, - 'type': 'multiinfo' + "version": 5, + "results": [ + { + "Name": pkg.Name, + "Version": pkg.Version, + "Description": pkg.Description, + "URL": pkg.URL, + "PackageBase": pkg.PackageBase.Name, + "NumVotes": pkg.PackageBase.NumVotes, + "Popularity": int(pkg.PackageBase.Popularity), + "OutOfDate": None, + "Maintainer": user.Username, + "URLPath": "/cgit/aur.git/snapshot/chungy-chungus.tar.gz", + "Depends": ["chungy-depends"], + "Conflicts": ["chungy-conflicts"], + "License": [], + "Keywords": [], + } + ], + "resultcount": 1, + "type": "multiinfo", } # Make dummy request. with client as request: - response = request.get("/rpc", params={ - "v": 5, "type": "info", "arg": "chungy-chungus" - }) + response = request.get( + "/rpc", params={"v": 5, "type": "info", "arg": "chungy-chungus"} + ) response_data = orjson.loads(response.content.decode()) # Remove inconsistent keys. @@ -429,18 +497,18 @@ def test_rpc_no_dependencies_omits_key(client: TestClient, user: User, def test_rpc_bad_type(client: TestClient): # Define expected response. expected_data = { - 'version': 5, - 'results': [], - 'resultcount': 0, - 'type': 'error', - 'error': 'Incorrect request type specified.' + "version": 5, + "results": [], + "resultcount": 0, + "type": "error", + "error": "Incorrect request type specified.", } # Make dummy request. with client as request: - response = request.get("/rpc", params={ - "v": 5, "type": "invalid-type", "arg": "big-chungus" - }) + response = request.get( + "/rpc", params={"v": 5, "type": "invalid-type", "arg": "big-chungus"} + ) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -452,18 +520,18 @@ def test_rpc_bad_type(client: TestClient): def test_rpc_bad_version(client: TestClient): # Define expected response. expected_data = { - 'version': 0, - 'resultcount': 0, - 'results': [], - 'type': 'error', - 'error': 'Invalid version specified.' + "version": 0, + "resultcount": 0, + "results": [], + "type": "error", + "error": "Invalid version specified.", } # Make dummy request. with client as request: - response = request.get("/rpc", params={ - "v": 0, "type": "info", "arg": "big-chungus" - }) + response = request.get( + "/rpc", params={"v": 0, "type": "info", "arg": "big-chungus"} + ) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -475,19 +543,16 @@ def test_rpc_bad_version(client: TestClient): def test_rpc_no_version(client: TestClient): # Define expected response. expected_data = { - 'version': None, - 'resultcount': 0, - 'results': [], - 'type': 'error', - 'error': 'Please specify an API version.' + "version": None, + "resultcount": 0, + "results": [], + "type": "error", + "error": "Please specify an API version.", } # Make dummy request. with client as request: - response = request.get("/rpc", params={ - "type": "info", - "arg": "big-chungus" - }) + response = request.get("/rpc", params={"type": "info", "arg": "big-chungus"}) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -499,11 +564,11 @@ def test_rpc_no_version(client: TestClient): def test_rpc_no_type(client: TestClient): # Define expected response. expected_data = { - 'version': 5, - 'results': [], - 'resultcount': 0, - 'type': 'error', - 'error': 'No request type/data specified.' + "version": 5, + "results": [], + "resultcount": 0, + "type": "error", + "error": "No request type/data specified.", } # Make dummy request. @@ -520,11 +585,11 @@ def test_rpc_no_type(client: TestClient): def test_rpc_no_args(client: TestClient): # Define expected response. expected_data = { - 'version': 5, - 'results': [], - 'resultcount': 0, - 'type': 'error', - 'error': 'No request type/data specified.' + "version": 5, + "results": [], + "resultcount": 0, + "type": "error", + "error": "No request type/data specified.", } # Make dummy request. @@ -541,9 +606,9 @@ def test_rpc_no_args(client: TestClient): def test_rpc_no_maintainer(client: TestClient, packages: list[Package]): # Make dummy request. with client as request: - response = request.get("/rpc", params={ - "v": 5, "type": "info", "arg": "woogly-chungus" - }) + response = request.get( + "/rpc", params={"v": 5, "type": "info", "arg": "woogly-chungus"} + ) # Load request response into Python dictionary. response_data = orjson.loads(response.content.decode()) @@ -620,8 +685,12 @@ def mock_config_getint(section: str, key: str): @mock.patch("aurweb.config.getint", side_effect=mock_config_getint) -def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient, - pipeline: Pipeline, packages: list[Package]): +def test_rpc_ratelimit( + getint: mock.MagicMock, + client: TestClient, + pipeline: Pipeline, + packages: list[Package], +): params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"} for i in range(4): @@ -685,7 +754,7 @@ def test_rpc_search(client: TestClient, packages: list[Package]): headers = {"If-None-Match": etag} response = request.get("/rpc", params=params, headers=headers) assert response.status_code == int(HTTPStatus.NOT_MODIFIED) - assert response.content == b'' + assert response.content == b"" # No args on non-m by types return an error. del params["arg"] @@ -703,12 +772,7 @@ def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]): # user1 maintains 4 packages; assert that we got them all. assert data.get("resultcount") == 4 names = list(sorted(r.get("Name") for r in data.get("results"))) - expected_results = [ - "big-chungus", - "chungy-chungus", - "gluggly-chungus", - "other-pkg" - ] + expected_results = ["big-chungus", "chungy-chungus", "gluggly-chungus", "other-pkg"] assert names == expected_results # Search for a non-existent maintainer, giving us zero packages. @@ -730,11 +794,10 @@ def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]): assert result.get("Name") == "big-chungus" -def test_rpc_search_depends(client: TestClient, packages: list[Package], - depends: list[PackageDependency]): - params = { - "v": 5, "type": "search", "by": "depends", "arg": "chungus-depends" - } +def test_rpc_search_depends( + client: TestClient, packages: list[Package], depends: list[PackageDependency] +): + params = {"v": 5, "type": "search", "by": "depends", "arg": "chungus-depends"} with client as request: response = request.get("/rpc", params=params) data = response.json() @@ -743,13 +806,14 @@ def test_rpc_search_depends(client: TestClient, packages: list[Package], assert result.get("Name") == packages[0].Name -def test_rpc_search_makedepends(client: TestClient, packages: list[Package], - depends: list[PackageDependency]): +def test_rpc_search_makedepends( + client: TestClient, packages: list[Package], depends: list[PackageDependency] +): params = { "v": 5, "type": "search", "by": "makedepends", - "arg": "chungus-makedepends" + "arg": "chungus-makedepends", } with client as request: response = request.get("/rpc", params=params) @@ -759,14 +823,10 @@ def test_rpc_search_makedepends(client: TestClient, packages: list[Package], assert result.get("Name") == packages[0].Name -def test_rpc_search_optdepends(client: TestClient, packages: list[Package], - depends: list[PackageDependency]): - params = { - "v": 5, - "type": "search", - "by": "optdepends", - "arg": "chungus-optdepends" - } +def test_rpc_search_optdepends( + client: TestClient, packages: list[Package], depends: list[PackageDependency] +): + params = {"v": 5, "type": "search", "by": "optdepends", "arg": "chungus-optdepends"} with client as request: response = request.get("/rpc", params=params) data = response.json() @@ -775,13 +835,14 @@ def test_rpc_search_optdepends(client: TestClient, packages: list[Package], assert result.get("Name") == packages[0].Name -def test_rpc_search_checkdepends(client: TestClient, packages: list[Package], - depends: list[PackageDependency]): +def test_rpc_search_checkdepends( + client: TestClient, packages: list[Package], depends: list[PackageDependency] +): params = { "v": 5, "type": "search", "by": "checkdepends", - "arg": "chungus-checkdepends" + "arg": "chungus-checkdepends", } with client as request: response = request.get("/rpc", params=params) @@ -799,21 +860,16 @@ def test_rpc_incorrect_by(client: TestClient): def test_rpc_jsonp_callback(client: TestClient): - """ Test the callback parameter. + """Test the callback parameter. For end-to-end verification, the `examples/jsonp.html` file can be used to submit jsonp callback requests to the RPC. """ - params = { - "v": 5, - "type": "search", - "arg": "big", - "callback": "jsonCallback" - } + params = {"v": 5, "type": "search", "arg": "big", "callback": "jsonCallback"} with client as request: response = request.get("/rpc", params=params) assert response.headers.get("content-type") == "text/javascript" - assert re.search(r'^/\*\*/jsonCallback\(.*\)$', response.text) is not None + assert re.search(r"^/\*\*/jsonCallback\(.*\)$", response.text) is not None # Test an invalid callback name; we get an application/json error. params["callback"] = "jsonCallback!" @@ -824,20 +880,14 @@ def test_rpc_jsonp_callback(client: TestClient): def test_rpc_post(client: TestClient, packages: list[Package]): - data = { - "v": 5, - "type": "info", - "arg": "big-chungus", - "arg[]": ["chungy-chungus"] - } + data = {"v": 5, "type": "info", "arg": "big-chungus", "arg[]": ["chungy-chungus"]} with client as request: resp = request.post("/rpc", data=data) assert resp.status_code == int(HTTPStatus.OK) assert resp.json().get("resultcount") == 2 -def test_rpc_too_many_search_results(client: TestClient, - packages: list[Package]): +def test_rpc_too_many_search_results(client: TestClient, packages: list[Package]): config_getint = config.getint def mock_config(section: str, key: str): @@ -858,10 +908,18 @@ def test_rpc_too_many_info_results(client: TestClient, packages: list[Package]): # regardless of the number of related records. with db.begin(): for i in range(len(packages) - 1): - db.create(PackageDependency, DepTypeID=DEPENDS_ID, - Package=packages[i], DepName=packages[i + 1].Name) - db.create(PackageRelation, RelTypeID=PROVIDES_ID, - Package=packages[i], RelName=packages[i + 1].Name) + db.create( + PackageDependency, + DepTypeID=DEPENDS_ID, + Package=packages[i], + DepName=packages[i + 1].Name, + ) + db.create( + PackageRelation, + RelTypeID=PROVIDES_ID, + Package=packages[i], + RelName=packages[i + 1].Name, + ) config_getint = config.getint diff --git a/test/test_rss.py b/test/test_rss.py index cef6a46f..8526caa1 100644 --- a/test/test_rss.py +++ b/test/test_rss.py @@ -2,7 +2,6 @@ from http import HTTPStatus import lxml.etree import pytest - from fastapi.testclient import TestClient from aurweb import db, logging, time @@ -27,13 +26,15 @@ def client(): @pytest.fixture def user(): - account_type = db.query(AccountType, - AccountType.AccountType == "User").first() - yield db.create(User, Username="test", - Email="test@example.org", - RealName="Test User", - Passwd="testPassword", - AccountType=account_type) + account_type = db.query(AccountType, AccountType.AccountType == "User").first() + yield db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountType=account_type, + ) @pytest.fixture @@ -45,8 +46,12 @@ def packages(user): with db.begin(): for i in range(101): pkgbase = db.create( - PackageBase, Maintainer=user, Name=f"test-package-{i}", - SubmittedTS=(now + i), ModifiedTS=(now + i)) + PackageBase, + Maintainer=user, + Name=f"test-package-{i}", + SubmittedTS=(now + i), + ModifiedTS=(now + i), + ) pkg = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase) pkgs.append(pkg) yield pkgs @@ -64,6 +69,7 @@ def test_rss(client, user, packages): # Test that the RSS we got is sorted by descending SubmittedTS. def key_(pkg): return pkg.PackageBase.SubmittedTS + packages = list(reversed(sorted(packages, key=key_))) # Just take the first 100. @@ -74,7 +80,7 @@ def test_rss(client, user, packages): assert len(items) == 100 for i, item in enumerate(items): - title = next(iter(item.xpath('./title'))) + title = next(iter(item.xpath("./title"))) logger.debug(f"title: '{title.text}' vs name: '{packages[i].Name}'") assert title.text == packages[i].Name @@ -87,6 +93,7 @@ def test_rss_modified(client, user, packages): # Test that the RSS we got is sorted by descending SubmittedTS. def key_(pkg): return pkg.PackageBase.ModifiedTS + packages = list(reversed(sorted(packages, key=key_))) # Just take the first 100. @@ -97,6 +104,6 @@ def test_rss_modified(client, user, packages): assert len(items) == 100 for i, item in enumerate(items): - title = next(iter(item.xpath('./title'))) + title = next(iter(item.xpath("./title"))) logger.debug(f"title: '{title.text}' vs name: '{packages[i].Name}'") assert title.text == packages[i].Name diff --git a/test/test_session.py b/test/test_session.py index edae57f9..db792b33 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -2,7 +2,6 @@ from unittest import mock import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db, time @@ -19,17 +18,23 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - ResetKey="testReset", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + ResetKey="testReset", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def session(user: User) -> Session: with db.begin(): - session = db.create(Session, User=user, SessionID="testSession", - LastUpdateTS=time.utcnow()) + session = db.create( + Session, User=user, SessionID="testSession", LastUpdateTS=time.utcnow() + ) yield session @@ -39,15 +44,21 @@ def test_session(user: User, session: Session): def test_session_cs(): - """ Test case sensitivity of the database table. """ + """Test case sensitivity of the database table.""" with db.begin(): - user2 = db.create(User, Username="test2", Email="test2@example.org", - ResetKey="testReset2", Passwd="testPassword", - AccountTypeID=USER_ID) + user2 = db.create( + User, + Username="test2", + Email="test2@example.org", + ResetKey="testReset2", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) with db.begin(): - session_cs = db.create(Session, User=user2, SessionID="TESTSESSION", - LastUpdateTS=time.utcnow()) + session_cs = db.create( + Session, User=user2, SessionID="TESTSESSION", LastUpdateTS=time.utcnow() + ) assert session_cs.SessionID == "TESTSESSION" assert session_cs.SessionID != "testSession" diff --git a/test/test_spawn.py b/test/test_spawn.py index 195eb897..be1c5e7c 100644 --- a/test/test_spawn.py +++ b/test/test_spawn.py @@ -1,6 +1,5 @@ import os import tempfile - from typing import Tuple from unittest import mock @@ -8,26 +7,21 @@ import pytest import aurweb.config import aurweb.spawn - from aurweb.exceptions import AurwebException # Some os.environ overrides we use in this suite. -TEST_ENVIRONMENT = { - "PHP_NGINX_PORT": "8001", - "FASTAPI_NGINX_PORT": "8002" -} +TEST_ENVIRONMENT = {"PHP_NGINX_PORT": "8001", "FASTAPI_NGINX_PORT": "8002"} class FakeProcess: - """ Fake a subprocess.Popen return object. """ + """Fake a subprocess.Popen return object.""" returncode = 0 - stdout = b'' - stderr = b'' + stdout = b"" + stderr = b"" def __init__(self, *args, **kwargs): - """ We need this constructor to remain compatible with Popen. """ - pass + """We need this constructor to remain compatible with Popen.""" def communicate(self) -> Tuple[bytes, bytes]: return (self.stdout, self.stderr) @@ -40,10 +34,9 @@ class FakeProcess: class MockFakeProcess: - """ FakeProcess construction helper to be used in mocks. """ + """FakeProcess construction helper to be used in mocks.""" - def __init__(self, return_code: int = 0, stdout: bytes = b'', - stderr: bytes = b''): + def __init__(self, return_code: int = 0, stdout: bytes = b"", stderr: bytes = b""): self.returncode = return_code self.stdout = stdout self.stderr = stderr @@ -101,7 +94,7 @@ def test_spawn_generate_nginx_config(): f'listen {php_host}:{TEST_ENVIRONMENT.get("PHP_NGINX_PORT")}', f"proxy_pass http://{php_address}", f'listen {fastapi_host}:{TEST_ENVIRONMENT.get("FASTAPI_NGINX_PORT")}', - f"proxy_pass http://{fastapi_address}" + f"proxy_pass http://{fastapi_address}", ] for expected in expected_content: assert expected in nginx_config diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py index 93298a11..1a586800 100644 --- a/test/test_ssh_pub_key.py +++ b/test/test_ssh_pub_key.py @@ -27,18 +27,23 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user @pytest.fixture def pubkey(user: User) -> SSHPubKey: with db.begin(): - pubkey = db.create(SSHPubKey, User=user, - Fingerprint="testFingerprint", - PubKey="testPubKey") + pubkey = db.create( + SSHPubKey, User=user, Fingerprint="testFingerprint", PubKey="testPubKey" + ) yield pubkey @@ -50,11 +55,11 @@ def test_pubkey(user: User, pubkey: SSHPubKey): def test_pubkey_cs(user: User): - """ Test case sensitivity of the database table. """ + """Test case sensitivity of the database table.""" with db.begin(): - pubkey_cs = db.create(SSHPubKey, User=user, - Fingerprint="TESTFINGERPRINT", - PubKey="TESTPUBKEY") + pubkey_cs = db.create( + SSHPubKey, User=user, Fingerprint="TESTFINGERPRINT", PubKey="TESTPUBKEY" + ) assert pubkey_cs.Fingerprint == "TESTFINGERPRINT" assert pubkey_cs.Fingerprint != "testFingerprint" diff --git a/test/test_templates.py b/test/test_templates.py index 4b138567..383f45d1 100644 --- a/test/test_templates.py +++ b/test/test_templates.py @@ -1,21 +1,23 @@ import re - from typing import Any import pytest import aurweb.filters # noqa: F401 - from aurweb import config, db, templates, time -from aurweb.filters import as_timezone, number_format -from aurweb.filters import timestamp_to_datetime as to_dt +from aurweb.filters import as_timezone, number_format, timestamp_to_datetime as to_dt from aurweb.models import Package, PackageBase, User from aurweb.models.account_type import USER_ID from aurweb.models.license import License from aurweb.models.package_license import PackageLicense from aurweb.models.package_relation import PackageRelation from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID -from aurweb.templates import base_template, make_context, register_filter, register_function +from aurweb.templates import ( + base_template, + make_context, + register_filter, + register_function, +) from aurweb.testing.html import parse_root from aurweb.testing.requests import Request @@ -35,19 +37,20 @@ def function(): def create_user(username: str) -> User: with db.begin(): - user = db.create(User, Username=username, - Email=f"{username}@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID) + user = db.create( + User, + Username=username, + Email=f"{username}@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) return user -def create_pkgrel(package: Package, reltype_id: int, relname: str) \ - -> PackageRelation: - return db.create(PackageRelation, - Package=package, - RelTypeID=reltype_id, - RelName=relname) +def create_pkgrel(package: Package, reltype_id: int, relname: str) -> PackageRelation: + return db.create( + PackageRelation, Package=package, RelTypeID=reltype_id, RelName=relname + ) @pytest.fixture @@ -60,8 +63,13 @@ def user(db_test) -> User: def pkgbase(user: User) -> PackageBase: now = time.utcnow() with db.begin(): - pkgbase = db.create(PackageBase, Name="test-pkg", Maintainer=user, - SubmittedTS=now, ModifiedTS=now) + pkgbase = db.create( + PackageBase, + Name="test-pkg", + Maintainer=user, + SubmittedTS=now, + ModifiedTS=now, + ) yield pkgbase @@ -79,9 +87,10 @@ def create_license(pkg: Package, license_name: str) -> PackageLicense: def test_register_function_exists_key_error(): - """ Most instances of register_filter are tested through module - imports or template renders, so we only test failures here. """ + """Most instances of register_filter are tested through module + imports or template renders, so we only test failures here.""" with pytest.raises(KeyError): + @register_function("function") def some_func(): pass @@ -93,8 +102,9 @@ def test_commit_hash(): commit_hash = "abcdefg" long_commit_hash = commit_hash + "1234567" - def config_get_with_fallback(section: str, option: str, - fallback: str = None) -> str: + def config_get_with_fallback( + section: str, option: str, fallback: str = None + ) -> str: if section == "devel" and option == "commit_hash": return long_commit_hash return config.original_get_with_fallback(section, option, fallback) @@ -134,12 +144,12 @@ def pager_context(num_packages: int) -> dict[str, Any]: "prefix": "/packages", "total": num_packages, "O": 0, - "PP": 50 + "PP": 50, } def test_pager_no_results(): - """ Test the pager partial with no results. """ + """Test the pager partial with no results.""" num_packages = 0 context = pager_context(num_packages) body = base_template("partials/pager.html").render(context) @@ -151,7 +161,7 @@ def test_pager_no_results(): def test_pager(): - """ Test the pager partial with two pages of results. """ + """Test the pager partial with two pages of results.""" num_packages = 100 context = pager_context(num_packages) body = base_template("partials/pager.html").render(context) @@ -274,17 +284,19 @@ def check_package_details(content: str, pkg: Package) -> None: def test_package_details(user: User, package: Package): - """ Test package details with most fields populated, but not all. """ + """Test package details with most fields populated, but not all.""" request = Request(user=user, authenticated=True) context = make_context(request, "Test Details") - context.update({ - "request": request, - "git_clone_uri_anon": GIT_CLONE_URI_ANON, - "git_clone_uri_priv": GIT_CLONE_URI_PRIV, - "pkgbase": package.PackageBase, - "pkg": package, - "comaintainers": [], - }) + context.update( + { + "request": request, + "git_clone_uri_anon": GIT_CLONE_URI_ANON, + "git_clone_uri_priv": GIT_CLONE_URI_PRIV, + "pkgbase": package.PackageBase, + "pkg": package, + "comaintainers": [], + } + ) base = base_template("partials/packages/details.html") body = base.render(context, show_package_details=True) @@ -292,7 +304,7 @@ def test_package_details(user: User, package: Package): def test_package_details_filled(user: User, package: Package): - """ Test package details with all fields populated. """ + """Test package details with all fields populated.""" pkgbase = package.PackageBase with db.begin(): @@ -311,19 +323,23 @@ def test_package_details_filled(user: User, package: Package): request = Request(user=user, authenticated=True) context = make_context(request, "Test Details") - context.update({ - "request": request, - "git_clone_uri_anon": GIT_CLONE_URI_ANON, - "git_clone_uri_priv": GIT_CLONE_URI_PRIV, - "pkgbase": package.PackageBase, - "pkg": package, - "comaintainers": [], - "licenses": package.package_licenses, - "provides": package.package_relations.filter( - PackageRelation.RelTypeID == PROVIDES_ID), - "replaces": package.package_relations.filter( - PackageRelation.RelTypeID == REPLACES_ID), - }) + context.update( + { + "request": request, + "git_clone_uri_anon": GIT_CLONE_URI_ANON, + "git_clone_uri_priv": GIT_CLONE_URI_PRIV, + "pkgbase": package.PackageBase, + "pkg": package, + "comaintainers": [], + "licenses": package.package_licenses, + "provides": package.package_relations.filter( + PackageRelation.RelTypeID == PROVIDES_ID + ), + "replaces": package.package_relations.filter( + PackageRelation.RelTypeID == REPLACES_ID + ), + } + ) base = base_template("partials/packages/details.html") body = base.render(context, show_package_details=True) diff --git a/test/test_term.py b/test/test_term.py index bfa73a76..4b608a9a 100644 --- a/test/test_term.py +++ b/test/test_term.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db @@ -13,8 +12,9 @@ def setup(db_test): def test_term_creation(): with db.begin(): - term = db.create(Term, Description="Term description", - URL="https://fake_url.io") + term = db.create( + Term, Description="Term description", URL="https://fake_url.io" + ) assert bool(term.ID) assert term.Description == "Term description" assert term.URL == "https://fake_url.io" diff --git a/test/test_time.py b/test/test_time.py index 2134d217..db7b30bf 100644 --- a/test/test_time.py +++ b/test/test_time.py @@ -1,5 +1,4 @@ import aurweb.config - from aurweb.testing.requests import Request from aurweb.time import get_request_timezone, tz_offset diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index 2e7dc193..203008e3 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -1,12 +1,10 @@ import re - from http import HTTPStatus from io import StringIO from typing import Tuple import lxml.etree import pytest - from fastapi.testclient import TestClient from aurweb import config, db, filters, time @@ -16,8 +14,8 @@ from aurweb.models.tu_voteinfo import TUVoteInfo from aurweb.models.user import User from aurweb.testing.requests import Request -DATETIME_REGEX = r'^[0-9]{4}-[0-9]{2}-[0-9]{2} \(.+\)$' -PARTICIPATION_REGEX = r'^1?[0-9]{2}[%]$' # 0% - 100% +DATETIME_REGEX = r"^[0-9]{4}-[0-9]{2}-[0-9]{2} \(.+\)$" +PARTICIPATION_REGEX = r"^1?[0-9]{2}[%]$" # 0% - 100% def parse_root(html): @@ -43,11 +41,11 @@ def get_pkglist_directions(table): def get_a(node): - return node.xpath('./a')[0].text.strip() + return node.xpath("./a")[0].text.strip() def get_span(node): - return node.xpath('./span')[0].text.strip() + return node.xpath("./span")[0].text.strip() def assert_current_vote_html(row, expected): @@ -82,39 +80,51 @@ def setup(db_test): @pytest.fixture def client(): from aurweb.asgi import app + yield TestClient(app=app) @pytest.fixture def tu_user(): - tu_type = db.query(AccountType, - AccountType.AccountType == "Trusted User").first() + tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first() with db.begin(): - tu_user = db.create(User, Username="test_tu", - Email="test_tu@example.org", - RealName="Test TU", Passwd="testPassword", - AccountType=tu_type) + tu_user = db.create( + User, + Username="test_tu", + Email="test_tu@example.org", + RealName="Test TU", + Passwd="testPassword", + AccountType=tu_type, + ) yield tu_user @pytest.fixture def tu_user2(): with db.begin(): - tu_user2 = db.create(User, Username="test_tu2", - Email="test_tu2@example.org", - RealName="Test TU 2", Passwd="testPassword", - AccountTypeID=TRUSTED_USER_ID) + tu_user2 = db.create( + User, + Username="test_tu2", + Email="test_tu2@example.org", + RealName="Test TU 2", + Passwd="testPassword", + AccountTypeID=TRUSTED_USER_ID, + ) yield tu_user2 @pytest.fixture def user(): - user_type = db.query(AccountType, - AccountType.AccountType == "User").first() + user_type = db.query(AccountType, AccountType.AccountType == "User").first() with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountType=user_type) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountType=user_type, + ) yield user @@ -126,10 +136,15 @@ def proposal(user, tu_user): end = ts + 1000 with db.begin(): - voteinfo = db.create(TUVoteInfo, - Agenda=agenda, Quorum=0.0, - User=user.Username, Submitter=tu_user, - Submitted=start, End=end) + voteinfo = db.create( + TUVoteInfo, + Agenda=agenda, + Quorum=0.0, + User=user.Username, + Submitter=tu_user, + Submitted=start, + End=end, + ) yield (tu_user, user, voteinfo) @@ -153,7 +168,7 @@ def test_tu_index_unauthorized(client: TestClient, user: User): def test_tu_empty_index(client, tu_user): - """ Check an empty index when we don't create any records. """ + """Check an empty index when we don't create any records.""" # Make a default get request to /tu. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} @@ -179,18 +194,23 @@ def test_tu_index(client, tu_user): # Create some test votes: (Agenda, Start, End). votes = [ ("Test agenda 1", ts - 5, ts + 1000), # Still running. - ("Test agenda 2", ts - 1000, ts - 5) # Not running anymore. + ("Test agenda 2", ts - 1000, ts - 5), # Not running anymore. ] vote_records = [] with db.begin(): for vote in votes: agenda, start, end = vote vote_records.append( - db.create(TUVoteInfo, Agenda=agenda, - User=tu_user.Username, - Submitted=start, End=end, - Quorum=0.0, - Submitter=tu_user)) + db.create( + TUVoteInfo, + Agenda=agenda, + User=tu_user.Username, + Submitted=start, + End=end, + Quorum=0.0, + Submitter=tu_user, + ) + ) with db.begin(): # Vote on an ended proposal. @@ -202,21 +222,23 @@ def test_tu_index(client, tu_user): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: # Pass an invalid cby and pby; let them default to "desc". - response = request.get("/tu", cookies=cookies, params={ - "cby": "BAD!", - "pby": "blah" - }, allow_redirects=False) + response = request.get( + "/tu", + cookies=cookies, + params={"cby": "BAD!", "pby": "blah"}, + allow_redirects=False, + ) assert response.status_code == int(HTTPStatus.OK) # Rows we expect to exist in HTML produced by /tu for current votes. expected_rows = [ ( - r'Test agenda 1', + r"Test agenda 1", DATETIME_REGEX, DATETIME_REGEX, tu_user.Username, - r'^(Yes|No)$' + r"^(Yes|No)$", ) ] @@ -239,13 +261,13 @@ def test_tu_index(client, tu_user): # Rows we expect to exist in HTML produced by /tu for past votes. expected_rows = [ ( - r'Test agenda 2', + r"Test agenda 2", DATETIME_REGEX, DATETIME_REGEX, tu_user.Username, - r'^\d+$', - r'^\d+$', - r'^(Yes|No)$' + r"^\d+$", + r"^\d+$", + r"^(Yes|No)$", ) ] @@ -315,19 +337,27 @@ def test_tu_index_table_paging(client, tu_user): with db.begin(): for i in range(25): # Create 25 current votes. - db.create(TUVoteInfo, Agenda=f"Agenda #{i}", - User=tu_user.Username, - Submitted=(ts - 5), End=(ts + 1000), - Quorum=0.0, - Submitter=tu_user) + db.create( + TUVoteInfo, + Agenda=f"Agenda #{i}", + User=tu_user.Username, + Submitted=(ts - 5), + End=(ts + 1000), + Quorum=0.0, + Submitter=tu_user, + ) for i in range(25): # Create 25 past votes. - db.create(TUVoteInfo, Agenda=f"Agenda #{25 + i}", - User=tu_user.Username, - Submitted=(ts - 1000), End=(ts - 5), - Quorum=0.0, - Submitter=tu_user) + db.create( + TUVoteInfo, + Agenda=f"Agenda #{25 + i}", + User=tu_user.Username, + Submitted=(ts - 1000), + End=(ts - 5), + Quorum=0.0, + Submitter=tu_user, + ) cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: @@ -347,7 +377,7 @@ def test_tu_index_table_paging(client, tu_user): DATETIME_REGEX, DATETIME_REGEX, tu_user.Username, - r'^(Yes|No)$' + r"^(Yes|No)$", ] for i, row in enumerate(rows): @@ -361,9 +391,9 @@ def test_tu_index_table_paging(client, tu_user): # Now, get the next page of current votes. offset = 10 # Specify coff=10 with client as request: - response = request.get("/tu", cookies=cookies, params={ - "coff": offset - }, allow_redirects=False) + response = request.get( + "/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) old_rows = rows @@ -390,9 +420,9 @@ def test_tu_index_table_paging(client, tu_user): offset = 20 # Specify coff=10 with client as request: - response = request.get("/tu", cookies=cookies, params={ - "coff": offset - }, allow_redirects=False) + response = request.get( + "/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) # Do it again, we only have five left. @@ -423,11 +453,15 @@ def test_tu_index_sorting(client, tu_user): with db.begin(): for i in range(2): # Create 'Agenda #1' and 'Agenda #2'. - db.create(TUVoteInfo, Agenda=f"Agenda #{i + 1}", - User=tu_user.Username, - Submitted=(ts + 5), End=(ts + 1000), - Quorum=0.0, - Submitter=tu_user) + db.create( + TUVoteInfo, + Agenda=f"Agenda #{i + 1}", + User=tu_user.Username, + Submitted=(ts + 5), + End=(ts + 1000), + Quorum=0.0, + Submitter=tu_user, + ) # Let's order each vote one day after the other. # This will allow us to test the sorting nature @@ -446,27 +480,27 @@ def test_tu_index_sorting(client, tu_user): rows = get_table_rows(table) # The latest Agenda is at the top by default. - expected = [ - "Agenda #2", - "Agenda #1" - ] + expected = ["Agenda #2", "Agenda #1"] assert len(rows) == len(expected) for i, row in enumerate(rows): - assert_current_vote_html(row, [ - expected[i], - DATETIME_REGEX, - DATETIME_REGEX, - tu_user.Username, - r'^(Yes|No)$' - ]) + assert_current_vote_html( + row, + [ + expected[i], + DATETIME_REGEX, + DATETIME_REGEX, + tu_user.Username, + r"^(Yes|No)$", + ], + ) # Make another request; one that sorts the current votes # in ascending order instead of the default descending order. with client as request: - response = request.get("/tu", cookies=cookies, params={ - "cby": "asc" - }, allow_redirects=False) + response = request.get( + "/tu", cookies=cookies, params={"cby": "asc"}, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) # Get lxml handles of the document. @@ -478,30 +512,37 @@ def test_tu_index_sorting(client, tu_user): rev_expected = list(reversed(expected)) assert len(rows) == len(rev_expected) for i, row in enumerate(rows): - assert_current_vote_html(row, [ - rev_expected[i], - DATETIME_REGEX, - DATETIME_REGEX, - tu_user.Username, - r'^(Yes|No)$' - ]) + assert_current_vote_html( + row, + [ + rev_expected[i], + DATETIME_REGEX, + DATETIME_REGEX, + tu_user.Username, + r"^(Yes|No)$", + ], + ) -def test_tu_index_last_votes(client: TestClient, tu_user: User, tu_user2: User, - user: User): +def test_tu_index_last_votes( + client: TestClient, tu_user: User, tu_user2: User, user: User +): ts = time.utcnow() with db.begin(): # Create a proposal which has ended. - voteinfo = db.create(TUVoteInfo, Agenda="Test agenda", - User=user.Username, - Submitted=(ts - 1000), - End=(ts - 5), - Yes=1, - No=1, - ActiveTUs=1, - Quorum=0.0, - Submitter=tu_user) + voteinfo = db.create( + TUVoteInfo, + Agenda="Test agenda", + User=user.Username, + Submitted=(ts - 1000), + End=(ts - 5), + Yes=1, + No=1, + ActiveTUs=1, + Quorum=0.0, + Submitter=tu_user, + ) # Create a vote on it from tu_user. db.create(TUVote, VoteInfo=voteinfo, User=tu_user) @@ -536,26 +577,27 @@ def test_tu_proposal_not_found(client, tu_user): assert response.status_code == int(HTTPStatus.NOT_FOUND) -def test_tu_proposal_unauthorized(client: TestClient, user: User, - proposal: Tuple[User, User, TUVoteInfo]): +def test_tu_proposal_unauthorized( + client: TestClient, user: User, proposal: Tuple[User, User, TUVoteInfo] +): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/tu/{proposal[2].ID}" with client as request: - response = request.get(endpoint, cookies=cookies, - allow_redirects=False) + response = request.get(endpoint, cookies=cookies, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" with client as request: - response = request.post(endpoint, cookies=cookies, - data={"decision": False}, - allow_redirects=False) + response = request.post( + endpoint, cookies=cookies, data={"decision": False}, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" -def test_tu_running_proposal(client: TestClient, - proposal: Tuple[User, User, TUVoteInfo]): +def test_tu_running_proposal( + client: TestClient, proposal: Tuple[User, User, TUVoteInfo] +): tu_user, user, voteinfo = proposal with db.begin(): voteinfo.ActiveTUs = 1 @@ -576,8 +618,7 @@ def test_tu_running_proposal(client: TestClient, assert vote_running.text.strip() == "This vote is still running." # Verify User field. - username = details.xpath( - './div[contains(@class, "user")]/strong/a/text()')[0] + username = details.xpath('./div[contains(@class, "user")]/strong/a/text()')[0] assert username.strip() == user.Username active = details.xpath('./div[contains(@class, "field")]')[1] @@ -585,10 +626,13 @@ def test_tu_running_proposal(client: TestClient, assert "Active Trusted Users assigned:" in content assert "1" in content - submitted = details.xpath( - './div[contains(@class, "submitted")]/text()')[0] - assert re.match(r'^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$', - submitted.strip()) is not None + submitted = details.xpath('./div[contains(@class, "submitted")]/text()')[0] + assert ( + re.match( + r"^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$", submitted.strip() + ) + is not None + ) submitter = details.xpath('./div[contains(@class, "submitted")]/a')[0] assert submitter.text.strip() == tu_user.Username assert submitter.attrib["href"] == f"/account/{tu_user.Username}" @@ -598,8 +642,10 @@ def test_tu_running_proposal(client: TestClient, assert end_label.strip() == "End:" end_datetime = end.xpath("./strong/text()")[0] - assert re.match(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\)$', - end_datetime.strip()) is not None + assert ( + re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\)$", end_datetime.strip()) + is not None + ) # We have not voted yet. Assert that our voting form is shown. form = root.xpath('//form[contains(@class, "action-form")]')[0] @@ -630,8 +676,7 @@ def test_tu_running_proposal(client: TestClient, # Make another request now that we've voted. with client as request: - response = request.get( - "/tu", params={"id": voteinfo.ID}, cookies=cookies) + response = request.get("/tu", params={"id": voteinfo.ID}, cookies=cookies) assert response.status_code == int(HTTPStatus.OK) # Parse our new root. @@ -685,12 +730,13 @@ def test_tu_ended_proposal(client, proposal): def test_tu_proposal_vote_not_found(client, tu_user): - """ Test POST request to a missing vote. """ + """Test POST request to a missing vote.""" cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post("/tu/1", cookies=cookies, - data=data, allow_redirects=False) + response = request.post( + "/tu/1", cookies=cookies, data=data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -703,16 +749,14 @@ def test_tu_proposal_vote(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data) + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) assert response.status_code == int(HTTPStatus.OK) # Check that the proposal record got updated. assert voteinfo.Yes == yes + 1 # Check that the new TUVote exists. - vote = db.query(TUVote, TUVote.VoteInfo == voteinfo, - TUVote.User == tu_user).first() + vote = db.query(TUVote, TUVote.VoteInfo == voteinfo, TUVote.User == tu_user).first() assert vote is not None root = parse_root(response.text) @@ -723,7 +767,8 @@ def test_tu_proposal_vote(client, proposal): def test_tu_proposal_vote_unauthorized( - client: TestClient, proposal: Tuple[User, User, TUVoteInfo]): + client: TestClient, proposal: Tuple[User, User, TUVoteInfo] +): tu_user, user, voteinfo = proposal with db.begin(): @@ -732,8 +777,9 @@ def test_tu_proposal_vote_unauthorized( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data, allow_redirects=False) + response = request.post( + f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.UNAUTHORIZED) root = parse_root(response.text) @@ -742,8 +788,9 @@ def test_tu_proposal_vote_unauthorized( with client as request: data = {"decision": "Yes"} - response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data, allow_redirects=False) + response = request.get( + f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -761,8 +808,9 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data, allow_redirects=False) + response = request.post( + f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.BAD_REQUEST) root = parse_root(response.text) @@ -771,8 +819,9 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): with client as request: data = {"decision": "Yes"} - response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data, allow_redirects=False) + response = request.get( + f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -791,8 +840,9 @@ def test_tu_proposal_vote_already_voted(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data, allow_redirects=False) + response = request.post( + f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.BAD_REQUEST) root = parse_root(response.text) @@ -801,8 +851,9 @@ def test_tu_proposal_vote_already_voted(client, proposal): with client as request: data = {"decision": "Yes"} - response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data, allow_redirects=False) + response = request.get( + f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False + ) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -816,8 +867,7 @@ def test_tu_proposal_vote_invalid_decision(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "EVIL"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, - data=data) + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) assert response.text == "Invalid 'decision' value." @@ -829,18 +879,17 @@ def test_tu_addvote(client: TestClient, tu_user: User): assert response.status_code == int(HTTPStatus.OK) -def test_tu_addvote_unauthorized(client: TestClient, user: User, - proposal: Tuple[User, User, TUVoteInfo]): +def test_tu_addvote_unauthorized( + client: TestClient, user: User, proposal: Tuple[User, User, TUVoteInfo] +): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.get("/addvote", cookies=cookies, - allow_redirects=False) + response = request.get("/addvote", cookies=cookies, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" with client as request: - response = request.post("/addvote", cookies=cookies, - allow_redirects=False) + response = request.post("/addvote", cookies=cookies, allow_redirects=False) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" @@ -848,8 +897,7 @@ def test_tu_addvote_unauthorized(client: TestClient, user: User, def test_tu_addvote_invalid_type(client: TestClient, tu_user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/addvote", params={"type": "faketype"}, - cookies=cookies) + response = request.get("/addvote", params={"type": "faketype"}, cookies=cookies) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -860,11 +908,7 @@ def test_tu_addvote_invalid_type(client: TestClient, tu_user: User): def test_tu_addvote_post(client: TestClient, tu_user: User, user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} - data = { - "user": user.Username, - "type": "add_tu", - "agenda": "Blah" - } + data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"} with client as request: response = request.post("/addvote", cookies=cookies, data=data) @@ -874,15 +918,12 @@ def test_tu_addvote_post(client: TestClient, tu_user: User, user: User): assert voteinfo is not None -def test_tu_addvote_post_cant_duplicate_username(client: TestClient, - tu_user: User, user: User): +def test_tu_addvote_post_cant_duplicate_username( + client: TestClient, tu_user: User, user: User +): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} - data = { - "user": user.Username, - "type": "add_tu", - "agenda": "Blah" - } + data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"} with client as request: response = request.post("/addvote", cookies=cookies, data=data) @@ -904,8 +945,7 @@ def test_tu_addvote_post_invalid_username(client: TestClient, tu_user: User): assert response.status_code == int(HTTPStatus.NOT_FOUND) -def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User, - user: User): +def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User, user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} data = {"user": user.Username} with client as request: @@ -913,8 +953,7 @@ def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User, assert response.status_code == int(HTTPStatus.BAD_REQUEST) -def test_tu_addvote_post_invalid_agenda(client: TestClient, - tu_user: User, user: User): +def test_tu_addvote_post_invalid_agenda(client: TestClient, tu_user: User, user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} data = {"user": user.Username, "type": "add_tu"} with client as request: diff --git a/test/test_tu_vote.py b/test/test_tu_vote.py index 91d73ecb..8c1c08de 100644 --- a/test/test_tu_vote.py +++ b/test/test_tu_vote.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db, time @@ -17,9 +16,14 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=TRUSTED_USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=TRUSTED_USER_ID, + ) yield user @@ -27,10 +31,15 @@ def user() -> User: def tu_voteinfo(user: User) -> TUVoteInfo: ts = time.utcnow() with db.begin(): - tu_voteinfo = db.create(TUVoteInfo, Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 5, - Quorum=0.5, Submitter=user) + tu_voteinfo = db.create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, + End=ts + 5, + Quorum=0.5, + Submitter=user, + ) yield tu_voteinfo diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py index 17226048..34845b86 100644 --- a/test/test_tu_voteinfo.py +++ b/test/test_tu_voteinfo.py @@ -1,5 +1,4 @@ import pytest - from sqlalchemy.exc import IntegrityError from aurweb import db, time @@ -17,21 +16,29 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=TRUSTED_USER_ID) + user = create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=TRUSTED_USER_ID, + ) yield user def test_tu_voteinfo_creation(user: User): ts = time.utcnow() with db.begin(): - tu_voteinfo = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 5, - Quorum=0.5, - Submitter=user) + tu_voteinfo = create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, + End=ts + 5, + Quorum=0.5, + Submitter=user, + ) assert bool(tu_voteinfo.ID) assert tu_voteinfo.Agenda == "Blah blah." assert tu_voteinfo.User == user.Username @@ -50,12 +57,15 @@ def test_tu_voteinfo_creation(user: User): def test_tu_voteinfo_is_running(user: User): ts = time.utcnow() with db.begin(): - tu_voteinfo = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 1000, - Quorum=0.5, - Submitter=user) + tu_voteinfo = create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, + End=ts + 1000, + Quorum=0.5, + Submitter=user, + ) assert tu_voteinfo.is_running() is True with db.begin(): @@ -66,12 +76,15 @@ def test_tu_voteinfo_is_running(user: User): def test_tu_voteinfo_total_votes(user: User): ts = time.utcnow() with db.begin(): - tu_voteinfo = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=ts, End=ts + 1000, - Quorum=0.5, - Submitter=user) + tu_voteinfo = create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=ts, + End=ts + 1000, + Quorum=0.5, + Submitter=user, + ) tu_voteinfo.Yes = 1 tu_voteinfo.No = 3 @@ -84,65 +97,81 @@ def test_tu_voteinfo_total_votes(user: User): def test_tu_voteinfo_null_submitter_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): - create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=0, End=0, - Quorum=0.50) + create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, + End=0, + Quorum=0.50, + ) rollback() def test_tu_voteinfo_null_agenda_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): - create(TUVoteInfo, - User=user.Username, - Submitted=0, End=0, - Quorum=0.50, - Submitter=user) + create( + TUVoteInfo, + User=user.Username, + Submitted=0, + End=0, + Quorum=0.50, + Submitter=user, + ) rollback() def test_tu_voteinfo_null_user_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): - create(TUVoteInfo, - Agenda="Blah blah.", - Submitted=0, End=0, - Quorum=0.50, - Submitter=user) + create( + TUVoteInfo, + Agenda="Blah blah.", + Submitted=0, + End=0, + Quorum=0.50, + Submitter=user, + ) rollback() def test_tu_voteinfo_null_submitted_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): - create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - End=0, - Quorum=0.50, - Submitter=user) + create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + End=0, + Quorum=0.50, + Submitter=user, + ) rollback() def test_tu_voteinfo_null_end_raises(user: User): with pytest.raises(IntegrityError): with db.begin(): - create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=0, - Quorum=0.50, - Submitter=user) + create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, + Quorum=0.50, + Submitter=user, + ) rollback() def test_tu_voteinfo_null_quorum_default(user: User): with db.begin(): - vi = create(TUVoteInfo, - Agenda="Blah blah.", - User=user.Username, - Submitted=0, End=0, - Submitter=user) + vi = create( + TUVoteInfo, + Agenda="Blah blah.", + User=user.Username, + Submitted=0, + End=0, + Submitter=user, + ) assert vi.Quorum == 0 diff --git a/test/test_tuvotereminder.py b/test/test_tuvotereminder.py index a54c52a4..0233c8b2 100644 --- a/test/test_tuvotereminder.py +++ b/test/test_tuvotereminder.py @@ -19,8 +19,13 @@ def create_vote(user: User, voteinfo: TUVoteInfo) -> TUVote: def create_user(username: str, type_id: int): with db.begin(): - user = db.create(User, AccountTypeID=type_id, Username=username, - Email=f"{username}@example.org", Passwd=str()) + user = db.create( + User, + AccountTypeID=type_id, + Username=username, + Email=f"{username}@example.org", + Passwd=str(), + ) return user @@ -32,9 +37,11 @@ def email_pieces(voteinfo: TUVoteInfo) -> Tuple[str, str]: :return: tuple(subject, content) """ subject = f"TU Vote Reminder: Proposal {voteinfo.ID}" - content = (f"Please remember to cast your vote on proposal {voteinfo.ID} " - f"[1]. The voting period\nends in less than 48 hours.\n\n" - f"[1] {aur_location}/tu/?id={voteinfo.ID}") + content = ( + f"Please remember to cast your vote on proposal {voteinfo.ID} " + f"[1]. The voting period\nends in less than 48 hours.\n\n" + f"[1] {aur_location}/tu/?id={voteinfo.ID}" + ) return (subject, content) @@ -58,14 +65,19 @@ def voteinfo(user: User) -> TUVoteInfo: now = time.utcnow() start = config.getint("tuvotereminder", "range_start") with db.begin(): - voteinfo = db.create(TUVoteInfo, Agenda="Lorem ipsum.", - User=user.Username, End=(now + start + 1), - Quorum=0.00, Submitter=user, Submitted=0) + voteinfo = db.create( + TUVoteInfo, + Agenda="Lorem ipsum.", + User=user.Username, + End=(now + start + 1), + Quorum=0.00, + Submitter=user, + Submitted=0, + ) yield voteinfo -def test_tu_vote_reminders(user: User, user2: User, user3: User, - voteinfo: TUVoteInfo): +def test_tu_vote_reminders(user: User, user2: User, user3: User, voteinfo: TUVoteInfo): reminder.main() assert Email.count() == 3 @@ -75,7 +87,7 @@ def test_tu_vote_reminders(user: User, user2: User, user3: User, # (to, content) (user.Email, subject, content), (user2.Email, subject, content), - (user3.Email, subject, content) + (user3.Email, subject, content), ] for i, element in enumerate(expectations): email, subject, content = element @@ -84,8 +96,9 @@ def test_tu_vote_reminders(user: User, user2: User, user3: User, assert emails[i].body == content -def test_tu_vote_reminders_only_unvoted(user: User, user2: User, user3: User, - voteinfo: TUVoteInfo): +def test_tu_vote_reminders_only_unvoted( + user: User, user2: User, user3: User, voteinfo: TUVoteInfo +): # Vote with user2 and user3; leaving only user to be notified. create_vote(user2, voteinfo) create_vote(user3, voteinfo) diff --git a/test/test_user.py b/test/test_user.py index 5f25f3c9..17fd0c0e 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -1,6 +1,5 @@ import hashlib import json - from datetime import datetime, timedelta import bcrypt @@ -9,10 +8,14 @@ import pytest import aurweb.auth import aurweb.config import aurweb.models.account_type as at - from aurweb import db from aurweb.auth import creds -from aurweb.models.account_type import DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.models.account_type import ( + DEVELOPER_ID, + TRUSTED_USER_AND_DEV_ID, + TRUSTED_USER_ID, + USER_ID, +) from aurweb.models.ban import Ban from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -31,10 +34,14 @@ def setup(db_test): def create_user(username: str, account_type_id: int): with db.begin(): - user = db.create(User, Username=username, - Email=f"{username}@example.org", - RealName=username.title(), Passwd="testPassword", - AccountTypeID=account_type_id) + user = db.create( + User, + Username=username, + Email=f"{username}@example.org", + RealName=username.title(), + Passwd="testPassword", + AccountTypeID=account_type_id, + ) return user @@ -71,7 +78,7 @@ def package(user: User) -> Package: def test_user_login_logout(user: User): - """ Test creating a user and reading its columns. """ + """Test creating a user and reading its columns.""" # Assert that make_user created a valid user. assert bool(user.ID) @@ -89,8 +96,7 @@ def test_user_login_logout(user: User): assert user.is_authenticated() # Expect that User session relationships work right. - user_session = db.query(Session, - Session.UsersID == user.ID).first() + user_session = db.query(Session, Session.UsersID == user.ID).first() assert user_session == user.session assert user.session.SessionID == sid assert user.session.User == user @@ -111,8 +117,10 @@ def test_user_login_logout(user: User): assert result.is_authenticated() # Test out user string functions. - assert repr(user) == f"" + assert ( + repr(user) + == f"" + ) # Test logout. user.logout(request) @@ -145,9 +153,7 @@ def test_user_login_suspended(user: User): def test_legacy_user_authentication(user: User): with db.begin(): user.Salt = bcrypt.gensalt().decode() - user.Passwd = hashlib.md5( - f"{user.Salt}testPassword".encode() - ).hexdigest() + user.Passwd = hashlib.md5(f"{user.Salt}testPassword".encode()).hexdigest() assert not user.valid_password("badPassword") assert user.valid_password("testPassword") @@ -160,8 +166,12 @@ def test_user_login_with_outdated_sid(user: User): # Make a session with a LastUpdateTS 5 seconds ago, causing # user.login to update it with a new sid. with db.begin(): - db.create(Session, UsersID=user.ID, SessionID="stub", - LastUpdateTS=datetime.utcnow().timestamp() - 5) + db.create( + Session, + UsersID=user.ID, + SessionID="stub", + LastUpdateTS=datetime.utcnow().timestamp() - 5, + ) sid = user.login(Request(), "testPassword") assert sid and user.is_authenticated() assert sid != "stub" @@ -186,9 +196,12 @@ def test_user_ssh_pub_key(user: User): assert user.ssh_pub_keys.first() is None with db.begin(): - ssh_pub_key = db.create(SSHPubKey, UserID=user.ID, - Fingerprint="testFingerprint", - PubKey="testPubKey") + ssh_pub_key = db.create( + SSHPubKey, + UserID=user.ID, + Fingerprint="testFingerprint", + PubKey="testPubKey", + ) assert user.ssh_pub_keys.first() == ssh_pub_key @@ -283,8 +296,9 @@ def test_user_packages(user: User, package: Package): assert package in user.packages() -def test_can_edit_user(user: User, tu_user: User, dev_user: User, - tu_and_dev_user: User): +def test_can_edit_user( + user: User, tu_user: User, dev_user: User, tu_and_dev_user: User +): # User can edit. assert user.can_edit_user(user) diff --git a/test/test_usermaint.py b/test/test_usermaint.py index e572569a..7d7bd135 100644 --- a/test/test_usermaint.py +++ b/test/test_usermaint.py @@ -14,13 +14,18 @@ def setup(db_test): @pytest.fixture def user() -> User: with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - Passwd="testPassword", AccountTypeID=USER_ID) + user = db.create( + User, + Username="test", + Email="test@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) yield user def test_usermaint_noop(user: User): - """ Last[SSH]Login isn't expired in this test: usermaint is noop. """ + """Last[SSH]Login isn't expired in this test: usermaint is noop.""" now = time.utcnow() with db.begin(): diff --git a/test/test_util.py b/test/test_util.py index ae1de81b..686e35b4 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -1,10 +1,8 @@ import json - from http import HTTPStatus import fastapi import pytest - from fastapi.responses import JSONResponse from aurweb import filters, util @@ -18,7 +16,7 @@ def test_round(): def test_git_search(): - """ Test that git_search matches the full commit if necessary. """ + """Test that git_search matches the full commit if necessary.""" commit_hash = "0123456789abcdef" repo = {commit_hash} prefixlen = util.git_search(repo, commit_hash) @@ -26,7 +24,7 @@ def test_git_search(): def test_git_search_double_commit(): - """ Test that git_search matches a shorter prefix length. """ + """Test that git_search matches a shorter prefix length.""" commit_hash = "0123456789abcdef" repo = {commit_hash[:13]} # Locate the shortest prefix length that matches commit_hash. @@ -36,7 +34,6 @@ def test_git_search_double_commit(): @pytest.mark.asyncio async def test_error_or_result(): - async def route(request: fastapi.Request): raise RuntimeError("No response returned.") diff --git a/util/fix-coverage b/util/fix-coverage index 3446c4af..77cf29c1 100755 --- a/util/fix-coverage +++ b/util/fix-coverage @@ -48,9 +48,8 @@ def main(): files[i] = path for _, i in enumerate(files.keys()): - new_path = re.sub(r'^/aurweb', aurwebdir, files[i]) - cursor.execute("UPDATE file SET path = ? WHERE id = ?", ( - new_path, i)) + new_path = re.sub(r"^/aurweb", aurwebdir, files[i]) + cursor.execute("UPDATE file SET path = ? WHERE id = ?", (new_path, i)) db.commit() db.close() diff --git a/web/html/503.php b/web/html/503.php index 80eb4369..23e7014e 100644 --- a/web/html/503.php +++ b/web/html/503.php @@ -12,4 +12,3 @@ html_header( __("Service Unavailable") );
      - diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php index 05eeacb2..dc285a97 100644 --- a/web/template/flag_comment.php +++ b/web/template/flag_comment.php @@ -24,4 +24,3 @@

      - diff --git a/web/template/header.php b/web/template/header.php index afe7a9b6..9631be91 100644 --- a/web/template/header.php +++ b/web/template/header.php @@ -80,4 +80,3 @@
    - diff --git a/web/template/pkgreq_close_form.php b/web/template/pkgreq_close_form.php index 6077b325..6228f6ab 100644 --- a/web/template/pkgreq_close_form.php +++ b/web/template/pkgreq_close_form.php @@ -29,4 +29,3 @@
    - diff --git a/web/template/template.phps b/web/template/template.phps index 4f8117c8..f1a0bb0d 100644 --- a/web/template/template.phps +++ b/web/template/template.phps @@ -17,4 +17,3 @@ print __("Hi, this is worth reading!")."
    \n"; html_footer(AURWEB_VERSION); - From 505eb90479df1d14c3c2e64a90a40a1ef5815765 Mon Sep 17 00:00:00 2001 From: Joakim Saario Date: Sat, 20 Aug 2022 19:29:25 +0200 Subject: [PATCH 1555/1891] chore: Add .git-blame-ignore-revs file The idea is to exclude commits that only contains formatting so that it's easier to backtrack actual code changes with `git blame`. --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..d3c9887b --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# style: Run pre-commit +9c6c13b78a30cb9d800043410799e29631f803d2 From de5538a40f5d706a1f7dee7a2361be32ff2760c1 Mon Sep 17 00:00:00 2001 From: Joakim Saario Date: Sun, 21 Aug 2022 22:16:52 +0200 Subject: [PATCH 1556/1891] ci(lint): Use pre-commit --- .gitlab-ci.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 98f99ae3..7134673c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,18 +13,16 @@ variables: LOG_CONFIG: logging.test.conf lint: - variables: - # Space-separated list of directories that should be linted. - REQUIRES_LINT: "aurweb test migrations" stage: .pre before_script: - pacman -Sy --noconfirm --noprogressbar --cachedir .pkg-cache archlinux-keyring - pacman -Syu --noconfirm --noprogressbar --cachedir .pkg-cache - python python-isort flake8 + git python python-pre-commit script: - - bash -c 'flake8 --count $(echo "$REQUIRES_LINT" | xargs); exit $?' - - bash -c 'isort --check-only $(echo "$REQUIRES_LINT" | xargs); exit $?' + # https://github.com/pre-commit/pre-commit/issues/2178#issuecomment-1002163763 + - export SETUPTOOLS_USE_DISTUTILS=stdlib + - pre-commit run -a test: stage: test From ce5dbf0eebb58a5f9d39736a42a1558ff0ee8b64 Mon Sep 17 00:00:00 2001 From: Joakim Saario Date: Mon, 22 Aug 2022 22:30:25 +0200 Subject: [PATCH 1557/1891] docs(contributing): Update Coding Style --- CONTRIBUTING.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52e182c7..58612a36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,21 +31,27 @@ Test patches that increase coverage in the codebase are always welcome. ### Coding Style -We use the `flake8` and `isort` tools to manage PEP-8 coherence and -import ordering in this project. +We use `autoflake`, `isort`, `black` and `flake8` to enforce coding style in a +PEP-8 compliant way. These tools run in GitLab CI using `pre-commit` to verify +that any pushed code changes comply with this. + +To enable the `pre-commit` git hook, install the `pre-commit` package either +with `pacman` or `pip` and then run `pre-commit install --install-hooks`. This +will ensure formatting is done before any code is commited to the git +repository. There are plugins for editors or IDEs which automate this process. Some example plugins: -- [tell-k/vim-autopep8](https://github.com/tell-k/vim-autopep8) +- [tenfyzhong/autoflake.vim](https://github.com/tenfyzhong/autoflake.vim) - [fisadev/vim-isort](https://github.com/fisadev/vim-isort) +- [psf/black](https://github.com/psf/black) +- [nvie/vim-flake8](https://github.com/nvie/vim-flake8) - [prabirshrestha/vim-lsp](https://github.com/prabirshrestha/vim-lsp) +- [dense-analysis/ale](https://github.com/dense-analysis/ale) -See `setup.cfg` for flake8 and isort specific rules. - -Note: We are planning on switching to [psf/black](https://github.com/psf/black). -For now, developers should ensure that flake8 and isort passes when submitting -merge requests or patch sets. +See `setup.cfg`, `pyproject.toml` and `.pre-commit-config.yaml` for tool +specific configurations. ### Development Environment From 57c040995820e08e4af9aadfdc5c946551d899ec Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 22 Aug 2022 23:44:56 -0700 Subject: [PATCH 1558/1891] style: set flake8's max-line-length=88 In accordance with black's defined style, we now expect a maximum of 88 columns for any one particular line. This change fixes remaining violations of 88 columns in the codebase (not many), and introduces the modified flake8 configuration. Signed-off-by: Kevin Morris --- schema/gendummydata.py | 13 ++++++++++--- setup.cfg | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/schema/gendummydata.py b/schema/gendummydata.py index fa59855f..dfc8eee5 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -233,7 +233,8 @@ for p in list(seen_pkgs.keys()): s = ( "INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, " - "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', '', %d, %d, %d, %s, %s);\n" + "SubmitterUID, MaintainerUID, PackagerUID) VALUES " + "(%d, '%s', '', %d, %d, %d, %s, %s);\n" ) s = s % (seen_pkgs[p], p, NOW, NOW, uuid, muid, puid) out.write(s) @@ -303,7 +304,10 @@ for p in seen_pkgs_keys: deptype = random.randrange(1, 5) if deptype == 4: dep += ": for " + random.choice(seen_pkgs_keys) - s = "INSERT INTO PackageDepends(PackageID, DepTypeID, DepName) VALUES (%d, %d, '%s');\n" + s = ( + "INSERT INTO PackageDepends(PackageID, DepTypeID, DepName) " + "VALUES (%d, %d, '%s');\n" + ) s = s % (seen_pkgs[p], deptype, dep) out.write(s) @@ -311,7 +315,10 @@ for p in seen_pkgs_keys: for i in range(0, num_deps): rel = random.choice(seen_pkgs_keys) reltype = random.randrange(1, 4) - s = "INSERT INTO PackageRelations(PackageID, RelTypeID, RelName) VALUES (%d, %d, '%s');\n" + s = ( + "INSERT INTO PackageRelations(PackageID, RelTypeID, RelName) " + "VALUES (%d, %d, '%s');\n" + ) s = s % (seen_pkgs[p], reltype, rel) out.write(s) diff --git a/setup.cfg b/setup.cfg index 3c9bf777..41978dae 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [flake8] -max-line-length = 127 +max-line-length = 88 max-complexity = 10 # Ignore some unavoidable flake8 warnings; we know this is against From fbb3e052fed5a82e334bb795c58f6e0a16f55890 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 23 Aug 2022 00:07:40 -0700 Subject: [PATCH 1559/1891] ci: use cache/virtualenv for test dependencies Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 3 +++ Dockerfile | 3 ++- docker/scripts/install-deps.sh | 3 ++- docker/scripts/install-python-deps.sh | 7 +++---- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7134673c..4d082582 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,7 @@ cache: paths: # For some reason Gitlab CI only supports storing cache/artifacts in a path relative to the build directory - .pkg-cache + - .venv variables: AUR_CONFIG: conf/config # Default MySQL config setup in before_script. @@ -31,6 +32,8 @@ test: before_script: - export PATH="$HOME/.poetry/bin:${PATH}" - ./docker/scripts/install-deps.sh + - virtualenv -p python3 .venv + - source .venv/bin/activate # Enable our virtualenv cache - ./docker/scripts/install-python-deps.sh - useradd -U -d /aurweb -c 'AUR User' aur - ./docker/mariadb-entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 16e6514e..28bca0e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ VOLUME /root/.cache/pypoetry/artifacts ENV PATH="/root/.poetry/bin:${PATH}" ENV PYTHONPATH=/aurweb ENV AUR_CONFIG=conf/config +ENV COMPOSE=1 # Install system-wide dependencies. COPY ./docker/scripts/install-deps.sh /install-deps.sh @@ -27,7 +28,7 @@ RUN cp -vf conf/config.dev conf/config RUN sed -i "s;YOUR_AUR_ROOT;/aurweb;g" conf/config # Install Python dependencies. -RUN /docker/scripts/install-python-deps.sh +RUN /docker/scripts/install-python-deps.sh compose # Compile asciidocs. RUN make -C doc diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index ced18c81..82496a2b 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -17,6 +17,7 @@ pacman -Syu --noconfirm --noprogressbar \ mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \ php php-fpm memcached php-memcached python-pip pyalpm \ python-srcinfo curl libeatmydata cronie python-poetry \ - python-poetry-core step-cli step-ca asciidoc + python-poetry-core step-cli step-ca asciidoc \ + python-virtualenv exec "$@" diff --git a/docker/scripts/install-python-deps.sh b/docker/scripts/install-python-deps.sh index 3d5f28f0..01a6eaa7 100755 --- a/docker/scripts/install-python-deps.sh +++ b/docker/scripts/install-python-deps.sh @@ -4,8 +4,7 @@ set -eou pipefail # Upgrade PIP; Arch Linux's version of pip is outdated for Poetry. pip install --upgrade pip -# Install the aurweb package and deps system-wide via poetry. -poetry config virtualenvs.create false +if [ ! -z "${COMPOSE+x}" ]; then + poetry config virtualenvs.create false +fi poetry install --no-interaction --no-ansi - -exec "$@" From 929bb756a8845fea4652d1b67cae515df872e98c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 23 Aug 2022 02:32:35 -0700 Subject: [PATCH 1560/1891] ci(lint): add .pre-commit cache for pre-commit Signed-off-by: Kevin Morris --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4d082582..23ed18f3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,6 +5,7 @@ cache: # For some reason Gitlab CI only supports storing cache/artifacts in a path relative to the build directory - .pkg-cache - .venv + - .pre-commit variables: AUR_CONFIG: conf/config # Default MySQL config setup in before_script. @@ -23,6 +24,7 @@ lint: script: # https://github.com/pre-commit/pre-commit/issues/2178#issuecomment-1002163763 - export SETUPTOOLS_USE_DISTUTILS=stdlib + - export XDG_CACHE_HOME=.pre-commit - pre-commit run -a test: From 8a3a7e31aca556c3a4b07f1ce717d7a0d6682f68 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Wed, 31 Aug 2022 22:01:54 -0700 Subject: [PATCH 1561/1891] upgrade: bump version to v6.1.1 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 4f97020c..ee14f61e 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.0.28" +AURWEB_VERSION = "v6.1.1" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 3a6dbe4d..f980ded9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.0.28" +version = "v6.1.1" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From b8a4ce4ceb085d70f7c33f7f884efb5433e65e47 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 2 Sep 2022 15:04:43 -0700 Subject: [PATCH 1562/1891] fix: include maint/comaint state in pkgbase post's error context Closes #386 Signed-off-by: Kevin Morris --- aurweb/routers/pkgbase.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 913e3955..076aec1e 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -587,6 +587,9 @@ async def pkgbase_disown_post( context = templates.make_context(request, "Disown Package") context["pkgbase"] = pkgbase + context["is_maint"] = request.user == pkgbase.Maintainer + context["is_comaint"] = request.user in comaints + if not confirm: context["errors"] = [ ( @@ -610,9 +613,7 @@ async def pkgbase_disown_post( request, "pkgbase/disown.html", context, status_code=HTTPStatus.BAD_REQUEST ) - if not next: - next = f"/pkgbase/{name}" - + next = next or f"/pkgbase/{name}" return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER) From 6435c2b1f1f324bc717f0c12afbdc42c88e7e66b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 2 Sep 2022 15:28:02 -0700 Subject: [PATCH 1563/1891] upgrade: bump to version v6.1.2 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index ee14f61e..df129c39 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.1" +AURWEB_VERSION = "v6.1.2" _parser = None diff --git a/pyproject.toml b/pyproject.toml index f980ded9..f249c80c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.1" +version = "v6.1.2" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 7fed5742b8e2267f7ce4f4a2db15087742d781e0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 5 Sep 2022 02:33:48 -0700 Subject: [PATCH 1564/1891] fix: display requests for TUs which no longer have an associated User Closes #387 Signed-off-by: Kevin Morris --- aurweb/routers/requests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index c7935575..51be6d2c 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -7,7 +7,7 @@ from sqlalchemy import case from aurweb import db, defaults, time, util from aurweb.auth import creds, requires_auth from aurweb.exceptions import handle_form_exceptions -from aurweb.models import PackageRequest, User +from aurweb.models import PackageRequest from aurweb.models.package_request import PENDING_ID, REJECTED_ID from aurweb.requests.util import get_pkgreq_by_id from aurweb.scripts import notify @@ -31,8 +31,8 @@ async def requests( context["O"] = O context["PP"] = PP - # A PackageRequest query, with left inner joined User and RequestType. - query = db.query(PackageRequest).join(User, User.ID == PackageRequest.UsersID) + # A PackageRequest query + query = db.query(PackageRequest) # If the request user is not elevated (TU or Dev), then # filter PackageRequests which are owned by the request user. From a629098b9299adc67a89589ee70924ee9cf4d464 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 5 Sep 2022 02:55:20 -0700 Subject: [PATCH 1565/1891] fix: conditional display on Request's 'Filed by' field Since we support requests which have no associated user, we must support the case where we are displaying such a request. Signed-off-by: Kevin Morris --- templates/requests.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/templates/requests.html b/templates/requests.html index ff265de1..ed8f31fb 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -46,9 +46,13 @@ {{ result.Comments }} {# Filed by #} - - {{ result.User.Username }} - + {# If the record has an associated User, display a link to that user. #} + {# Otherwise, display nothing (an empty column). #} + {% if result.User %} + + {{ result.User.Username }} + + {% endif %} {% set idle_time = config_getint("options", "request_idle_time") %} {% set time_delta = (utcnow - result.RequestTS) | int %} From 83ddbd220fe7b00ef66eb5a9c8269fd1e0bf322a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 5 Sep 2022 02:56:48 -0700 Subject: [PATCH 1566/1891] test: get /requests displays all requests, including those without a User Signed-off-by: Kevin Morris --- test/test_requests.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_requests.py b/test/test_requests.py index fd831674..83cdb402 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -743,6 +743,22 @@ def test_requests( assert len(rows) == 5 # There are five records left on the second page. +def test_requests_by_deleted_users( + client: TestClient, user: User, tu_user: User, pkgreq: PackageRequest +): + with db.begin(): + db.delete(user) + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + resp = request.get("/requests", cookies=cookies) + assert resp.status_code == HTTPStatus.OK + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + + def test_requests_selfmade( client: TestClient, user: User, requests: list[PackageRequest] ): From 0388b12896e31bf7d4a5b0feeeb207ce6c0231dc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 5 Sep 2022 19:25:32 -0700 Subject: [PATCH 1567/1891] fix: package description on /packages/{name} view ...What in the world happened here. We were literally just populating `pkg` based on `pkgbase.packages.first()`. We should have been focusing on the package passed by the context, which is always available when `show_package_details` is true. Closes #384 Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index ca7159be..cdb62128 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -1,4 +1,3 @@ -{% set pkg = pkgbase.packages.first() %} @@ -20,13 +19,13 @@ - + - + diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index a707bbac..6e92eeff 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -304,6 +304,50 @@ def test_package(client: TestClient, package: Package): assert conflicts[0].text.strip() == ", ".join(expected) +def test_package_split_description(client: TestClient, user: User): + + with db.begin(): + pkgbase = db.create( + PackageBase, + Name="pkgbase", + Maintainer=user, + Packager=user, + ) + + pkg_a = db.create( + Package, + PackageBase=pkgbase, + Name="pkg_a", + Description="pkg_a desc", + ) + pkg_b = db.create( + Package, + PackageBase=pkgbase, + Name="pkg_b", + Description="pkg_b desc", + ) + + # Check pkg_a + with client as request: + endp = f"/packages/{pkg_a.Name}" + resp = request.get(endp) + assert resp.status_code == HTTPStatus.OK + + root = parse_root(resp.text) + row = root.xpath('//tr[@id="pkg-description"]/td')[0] + assert row.text == pkg_a.Description + + # Check pkg_b + with client as request: + endp = f"/packages/{pkg_b.Name}" + resp = request.get(endp) + assert resp.status_code == HTTPStatus.OK + + root = parse_root(resp.text) + row = root.xpath('//tr[@id="pkg-description"]/td')[0] + assert row.text == pkg_b.Description + + def paged_depends_required(client: TestClient, package: Package): maint = package.PackageBase.Maintainer new_pkgs = [] diff --git a/test/test_templates.py b/test/test_templates.py index 383f45d1..f80e68eb 100644 --- a/test/test_templates.py +++ b/test/test_templates.py @@ -293,7 +293,7 @@ def test_package_details(user: User, package: Package): "git_clone_uri_anon": GIT_CLONE_URI_ANON, "git_clone_uri_priv": GIT_CLONE_URI_PRIV, "pkgbase": package.PackageBase, - "pkg": package, + "package": package, "comaintainers": [], } ) @@ -329,7 +329,7 @@ def test_package_details_filled(user: User, package: Package): "git_clone_uri_anon": GIT_CLONE_URI_ANON, "git_clone_uri_priv": GIT_CLONE_URI_PRIV, "pkgbase": package.PackageBase, - "pkg": package, + "package": package, "comaintainers": [], "licenses": package.package_licenses, "provides": package.package_relations.filter( From 310c469ba8d7831495d6cc2e24dba7224a705d5f Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 5 Sep 2022 17:08:55 +0100 Subject: [PATCH 1569/1891] fix: run pre-commit checks instead of flake8 and isort Signed-off-by: Leonidas Spyropoulos --- docker/scripts/install-deps.sh | 2 +- docker/scripts/run-tests.sh | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 82496a2b..85403969 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -18,6 +18,6 @@ pacman -Syu --noconfirm --noprogressbar \ php php-fpm memcached php-memcached python-pip pyalpm \ python-srcinfo curl libeatmydata cronie python-poetry \ python-poetry-core step-cli step-ca asciidoc \ - python-virtualenv + python-virtualenv python-pre-commit exec "$@" diff --git a/docker/scripts/run-tests.sh b/docker/scripts/run-tests.sh index a726c957..5d454ecb 100755 --- a/docker/scripts/run-tests.sh +++ b/docker/scripts/run-tests.sh @@ -21,8 +21,7 @@ rm -f /data/.coverage cp -v .coverage /data/.coverage chmod 666 /data/.coverage -# Run flake8 and isort checks. +# Run pre-commit checks for dir in aurweb test migrations; do - flake8 --count $dir - isort --check-only $dir + pre-commit run -a done From a84d115fa1715c19f66540066e021ac3d4c44a3d Mon Sep 17 00:00:00 2001 From: renovate Date: Tue, 6 Sep 2022 08:24:03 +0000 Subject: [PATCH 1570/1891] chore(deps): add renovate.json --- renovate.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..39a2b6e9 --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ] +} From 655402a50931693b3ac376dd5dea4b0c05d893e9 Mon Sep 17 00:00:00 2001 From: renovate Date: Tue, 6 Sep 2022 10:25:02 +0000 Subject: [PATCH 1571/1891] chore(deps): update dependency pytest-asyncio to ^0.19.0 --- poetry.lock | 124 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0395db3b..eddb0f95 100644 --- a/poetry.lock +++ b/poetry.lock @@ -34,9 +34,9 @@ idna = ">=2.8" sniffio = ">=1.1" [package.extras] +doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] trio = ["trio (>=0.16)"] -test = ["uvloop (>=0.15)", "mock (>=4)", "uvloop (<0.15)", "contextlib2", "trustme", "pytest-mock (>=3.6.1)", "pytest (>=7.0)", "hypothesis (>=4.0)", "coverage[toml] (>=4.5)"] -doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme", "packaging"] [[package]] name = "asgiref" @@ -47,7 +47,7 @@ optional = false python-versions = ">=3.7" [package.extras] -tests = ["mypy (>=0.800)", "pytest-asyncio", "pytest"] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] [[package]] name = "atomicwrites" @@ -66,10 +66,10 @@ optional = false python-versions = ">=3.5" [package.extras] -tests_no_zope = ["cloudpickle", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] -tests = ["cloudpickle", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] -docs = ["sphinx-notfound-page", "zope.interface", "sphinx", "furo"] -dev = ["cloudpickle", "pre-commit", "sphinx-notfound-page", "sphinx", "furo", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] +docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "authlib" @@ -189,11 +189,11 @@ cffi = ">=1.12" [package.extras] docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] -docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] sdist = ["setuptools_rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] [[package]] name = "dnspython" @@ -204,12 +204,12 @@ optional = false python-versions = ">=3.6,<4.0" [package.extras] -wmi = ["wmi (>=1.5.1,<2.0.0)"] -trio = ["trio (>=0.14,<0.20)"] -curio = ["sniffio (>=1.1,<2.0)", "curio (>=1.2,<2.0)"] -doh = ["requests-toolbelt (>=0.9.1,<0.10.0)", "requests (>=2.23.0,<3.0.0)", "httpx (>=0.21.1)", "h2 (>=4.1.0)"] -idna = ["idna (>=2.1,<4.0)"] +curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] dnssec = ["cryptography (>=2.6,<37.0)"] +doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"] +idna = ["idna (>=2.1,<4.0)"] +trio = ["trio (>=0.14,<0.20)"] +wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] name = "email-validator" @@ -248,8 +248,8 @@ six = ">=1.16.0,<2.0.0" sortedcontainers = ">=2.4.0,<3.0.0" [package.extras] -lua = ["lupa (>=1.13,<2.0)"] aioredis = ["aioredis (>=2.0.1,<3.0.0)"] +lua = ["lupa (>=1.13,<2.0)"] [[package]] name = "fastapi" @@ -264,10 +264,10 @@ pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1. starlette = "0.17.1" [package.extras] -test = ["types-dataclasses (==0.1.7)", "types-orjson (==3.6.0)", "types-ujson (==0.1.1)", "anyio[trio] (>=3.2.1,<4.0.0)", "flask (>=1.1.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "peewee (>=3.13.3,<4.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "email_validator (>=1.1.1,<2.0.0)", "httpx (>=0.14.0,<0.19.0)", "requests (>=2.24.0,<3.0.0)", "isort (>=5.0.6,<6.0.0)", "black (==21.9b0)", "flake8 (>=3.8.3,<4.0.0)", "mypy (==0.910)", "pytest-cov (>=2.12.0,<4.0.0)", "pytest (>=6.2.4,<7.0.0)"] -doc = ["pyyaml (>=5.3.1,<6.0.0)", "typer-cli (>=0.0.12,<0.0.13)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mkdocs (>=1.1.2,<2.0.0)"] -dev = ["uvicorn[standard] (>=0.12.0,<0.16.0)", "flake8 (>=3.8.3,<4.0.0)", "autoflake (>=1.4.0,<2.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)"] -all = ["uvicorn[standard] (>=0.12.0,<0.16.0)", "email_validator (>=1.1.1,<2.0.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "jinja2 (>=2.11.2,<4.0.0)", "requests (>=2.24.0,<3.0.0)"] +all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,<5.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] +dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "typer-cli (>=0.0.12,<0.0.13)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==21.9b0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.1.7)", "types-orjson (==3.6.0)", "types-ujson (==0.1.1)", "ujson (>=4.0.1,<5.0.0)"] [[package]] name = "feedgen" @@ -290,8 +290,8 @@ optional = false python-versions = ">=3.7" [package.extras] -testing = ["pytest-timeout (>=2.1)", "pytest-cov (>=3)", "pytest (>=7.1.2)", "coverage (>=6.4.2)", "covdefaults (>=2.2)"] -docs = ["sphinx-autodoc-typehints (>=1.19.1)", "sphinx (>=5.1.1)", "furo (>=2022.6.21)"] +docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"] +testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"] [[package]] name = "greenlet" @@ -378,9 +378,9 @@ rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] -http2 = ["h2 (>=3,<5)"] -cli = ["pygments (>=2.0.0,<3.0.0)", "rich (>=10.0.0,<11.0.0)", "click (>=8.0.0,<9.0.0)"] brotli = ["brotli", "brotlicffi"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10.0.0,<11.0.0)"] +http2 = ["h2 (>=3,<5)"] [[package]] name = "hypercorn" @@ -398,10 +398,10 @@ toml = "*" wsproto = ">=0.14.0" [package.extras] -uvloop = ["uvloop"] -trio = ["trio (>=0.11.0)"] -tests = ["trio", "pytest-trio", "pytest-cov", "pytest-asyncio", "pytest", "mock", "hypothesis"] h3 = ["aioquic (>=0.9.0,<1.0)"] +tests = ["hypothesis", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-trio", "trio"] +trio = ["trio (>=0.11.0)"] +uvloop = ["uvloop"] [[package]] name = "hyperframe" @@ -431,9 +431,9 @@ python-versions = ">=3.7" zipp = ">=0.5" [package.extras] -testing = ["importlib-resources (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-black (>=0.3.7)", "pytest-perf (>=0.9.2)", "flufl.flake8", "pyfakefs", "packaging", "pytest-enabler (>=1.3)", "pytest-cov", "pytest-flake8", "pytest-checkdocs (>=2.4)", "pytest (>=6)"] +docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"] perf = ["ipython"] -docs = ["rst.linker (>=1.9)", "jaraco.packaging (>=9)", "sphinx"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "iniconfig" @@ -474,10 +474,10 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" [package.extras] -source = ["Cython (>=0.29.7)"] -htmlsoup = ["beautifulsoup4"] -html5 = ["html5lib"] cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["beautifulsoup4"] +source = ["Cython (>=0.29.7)"] [[package]] name = "mako" @@ -507,7 +507,7 @@ python-versions = ">=3.7" importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] -testing = ["pyyaml", "coverage"] +testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" @@ -569,8 +569,8 @@ optional = false python-versions = ">=3.6" [package.extras] -testing = ["pytest-benchmark", "pytest"] -dev = ["tox", "pre-commit"] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] [[package]] name = "posix-ipc" @@ -655,8 +655,8 @@ python-versions = ">=3.6.1" typing-extensions = ">=3.7.4.3" [package.extras] -email = ["email-validator (>=1.0.3)"] dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" @@ -699,21 +699,21 @@ py = ">=1.8.2" toml = "*" [package.extras] -testing = ["xmlschema", "requests", "nose", "mock", "hypothesis (>=3.56)", "argcomplete"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.16.0" -description = "Pytest support for asyncio." +version = "0.19.0" +description = "Pytest support for asyncio" category = "dev" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.7" [package.dependencies] -pytest = ">=5.4.0" +pytest = ">=6.1.0" [package.extras] -testing = ["hypothesis (>=5.7.1)", "coverage"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] [[package]] name = "pytest-cov" @@ -728,7 +728,7 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["virtualenv", "pytest-xdist", "six", "process-tests", "hunter", "fields"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pytest-forked" @@ -768,9 +768,9 @@ pytest = ">=6.2.0" pytest-forked = "*" [package.extras] -testing = ["filelock"] -setproctitle = ["setproctitle"] psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] [[package]] name = "python-dateutil" @@ -820,8 +820,8 @@ idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" [package.extras] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rfc3986" @@ -873,24 +873,24 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} [package.extras] -aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] -aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"] +aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3,!=0.2.4)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] mssql_pymssql = ["pymssql"] mssql_pyodbc = ["pyodbc"] -mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] -mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] +mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] +mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] mysql_connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] +oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] +postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] postgresql_psycopg2binary = ["psycopg2-binary"] postgresql_psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql (<1)", "pymysql"] +pymysql = ["pymysql", "pymysql (<1)"] sqlcipher = ["sqlcipher3-binary"] [[package]] @@ -916,7 +916,7 @@ python-versions = ">=3.6" anyio = ">=3.0.0,<4" [package.extras] -full = ["requests", "pyyaml", "python-multipart", "jinja2", "itsdangerous"] +full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] [[package]] name = "tap.py" @@ -962,9 +962,9 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" [package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] -secure = ["ipaddress", "certifi", "idna (>=2.0.0)", "cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"] -brotli = ["brotlipy (>=0.6.0)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] [[package]] name = "uvicorn" @@ -980,7 +980,7 @@ click = ">=7.0" h11 = ">=0.8" [package.extras] -standard = ["colorama (>=0.4)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "PyYAML (>=5.1)", "python-dotenv (>=0.13)", "watchgod (>=0.6)", "httptools (>=0.2.0,<0.3.0)", "websockets (>=9.1)"] +standard = ["PyYAML (>=5.1)", "colorama (>=0.4)", "httptools (>=0.2.0,<0.3.0)", "python-dotenv (>=0.13)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchgod (>=0.6)", "websockets (>=9.1)"] [[package]] name = "webencodings" @@ -1024,13 +1024,13 @@ optional = false python-versions = ">=3.7" [package.extras] -testing = ["pytest-mypy (>=0.9.1)", "pytest-black (>=0.3.7)", "func-timeout", "jaraco.itertools", "pytest-enabler (>=1.3)", "pytest-cov", "pytest-flake8", "pytest-checkdocs (>=2.4)", "pytest (>=6)"] -docs = ["jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "jaraco.packaging (>=9)", "sphinx"] +docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] +testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "7630feca99b54b3d08fd947d5c5857590ca8af8b6c3a9f0bed7eecf03385597e" +content-hash = "5326e59079df0c0520a8654e8e92e936a50df127e2e5eb6c81f465e0a3dfd339" [metadata.files] aiofiles = [ @@ -1698,8 +1698,8 @@ pytest = [ {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.16.0.tar.gz", hash = "sha256:7496c5977ce88c34379df64a66459fe395cd05543f0a2f837016e7144391fcfb"}, - {file = "pytest_asyncio-0.16.0-py3-none-any.whl", hash = "sha256:5f2a21273c47b331ae6aa5b36087047b4899e40f03f18397c0e65fa5cca54e9b"}, + {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, + {file = "pytest_asyncio-0.19.0-py3-none-any.whl", hash = "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa"}, ] pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, diff --git a/pyproject.toml b/pyproject.toml index f249c80c..283b8101 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,7 @@ srcinfo = "^0.0.8" [tool.poetry.dev-dependencies] coverage = "^6.0.2" pytest = "^6.2.5" -pytest-asyncio = "^0.16.0" +pytest-asyncio = "^0.19.0" pytest-cov = "^3.0.0" pytest-tap = "^3.2" From b38e765dfe552d68a9fdcf14116e06efcc3b4b61 Mon Sep 17 00:00:00 2001 From: renovate Date: Tue, 6 Sep 2022 22:24:52 +0000 Subject: [PATCH 1572/1891] fix(deps): update dependency aiofiles to ^0.8.0 --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index eddb0f95..61782e65 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "aiofiles" -version = "0.7.0" +version = "0.8.0" description = "File support for asyncio." category = "main" optional = false @@ -1030,12 +1030,12 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "5326e59079df0c0520a8654e8e92e936a50df127e2e5eb6c81f465e0a3dfd339" +content-hash = "cf2d693b3a53f8c1d47b46c9787d710cb39ffdba5c3285e7d5cd0c02ec191154" [metadata.files] aiofiles = [ - {file = "aiofiles-0.7.0-py3-none-any.whl", hash = "sha256:c67a6823b5f23fcab0a2595a289cec7d8c863ffcb4322fb8cd6b90400aedfdbc"}, - {file = "aiofiles-0.7.0.tar.gz", hash = "sha256:a1c4fc9b2ff81568c83e21392a82f344ea9d23da906e4f6a52662764545e19d4"}, + {file = "aiofiles-0.8.0-py3-none-any.whl", hash = "sha256:7a973fc22b29e9962d0897805ace5856e6a566ab1f0c8e5c91ff6c866519c937"}, + {file = "aiofiles-0.8.0.tar.gz", hash = "sha256:8334f23235248a3b2e83b2c3a78a22674f39969b96397126cc93664d9a901e59"}, ] alembic = [ {file = "alembic-1.8.1-py3-none-any.whl", hash = "sha256:0a024d7f2de88d738d7395ff866997314c837be6104e90c5724350313dee4da4"}, diff --git a/pyproject.toml b/pyproject.toml index 283b8101..a1112d35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ python = ">=3.9,<3.11" # based on git tags. # General -aiofiles = "^0.7.0" +aiofiles = "^0.8.0" asgiref = "^3.4.1" bcrypt = "^3.2.0" bleach = "^4.1.0" From cdc7bd618c8ce06b52da87d2a6efe81a3dcb896e Mon Sep 17 00:00:00 2001 From: renovate Date: Tue, 6 Sep 2022 23:24:49 +0000 Subject: [PATCH 1573/1891] fix(deps): update dependency email-validator to v1.2.1 --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 61782e65..691ae494 100644 --- a/poetry.lock +++ b/poetry.lock @@ -213,8 +213,8 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] name = "email-validator" -version = "1.1.3" -description = "A robust email syntax and deliverability validation library for Python 2.x/3.x." +version = "1.2.1" +description = "A robust email syntax and deliverability validation library." category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" @@ -1030,7 +1030,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "cf2d693b3a53f8c1d47b46c9787d710cb39ffdba5c3285e7d5cd0c02ec191154" +content-hash = "5c5c0ec98e190669e257f4d717162794dc5841dca9168d7a941f5e72ea85f03f" [metadata.files] aiofiles = [ @@ -1240,8 +1240,8 @@ dnspython = [ {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, ] email-validator = [ - {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, - {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"}, + {file = "email_validator-1.2.1-py2.py3-none-any.whl", hash = "sha256:c8589e691cf73eb99eed8d10ce0e9cbb05a0886ba920c8bcb7c82873f4c5789c"}, + {file = "email_validator-1.2.1.tar.gz", hash = "sha256:6757aea012d40516357c0ac2b1a4c31219ab2f899d26831334c5d069e8b6c3d8"}, ] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, diff --git a/pyproject.toml b/pyproject.toml index a1112d35..27369c45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ aiofiles = "^0.8.0" asgiref = "^3.4.1" bcrypt = "^3.2.0" bleach = "^4.1.0" -email-validator = "1.1.3" +email-validator = "1.2.1" fakeredis = "^1.6.1" feedgen = "^0.9.0" httpx = "^0.20.0" From a981ae4052fd064e0ea23fb91fcd8a0d16f36c58 Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 7 Sep 2022 00:25:32 +0000 Subject: [PATCH 1574/1891] fix(deps): update dependency httpx to ^0.23.0 --- poetry.lock | 26 ++++++++++++++------------ pyproject.toml | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 691ae494..1a1a8c62 100644 --- a/poetry.lock +++ b/poetry.lock @@ -348,39 +348,41 @@ python-versions = ">=3.6.1" [[package]] name = "httpcore" -version = "0.13.7" +version = "0.15.0" description = "A minimal low-level HTTP client." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] anyio = ">=3.0.0,<4.0.0" +certifi = "*" h11 = ">=0.11,<0.13" sniffio = ">=1.0.0,<2.0.0" [package.extras] http2 = ["h2 (>=3,<5)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" -version = "0.20.0" +version = "0.23.0" description = "The next generation HTTP client." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] certifi = "*" -charset-normalizer = "*" -httpcore = ">=0.13.3,<0.14.0" +httpcore = ">=0.15.0,<0.16.0" rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10.0.0,<11.0.0)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] http2 = ["h2 (>=3,<5)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "hypercorn" @@ -1030,7 +1032,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "5c5c0ec98e190669e257f4d717162794dc5841dca9168d7a941f5e72ea85f03f" +content-hash = "879b45a5c84c40462afe971096ff654f7ef6981bbdcea5d5e6107e7f68355802" [metadata.files] aiofiles = [ @@ -1336,12 +1338,12 @@ hpack = [ {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, ] httpcore = [ - {file = "httpcore-0.13.7-py3-none-any.whl", hash = "sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0"}, - {file = "httpcore-0.13.7.tar.gz", hash = "sha256:036f960468759e633574d7c121afba48af6419615d36ab8ede979f1ad6276fa3"}, + {file = "httpcore-0.15.0-py3-none-any.whl", hash = "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6"}, + {file = "httpcore-0.15.0.tar.gz", hash = "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b"}, ] httpx = [ - {file = "httpx-0.20.0-py3-none-any.whl", hash = "sha256:33af5aad9bdc82ef1fc89219c1e36f5693bf9cd0ebe330884df563445682c0f8"}, - {file = "httpx-0.20.0.tar.gz", hash = "sha256:09606d630f070d07f9ff28104fbcea429ea0014c1e89ac90b4d8de8286c40e7b"}, + {file = "httpx-0.23.0-py3-none-any.whl", hash = "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b"}, + {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, ] hypercorn = [ {file = "Hypercorn-0.11.2-py3-none-any.whl", hash = "sha256:8007c10f81566920f8ae12c0e26e146f94ca70506da964b5a727ad610aa1d821"}, diff --git a/pyproject.toml b/pyproject.toml index 27369c45..e0c7ba00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,7 @@ bleach = "^4.1.0" email-validator = "1.2.1" fakeredis = "^1.6.1" feedgen = "^0.9.0" -httpx = "^0.20.0" +httpx = "^0.23.0" itsdangerous = "^2.0.1" lxml = "^4.6.3" orjson = "^3.6.4" From a73af3e76d3fd4a89cba2cf23ee91f431ad2a990 Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 7 Sep 2022 01:25:03 +0000 Subject: [PATCH 1575/1891] fix(deps): update dependency hypercorn to ^0.14.0 --- poetry.lock | 12 ++++++------ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1a1a8c62..801d9e95 100644 --- a/poetry.lock +++ b/poetry.lock @@ -386,8 +386,8 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "hypercorn" -version = "0.11.2" -description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn." +version = "0.14.3" +description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" category = "main" optional = false python-versions = ">=3.7" @@ -400,8 +400,8 @@ toml = "*" wsproto = ">=0.14.0" [package.extras] +docs = ["pydata-sphinx-theme"] h3 = ["aioquic (>=0.9.0,<1.0)"] -tests = ["hypothesis", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-trio", "trio"] trio = ["trio (>=0.11.0)"] uvloop = ["uvloop"] @@ -1032,7 +1032,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "879b45a5c84c40462afe971096ff654f7ef6981bbdcea5d5e6107e7f68355802" +content-hash = "0afd4b5faa1d291565d5a1a90d6d916ffc37537913d4037660a99c86bb3b3ed1" [metadata.files] aiofiles = [ @@ -1346,8 +1346,8 @@ httpx = [ {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, ] hypercorn = [ - {file = "Hypercorn-0.11.2-py3-none-any.whl", hash = "sha256:8007c10f81566920f8ae12c0e26e146f94ca70506da964b5a727ad610aa1d821"}, - {file = "Hypercorn-0.11.2.tar.gz", hash = "sha256:5ba1e719c521080abd698ff5781a2331e34ef50fc1c89a50960538115a896a9a"}, + {file = "Hypercorn-0.14.3-py3-none-any.whl", hash = "sha256:7c491d5184f28ee960dcdc14ab45d14633ca79d72ddd13cf4fcb4cb854d679ab"}, + {file = "Hypercorn-0.14.3.tar.gz", hash = "sha256:4a87a0b7bbe9dc75fab06dbe4b301b9b90416e9866c23a377df21a969d6ab8dd"}, ] hyperframe = [ {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, diff --git a/pyproject.toml b/pyproject.toml index e0c7ba00..e6cb2c83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,7 +87,7 @@ SQLAlchemy = "^1.4.26" # ASGI uvicorn = "^0.15.0" gunicorn = "^20.1.0" -Hypercorn = "^0.11.2" +Hypercorn = "^0.14.0" prometheus-fastapi-instrumentator = "^5.7.1" pytest-xdist = "^2.4.0" filelock = "^3.3.2" From bb310bdf65add1559c8b459b1be71cf70864dbb1 Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 7 Sep 2022 02:24:55 +0000 Subject: [PATCH 1576/1891] fix(deps): update dependency uvicorn to ^0.18.0 --- poetry.lock | 13 ++++++------- pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index 801d9e95..4d51292d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -970,19 +970,18 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.15.0" +version = "0.18.3" description = "The lightning-fast ASGI server." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" [package.dependencies] -asgiref = ">=3.4.0" click = ">=7.0" h11 = ">=0.8" [package.extras] -standard = ["PyYAML (>=5.1)", "colorama (>=0.4)", "httptools (>=0.2.0,<0.3.0)", "python-dotenv (>=0.13)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchgod (>=0.6)", "websockets (>=9.1)"] +standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] [[package]] name = "webencodings" @@ -1032,7 +1031,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "0afd4b5faa1d291565d5a1a90d6d916ffc37537913d4037660a99c86bb3b3ed1" +content-hash = "17c8d99957aa94e4b9b0a8fa14098122d402ef52da860c13049a690e5dd18792" [metadata.files] aiofiles = [ @@ -1817,8 +1816,8 @@ urllib3 = [ {file = "urllib3-1.26.11.tar.gz", hash = "sha256:ea6e8fb210b19d950fab93b60c9009226c63a28808bc8386e05301e25883ac0a"}, ] uvicorn = [ - {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, - {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, + {file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"}, + {file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, diff --git a/pyproject.toml b/pyproject.toml index e6cb2c83..4122241d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,7 +85,7 @@ Werkzeug = "^2.0.2" SQLAlchemy = "^1.4.26" # ASGI -uvicorn = "^0.15.0" +uvicorn = "^0.18.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.0" prometheus-fastapi-instrumentator = "^5.7.1" From a39f34d695ae8f191957b38d43b2d04a7aaf1c38 Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 7 Sep 2022 03:25:30 +0000 Subject: [PATCH 1577/1891] chore(deps): update dependency pytest to v7 --- poetry.lock | 28 ++++++++-------------------- pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4d51292d..bea03647 100644 --- a/poetry.lock +++ b/poetry.lock @@ -49,14 +49,6 @@ python-versions = ">=3.7" [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] -[[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - [[package]] name = "attrs" version = "22.1.0" @@ -684,24 +676,23 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "6.2.5" +version = "7.1.3" description = "pytest: simple powerful testing with Python" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" py = ">=1.8.2" -toml = "*" +tomli = ">=1.0.0" [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -943,7 +934,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -1031,7 +1022,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "17c8d99957aa94e4b9b0a8fa14098122d402ef52da860c13049a690e5dd18792" +content-hash = "f6a259093ff2796b5a3f579fcd00cc1c6a841d769abd9c898a91a8a6a2eec76f" [metadata.files] aiofiles = [ @@ -1050,9 +1041,6 @@ asgiref = [ {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, ] -atomicwrites = [ - {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, -] attrs = [ {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, @@ -1695,8 +1683,8 @@ pyparsing = [ {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] pytest = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, + {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, + {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, ] pytest-asyncio = [ {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, diff --git a/pyproject.toml b/pyproject.toml index 4122241d..4c0df93c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ srcinfo = "^0.0.8" [tool.poetry.dev-dependencies] coverage = "^6.0.2" -pytest = "^6.2.5" +pytest = "^7.0.0" pytest-asyncio = "^0.19.0" pytest-cov = "^3.0.0" pytest-tap = "^3.2" From 486f8bd61c458b44232a4bb7c07d08e0e15b86f8 Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 7 Sep 2022 04:24:53 +0000 Subject: [PATCH 1578/1891] fix(deps): update dependency aiofiles to v22 --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index bea03647..a12b6aa4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,10 @@ [[package]] name = "aiofiles" -version = "0.8.0" +version = "22.1.0" description = "File support for asyncio." category = "main" optional = false -python-versions = ">=3.6,<4.0" +python-versions = ">=3.7,<4.0" [[package]] name = "alembic" @@ -1022,12 +1022,12 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "f6a259093ff2796b5a3f579fcd00cc1c6a841d769abd9c898a91a8a6a2eec76f" +content-hash = "888f848aad23900dcff3c089e13b88547605ef760dc3714a9872a89346e150e2" [metadata.files] aiofiles = [ - {file = "aiofiles-0.8.0-py3-none-any.whl", hash = "sha256:7a973fc22b29e9962d0897805ace5856e6a566ab1f0c8e5c91ff6c866519c937"}, - {file = "aiofiles-0.8.0.tar.gz", hash = "sha256:8334f23235248a3b2e83b2c3a78a22674f39969b96397126cc93664d9a901e59"}, + {file = "aiofiles-22.1.0-py3-none-any.whl", hash = "sha256:1142fa8e80dbae46bb6339573ad4c8c0841358f79c6eb50a493dceca14621bad"}, + {file = "aiofiles-22.1.0.tar.gz", hash = "sha256:9107f1ca0b2a5553987a94a3c9959fe5b491fdf731389aa5b7b1bd0733e32de6"}, ] alembic = [ {file = "alembic-1.8.1-py3-none-any.whl", hash = "sha256:0a024d7f2de88d738d7395ff866997314c837be6104e90c5724350313dee4da4"}, diff --git a/pyproject.toml b/pyproject.toml index 4c0df93c..78d7e73a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ python = ">=3.9,<3.11" # based on git tags. # General -aiofiles = "^0.8.0" +aiofiles = "^22.0.0" asgiref = "^3.4.1" bcrypt = "^3.2.0" bleach = "^4.1.0" From 6ab9663b7684dd25bedd5b2ee75e774ddf440fe0 Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 7 Sep 2022 06:25:25 +0000 Subject: [PATCH 1579/1891] fix(deps): update dependency authlib to v1 --- poetry.lock | 15 ++++++--------- pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/poetry.lock b/poetry.lock index a12b6aa4..69721ec2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -65,17 +65,14 @@ tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy [[package]] name = "authlib" -version = "0.15.5" -description = "The ultimate Python library in building OAuth and OpenID Connect servers." +version = "1.0.1" +description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." category = "main" optional = false python-versions = "*" [package.dependencies] -cryptography = "*" - -[package.extras] -client = ["requests"] +cryptography = ">=3.2" [[package]] name = "bcrypt" @@ -1022,7 +1019,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "888f848aad23900dcff3c089e13b88547605ef760dc3714a9872a89346e150e2" +content-hash = "c2412181a05b96ad1daab6e9bddff8e1d4ce2b0b7671536ccccd69c66924c27d" [metadata.files] aiofiles = [ @@ -1046,8 +1043,8 @@ attrs = [ {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, ] authlib = [ - {file = "Authlib-0.15.5-py2.py3-none-any.whl", hash = "sha256:ecf4a7a9f2508c0bb07e93a752dd3c495cfaffc20e864ef0ffc95e3f40d2abaf"}, - {file = "Authlib-0.15.5.tar.gz", hash = "sha256:b83cf6360c8e92b0e9df0d1f32d675790bcc4e3c03977499b1eed24dcdef4252"}, + {file = "Authlib-1.0.1-py2.py3-none-any.whl", hash = "sha256:1286e2d5ef5bfe5a11cc2d0a0d1031f0393f6ce4d61f5121cfe87fa0054e98bd"}, + {file = "Authlib-1.0.1.tar.gz", hash = "sha256:6e74a4846ac36dfc882b3cc2fbd3d9eb410a627f2f2dc11771276655345223b1"}, ] bcrypt = [ {file = "bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e"}, diff --git a/pyproject.toml b/pyproject.toml index 78d7e73a..14182ed2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ paginate = "^0.5.6" # SQL alembic = "^1.7.4" mysqlclient = "^2.0.3" -Authlib = "^0.15.5" +Authlib = "^1.0.0" Jinja2 = "^3.0.2" Markdown = "^3.3.6" Werkzeug = "^2.0.2" From 7ad22d81433bc9507738e8b52f68fd1ba9c0a4b6 Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 7 Sep 2022 14:24:55 +0000 Subject: [PATCH 1580/1891] fix(deps): update dependency bcrypt to v4 --- poetry.lock | 30 ++++++++++++++---------------- pyproject.toml | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index 69721ec2..80104bee 100644 --- a/poetry.lock +++ b/poetry.lock @@ -76,15 +76,12 @@ cryptography = ">=3.2" [[package]] name = "bcrypt" -version = "3.2.2" +version = "4.0.0" description = "Modern password hashing for your software and your servers" category = "main" optional = false python-versions = ">=3.6" -[package.dependencies] -cffi = ">=1.1" - [package.extras] tests = ["pytest (>=3.2.1,!=3.3.0)"] typecheck = ["mypy"] @@ -1019,7 +1016,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "c2412181a05b96ad1daab6e9bddff8e1d4ce2b0b7671536ccccd69c66924c27d" +content-hash = "38f6da4f493e57dbbfa462388d4b549fb54e7fd9481dc114602210e846770a9f" [metadata.files] aiofiles = [ @@ -1047,17 +1044,18 @@ authlib = [ {file = "Authlib-1.0.1.tar.gz", hash = "sha256:6e74a4846ac36dfc882b3cc2fbd3d9eb410a627f2f2dc11771276655345223b1"}, ] bcrypt = [ - {file = "bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40"}, - {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa"}, - {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa"}, - {file = "bcrypt-3.2.2-cp36-abi3-win32.whl", hash = "sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e"}, - {file = "bcrypt-3.2.2-cp36-abi3-win_amd64.whl", hash = "sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129"}, - {file = "bcrypt-3.2.2.tar.gz", hash = "sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb"}, + {file = "bcrypt-4.0.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:845b1daf4df2dd94d2fdbc9454953ca9dd0e12970a0bfc9f3dcc6faea3fa96e4"}, + {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8780e69f9deec9d60f947b169507d2c9816e4f11548f1f7ebee2af38b9b22ae4"}, + {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c3334446fac200499e8bc04a530ce3cf0b3d7151e0e4ac5c0dddd3d95e97843"}, + {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfb67f6a6c72dfb0a02f3df51550aa1862708e55128b22543e2b42c74f3620d7"}, + {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:7c7dd6c1f05bf89e65261d97ac3a6520f34c2acb369afb57e3ea4449be6ff8fd"}, + {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:594780b364fb45f2634c46ec8d3e61c1c0f1811c4f2da60e8eb15594ecbf93ed"}, + {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2d0dd19aad87e4ab882ef1d12df505f4c52b28b69666ce83c528f42c07379227"}, + {file = "bcrypt-4.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bf413f2a9b0a2950fc750998899013f2e718d20fa4a58b85ca50b6df5ed1bbf9"}, + {file = "bcrypt-4.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ede0f506554571c8eda80db22b83c139303ec6b595b8f60c4c8157bdd0bdee36"}, + {file = "bcrypt-4.0.0-cp36-abi3-win32.whl", hash = "sha256:dc6ec3dc19b1c193b2f7cf279d3e32e7caf447532fbcb7af0906fe4398900c33"}, + {file = "bcrypt-4.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:0b0f0c7141622a31e9734b7f649451147c04ebb5122327ac0bd23744df84be90"}, + {file = "bcrypt-4.0.0.tar.gz", hash = "sha256:c59c170fc9225faad04dde1ba61d85b413946e8ce2e5f5f5ff30dfd67283f319"}, ] bleach = [ {file = "bleach-4.1.0-py2.py3-none-any.whl", hash = "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"}, diff --git a/pyproject.toml b/pyproject.toml index 14182ed2..52629cfb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ python = ">=3.9,<3.11" # General aiofiles = "^22.0.0" asgiref = "^3.4.1" -bcrypt = "^3.2.0" +bcrypt = "^4.0.0" bleach = "^4.1.0" email-validator = "1.2.1" fakeredis = "^1.6.1" From 3de17311cfb92755f4b91e34dcf5e43f66652ea4 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 10 Sep 2022 00:25:02 +0000 Subject: [PATCH 1581/1891] fix(deps): update dependency bleach to v5 --- poetry.lock | 15 +++++++++------ pyproject.toml | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 80104bee..f13e1df2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -88,17 +88,20 @@ typecheck = ["mypy"] [[package]] name = "bleach" -version = "4.1.0" +version = "5.0.1" description = "An easy safelist-based HTML-sanitizing tool." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -packaging = "*" six = ">=1.9.0" webencodings = "*" +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.2)"] +dev = ["Sphinx (==4.3.2)", "black (==22.3.0)", "build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "mypy (==0.961)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)"] + [[package]] name = "certifi" version = "2022.6.15" @@ -1016,7 +1019,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "38f6da4f493e57dbbfa462388d4b549fb54e7fd9481dc114602210e846770a9f" +content-hash = "ac45bb4ee013a8f79016947fe222a3158ffe716008349a81086e2dbeac6b914c" [metadata.files] aiofiles = [ @@ -1058,8 +1061,8 @@ bcrypt = [ {file = "bcrypt-4.0.0.tar.gz", hash = "sha256:c59c170fc9225faad04dde1ba61d85b413946e8ce2e5f5f5ff30dfd67283f319"}, ] bleach = [ - {file = "bleach-4.1.0-py2.py3-none-any.whl", hash = "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"}, - {file = "bleach-4.1.0.tar.gz", hash = "sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da"}, + {file = "bleach-5.0.1-py3-none-any.whl", hash = "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a"}, + {file = "bleach-5.0.1.tar.gz", hash = "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"}, ] certifi = [ {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, diff --git a/pyproject.toml b/pyproject.toml index 52629cfb..704e581a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ python = ">=3.9,<3.11" aiofiles = "^22.0.0" asgiref = "^3.4.1" bcrypt = "^4.0.0" -bleach = "^4.1.0" +bleach = "^5.0.0" email-validator = "1.2.1" fakeredis = "^1.6.1" feedgen = "^0.9.0" From 307d944cf1aebae5474695932a5530716794e1f7 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 10 Sep 2022 03:25:08 +0000 Subject: [PATCH 1582/1891] fix(deps): update dependency protobuf to v4 --- poetry.lock | 44 +++++++++++++++++--------------------------- pyproject.toml | 2 +- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/poetry.lock b/poetry.lock index f13e1df2..b2342cb4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -604,8 +604,8 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "3.20.1" -description = "Protocol Buffers" +version = "4.21.5" +description = "" category = "main" optional = false python-versions = ">=3.7" @@ -1019,7 +1019,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "ac45bb4ee013a8f79016947fe222a3158ffe716008349a81086e2dbeac6b914c" +content-hash = "478ba8d01d46e13dd56df2b19835750dda11e9a8bfe46ee8e7e22cb4579cf7b5" [metadata.files] aiofiles = [ @@ -1568,30 +1568,20 @@ prometheus-fastapi-instrumentator = [ {file = "prometheus_fastapi_instrumentator-5.8.2-py3-none-any.whl", hash = "sha256:5bfec239a924e1fed4ba94eb0addc73422d11821e894200b6d0e36a61c966827"}, ] protobuf = [ - {file = "protobuf-3.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996"}, - {file = "protobuf-3.20.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3"}, - {file = "protobuf-3.20.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde"}, - {file = "protobuf-3.20.1-cp310-cp310-win32.whl", hash = "sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c"}, - {file = "protobuf-3.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7"}, - {file = "protobuf-3.20.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153"}, - {file = "protobuf-3.20.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f"}, - {file = "protobuf-3.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20"}, - {file = "protobuf-3.20.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531"}, - {file = "protobuf-3.20.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e"}, - {file = "protobuf-3.20.1-cp37-cp37m-win32.whl", hash = "sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c"}, - {file = "protobuf-3.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067"}, - {file = "protobuf-3.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf"}, - {file = "protobuf-3.20.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab"}, - {file = "protobuf-3.20.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c"}, - {file = "protobuf-3.20.1-cp38-cp38-win32.whl", hash = "sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7"}, - {file = "protobuf-3.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739"}, - {file = "protobuf-3.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7"}, - {file = "protobuf-3.20.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f"}, - {file = "protobuf-3.20.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9"}, - {file = "protobuf-3.20.1-cp39-cp39-win32.whl", hash = "sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8"}, - {file = "protobuf-3.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91"}, - {file = "protobuf-3.20.1-py2.py3-none-any.whl", hash = "sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388"}, - {file = "protobuf-3.20.1.tar.gz", hash = "sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9"}, + {file = "protobuf-4.21.5-cp310-abi3-win32.whl", hash = "sha256:5310cbe761e87f0c1decce019d23f2101521d4dfff46034f8a12a53546036ec7"}, + {file = "protobuf-4.21.5-cp310-abi3-win_amd64.whl", hash = "sha256:e5c5a2886ae48d22a9d32fbb9b6636a089af3cd26b706750258ce1ca96cc0116"}, + {file = "protobuf-4.21.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ee04f5823ed98bb9a8c3b1dc503c49515e0172650875c3f76e225b223793a1f2"}, + {file = "protobuf-4.21.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:b04484d6f42f48c57dd2737a72692f4c6987529cdd148fb5b8e5f616862a2e37"}, + {file = "protobuf-4.21.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:5e0b272217aad8971763960238c1a1e6a65d50ef7824e23300da97569a251c55"}, + {file = "protobuf-4.21.5-cp37-cp37m-win32.whl", hash = "sha256:5eb0724615e90075f1d763983e708e1cef08e66b1891d8b8b6c33bc3b2f1a02b"}, + {file = "protobuf-4.21.5-cp37-cp37m-win_amd64.whl", hash = "sha256:011c0f267e85f5d73750b6c25f0155d5db1e9443cd3590ab669a6221dd8fcdb0"}, + {file = "protobuf-4.21.5-cp38-cp38-win32.whl", hash = "sha256:7b6f22463e2d1053d03058b7b4ceca6e4ed4c14f8c286c32824df751137bf8e7"}, + {file = "protobuf-4.21.5-cp38-cp38-win_amd64.whl", hash = "sha256:b52e7a522911a40445a5f588bd5b5e584291bfc5545e09b7060685e4b2ff814f"}, + {file = "protobuf-4.21.5-cp39-cp39-win32.whl", hash = "sha256:a7faa62b183d6a928e3daffd06af843b4287d16ef6e40f331575ecd236a7974d"}, + {file = "protobuf-4.21.5-cp39-cp39-win_amd64.whl", hash = "sha256:5e0ce02418ef03d7657a420ae8fd6fec4995ac713a3cb09164e95f694dbcf085"}, + {file = "protobuf-4.21.5-py2.py3-none-any.whl", hash = "sha256:bf711b451212dc5b0fa45ae7dada07d8e71a4b0ff0bc8e4783ee145f47ac4f82"}, + {file = "protobuf-4.21.5-py3-none-any.whl", hash = "sha256:3ec6f5b37935406bb9df9b277e79f8ed81d697146e07ef2ba8a5a272fb24b2c9"}, + {file = "protobuf-4.21.5.tar.gz", hash = "sha256:eb1106e87e095628e96884a877a51cdb90087106ee693925ec0a300468a9be3a"}, ] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, diff --git a/pyproject.toml b/pyproject.toml index 704e581a..b44291d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,7 @@ httpx = "^0.23.0" itsdangerous = "^2.0.1" lxml = "^4.6.3" orjson = "^3.6.4" -protobuf = "^3.19.0" +protobuf = "^4.0.0" pygit2 = "^1.7.0" python-multipart = "^0.0.5" redis = "^3.5.3" From 69d67247498123bb0b14b731b3f662935c1867a6 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 10 Sep 2022 05:25:06 +0000 Subject: [PATCH 1583/1891] fix(deps): update dependency redis to v4 --- poetry.lock | 124 ++++++++++++++++++++++++++++++++++++++++++++++--- pyproject.toml | 2 +- 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index b2342cb4..ef0fc1f7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -49,6 +49,14 @@ python-versions = ">=3.7" [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] +[[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "attrs" version = "22.1.0" @@ -184,6 +192,20 @@ sdist = ["setuptools_rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] +[[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest (<5)", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "pytest", "pytest-cov", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] + [[package]] name = "dnspython" version = "2.2.1" @@ -786,14 +808,20 @@ six = ">=1.4.0" [[package]] name = "redis" -version = "3.5.3" -description = "Python client for Redis key-value store" +version = "4.3.4" +description = "Python client for Redis database and key-value store" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" + +[package.dependencies] +async-timeout = ">=4.0.2" +deprecated = ">=1.2.3" +packaging = ">=20.4" [package.extras] -hiredis = ["hiredis (>=0.1.3)"] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] [[package]] name = "requests" @@ -993,6 +1021,14 @@ MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog"] +[[package]] +name = "wrapt" +version = "1.14.1" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + [[package]] name = "wsproto" version = "1.1.0" @@ -1019,7 +1055,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "478ba8d01d46e13dd56df2b19835750dda11e9a8bfe46ee8e7e22cb4579cf7b5" +content-hash = "e084bad4236ac74fb90fcf4537c78c228b2de606e83c63ac2557a677d681e743" [metadata.files] aiofiles = [ @@ -1038,6 +1074,10 @@ asgiref = [ {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, ] +async-timeout = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] attrs = [ {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, @@ -1222,6 +1262,10 @@ cryptography = [ {file = "cryptography-37.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab"}, {file = "cryptography-37.0.4.tar.gz", hash = "sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82"}, ] +deprecated = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, +] dnspython = [ {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, @@ -1702,8 +1746,8 @@ python-multipart = [ {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, ] redis = [ - {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, - {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, + {file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"}, + {file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"}, ] requests = [ {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, @@ -1803,6 +1847,72 @@ werkzeug = [ {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"}, {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"}, ] +wrapt = [ + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, +] wsproto = [ {file = "wsproto-1.1.0-py3-none-any.whl", hash = "sha256:2218cb57952d90b9fca325c0dcfb08c3bda93e8fd8070b0a17f048e2e47a521b"}, {file = "wsproto-1.1.0.tar.gz", hash = "sha256:a2e56bfd5c7cd83c1369d83b5feccd6d37798b74872866e62616e0ecf111bda8"}, diff --git a/pyproject.toml b/pyproject.toml index b44291d7..8f9624dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,7 @@ orjson = "^3.6.4" protobuf = "^4.0.0" pygit2 = "^1.7.0" python-multipart = "^0.0.5" -redis = "^3.5.3" +redis = "^4.0.0" requests = "^2.28.1" paginate = "^0.5.6" From a2d08e441ed0e769a5ec44312eba996bcd7f227c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 11 Sep 2022 17:59:45 -0700 Subject: [PATCH 1584/1891] fix(docker): run `pre-commit run -a` once Signed-off-by: Kevin Morris --- docker/scripts/run-tests.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docker/scripts/run-tests.sh b/docker/scripts/run-tests.sh index 5d454ecb..75e562b0 100755 --- a/docker/scripts/run-tests.sh +++ b/docker/scripts/run-tests.sh @@ -22,6 +22,4 @@ cp -v .coverage /data/.coverage chmod 666 /data/.coverage # Run pre-commit checks -for dir in aurweb test migrations; do - pre-commit run -a -done +pre-commit run -a From 03776c4663dda25195b262d483fd46b2a08dc5b9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 11 Sep 2022 18:00:11 -0700 Subject: [PATCH 1585/1891] fix(docker): cache & install pre-commit deps during image build Signed-off-by: Kevin Morris --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index 28bca0e4..1f667611 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,7 @@ FROM archlinux:base-devel VOLUME /root/.cache/pypoetry/cache VOLUME /root/.cache/pypoetry/artifacts +VOLUME /root/.cache/pre-commit ENV PATH="/root/.poetry/bin:${PATH}" ENV PYTHONPATH=/aurweb @@ -41,3 +42,6 @@ RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime # Install translations. RUN make -C po all install + +# Install pre-commit repositories and run lint check. +RUN pre-commit run -a From b3853e01b82372bc0ceb41a9352e5a54a6190dda Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 11 Sep 2022 18:07:54 -0700 Subject: [PATCH 1586/1891] fix(pre-commit): include migrations in fixes/checks We want all python files related to the project to be checked, really. Some of which are still included, but migrations are a core part of FastAPI aurweb and should be included. Signed-off-by: Kevin Morris --- .pre-commit-config.yaml | 2 - ...2ce8e2ffa_utf8mb4_charset_and_collation.py | 52 +++++++++---------- .../be7adae47ac3_upgrade_voteinfo_integers.py | 6 +-- .../d64e5571bc8d_fix_pkgvote_votets.py | 7 ++- ...6e1cd_add_sso_account_id_in_table_users.py | 21 ++++---- .../versions/f47cad5d6d03_initial_revision.py | 2 +- 6 files changed, 44 insertions(+), 46 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1480d2b8..09659269 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,3 @@ -exclude: ^migrations/versions - repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 diff --git a/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py b/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py index c3b79dab..5a9d5f39 100644 --- a/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py +++ b/migrations/versions/56e2ce8e2ffa_utf8mb4_charset_and_collation.py @@ -10,41 +10,41 @@ from alembic import op import aurweb.config # revision identifiers, used by Alembic. -revision = '56e2ce8e2ffa' -down_revision = 'ef39fcd6e1cd' +revision = "56e2ce8e2ffa" +down_revision = "ef39fcd6e1cd" branch_labels = None depends_on = None # Tables affected by charset/collate change tables = [ - ('AccountTypes', 'utf8mb4', 'utf8mb4_general_ci'), - ('ApiRateLimit', 'utf8mb4', 'utf8mb4_general_ci'), - ('Bans', 'utf8mb4', 'utf8mb4_general_ci'), - ('DependencyTypes', 'utf8mb4', 'utf8mb4_general_ci'), - ('Groups', 'utf8mb4', 'utf8mb4_general_ci'), - ('Licenses', 'utf8mb4', 'utf8mb4_general_ci'), - ('OfficialProviders', 'utf8mb4', 'utf8mb4_bin'), - ('PackageBases', 'utf8mb4', 'utf8mb4_general_ci'), - ('PackageBlacklist', 'utf8mb4', 'utf8mb4_general_ci'), - ('PackageComments', 'utf8mb4', 'utf8mb4_general_ci'), - ('PackageDepends', 'utf8mb4', 'utf8mb4_general_ci'), - ('PackageKeywords', 'utf8mb4', 'utf8mb4_general_ci'), - ('PackageRelations', 'utf8mb4', 'utf8mb4_general_ci'), - ('PackageRequests', 'utf8mb4', 'utf8mb4_general_ci'), - ('PackageSources', 'utf8mb4', 'utf8mb4_general_ci'), - ('Packages', 'utf8mb4', 'utf8mb4_general_ci'), - ('RelationTypes', 'utf8mb4', 'utf8mb4_general_ci'), - ('RequestTypes', 'utf8mb4', 'utf8mb4_general_ci'), - ('SSHPubKeys', 'utf8mb4', 'utf8mb4_bin'), - ('Sessions', 'utf8mb4', 'utf8mb4_bin'), - ('TU_VoteInfo', 'utf8mb4', 'utf8mb4_general_ci'), - ('Terms', 'utf8mb4', 'utf8mb4_general_ci'), - ('Users', 'utf8mb4', 'utf8mb4_general_ci') + ("AccountTypes", "utf8mb4", "utf8mb4_general_ci"), + ("ApiRateLimit", "utf8mb4", "utf8mb4_general_ci"), + ("Bans", "utf8mb4", "utf8mb4_general_ci"), + ("DependencyTypes", "utf8mb4", "utf8mb4_general_ci"), + ("Groups", "utf8mb4", "utf8mb4_general_ci"), + ("Licenses", "utf8mb4", "utf8mb4_general_ci"), + ("OfficialProviders", "utf8mb4", "utf8mb4_bin"), + ("PackageBases", "utf8mb4", "utf8mb4_general_ci"), + ("PackageBlacklist", "utf8mb4", "utf8mb4_general_ci"), + ("PackageComments", "utf8mb4", "utf8mb4_general_ci"), + ("PackageDepends", "utf8mb4", "utf8mb4_general_ci"), + ("PackageKeywords", "utf8mb4", "utf8mb4_general_ci"), + ("PackageRelations", "utf8mb4", "utf8mb4_general_ci"), + ("PackageRequests", "utf8mb4", "utf8mb4_general_ci"), + ("PackageSources", "utf8mb4", "utf8mb4_general_ci"), + ("Packages", "utf8mb4", "utf8mb4_general_ci"), + ("RelationTypes", "utf8mb4", "utf8mb4_general_ci"), + ("RequestTypes", "utf8mb4", "utf8mb4_general_ci"), + ("SSHPubKeys", "utf8mb4", "utf8mb4_bin"), + ("Sessions", "utf8mb4", "utf8mb4_bin"), + ("TU_VoteInfo", "utf8mb4", "utf8mb4_general_ci"), + ("Terms", "utf8mb4", "utf8mb4_general_ci"), + ("Users", "utf8mb4", "utf8mb4_general_ci"), ] # Indexes affected by charset/collate change # Map of Unique Indexes key = index_name, value = [table_name, column1, column2] -indexes = {'ProviderNameProvides': ['OfficialProviders', 'Name', 'Provides']} +indexes = {"ProviderNameProvides": ["OfficialProviders", "Name", "Provides"]} # Source charset/collation, before this migration is run. src_charset = "utf8" diff --git a/migrations/versions/be7adae47ac3_upgrade_voteinfo_integers.py b/migrations/versions/be7adae47ac3_upgrade_voteinfo_integers.py index d910a14b..d273804f 100644 --- a/migrations/versions/be7adae47ac3_upgrade_voteinfo_integers.py +++ b/migrations/versions/be7adae47ac3_upgrade_voteinfo_integers.py @@ -19,8 +19,8 @@ from alembic import op from sqlalchemy.dialects.mysql import INTEGER, TINYINT # revision identifiers, used by Alembic. -revision = 'be7adae47ac3' -down_revision = '56e2ce8e2ffa' +revision = "be7adae47ac3" +down_revision = "56e2ce8e2ffa" branch_labels = None depends_on = None @@ -32,7 +32,7 @@ DOWNGRADE_T = TINYINT(3, unsigned=True) def upgrade(): - """ Upgrade 'Yes', 'No', 'Abstain' and 'ActiveTUs' to unsigned INTEGER. """ + """Upgrade 'Yes', 'No', 'Abstain' and 'ActiveTUs' to unsigned INTEGER.""" op.alter_column("TU_VoteInfo", "Yes", type_=UPGRADE_T) op.alter_column("TU_VoteInfo", "No", type_=UPGRADE_T) op.alter_column("TU_VoteInfo", "Abstain", type_=UPGRADE_T) diff --git a/migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py b/migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py index a89d97ef..a20b80fa 100644 --- a/migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py +++ b/migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py @@ -8,20 +8,19 @@ Create Date: 2022-02-18 12:47:05.322766 from datetime import datetime import sqlalchemy as sa - from alembic import op from aurweb import db from aurweb.models import PackageVote # revision identifiers, used by Alembic. -revision = 'd64e5571bc8d' -down_revision = 'be7adae47ac3' +revision = "d64e5571bc8d" +down_revision = "be7adae47ac3" branch_labels = None depends_on = None table = PackageVote.__tablename__ -column = 'VoteTS' +column = "VoteTS" epoch = datetime(1970, 1, 1) diff --git a/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py b/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py index 49bf055a..3cf369e7 100644 --- a/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py +++ b/migrations/versions/ef39fcd6e1cd_add_sso_account_id_in_table_users.py @@ -6,31 +6,32 @@ Create Date: 2020-06-08 10:04:13.898617 """ import sqlalchemy as sa - from alembic import op from sqlalchemy.engine.reflection import Inspector # revision identifiers, used by Alembic. -revision = 'ef39fcd6e1cd' -down_revision = 'f47cad5d6d03' +revision = "ef39fcd6e1cd" +down_revision = "f47cad5d6d03" branch_labels = None depends_on = None def table_has_column(table, column_name): for element in Inspector.from_engine(op.get_bind()).get_columns(table): - if element.get('name') == column_name: + if element.get("name") == column_name: return True return False def upgrade(): - if not table_has_column('Users', 'SSOAccountID'): - op.add_column('Users', sa.Column('SSOAccountID', sa.String(length=255), nullable=True)) - op.create_unique_constraint(None, 'Users', ['SSOAccountID']) + if not table_has_column("Users", "SSOAccountID"): + op.add_column( + "Users", sa.Column("SSOAccountID", sa.String(length=255), nullable=True) + ) + op.create_unique_constraint(None, "Users", ["SSOAccountID"]) def downgrade(): - if table_has_column('Users', 'SSOAccountID'): - op.drop_constraint('SSOAccountID', 'Users', type_='unique') - op.drop_column('Users', 'SSOAccountID') + if table_has_column("Users", "SSOAccountID"): + op.drop_constraint("SSOAccountID", "Users", type_="unique") + op.drop_column("Users", "SSOAccountID") diff --git a/migrations/versions/f47cad5d6d03_initial_revision.py b/migrations/versions/f47cad5d6d03_initial_revision.py index b214beea..7373e0fb 100644 --- a/migrations/versions/f47cad5d6d03_initial_revision.py +++ b/migrations/versions/f47cad5d6d03_initial_revision.py @@ -5,7 +5,7 @@ Create Date: 2020-02-23 13:23:32.331396 """ # revision identifiers, used by Alembic. -revision = 'f47cad5d6d03' +revision = "f47cad5d6d03" down_revision = None branch_labels = None depends_on = None From 4e0618469df308340cb3ddb2f1c74d04c470c57a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 11 Sep 2022 18:40:31 -0700 Subject: [PATCH 1587/1891] fix(test): JSONResponse() requires a content argument with fastapi 0.83.0 Signed-off-by: Kevin Morris --- test/test_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_util.py b/test/test_util.py index 686e35b4..2e8b2e4e 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -44,7 +44,7 @@ async def test_error_or_result(): assert data.get("error") == "No response returned." async def good_route(request: fastapi.Request): - return JSONResponse() + return JSONResponse("{}") response = await util.error_or_result(good_route, Request()) assert response.status_code == HTTPStatus.OK From bb6e602e13184b79f8d5644866ab76215b723853 Mon Sep 17 00:00:00 2001 From: renovate Date: Mon, 12 Sep 2022 01:24:39 +0000 Subject: [PATCH 1588/1891] fix(deps): update dependency fastapi to ^0.83.0 --- poetry.lock | 27 ++++++++++++++------------- pyproject.toml | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index ef0fc1f7..ef2c70f9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -264,7 +264,7 @@ lua = ["lupa (>=1.13,<2.0)"] [[package]] name = "fastapi" -version = "0.71.0" +version = "0.83.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -272,13 +272,13 @@ python-versions = ">=3.6.1" [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.17.1" +starlette = "0.19.1" [package.extras] -all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,<5.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] -dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "typer-cli (>=0.0.12,<0.0.13)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==21.9b0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.1.7)", "types-orjson (==3.6.0)", "types-ujson (==0.1.1)", "ujson (>=4.0.1,<5.0.0)"] +all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] +dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] [[package]] name = "feedgen" @@ -924,14 +924,15 @@ parse = "*" [[package]] name = "starlette" -version = "0.17.1" +version = "0.19.1" description = "The little ASGI library that shines." category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -anyio = ">=3.0.0,<4" +anyio = ">=3.4.0,<5" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] @@ -1055,7 +1056,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "e084bad4236ac74fb90fcf4537c78c228b2de606e83c63ac2557a677d681e743" +content-hash = "e1f9d796eea832af84c40c754ee3c58e633e98bd7cdb42a985b2c8657e82037e" [metadata.files] aiofiles = [ @@ -1283,8 +1284,8 @@ fakeredis = [ {file = "fakeredis-1.9.0.tar.gz", hash = "sha256:60639946e3bb1274c30416f539f01f9d73b4ea68c244c1442f5524e45f51e882"}, ] fastapi = [ - {file = "fastapi-0.71.0-py3-none-any.whl", hash = "sha256:a78eca6b084de9667f2d5f37e2ae297270e5a119cd01c2f04815795da92fc87f"}, - {file = "fastapi-0.71.0.tar.gz", hash = "sha256:2b5ac0ae89c80b40d1dd4b2ea0bb1f78d7c4affd3644d080bf050f084759fff2"}, + {file = "fastapi-0.83.0-py3-none-any.whl", hash = "sha256:694a2b6c2607a61029a4be1c6613f84d74019cb9f7a41c7a475dca8e715f9368"}, + {file = "fastapi-0.83.0.tar.gz", hash = "sha256:96eb692350fe13d7a9843c3c87a874f0d45102975257dd224903efd6c0fde3bd"}, ] feedgen = [ {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, @@ -1812,8 +1813,8 @@ srcinfo = [ {file = "srcinfo-0.0.8.tar.gz", hash = "sha256:5ac610cf8b15d4b0a0374bd1f7ad301675c2938f0414addf3ef7d7e3fcaf5c65"}, ] starlette = [ - {file = "starlette-0.17.1-py3-none-any.whl", hash = "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050"}, - {file = "starlette-0.17.1.tar.gz", hash = "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8"}, + {file = "starlette-0.19.1-py3-none-any.whl", hash = "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf"}, + {file = "starlette-0.19.1.tar.gz", hash = "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7"}, ] "tap.py" = [ {file = "tap.py-3.1-py3-none-any.whl", hash = "sha256:928c852f3361707b796c93730cc5402c6378660b161114461066acf53d65bf5d"}, diff --git a/pyproject.toml b/pyproject.toml index 8f9624dc..4649d74f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,7 @@ pytest-xdist = "^2.4.0" filelock = "^3.3.2" posix-ipc = "^1.0.5" pyalpm = "^0.10.6" -fastapi = "^0.71.0" +fastapi = "^0.83.0" srcinfo = "^0.0.8" [tool.poetry.dev-dependencies] From df0a4a2be242a8bd5d318e71dcca0d90e0e1cc6a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 11 Sep 2022 19:04:42 -0700 Subject: [PATCH 1589/1891] feat(rpc): add /rpc/v5/{type} openapi-compatible routes We will be modeling future RPC implementations on an OpenAPI spec. While this commit does not completely cohere to OpenAPI in terms of response data, this is a good start and will allow us to cleanly document these openapi routes in the current and future. This commit brings in the new RPC routes: - GET /rpc/v5/info/{pkgname} - GET /rpc/v5/info?arg[]=pkg1&arg[]=pkg2 - POST /rpc/v5/info with JSON data `{"arg": ["pkg1", "pkg2"]}` - GET /rpc/v5/search?arg=keywords&by=valid-by-value - POST /rpc/v5/search with JSON data `{"by": "valid-by-value", "arg": "keywords"}` Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 104 ++++++++++++++++++++++++++++++++++++++++++ test/test_rpc.py | 95 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index a0cf5019..9777c0a2 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -160,3 +160,107 @@ async def rpc_post( callback: Optional[str] = Form(default=None), ): return await rpc_request(request, v, type, by, arg, args, callback) + + +@router.get("/rpc/v{version}/info/{name}") +async def rpc_openapi_info(request: Request, version: int, name: str): + return await rpc_request( + request, + version, + "info", + defaults.RPC_SEARCH_BY, + name, + [], + ) + + +@router.get("/rpc/v{version}/info") +async def rpc_openapi_multiinfo( + request: Request, + version: int, + args: Optional[list[str]] = Query(default=[], alias="arg[]"), +): + arg = args.pop(0) if args else None + return await rpc_request( + request, + version, + "info", + defaults.RPC_SEARCH_BY, + arg, + args, + ) + + +@router.post("/rpc/v{version}/info") +async def rpc_openapi_multiinfo_post( + request: Request, + version: int, +): + data = await request.json() + + args = data.get("arg", []) + if not isinstance(args, list): + rpc = RPC(version, "info") + return JSONResponse( + rpc.error("the 'arg' parameter must be of array type"), + status_code=HTTPStatus.BAD_REQUEST, + ) + + arg = args.pop(0) if args else None + return await rpc_request( + request, + version, + "info", + defaults.RPC_SEARCH_BY, + arg, + args, + ) + + +@router.get("/rpc/v{version}/search") +async def rpc_openapi_search( + request: Request, + version: int, + by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), + arg: Optional[str] = Query(default=str()), +): + return await rpc_request( + request, + version, + "search", + by, + arg, + [], + ) + + +@router.post("/rpc/v{version}/search") +async def rpc_openapi_search_post( + request: Request, + version: int, +): + data = await request.json() + by = data.get("by", defaults.RPC_SEARCH_BY) + if not isinstance(by, str): + rpc = RPC(version, "search") + return JSONResponse( + rpc.error("the 'by' parameter must be of string type"), + status_code=HTTPStatus.BAD_REQUEST, + ) + + arg = data.get("arg", str()) + if not isinstance(arg, str): + rpc = RPC(version, "search") + return JSONResponse( + rpc.error("the 'arg' parameter must be of string type"), + status_code=HTTPStatus.BAD_REQUEST, + ) + + return await rpc_request( + request, + version, + "search", + by, + arg, + [], + ) diff --git a/test/test_rpc.py b/test/test_rpc.py index ed7e8894..0edd3e2e 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -933,3 +933,98 @@ def test_rpc_too_many_info_results(client: TestClient, packages: list[Package]): with client as request: resp = request.get("/rpc", params=params) assert resp.json().get("error") == "Too many package results." + + +def test_rpc_openapi_info(client: TestClient, packages: list[Package]): + pkgname = packages[0].Name + + with client as request: + endp = f"/rpc/v5/info/{pkgname}" + resp = request.get(endp) + assert resp.status_code == HTTPStatus.OK + + data = resp.json() + assert data.get("resultcount") == 1 + + +def test_rpc_openapi_multiinfo(client: TestClient, packages: list[Package]): + pkgname = packages[0].Name + + with client as request: + endp = "/rpc/v5/info" + resp = request.get(endp, params={"arg[]": [pkgname]}) + assert resp.status_code == HTTPStatus.OK + + data = resp.json() + assert data.get("resultcount") == 1 + + +def test_rpc_openapi_multiinfo_post(client: TestClient, packages: list[Package]): + pkgname = packages[0].Name + + with client as request: + endp = "/rpc/v5/info" + resp = request.post(endp, json={"arg": [pkgname]}) + assert resp.status_code == HTTPStatus.OK + + data = resp.json() + assert data.get("resultcount") == 1 + + +def test_rpc_openapi_multiinfo_post_bad_request( + client: TestClient, packages: list[Package] +): + pkgname = packages[0].Name + + with client as request: + endp = "/rpc/v5/info" + resp = request.post(endp, json={"arg": pkgname}) + assert resp.status_code == HTTPStatus.BAD_REQUEST + + data = resp.json() + expected = "the 'arg' parameter must be of array type" + assert data.get("error") == expected + + +def test_rpc_openapi_search(client: TestClient, packages: list[Package]): + pkgname = packages[0].Name + + with client as request: + endp = "/rpc/v5/search" + resp = request.get(endp, params={"arg": pkgname}) + assert resp.status_code == HTTPStatus.OK + + data = resp.json() + assert data.get("resultcount") == 1 + + +def test_rpc_openapi_search_post(client: TestClient, packages: list[Package]): + pkgname = packages[0].Name + + with client as request: + endp = "/rpc/v5/search" + resp = request.post(endp, json={"arg": pkgname}) + assert resp.status_code == HTTPStatus.OK + + data = resp.json() + assert data.get("resultcount") == 1 + + +def test_rpc_openapi_search_post_bad_request(client: TestClient): + # Test by parameter + with client as request: + endp = "/rpc/v5/search" + resp = request.post(endp, json={"by": 1}) + assert resp.status_code == HTTPStatus.BAD_REQUEST + data = resp.json() + expected = "the 'by' parameter must be of string type" + assert data.get("error") == expected + + # Test arg parameter + with client as request: + endp = "/rpc/v5/search" + resp = request.post(endp, json={"arg": ["a", "list"]}) + assert resp.status_code == HTTPStatus.BAD_REQUEST + data = resp.json() + expected = "the 'arg' parameter must be of string type" + assert data.get("error") == expected From 9faa7b801d54fb853bcb54c720ae0a3e297e0b10 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 11 Sep 2022 15:22:10 -0700 Subject: [PATCH 1590/1891] feat: add cdn.jsdelivr.net to script/style CSP Signed-off-by: Kevin Morris --- aurweb/asgi.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index ccca3fc5..d1703c10 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -253,10 +253,14 @@ async def add_security_headers(request: Request, call_next: typing.Callable): # Add CSP header. nonce = request.user.nonce csp = "default-src 'self'; " - script_hosts = [] + + # swagger-ui needs access to cdn.jsdelivr.net javascript + script_hosts = ["cdn.jsdelivr.net"] csp += f"script-src 'self' 'nonce-{nonce}' " + " ".join(script_hosts) - # It's fine if css is inlined. - csp += "; style-src 'self' 'unsafe-inline'" + + # swagger-ui needs access to cdn.jsdelivr.net css + css_hosts = ["cdn.jsdelivr.net"] + csp += "; style-src 'self' 'unsafe-inline' " + " ".join(css_hosts) response.headers["Content-Security-Policy"] = csp # Add XTCO header. From 5e75a00c17609dc72fb8600cb309f07a7dde41e5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sun, 11 Sep 2022 19:59:16 -0700 Subject: [PATCH 1591/1891] upgrade: bump to version v6.1.3 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index df129c39..8b97cd0e 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.2" +AURWEB_VERSION = "v6.1.3" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 4649d74f..303b7637 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.2" +version = "v6.1.3" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 8e8b746a5b82511716b397c31e42f199a87e65d9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 12 Sep 2022 06:49:20 -0700 Subject: [PATCH 1592/1891] feat(rpc): add GET /rpc/v5/search/{arg} openapi route Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 19 ++++++++++++++++++- test/test_rpc.py | 12 ++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 9777c0a2..25574ff8 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -217,12 +217,29 @@ async def rpc_openapi_multiinfo_post( ) +@router.get("/rpc/v{version}/search/{arg}") +async def rpc_openapi_search_arg( + request: Request, + version: int, + arg: str, + by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), +): + return await rpc_request( + request, + version, + "search", + by, + arg, + [], + ) + + @router.get("/rpc/v{version}/search") async def rpc_openapi_search( request: Request, version: int, - by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), arg: Optional[str] = Query(default=str()), + by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY), ): return await rpc_request( request, diff --git a/test/test_rpc.py b/test/test_rpc.py index 0edd3e2e..e5b37542 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -986,6 +986,18 @@ def test_rpc_openapi_multiinfo_post_bad_request( assert data.get("error") == expected +def test_rpc_openapi_search_arg(client: TestClient, packages: list[Package]): + pkgname = packages[0].Name + + with client as request: + endp = f"/rpc/v5/search/{pkgname}" + resp = request.get(endp) + assert resp.status_code == HTTPStatus.OK + + data = resp.json() + assert data.get("resultcount") == 1 + + def test_rpc_openapi_search(client: TestClient, packages: list[Package]): pkgname = packages[0].Name From 17f2c05fd35cb105a5346671bd2e2ae178b83f02 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 12 Sep 2022 06:49:54 -0700 Subject: [PATCH 1593/1891] feat(rpc): add GET /rpc/v5/suggest/{arg} openapi route Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 12 ++++++++++++ test/test_rpc.py | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 25574ff8..23978f1d 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -281,3 +281,15 @@ async def rpc_openapi_search_post( arg, [], ) + + +@router.get("/rpc/v{version}/suggest/{arg}") +async def rpc_openapi_suggest(request: Request, version: int, arg: str): + return await rpc_request( + request, + version, + "suggest", + defaults.RPC_SEARCH_BY, + arg, + [], + ) diff --git a/test/test_rpc.py b/test/test_rpc.py index e5b37542..84ddd8d7 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -1040,3 +1040,19 @@ def test_rpc_openapi_search_post_bad_request(client: TestClient): data = resp.json() expected = "the 'arg' parameter must be of string type" assert data.get("error") == expected + + +def test_rpc_openapi_suggest(client: TestClient, packages: list[Package]): + suggestions = { + "big": ["big-chungus"], + "chungy": ["chungy-chungus"], + } + + for term, expected in suggestions.items(): + with client as request: + endp = f"/rpc/v5/suggest/{term}" + resp = request.get(endp) + assert resp.status_code == HTTPStatus.OK + + data = resp.json() + assert data == expected From 624954042b173c285e9ef5a87adc6319c3293685 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 12 Sep 2022 06:59:52 -0700 Subject: [PATCH 1594/1891] doc(rpc): include route doc at the top of aurweb.routers.rpc Signed-off-by: Kevin Morris --- aurweb/routers/rpc.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 23978f1d..f15b9781 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -1,3 +1,28 @@ +""" +RPC API routing module + +For legacy route documentation, see https://aur.archlinux.org/rpc + +Legacy Routes: +- GET /rpc +- POST /rpc + +Legacy example (version 5): /rpc?v=5&type=info&arg=my-package + +For OpenAPI route documentation, see https://aur.archlinux.org/docs + +OpenAPI Routes: +- GET /rpc/v{version}/info/{arg} +- GET /rpc/v{version}/info +- POST /rpc/v{version}/info +- GET /rpc/v{version}/search/{arg} +- GET /rpc/v{version}/search +- POST /rpc/v{version}/search +- GET /rpc/v{version}/suggest/{arg} + +OpenAPI example (version 5): /rpc/v5/info/my-package + +""" import hashlib import re from http import HTTPStatus From 37c7dee099841cfe368c64c93ae7432cc4364858 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 12 Sep 2022 10:36:50 -0700 Subject: [PATCH 1595/1891] fix: produce DeleteNotification a line before handle_request With this on a single line, the argument ordering and class/func execution was a bit too RNG causing exceptions to be thrown when producing a notification based off of a deleted pkgbase object. Signed-off-by: Kevin Morris --- aurweb/pkgbase/actions.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 4834f8dd..9e7b0df5 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -99,9 +99,8 @@ def pkgbase_adopt_instance(request: Request, pkgbase: PackageBase) -> None: def pkgbase_delete_instance( request: Request, pkgbase: PackageBase, comments: str = str() ) -> list[notify.Notification]: - notifs = handle_request(request, DELETION_ID, pkgbase) + [ - notify.DeleteNotification(request.user.ID, pkgbase.ID) - ] + notif = notify.DeleteNotification(request.user.ID, pkgbase.ID) + notifs = handle_request(request, DELETION_ID, pkgbase) + [notif] with db.begin(): update_closure_comment(pkgbase, DELETION_ID, comments) From adc3a218636e836988105f31872b139d88c5bcc1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 12 Sep 2022 12:28:42 -0700 Subject: [PATCH 1596/1891] fix: add 'unsafe-inline' to script-src CSP swagger-ui uses inline javascript to bootstrap itself, so we need to allow unsafe inline because we can't give swagger-ui a nonce to embed. Signed-off-by: Kevin Morris --- aurweb/asgi.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index d1703c10..72b47b4c 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -256,7 +256,9 @@ async def add_security_headers(request: Request, call_next: typing.Callable): # swagger-ui needs access to cdn.jsdelivr.net javascript script_hosts = ["cdn.jsdelivr.net"] - csp += f"script-src 'self' 'nonce-{nonce}' " + " ".join(script_hosts) + csp += f"script-src 'self' 'unsafe-inline' 'nonce-{nonce}' " + " ".join( + script_hosts + ) # swagger-ui needs access to cdn.jsdelivr.net css css_hosts = ["cdn.jsdelivr.net"] From f450b5dfc7e684392b85c253f44521bf097f095b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 12 Sep 2022 12:29:57 -0700 Subject: [PATCH 1597/1891] upgrade: bump to version v6.1.4 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 8b97cd0e..c1f87984 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.3" +AURWEB_VERSION = "v6.1.4" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 303b7637..f732f2e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.3" +version = "v6.1.4" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From ec3152014b05c2c6730e8363f32be01609c711b0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 13 Sep 2022 12:47:52 -0700 Subject: [PATCH 1598/1891] fix: retry transactions who fail due to deadlocks In my opinion, this kind of handling of transactions is pretty ugly. The being said, we have issues with running into deadlocks on aur.al, so this commit works against that immediate bug. An ideal solution would be to deal with retrying transactions through the `db.begin()` scope, so we wouldn't have to explicitly annotate functions as "retry functions," which is what this commit does. Closes #376 Signed-off-by: Kevin Morris --- aurweb/auth/__init__.py | 4 +- aurweb/db.py | 40 +++++++++++++++ aurweb/models/user.py | 2 +- aurweb/packages/requests.py | 23 +++++---- aurweb/packages/util.py | 20 ++++---- aurweb/pkgbase/actions.py | 91 ++++++++++++++++++++++++---------- aurweb/pkgbase/util.py | 2 + aurweb/ratelimit.py | 23 ++++++--- aurweb/routers/accounts.py | 26 +++++----- aurweb/routers/auth.py | 29 ++++++++--- aurweb/routers/html.py | 1 + aurweb/routers/pkgbase.py | 19 +++++++ aurweb/routers/requests.py | 1 + aurweb/routers/trusted_user.py | 16 +++--- aurweb/users/update.py | 6 +++ test/test_db.py | 20 ++++++++ 16 files changed, 241 insertions(+), 82 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 0c8bba69..b8056f91 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -96,6 +96,7 @@ class AnonymousUser: class BasicAuthBackend(AuthenticationBackend): + @db.async_retry_deadlock async def authenticate(self, conn: HTTPConnection): unauthenticated = (None, AnonymousUser()) sid = conn.cookies.get("AURSID") @@ -122,8 +123,7 @@ class BasicAuthBackend(AuthenticationBackend): # At this point, we cannot have an invalid user if the record # exists, due to ForeignKey constraints in the schema upheld # by mysqlclient. - with db.begin(): - user = db.query(User).filter(User.ID == record.UsersID).first() + user = db.query(User).filter(User.ID == record.UsersID).first() user.nonce = util.make_nonce() user.authenticated = True diff --git a/aurweb/db.py b/aurweb/db.py index 7425d928..ab0f80b8 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -161,6 +161,46 @@ def begin(): return get_session().begin() +def retry_deadlock(func): + from sqlalchemy.exc import OperationalError + + def wrapper(*args, _i: int = 0, **kwargs): + # Retry 10 times, then raise the exception + # If we fail before the 10th, recurse into `wrapper` + # If we fail on the 10th, continue to throw the exception + limit = 10 + try: + return func(*args, **kwargs) + except OperationalError as exc: + if _i < limit and "Deadlock found" in str(exc): + # Retry on deadlock by recursing into `wrapper` + return wrapper(*args, _i=_i + 1, **kwargs) + # Otherwise, just raise the exception + raise exc + + return wrapper + + +def async_retry_deadlock(func): + from sqlalchemy.exc import OperationalError + + async def wrapper(*args, _i: int = 0, **kwargs): + # Retry 10 times, then raise the exception + # If we fail before the 10th, recurse into `wrapper` + # If we fail on the 10th, continue to throw the exception + limit = 10 + try: + return await func(*args, **kwargs) + except OperationalError as exc: + if _i < limit and "Deadlock found" in str(exc): + # Retry on deadlock by recursing into `wrapper` + return await wrapper(*args, _i=_i + 1, **kwargs) + # Otherwise, just raise the exception + raise exc + + return wrapper + + def get_sqlalchemy_url(): """ Build an SQLAlchemy URL for use with create_engine. diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 0404c77a..0d638677 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -151,7 +151,7 @@ class User(Base): return has_credential(self, credential, approved) - def logout(self, request: Request): + def logout(self, request: Request) -> None: self.authenticated = False if self.session: with db.begin(): diff --git a/aurweb/packages/requests.py b/aurweb/packages/requests.py index 7309a880..c09082f5 100644 --- a/aurweb/packages/requests.py +++ b/aurweb/packages/requests.py @@ -151,6 +151,7 @@ def close_pkgreq( pkgreq.ClosedTS = now +@db.retry_deadlock def handle_request( request: Request, reqtype_id: int, pkgbase: PackageBase, target: PackageBase = None ) -> list[notify.Notification]: @@ -239,15 +240,19 @@ def handle_request( to_accept.append(pkgreq) # Update requests with their new status and closures. - with db.begin(): - util.apply_all( - to_accept, - lambda p: close_pkgreq(p, request.user, pkgbase, target, ACCEPTED_ID), - ) - util.apply_all( - to_reject, - lambda p: close_pkgreq(p, request.user, pkgbase, target, REJECTED_ID), - ) + @db.retry_deadlock + def retry_closures(): + with db.begin(): + util.apply_all( + to_accept, + lambda p: close_pkgreq(p, request.user, pkgbase, target, ACCEPTED_ID), + ) + util.apply_all( + to_reject, + lambda p: close_pkgreq(p, request.user, pkgbase, target, REJECTED_ID), + ) + + retry_closures() # Create RequestCloseNotifications for all requests involved. for pkgreq in to_accept + to_reject: diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 1ae7f9fe..b6ba7e20 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -99,8 +99,7 @@ def get_pkg_or_base( :raises HTTPException: With status code 404 if record doesn't exist :return: {Package,PackageBase} instance """ - with db.begin(): - instance = db.query(cls).filter(cls.Name == name).first() + instance = db.query(cls).filter(cls.Name == name).first() if not instance: raise HTTPException(status_code=HTTPStatus.NOT_FOUND) return instance @@ -133,16 +132,15 @@ def updated_packages(limit: int = 0, cache_ttl: int = 600) -> list[models.Packag # If we already have a cache, deserialize it and return. return orjson.loads(packages) - with db.begin(): - query = ( - db.query(models.Package) - .join(models.PackageBase) - .filter(models.PackageBase.PackagerUID.isnot(None)) - .order_by(models.PackageBase.ModifiedTS.desc()) - ) + query = ( + db.query(models.Package) + .join(models.PackageBase) + .filter(models.PackageBase.PackagerUID.isnot(None)) + .order_by(models.PackageBase.ModifiedTS.desc()) + ) - if limit: - query = query.limit(limit) + if limit: + query = query.limit(limit) packages = [] for pkg in query: diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 9e7b0df5..a453cb36 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -2,7 +2,7 @@ from fastapi import Request from aurweb import db, logging, util from aurweb.auth import creds -from aurweb.models import PackageBase +from aurweb.models import PackageBase, User from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_notification import PackageNotification from aurweb.models.request_type import DELETION_ID, MERGE_ID, ORPHAN_ID @@ -13,6 +13,12 @@ from aurweb.scripts import notify, popupdate logger = logging.get_logger(__name__) +@db.retry_deadlock +def _retry_notify(user: User, pkgbase: PackageBase) -> None: + with db.begin(): + db.create(PackageNotification, PackageBase=pkgbase, User=user) + + def pkgbase_notify_instance(request: Request, pkgbase: PackageBase) -> None: notif = db.query( pkgbase.notifications.filter( @@ -21,8 +27,13 @@ def pkgbase_notify_instance(request: Request, pkgbase: PackageBase) -> None: ).scalar() has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY) if has_cred and not notif: - with db.begin(): - db.create(PackageNotification, PackageBase=pkgbase, User=request.user) + _retry_notify(request.user, pkgbase) + + +@db.retry_deadlock +def _retry_unnotify(notif: PackageNotification, pkgbase: PackageBase) -> None: + with db.begin(): + db.delete(notif) def pkgbase_unnotify_instance(request: Request, pkgbase: PackageBase) -> None: @@ -31,8 +42,15 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: PackageBase) -> None: ).first() has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY) if has_cred and notif: - with db.begin(): - db.delete(notif) + _retry_unnotify(notif, pkgbase) + + +@db.retry_deadlock +def _retry_unflag(pkgbase: PackageBase) -> None: + with db.begin(): + pkgbase.OutOfDateTS = None + pkgbase.Flagger = None + pkgbase.FlaggerComment = str() def pkgbase_unflag_instance(request: Request, pkgbase: PackageBase) -> None: @@ -42,20 +60,17 @@ def pkgbase_unflag_instance(request: Request, pkgbase: PackageBase) -> None: + [c.User for c in pkgbase.comaintainers], ) if has_cred: - with db.begin(): - pkgbase.OutOfDateTS = None - pkgbase.Flagger = None - pkgbase.FlaggerComment = str() + _retry_unflag(pkgbase) -def pkgbase_disown_instance(request: Request, pkgbase: PackageBase) -> None: - disowner = request.user - notifs = [notify.DisownNotification(disowner.ID, pkgbase.ID)] +@db.retry_deadlock +def _retry_disown(request: Request, pkgbase: PackageBase): + notifs: list[notify.Notification] = [] - is_maint = disowner == pkgbase.Maintainer + is_maint = request.user == pkgbase.Maintainer comaint = pkgbase.comaintainers.filter( - PackageComaintainer.User == disowner + PackageComaintainer.User == request.user ).one_or_none() is_comaint = comaint is not None @@ -85,38 +100,48 @@ def pkgbase_disown_instance(request: Request, pkgbase: PackageBase) -> None: pkgbase.Maintainer = None db.delete_all(pkgbase.comaintainers) + return notifs + + +def pkgbase_disown_instance(request: Request, pkgbase: PackageBase) -> None: + disowner = request.user + notifs = [notify.DisownNotification(disowner.ID, pkgbase.ID)] + notifs += _retry_disown(request, pkgbase) util.apply_all(notifs, lambda n: n.send()) -def pkgbase_adopt_instance(request: Request, pkgbase: PackageBase) -> None: +@db.retry_deadlock +def _retry_adopt(request: Request, pkgbase: PackageBase) -> None: with db.begin(): pkgbase.Maintainer = request.user + +def pkgbase_adopt_instance(request: Request, pkgbase: PackageBase) -> None: + _retry_adopt(request, pkgbase) notif = notify.AdoptNotification(request.user.ID, pkgbase.ID) notif.send() +@db.retry_deadlock +def _retry_delete(pkgbase: PackageBase, comments: str) -> None: + with db.begin(): + update_closure_comment(pkgbase, DELETION_ID, comments) + db.delete(pkgbase) + + def pkgbase_delete_instance( request: Request, pkgbase: PackageBase, comments: str = str() ) -> list[notify.Notification]: notif = notify.DeleteNotification(request.user.ID, pkgbase.ID) notifs = handle_request(request, DELETION_ID, pkgbase) + [notif] - with db.begin(): - update_closure_comment(pkgbase, DELETION_ID, comments) - db.delete(pkgbase) + _retry_delete(pkgbase, comments) return notifs -def pkgbase_merge_instance( - request: Request, pkgbase: PackageBase, target: PackageBase, comments: str = str() -) -> None: - pkgbasename = str(pkgbase.Name) - - # Create notifications. - notifs = handle_request(request, MERGE_ID, pkgbase, target) - +@db.retry_deadlock +def _retry_merge(pkgbase: PackageBase, target: PackageBase) -> None: # Target votes and notifications sets of user IDs that are # looking to be migrated. target_votes = set(v.UsersID for v in target.package_votes) @@ -146,6 +171,20 @@ def pkgbase_merge_instance( db.delete(pkg) db.delete(pkgbase) + +def pkgbase_merge_instance( + request: Request, + pkgbase: PackageBase, + target: PackageBase, + comments: str = str(), +) -> None: + pkgbasename = str(pkgbase.Name) + + # Create notifications. + notifs = handle_request(request, MERGE_ID, pkgbase, target) + + _retry_merge(pkgbase, target) + # Log this out for accountability purposes. logger.info( f"Trusted User '{request.user.Username}' merged " diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index 223c3013..968135d1 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -106,6 +106,7 @@ def remove_comaintainer( return notif +@db.retry_deadlock def remove_comaintainers(pkgbase: PackageBase, usernames: list[str]) -> None: """ Remove comaintainers from `pkgbase`. @@ -155,6 +156,7 @@ class NoopComaintainerNotification: return +@db.retry_deadlock def add_comaintainer( pkgbase: PackageBase, comaintainer: User ) -> notify.ComaintainerAddNotification: diff --git a/aurweb/ratelimit.py b/aurweb/ratelimit.py index cb08cdf5..97923a52 100644 --- a/aurweb/ratelimit.py +++ b/aurweb/ratelimit.py @@ -38,17 +38,26 @@ def _update_ratelimit_db(request: Request): now = time.utcnow() time_to_delete = now - window_length + @db.retry_deadlock + def retry_delete(records: list[ApiRateLimit]) -> None: + with db.begin(): + db.delete_all(records) + records = db.query(ApiRateLimit).filter(ApiRateLimit.WindowStart < time_to_delete) - with db.begin(): - db.delete_all(records) + retry_delete(records) + + @db.retry_deadlock + def retry_create(record: ApiRateLimit, now: int, host: str) -> ApiRateLimit: + with db.begin(): + if not record: + record = db.create(ApiRateLimit, WindowStart=now, IP=host, Requests=1) + else: + record.Requests += 1 + return record host = request.client.host record = db.query(ApiRateLimit, ApiRateLimit.IP == host).first() - with db.begin(): - if not record: - record = db.create(ApiRateLimit, WindowStart=now, IP=host, Requests=1) - else: - record.Requests += 1 + record = retry_create(record, now, host) logger.debug(record.Requests) return record diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index db05955a..3937757a 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -32,6 +32,7 @@ async def passreset(request: Request): return render_template(request, "passreset.html", context) +@db.async_retry_deadlock @router.post("/passreset", response_class=HTMLResponse) @handle_form_exceptions @requires_guest @@ -260,6 +261,7 @@ async def account_register( return render_template(request, "register.html", context) +@db.async_retry_deadlock @router.post("/register", response_class=HTMLResponse) @handle_form_exceptions @requires_guest @@ -336,18 +338,15 @@ async def account_register_post( AccountType=atype, ) - # If a PK was given and either one does not exist or the given - # PK mismatches the existing user's SSHPubKey.PubKey. - if PK: - # Get the second element in the PK, which is the actual key. - keys = util.parse_ssh_keys(PK.strip()) - for k in keys: - pk = " ".join(k) - fprint = get_fingerprint(pk) - with db.begin(): - db.create( - models.SSHPubKey, UserID=user.ID, PubKey=pk, Fingerprint=fprint - ) + # If a PK was given and either one does not exist or the given + # PK mismatches the existing user's SSHPubKey.PubKey. + if PK: + # Get the second element in the PK, which is the actual key. + keys = util.parse_ssh_keys(PK.strip()) + for k in keys: + pk = " ".join(k) + fprint = get_fingerprint(pk) + db.create(models.SSHPubKey, User=user, PubKey=pk, Fingerprint=fprint) # Send a reset key notification to the new user. WelcomeNotification(user.ID).send() @@ -458,6 +457,8 @@ async def account_edit_post( update.password, ] + # These update functions are all guarded by retry_deadlock; + # there's no need to guard this route itself. for f in updates: f(**args, request=request, user=user, context=context) @@ -633,6 +634,7 @@ async def terms_of_service(request: Request): return render_terms_of_service(request, context, accept_needed) +@db.async_retry_deadlock @router.post("/tos") @handle_form_exceptions @requires_auth diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 3f94952e..0e675559 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -28,6 +28,11 @@ async def login_get(request: Request, next: str = "/"): return await login_template(request, next) +@db.retry_deadlock +def _retry_login(request: Request, user: User, passwd: str, cookie_timeout: int) -> str: + return user.login(request, passwd, cookie_timeout) + + @router.post("/login", response_class=HTMLResponse) @handle_form_exceptions @requires_guest @@ -48,13 +53,16 @@ async def login_post( status_code=HTTPStatus.BAD_REQUEST, detail=_("Bad Referer header.") ) - with db.begin(): - user = ( - db.query(User) - .filter(or_(User.Username == user, User.Email == user)) - .first() + user = ( + db.query(User) + .filter( + or_( + User.Username == user, + User.Email == user, + ) ) - + .first() + ) if not user: return await login_template(request, next, errors=["Bad username or password."]) @@ -62,7 +70,7 @@ async def login_post( return await login_template(request, next, errors=["Account Suspended"]) cookie_timeout = cookies.timeout(remember_me) - sid = user.login(request, passwd, cookie_timeout) + sid = _retry_login(request, user, passwd, cookie_timeout) if not sid: return await login_template(request, next, errors=["Bad username or password."]) @@ -101,12 +109,17 @@ async def login_post( return response +@db.retry_deadlock +def _retry_logout(request: Request) -> None: + request.user.logout(request) + + @router.post("/logout") @handle_form_exceptions @requires_auth async def logout(request: Request, next: str = Form(default="/")): if request.user.is_authenticated(): - request.user.logout(request) + _retry_logout(request) # Use 303 since we may be handling a post request, that'll get it # to redirect to a get request. diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 2148d535..da1ffd55 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -35,6 +35,7 @@ async def favicon(request: Request): return RedirectResponse("/static/images/favicon.ico") +@db.async_retry_deadlock @router.post("/language", response_class=RedirectResponse) @handle_form_exceptions async def language( diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 076aec1e..3b1ab688 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -87,6 +87,7 @@ async def pkgbase_flag_comment(request: Request, name: str): return render_template(request, "pkgbase/flag-comment.html", context) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/keywords") @handle_form_exceptions async def pkgbase_keywords( @@ -139,6 +140,7 @@ async def pkgbase_flag_get(request: Request, name: str): return render_template(request, "pkgbase/flag.html", context) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/flag") @handle_form_exceptions @requires_auth @@ -170,6 +172,7 @@ async def pkgbase_flag_post( return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/comments") @handle_form_exceptions @requires_auth @@ -279,6 +282,7 @@ async def pkgbase_comment_edit( return render_template(request, "pkgbase/comments/edit.html", context) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/comments/{id}") @handle_form_exceptions @requires_auth @@ -324,6 +328,7 @@ async def pkgbase_comment_post( ) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/comments/{id}/pin") @handle_form_exceptions @requires_auth @@ -362,6 +367,7 @@ async def pkgbase_comment_pin( return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/comments/{id}/unpin") @handle_form_exceptions @requires_auth @@ -399,6 +405,7 @@ async def pkgbase_comment_unpin( return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/comments/{id}/delete") @handle_form_exceptions @requires_auth @@ -440,6 +447,7 @@ async def pkgbase_comment_delete( return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/comments/{id}/undelete") @handle_form_exceptions @requires_auth @@ -482,6 +490,7 @@ async def pkgbase_comment_undelete( return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/vote") @handle_form_exceptions @requires_auth @@ -501,6 +510,7 @@ async def pkgbase_vote(request: Request, name: str): return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/unvote") @handle_form_exceptions @requires_auth @@ -519,6 +529,7 @@ async def pkgbase_unvote(request: Request, name: str): return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/notify") @handle_form_exceptions @requires_auth @@ -528,6 +539,7 @@ async def pkgbase_notify(request: Request, name: str): return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/unnotify") @handle_form_exceptions @requires_auth @@ -537,6 +549,7 @@ async def pkgbase_unnotify(request: Request, name: str): return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/unflag") @handle_form_exceptions @requires_auth @@ -567,6 +580,7 @@ async def pkgbase_disown_get( return render_template(request, "pkgbase/disown.html", context) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/disown") @handle_form_exceptions @requires_auth @@ -617,6 +631,7 @@ async def pkgbase_disown_post( return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/adopt") @handle_form_exceptions @requires_auth @@ -659,6 +674,7 @@ async def pkgbase_comaintainers(request: Request, name: str) -> Response: return render_template(request, "pkgbase/comaintainers.html", context) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/comaintainers") @handle_form_exceptions @requires_auth @@ -715,6 +731,7 @@ async def pkgbase_request( return render_template(request, "pkgbase/request.html", context) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/request") @handle_form_exceptions @requires_auth @@ -817,6 +834,7 @@ async def pkgbase_delete_get( return render_template(request, "pkgbase/delete.html", context) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/delete") @handle_form_exceptions @requires_auth @@ -889,6 +907,7 @@ async def pkgbase_merge_get( ) +@db.async_retry_deadlock @router.post("/pkgbase/{name}/merge") @handle_form_exceptions @requires_auth diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 51be6d2c..bf86bdcc 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -69,6 +69,7 @@ async def request_close(request: Request, id: int): return render_template(request, "requests/close.html", context) +@db.async_retry_deadlock @router.post("/requests/{id}/close") @handle_form_exceptions @requires_auth diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index a84bb6bd..37edb072 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -217,6 +217,7 @@ async def trusted_user_proposal(request: Request, proposal: int): return render_proposal(request, context, proposal, voteinfo, voters, vote) +@db.async_retry_deadlock @router.post("/tu/{proposal}") @handle_form_exceptions @requires_auth @@ -267,13 +268,15 @@ async def trusted_user_proposal_post( request, context, proposal, voteinfo, voters, vote, status_code=status_code ) - if decision in {"Yes", "No", "Abstain"}: - # Increment whichever decision was given to us. - setattr(voteinfo, decision, getattr(voteinfo, decision) + 1) - else: - return Response("Invalid 'decision' value.", status_code=HTTPStatus.BAD_REQUEST) - with db.begin(): + if decision in {"Yes", "No", "Abstain"}: + # Increment whichever decision was given to us. + setattr(voteinfo, decision, getattr(voteinfo, decision) + 1) + else: + return Response( + "Invalid 'decision' value.", status_code=HTTPStatus.BAD_REQUEST + ) + vote = db.create(models.TUVote, User=request.user, VoteInfo=voteinfo) context["error"] = "You've already voted for this proposal." @@ -301,6 +304,7 @@ async def trusted_user_addvote( return render_template(request, "addvote.html", context) +@db.async_retry_deadlock @router.post("/addvote") @handle_form_exceptions @requires_auth diff --git a/aurweb/users/update.py b/aurweb/users/update.py index 51f2d2e0..6bd4a295 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -8,6 +8,7 @@ from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.util import strtobool +@db.retry_deadlock def simple( U: str = str(), E: str = str(), @@ -42,6 +43,7 @@ def simple( user.OwnershipNotify = strtobool(ON) +@db.retry_deadlock def language( L: str = str(), request: Request = None, @@ -55,6 +57,7 @@ def language( context["language"] = L +@db.retry_deadlock def timezone( TZ: str = str(), request: Request = None, @@ -68,6 +71,7 @@ def timezone( context["language"] = TZ +@db.retry_deadlock def ssh_pubkey(PK: str = str(), user: models.User = None, **kwargs) -> None: if not PK: # If no pubkey is provided, wipe out any pubkeys the user @@ -101,12 +105,14 @@ def ssh_pubkey(PK: str = str(), user: models.User = None, **kwargs) -> None: ) +@db.retry_deadlock def account_type(T: int = None, user: models.User = None, **kwargs) -> None: if T is not None and (T := int(T)) != user.AccountTypeID: with db.begin(): user.AccountTypeID = T +@db.retry_deadlock def password( P: str = str(), request: Request = None, diff --git a/test/test_db.py b/test/test_db.py index 8ac5607d..22dbdd36 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -5,6 +5,7 @@ import tempfile from unittest import mock import pytest +from sqlalchemy.exc import OperationalError import aurweb.config import aurweb.initdb @@ -226,3 +227,22 @@ def test_name_without_pytest_current_test(): with mock.patch.dict("os.environ", {}, clear=True): dbname = aurweb.db.name() assert dbname == aurweb.config.get("database", "name") + + +def test_retry_deadlock(): + @db.retry_deadlock + def func(): + raise OperationalError("Deadlock found", tuple(), "") + + with pytest.raises(OperationalError): + func() + + +@pytest.mark.asyncio +async def test_async_retry_deadlock(): + @db.async_retry_deadlock + async def func(): + raise OperationalError("Deadlock found", tuple(), "") + + with pytest.raises(OperationalError): + await func() From 30e72d2db5f9b3b863ddc03efda65c37c0a4aa2c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 24 Sep 2022 16:51:25 +0000 Subject: [PATCH 1599/1891] feat: archive git repository (experimental) See doc/git-archive.md for general Git archive specifications See doc/repos/metadata-repo.md for info and direction related to the new Git metadata archive --- aurweb/archives/__init__.py | 1 + aurweb/archives/spec/__init__.py | 1 + aurweb/archives/spec/base.py | 77 ++++++ aurweb/archives/spec/metadata.py | 85 ++++++ aurweb/archives/spec/pkgbases.py | 32 +++ aurweb/archives/spec/pkgnames.py | 33 +++ aurweb/archives/spec/users.py | 26 ++ aurweb/models/package_base.py | 10 + aurweb/pkgbase/util.py | 5 +- aurweb/rpc.py | 76 +++--- aurweb/schema.py | 6 + aurweb/scripts/git_archive.py | 125 +++++++++ aurweb/scripts/mkpkglists.py | 1 + aurweb/scripts/popupdate.py | 14 +- aurweb/testing/git.py | 8 +- aurweb/util.py | 8 + conf/config.defaults | 12 + conf/config.dev | 6 + doc/git-archive.md | 75 ++++++ doc/maintenance.txt | 36 ++- doc/repos/metadata-repo.md | 121 +++++++++ doc/repos/pkgbases-repo.md | 15 ++ doc/repos/pkgnames-repo.md | 15 ++ doc/repos/users-repo.md | 15 ++ doc/specs/metadata.md | 14 + doc/specs/pkgbases.md | 14 + doc/specs/pkgnames.md | 14 + doc/specs/popularity.md | 14 + doc/specs/users.md | 14 + ...70_add_popularityupdated_to_packagebase.py | 33 +++ pyproject.toml | 1 + templates/partials/packages/details.html | 2 +- test/test_git_archives.py | 241 ++++++++++++++++++ test/test_templates.py | 4 + 34 files changed, 1104 insertions(+), 50 deletions(-) create mode 100644 aurweb/archives/__init__.py create mode 100644 aurweb/archives/spec/__init__.py create mode 100644 aurweb/archives/spec/base.py create mode 100644 aurweb/archives/spec/metadata.py create mode 100644 aurweb/archives/spec/pkgbases.py create mode 100644 aurweb/archives/spec/pkgnames.py create mode 100644 aurweb/archives/spec/users.py create mode 100644 aurweb/scripts/git_archive.py create mode 100644 doc/git-archive.md create mode 100644 doc/repos/metadata-repo.md create mode 100644 doc/repos/pkgbases-repo.md create mode 100644 doc/repos/pkgnames-repo.md create mode 100644 doc/repos/users-repo.md create mode 100644 doc/specs/metadata.md create mode 100644 doc/specs/pkgbases.md create mode 100644 doc/specs/pkgnames.md create mode 100644 doc/specs/popularity.md create mode 100644 doc/specs/users.md create mode 100644 migrations/versions/6441d3b65270_add_popularityupdated_to_packagebase.py create mode 100644 test/test_git_archives.py diff --git a/aurweb/archives/__init__.py b/aurweb/archives/__init__.py new file mode 100644 index 00000000..47020641 --- /dev/null +++ b/aurweb/archives/__init__.py @@ -0,0 +1 @@ +# aurweb.archives diff --git a/aurweb/archives/spec/__init__.py b/aurweb/archives/spec/__init__.py new file mode 100644 index 00000000..b6e376b4 --- /dev/null +++ b/aurweb/archives/spec/__init__.py @@ -0,0 +1 @@ +# aurweb.archives.spec diff --git a/aurweb/archives/spec/base.py b/aurweb/archives/spec/base.py new file mode 100644 index 00000000..60f734f2 --- /dev/null +++ b/aurweb/archives/spec/base.py @@ -0,0 +1,77 @@ +from pathlib import Path +from typing import Any, Dict, Iterable, List, Set + + +class GitInfo: + """Information about a Git repository.""" + + """ Path to Git repository. """ + path: str + + """ Local Git repository configuration. """ + config: Dict[str, Any] + + def __init__(self, path: str, config: Dict[str, Any] = dict()) -> "GitInfo": + self.path = Path(path) + self.config = config + + +class SpecOutput: + """Class used for git_archive.py output details.""" + + """ Filename relative to the Git repository root. """ + filename: Path + + """ Git repository information. """ + git_info: GitInfo + + """ Bytes bound for `SpecOutput.filename`. """ + data: bytes + + def __init__(self, filename: str, git_info: GitInfo, data: bytes) -> "SpecOutput": + self.filename = filename + self.git_info = git_info + self.data = data + + +class SpecBase: + """ + Base for Spec classes defined in git_archve.py --spec modules. + + All supported --spec modules must contain the following classes: + - Spec(SpecBase) + """ + + """ A list of SpecOutputs, each of which contain output file data. """ + outputs: List[SpecOutput] = list() + + """ A set of repositories to commit changes to. """ + repos: Set[str] = set() + + def generate(self) -> Iterable[SpecOutput]: + """ + "Pure virtual" output generator. + + `SpecBase.outputs` and `SpecBase.repos` should be populated within an + overridden version of this function in SpecBase derivatives. + """ + raise NotImplementedError() + + def add_output(self, filename: str, git_info: GitInfo, data: bytes) -> None: + """ + Add a SpecOutput instance to the set of outputs. + + :param filename: Filename relative to the git repository root + :param git_info: GitInfo instance + :param data: Binary data bound for `filename` + """ + if git_info.path not in self.repos: + self.repos.add(git_info.path) + + self.outputs.append( + SpecOutput( + filename, + git_info, + data, + ) + ) diff --git a/aurweb/archives/spec/metadata.py b/aurweb/archives/spec/metadata.py new file mode 100644 index 00000000..e7c8e096 --- /dev/null +++ b/aurweb/archives/spec/metadata.py @@ -0,0 +1,85 @@ +from typing import Iterable + +import orjson + +from aurweb import config, db +from aurweb.models import Package, PackageBase, User +from aurweb.rpc import RPC + +from .base import GitInfo, SpecBase, SpecOutput + +ORJSON_OPTS = orjson.OPT_SORT_KEYS | orjson.OPT_INDENT_2 + + +class Spec(SpecBase): + def __init__(self) -> "Spec": + self.metadata_repo = GitInfo( + config.get("git-archive", "metadata-repo"), + ) + + def generate(self) -> Iterable[SpecOutput]: + # Base query used by the RPC. + base_query = ( + db.query(Package) + .join(PackageBase) + .join(User, PackageBase.MaintainerUID == User.ID) + ) + + # Create an instance of RPC, use it to get entities from + # our query and perform a metadata subquery for all packages. + rpc = RPC(version=5, type="info") + print("performing package database query") + packages = rpc.entities(base_query).all() + print("performing package database subqueries") + rpc.subquery({pkg.ID for pkg in packages}) + + pkgbases, pkgnames = dict(), dict() + for package in packages: + # Produce RPC type=info data for `package` + data = rpc.get_info_json_data(package) + + pkgbase_name = data.get("PackageBase") + pkgbase_data = { + "ID": data.pop("PackageBaseID"), + "URLPath": data.pop("URLPath"), + "FirstSubmitted": data.pop("FirstSubmitted"), + "LastModified": data.pop("LastModified"), + "OutOfDate": data.pop("OutOfDate"), + "Maintainer": data.pop("Maintainer"), + "Keywords": data.pop("Keywords"), + "NumVotes": data.pop("NumVotes"), + "Popularity": data.pop("Popularity"), + "PopularityUpdated": package.PopularityUpdated.timestamp(), + } + + # Store the data in `pkgbases` dict. We do this so we only + # end up processing a single `pkgbase` if repeated after + # this loop + pkgbases[pkgbase_name] = pkgbase_data + + # Remove Popularity and NumVotes from package data. + # These fields change quite often which causes git data + # modification to explode. + # data.pop("NumVotes") + # data.pop("Popularity") + + # Remove the ID key from package json. + data.pop("ID") + + # Add the `package`.Name to the pkgnames set + name = data.get("Name") + pkgnames[name] = data + + # Add metadata outputs + self.add_output( + "pkgname.json", + self.metadata_repo, + orjson.dumps(pkgnames, option=ORJSON_OPTS), + ) + self.add_output( + "pkgbase.json", + self.metadata_repo, + orjson.dumps(pkgbases, option=ORJSON_OPTS), + ) + + return self.outputs diff --git a/aurweb/archives/spec/pkgbases.py b/aurweb/archives/spec/pkgbases.py new file mode 100644 index 00000000..9f02c1c6 --- /dev/null +++ b/aurweb/archives/spec/pkgbases.py @@ -0,0 +1,32 @@ +from typing import Iterable + +import orjson + +from aurweb import config, db +from aurweb.models import PackageBase + +from .base import GitInfo, SpecBase, SpecOutput + +ORJSON_OPTS = orjson.OPT_SORT_KEYS | orjson.OPT_INDENT_2 + + +class Spec(SpecBase): + def __init__(self) -> "Spec": + self.pkgbases_repo = GitInfo(config.get("git-archive", "pkgbases-repo")) + + def generate(self) -> Iterable[SpecOutput]: + filt = PackageBase.PackagerUID.isnot(None) + query = ( + db.query(PackageBase.Name) + .filter(filt) + .order_by(PackageBase.Name.asc()) + .all() + ) + pkgbases = [pkgbase.Name for pkgbase in query] + + self.add_output( + "pkgbase.json", + self.pkgbases_repo, + orjson.dumps(pkgbases, option=ORJSON_OPTS), + ) + return self.outputs diff --git a/aurweb/archives/spec/pkgnames.py b/aurweb/archives/spec/pkgnames.py new file mode 100644 index 00000000..c7cd9ea7 --- /dev/null +++ b/aurweb/archives/spec/pkgnames.py @@ -0,0 +1,33 @@ +from typing import Iterable + +import orjson + +from aurweb import config, db +from aurweb.models import Package, PackageBase + +from .base import GitInfo, SpecBase, SpecOutput + +ORJSON_OPTS = orjson.OPT_SORT_KEYS | orjson.OPT_INDENT_2 + + +class Spec(SpecBase): + def __init__(self) -> "Spec": + self.pkgnames_repo = GitInfo(config.get("git-archive", "pkgnames-repo")) + + def generate(self) -> Iterable[SpecOutput]: + filt = PackageBase.PackagerUID.isnot(None) + query = ( + db.query(Package.Name) + .join(PackageBase, PackageBase.ID == Package.PackageBaseID) + .filter(filt) + .order_by(Package.Name.asc()) + .all() + ) + pkgnames = [pkg.Name for pkg in query] + + self.add_output( + "pkgname.json", + self.pkgnames_repo, + orjson.dumps(pkgnames, option=ORJSON_OPTS), + ) + return self.outputs diff --git a/aurweb/archives/spec/users.py b/aurweb/archives/spec/users.py new file mode 100644 index 00000000..80da1641 --- /dev/null +++ b/aurweb/archives/spec/users.py @@ -0,0 +1,26 @@ +from typing import Iterable + +import orjson + +from aurweb import config, db +from aurweb.models import User + +from .base import GitInfo, SpecBase, SpecOutput + +ORJSON_OPTS = orjson.OPT_SORT_KEYS | orjson.OPT_INDENT_2 + + +class Spec(SpecBase): + def __init__(self) -> "Spec": + self.users_repo = GitInfo(config.get("git-archive", "users-repo")) + + def generate(self) -> Iterable[SpecOutput]: + query = db.query(User.Username).order_by(User.Username.asc()).all() + users = [user.Username for user in query] + + self.add_output( + "users.json", + self.users_repo, + orjson.dumps(users, option=ORJSON_OPTS), + ) + return self.outputs diff --git a/aurweb/models/package_base.py b/aurweb/models/package_base.py index bf80233d..26d9165f 100644 --- a/aurweb/models/package_base.py +++ b/aurweb/models/package_base.py @@ -64,3 +64,13 @@ class PackageBase(Base): if key in PackageBase.TO_FLOAT and not isinstance(attr, float): return float(attr) return attr + + +def popularity_decay(pkgbase: PackageBase, utcnow: int): + """Return the delta between now and the last time popularity was updated, in days""" + return int((utcnow - pkgbase.PopularityUpdated.timestamp()) / 86400) + + +def popularity(pkgbase: PackageBase, utcnow: int): + """Return up-to-date popularity""" + return float(pkgbase.Popularity) * (0.98 ** popularity_decay(pkgbase, utcnow)) diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py index 968135d1..46d6e2db 100644 --- a/aurweb/pkgbase/util.py +++ b/aurweb/pkgbase/util.py @@ -3,8 +3,9 @@ from typing import Any from fastapi import Request from sqlalchemy import and_ -from aurweb import config, db, defaults, l10n, util +from aurweb import config, db, defaults, l10n, time, util from aurweb.models import PackageBase, User +from aurweb.models.package_base import popularity from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_comment import PackageComment from aurweb.models.package_request import PENDING_ID, PackageRequest @@ -81,6 +82,8 @@ def make_context( and_(PackageRequest.Status == PENDING_ID, PackageRequest.ClosedTS.is_(None)) ).count() + context["popularity"] = popularity(pkgbase, time.utcnow()) + return context diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 26677f80..515c6ffb 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -6,9 +6,10 @@ from fastapi.responses import HTMLResponse from sqlalchemy import and_, literal, orm import aurweb.config as config -from aurweb import db, defaults, models +from aurweb import db, defaults, models, time from aurweb.exceptions import RPCError from aurweb.filters import number_format +from aurweb.models.package_base import popularity from aurweb.packages.search import RPCSearch TYPE_MAPPING = { @@ -120,16 +121,15 @@ class RPC: if not args: raise RPCError("No request type/data specified.") - def _get_json_data(self, package: models.Package) -> dict[str, Any]: + def get_json_data(self, package: models.Package) -> dict[str, Any]: """Produce dictionary data of one Package that can be JSON-serialized. :param package: Package instance :returns: JSON-serializable dictionary """ - # Produce RPC API compatible Popularity: If zero, it's an integer - # 0, otherwise, it's formatted to the 6th decimal place. - pop = package.Popularity + # Normalize Popularity for RPC output to 6 decimal precision + pop = popularity(package, time.utcnow()) pop = 0 if not pop else float(number_format(pop, 6)) snapshot_uri = config.get("options", "snapshot_uri") @@ -151,8 +151,8 @@ class RPC: "LastModified": package.ModifiedTS, } - def _get_info_json_data(self, package: models.Package) -> dict[str, Any]: - data = self._get_json_data(package) + def get_info_json_data(self, package: models.Package) -> dict[str, Any]: + data = self.get_json_data(package) # All info results have _at least_ an empty list of # License and Keywords. @@ -176,7 +176,7 @@ class RPC: """ return [data_generator(pkg) for pkg in packages] - def _entities(self, query: orm.Query) -> orm.Query: + def entities(self, query: orm.Query) -> orm.Query: """Select specific RPC columns on `query`.""" return query.with_entities( models.Package.ID, @@ -188,38 +188,14 @@ class RPC: models.PackageBase.Name.label("PackageBaseName"), models.PackageBase.NumVotes, models.PackageBase.Popularity, + models.PackageBase.PopularityUpdated, models.PackageBase.OutOfDateTS, models.PackageBase.SubmittedTS, models.PackageBase.ModifiedTS, models.User.Username.label("Maintainer"), ).group_by(models.Package.ID) - def _handle_multiinfo_type( - self, args: list[str] = [], **kwargs - ) -> list[dict[str, Any]]: - self._enforce_args(args) - args = set(args) - - packages = ( - db.query(models.Package) - .join(models.PackageBase) - .join( - models.User, - models.User.ID == models.PackageBase.MaintainerUID, - isouter=True, - ) - .filter(models.Package.Name.in_(args)) - ) - - max_results = config.getint("options", "max_rpc_results") - packages = self._entities(packages).limit(max_results + 1) - - if packages.count() > max_results: - raise RPCError("Too many package results.") - - ids = {pkg.ID for pkg in packages} - - # Aliases for 80-width. + def subquery(self, ids: set[int]): Package = models.Package PackageKeyword = models.PackageKeyword @@ -311,7 +287,33 @@ class RPC: self.extra_info[record.ID][type_].append(name) - return self._assemble_json_data(packages, self._get_info_json_data) + def _handle_multiinfo_type( + self, args: list[str] = [], **kwargs + ) -> list[dict[str, Any]]: + self._enforce_args(args) + args = set(args) + + packages = ( + db.query(models.Package) + .join(models.PackageBase) + .join( + models.User, + models.User.ID == models.PackageBase.MaintainerUID, + isouter=True, + ) + .filter(models.Package.Name.in_(args)) + ) + + max_results = config.getint("options", "max_rpc_results") + packages = self.entities(packages).limit(max_results + 1) + + if packages.count() > max_results: + raise RPCError("Too many package results.") + + ids = {pkg.ID for pkg in packages} + self.subquery(ids) + + return self._assemble_json_data(packages, self.get_info_json_data) def _handle_search_type( self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = [] @@ -330,12 +332,12 @@ class RPC: search.search_by(by, arg) max_results = config.getint("options", "max_rpc_results") - results = self._entities(search.results()).limit(max_results + 1).all() + results = self.entities(search.results()).limit(max_results + 1).all() if len(results) > max_results: raise RPCError("Too many package results.") - return self._assemble_json_data(results, self._get_json_data) + return self._assemble_json_data(results, self.get_json_data) def _handle_msearch_type( self, args: list[str] = [], **kwargs diff --git a/aurweb/schema.py b/aurweb/schema.py index b3b36195..5f998ed9 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -155,6 +155,12 @@ PackageBases = Table( nullable=False, server_default=text("0"), ), + Column( + "PopularityUpdated", + TIMESTAMP, + nullable=False, + server_default=text("'1970-01-01 00:00:01.000000'"), + ), Column("OutOfDateTS", BIGINT(unsigned=True)), Column("FlaggerComment", Text, nullable=False), Column("SubmittedTS", BIGINT(unsigned=True), nullable=False), diff --git a/aurweb/scripts/git_archive.py b/aurweb/scripts/git_archive.py new file mode 100644 index 00000000..4c909c18 --- /dev/null +++ b/aurweb/scripts/git_archive.py @@ -0,0 +1,125 @@ +import argparse +import importlib +import os +import sys +import traceback +from datetime import datetime + +import orjson +import pygit2 + +from aurweb import config + +# Constants +REF = "refs/heads/master" +ORJSON_OPTS = orjson.OPT_SORT_KEYS | orjson.OPT_INDENT_2 + + +def init_repository(git_info) -> None: + pygit2.init_repository(git_info.path) + repo = pygit2.Repository(git_info.path) + for k, v in git_info.config.items(): + repo.config[k] = v + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--spec", + type=str, + required=True, + help="name of spec module in the aurweb.archives.spec package", + ) + return parser.parse_args() + + +def update_repository(repo: pygit2.Repository): + # Use git status to determine file changes + has_changes = False + changes = repo.status() + for filepath, flags in changes.items(): + if flags != pygit2.GIT_STATUS_CURRENT: + has_changes = True + break + + if has_changes: + print("diff detected, committing") + # Add everything in the tree. + print("adding files to git tree") + + # Add the tree to staging + repo.index.read() + repo.index.add_all() + repo.index.write() + tree = repo.index.write_tree() + + # Determine base commit; if repo.head.target raises GitError, + # we have no current commits + try: + base = [repo.head.target] + except pygit2.GitError: + base = [] + + utcnow = datetime.utcnow() + author = pygit2.Signature( + config.get("git-archive", "author"), + config.get("git-archive", "author-email"), + int(utcnow.timestamp()), + 0, + ) + + # Commit the changes + timestamp = utcnow.strftime("%Y-%m-%d %H:%M:%S") + title = f"update - {timestamp}" + repo.create_commit(REF, author, author, title, tree, base) + + print("committed changes") + else: + print("no diff detected") + + +def main() -> int: + args = parse_args() + + print(f"loading '{args.spec}' spec") + spec_package = "aurweb.archives.spec" + module_path = f"{spec_package}.{args.spec}" + spec_module = importlib.import_module(module_path) + print(f"loaded '{args.spec}'") + + # Track repositories that the spec modifies. After we run + # through specs, we want to make a single commit for all + # repositories that contain changes. + repos = dict() + + print(f"running '{args.spec}' spec...") + spec = spec_module.Spec() + for output in spec.generate(): + if not os.path.exists(output.git_info.path / ".git"): + init_repository(output.git_info) + + path = output.git_info.path / output.filename + with open(path, "wb") as f: + f.write(output.data) + + if output.git_info.path not in repos: + repos[output.git_info.path] = pygit2.Repository(output.git_info.path) + + print(f"done running '{args.spec}' spec") + + print("processing repositories") + for path in spec.repos: + print(f"processing repository: {path}") + update_repository(pygit2.Repository(path)) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except KeyboardInterrupt: + sys.exit(0) + except Exception: + traceback.print_exc() + sys.exit(1) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 7ca171ab..bfdd12b4 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -188,6 +188,7 @@ def _main(): USERS = aurweb.config.get("mkpkglists", "userfile") bench = Benchmark() + logger.warning(f"{sys.argv[0]} is deprecated and will be soon be removed") logger.info("Started re-creating archives, wait a while...") query = ( diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py index aa163be1..83506e22 100755 --- a/aurweb/scripts/popupdate.py +++ b/aurweb/scripts/popupdate.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 +from datetime import datetime from sqlalchemy import and_, func from sqlalchemy.sql.functions import coalesce, sum as _sum -from aurweb import db, time +from aurweb import config, db, time from aurweb.models import PackageBase, PackageVote @@ -46,13 +47,24 @@ def run_variable(pkgbases: list[PackageBase] = []) -> None: ids = set() if pkgbases: + # If `pkgbases` were given, we should forcefully update the given + # package base records' popularities. ids = {pkgbase.ID for pkgbase in pkgbases} query = query.filter(PackageBase.ID.in_(ids)) + else: + # Otherwise, we should only update popularities which have exceeded + # the popularity interval length. + interval = config.getint("git-archive", "popularity-interval") + query = query.filter( + PackageBase.PopularityUpdated + <= datetime.fromtimestamp((now - interval)) + ) query.update( { "NumVotes": votes_subq.scalar_subquery(), "Popularity": pop_subq.scalar_subquery(), + "PopularityUpdated": datetime.fromtimestamp(now), } ) diff --git a/aurweb/testing/git.py b/aurweb/testing/git.py index 216515c8..39af87de 100644 --- a/aurweb/testing/git.py +++ b/aurweb/testing/git.py @@ -1,6 +1,4 @@ import os -import shlex -from subprocess import PIPE, Popen from typing import Tuple import py @@ -8,6 +6,7 @@ import py from aurweb.models import Package from aurweb.templates import base_template from aurweb.testing.filelock import FileLock +from aurweb.util import shell_exec class GitRepository: @@ -24,10 +23,7 @@ class GitRepository: self.file_lock.lock(on_create=self._setup) def _exec(self, cmdline: str, cwd: str) -> Tuple[int, str, str]: - args = shlex.split(cmdline) - proc = Popen(args, cwd=cwd, stdout=PIPE, stderr=PIPE) - out, err = proc.communicate() - return (proc.returncode, out.decode().strip(), err.decode().strip()) + return shell_exec(cmdline, cwd) def _exec_repository(self, cmdline: str) -> Tuple[int, str, str]: return self._exec(cmdline, cwd=str(self.file_lock.path)) diff --git a/aurweb/util.py b/aurweb/util.py index 4f1bd64e..432b818a 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -1,6 +1,7 @@ import math import re import secrets +import shlex import string from datetime import datetime from http import HTTPStatus @@ -192,3 +193,10 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: def parse_ssh_keys(string: str) -> list[Tuple[str, str]]: """Parse a list of SSH public keys.""" return [parse_ssh_key(e) for e in string.splitlines()] + + +def shell_exec(cmdline: str, cwd: str) -> Tuple[int, str, str]: + args = shlex.split(cmdline) + proc = Popen(args, cwd=cwd, stdout=PIPE, stderr=PIPE) + out, err = proc.communicate() + return (proc.returncode, out.decode().strip(), err.decode().strip()) diff --git a/conf/config.defaults b/conf/config.defaults index 722802cc..6cdffe65 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -131,6 +131,18 @@ packagesmetaextfile = /srv/http/aurweb/web/html/packages-meta-ext-v1.json.gz pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz userfile = /srv/http/aurweb/web/html/users.gz +[git-archive] +author = git_archive.py +author-email = no-reply@archlinux.org + +; One week worth of seconds (86400 * 7) +popularity-interval = 604800 + +metadata-repo = /srv/http/aurweb/metadata.git +users-repo = /srv/http/aurweb/users.git +pkgbases-repo = /srv/http/aurweb/pkgbases.git +pkgnames-repo = /srv/http/aurweb/pkgnames.git + [devel] ; commit_url is a format string used to produce a link to a commit hash. commit_url = https://gitlab.archlinux.org/archlinux/aurweb/-/commits/%s diff --git a/conf/config.dev b/conf/config.dev index 923c34ff..b36bfe77 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -76,5 +76,11 @@ packagesmetaextfile = /var/lib/aurweb/archives/packages-meta-ext-v1.json.gz pkgbasefile = /var/lib/aurweb/archives/pkgbase.gz userfile = /var/lib/aurweb/archives/users.gz +[git-archive] +metadata-repo = metadata.git +users-repo = users.git +pkgbases-repo = pkgbases.git +pkgnames-repo = pkgnames.git + [aurblup] db-path = YOUR_AUR_ROOT/aurblup/ diff --git a/doc/git-archive.md b/doc/git-archive.md new file mode 100644 index 00000000..cbc148b9 --- /dev/null +++ b/doc/git-archive.md @@ -0,0 +1,75 @@ +# aurweb Git Archive Specification + + + WARNING: This aurweb Git Archive implementation is + experimental and may be changed. + + +## Overview + +This git archive specification refers to the archive git repositories +created by [aurweb/scripts/git_archive.py](aurweb/scripts/git_archive.py) +using [spec modules](#spec-modules). + +## Configuration + +- `[git-archive]` + - `author` + - Git commit author + - `author-email` + - Git commit author email + +See an [official spec](#official-specs)'s documentation for spec-specific +configurations. + +## Fetch/Update Archives + +When a client has not yet fetched any initial archives, they should clone +the repository: + + $ git clone https://aur.archlinux.org/archive.git aurweb-archive + +When updating, the repository is already cloned and changes need to be pulled +from remote: + + # To update: + $ cd aurweb-archive && git pull + +For end-user production applications, see +[Minimize Disk Space](#minimize-disk-space). + +## Minimize Disk Space + +Using `git gc` on the repository will compress revisions and remove +unreachable objects which grow the repository a considerable amount +each commit. It is recommended that the following command is used +after cloning the archive or pulling updates: + + $ cd aurweb-archive && git gc --aggressive + +## Spec Modules + +Each aurweb spec module belongs to the `aurweb.archives.spec` package. For +example: a spec named "example" would be located at +`aurweb.archives.spec.example`. + +[Official spec listings](#official-specs) use the following format: + +- `spec_name` + - Spec description; what this spec produces + - `` + +### Official Specs + +- [metadata](doc/specs/metadata.md) + - Package RPC `type=info` metadata + - [metadata-repo](repos/metadata-repo.md) +- [users](doc/specs/users.md) + - List of users found in the database + - [users-repo](repos/users-repo.md) +- [pkgbases](doc/specs/pkgbases.md) + - List of package bases found in the database + - [pkgbases-repo](repos/pkgbases-repo.md) +- [pkgnames](doc/specs/pkgnames.md) + - List of package names found in the database + - [pkgnames-repo](repos/pkgnames-repo.md) diff --git a/doc/maintenance.txt b/doc/maintenance.txt index c52cf76f..56616f79 100644 --- a/doc/maintenance.txt +++ b/doc/maintenance.txt @@ -70,20 +70,48 @@ computations and clean up the database: * aurweb-pkgmaint automatically removes empty repositories that were created within the last 24 hours but never populated. -* aurweb-mkpkglists generates the package list files; it takes an optional - --extended flag, which additionally produces multiinfo metadata. It also - generates {archive.gz}.sha256 files that should be located within +* [Deprecated] aurweb-mkpkglists generates the package list files; it takes + an optional --extended flag, which additionally produces multiinfo metadata. + It also generates {archive.gz}.sha256 files that should be located within mkpkglists.archivedir which contain a SHA-256 hash of their matching .gz counterpart. * aurweb-usermaint removes the last login IP address of all users that did not login within the past seven days. +* aurweb-git-archive generates Git repository archives based on a --spec. + This script is a new generation of aurweb-mkpkglists, which creates and + maintains Git repository versions of the archives produced by + aurweb-mkpkglists. See doc/git-archive.md for detailed documentation. + These scripts can be installed by running `poetry install` and are usually scheduled using Cron. The current setup is: ---- -*/5 * * * * poetry run aurweb-mkpkglists [--extended] +# Run aurweb-git-archive --spec metadata directly after +# aurweb-mkpkglists so that they are executed sequentially, since +# both scripts are quite heavy. `aurweb-mkpkglists` should be removed +# from here once its deprecation period has ended. +*/5 * * * * poetry run aurweb-mkpkglists [--extended] && poetry run aurweb-git-archive --spec metadata + +# Update popularity once an hour. This is done to reduce the amount +# of changes caused by popularity data. Even if a package is otherwise +# unchanged, popularity is recalculated every 5 minutes via aurweb-popupdate, +# which causes changes for a large chunk of packages. +# +# At this interval, clients can still take advantage of popularity +# data, but its updates are guarded behind hour-long intervals. +*/60 * * * * poetry run aurweb-git-archive --spec popularity + +# Usernames +*/5 * * * * poetry run aurweb-git-archive --spec users + +# Package base names +*/5 * * * * poetry run aurweb-git-archive --spec pkgbases + +# Package names +*/5 * * * * poetry run aurweb-git-archive --spec pkgnames + 1 */2 * * * poetry run aurweb-popupdate 2 */2 * * * poetry run aurweb-aurblup 3 */2 * * * poetry run aurweb-pkgmaint diff --git a/doc/repos/metadata-repo.md b/doc/repos/metadata-repo.md new file mode 100644 index 00000000..cc678f40 --- /dev/null +++ b/doc/repos/metadata-repo.md @@ -0,0 +1,121 @@ +# Repository: metadata-repo + +## Overview + +The resulting repository contains RPC `type=info` JSON data for packages, +split into two different files: + +- `pkgbase.json` contains details about each package base in the AUR +- `pkgname.json` contains details about each package in the AUR + +See [Data](#data) for a breakdown of how data is presented in this +repository based off of a RPC `type=info` base. + +See [File Layout](#file-layout) for a detailed summary of the layout +of these files and the data contained within. + +**NOTE: `Popularity` now requires a client-side calculation, see [Popularity Calculation](#popularity-calculation).** + +## Data + +This repository contains RPC `type=info` data for all packages found +in AUR's database, reorganized to be suitable for Git repository +changes. + +- `pkgname.json` holds Package-specific metadata + - Some fields have been removed from `pkgname.json` objects + - `ID` + - `PackageBaseID -> ID` (moved to `pkgbase.json`) + - `NumVotes` (moved to `pkgbase.json`) + - `Popularity` (moved to `pkgbase.json`) +- `pkgbase.json` holds PackageBase-specific metadata + - Package Base fields from `pkgname.json` have been moved over to + `pkgbase.json` + - `ID` + - `Keywords` + - `FirstSubmitted` + - `LastModified` + - `OutOfDate` + - `Maintainer` + - `URLPath` + - `NumVotes` + - `Popularity` + - `PopularityUpdated` + +## Popularity Calculation + +Clients intending to use popularity data from this archive **must** +perform a decay calculation on their end to reflect a close approximation +of up-to-date popularity. + +Putting this step onto the client allows the server to maintain +less popularity record updates, dramatically improving archiving +of popularity data. The same calculation is done on the server-side +when producing outputs for RPC `type=info` and package pages. + +``` +Let T = Current UTC timestamp in seconds +Let PU = PopularityUpdated timestamp in seconds + +# The delta between now and PU in days +Let D = (T - PU) / 86400 + +# Calculate up-to-date popularity: +P = Popularity * (0.98^D) +``` + +We can see that the resulting up-to-date popularity value decays as +the exponent is increased: +- `1.0 * (0.98^1) = 0.98` +- `1.0 * (0.98^2) = 0.96039999` +- ... + +This decay calculation is essentially pushing back the date found for +votes by the exponent, which takes into account the time-factor. However, +since this calculation is based off of decimals and exponents, it +eventually becomes imprecise. The AUR updates these records on a forced +interval and whenever a vote is added to or removed from a particular package +to avoid imprecision from being an issue for clients + +## File Layout + +#### pkgbase.json: + + { + "pkgbase1": { + "FirstSubmitted": 123456, + "ID": 1, + "LastModified": 123456, + "Maintainer": "kevr", + "OutOfDate": null, + "URLPath": "/cgit/aur.git/snapshot/pkgbase1.tar.gz", + "NumVotes": 1, + "Popularity": 1.0, + "PopularityUpdated": 12345567753.0 + }, + ... + } + +#### pkgname.json: + + { + "pkg1": { + "CheckDepends": [], # Only included if a check dependency exists + "Conflicts": [], # Only included if a conflict exists + "Depends": [], # Only included if a dependency exists + "Description": "some description", + "Groups": [], # Only included if a group exists + "ID": 1, + "Keywords": [], + "License": [], + "MakeDepends": [], # Only included if a make dependency exists + "Name": "pkg1", + "OptDepends": [], # Only included if an opt dependency exists + "PackageBase": "pkgbase1", + "Provides": [], # Only included if `provides` is defined + "Replaces": [], # Only included if `replaces` is defined + "URL": "https://some_url.com", + "Version": "1.0-1" + }, + ... + } diff --git a/doc/repos/pkgbases-repo.md b/doc/repos/pkgbases-repo.md new file mode 100644 index 00000000..f4cb896f --- /dev/null +++ b/doc/repos/pkgbases-repo.md @@ -0,0 +1,15 @@ +# Repository: pkgbases-repo + +## Overview + +- `pkgbase.json` contains a list of package base names + +## File Layout + +### pkgbase.json: + + [ + "pkgbase1", + "pkgbase2", + ... + ] diff --git a/doc/repos/pkgnames-repo.md b/doc/repos/pkgnames-repo.md new file mode 100644 index 00000000..ae6fb4ed --- /dev/null +++ b/doc/repos/pkgnames-repo.md @@ -0,0 +1,15 @@ +# Repository: pkgnames-repo + +## Overview + +- `pkgname.json` contains a list of package names + +## File Layout + +### pkgname.json: + + [ + "pkgname1", + "pkgname2", + ... + ] diff --git a/doc/repos/users-repo.md b/doc/repos/users-repo.md new file mode 100644 index 00000000..23db9cfb --- /dev/null +++ b/doc/repos/users-repo.md @@ -0,0 +1,15 @@ +# Repository: users-repo + +## Overview + +- `users.json` contains a list of usernames + +## File Layout + +### users.json: + + [ + "user1", + "user2", + ... + ] diff --git a/doc/specs/metadata.md b/doc/specs/metadata.md new file mode 100644 index 00000000..282c0dd5 --- /dev/null +++ b/doc/specs/metadata.md @@ -0,0 +1,14 @@ +# Git Archive Spec: metadata + +## Configuration + +- `[git-archive]` + - `metadata-repo` + - Path to package metadata git repository location + +## Repositories + +For documentation on each one of these repositories, follow their link, +which brings you to a topical markdown for that repository. + +- [metadata-repo](doc/repos/metadata-repo.md) diff --git a/doc/specs/pkgbases.md b/doc/specs/pkgbases.md new file mode 100644 index 00000000..80279070 --- /dev/null +++ b/doc/specs/pkgbases.md @@ -0,0 +1,14 @@ +# Git Archive Spec: pkgbases + +## Configuration + +- `[git-archive]` + - `pkgbases-repo` + - Path to pkgbases git repository location + +## Repositories + +For documentation on each one of these repositories, follow their link, +which brings you to a topical markdown for that repository. + +- [pkgbases-repo](doc/repos/pkgbases-repo.md) diff --git a/doc/specs/pkgnames.md b/doc/specs/pkgnames.md new file mode 100644 index 00000000..0a4a907d --- /dev/null +++ b/doc/specs/pkgnames.md @@ -0,0 +1,14 @@ +# Git Archive Spec: pkgnames + +## Configuration + +- `[git-archive]` + - `pkgnames-repo` + - Path to pkgnames git repository location + +## Repositories + +For documentation on each one of these repositories, follow their link, +which brings you to a topical markdown for that repository. + +- [pkgnames-repo](doc/repos/pkgnames-repo.md) diff --git a/doc/specs/popularity.md b/doc/specs/popularity.md new file mode 100644 index 00000000..3084f458 --- /dev/null +++ b/doc/specs/popularity.md @@ -0,0 +1,14 @@ +# Git Archive Spec: popularity + +## Configuration + +- `[git-archive]` + - `popularity-repo` + - Path to popularity git repository location + +## Repositories + +For documentation on each one of these repositories, follow their link, +which brings you to a topical markdown for that repository. + +- [popularity-repo](doc/repos/popularity-repo.md) diff --git a/doc/specs/users.md b/doc/specs/users.md new file mode 100644 index 00000000..25396154 --- /dev/null +++ b/doc/specs/users.md @@ -0,0 +1,14 @@ +# Git Archive Spec: users + +## Configuration + +- `[git-archive]` + - `users-repo` + - Path to users git repository location + +## Repositories + +For documentation on each one of these repositories, follow their link, +which brings you to a topical markdown for that repository. + +- [users-repo](doc/repos/users-repo.md) diff --git a/migrations/versions/6441d3b65270_add_popularityupdated_to_packagebase.py b/migrations/versions/6441d3b65270_add_popularityupdated_to_packagebase.py new file mode 100644 index 00000000..afa87687 --- /dev/null +++ b/migrations/versions/6441d3b65270_add_popularityupdated_to_packagebase.py @@ -0,0 +1,33 @@ +"""add PopularityUpdated to PackageBase + +Revision ID: 6441d3b65270 +Revises: d64e5571bc8d +Create Date: 2022-09-22 18:08:03.280664 + +""" +from alembic import op +from sqlalchemy.exc import OperationalError + +from aurweb.models.package_base import PackageBase +from aurweb.scripts import popupdate + +# revision identifiers, used by Alembic. +revision = "6441d3b65270" +down_revision = "d64e5571bc8d" +branch_labels = None +depends_on = None + +table = PackageBase.__table__ + + +def upgrade(): + try: + op.add_column(table.name, table.c.PopularityUpdated) + except OperationalError: + print(f"table '{table.name}' already exists, skipping migration") + + popupdate.run_variable() + + +def downgrade(): + op.drop_column(table.name, "PopularityUpdated") diff --git a/pyproject.toml b/pyproject.toml index f732f2e7..775ece09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,3 +117,4 @@ aurweb-tuvotereminder = "aurweb.scripts.tuvotereminder:main" aurweb-usermaint = "aurweb.scripts.usermaint:main" aurweb-config = "aurweb.scripts.config:main" aurweb-adduser = "aurweb.scripts.adduser:main" +aurweb-git-archive = "aurweb.scripts.git_archive:main" diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 86bc1de5..8ecf9bd8 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -149,7 +149,7 @@ - + diff --git a/test/test_git_archives.py b/test/test_git_archives.py new file mode 100644 index 00000000..8ee4c2ba --- /dev/null +++ b/test/test_git_archives.py @@ -0,0 +1,241 @@ +from http import HTTPStatus +from typing import Tuple +from unittest import mock + +import py +import pygit2 +import pytest +from fastapi.testclient import TestClient + +from aurweb import asgi, config, db +from aurweb.archives.spec.base import GitInfo, SpecBase +from aurweb.models import Package, PackageBase, User +from aurweb.scripts import git_archive +from aurweb.testing.requests import Request + + +@pytest.fixture +def mock_metadata_archive( + tmp_path: py.path.local, +) -> Tuple[py.path.local, py.path.local]: + metadata_path = tmp_path / "metadata.git" + + get_ = config.get + + def mock_config(section: str, option: str) -> str: + if section == "git-archive": + if option == "metadata-repo": + return str(metadata_path) + return get_(section, option) + + with mock.patch("aurweb.config.get", side_effect=mock_config): + yield metadata_path + + +@pytest.fixture +def mock_users_archive(tmp_path: py.path.local) -> py.path.local: + users_path = tmp_path / "users.git" + + get_ = config.get + + def mock_config(section: str, option: str) -> str: + if section == "git-archive": + if option == "users-repo": + return str(users_path) + return get_(section, option) + + with mock.patch("aurweb.config.get", side_effect=mock_config): + yield users_path + + +@pytest.fixture +def mock_pkgbases_archive(tmp_path: py.path.local) -> py.path.local: + pkgbases_path = tmp_path / "pkgbases.git" + + get_ = config.get + + def mock_config(section: str, option: str) -> str: + if section == "git-archive": + if option == "pkgbases-repo": + return str(pkgbases_path) + return get_(section, option) + + with mock.patch("aurweb.config.get", side_effect=mock_config): + yield pkgbases_path + + +@pytest.fixture +def mock_pkgnames_archive(tmp_path: py.path.local) -> py.path.local: + pkgnames_path = tmp_path / "pkgnames.git" + + get_ = config.get + + def mock_config(section: str, option: str) -> str: + if section == "git-archive": + if option == "pkgnames-repo": + return str(pkgnames_path) + return get_(section, option) + + with mock.patch("aurweb.config.get", side_effect=mock_config): + yield pkgnames_path + + +@pytest.fixture +def metadata(mock_metadata_archive: py.path.local) -> py.path.local: + args = [__name__, "--spec", "metadata"] + with mock.patch("sys.argv", args): + yield mock_metadata_archive + + +@pytest.fixture +def users(mock_users_archive: py.path.local) -> py.path.local: + args = [__name__, "--spec", "users"] + with mock.patch("sys.argv", args): + yield mock_users_archive + + +@pytest.fixture +def pkgbases(mock_pkgbases_archive: py.path.local) -> py.path.local: + args = [__name__, "--spec", "pkgbases"] + with mock.patch("sys.argv", args): + yield mock_pkgbases_archive + + +@pytest.fixture +def pkgnames(mock_pkgnames_archive: py.path.local) -> py.path.local: + args = [__name__, "--spec", "pkgnames"] + with mock.patch("sys.argv", args): + yield mock_pkgnames_archive + + +@pytest.fixture +def client() -> TestClient: + yield TestClient(app=asgi.app) + + +@pytest.fixture +def user(db_test: None) -> User: + with db.begin(): + user_ = db.create( + User, + Username="test", + Email="test@example.org", + Passwd="testPassword", + ) + + yield user_ + + +@pytest.fixture +def package(user: User) -> Package: + with db.begin(): + pkgbase_ = db.create( + PackageBase, + Name="test", + Maintainer=user, + Packager=user, + ) + + pkg_ = db.create( + Package, + PackageBase=pkgbase_, + Name="test", + ) + + yield pkg_ + + +def commit_count(repo: pygit2.Repository) -> int: + commits = 0 + for _ in repo.walk(repo.head.target): + commits += 1 + return commits + + +def test_specbase_raises_notimplementederror(): + spec = SpecBase() + with pytest.raises(NotImplementedError): + spec.generate() + + +def test_gitinfo_config(tmpdir: py.path.local): + path = tmpdir / "test.git" + git_info = GitInfo(path, {"user.name": "Test Person"}) + git_archive.init_repository(git_info) + + repo = pygit2.Repository(path) + assert repo.config["user.name"] == "Test Person" + + +def test_metadata(metadata: py.path.local, package: Package): + # Run main(), which creates mock_metadata_archive and commits current + # package data to it, exercising the "diff detected, committing" path + assert git_archive.main() == 0 + repo = pygit2.Repository(metadata) + assert commit_count(repo) == 1 + + # Run main() again to exercise the "no diff detected" path + assert git_archive.main() == 0 + repo = pygit2.Repository(metadata) + assert commit_count(repo) == 1 + + +def test_metadata_change( + client: TestClient, metadata: py.path.local, user: User, package: Package +): + """Test that metadata changes via aurweb cause git_archive to produce diffs.""" + # Run main(), which creates mock_metadata_archive and commits current + # package data to it, exercising the "diff detected, committing" path + assert git_archive.main() == 0 + repo = pygit2.Repository(metadata) + assert commit_count(repo) == 1 + + # Now, we modify `package`-related metadata via aurweb POST. + pkgbasename = package.PackageBase.Name + cookies = {"AURSID": user.login(Request(), "testPassword")} + + with client as request: + endp = f"/pkgbase/{pkgbasename}/keywords" + post_data = {"keywords": "abc def"} + resp = request.post(endp, data=post_data, cookies=cookies, allow_redirects=True) + assert resp.status_code == HTTPStatus.OK + + # Run main() again, which should now produce a new commit with the + # keyword changes we just made + assert git_archive.main() == 0 + repo = pygit2.Repository(metadata) + assert commit_count(repo) == 2 + + +def test_metadata_delete(client: TestClient, metadata: py.path.local, package: Package): + # Run main(), which creates mock_metadata_archive and commits current + # package data to it, exercising the "diff detected, committing" path + assert git_archive.main() == 0 + repo = pygit2.Repository(metadata) + assert commit_count(repo) == 1 + + with db.begin(): + db.delete(package) + + # The deletion here should have caused a diff to be produced in git + assert git_archive.main() == 0 + repo = pygit2.Repository(metadata) + assert commit_count(repo) == 2 + + +def test_users(users: py.path.local, user: User): + assert git_archive.main() == 0 + repo = pygit2.Repository(users) + assert commit_count(repo) == 1 + + +def test_pkgbases(pkgbases: py.path.local, package: Package): + assert git_archive.main() == 0 + repo = pygit2.Repository(pkgbases) + assert commit_count(repo) == 1 + + +def test_pkgnames(pkgnames: py.path.local, package: Package): + assert git_archive.main() == 0 + repo = pygit2.Repository(pkgnames) + assert commit_count(repo) == 1 diff --git a/test/test_templates.py b/test/test_templates.py index f80e68eb..2ff31fc9 100644 --- a/test/test_templates.py +++ b/test/test_templates.py @@ -9,6 +9,7 @@ from aurweb.filters import as_timezone, number_format, timestamp_to_datetime as from aurweb.models import Package, PackageBase, User from aurweb.models.account_type import USER_ID from aurweb.models.license import License +from aurweb.models.package_base import popularity from aurweb.models.package_license import PackageLicense from aurweb.models.package_relation import PackageRelation from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID @@ -287,12 +288,14 @@ def test_package_details(user: User, package: Package): """Test package details with most fields populated, but not all.""" request = Request(user=user, authenticated=True) context = make_context(request, "Test Details") + context.update( { "request": request, "git_clone_uri_anon": GIT_CLONE_URI_ANON, "git_clone_uri_priv": GIT_CLONE_URI_PRIV, "pkgbase": package.PackageBase, + "popularity": popularity(package.PackageBase, time.utcnow()), "package": package, "comaintainers": [], } @@ -329,6 +332,7 @@ def test_package_details_filled(user: User, package: Package): "git_clone_uri_anon": GIT_CLONE_URI_ANON, "git_clone_uri_priv": GIT_CLONE_URI_PRIV, "pkgbase": package.PackageBase, + "popularity": popularity(package.PackageBase, time.utcnow()), "package": package, "comaintainers": [], "licenses": package.package_licenses, From 137644e9192c8421b0a78a1b955910eed09e9276 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 25 Sep 2022 10:03:05 +0200 Subject: [PATCH 1600/1891] docs: suggest shallow clone in git-archive.md we should be suggesting to make a shallow clone to reduce the amount of data that is being transferred initially Signed-off-by: moson-mo --- doc/git-archive.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/git-archive.md b/doc/git-archive.md index cbc148b9..d7c80f76 100644 --- a/doc/git-archive.md +++ b/doc/git-archive.md @@ -24,10 +24,10 @@ configurations. ## Fetch/Update Archives -When a client has not yet fetched any initial archives, they should clone -the repository: +When a client has not yet fetched any initial archives, they should +shallow-clone the repository: - $ git clone https://aur.archlinux.org/archive.git aurweb-archive + $ git clone --depth=1 https://aur.archlinux.org/archive.git aurweb-archive When updating, the repository is already cloned and changes need to be pulled from remote: From 0dddaeeb98ea13dfa10a0462af178dc50481333f Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 23 Sep 2022 13:31:50 +0100 Subject: [PATCH 1601/1891] fix: remove sessions of suspended users Fixes: #394 Signed-off-by: Leonidas Spyropoulos --- aurweb/routers/accounts.py | 2 ++ aurweb/users/update.py | 16 +++++++++ test/test_accounts_routes.py | 70 +++++++++++++++++++++++++++++++----- 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 3937757a..524ef814 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -412,6 +412,7 @@ async def account_edit_post( TZ: str = Form(aurweb.config.get("options", "default_timezone")), P: str = Form(default=str()), # New Password C: str = Form(default=None), # Password Confirm + S: bool = Form(default=False), # Suspended PK: str = Form(default=None), # PubKey CN: bool = Form(default=False), # Comment Notify UN: bool = Form(default=False), # Update Notify @@ -455,6 +456,7 @@ async def account_edit_post( update.ssh_pubkey, update.account_type, update.password, + update.suspend, ] # These update functions are all guarded by retry_deadlock; diff --git a/aurweb/users/update.py b/aurweb/users/update.py index 6bd4a295..df41f843 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -134,3 +134,19 @@ def password( # If the target user is the request user, login with # the updated password to update the Session record. user.login(request, P, cookies.timeout(remember_me)) + + +@db.retry_deadlock +def suspend( + S: bool = False, + request: Request = None, + user: models.User = None, + context: dict[str, Any] = {}, + **kwargs, +) -> None: + if S and user.session: + context["S"] = None + with db.begin(): + db.delete_all( + db.query(models.Session).filter(models.Session.UsersID == user.ID) + ) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index eab8fa4f..b6dce19e 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -9,6 +9,7 @@ import lxml.html import pytest from fastapi.testclient import TestClient +import aurweb.config import aurweb.models.account_type as at from aurweb import captcha, db, logging, time from aurweb.asgi import app @@ -35,6 +36,9 @@ logger = logging.get_logger(__name__) # Some test global constants. TEST_USERNAME = "test" TEST_EMAIL = "test@example.org" +TEST_REFERER = { + "referer": aurweb.config.get("options", "aur_location") + "/login", +} def make_ssh_pubkey(): @@ -61,7 +65,12 @@ def setup(db_test): @pytest.fixture def client() -> TestClient: - yield TestClient(app=app) + client = TestClient(app=app) + + # Necessary for forged login CSRF protection on the login route. Set here + # instead of only on the necessary requests for convenience. + client.headers.update(TEST_REFERER) + yield client def create_user(username: str) -> User: @@ -1003,13 +1012,8 @@ def test_post_account_edit_suspended(client: TestClient, user: User): # Make sure the user record got updated correctly. assert user.Suspended - - post_data.update({"S": False}) - with client as request: - resp = request.post(endpoint, data=post_data, cookies=cookies) - assert resp.status_code == int(HTTPStatus.OK) - - assert not user.Suspended + # Let's make sure the DB got updated properly. + assert user.session is None def test_post_account_edit_error_unauthorized(client: TestClient, user: User): @@ -1262,6 +1266,56 @@ def test_post_account_edit_other_user_type_as_tu( assert expected in caplog.text +def test_post_account_edit_other_user_suspend_as_tu(client: TestClient, tu_user: User): + with db.begin(): + user = create_user("test3") + # Create a session for user + sid = user.login(Request(), "testPassword") + assert sid is not None + + # `user` needs its own TestClient, to keep its AURSID cookies + # apart from `tu_user`s during our testing. + user_client = TestClient(app=app) + user_client.headers.update(TEST_REFERER) + + # Test that `user` can view their account edit page while logged in. + user_cookies = {"AURSID": sid} + with client as request: + endpoint = f"/account/{user.Username}/edit" + resp = request.get(endpoint, cookies=user_cookies, allow_redirects=False) + assert resp.status_code == HTTPStatus.OK + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + assert cookies is not None # This is useless, we create the dict here ^ + # As a TU, we can see the Account for other users. + with client as request: + resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + assert resp.status_code == int(HTTPStatus.OK) + # As a TU, we can modify other user's account types. + data = { + "U": user.Username, + "E": user.Email, + "S": True, + "passwd": "testPassword", + } + with client as request: + resp = request.post(endpoint, data=data, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + + # Test that `user` no longer has a session. + with user_client as request: + resp = request.get(endpoint, cookies=user_cookies, allow_redirects=False) + assert resp.status_code == HTTPStatus.SEE_OTHER + + # Since user is now suspended, they should not be able to login. + data = {"user": user.Username, "passwd": "testPassword", "next": "/"} + with user_client as request: + resp = request.post("/login", data=data) + assert resp.status_code == HTTPStatus.OK + errors = get_errors(resp.text) + assert errors[0].text.strip() == "Account Suspended" + + def test_post_account_edit_other_user_type_as_tu_invalid_type( client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture ): From e00b0059f75cb467d4eeab7fb8f8332bbc67288d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 26 Sep 2022 01:27:37 -0700 Subject: [PATCH 1602/1891] doc: remove --spec popularity from cron recommendations Signed-off-by: Kevin Morris --- doc/maintenance.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/doc/maintenance.txt b/doc/maintenance.txt index 56616f79..dacf2b60 100644 --- a/doc/maintenance.txt +++ b/doc/maintenance.txt @@ -94,15 +94,6 @@ usually scheduled using Cron. The current setup is: # from here once its deprecation period has ended. */5 * * * * poetry run aurweb-mkpkglists [--extended] && poetry run aurweb-git-archive --spec metadata -# Update popularity once an hour. This is done to reduce the amount -# of changes caused by popularity data. Even if a package is otherwise -# unchanged, popularity is recalculated every 5 minutes via aurweb-popupdate, -# which causes changes for a large chunk of packages. -# -# At this interval, clients can still take advantage of popularity -# data, but its updates are guarded behind hour-long intervals. -*/60 * * * * poetry run aurweb-git-archive --spec popularity - # Usernames */5 * * * * poetry run aurweb-git-archive --spec users From eb0c5605e491d51ee1ade8431934bad78f7b141e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 26 Sep 2022 01:28:38 -0700 Subject: [PATCH 1603/1891] upgrade: bump version to v6.1.5 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index c1f87984..83b965e3 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.4" +AURWEB_VERSION = "v6.1.5" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 775ece09..46d8806f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.4" +version = "v6.1.5" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 8657fd336e4c47dce3eaf78988944658f85bd64e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 29 Sep 2022 17:43:26 -0700 Subject: [PATCH 1604/1891] feat: GET|POST /account/{name}/delete Closes #348 Signed-off-by: Kevin Morris --- aurweb/models/package_vote.py | 2 +- aurweb/models/session.py | 2 +- aurweb/routers/accounts.py | 76 ++++++++++++++++++++++++- po/aurweb.pot | 4 ++ templates/account/delete.html | 43 ++++++++++++++ test/test_accounts_routes.py | 103 ++++++++++++++++++++++++++++++++++ 6 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 templates/account/delete.html diff --git a/aurweb/models/package_vote.py b/aurweb/models/package_vote.py index fa769bb6..b9e233d9 100644 --- a/aurweb/models/package_vote.py +++ b/aurweb/models/package_vote.py @@ -14,7 +14,7 @@ class PackageVote(Base): User = relationship( _User, - backref=backref("package_votes", lazy="dynamic"), + backref=backref("package_votes", lazy="dynamic", cascade="all, delete"), foreign_keys=[__table__.c.UsersID], ) diff --git a/aurweb/models/session.py b/aurweb/models/session.py index d3d69f8c..ff97f017 100644 --- a/aurweb/models/session.py +++ b/aurweb/models/session.py @@ -13,7 +13,7 @@ class Session(Base): User = relationship( _User, - backref=backref("session", uselist=False), + backref=backref("session", cascade="all, delete", uselist=False), foreign_keys=[__table__.c.UsersID], ) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 524ef814..12e59b30 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -3,13 +3,13 @@ import typing from http import HTTPStatus from typing import Any -from fastapi import APIRouter, Form, Request +from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, or_ import aurweb.config from aurweb import cookies, db, l10n, logging, models, util -from aurweb.auth import account_type_required, requires_auth, requires_guest +from aurweb.auth import account_type_required, creds, requires_auth, requires_guest from aurweb.captcha import get_captcha_salts from aurweb.exceptions import ValidationError, handle_form_exceptions from aurweb.l10n import get_translator_for_request @@ -598,6 +598,78 @@ async def accounts_post( return render_template(request, "account/index.html", context) +@router.get("/account/{name}/delete") +@requires_auth +async def account_delete(request: Request, name: str): + user = db.query(models.User).filter(models.User.Username == name).first() + if not user: + raise HTTPException(status_code=HTTPStatus.NOT_FOUND) + + has_cred = request.user.has_credential(creds.ACCOUNT_EDIT, approved=[user]) + if not has_cred: + _ = l10n.get_translator_for_request(request) + raise HTTPException( + detail=_("You do not have permission to edit this account."), + status_code=HTTPStatus.UNAUTHORIZED, + ) + + context = make_context(request, "Accounts") + context["name"] = name + return render_template(request, "account/delete.html", context) + + +@db.async_retry_deadlock +@router.post("/account/{name}/delete") +@handle_form_exceptions +@requires_auth +async def account_delete_post( + request: Request, + name: str, + passwd: str = Form(default=str()), + confirm: bool = Form(default=False), +): + user = db.query(models.User).filter(models.User.Username == name).first() + if not user: + raise HTTPException(status_code=HTTPStatus.NOT_FOUND) + + has_cred = request.user.has_credential(creds.ACCOUNT_EDIT, approved=[user]) + if not has_cred: + _ = l10n.get_translator_for_request(request) + raise HTTPException( + detail=_("You do not have permission to edit this account."), + status_code=HTTPStatus.UNAUTHORIZED, + ) + + context = make_context(request, "Accounts") + context["name"] = name + + confirm = util.strtobool(confirm) + if not confirm: + context["errors"] = [ + "The account has not been deleted, check the confirmation checkbox." + ] + return render_template( + request, + "account/delete.html", + context, + status_code=HTTPStatus.BAD_REQUEST, + ) + + if not request.user.valid_password(passwd): + context["errors"] = ["Invalid password."] + return render_template( + request, + "account/delete.html", + context, + status_code=HTTPStatus.BAD_REQUEST, + ) + + with db.begin(): + db.delete(user) + + return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) + + def render_terms_of_service(request: Request, context: dict, terms: typing.Iterable): if not terms: return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) diff --git a/po/aurweb.pot b/po/aurweb.pot index bc4bab84..1838fae5 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2346,3 +2346,7 @@ msgstr "" #: templates/partials/packages/package_metadata.html msgid "dependencies" msgstr "" + +#: aurweb/routers/accounts.py +msgid "The account has not been deleted, check the confirmation checkbox." +msgstr "" diff --git a/templates/account/delete.html b/templates/account/delete.html new file mode 100644 index 00000000..625d3c2d --- /dev/null +++ b/templates/account/delete.html @@ -0,0 +1,43 @@ +{% extends "partials/layout.html" %} + +{% block pageContent %} +
    +

    {{ "Accounts" | tr }}

    + + {% include "partials/error.html" %} + +

    + {{ + "You can use this form to permanently delete the AUR account %s%s%s." + | tr | format("", name, "") | safe + }} +

    + +

    + {{ + "%sWARNING%s: This action cannot be undone." + | tr | format("", "") | safe + }} +

    + + +
    +
    +

    + + +

    +

    + +

    +

    + +

    +
    + + +
    +{% endblock %} diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index b6dce19e..f4034a9a 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -1949,3 +1949,106 @@ def test_accounts_unauthorized(client: TestClient, user: User): resp = request.get("/accounts", cookies=cookies, allow_redirects=False) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" + + +def test_account_delete_self_unauthorized(client: TestClient, tu_user: User): + with db.begin(): + user = create_user("some_user") + user2 = create_user("user2") + + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/account/{user2.Username}/delete" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == HTTPStatus.UNAUTHORIZED + + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == HTTPStatus.UNAUTHORIZED + + # But a TU does have access + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with TestClient(app=app) as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == HTTPStatus.OK + + +def test_account_delete_self_not_found(client: TestClient, user: User): + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = "/account/non-existent-user/delete" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == HTTPStatus.NOT_FOUND + + resp = request.post(endpoint, cookies=cookies) + assert resp.status_code == HTTPStatus.NOT_FOUND + + +def test_account_delete_self(client: TestClient, user: User): + username = user.Username + + # Confirm that we can view our own account deletion page + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/account/{username}/delete" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == HTTPStatus.OK + + # The checkbox must be checked + with client as request: + resp = request.post( + endpoint, + data={"passwd": "fakePassword", "confirm": False}, + cookies=cookies, + ) + assert resp.status_code == HTTPStatus.BAD_REQUEST + errors = get_errors(resp.text) + assert ( + errors[0].text.strip() + == "The account has not been deleted, check the confirmation checkbox." + ) + + # The correct password must be supplied + with client as request: + resp = request.post( + endpoint, + data={"passwd": "fakePassword", "confirm": True}, + cookies=cookies, + ) + assert resp.status_code == HTTPStatus.BAD_REQUEST + errors = get_errors(resp.text) + assert errors[0].text.strip() == "Invalid password." + + # Supply everything correctly and delete ourselves + with client as request: + resp = request.post( + endpoint, + data={"passwd": "testPassword", "confirm": True}, + cookies=cookies, + ) + assert resp.status_code == HTTPStatus.SEE_OTHER + + # Check that our User record no longer exists in the database + record = db.query(User).filter(User.Username == username).first() + assert record is None + + +def test_account_delete_as_tu(client: TestClient, tu_user: User): + with db.begin(): + user = create_user("user2") + + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + username = user.Username + endpoint = f"/account/{username}/delete" + + # Delete the user + with client as request: + resp = request.post( + endpoint, + data={"passwd": "testPassword", "confirm": True}, + cookies=cookies, + ) + assert resp.status_code == HTTPStatus.SEE_OTHER + + # Check that our User record no longer exists in the database + record = db.query(User).filter(User.Username == username).first() + assert record is None From 3ae6323a7ccf9d2637255c522e0ff8371f7ace20 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Fri, 30 Sep 2022 05:19:58 -0700 Subject: [PATCH 1605/1891] upgrade: bump to v6.1.6 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 83b965e3..c9f36e51 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.5" +AURWEB_VERSION = "v6.1.6" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 46d8806f..77d136db 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.5" +version = "v6.1.6" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 18f5e142b9180648763c5513e2f123dbcfde67b4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 11 Oct 2022 14:50:09 -0700 Subject: [PATCH 1606/1891] fix: include orphaned packages in metadata output Signed-off-by: Kevin Morris --- aurweb/archives/spec/metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/archives/spec/metadata.py b/aurweb/archives/spec/metadata.py index e7c8e096..ce7c6f30 100644 --- a/aurweb/archives/spec/metadata.py +++ b/aurweb/archives/spec/metadata.py @@ -22,7 +22,7 @@ class Spec(SpecBase): base_query = ( db.query(Package) .join(PackageBase) - .join(User, PackageBase.MaintainerUID == User.ID) + .join(User, PackageBase.MaintainerUID == User.ID, isouter=True) ) # Create an instance of RPC, use it to get entities from From da5a646a731eab817d6bc2b2ebf54bb1dec58e23 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 11 Oct 2022 15:04:25 -0700 Subject: [PATCH 1607/1891] upgrade: bump to v6.1.7 Signed-off-by: Kevin Morris --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index c9f36e51..e8ca70d9 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.6" +AURWEB_VERSION = "v6.1.7" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 77d136db..fea2f922 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.6" +version = "v6.1.7" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From b757e66997579b1d5e5c25a444894a6ac246577d Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 12 Jul 2022 15:12:38 +0100 Subject: [PATCH 1608/1891] feature: add filters and stats for requests Signed-off-by: Leonidas Spyropoulos --- aurweb/routers/requests.py | 46 ++++++++++++++++++++++++++--- templates/requests.html | 59 ++++++++++++++++++++++++++++++++++++++ test/test_requests.py | 16 ++++++++++- 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index bf86bdcc..ca5fae73 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -8,7 +8,12 @@ from aurweb import db, defaults, time, util from aurweb.auth import creds, requires_auth from aurweb.exceptions import handle_form_exceptions from aurweb.models import PackageRequest -from aurweb.models.package_request import PENDING_ID, REJECTED_ID +from aurweb.models.package_request import ( + ACCEPTED_ID, + CLOSED_ID, + PENDING_ID, + REJECTED_ID, +) from aurweb.requests.util import get_pkgreq_by_id from aurweb.scripts import notify from aurweb.templates import make_context, render_template @@ -22,26 +27,59 @@ async def requests( request: Request, O: int = Query(default=defaults.O), PP: int = Query(default=defaults.PP), + filter_pending: bool = False, + filter_closed: bool = False, + filter_accepted: bool = False, + filter_rejected: bool = False, ): context = make_context(request, "Requests") context["q"] = dict(request.query_params) + if len(dict(request.query_params)) == 0: + filter_pending = True + O, PP = util.sanitize_params(O, PP) context["O"] = O context["PP"] = PP + context["filter_pending"] = filter_pending + context["filter_closed"] = filter_closed + context["filter_accepted"] = filter_accepted + context["filter_rejected"] = filter_rejected # A PackageRequest query query = db.query(PackageRequest) + # Requests statistics + context["total_requests"] = query.count() + pending_count = 0 + query.filter(PackageRequest.Status == PENDING_ID).count() + context["pending_requests"] = pending_count + closed_count = 0 + query.filter(PackageRequest.Status == CLOSED_ID).count() + context["closed_requests"] = closed_count + accepted_count = 0 + query.filter(PackageRequest.Status == ACCEPTED_ID).count() + context["accepted_requests"] = accepted_count + rejected_count = 0 + query.filter(PackageRequest.Status == REJECTED_ID).count() + context["rejected_requests"] = rejected_count + + # Apply filters + in_filters = [] + if filter_pending: + in_filters.append(PENDING_ID) + if filter_closed: + in_filters.append(CLOSED_ID) + if filter_accepted: + in_filters.append(ACCEPTED_ID) + if filter_rejected: + in_filters.append(REJECTED_ID) + filtered = query.filter(PackageRequest.Status.in_(in_filters)) # If the request user is not elevated (TU or Dev), then # filter PackageRequests which are owned by the request user. if not request.user.is_elevated(): - query = query.filter(PackageRequest.UsersID == request.user.ID) + filtered = filtered.filter(PackageRequest.UsersID == request.user.ID) - context["total"] = query.count() + context["total"] = filtered.count() context["results"] = ( - query.order_by( + filtered.order_by( # Order primarily by the Status column being PENDING_ID, # and secondarily by RequestTS; both in descending order. case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), diff --git a/templates/requests.html b/templates/requests.html index ed8f31fb..9037855c 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -4,6 +4,65 @@ {% set plural = "%d package requests found." %} {% block pageContent %} +
    +

    {{ "Requests" | tr }}

    +

    {{ "Total Statistics" | tr }}

    +
    {{ "Git Clone URL" | tr }}:
    {{ "Description" | tr }}:{{ pkg.Description }}{{ package.Description }}
    {{ "Upstream URL" | tr }}: - {% if pkg.URL %} - {{ pkg.URL }} + {% if package.URL %} + {{ package.URL }} {% else %} {{ "None" | tr }} {% endif %} From 25e05830a670b0ca99d007eabf2d8c127a13ce9a Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Mon, 5 Sep 2022 19:50:41 -0700 Subject: [PATCH 1568/1891] test: test that /packages/{name} produces the package's description This commit fixes two of our tests in test_templates.py to go along with our new template modifications, as well as a new test in test_packages_routes.py which constructs two packages belonging to the same package base, then tests that viewing their pages produces their independent descriptions. Signed-off-by: Kevin Morris --- templates/partials/packages/details.html | 2 +- test/test_packages_routes.py | 44 ++++++++++++++++++++++++ test/test_templates.py | 4 +-- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index cdb62128..86bc1de5 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -17,7 +17,7 @@
    {{ "Description" | tr }}: {{ package.Description }}
    {{ "Popularity" | tr }}:{{ pkgbase.Popularity | number_format(6 if pkgbase.Popularity <= 0.2 else 2) }}{{ popularity | number_format(6 if popularity <= 0.2 else 2) }}
    {{ "First Submitted" | tr }}:
    + + + + + + + + + + + + + + + + + + + + + + +
    {{ "Total" | tr }}:{{ total_requests }}
    {{ "Pending" | tr }}:{{ pending_requests }}
    {{ "Closed" | tr }}:{{ closed_requests }}
    {{ "Accepted" | tr }}:{{ accepted_requests }}
    {{ "Rejected" | tr }}:{{ rejected_requests }}
    +

    {{ "Filters" | tr }}

    +
    +
    +
    + {{ "Select filter criteria" | tr }} +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    {% if not total %}

    {{ "No requests matched your search criteria." | tr }}

    diff --git a/test/test_requests.py b/test/test_requests.py index 83cdb402..344b9edc 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -717,6 +717,10 @@ def test_requests( "O": 0, # Page 1 "SeB": "nd", "SB": "n", + "filter_pending": True, + "filter_closed": True, + "filter_accepted": True, + "filter_rejected": True, }, cookies=cookies, ) @@ -732,7 +736,17 @@ def test_requests( # Request page 2 of the requests page. with client as request: - resp = request.get("/requests", params={"O": 50}, cookies=cookies) # Page 2 + resp = request.get( + "/requests", + params={ + "O": 50, + "filter_pending": True, + "filter_closed": True, + "filter_accepted": True, + "filter_rejected": True, + }, + cookies=cookies, + ) # Page 2 assert resp.status_code == int(HTTPStatus.OK) assert "‹ Previous" in resp.text From 9c0f8f053ecaa2a34473dcf4b6b45c2d6812df96 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 6 May 2022 20:22:07 +0100 Subject: [PATCH 1609/1891] chore: rename logging.py and redis.py to avoid circular imports Signed-off-by: Leonidas Spyropoulos --- aurweb/asgi.py | 7 +++---- aurweb/{logging.py => aur_logging.py} | 0 aurweb/{redis.py => aur_redis.py} | 4 ++-- aurweb/initdb.py | 2 +- aurweb/models/user.py | 4 ++-- aurweb/packages/util.py | 2 +- aurweb/pkgbase/actions.py | 4 ++-- aurweb/prometheus.py | 4 ++-- aurweb/ratelimit.py | 6 +++--- aurweb/routers/accounts.py | 4 ++-- aurweb/routers/html.py | 6 +++--- aurweb/routers/packages.py | 4 ++-- aurweb/routers/pkgbase.py | 4 ++-- aurweb/routers/trusted_user.py | 4 ++-- aurweb/scripts/mkpkglists.py | 4 ++-- aurweb/scripts/notify.py | 4 ++-- aurweb/scripts/rendercomment.py | 4 ++-- aurweb/testing/alpm.py | 4 ++-- aurweb/testing/filelock.py | 4 ++-- aurweb/users/validate.py | 4 ++-- aurweb/util.py | 4 ++-- test/conftest.py | 4 ++-- test/test_accounts_routes.py | 4 ++-- test/test_asgi.py | 6 +++--- test/test_homepage.py | 2 +- test/test_logging.py | 4 ++-- test/test_packages_util.py | 2 +- test/test_ratelimit.py | 6 +++--- test/test_redis.py | 24 ++++++++++++------------ test/test_rendercomment.py | 4 ++-- test/test_rpc.py | 2 +- test/test_rss.py | 4 ++-- 32 files changed, 72 insertions(+), 73 deletions(-) rename aurweb/{logging.py => aur_logging.py} (100%) rename aurweb/{redis.py => aur_redis.py} (95%) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 72b47b4c..b172626f 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -22,19 +22,18 @@ from starlette.middleware.sessions import SessionMiddleware import aurweb.captcha # noqa: F401 import aurweb.config import aurweb.filters # noqa: F401 -import aurweb.logging import aurweb.pkgbase.util as pkgbaseutil -from aurweb import logging, prometheus, util +from aurweb import aur_logging, prometheus, util +from aurweb.aur_redis import redis_connection from aurweb.auth import BasicAuthBackend from aurweb.db import get_engine, query from aurweb.models import AcceptedTerm, Term from aurweb.packages.util import get_pkg_or_base from aurweb.prometheus import instrumentator -from aurweb.redis import redis_connection from aurweb.routers import APP_ROUTES from aurweb.templates import make_context, render_template -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) # Setup the FastAPI app. app = FastAPI() diff --git a/aurweb/logging.py b/aurweb/aur_logging.py similarity index 100% rename from aurweb/logging.py rename to aurweb/aur_logging.py diff --git a/aurweb/redis.py b/aurweb/aur_redis.py similarity index 95% rename from aurweb/redis.py rename to aurweb/aur_redis.py index af179b9b..ec66df19 100644 --- a/aurweb/redis.py +++ b/aurweb/aur_redis.py @@ -2,9 +2,9 @@ import fakeredis from redis import ConnectionPool, Redis import aurweb.config -from aurweb import logging +from aurweb import aur_logging -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) pool = None diff --git a/aurweb/initdb.py b/aurweb/initdb.py index ded4330d..ee59212c 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -3,8 +3,8 @@ import argparse import alembic.command import alembic.config +import aurweb.aur_logging import aurweb.db -import aurweb.logging import aurweb.schema diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 0d638677..9846d996 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -10,12 +10,12 @@ from sqlalchemy.orm import backref, relationship import aurweb.config import aurweb.models.account_type import aurweb.schema -from aurweb import db, logging, schema, time, util +from aurweb import aur_logging, db, schema, time, util from aurweb.models.account_type import AccountType as _AccountType from aurweb.models.ban import is_banned from aurweb.models.declarative import Base -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) SALT_ROUNDS_DEFAULT = 12 diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index b6ba7e20..cddec0ac 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -7,11 +7,11 @@ from fastapi import HTTPException from sqlalchemy import orm from aurweb import config, db, models +from aurweb.aur_redis import redis_connection from aurweb.models import Package from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_relation import PackageRelation -from aurweb.redis import redis_connection from aurweb.templates import register_filter Providers = list[Union[PackageRelation, OfficialProvider]] diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index a453cb36..56ba738d 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -1,6 +1,6 @@ from fastapi import Request -from aurweb import db, logging, util +from aurweb import aur_logging, db, util from aurweb.auth import creds from aurweb.models import PackageBase, User from aurweb.models.package_comaintainer import PackageComaintainer @@ -10,7 +10,7 @@ from aurweb.packages.requests import handle_request, update_closure_comment from aurweb.pkgbase import util as pkgbaseutil from aurweb.scripts import notify, popupdate -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) @db.retry_deadlock diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index 0bbea4be..b8b7984f 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -5,9 +5,9 @@ from prometheus_fastapi_instrumentator import Instrumentator from prometheus_fastapi_instrumentator.metrics import Info from starlette.routing import Match, Route -from aurweb import logging +from aurweb import aur_logging -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) _instrumentator = Instrumentator() diff --git a/aurweb/ratelimit.py b/aurweb/ratelimit.py index 97923a52..ea191972 100644 --- a/aurweb/ratelimit.py +++ b/aurweb/ratelimit.py @@ -1,11 +1,11 @@ from fastapi import Request from redis.client import Pipeline -from aurweb import config, db, logging, time +from aurweb import aur_logging, config, db, time +from aurweb.aur_redis import redis_connection from aurweb.models import ApiRateLimit -from aurweb.redis import redis_connection -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) def _update_ratelimit_redis(request: Request, pipeline: Pipeline): diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 12e59b30..24aacdf7 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -8,7 +8,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, or_ import aurweb.config -from aurweb import cookies, db, l10n, logging, models, util +from aurweb import aur_logging, cookies, db, l10n, models, util from aurweb.auth import account_type_required, creds, requires_auth, requires_guest from aurweb.captcha import get_captcha_salts from aurweb.exceptions import ValidationError, handle_form_exceptions @@ -22,7 +22,7 @@ from aurweb.users import update, validate from aurweb.users.util import get_user_by_name router = APIRouter() -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) @router.get("/passreset", response_class=HTMLResponse) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index da1ffd55..f5e6657f 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -16,7 +16,7 @@ from sqlalchemy import and_, case, or_ import aurweb.config import aurweb.models.package_request -from aurweb import cookies, db, logging, models, time, util +from aurweb import aur_logging, cookies, db, models, time, util from aurweb.cache import db_count_cache from aurweb.exceptions import handle_form_exceptions from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID @@ -24,7 +24,7 @@ from aurweb.models.package_request import PENDING_ID from aurweb.packages.util import query_notified, query_voted, updated_packages from aurweb.templates import make_context, render_template -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) router = APIRouter() @@ -80,7 +80,7 @@ async def index(request: Request): bases = db.query(models.PackageBase) - redis = aurweb.redis.redis_connection() + redis = aurweb.aur_redis.redis_connection() cache_expire = 300 # Five minutes. # Package statistics. diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 55d2abf5..0d482521 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -5,7 +5,7 @@ from typing import Any from fastapi import APIRouter, Form, Query, Request, Response import aurweb.filters # noqa: F401 -from aurweb import config, db, defaults, logging, models, util +from aurweb import aur_logging, config, db, defaults, models, util from aurweb.auth import creds, requires_auth from aurweb.exceptions import InvariantError, handle_form_exceptions from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID @@ -15,7 +15,7 @@ from aurweb.packages.util import get_pkg_or_base from aurweb.pkgbase import actions as pkgbase_actions, util as pkgbaseutil from aurweb.templates import make_context, make_variable_context, render_template -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) router = APIRouter() diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 3b1ab688..9dab76f8 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -4,7 +4,7 @@ from fastapi import APIRouter, Form, HTTPException, Query, Request, Response from fastapi.responses import JSONResponse, RedirectResponse from sqlalchemy import and_ -from aurweb import config, db, l10n, logging, templates, time, util +from aurweb import aur_logging, config, db, l10n, templates, time, util from aurweb.auth import creds, requires_auth from aurweb.exceptions import InvariantError, ValidationError, handle_form_exceptions from aurweb.models import PackageBase @@ -21,7 +21,7 @@ from aurweb.scripts import notify, popupdate from aurweb.scripts.rendercomment import update_comment_render_fastapi from aurweb.templates import make_variable_context, render_template -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) router = APIRouter() diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py index 37edb072..4248347d 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/trusted_user.py @@ -7,7 +7,7 @@ from fastapi import APIRouter, Form, HTTPException, Request from fastapi.responses import RedirectResponse, Response from sqlalchemy import and_, func, or_ -from aurweb import db, l10n, logging, models, time +from aurweb import aur_logging, db, l10n, models, time from aurweb.auth import creds, requires_auth from aurweb.exceptions import handle_form_exceptions from aurweb.models import User @@ -15,7 +15,7 @@ from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID from aurweb.templates import make_context, make_variable_context, render_template router = APIRouter() -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) # Some TU route specific constants. ITEMS_PER_PAGE = 10 # Paged table size. diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index bfdd12b4..e74bbf25 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -32,11 +32,11 @@ import orjson from sqlalchemy import literal, orm import aurweb.config -from aurweb import db, filters, logging, models, util +from aurweb import aur_logging, db, filters, models, util from aurweb.benchmark import Benchmark from aurweb.models import Package, PackageBase, User -logger = logging.get_logger("aurweb.scripts.mkpkglists") +logger = aur_logging.get_logger("aurweb.scripts.mkpkglists") TYPE_MAP = { diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index f19438bb..93108cd3 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -13,7 +13,7 @@ import aurweb.config import aurweb.db import aurweb.filters import aurweb.l10n -from aurweb import db, logging +from aurweb import aur_logging, db from aurweb.models import PackageBase, User from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_comment import PackageComment @@ -22,7 +22,7 @@ from aurweb.models.package_request import PackageRequest from aurweb.models.request_type import RequestType from aurweb.models.tu_vote import TUVote -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) aur_location = aurweb.config.get("options", "aur_location") diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index ff6fe09c..4a2c84bd 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -9,10 +9,10 @@ import markdown import pygit2 import aurweb.config -from aurweb import db, logging, util +from aurweb import aur_logging, db, util from aurweb.models import PackageComment -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) class LinkifyExtension(markdown.extensions.Extension): diff --git a/aurweb/testing/alpm.py b/aurweb/testing/alpm.py index ddafb710..61a9315f 100644 --- a/aurweb/testing/alpm.py +++ b/aurweb/testing/alpm.py @@ -4,10 +4,10 @@ import re import shutil import subprocess -from aurweb import logging, util +from aurweb import aur_logging, util from aurweb.templates import base_template -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) class AlpmDatabase: diff --git a/aurweb/testing/filelock.py b/aurweb/testing/filelock.py index 33b42cb3..d582f0bf 100644 --- a/aurweb/testing/filelock.py +++ b/aurweb/testing/filelock.py @@ -4,9 +4,9 @@ from typing import Callable from posix_ipc import O_CREAT, Semaphore -from aurweb import logging +from aurweb import aur_logging -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) def default_on_create(path): diff --git a/aurweb/users/validate.py b/aurweb/users/validate.py index 6c27a0b7..8fc68864 100644 --- a/aurweb/users/validate.py +++ b/aurweb/users/validate.py @@ -9,7 +9,7 @@ when encountering invalid criteria and return silently otherwise. from fastapi import Request from sqlalchemy import and_ -from aurweb import config, db, l10n, logging, models, time, util +from aurweb import aur_logging, config, db, l10n, models, time, util from aurweb.auth import creds from aurweb.captcha import get_captcha_answer, get_captcha_salts, get_captcha_token from aurweb.exceptions import ValidationError @@ -17,7 +17,7 @@ from aurweb.models.account_type import ACCOUNT_TYPE_NAME from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.util import strtobool -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) def invalid_fields(E: str = str(), U: str = str(), **kwargs) -> None: diff --git a/aurweb/util.py b/aurweb/util.py index 432b818a..cda12af1 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -15,9 +15,9 @@ from email_validator import EmailSyntaxError, validate_email from fastapi.responses import JSONResponse import aurweb.config -from aurweb import defaults, logging +from aurweb import aur_logging, defaults -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) def make_random_string(length: int) -> str: diff --git a/test/conftest.py b/test/conftest.py index aac221f7..15a982aa 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -52,12 +52,12 @@ from sqlalchemy.orm import scoped_session import aurweb.config import aurweb.db -from aurweb import initdb, logging, testing +from aurweb import aur_logging, initdb, testing from aurweb.testing.email import Email from aurweb.testing.filelock import FileLock from aurweb.testing.git import GitRepository -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) # Synchronization lock for database setup. setup_lock = Lock() diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index f4034a9a..33baa0ea 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -11,7 +11,7 @@ from fastapi.testclient import TestClient import aurweb.config import aurweb.models.account_type as at -from aurweb import captcha, db, logging, time +from aurweb import aur_logging, captcha, db, time from aurweb.asgi import app from aurweb.db import create, query from aurweb.models.accepted_term import AcceptedTerm @@ -31,7 +31,7 @@ from aurweb.models.user import User from aurweb.testing.html import get_errors from aurweb.testing.requests import Request -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) # Some test global constants. TEST_USERNAME = "test" diff --git a/test/test_asgi.py b/test/test_asgi.py index 6ff80fa3..3b794c76 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -10,17 +10,17 @@ from fastapi import HTTPException from fastapi.testclient import TestClient import aurweb.asgi +import aurweb.aur_redis import aurweb.config -import aurweb.redis from aurweb.exceptions import handle_form_exceptions from aurweb.testing.requests import Request @pytest.fixture def setup(db_test, email_test): - aurweb.redis.redis_connection().flushall() + aurweb.aur_redis.redis_connection().flushall() yield - aurweb.redis.redis_connection().flushall() + aurweb.aur_redis.redis_connection().flushall() @pytest.fixture diff --git a/test/test_homepage.py b/test/test_homepage.py index 5490a244..521f71c4 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -7,6 +7,7 @@ from fastapi.testclient import TestClient from aurweb import db, time from aurweb.asgi import app +from aurweb.aur_redis import redis_connection from aurweb.models.account_type import USER_ID from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -14,7 +15,6 @@ from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_request import PackageRequest from aurweb.models.request_type import DELETION_ID, RequestType from aurweb.models.user import User -from aurweb.redis import redis_connection from aurweb.testing.html import parse_root from aurweb.testing.requests import Request diff --git a/test/test_logging.py b/test/test_logging.py index 63092d07..90d13c93 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -1,6 +1,6 @@ -from aurweb import logging +from aurweb import aur_logging -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) def test_logging(caplog): diff --git a/test/test_packages_util.py b/test/test_packages_util.py index 0042cd71..a5273b68 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -2,6 +2,7 @@ import pytest from fastapi.testclient import TestClient from aurweb import asgi, config, db, time +from aurweb.aur_redis import kill_redis from aurweb.models.account_type import USER_ID from aurweb.models.official_provider import OFFICIAL_BASE, OfficialProvider from aurweb.models.package import Package @@ -11,7 +12,6 @@ from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote from aurweb.models.user import User from aurweb.packages import util -from aurweb.redis import kill_redis @pytest.fixture(autouse=True) diff --git a/test/test_ratelimit.py b/test/test_ratelimit.py index 20528847..b7cd7e7d 100644 --- a/test/test_ratelimit.py +++ b/test/test_ratelimit.py @@ -3,13 +3,13 @@ from unittest import mock import pytest from redis.client import Pipeline -from aurweb import config, db, logging +from aurweb import aur_logging, config, db +from aurweb.aur_redis import redis_connection from aurweb.models import ApiRateLimit from aurweb.ratelimit import check_ratelimit -from aurweb.redis import redis_connection from aurweb.testing.requests import Request -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) @pytest.fixture(autouse=True) diff --git a/test/test_redis.py b/test/test_redis.py index a66cd204..6f9bdb40 100644 --- a/test/test_redis.py +++ b/test/test_redis.py @@ -3,11 +3,11 @@ from unittest import mock import pytest import aurweb.config -from aurweb.redis import redis_connection +from aurweb.aur_redis import redis_connection @pytest.fixture -def rediss(): +def redis(): """Create a RedisStub.""" def mock_get(section, key): @@ -21,20 +21,20 @@ def rediss(): yield redis -def test_redis_stub(rediss): +def test_redis_stub(redis): # We don't yet have a test key set. - assert rediss.get("test") is None + assert redis.get("test") is None # Set the test key to abc. - rediss.set("test", "abc") - assert rediss.get("test").decode() == "abc" + redis.set("test", "abc") + assert redis.get("test").decode() == "abc" # Test expire. - rediss.expire("test", 0) - assert rediss.get("test") is None + redis.expire("test", 0) + assert redis.get("test") is None # Now, set the test key again and use delete() on it. - rediss.set("test", "abc") - assert rediss.get("test").decode() == "abc" - rediss.delete("test") - assert rediss.get("test") is None + redis.set("test", "abc") + assert redis.get("test").decode() == "abc" + redis.delete("test") + assert redis.get("test") is None diff --git a/test/test_rendercomment.py b/test/test_rendercomment.py index 5b7ff5ac..59eb7191 100644 --- a/test/test_rendercomment.py +++ b/test/test_rendercomment.py @@ -2,14 +2,14 @@ from unittest import mock import pytest -from aurweb import config, db, logging, time +from aurweb import aur_logging, config, db, time from aurweb.models import Package, PackageBase, PackageComment, User from aurweb.models.account_type import USER_ID from aurweb.scripts import rendercomment from aurweb.scripts.rendercomment import update_comment_render from aurweb.testing.git import GitRepository -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) aur_location = config.get("options", "aur_location") diff --git a/test/test_rpc.py b/test/test_rpc.py index 84ddd8d7..f417d379 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -10,6 +10,7 @@ from redis.client import Pipeline import aurweb.models.dependency_type as dt import aurweb.models.relation_type as rt from aurweb import asgi, config, db, rpc, scripts, time +from aurweb.aur_redis import redis_connection from aurweb.models.account_type import USER_ID from aurweb.models.dependency_type import DEPENDS_ID from aurweb.models.license import License @@ -22,7 +23,6 @@ from aurweb.models.package_relation import PackageRelation from aurweb.models.package_vote import PackageVote from aurweb.models.relation_type import PROVIDES_ID from aurweb.models.user import User -from aurweb.redis import redis_connection @pytest.fixture diff --git a/test/test_rss.py b/test/test_rss.py index 8526caa1..d227a183 100644 --- a/test/test_rss.py +++ b/test/test_rss.py @@ -4,14 +4,14 @@ import lxml.etree import pytest from fastapi.testclient import TestClient -from aurweb import db, logging, time +from aurweb import aur_logging, db, time from aurweb.asgi import app from aurweb.models.account_type import AccountType from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.user import User -logger = logging.get_logger(__name__) +logger = aur_logging.get_logger(__name__) @pytest.fixture(autouse=True) From 8555e232aeb331d3104fba5ec6b71341f979628b Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 22 Oct 2022 20:15:46 +0100 Subject: [PATCH 1610/1891] docs: fix mailing list after migration to mailman3 Closes: #396 Signed-off-by: Leonidas Spyropoulos --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 58612a36..c8d4f90d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Before sending patches, you are recommended to run `flake8` and `isort`. You can add a git hook to do this by installing `python-pre-commit` and running `pre-commit install`. -[1]: https://lists.archlinux.org/listinfo/aur-dev +[1]: https://lists.archlinux.org/mailman3/lists/aur-dev.lists.archlinux.org/ [2]: https://gitlab.archlinux.org/archlinux/aurweb ### Coding Guidelines From 0417603499f890a475eb7890bad3ba63c44637ca Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 22 Oct 2022 21:48:40 +0100 Subject: [PATCH 1611/1891] housekeep: bump renovate dependencies email-validator: 1.2.1 -> ^1.3.0 uvicorn: ^0.18.0 -> ^0.19.0 fastapi: ^0.83.0 -> ^0.85.0 pytest-asyncio: ^0.19.0 -> ^0.20.1 pytest-cov ^3.0.0 -> ^4.0.0 Signed-off-by: Leonidas Spyropoulos --- poetry.lock | 869 ++++++++++++++++++++++++++----------------------- pyproject.toml | 10 +- 2 files changed, 466 insertions(+), 413 deletions(-) diff --git a/poetry.lock b/poetry.lock index ef2c70f9..9cf24f9a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -23,7 +23,7 @@ tz = ["python-dateutil"] [[package]] name = "anyio" -version = "3.6.1" +version = "3.6.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "main" optional = false @@ -36,7 +36,7 @@ sniffio = ">=1.1" [package.extras] doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] -trio = ["trio (>=0.16)"] +trio = ["trio (>=0.16,<0.22)"] [[package]] name = "asgiref" @@ -69,11 +69,11 @@ python-versions = ">=3.5" dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "authlib" -version = "1.0.1" +version = "1.1.0" description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." category = "main" optional = false @@ -84,7 +84,7 @@ cryptography = ">=3.2" [[package]] name = "bcrypt" -version = "4.0.0" +version = "4.0.1" description = "Modern password hashing for your software and your servers" category = "main" optional = false @@ -112,7 +112,7 @@ dev = ["Sphinx (==4.3.2)", "black (==22.3.0)", "build (==0.8.0)", "flake8 (==4.0 [[package]] name = "certifi" -version = "2022.6.15" +version = "2022.9.24" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -138,7 +138,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode_backport = ["unicodedata2"] +unicode-backport = ["unicodedata2"] [[package]] name = "click" @@ -161,7 +161,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.4.4" +version = "6.5.0" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -175,7 +175,7 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "37.0.4" +version = "38.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -188,7 +188,7 @@ cffi = ">=1.12" docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] -sdist = ["setuptools_rust (>=0.11.4)"] +sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] @@ -204,7 +204,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest (<5)", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "pytest", "pytest-cov", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] +dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] [[package]] name = "dnspython" @@ -224,8 +224,8 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] name = "email-validator" -version = "1.2.1" -description = "A robust email syntax and deliverability validation library." +version = "1.3.0" +description = "A robust email address syntax and deliverability validation library." category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" @@ -247,7 +247,7 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "1.9.0" +version = "1.9.4" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false @@ -255,7 +255,6 @@ python-versions = ">=3.7,<4.0" [package.dependencies] redis = "<4.4" -six = ">=1.16.0,<2.0.0" sortedcontainers = ">=2.4.0,<3.0.0" [package.extras] @@ -264,21 +263,21 @@ lua = ["lupa (>=1.13,<2.0)"] [[package]] name = "fastapi" -version = "0.83.0" +version = "0.85.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.19.1" +starlette = "0.20.4" [package.extras] -all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +all = ["email-validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] +dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.7.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-orjson (==3.6.2)", "types-ujson (==5.4.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] [[package]] name = "feedgen" @@ -306,14 +305,14 @@ testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pyt [[package]] name = "greenlet" -version = "1.1.2" +version = "1.1.3.post0" description = "Lightweight in-process concurrent programming" category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" [package.extras] -docs = ["sphinx"] +docs = ["Sphinx"] [[package]] name = "gunicorn" @@ -323,6 +322,9 @@ category = "main" optional = false python-versions = ">=3.5" +[package.dependencies] +setuptools = ">=3.0" + [package.extras] eventlet = ["eventlet (>=0.24.1)"] gevent = ["gevent (>=1.4.0)"] @@ -411,7 +413,7 @@ toml = "*" wsproto = ">=0.14.0" [package.extras] -docs = ["pydata-sphinx-theme"] +docs = ["pydata_sphinx_theme"] h3 = ["aioquic (>=0.9.0,<1.0)"] trio = ["trio (>=0.11.0)"] uvloop = ["uvloop"] @@ -426,7 +428,7 @@ python-versions = ">=3.6.1" [[package]] name = "idna" -version = "3.3" +version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -434,7 +436,7 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.12.0" +version = "5.0.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -444,9 +446,9 @@ python-versions = ">=3.7" zipp = ">=0.5" [package.extras] -docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "iniconfig" @@ -489,12 +491,12 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] -htmlsoup = ["beautifulsoup4"] +htmlsoup = ["BeautifulSoup4"] source = ["Cython (>=0.29.7)"] [[package]] name = "mako" -version = "1.2.1" +version = "1.2.3" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." category = "main" optional = false @@ -504,7 +506,7 @@ python-versions = ">=3.7" MarkupSafe = ">=0.9.2" [package.extras] -babel = ["babel"] +babel = ["Babel"] lingua = ["lingua"] testing = ["pytest"] @@ -540,7 +542,7 @@ python-versions = ">=3.5" [[package]] name = "orjson" -version = "3.7.12" +version = "3.8.0" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false @@ -603,7 +605,7 @@ python-versions = ">=3.6.1" [[package]] name = "prometheus-client" -version = "0.14.1" +version = "0.15.0" description = "Python client for the Prometheus monitoring system." category = "main" optional = false @@ -614,7 +616,7 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.8.2" +version = "5.9.1" description = "Instrument your FastAPI with Prometheus metrics" category = "main" optional = false @@ -626,7 +628,7 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.21.5" +version = "4.21.8" description = "" category = "main" optional = false @@ -658,14 +660,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pydantic" -version = "1.9.2" +version = "1.10.2" description = "Data validation and settings management using python type hints" category = "main" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [package.dependencies] -typing-extensions = ">=3.7.4.3" +typing-extensions = ">=4.1.0" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] @@ -673,7 +675,7 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.10.0" +version = "1.10.1" description = "Python bindings for libgit2." category = "main" optional = false @@ -715,7 +717,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. [[package]] name = "pytest-asyncio" -version = "0.19.0" +version = "0.20.1" description = "Pytest support for asyncio" category = "dev" optional = false @@ -729,7 +731,7 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy [[package]] name = "pytest-cov" -version = "3.0.0" +version = "4.0.0" description = "Pytest plugin for measuring coverage." category = "dev" optional = false @@ -839,7 +841,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rfc3986" @@ -855,6 +857,19 @@ idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} [package.extras] idna2008 = ["idna"] +[[package]] +name = "setuptools" +version = "65.5.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "six" version = "1.16.0" @@ -865,11 +880,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "sniffio" -version = "1.2.0" +version = "1.3.0" description = "Sniff out which async library your code is running under" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [[package]] name = "sortedcontainers" @@ -881,7 +896,7 @@ python-versions = "*" [[package]] name = "sqlalchemy" -version = "1.4.40" +version = "1.4.42" description = "Database Abstraction Library" category = "main" optional = false @@ -895,21 +910,21 @@ aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql_pymssql = ["pymssql"] -mssql_pyodbc = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql_connector = ["mysql-connector-python"] +mysql-connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql_psycopg2binary = ["psycopg2-binary"] -postgresql_psycopg2cffi = ["psycopg2cffi"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3-binary"] +sqlcipher = ["sqlcipher3_binary"] [[package]] name = "srcinfo" @@ -924,11 +939,11 @@ parse = "*" [[package]] name = "starlette" -version = "0.19.1" +version = "0.20.4" description = "The little ASGI library that shines." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] anyio = ">=3.4.0,<5" @@ -938,7 +953,7 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\"" full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] [[package]] -name = "tap.py" +name = "tap-py" version = "3.1" description = "Test Anything Protocol (TAP) tools" category = "dev" @@ -966,7 +981,7 @@ python-versions = ">=3.7" [[package]] name = "typing-extensions" -version = "4.3.0" +version = "4.4.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false @@ -974,7 +989,7 @@ python-versions = ">=3.7" [[package]] name = "urllib3" -version = "1.26.11" +version = "1.26.12" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -982,12 +997,12 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.18.3" +version = "0.19.0" description = "The lightning-fast ASGI server." category = "main" optional = false @@ -998,7 +1013,7 @@ click = ">=7.0" h11 = ">=0.8" [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] [[package]] name = "webencodings" @@ -1032,7 +1047,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "wsproto" -version = "1.1.0" +version = "1.2.0" description = "WebSockets state-machine based protocol implementation" category = "main" optional = false @@ -1043,20 +1058,20 @@ h11 = ">=0.9.0,<1" [[package]] name = "zipp" -version = "3.8.1" +version = "3.9.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] -testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "e1f9d796eea832af84c40c754ee3c58e633e98bd7cdb42a985b2c8657e82037e" +content-hash = "de9f0dc1d7e3f149a83629ad30d161da38aa1498b81aaa8bdfd2ebed50f232ab" [metadata.files] aiofiles = [ @@ -1068,8 +1083,8 @@ alembic = [ {file = "alembic-1.8.1.tar.gz", hash = "sha256:cd0b5e45b14b706426b833f06369b9a6d5ee03f826ec3238723ce8caaf6e5ffa"}, ] anyio = [ - {file = "anyio-3.6.1-py3-none-any.whl", hash = "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be"}, - {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"}, + {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, + {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, ] asgiref = [ {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, @@ -1084,30 +1099,39 @@ attrs = [ {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, ] authlib = [ - {file = "Authlib-1.0.1-py2.py3-none-any.whl", hash = "sha256:1286e2d5ef5bfe5a11cc2d0a0d1031f0393f6ce4d61f5121cfe87fa0054e98bd"}, - {file = "Authlib-1.0.1.tar.gz", hash = "sha256:6e74a4846ac36dfc882b3cc2fbd3d9eb410a627f2f2dc11771276655345223b1"}, + {file = "Authlib-1.1.0-py2.py3-none-any.whl", hash = "sha256:be4b6a1dea51122336c210a6945b27a105b9ac572baffd15b07bcff4376c1523"}, + {file = "Authlib-1.1.0.tar.gz", hash = "sha256:0a270c91409fc2b7b0fbee6996e09f2ee3187358762111a9a4225c874b94e891"}, ] bcrypt = [ - {file = "bcrypt-4.0.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:845b1daf4df2dd94d2fdbc9454953ca9dd0e12970a0bfc9f3dcc6faea3fa96e4"}, - {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8780e69f9deec9d60f947b169507d2c9816e4f11548f1f7ebee2af38b9b22ae4"}, - {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c3334446fac200499e8bc04a530ce3cf0b3d7151e0e4ac5c0dddd3d95e97843"}, - {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfb67f6a6c72dfb0a02f3df51550aa1862708e55128b22543e2b42c74f3620d7"}, - {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:7c7dd6c1f05bf89e65261d97ac3a6520f34c2acb369afb57e3ea4449be6ff8fd"}, - {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:594780b364fb45f2634c46ec8d3e61c1c0f1811c4f2da60e8eb15594ecbf93ed"}, - {file = "bcrypt-4.0.0-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2d0dd19aad87e4ab882ef1d12df505f4c52b28b69666ce83c528f42c07379227"}, - {file = "bcrypt-4.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bf413f2a9b0a2950fc750998899013f2e718d20fa4a58b85ca50b6df5ed1bbf9"}, - {file = "bcrypt-4.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ede0f506554571c8eda80db22b83c139303ec6b595b8f60c4c8157bdd0bdee36"}, - {file = "bcrypt-4.0.0-cp36-abi3-win32.whl", hash = "sha256:dc6ec3dc19b1c193b2f7cf279d3e32e7caf447532fbcb7af0906fe4398900c33"}, - {file = "bcrypt-4.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:0b0f0c7141622a31e9734b7f649451147c04ebb5122327ac0bd23744df84be90"}, - {file = "bcrypt-4.0.0.tar.gz", hash = "sha256:c59c170fc9225faad04dde1ba61d85b413946e8ce2e5f5f5ff30dfd67283f319"}, + {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"}, + {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"}, + {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"}, + {file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"}, ] bleach = [ {file = "bleach-5.0.1-py3-none-any.whl", hash = "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a"}, {file = "bleach-5.0.1.tar.gz", hash = "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"}, ] certifi = [ - {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, - {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"}, + {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, + {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, ] cffi = [ {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, @@ -1188,80 +1212,84 @@ colorama = [ {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] coverage = [ - {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, - {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, - {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, - {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, - {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, - {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, - {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, - {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, - {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, - {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, - {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, - {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, - {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, - {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, - {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, - {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, + {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, + {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, + {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, + {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, + {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, + {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, + {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, + {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, + {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, + {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, + {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, + {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, + {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, + {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, ] cryptography = [ - {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884"}, - {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6"}, - {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046"}, - {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5"}, - {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b"}, - {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8"}, - {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280"}, - {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3"}, - {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59"}, - {file = "cryptography-37.0.4-cp36-abi3-win32.whl", hash = "sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157"}, - {file = "cryptography-37.0.4-cp36-abi3-win_amd64.whl", hash = "sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327"}, - {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b"}, - {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9"}, - {file = "cryptography-37.0.4-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67"}, - {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d"}, - {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282"}, - {file = "cryptography-37.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa"}, - {file = "cryptography-37.0.4-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441"}, - {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596"}, - {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a"}, - {file = "cryptography-37.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab"}, - {file = "cryptography-37.0.4.tar.gz", hash = "sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82"}, + {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f"}, + {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd"}, + {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6"}, + {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a"}, + {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294"}, + {file = "cryptography-38.0.1-cp36-abi3-win32.whl", hash = "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0"}, + {file = "cryptography-38.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a"}, + {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d"}, + {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9"}, + {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013"}, + {file = "cryptography-38.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a"}, + {file = "cryptography-38.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b"}, + {file = "cryptography-38.0.1.tar.gz", hash = "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7"}, ] deprecated = [ {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, @@ -1272,20 +1300,20 @@ dnspython = [ {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, ] email-validator = [ - {file = "email_validator-1.2.1-py2.py3-none-any.whl", hash = "sha256:c8589e691cf73eb99eed8d10ce0e9cbb05a0886ba920c8bcb7c82873f4c5789c"}, - {file = "email_validator-1.2.1.tar.gz", hash = "sha256:6757aea012d40516357c0ac2b1a4c31219ab2f899d26831334c5d069e8b6c3d8"}, + {file = "email_validator-1.3.0-py2.py3-none-any.whl", hash = "sha256:816073f2a7cffef786b29928f58ec16cdac42710a53bb18aa94317e3e145ec5c"}, + {file = "email_validator-1.3.0.tar.gz", hash = "sha256:553a66f8be2ec2dea641ae1d3f29017ab89e9d603d4a25cdaac39eefa283d769"}, ] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, ] fakeredis = [ - {file = "fakeredis-1.9.0-py3-none-any.whl", hash = "sha256:868467ff399520fc77e37ff002c60d1b2a1674742982e27338adaeebcc537648"}, - {file = "fakeredis-1.9.0.tar.gz", hash = "sha256:60639946e3bb1274c30416f539f01f9d73b4ea68c244c1442f5524e45f51e882"}, + {file = "fakeredis-1.9.4-py3-none-any.whl", hash = "sha256:61afe14095aad3e7413a0a6fe63041da1b4bc3e41d5228a33b60bd03fabf22d8"}, + {file = "fakeredis-1.9.4.tar.gz", hash = "sha256:17415645d11994061f5394f3f1c76ba4531f3f8b63f9c55a8fd2120bebcbfae9"}, ] fastapi = [ - {file = "fastapi-0.83.0-py3-none-any.whl", hash = "sha256:694a2b6c2607a61029a4be1c6613f84d74019cb9f7a41c7a475dca8e715f9368"}, - {file = "fastapi-0.83.0.tar.gz", hash = "sha256:96eb692350fe13d7a9843c3c87a874f0d45102975257dd224903efd6c0fde3bd"}, + {file = "fastapi-0.85.1-py3-none-any.whl", hash = "sha256:de3166b6b1163dc22da4dc4ebdc3192fcbac7700dd1870a1afa44de636a636b5"}, + {file = "fastapi-0.85.1.tar.gz", hash = "sha256:1facd097189682a4ff11cbd01334a992e51b56be663b2bd50c2c09523624f144"}, ] feedgen = [ {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, @@ -1295,61 +1323,72 @@ filelock = [ {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, ] greenlet = [ - {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"}, - {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"}, - {file = "greenlet-1.1.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d"}, - {file = "greenlet-1.1.2-cp27-cp27m-win32.whl", hash = "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713"}, - {file = "greenlet-1.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40"}, - {file = "greenlet-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d"}, - {file = "greenlet-1.1.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8"}, - {file = "greenlet-1.1.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"}, - {file = "greenlet-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965"}, - {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"}, - {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"}, - {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"}, - {file = "greenlet-1.1.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c"}, - {file = "greenlet-1.1.2-cp35-cp35m-win32.whl", hash = "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963"}, - {file = "greenlet-1.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e"}, - {file = "greenlet-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"}, - {file = "greenlet-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f"}, - {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"}, - {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"}, - {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"}, - {file = "greenlet-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe"}, - {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"}, - {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"}, - {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"}, - {file = "greenlet-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2"}, - {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"}, - {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"}, - {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"}, - {file = "greenlet-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3"}, - {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"}, - {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, - {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9649891ab4153f217f319914455ccf0b86986b55fc0573ce803eb998ad7d6854"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-win32.whl", hash = "sha256:11fc7692d95cc7a6a8447bb160d98671ab291e0a8ea90572d582d57361360f05"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-win_amd64.whl", hash = "sha256:05ae7383f968bba4211b1fbfc90158f8e3da86804878442b4fb6c16ccbcaa519"}, + {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ccbe7129a282ec5797df0451ca1802f11578be018a32979131065565da89b392"}, + {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a8b58232f5b72973350c2b917ea3df0bebd07c3c82a0a0e34775fc2c1f857e9"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f6661b58412879a2aa099abb26d3c93e91dedaba55a6394d1fb1512a77e85de9"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c6e942ca9835c0b97814d14f78da453241837419e0d26f7403058e8db3e38f8"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a812df7282a8fc717eafd487fccc5ba40ea83bb5b13eb3c90c446d88dbdfd2be"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a7a6560df073ec9de2b7cb685b199dfd12519bc0020c62db9d1bb522f989fa"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17a69967561269b691747e7f436d75a4def47e5efcbc3c573180fc828e176d80"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:60839ab4ea7de6139a3be35b77e22e0398c270020050458b3d25db4c7c394df5"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-win_amd64.whl", hash = "sha256:8926a78192b8b73c936f3e87929931455a6a6c6c385448a07b9f7d1072c19ff3"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:c6f90234e4438062d6d09f7d667f79edcc7c5e354ba3a145ff98176f974b8132"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814f26b864ed2230d3a7efe0336f5766ad012f94aad6ba43a7c54ca88dd77cba"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fda1139d87ce5f7bd80e80e54f9f2c6fe2f47983f1a6f128c47bf310197deb6"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0643250dd0756f4960633f5359884f609a234d4066686754e834073d84e9b51"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cb863057bed786f6622982fb8b2c122c68e6e9eddccaa9fa98fd937e45ee6c4f"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8c0581077cf2734569f3e500fab09c0ff6a2ab99b1afcacbad09b3c2843ae743"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:695d0d8b5ae42c800f1763c9fce9d7b94ae3b878919379150ee5ba458a460d57"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5662492df0588a51d5690f6578f3bbbd803e7f8d99a99f3bf6128a401be9c269"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:bffba15cff4802ff493d6edcf20d7f94ab1c2aee7cfc1e1c7627c05f1102eee8"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-win32.whl", hash = "sha256:7afa706510ab079fd6d039cc6e369d4535a48e202d042c32e2097f030a16450f"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-win_amd64.whl", hash = "sha256:3a24f3213579dc8459e485e333330a921f579543a5214dbc935bc0763474ece3"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:64e10f303ea354500c927da5b59c3802196a07468332d292aef9ddaca08d03dd"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:eb6ac495dccb1520667cfea50d89e26f9ffb49fa28496dea2b95720d8b45eb54"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:88720794390002b0c8fa29e9602b395093a9a766b229a847e8d88349e418b28a"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39464518a2abe9c505a727af7c0b4efff2cf242aa168be5f0daa47649f4d7ca8"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0914f02fcaa8f84f13b2df4a81645d9e82de21ed95633765dd5cc4d3af9d7403"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96656c5f7c95fc02c36d4f6ef32f4e94bb0b6b36e6a002c21c39785a4eec5f5d"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4f74aa0092602da2069df0bc6553919a15169d77bcdab52a21f8c5242898f519"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3aeac044c324c1a4027dca0cde550bd83a0c0fbff7ef2c98df9e718a5086c194"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-win32.whl", hash = "sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:70048d7b2c07c5eadf8393e6398595591df5f59a2f26abc2f81abca09610492f"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:66aa4e9a726b70bcbfcc446b7ba89c8cec40f405e51422c39f42dfa206a96a05"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:025b8de2273d2809f027d347aa2541651d2e15d593bbce0d5f502ca438c54136"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:82a38d7d2077128a017094aff334e67e26194f46bd709f9dcdacbf3835d47ef5"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8ece5d1a99a2adcb38f69af2f07d96fb615415d32820108cd340361f590d128"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2794eef1b04b5ba8948c72cc606aab62ac4b0c538b14806d9c0d88afd0576d6b"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a8d24eb5cb67996fb84633fdc96dbc04f2d8b12bfcb20ab3222d6be271616b67"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0120a879aa2b1ac5118bce959ea2492ba18783f65ea15821680a256dfad04754"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-win32.whl", hash = "sha256:bef49c07fcb411c942da6ee7d7ea37430f830c482bf6e4b72d92fd506dd3a427"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:62723e7eb85fa52e536e516ee2ac91433c7bb60d51099293671815ff49ed1c21"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d25cdedd72aa2271b984af54294e9527306966ec18963fd032cc851a725ddc1b"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:924df1e7e5db27d19b1359dc7d052a917529c95ba5b8b62f4af611176da7c8ad"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ec615d2912b9ad807afd3be80bf32711c0ff9c2b00aa004a45fd5d5dde7853d9"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0971d37ae0eaf42344e8610d340aa0ad3d06cd2eee381891a10fe771879791f9"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:325f272eb997916b4a3fc1fea7313a8adb760934c2140ce13a2117e1b0a8095d"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75afcbb214d429dacdf75e03a1d6d6c5bd1fa9c35e360df8ea5b6270fb2211c"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5c2d21c2b768d8c86ad935e404cc78c30d53dea009609c3ef3a9d49970c864b5"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:467b73ce5dcd89e381292fb4314aede9b12906c18fab903f995b86034d96d5c8"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-win32.whl", hash = "sha256:8149a6865b14c33be7ae760bcdb73548bb01e8e47ae15e013bf7ef9290ca309a"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-win_amd64.whl", hash = "sha256:104f29dd822be678ef6b16bf0035dcd43206a8a48668a6cae4d2fe9c7a7abdeb"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:c8c9301e3274276d3d20ab6335aa7c5d9e5da2009cccb01127bddb5c951f8870"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:8415239c68b2ec9de10a5adf1130ee9cb0ebd3e19573c55ba160ff0ca809e012"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:3c22998bfef3fcc1b15694818fc9b1b87c6cc8398198b96b6d355a7bcb8c934e"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa1845944e62f358d63fcc911ad3b415f585612946b8edc824825929b40e59e"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:890f633dc8cb307761ec566bc0b4e350a93ddd77dc172839be122be12bae3e10"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cf37343e43404699d58808e51f347f57efd3010cc7cee134cdb9141bd1ad9ea"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5edf75e7fcfa9725064ae0d8407c849456553a181ebefedb7606bac19aa1478b"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-win32.whl", hash = "sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-win_amd64.whl", hash = "sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7"}, + {file = "greenlet-1.1.3.post0.tar.gz", hash = "sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c"}, ] gunicorn = [ {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, @@ -1384,12 +1423,12 @@ hyperframe = [ {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, ] idna = [ - {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, - {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"}, - {file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"}, + {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, + {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1476,8 +1515,8 @@ lxml = [ {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, ] mako = [ - {file = "Mako-1.2.1-py3-none-any.whl", hash = "sha256:df3921c3081b013c8a2d5ff03c18375651684921ae83fd12e64800b7da923257"}, - {file = "Mako-1.2.1.tar.gz", hash = "sha256:f054a5ff4743492f1aa9ecc47172cb33b42b9d993cffcc146c9de17e717b0307"}, + {file = "Mako-1.2.3-py3-none-any.whl", hash = "sha256:c413a086e38cd885088d5e165305ee8eed04e8b3f8f62df343480da0a385735f"}, + {file = "Mako-1.2.3.tar.gz", hash = "sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd"}, ] markdown = [ {file = "Markdown-3.4.1-py3-none-any.whl", hash = "sha256:08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186"}, @@ -1535,48 +1574,48 @@ mysqlclient = [ {file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"}, ] orjson = [ - {file = "orjson-3.7.12-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:5fbf5ec736c952e150a4399862bdd0043c1597e4d9e64adebe750855e72e2f65"}, - {file = "orjson-3.7.12-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:c09ed2e953447472c497ec682f4f40727744ed72672600e2e105ed5c373a82b1"}, - {file = "orjson-3.7.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdbbf6f8a23c66fa67661966891fd62341c5b7265e77fd6ecd7195aac26e76c0"}, - {file = "orjson-3.7.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a04df90f09e9c64c082d5e9af50e3e4c8cdc151b681f9d4928bb6bb17ef45c7b"}, - {file = "orjson-3.7.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:946d769d6e57e31838c8486e3f440540214690aaecca3bd2a57e31a227d27031"}, - {file = "orjson-3.7.12-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:fff4760d3c04edcc99be0c9040b4cbb3f6c4ae5b4c4fc1ec1f70c3fe47a9ea5a"}, - {file = "orjson-3.7.12-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a7a57ab51d92235604044da31e1481e53b44b6df4688929dd8c176ff09381516"}, - {file = "orjson-3.7.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0966b2f6db800ed40138df80040b84ba6a180f50af9b9a4ed5f7231114f6beb8"}, - {file = "orjson-3.7.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ec3f644f1a1e3b642050ee1428311eaec2b959ffb6122ebc216143e67a939b64"}, - {file = "orjson-3.7.12-cp310-none-win_amd64.whl", hash = "sha256:75a7d1b61300e76b06767dc60ff3f38af4a6634cb8169bc8e9db2b4124c27e6d"}, - {file = "orjson-3.7.12-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8c618af13ae16e050342018a9d019365c6f7d1cba04f42fd8d8ca1d1a604a54c"}, - {file = "orjson-3.7.12-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9ef5f5c5fd1d0086f9323dafacfa902c2f4f120f319e689457ee2a66aebfc889"}, - {file = "orjson-3.7.12-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:eec6d61468ee0f251ac33d8738942390fda4e1e36f2d9c365ac271a87e78004b"}, - {file = "orjson-3.7.12-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:277ac2591570d88d5501cbf5855fc4a421cc51f3075b3be1b50ef2f8e8d2d014"}, - {file = "orjson-3.7.12-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae14ccad9b912abfee0e598a9fb57b6888ec3d2121983b757d9135702d1ab035"}, - {file = "orjson-3.7.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b8ac02e683286e1979f1c57c026503c2433a26525adb1671142b0b13d52a7c"}, - {file = "orjson-3.7.12-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:4d76fc5708cf1a7a394b42c1c697a8635fbce73730455870127815b8d7229bcf"}, - {file = "orjson-3.7.12-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:39717add544688a3a938fcbc4122cf1b31030ba8ea1145d12fc6ee29d0eabe27"}, - {file = "orjson-3.7.12-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:93beb800fc35402db6c7d435fcf8b3e45822eb668d112c2def3e2851b3557bb1"}, - {file = "orjson-3.7.12-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:148b33d2a9f7e464e0a292f13fa11e226baf11b61495ad536977e800bc9ca845"}, - {file = "orjson-3.7.12-cp37-none-win_amd64.whl", hash = "sha256:2baefa5fb5133448f06d24b2523dfb3eda562a93bb69c33f539c7bbb8b0d61ed"}, - {file = "orjson-3.7.12-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:e6ae6d14062be5a210909f8816936e0b9b9747b8416d99ec927ab4b8d73bdce6"}, - {file = "orjson-3.7.12-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:22738105f3e926ef22702b14a9b79652f18f8dd45b798a126ee9644e0ac683d8"}, - {file = "orjson-3.7.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e5aa0bf79f475c67d22eb4c085416ebb05042ce3c98abdbcfe11c1674d096d"}, - {file = "orjson-3.7.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e7698b66ed751d9b887a27f5e02fb8405f06edafc47ac4542b2e10b2927f9e1"}, - {file = "orjson-3.7.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9accc4ba1cb83b70ac89f9de465b12e96bc6713158d27b655106413ed07944a"}, - {file = "orjson-3.7.12-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:5a9cc4f2231756b939f3aaa997024e748e06ac9bc5619343aa0e88b2833a567f"}, - {file = "orjson-3.7.12-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:e1082f82cfc2fd9ee42b3716900da8b13a2efd627a105438c5d98f2476ddcd54"}, - {file = "orjson-3.7.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a80722ed6545069d4f8fe16e02f5e9a67e09b6872c4c7501fa095d57471d96a6"}, - {file = "orjson-3.7.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b37eba028ef4f55587ac4eb6dffc5207a884cb506f79e4104f2d5587f163a676"}, - {file = "orjson-3.7.12-cp38-none-win_amd64.whl", hash = "sha256:94cc18a7d20b1fc36f6a60ad98027a27e1462fb815cf0245728285df0ea6b5cf"}, - {file = "orjson-3.7.12-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:71975ed815c929e14351cfde6d74ea892e850f74b02eaa57d2b96cc8c3fbed7b"}, - {file = "orjson-3.7.12-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:5a45baa048b462774b3b777725416006b7eec4b70b1bfc40d895cfa65c5b5eac"}, - {file = "orjson-3.7.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bffc45cd04480be9f18b790f28d716dde117de43b02e0f702935b584fada1de"}, - {file = "orjson-3.7.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a7122f702fe62e79ff3e8a6f975b5559440345ace5618ee1d97c49230f2839b6"}, - {file = "orjson-3.7.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6d1fd006691ea9e500ebba753dea471daef8972260e8ef48b4f356daa2fb3d1"}, - {file = "orjson-3.7.12-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:4b5851c0acc2a35173ba5fa854e15bf6f18757fafe1f7cce0fbc7fc24af3ec8a"}, - {file = "orjson-3.7.12-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:0f2ddd043450579ba35bbcf34e9217ee4de0fc52716ae3eb6cfff5e24fcc0ba3"}, - {file = "orjson-3.7.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ff6006857688991e800e9d2d992195451e25353c47b313f0db859016ceb811b3"}, - {file = "orjson-3.7.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:818405b65fa9d9d37330e57d87f91b40c10d2469d16914c7a819d0d494af482c"}, - {file = "orjson-3.7.12-cp39-none-win_amd64.whl", hash = "sha256:c1e4297b5dee3e14e068cc35505b3e1a626dd3fb8d357842902616564d2f713f"}, - {file = "orjson-3.7.12.tar.gz", hash = "sha256:05f20fa1a368207d16ecdf16072c3be58f85c4954cd2ed6c9704463963b9791a"}, + {file = "orjson-3.8.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:9a93850a1bdc300177b111b4b35b35299f046148ba23020f91d6efd7bf6b9d20"}, + {file = "orjson-3.8.0-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:7536a2a0b41672f824912aeab545c2467a9ff5ca73a066ff04fb81043a0a177a"}, + {file = "orjson-3.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66c19399bb3b058e3236af7910b57b19a4fc221459d722ed72a7dc90370ca090"}, + {file = "orjson-3.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b391d5c2ddc2f302d22909676b306cb6521022c3ee306c861a6935670291b2c"}, + {file = "orjson-3.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bdb1042970ca5f544a047d6c235a7eb4acdb69df75441dd1dfcbc406377ab37"}, + {file = "orjson-3.8.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d189e2acb510e374700cb98cf11b54f0179916ee40f8453b836157ae293efa79"}, + {file = "orjson-3.8.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6a23b40c98889e9abac084ce5a1fb251664b41da9f6bdb40a4729e2288ed2ed4"}, + {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"}, + {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"}, + {file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"}, + {file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"}, + {file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"}, + {file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"}, + {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"}, + {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6e3da2e4bd27c3b796519ca74132c7b9e5348fb6746315e0f6c1592bc5cf1caf"}, + {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896a21a07f1998648d9998e881ab2b6b80d5daac4c31188535e9d50460edfcf7"}, + {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:4065906ce3ad6195ac4d1bddde862fe811a42d7be237a1ff762666c3a4bb2151"}, + {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:5f856279872a4449fc629924e6a083b9821e366cf98b14c63c308269336f7c14"}, + {file = "orjson-3.8.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1b1cd25acfa77935bb2e791b75211cec0cfc21227fe29387e553c545c3ff87e1"}, + {file = "orjson-3.8.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3e2459d441ab8fd8b161aa305a73d5269b3cda13b5a2a39eba58b4dd3e394f49"}, + {file = "orjson-3.8.0-cp37-none-win_amd64.whl", hash = "sha256:d2b5dafbe68237a792143137cba413447f60dd5df428e05d73dcba10c1ea6fcf"}, + {file = "orjson-3.8.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:5b072ef8520cfe7bd4db4e3c9972d94336763c2253f7c4718a49e8733bada7b8"}, + {file = "orjson-3.8.0-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e68c699471ea3e2dd1b35bfd71c6a0a0e4885b64abbe2d98fce1ef11e0afaff3"}, + {file = "orjson-3.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7225e8b08996d1a0c804d3a641a53e796685e8c9a9fd52bd428980032cad9a"}, + {file = "orjson-3.8.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f687776a03c19f40b982fb5c414221b7f3d19097841571be2223d1569a59877"}, + {file = "orjson-3.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7990a9caf3b34016ac30be5e6cfc4e7efd76aa85614a1215b0eae4f0c7e3db59"}, + {file = "orjson-3.8.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:02d638d43951ba346a80f0abd5942a872cc87db443e073f6f6fc530fee81e19b"}, + {file = "orjson-3.8.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f4b46dbdda2f0bd6480c39db90b21340a19c3b0fcf34bc4c6e465332930ca539"}, + {file = "orjson-3.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:655d7387a1634a9a477c545eea92a1ee902ab28626d701c6de4914e2ed0fecd2"}, + {file = "orjson-3.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5edb93cdd3eb32977633fa7aaa6a34b8ab54d9c49cdcc6b0d42c247a29091b22"}, + {file = "orjson-3.8.0-cp38-none-win_amd64.whl", hash = "sha256:03ed95814140ff09f550b3a42e6821f855d981c94d25b9cc83e8cca431525d70"}, + {file = "orjson-3.8.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7b0e72974a5d3b101226899f111368ec2c9824d3e9804af0e5b31567f53ad98a"}, + {file = "orjson-3.8.0-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6ea5fe20ef97545e14dd4d0263e4c5c3bc3d2248d39b4b0aed4b84d528dfc0af"}, + {file = "orjson-3.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6433c956f4a18112342a18281e0bec67fcd8b90be3a5271556c09226e045d805"}, + {file = "orjson-3.8.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87462791dd57de2e3e53068bf4b7169c125c50960f1bdda08ed30c797cb42a56"}, + {file = "orjson-3.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be02f6acee33bb63862eeff80548cd6b8a62e2d60ad2d8dfd5a8824cc43d8887"}, + {file = "orjson-3.8.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:a709c2249c1f2955dbf879506fd43fa08c31fdb79add9aeb891e3338b648bf60"}, + {file = "orjson-3.8.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2065b6d280dc58f131ffd93393737961ff68ae7eb6884b68879394074cc03c13"}, + {file = "orjson-3.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fd6cac83136e06e538a4d17117eaeabec848c1e86f5742d4811656ad7ee475f"}, + {file = "orjson-3.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:25b5e48fbb9f0b428a5e44cf740675c9281dd67816149fc33659803399adbbe8"}, + {file = "orjson-3.8.0-cp39-none-win_amd64.whl", hash = "sha256:2058653cc12b90e482beacb5c2d52dc3d7606f9e9f5a52c1c10ef49371e76f52"}, + {file = "orjson-3.8.0.tar.gz", hash = "sha256:fb42f7cf57d5804a9daa6b624e3490ec9e2631e042415f3aebe9f35a8492ba6c"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -1605,28 +1644,28 @@ priority = [ {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, ] prometheus-client = [ - {file = "prometheus_client-0.14.1-py3-none-any.whl", hash = "sha256:522fded625282822a89e2773452f42df14b5a8e84a86433e3f8a189c1d54dc01"}, - {file = "prometheus_client-0.14.1.tar.gz", hash = "sha256:5459c427624961076277fdc6dc50540e2bacb98eebde99886e59ec55ed92093a"}, + {file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"}, + {file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"}, ] prometheus-fastapi-instrumentator = [ - {file = "prometheus-fastapi-instrumentator-5.8.2.tar.gz", hash = "sha256:f1fa362043b974d138f5245acc973c32d1fa798bd2bd98ef2754befbf385a566"}, - {file = "prometheus_fastapi_instrumentator-5.8.2-py3-none-any.whl", hash = "sha256:5bfec239a924e1fed4ba94eb0addc73422d11821e894200b6d0e36a61c966827"}, + {file = "prometheus-fastapi-instrumentator-5.9.1.tar.gz", hash = "sha256:3651a72f73359a28e8afb0d370ebe3774147323ee2285e21236b229ce79172fc"}, + {file = "prometheus_fastapi_instrumentator-5.9.1-py3-none-any.whl", hash = "sha256:b5206ea9aa6975a0b07f3bf7376932b8a1b2983164b5abb04878e75ba336d9ed"}, ] protobuf = [ - {file = "protobuf-4.21.5-cp310-abi3-win32.whl", hash = "sha256:5310cbe761e87f0c1decce019d23f2101521d4dfff46034f8a12a53546036ec7"}, - {file = "protobuf-4.21.5-cp310-abi3-win_amd64.whl", hash = "sha256:e5c5a2886ae48d22a9d32fbb9b6636a089af3cd26b706750258ce1ca96cc0116"}, - {file = "protobuf-4.21.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ee04f5823ed98bb9a8c3b1dc503c49515e0172650875c3f76e225b223793a1f2"}, - {file = "protobuf-4.21.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:b04484d6f42f48c57dd2737a72692f4c6987529cdd148fb5b8e5f616862a2e37"}, - {file = "protobuf-4.21.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:5e0b272217aad8971763960238c1a1e6a65d50ef7824e23300da97569a251c55"}, - {file = "protobuf-4.21.5-cp37-cp37m-win32.whl", hash = "sha256:5eb0724615e90075f1d763983e708e1cef08e66b1891d8b8b6c33bc3b2f1a02b"}, - {file = "protobuf-4.21.5-cp37-cp37m-win_amd64.whl", hash = "sha256:011c0f267e85f5d73750b6c25f0155d5db1e9443cd3590ab669a6221dd8fcdb0"}, - {file = "protobuf-4.21.5-cp38-cp38-win32.whl", hash = "sha256:7b6f22463e2d1053d03058b7b4ceca6e4ed4c14f8c286c32824df751137bf8e7"}, - {file = "protobuf-4.21.5-cp38-cp38-win_amd64.whl", hash = "sha256:b52e7a522911a40445a5f588bd5b5e584291bfc5545e09b7060685e4b2ff814f"}, - {file = "protobuf-4.21.5-cp39-cp39-win32.whl", hash = "sha256:a7faa62b183d6a928e3daffd06af843b4287d16ef6e40f331575ecd236a7974d"}, - {file = "protobuf-4.21.5-cp39-cp39-win_amd64.whl", hash = "sha256:5e0ce02418ef03d7657a420ae8fd6fec4995ac713a3cb09164e95f694dbcf085"}, - {file = "protobuf-4.21.5-py2.py3-none-any.whl", hash = "sha256:bf711b451212dc5b0fa45ae7dada07d8e71a4b0ff0bc8e4783ee145f47ac4f82"}, - {file = "protobuf-4.21.5-py3-none-any.whl", hash = "sha256:3ec6f5b37935406bb9df9b277e79f8ed81d697146e07ef2ba8a5a272fb24b2c9"}, - {file = "protobuf-4.21.5.tar.gz", hash = "sha256:eb1106e87e095628e96884a877a51cdb90087106ee693925ec0a300468a9be3a"}, + {file = "protobuf-4.21.8-cp310-abi3-win32.whl", hash = "sha256:c252c55ee15175aa1b21b7b9896e6add5162d066d5202e75c39f96136f08cce3"}, + {file = "protobuf-4.21.8-cp310-abi3-win_amd64.whl", hash = "sha256:809ca0b225d3df42655a12f311dd0f4148a943c51f1ad63c38343e457492b689"}, + {file = "protobuf-4.21.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bbececaf3cfea9ea65ebb7974e6242d310d2a7772a6f015477e0d79993af4511"}, + {file = "protobuf-4.21.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:b02eabb9ebb1a089ed20626a90ad7a69cee6bcd62c227692466054b19c38dd1f"}, + {file = "protobuf-4.21.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:4761201b93e024bb70ee3a6a6425d61f3152ca851f403ba946fb0cde88872661"}, + {file = "protobuf-4.21.8-cp37-cp37m-win32.whl", hash = "sha256:f2d55ff22ec300c4d954d3b0d1eeb185681ec8ad4fbecff8a5aee6a1cdd345ba"}, + {file = "protobuf-4.21.8-cp37-cp37m-win_amd64.whl", hash = "sha256:c5f94911dd8feb3cd3786fc90f7565c9aba7ce45d0f254afd625b9628f578c3f"}, + {file = "protobuf-4.21.8-cp38-cp38-win32.whl", hash = "sha256:b37b76efe84d539f16cba55ee0036a11ad91300333abd213849cbbbb284b878e"}, + {file = "protobuf-4.21.8-cp38-cp38-win_amd64.whl", hash = "sha256:2c92a7bfcf4ae76a8ac72e545e99a7407e96ffe52934d690eb29a8809ee44d7b"}, + {file = "protobuf-4.21.8-cp39-cp39-win32.whl", hash = "sha256:89d641be4b5061823fa0e463c50a2607a97833e9f8cfb36c2f91ef5ccfcc3861"}, + {file = "protobuf-4.21.8-cp39-cp39-win_amd64.whl", hash = "sha256:bc471cf70a0f53892fdd62f8cd4215f0af8b3f132eeee002c34302dff9edd9b6"}, + {file = "protobuf-4.21.8-py2.py3-none-any.whl", hash = "sha256:a55545ce9eec4030cf100fcb93e861c622d927ef94070c1a3c01922902464278"}, + {file = "protobuf-4.21.8-py3-none-any.whl", hash = "sha256:0f236ce5016becd989bf39bd20761593e6d8298eccd2d878eda33012645dc369"}, + {file = "protobuf-4.21.8.tar.gz", hash = "sha256:427426593b55ff106c84e4a88cac855175330cb6eb7e889e85aaa7b5652b686d"}, ] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, @@ -1640,76 +1679,81 @@ pycparser = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] pydantic = [ - {file = "pydantic-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c9e04a6cdb7a363d7cb3ccf0efea51e0abb48e180c0d31dca8d247967d85c6e"}, - {file = "pydantic-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fafe841be1103f340a24977f61dee76172e4ae5f647ab9e7fd1e1fca51524f08"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afacf6d2a41ed91fc631bade88b1d319c51ab5418870802cedb590b709c5ae3c"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ee0d69b2a5b341fc7927e92cae7ddcfd95e624dfc4870b32a85568bd65e6131"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ff68fc85355532ea77559ede81f35fff79a6a5543477e168ab3a381887caea76"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c0f5e142ef8217019e3eef6ae1b6b55f09a7a15972958d44fbd228214cede567"}, - {file = "pydantic-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:615661bfc37e82ac677543704437ff737418e4ea04bef9cf11c6d27346606044"}, - {file = "pydantic-1.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:328558c9f2eed77bd8fffad3cef39dbbe3edc7044517f4625a769d45d4cf7555"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bd446bdb7755c3a94e56d7bdfd3ee92396070efa8ef3a34fab9579fe6aa1d84"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0b214e57623a535936005797567231a12d0da0c29711eb3514bc2b3cd008d0f"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d8ce3fb0841763a89322ea0432f1f59a2d3feae07a63ea2c958b2315e1ae8adb"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b34ba24f3e2d0b39b43f0ca62008f7ba962cff51efa56e64ee25c4af6eed987b"}, - {file = "pydantic-1.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:84d76ecc908d917f4684b354a39fd885d69dd0491be175f3465fe4b59811c001"}, - {file = "pydantic-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4de71c718c9756d679420c69f216776c2e977459f77e8f679a4a961dc7304a56"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5803ad846cdd1ed0d97eb00292b870c29c1f03732a010e66908ff48a762f20e4"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8c5360a0297a713b4123608a7909e6869e1b56d0e96eb0d792c27585d40757f"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdb4272678db803ddf94caa4f94f8672e9a46bae4a44f167095e4d06fec12979"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19b5686387ea0d1ea52ecc4cffb71abb21702c5e5b2ac626fd4dbaa0834aa49d"}, - {file = "pydantic-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:32e0b4fb13ad4db4058a7c3c80e2569adbd810c25e6ca3bbd8b2a9cc2cc871d7"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91089b2e281713f3893cd01d8e576771cd5bfdfbff5d0ed95969f47ef6d676c3"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e631c70c9280e3129f071635b81207cad85e6c08e253539467e4ead0e5b219aa"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b3946f87e5cef3ba2e7bd3a4eb5a20385fe36521d6cc1ebf3c08a6697c6cfb3"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5565a49effe38d51882cb7bac18bda013cdb34d80ac336428e8908f0b72499b0"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd67cb2c2d9602ad159389c29e4ca964b86fa2f35c2faef54c3eb28b4efd36c8"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4aafd4e55e8ad5bd1b19572ea2df546ccace7945853832bb99422a79c70ce9b8"}, - {file = "pydantic-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:d70916235d478404a3fa8c997b003b5f33aeac4686ac1baa767234a0f8ac2326"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ca86b525264daa5f6b192f216a0d1e860b7383e3da1c65a1908f9c02f42801"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1061c6ee6204f4f5a27133126854948e3b3d51fcc16ead2e5d04378c199b2f44"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e78578f0c7481c850d1c969aca9a65405887003484d24f6110458fb02cca7747"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5da164119602212a3fe7e3bc08911a89db4710ae51444b4224c2382fd09ad453"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ead3cd020d526f75b4188e0a8d71c0dbbe1b4b6b5dc0ea775a93aca16256aeb"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7d0f183b305629765910eaad707800d2f47c6ac5bcfb8c6397abdc30b69eeb15"}, - {file = "pydantic-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1a68f4f65a9ee64b6ccccb5bf7e17db07caebd2730109cb8a95863cfa9c4e55"}, - {file = "pydantic-1.9.2-py3-none-any.whl", hash = "sha256:78a4d6bdfd116a559aeec9a4cfe77dda62acc6233f8b56a716edad2651023e5e"}, - {file = "pydantic-1.9.2.tar.gz", hash = "sha256:8cb0bc509bfb71305d7a59d00163d5f9fc4530f0881ea32c74ff4f74c85f3d3d"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, + {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, + {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, + {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, + {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, + {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, + {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, + {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, + {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, ] pygit2 = [ - {file = "pygit2-1.10.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:493a0ce9cbc580855942cdcb2bf3b674f3295c26233e990bfa98058c321313f1"}, - {file = "pygit2-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:73a5fd0304252c84f5f9f1b5b0eadfa3641a04d11f96d89fbd77ffade52adc37"}, - {file = "pygit2-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f812ec8ea10e83b05a770f4f95808f729bc821e0548af69fd0a80e17876003"}, - {file = "pygit2-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71a6e0866bb033b1dcfc62fedfe44b12dee92f619c6cfed7ca1de6867fba31f9"}, - {file = "pygit2-1.10.0-cp310-cp310-win32.whl", hash = "sha256:9b3b328ad53420a16908a5bba4923d3b26eef27a570802e68c5ed5afb0eca0f3"}, - {file = "pygit2-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:21021a48aa2151e5f0504d56099a194cffc0fede688703f8d0764edf186d802b"}, - {file = "pygit2-1.10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5717cd2fd1a0d23a2bbdf8ce4271aa72e1d283d258c88b341d9d9c4673707e73"}, - {file = "pygit2-1.10.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0c4506581e816e2357adf4e9b642de8b386778cbf09bd870a9843ef9c9a5379"}, - {file = "pygit2-1.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c514d6d9b051f2f5f0d8e277ccefda3380bfbf38047e12c92f8e3f110d27314"}, - {file = "pygit2-1.10.0-cp37-cp37m-win32.whl", hash = "sha256:2a23e157251a77f2cfd944ae119a730ef5fa66132eb15119b01b016650a1dbae"}, - {file = "pygit2-1.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c380f0a8c669aeaf71d9d73f8de16502dc050a6022f0571c77bd5efecf88492c"}, - {file = "pygit2-1.10.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a0f30d90e52a664a8b1a6ae30067e503a576fc53d40c6a1bc533dc67a70b1410"}, - {file = "pygit2-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9308e78f83e46c95db59128161a5dfe5f6a1652342238224142474d41a0d7011"}, - {file = "pygit2-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e64db8ec4ee0aaf6e726fa4655ea9cbde7a7f2cf34f134f25f6faa52a27d618"}, - {file = "pygit2-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f702aacea8ace3422e02ac20161a4f1afcf13bd0d20edd18726ff386165bbb"}, - {file = "pygit2-1.10.0-cp38-cp38-win32.whl", hash = "sha256:e86bc4c74c40fb46156158c1dd774c1f0e50ee3a860af4131ce2ac1dfff4fc34"}, - {file = "pygit2-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:f1785ba78690b06581694b2e898b68cd1bc344417475c0b994d574b0d2010160"}, - {file = "pygit2-1.10.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e9d7db4fe6ddf8f7ab29c6a24a8a9bd0af92a214ad0e812b49eb7c411cddf3e"}, - {file = "pygit2-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56d44a3437a6d642c98a33830d8e3d2556e608abba412e451fec514702fa9a76"}, - {file = "pygit2-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8eb687e4bf7b46ca545f50eb25c5e9c41a86be59ae51e83ce42f7793658b560"}, - {file = "pygit2-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71e084dd1c075c0ca3f4b8015ce3cc2dd73fc1c0ead52b6a79990ec5ab7f67d9"}, - {file = "pygit2-1.10.0-cp39-cp39-win32.whl", hash = "sha256:e1f4d7e981c9240912cd587e9b5f1d00a03b79248fcf15add5e3944d11d21884"}, - {file = "pygit2-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2ee457af2d6ca47838d5ddd0c558af829e7db8d1402f61e4695024d3ce54301d"}, - {file = "pygit2-1.10.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:55f05d86b5d635f98816183b1eadbc0349dc26451a58b1920051b2f7593b9d0a"}, - {file = "pygit2-1.10.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd17ebbbcf5c7f10e2dfbd2b7b6abdf5686069a0a1a84c72c1c6bf17c26c72dd"}, - {file = "pygit2-1.10.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2098086b479b6b744d5fb2822fd2d01d14d05ac84c34d911c46b609bd5435c18"}, - {file = "pygit2-1.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:01b66a9de0a753ccd2e835b8598f119bccb587bcde9f78adc24a73ead456b083"}, - {file = "pygit2-1.10.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ca00acb3d117d736d9dc1144092fdb899f95e1b1aba6d2c3b6df58b80b24dfb"}, - {file = "pygit2-1.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c61db929b4bc52796f22516199ae697a594bbc205e97275f61365c0225ac1130"}, - {file = "pygit2-1.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:33cf14c6188e6494231547e581790e73e66114b5d5e6ef8617487b8a5e13e987"}, - {file = "pygit2-1.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23de3170eb76bcaa207fe23caea939bdfefeabdefc3f09191acf0d0b461ce87b"}, - {file = "pygit2-1.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a70e219feee75b18cfc78bd2cee755760be8ec4bedd40aa10d6cd257567a44a"}, - {file = "pygit2-1.10.0.tar.gz", hash = "sha256:7c751eee88c731b922e4e487ee287e2e40906b2bd32d0bfd2105947f63e867de"}, + {file = "pygit2-1.10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e3f60e47c6a7a87f18a112753eb98848f4c5333986bec1940558ce09cdaf53bf"}, + {file = "pygit2-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f0f69ea42231bebf08006c85cd5aa233c9c047c5a88b7fcfb4b639476b70e31b"}, + {file = "pygit2-1.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0097b6631ef05c837c4800fad559d0865a90c55475a18f38c6f2f5a12750e914"}, + {file = "pygit2-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb3b5bdcdfae205d9cc0c80bc53fad222a5ba67e66fd336ef223f86b0ac5835"}, + {file = "pygit2-1.10.1-cp310-cp310-win32.whl", hash = "sha256:3efd2a2ab2bb443e1b758525546d74a5a12fe27006194d3c02b3e6ecc1e101e6"}, + {file = "pygit2-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:11225811194ae6b9dbb34c2e8900e0eba6eacc180d82766e3dbddcbd2c6e6454"}, + {file = "pygit2-1.10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:73e251d0b73f1010ad28c20bcdcf33e312fb363f10b7268ad2bcfa09770f9ac2"}, + {file = "pygit2-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cb73f7967207a9ac485722ef0e517e5ca482f3c1308a0ac934707cb267b0ac7a"}, + {file = "pygit2-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b115bef251af4daf18f2f967287b56da2eae2941d5389dc1666bd0160892d769"}, + {file = "pygit2-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd55a6cf7ad6276fb5772e5c60c51fca2d9a5e68ea3e7237847421c10080a68"}, + {file = "pygit2-1.10.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:33138c256ad0ff084f5d8a82ab7d280f9ed6706ebb000ac82e3d133e2d82b366"}, + {file = "pygit2-1.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f4f507e5cd775f6d5d95ec65761af4cdb33b2f859af15bf10a06d11efd0d3b2"}, + {file = "pygit2-1.10.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:752f844d5379081fae5ef78e3bf6f0f35ae9b11aafc37e5e03e1c3607b196806"}, + {file = "pygit2-1.10.1-cp37-cp37m-win32.whl", hash = "sha256:b31ffdbc87629613ae03a533e01eee79112a12f66faf375fa08934074044a664"}, + {file = "pygit2-1.10.1-cp37-cp37m-win_amd64.whl", hash = "sha256:e09386b71ad474f2c2c02b6b251fa904b1145dabfe9095955ab30a789aaf84c0"}, + {file = "pygit2-1.10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:564e832e750f889aea3bb3e82674e1c860c9b89a141404530271e1341723a258"}, + {file = "pygit2-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43bb910272866eb822e930dbd0feecc340e0c24934143aab651fa180cc5ebfb0"}, + {file = "pygit2-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e4905cbb87db598b1cb38800ff995c0ba1f58745e2f52af4d54dbc93b9bda8"}, + {file = "pygit2-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb1f4689ce38cd62a7000d38602ba4d704df5cec708e5d98dadaffcf510f3317"}, + {file = "pygit2-1.10.1-cp38-cp38-win32.whl", hash = "sha256:b67ef30f3c022be1d6da9ef0188f60fc2d20639bff44693ef5653818e887001b"}, + {file = "pygit2-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:dcd849c44bd743d829dbd9dc9d7e13c14cf31a47c22e2e3f9e98fa845a8b8b28"}, + {file = "pygit2-1.10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e8bb9002924975271d64e8869b44ea97f068e85b5edd03e802e4917b770aaf2d"}, + {file = "pygit2-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:889ca83528c0649afd970da700cc6ed47dc340481f146a39ba5bfbeca1ddd6f8"}, + {file = "pygit2-1.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5465db21c6fd481ec29aa7afcca9a85b1fdb19b2f2d09a31b4bdba2f1bd0e75"}, + {file = "pygit2-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ceecd5d30583f9db56aadcd7238bb3c76a2934d8a932de47aed77fe3c188e7"}, + {file = "pygit2-1.10.1-cp39-cp39-win32.whl", hash = "sha256:9d6e1270b91e7bf70185bb4c3686e04cca87a385c8a2d5c74eec8770091531be"}, + {file = "pygit2-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:d4251830276018c2346ddccad4b4ce06ed1d983b002a633c4d894b13669052d0"}, + {file = "pygit2-1.10.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7eb2cee54a1cb468b5502493ee4f3ec2f1f82db9c46fab7dacaa37afc4fcde8e"}, + {file = "pygit2-1.10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:411dc8af5f25c30a0c3d79ee1e22fb892d6fd6ccb54d4c1fb7746e6274e36426"}, + {file = "pygit2-1.10.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe41da630f4e7cb290dc7e97edf30a59d634426af52a89d4ab5c0fb1ea9ccfe4"}, + {file = "pygit2-1.10.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9da53c6f5c08308450059d7dfb3067d59c45f14bee99743e536c5f9d9823f154"}, + {file = "pygit2-1.10.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb49f9469a893f75f105cdf2c79254859aaf2fdce1078c38514ca12fe185a759"}, + {file = "pygit2-1.10.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff838665d6410b5a605f53c1ccd2d2f87ca30de59e89773e7cb5e10211426f90"}, + {file = "pygit2-1.10.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9d23bb613f5692da78c09a79ae40d6ced57b772ae9153aed23a9aa1889a16c85"}, + {file = "pygit2-1.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3a3cc867fa6907bfc78d7d1322f3dabd4107b16238205df7e2dec9ee265f0c0"}, + {file = "pygit2-1.10.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb3eb2f1d437db6e115d5f56d122f2f3737fa2e6063aa42e4d856ca76d785ce6"}, + {file = "pygit2-1.10.1.tar.gz", hash = "sha256:354651bf062c02d1f08041d6fbf1a9b4bf7a93afce65979bdc08bdc65653aa2e"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, @@ -1720,12 +1764,12 @@ pytest = [ {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, - {file = "pytest_asyncio-0.19.0-py3-none-any.whl", hash = "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa"}, + {file = "pytest-asyncio-0.20.1.tar.gz", hash = "sha256:626699de2a747611f3eeb64168b3575f70439b06c3d0206e6ceaeeb956e65519"}, + {file = "pytest_asyncio-0.20.1-py3-none-any.whl", hash = "sha256:2c85a835df33fda40fe3973b451e0c194ca11bc2c007eabff90bb3d156fc172b"}, ] pytest-cov = [ - {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, - {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, ] pytest-forked = [ {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, @@ -1758,65 +1802,74 @@ rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, ] +setuptools = [ + {file = "setuptools-65.5.0-py3-none-any.whl", hash = "sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356"}, + {file = "setuptools-65.5.0.tar.gz", hash = "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17"}, +] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] sniffio = [ - {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, - {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] sortedcontainers = [ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] sqlalchemy = [ - {file = "SQLAlchemy-1.4.40-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:b07fc38e6392a65935dc8b486229679142b2ea33c94059366b4d8b56f1e35a97"}, - {file = "SQLAlchemy-1.4.40-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fb4edb6c354eac0fcc07cb91797e142f702532dbb16c1d62839d6eec35f814cf"}, - {file = "SQLAlchemy-1.4.40-cp27-cp27m-win32.whl", hash = "sha256:2026632051a93997cf8f6fda14360f99230be1725b7ab2ef15be205a4b8a5430"}, - {file = "SQLAlchemy-1.4.40-cp27-cp27m-win_amd64.whl", hash = "sha256:f2aa85aebc0ef6b342d5d3542f969caa8c6a63c8d36cf5098769158a9fa2123c"}, - {file = "SQLAlchemy-1.4.40-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0b9e3d81f86ba04007f0349e373a5b8c81ec2047aadb8d669caf8c54a092461"}, - {file = "SQLAlchemy-1.4.40-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:1ab08141d93de83559f6a7d9a962830f918623a885b3759ec2b9d1a531ff28fe"}, - {file = "SQLAlchemy-1.4.40-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00dd998b43b282c71de46b061627b5edb9332510eb1edfc5017b9e4356ed44ea"}, - {file = "SQLAlchemy-1.4.40-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb342c0e25cc8f78a0e7c692da3b984f072666b316fbbec2a0e371cb4dfef5f0"}, - {file = "SQLAlchemy-1.4.40-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23b693876ac7963b6bc7b1a5f3a2642f38d2624af834faad5933913928089d1b"}, - {file = "SQLAlchemy-1.4.40-cp310-cp310-win32.whl", hash = "sha256:2cf50611ef4221ad587fb7a1708e61ff72966f84330c6317642e08d6db4138fd"}, - {file = "SQLAlchemy-1.4.40-cp310-cp310-win_amd64.whl", hash = "sha256:26ee4dbac5dd7abf18bf3cd8f04e51f72c339caf702f68172d308888cd26c6c9"}, - {file = "SQLAlchemy-1.4.40-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b41b87b929118838bafc4bb18cf3c5cd1b3be4b61cd9042e75174df79e8ac7a2"}, - {file = "SQLAlchemy-1.4.40-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:885e11638946472b4a0a7db8e6df604b2cf64d23dc40eedc3806d869fcb18fae"}, - {file = "SQLAlchemy-1.4.40-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b7ff0a8bf0aec1908b92b8dfa1246128bf4f94adbdd3da6730e9c542e112542d"}, - {file = "SQLAlchemy-1.4.40-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfa8ab4ba0c97ab6bcae1f0948497d14c11b6c6ecd1b32b8a79546a0823d8211"}, - {file = "SQLAlchemy-1.4.40-cp36-cp36m-win32.whl", hash = "sha256:d259fa08e4b3ed952c01711268bcf6cd2442b0c54866d64aece122f83da77c6d"}, - {file = "SQLAlchemy-1.4.40-cp36-cp36m-win_amd64.whl", hash = "sha256:c8d974c991eef0cd29418a5957ae544559dc326685a6f26b3a914c87759bf2f4"}, - {file = "SQLAlchemy-1.4.40-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:28b1791a30d62fc104070965f1a2866699c45bbf5adc0be0cf5f22935edcac58"}, - {file = "SQLAlchemy-1.4.40-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7ccdca6cd167611f4a62a8c2c0c4285c2535640d77108f782ce3f3cccb70f3a"}, - {file = "SQLAlchemy-1.4.40-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:69deec3a94de10062080d91e1ba69595efeafeafe68b996426dec9720031fb25"}, - {file = "SQLAlchemy-1.4.40-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ad778f4e80913fb171247e4fa82123d0068615ae1d51a9791fc4284cb81748"}, - {file = "SQLAlchemy-1.4.40-cp37-cp37m-win32.whl", hash = "sha256:9ced2450c9fd016f9232d976661623e54c450679eeefc7aa48a3d29924a63189"}, - {file = "SQLAlchemy-1.4.40-cp37-cp37m-win_amd64.whl", hash = "sha256:cdee4d475e35684d210dc6b430ff8ca2ed0636378ac19b457e2f6f350d1f5acc"}, - {file = "SQLAlchemy-1.4.40-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:08b47c971327e733ffd6bae2d4f50a7b761793efe69d41067fcba86282819eea"}, - {file = "SQLAlchemy-1.4.40-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf03d37819dc17a388d313919daf32058d19ba1e592efdf14ce8cbd997e6023"}, - {file = "SQLAlchemy-1.4.40-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a62c0ecbb9976550f26f7bf75569f425e661e7249349487f1483115e5fc893a6"}, - {file = "SQLAlchemy-1.4.40-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ec440990ab00650d0c7ea2c75bc225087afdd7ddcb248e3d934def4dff62762"}, - {file = "SQLAlchemy-1.4.40-cp38-cp38-win32.whl", hash = "sha256:2b64955850a14b9d481c17becf0d3f62fb1bb31ac2c45c2caf5ad06d9e811187"}, - {file = "SQLAlchemy-1.4.40-cp38-cp38-win_amd64.whl", hash = "sha256:959bf4390766a8696aa01285016c766b4eb676f712878aac5fce956dd49695d9"}, - {file = "SQLAlchemy-1.4.40-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:0992f3cc640ec0f88f721e426da884c34ff0a60eb73d3d64172e23dfadfc8a0b"}, - {file = "SQLAlchemy-1.4.40-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa9e0d7832b7511b3b3fd0e67fac85ff11fd752834c143ca2364c9b778c0485a"}, - {file = "SQLAlchemy-1.4.40-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9d0f1a9538cc5e75f2ea0cb6c3d70155a1b7f18092c052e0d84105622a41b63"}, - {file = "SQLAlchemy-1.4.40-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c956a5d1adb49a35d78ef0fae26717afc48a36262359bb5b0cbd7a3a247c26f"}, - {file = "SQLAlchemy-1.4.40-cp39-cp39-win32.whl", hash = "sha256:6b70d02bbe1adbbf715d2249cacf9ac17c6f8d22dfcb3f1a4fbc5bf64364da8a"}, - {file = "SQLAlchemy-1.4.40-cp39-cp39-win_amd64.whl", hash = "sha256:bf073c619b5a7f7cd731507d0fdc7329bee14b247a63b0419929e4acd24afea8"}, - {file = "SQLAlchemy-1.4.40.tar.gz", hash = "sha256:44a660506080cc975e1dfa5776fe5f6315ddc626a77b50bf0eee18b0389ea265"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27m-win32.whl", hash = "sha256:1d0c23ecf7b3bc81e29459c34a3f4c68ca538de01254e24718a7926810dc39a6"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27m-win_amd64.whl", hash = "sha256:6c9d004eb78c71dd4d3ce625b80c96a827d2e67af9c0d32b1c1e75992a7916cc"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9e3a65ce9ed250b2f096f7b559fe3ee92e6605fab3099b661f0397a9ac7c8d95"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:2e56dfed0cc3e57b2f5c35719d64f4682ef26836b81067ee6cfad062290fd9e2"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b42c59ffd2d625b28cdb2ae4cde8488543d428cba17ff672a543062f7caee525"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22459fc1718785d8a86171bbe7f01b5c9d7297301ac150f508d06e62a2b4e8d2"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df76e9c60879fdc785a34a82bf1e8691716ffac32e7790d31a98d7dec6e81545"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-win32.whl", hash = "sha256:e7e740453f0149437c101ea4fdc7eea2689938c5760d7dcc436c863a12f1f565"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-win_amd64.whl", hash = "sha256:effc89e606165ca55f04f3f24b86d3e1c605e534bf1a96e4e077ce1b027d0b71"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:97ff50cd85bb907c2a14afb50157d0d5486a4b4639976b4a3346f34b6d1b5272"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12c6949bae10f1012ab5c0ea52ab8db99adcb8c7b717938252137cdf694c775"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11b2ec26c5d2eefbc3e6dca4ec3d3d95028be62320b96d687b6e740424f83b7d"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-win32.whl", hash = "sha256:6045b3089195bc008aee5c273ec3ba9a93f6a55bc1b288841bd4cfac729b6516"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-win_amd64.whl", hash = "sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6e39e97102f8e26c6c8550cb368c724028c575ec8bc71afbbf8faaffe2b2092a"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15d878929c30e41fb3d757a5853b680a561974a0168cd33a750be4ab93181628"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fa5b7eb2051e857bf83bade0641628efe5a88de189390725d3e6033a1fff4257"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1c5f8182b4f89628d782a183d44db51b5af84abd6ce17ebb9804355c88a7b5"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-win32.whl", hash = "sha256:a7dd5b7b34a8ba8d181402d824b87c5cee8963cb2e23aa03dbfe8b1f1e417cde"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-win_amd64.whl", hash = "sha256:5ede1495174e69e273fad68ad45b6d25c135c1ce67723e40f6cf536cb515e20b"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:9256563506e040daddccaa948d055e006e971771768df3bb01feeb4386c242b0"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4948b6c5f4e56693bbeff52f574279e4ff972ea3353f45967a14c30fb7ae2beb"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1811a0b19a08af7750c0b69e38dec3d46e47c4ec1d74b6184d69f12e1c99a5e0"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b01d9cd2f9096f688c71a3d0f33f3cd0af8549014e66a7a7dee6fc214a7277d"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-win32.whl", hash = "sha256:bd448b262544b47a2766c34c0364de830f7fb0772d9959c1c42ad61d91ab6565"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-win_amd64.whl", hash = "sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3ab7c158f98de6cb4f1faab2d12973b330c2878d0c6b689a8ca424c02d66e1b3"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:934472bb7d8666727746a75670a1f8d91a9cae8c464bba79da30a0f6faccd9e1"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb94a3d1ba77ff2ef11912192c066f01e68416f554c194d769391638c8ad09a"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-win32.whl", hash = "sha256:f0f574465b78f29f533976c06b913e54ab4980b9931b69aa9d306afff13a9471"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-win_amd64.whl", hash = "sha256:a85723c00a636eed863adb11f1e8aaa36ad1c10089537823b4540948a8429798"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5ce6929417d5dce5ad1d3f147db81735a4a0573b8fb36e3f95500a06eaddd93e"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723e3b9374c1ce1b53564c863d1a6b2f1dc4e97b1c178d9b643b191d8b1be738"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:876eb185911c8b95342b50a8c4435e1c625944b698a5b4a978ad2ffe74502908"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd49af453e590884d9cdad3586415922a8e9bb669d874ee1dc55d2bc425aacd"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-win32.whl", hash = "sha256:e4ef8cb3c5b326f839bfeb6af5f406ba02ad69a78c7aac0fbeeba994ad9bb48a"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-win_amd64.whl", hash = "sha256:5f966b64c852592469a7eb759615bbd351571340b8b344f1d3fa2478b5a4c934"}, + {file = "SQLAlchemy-1.4.42.tar.gz", hash = "sha256:177e41914c476ed1e1b77fd05966ea88c094053e17a85303c4ce007f88eff363"}, ] srcinfo = [ {file = "srcinfo-0.0.8-py3-none-any.whl", hash = "sha256:0922ee4302b927d7ddea74c47e539b226a0a7738dc89f95b66404a28d07f3f6b"}, {file = "srcinfo-0.0.8.tar.gz", hash = "sha256:5ac610cf8b15d4b0a0374bd1f7ad301675c2938f0414addf3ef7d7e3fcaf5c65"}, ] starlette = [ - {file = "starlette-0.19.1-py3-none-any.whl", hash = "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf"}, - {file = "starlette-0.19.1.tar.gz", hash = "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7"}, + {file = "starlette-0.20.4-py3-none-any.whl", hash = "sha256:c0414d5a56297d37f3db96a84034d61ce29889b9eaccf65eb98a0b39441fcaa3"}, + {file = "starlette-0.20.4.tar.gz", hash = "sha256:42fcf3122f998fefce3e2c5ad7e5edbf0f02cf685d646a83a08d404726af5084"}, ] -"tap.py" = [ +tap-py = [ {file = "tap.py-3.1-py3-none-any.whl", hash = "sha256:928c852f3361707b796c93730cc5402c6378660b161114461066acf53d65bf5d"}, {file = "tap.py-3.1.tar.gz", hash = "sha256:3c0cd45212ad5a25b35445964e2517efa000a118a1bfc3437dae828892eaf1e1"}, ] @@ -1829,16 +1882,16 @@ tomli = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] typing-extensions = [ - {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, - {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, ] urllib3 = [ - {file = "urllib3-1.26.11-py2.py3-none-any.whl", hash = "sha256:c33ccba33c819596124764c23a97d25f32b28433ba0dedeb77d873a38722c9bc"}, - {file = "urllib3-1.26.11.tar.gz", hash = "sha256:ea6e8fb210b19d950fab93b60c9009226c63a28808bc8386e05301e25883ac0a"}, + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, ] uvicorn = [ - {file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"}, - {file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"}, + {file = "uvicorn-0.19.0-py3-none-any.whl", hash = "sha256:cc277f7e73435748e69e075a721841f7c4a95dba06d12a72fe9874acced16f6f"}, + {file = "uvicorn-0.19.0.tar.gz", hash = "sha256:cf538f3018536edb1f4a826311137ab4944ed741d52aeb98846f52215de57f25"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, @@ -1915,10 +1968,10 @@ wrapt = [ {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, ] wsproto = [ - {file = "wsproto-1.1.0-py3-none-any.whl", hash = "sha256:2218cb57952d90b9fca325c0dcfb08c3bda93e8fd8070b0a17f048e2e47a521b"}, - {file = "wsproto-1.1.0.tar.gz", hash = "sha256:a2e56bfd5c7cd83c1369d83b5feccd6d37798b74872866e62616e0ecf111bda8"}, + {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, + {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, ] zipp = [ - {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, - {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, + {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, + {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, ] diff --git a/pyproject.toml b/pyproject.toml index fea2f922..3b615c73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ aiofiles = "^22.0.0" asgiref = "^3.4.1" bcrypt = "^4.0.0" bleach = "^5.0.0" -email-validator = "1.2.1" +email-validator = "^1.3.0" fakeredis = "^1.6.1" feedgen = "^0.9.0" httpx = "^0.23.0" @@ -85,7 +85,7 @@ Werkzeug = "^2.0.2" SQLAlchemy = "^1.4.26" # ASGI -uvicorn = "^0.18.0" +uvicorn = "^0.19.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.0" prometheus-fastapi-instrumentator = "^5.7.1" @@ -93,14 +93,14 @@ pytest-xdist = "^2.4.0" filelock = "^3.3.2" posix-ipc = "^1.0.5" pyalpm = "^0.10.6" -fastapi = "^0.83.0" +fastapi = "^0.85.1" srcinfo = "^0.0.8" [tool.poetry.dev-dependencies] coverage = "^6.0.2" pytest = "^7.0.0" -pytest-asyncio = "^0.19.0" -pytest-cov = "^3.0.0" +pytest-asyncio = "^0.20.1" +pytest-cov = "^4.0.0" pytest-tap = "^3.2" [tool.poetry.scripts] From 524334409a1744e8caf6fb4b2f0d42ec189bca27 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 22 Oct 2022 21:58:30 +0100 Subject: [PATCH 1612/1891] fix: add production logging.prod.conf to be less verbose Signed-off-by: Leonidas Spyropoulos --- logging.prod.conf | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 logging.prod.conf diff --git a/logging.prod.conf b/logging.prod.conf new file mode 100644 index 00000000..63692a28 --- /dev/null +++ b/logging.prod.conf @@ -0,0 +1,58 @@ +[loggers] +keys=root,aurweb,uvicorn,hypercorn,alembic + +[handlers] +keys=simpleHandler,detailedHandler + +[formatters] +keys=simpleFormatter,detailedFormatter + +[logger_root] +level=INFO +; We add NullHandler programmatically. +handlers= +propogate=0 + +[logger_aurweb] +level=INFO +handlers=simpleHandler +qualname=aurweb +propagate=1 + +[logger_uvicorn] +level=WARN +handlers=simpleHandler +qualname=uvicorn +propagate=0 + +[logger_hypercorn] +level=WARN +handlers=simpleHandler +qualname=hypercorn +propagate=0 + +[logger_alembic] +level=WARN +handlers=simpleHandler +qualname=alembic +propagate=0 + +[handler_simpleHandler] +class=StreamHandler +level=INFO +formatter=simpleFormatter +args=(sys.stdout,) + +[handler_detailedHandler] +class=StreamHandler +level=DEBUG +formatter=detailedFormatter +args=(sys.stdout,) + +[formatter_simpleFormatter] +format=%(asctime)s %(levelname)-8s | %(name)s @ (%(filename)s:%(lineno)d): %(message)s +datefmt=%H:%M:%S + +[formatter_detailedFormatter] +format=%(asctime)s %(levelname)-8s | [%(name)s.%(funcName)s() @ %(filename)s:%(lineno)d]: %(message)s +datefmt=%H:%M:%S From 3dcbee5a4f035777b5b65d124bc3c46240b661c8 Mon Sep 17 00:00:00 2001 From: Mario Oenning Date: Fri, 28 Oct 2022 12:42:50 +0000 Subject: [PATCH 1613/1891] fix: make overwriting of archive files atomic --- aurweb/scripts/mkpkglists.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index e74bbf25..67cc7fab 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -24,7 +24,6 @@ import io import os import shutil import sys -import tempfile from collections import defaultdict from typing import Any @@ -219,10 +218,9 @@ def _main(): output = list() snapshot_uri = aurweb.config.get("options", "snapshot_uri") - tmpdir = tempfile.mkdtemp() - tmp_packages = os.path.join(tmpdir, os.path.basename(PACKAGES)) - tmp_meta = os.path.join(tmpdir, os.path.basename(META)) - tmp_metaext = os.path.join(tmpdir, os.path.basename(META_EXT)) + tmp_packages = f"{PACKAGES}.tmp" + tmp_meta = f"{META}.tmp" + tmp_metaext = f"{META_EXT}.tmp" gzips = { "packages": gzip.open(tmp_packages, "wt"), "meta": gzip.open(tmp_meta, "wb"), @@ -276,13 +274,13 @@ def _main(): # Produce pkgbase.gz query = db.query(PackageBase.Name).filter(PackageBase.PackagerUID.isnot(None)).all() - tmp_pkgbase = os.path.join(tmpdir, os.path.basename(PKGBASE)) + tmp_pkgbase = f"{PKGBASE}.tmp" with gzip.open(tmp_pkgbase, "wt") as f: f.writelines([f"{base.Name}\n" for i, base in enumerate(query)]) # Produce users.gz query = db.query(User.Username).all() - tmp_users = os.path.join(tmpdir, os.path.basename(USERS)) + tmp_users = f"{USERS}.tmp" with gzip.open(tmp_users, "wt") as f: f.writelines([f"{user.Username}\n" for i, user in enumerate(query)]) @@ -297,7 +295,7 @@ def _main(): for src, dst in files: checksum = sha256sum(src) - base = os.path.basename(src) + base = os.path.basename(dst) checksum_formatted = f"SHA256 ({base}) = {checksum}" checksum_file = f"{dst}.sha256" @@ -307,7 +305,6 @@ def _main(): # Move the new archive into its rightful place. shutil.move(src, dst) - os.removedirs(tmpdir) seconds = filters.number_format(bench.end(), 4) logger.info(f"Completed in {seconds} seconds.") From d793193fdfc9d8369a89a932b5dc719ab1153985 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 27 Oct 2022 15:11:37 +0100 Subject: [PATCH 1614/1891] style: make logging easier to read Signed-off-by: Leonidas Spyropoulos --- logging.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logging.conf b/logging.conf index 7dfd30f0..d27b0153 100644 --- a/logging.conf +++ b/logging.conf @@ -50,9 +50,9 @@ formatter=detailedFormatter args=(sys.stdout,) [formatter_simpleFormatter] -format=%(asctime)s %(levelname)-5s | %(name)s: %(message)s +format=%(asctime)s %(levelname)-8s | %(name)s @ (%(filename)s:%(lineno)d): %(message)s datefmt=%H:%M:%S [formatter_detailedFormatter] -format=%(asctime)s %(levelname)-5s | %(name)s.%(funcName)s() @ L%(lineno)d: %(message)s +format=%(asctime)s %(levelname)-8s | [%(name)s.%(funcName)s() @ %(filename)s:%(lineno)d]: %(message)s datefmt=%H:%M:%S From 7e06823e580942cc11b8164a559386e766d94470 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 27 Oct 2022 15:34:52 +0100 Subject: [PATCH 1615/1891] refactor: remove redundand parenthesis when return tuple Signed-off-by: Leonidas Spyropoulos --- aurweb/auth/__init__.py | 2 +- aurweb/git/update.py | 2 +- aurweb/packages/util.py | 6 +++--- aurweb/routers/accounts.py | 4 ++-- aurweb/routers/packages.py | 30 +++++++++++++++--------------- aurweb/scripts/rendercomment.py | 6 +++--- aurweb/util.py | 6 +++--- test/test_packages_routes.py | 4 ++-- test/test_pkgbase_routes.py | 4 ++-- test/test_spawn.py | 2 +- test/test_tuvotereminder.py | 2 +- 11 files changed, 34 insertions(+), 34 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index b8056f91..5a1fc8d0 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -127,7 +127,7 @@ class BasicAuthBackend(AuthenticationBackend): user.nonce = util.make_nonce() user.authenticated = True - return (AuthCredentials(["authenticated"]), user) + return AuthCredentials(["authenticated"]), user def _auth_required(auth_goal: bool = True): diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 94a8d623..b1256fdb 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -52,7 +52,7 @@ def parse_dep(depstring): depname = re.sub(r"(<|=|>).*", "", dep) depcond = dep[len(depname) :] - return (depname, desc, depcond) + return depname, desc, depcond def create_pkgbase(conn, pkgbase, user): diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index cddec0ac..25671028 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -239,12 +239,12 @@ def source_uri(pkgsrc: models.PackageSource) -> Tuple[str, str]: the package base name. :param pkgsrc: PackageSource instance - :return (text, uri) tuple + :return text, uri)tuple """ if "::" in pkgsrc.Source: return pkgsrc.Source.split("::", 1) elif "://" in pkgsrc.Source: - return (pkgsrc.Source, pkgsrc.Source) + return pkgsrc.Source, pkgsrc.Source path = config.get("options", "source_file_uri") pkgbasename = pkgsrc.Package.PackageBase.Name - return (pkgsrc.Source, path % (pkgsrc.Source, pkgbasename)) + return pkgsrc.Source, path % (pkgsrc.Source, pkgbasename) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 24aacdf7..07962c37 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -160,9 +160,9 @@ def process_account_form(request: Request, user: models.User, args: dict[str, An for check in checks: check(**args, request=request, user=user, _=_) except ValidationError as exc: - return (False, exc.data) + return False, exc.data - return (True, []) + return True, [] def make_account_form_context( diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 0d482521..a4aac496 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -213,7 +213,7 @@ async def package( async def packages_unflag(request: Request, package_ids: list[int] = [], **kwargs): if not package_ids: - return (False, ["You did not select any packages to unflag."]) + return False, ["You did not select any packages to unflag."] # Holds the set of package bases we're looking to unflag. # Constructed below via looping through the packages query. @@ -226,14 +226,14 @@ async def packages_unflag(request: Request, package_ids: list[int] = [], **kwarg creds.PKGBASE_UNFLAG, approved=[pkg.PackageBase.Flagger] ) if not has_cred: - return (False, ["You did not select any packages to unflag."]) + return False, ["You did not select any packages to unflag."] if pkg.PackageBase not in bases: bases.update({pkg.PackageBase}) for pkgbase in bases: pkgbase_actions.pkgbase_unflag_instance(request, pkgbase) - return (True, ["The selected packages have been unflagged."]) + return True, ["The selected packages have been unflagged."] async def packages_notify(request: Request, package_ids: list[int] = [], **kwargs): @@ -271,13 +271,13 @@ async def packages_notify(request: Request, package_ids: list[int] = [], **kwarg pkgbase_actions.pkgbase_notify_instance(request, pkgbase) # TODO: This message does not yet have a translation. - return (True, ["The selected packages' notifications have been enabled."]) + return True, ["The selected packages' notifications have been enabled."] async def packages_unnotify(request: Request, package_ids: list[int] = [], **kwargs): if not package_ids: # TODO: This error does not yet have a translation. - return (False, ["You did not select any packages for notification removal."]) + return False, ["You did not select any packages for notification removal."] # TODO: This error does not yet have a translation. error_tuple = ( @@ -307,14 +307,14 @@ async def packages_unnotify(request: Request, package_ids: list[int] = [], **kwa pkgbase_actions.pkgbase_unnotify_instance(request, pkgbase) # TODO: This message does not yet have a translation. - return (True, ["The selected packages' notifications have been removed."]) + return True, ["The selected packages' notifications have been removed."] async def packages_adopt( request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs ): if not package_ids: - return (False, ["You did not select any packages to adopt."]) + return False, ["You did not select any packages to adopt."] if not confirm: return ( @@ -347,7 +347,7 @@ async def packages_adopt( for pkgbase in bases: pkgbase_actions.pkgbase_adopt_instance(request, pkgbase) - return (True, ["The selected packages have been adopted."]) + return True, ["The selected packages have been adopted."] def disown_all(request: Request, pkgbases: list[models.PackageBase]) -> list[str]: @@ -364,7 +364,7 @@ async def packages_disown( request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs ): if not package_ids: - return (False, ["You did not select any packages to disown."]) + return False, ["You did not select any packages to disown."] if not confirm: return ( @@ -397,9 +397,9 @@ async def packages_disown( # Now, disown all the bases if we can. if errors := disown_all(request, bases): - return (False, errors) + return False, errors - return (True, ["The selected packages have been disowned."]) + return True, ["The selected packages have been disowned."] async def packages_delete( @@ -410,7 +410,7 @@ async def packages_delete( **kwargs, ): if not package_ids: - return (False, ["You did not select any packages to delete."]) + return False, ["You did not select any packages to delete."] if not confirm: return ( @@ -422,7 +422,7 @@ async def packages_delete( ) if not request.user.has_credential(creds.PKGBASE_DELETE): - return (False, ["You do not have permission to delete packages."]) + return False, ["You do not have permission to delete packages."] # set-ify package_ids and query the database for related records. package_ids = set(package_ids) @@ -432,7 +432,7 @@ async def packages_delete( # Let the user know there was an issue with their input: they have # provided at least one package_id which does not exist in the DB. # TODO: This error has not yet been translated. - return (False, ["One of the packages you selected does not exist."]) + return False, ["One of the packages you selected does not exist."] # Make a set out of all package bases related to `packages`. bases = {pkg.PackageBase for pkg in packages} @@ -448,7 +448,7 @@ async def packages_delete( ) util.apply_all(notifs, lambda n: n.send()) - return (True, ["The selected packages have been deleted."]) + return True, ["The selected packages have been deleted."] # A mapping of action string -> callback functions used within the diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index 4a2c84bd..643b0370 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -46,7 +46,7 @@ class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor): el = Element("a") el.set("href", f"https://bugs.archlinux.org/task/{m.group(1)}") el.text = markdown.util.AtomicString(m.group(0)) - return (el, m.start(0), m.end(0)) + return el, m.start(0), m.end(0) class FlysprayLinksExtension(markdown.extensions.Extension): @@ -74,7 +74,7 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): oid = m.group(1) if oid not in self._repo: # Unknown OID; preserve the orginal text. - return (None, None, None) + return None, None, None el = Element("a") commit_uri = aurweb.config.get("options", "commit_uri") @@ -83,7 +83,7 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): "href", commit_uri % (quote_plus(self._head), quote_plus(oid[:prefixlen])) ) el.text = markdown.util.AtomicString(oid[:prefixlen]) - return (el, m.start(0), m.end(0)) + return el, m.start(0), m.end(0) class GitCommitsExtension(markdown.extensions.Extension): diff --git a/aurweb/util.py b/aurweb/util.py index cda12af1..0a39cd3d 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -107,7 +107,7 @@ def sanitize_params(offset: str, per_page: str) -> Tuple[int, int]: except ValueError: per_page = defaults.PP - return (offset, per_page) + return offset, per_page def strtobool(value: Union[str, bool]) -> bool: @@ -187,7 +187,7 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: if proc.returncode: raise invalid_exc - return (prefix, key) + return prefix, key def parse_ssh_keys(string: str) -> list[Tuple[str, str]]: @@ -199,4 +199,4 @@ def shell_exec(cmdline: str, cwd: str) -> Tuple[int, str, str]: args = shlex.split(cmdline) proc = Popen(args, cwd=cwd, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() - return (proc.returncode, out.decode().strip(), err.decode().strip()) + return proc.returncode, out.decode().strip(), err.decode().strip() diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 6e92eeff..3b717783 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -1149,7 +1149,7 @@ def test_packages_post_unknown_action(client: TestClient, user: User, package: P def test_packages_post_error(client: TestClient, user: User, package: Package): async def stub_action(request: Request, **kwargs): - return (False, ["Some error."]) + return False, ["Some error."] actions = {"stub": stub_action} with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): @@ -1170,7 +1170,7 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): def test_packages_post(client: TestClient, user: User, package: Package): async def stub_action(request: Request, **kwargs): - return (True, ["Some success."]) + return True, ["Some success."] actions = {"stub": stub_action} with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index bfdb0c37..18c11626 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -1315,7 +1315,7 @@ def test_packages_post_unknown_action(client: TestClient, user: User, package: P def test_packages_post_error(client: TestClient, user: User, package: Package): async def stub_action(request: Request, **kwargs): - return (False, ["Some error."]) + return False, ["Some error."] actions = {"stub": stub_action} with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): @@ -1336,7 +1336,7 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): def test_packages_post(client: TestClient, user: User, package: Package): async def stub_action(request: Request, **kwargs): - return (True, ["Some success."]) + return True, ["Some success."] actions = {"stub": stub_action} with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): diff --git a/test/test_spawn.py b/test/test_spawn.py index be1c5e7c..25b9ebfc 100644 --- a/test/test_spawn.py +++ b/test/test_spawn.py @@ -24,7 +24,7 @@ class FakeProcess: """We need this constructor to remain compatible with Popen.""" def communicate(self) -> Tuple[bytes, bytes]: - return (self.stdout, self.stderr) + return self.stdout, self.stderr def terminate(self) -> None: raise Exception("Fake termination.") diff --git a/test/test_tuvotereminder.py b/test/test_tuvotereminder.py index 0233c8b2..5f2ae3a1 100644 --- a/test/test_tuvotereminder.py +++ b/test/test_tuvotereminder.py @@ -42,7 +42,7 @@ def email_pieces(voteinfo: TUVoteInfo) -> Tuple[str, str]: f"[1]. The voting period\nends in less than 48 hours.\n\n" f"[1] {aur_location}/tu/?id={voteinfo.ID}" ) - return (subject, content) + return subject, content @pytest.fixture From 48e5dc6763b664fb307d2894cedab0a9aaf09630 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 27 Oct 2022 15:49:48 +0100 Subject: [PATCH 1616/1891] feat: remove empty lines from ssh_keys text area, and show helpful message Signed-off-by: Leonidas Spyropoulos --- aurweb/util.py | 2 +- po/aurweb.pot | 4 ++++ templates/partials/account_form.html | 7 +++++++ test/test_util.py | 29 +++++++++++++++++++++++++--- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index 0a39cd3d..7b997609 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -192,7 +192,7 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: def parse_ssh_keys(string: str) -> list[Tuple[str, str]]: """Parse a list of SSH public keys.""" - return [parse_ssh_key(e) for e in string.splitlines()] + return [parse_ssh_key(e) for e in string.strip().splitlines(True) if e.strip()] def shell_exec(cmdline: str, cwd: str) -> Tuple[int, str, str]: diff --git a/po/aurweb.pot b/po/aurweb.pot index 1838fae5..ff1bde8b 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -1398,6 +1398,10 @@ msgid "" "the Arch User Repository." msgstr "" +#: templates/partials/account_form.html +msgid "Specify multiple SSH Keys separated by new line, empty lines are ignored." +msgstr "" + #: template/account_edit_form.php msgid "SSH Public Key" msgstr "" diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 007fb389..a433a57d 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -264,6 +264,13 @@

    +

    + + {{ + "Specify multiple SSH Keys separated by new line, empty lines are ignored." | tr + }} + +

    diff --git a/test/test_util.py b/test/test_util.py index 2e8b2e4e..fd7d8655 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -96,14 +96,37 @@ YbxDwGimZZslg0OZu9UzoAT6xEGyiZsqJkTMbRp1ZYIOv9jHCJxRuxxuN3fzxyT3xE69+vhq2/NJX\ vTNJCD6JtMClxbIXW9q74nNqG+2SD/VQNMUz/505TK1PbY/4uyFfq5HquHJXQVCBll03FRerNHH2N\ schFne6BFHpa48PCoZNH45wLjFXwUyrGU1HrNqh6ZPdRfBTrTOkgs+BKBxGNeV45aYUPu/cFBSPcB\ fRSo6OFcejKc=""" + assert_multiple_keys(pks) + + +def test_parse_ssh_keys_with_extra_lines(): + pks = """ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyN\ +TYAAABBBEURnkiY6JoLyqDE8Li1XuAW+LHmkmLDMW/GL5wY7k4/A+Ta7bjA3MOKrF9j4EuUTvCuNX\ +ULxvpfSqheTFWZc+g= + + + + +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDmqEapFMh/ajPHnm1dBweYPeLOUjC0Ydp6uw7rB\ +S5KCggUVQR8WfIm+sRYTj2+smGsK6zHMBjFnbzvV11vnMqcnY+Sa4LhIAdwkbt/b8HlGaLj1hCWSh\ +a5b5/noeK7L+CECGHdvfJhpxBbhq38YEdFnCGbslk/4NriNcUp/DO81CXb1RzJ9GBFH8ivPW1mbe9\ +YbxDwGimZZslg0OZu9UzoAT6xEGyiZsqJkTMbRp1ZYIOv9jHCJxRuxxuN3fzxyT3xE69+vhq2/NJX\ +8aRsxGPL9G/XKcaYGS6y6LW4quIBCz/XsTZfx1GmkQeZPYHH8FeE+XC/+toXL/kamxdOQKFYEEpWK\ +vTNJCD6JtMClxbIXW9q74nNqG+2SD/VQNMUz/505TK1PbY/4uyFfq5HquHJXQVCBll03FRerNHH2N\ +schFne6BFHpa48PCoZNH45wLjFXwUyrGU1HrNqh6ZPdRfBTrTOkgs+BKBxGNeV45aYUPu/cFBSPcB\ +fRSo6OFcejKc= + + +""" + assert_multiple_keys(pks) + + +def assert_multiple_keys(pks): keys = util.parse_ssh_keys(pks) assert len(keys) == 2 - pfx1, key1, pfx2, key2 = pks.split() k1, k2 = keys - assert pfx1 == k1[0] assert key1 == k1[1] - assert pfx2 == k2[0] assert key2 == k2[1] From 333051ab1f65d28fce7ecbae8ada50a75564303d Mon Sep 17 00:00:00 2001 From: Mario Oenning Date: Fri, 28 Oct 2022 16:55:16 +0000 Subject: [PATCH 1617/1891] feat: add field "Submitter" to metadata-archives --- aurweb/scripts/mkpkglists.py | 5 +++++ test/test_mkpkglists.py | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 67cc7fab..1ff6fbb2 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -163,6 +163,7 @@ def as_dict(package: Package) -> dict[str, Any]: "Popularity": float(package.Popularity), "OutOfDate": package.OutOfDate, "Maintainer": package.Maintainer, + "Submitter": package.Submitter, "FirstSubmitted": package.FirstSubmitted, "LastModified": package.LastModified, } @@ -190,10 +191,13 @@ def _main(): logger.warning(f"{sys.argv[0]} is deprecated and will be soon be removed") logger.info("Started re-creating archives, wait a while...") + Submitter = orm.aliased(User) + query = ( db.query(Package) .join(PackageBase, PackageBase.ID == Package.PackageBaseID) .join(User, PackageBase.MaintainerUID == User.ID, isouter=True) + .join(Submitter, PackageBase.SubmitterUID == Submitter.ID, isouter=True) .filter(PackageBase.PackagerUID.isnot(None)) .with_entities( Package.ID, @@ -207,6 +211,7 @@ def _main(): PackageBase.Popularity, PackageBase.OutOfDateTS.label("OutOfDate"), User.Username.label("Maintainer"), + Submitter.Username.label("Submitter"), PackageBase.SubmittedTS.label("FirstSubmitted"), PackageBase.ModifiedTS.label("LastModified"), ) diff --git a/test/test_mkpkglists.py b/test/test_mkpkglists.py index 3c105817..e7800ffe 100644 --- a/test/test_mkpkglists.py +++ b/test/test_mkpkglists.py @@ -30,6 +30,7 @@ META_KEYS = [ "Popularity", "OutOfDate", "Maintainer", + "Submitter", "FirstSubmitted", "LastModified", "URLPath", @@ -61,7 +62,12 @@ def packages(user: User) -> list[Package]: lic = db.create(License, Name="GPL") for i in range(5): # Create the package. - pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}", Packager=user) + pkgbase = db.create( + PackageBase, + Name=f"pkgbase_{i}", + Packager=user, + Submitter=user, + ) pkg = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}") # Create some related records. From 6ee34ab3cb14ada09d991141779ae9c5f9f50698 Mon Sep 17 00:00:00 2001 From: Mario Oenning Date: Mon, 31 Oct 2022 09:42:56 +0000 Subject: [PATCH 1618/1891] feat: add field "CoMaintainers" to metadata-archives --- aurweb/scripts/mkpkglists.py | 15 +++++++++++++++ test/test_mkpkglists.py | 3 +++ 2 files changed, 18 insertions(+) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 1ff6fbb2..903d96ae 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -142,6 +142,21 @@ def get_extended_fields(): ) .distinct() .order_by("Name"), + # Co-Maintainer + db.query(models.PackageComaintainer) + .join(models.User, models.User.ID == models.PackageComaintainer.UsersID) + .join( + models.Package, + models.Package.PackageBaseID == models.PackageComaintainer.PackageBaseID, + ) + .with_entities( + models.Package.ID, + literal("CoMaintainers").label("Type"), + models.User.Username.label("Name"), + literal(str()).label("Cond"), + ) + .distinct() + .order_by("Name"), ] query = subqueries[0].union_all(*subqueries[1:]) return get_extended_dict(query) diff --git a/test/test_mkpkglists.py b/test/test_mkpkglists.py index e7800ffe..8edbcd81 100644 --- a/test/test_mkpkglists.py +++ b/test/test_mkpkglists.py @@ -11,6 +11,7 @@ from aurweb.models import ( License, Package, PackageBase, + PackageComaintainer, PackageDependency, PackageLicense, User, @@ -79,6 +80,7 @@ def packages(user: User) -> list[Package]: DepName=f"dep_{i}", DepCondition=">=1.0", ) + db.create(PackageComaintainer, User=user, PackageBase=pkgbase, Priority=1) # Add the package to our output list. output.append(pkg) @@ -229,6 +231,7 @@ def test_mkpkglists_extended(config_mock: None, user: User, packages: list[Packa assert key in pkg, f"{pkg=} record does not have {key=}" assert isinstance(pkg["Depends"], list) assert isinstance(pkg["License"], list) + assert isinstance(pkg["CoMaintainers"], list) for file in (PACKAGES, PKGBASE, USERS, META, META_EXT): with open(f"{file}.sha256") as f: From 286834bab1e184d2f92b6c03440e8dc85c2b8d0c Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 31 Oct 2022 14:43:31 +0000 Subject: [PATCH 1619/1891] fix: regression on gzipped filenames from 3dcbee5a With the 3dcbee5a the filenames inside the .gz archives contained .tmp at the end. This fixes those by using Gzip Class constructor instead of the gzip.open method. Signed-off-by: Leonidas Spyropoulos --- aurweb/scripts/mkpkglists.py | 55 +++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 903d96ae..7ff2690b 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -242,8 +242,10 @@ def _main(): tmp_meta = f"{META}.tmp" tmp_metaext = f"{META_EXT}.tmp" gzips = { - "packages": gzip.open(tmp_packages, "wt"), - "meta": gzip.open(tmp_meta, "wb"), + "packages": gzip.GzipFile( + filename=PACKAGES, mode="wb", fileobj=open(tmp_packages, "wb") + ), + "meta": gzip.GzipFile(filename=META, mode="wb", fileobj=open(tmp_meta, "wb")), } # Append list opening to the metafile. @@ -252,7 +254,9 @@ def _main(): # Produce packages.gz + packages-meta-ext-v1.json.gz extended = False if len(sys.argv) > 1 and sys.argv[1] in EXTENDED_FIELD_HANDLERS: - gzips["meta_ext"] = gzip.open(tmp_metaext, "wb") + gzips["meta_ext"] = gzip.GzipFile( + filename=META_EXT, mode="wb", fileobj=open(tmp_metaext, "wb") + ) # Append list opening to the meta_ext file. gzips.get("meta_ext").write(b"[\n") f = EXTENDED_FIELD_HANDLERS.get(sys.argv[1]) @@ -261,28 +265,29 @@ def _main(): results = query.all() n = len(results) - 1 - for i, result in enumerate(results): - # Append to packages.gz. - gzips.get("packages").write(f"{result.Name}\n") + with io.TextIOWrapper(gzips.get("packages")) as p: + for i, result in enumerate(results): + # Append to packages.gz. + p.write(f"{result.Name}\n") - # Construct our result JSON dictionary. - item = as_dict(result) - item["URLPath"] = snapshot_uri % result.Name + # Construct our result JSON dictionary. + item = as_dict(result) + item["URLPath"] = snapshot_uri % result.Name - # We stream out package json objects line per line, so - # we also need to include the ',' character at the end - # of package lines (excluding the last package). - suffix = b",\n" if i < n else b"\n" + # We stream out package json objects line per line, so + # we also need to include the ',' character at the end + # of package lines (excluding the last package). + suffix = b",\n" if i < n else b"\n" - # Write out to packagesmetafile - output.append(item) - gzips.get("meta").write(orjson.dumps(output[-1]) + suffix) + # Write out to packagesmetafile + output.append(item) + gzips.get("meta").write(orjson.dumps(output[-1]) + suffix) - if extended: - # Write out to packagesmetaextfile. - data_ = data.get(result.ID, {}) - output[-1].update(data_) - gzips.get("meta_ext").write(orjson.dumps(output[-1]) + suffix) + if extended: + # Write out to packagesmetaextfile. + data_ = data.get(result.ID, {}) + output[-1].update(data_) + gzips.get("meta_ext").write(orjson.dumps(output[-1]) + suffix) # Append the list closing to meta/meta_ext. gzips.get("meta").write(b"]") @@ -295,13 +300,17 @@ def _main(): # Produce pkgbase.gz query = db.query(PackageBase.Name).filter(PackageBase.PackagerUID.isnot(None)).all() tmp_pkgbase = f"{PKGBASE}.tmp" - with gzip.open(tmp_pkgbase, "wt") as f: + pkgbase_gzip = gzip.GzipFile( + filename=PKGBASE, mode="wb", fileobj=open(tmp_pkgbase, "wb") + ) + with io.TextIOWrapper(pkgbase_gzip) as f: f.writelines([f"{base.Name}\n" for i, base in enumerate(query)]) # Produce users.gz query = db.query(User.Username).all() tmp_users = f"{USERS}.tmp" - with gzip.open(tmp_users, "wt") as f: + users_gzip = gzip.GzipFile(filename=USERS, mode="wb", fileobj=open(tmp_users, "wb")) + with io.TextIOWrapper(users_gzip) as f: f.writelines([f"{user.Username}\n" for i, user in enumerate(query)]) files = [ From 5669821b299427081f32de7d9d6712dff8b793dc Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 31 Oct 2022 18:00:39 +0100 Subject: [PATCH 1620/1891] perf: tweak some queries in mkpkglists We can omit the "distinct" from some queries because constraints in the DB ensure uniqueness: * Groups sub-query PackageGroup: Primary key makes "PackageID" + "GroupID" unique Groups: Unique index on "Name" column -> Technically we can't have a package with the same group-name twice * Licenses sub-query: PackageLicense -> Primary key makes "PackageID" + "LicenseID" unique Licenses -> Unique index on "Name" column -> Technically we can't have a package with the same license-name twice * Keywords sub-query: PackageKeywords -> Primary key makes "PackageBaseID" + "KeywordID" unique (And a Package can only have one PackageBase) Keywords -> Unique index on "Name" column -> Technically we can't have a package with the same Keyword twice * Packages main-query: We join PackageBases and Users on their primary key columns (which are guaranteed to be unique) -> There is no way we could end up with more than one record for a Package Signed-off-by: moson-mo --- aurweb/scripts/mkpkglists.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index 7ff2690b..d2d11c5e 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -94,7 +94,7 @@ def get_extended_fields(): models.PackageDependency.DepName.label("Name"), models.PackageDependency.DepCondition.label("Cond"), ) - .distinct() + .distinct() # A package could have the same dependency multiple times .order_by("Name"), # PackageRelation db.query(models.PackageRelation) @@ -105,7 +105,7 @@ def get_extended_fields(): models.PackageRelation.RelName.label("Name"), models.PackageRelation.RelCondition.label("Cond"), ) - .distinct() + .distinct() # A package could have the same relation multiple times .order_by("Name"), # Groups db.query(models.PackageGroup) @@ -116,7 +116,6 @@ def get_extended_fields(): models.Group.Name.label("Name"), literal(str()).label("Cond"), ) - .distinct() .order_by("Name"), # Licenses db.query(models.PackageLicense) @@ -127,7 +126,6 @@ def get_extended_fields(): models.License.Name.label("Name"), literal(str()).label("Cond"), ) - .distinct() .order_by("Name"), # Keywords db.query(models.PackageKeyword) @@ -140,7 +138,6 @@ def get_extended_fields(): models.PackageKeyword.Keyword.label("Name"), literal(str()).label("Cond"), ) - .distinct() .order_by("Name"), # Co-Maintainer db.query(models.PackageComaintainer) @@ -155,7 +152,7 @@ def get_extended_fields(): models.User.Username.label("Name"), literal(str()).label("Cond"), ) - .distinct() + .distinct() # A package could have the same co-maintainer multiple times .order_by("Name"), ] query = subqueries[0].union_all(*subqueries[1:]) @@ -230,7 +227,6 @@ def _main(): PackageBase.SubmittedTS.label("FirstSubmitted"), PackageBase.ModifiedTS.label("LastModified"), ) - .distinct() .order_by("Name") ) From f10c1a0505d446dfd0f78fc3a03f842d62be82f7 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sun, 23 Oct 2022 10:28:30 +0100 Subject: [PATCH 1621/1891] perf: add PackageKeywords.PackageBaseID index This is used on the export for package-meta.v1.gz generation Signed-off-by: Leonidas Spyropoulos --- aurweb/schema.py | 1 + ...57fd7_add_packagekeyword_packagebaseuid.py | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 migrations/versions/9e3158957fd7_add_packagekeyword_packagebaseuid.py diff --git a/aurweb/schema.py b/aurweb/schema.py index 5f998ed9..0ba3e9c2 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -201,6 +201,7 @@ PackageKeywords = Table( nullable=False, server_default=text("''"), ), + Index("KeywordsPackageBaseID", "PackageBaseID"), mysql_engine="InnoDB", mysql_charset="utf8mb4", mysql_collate="utf8mb4_general_ci", diff --git a/migrations/versions/9e3158957fd7_add_packagekeyword_packagebaseuid.py b/migrations/versions/9e3158957fd7_add_packagekeyword_packagebaseuid.py new file mode 100644 index 00000000..03291152 --- /dev/null +++ b/migrations/versions/9e3158957fd7_add_packagekeyword_packagebaseuid.py @@ -0,0 +1,24 @@ +"""add PackageKeyword.PackageBaseUID index + +Revision ID: 9e3158957fd7 +Revises: 6441d3b65270 +Create Date: 2022-10-17 11:11:46.203322 + +""" +from alembic import op + +# revision identifiers, used by Alembic. +revision = "9e3158957fd7" +down_revision = "6441d3b65270" +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_index( + "KeywordsPackageBaseID", "PackageKeywords", ["PackageBaseID"], unique=False + ) + + +def downgrade(): + op.drop_index("KeywordsPackageBaseID", table_name="PackageKeywords") From d00371f444aa3465c0adc2ea9118c5eb0633e1be Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 1 Nov 2022 17:17:34 +0000 Subject: [PATCH 1622/1891] housekeep: bump renovate dependencies Signed-off-by: Leonidas Spyropoulos --- poetry.lock | 341 +++++++++++++++++++++++-------------------------- pyproject.toml | 10 +- 2 files changed, 167 insertions(+), 184 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9cf24f9a..f6b79a30 100644 --- a/poetry.lock +++ b/poetry.lock @@ -153,11 +153,11 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" [[package]] name = "coverage" @@ -234,6 +234,17 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" dnspython = ">=1.15.0" idna = ">=2.0.0" +[[package]] +name = "exceptiongroup" +version = "1.0.0" +description = "Backport of PEP 654 (exception groups)" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "execnet" version = "1.9.0" @@ -247,7 +258,7 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "1.9.4" +version = "1.10.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false @@ -263,7 +274,7 @@ lua = ["lupa (>=1.13,<2.0)"] [[package]] name = "fastapi" -version = "0.85.1" +version = "0.85.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -276,8 +287,8 @@ starlette = "0.20.4" [package.extras] all = ["email-validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.7.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-orjson (==3.6.2)", "types-ujson (==5.4.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer[all] (>=0.6.1,<0.7.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "pytest-cov (>=2.12.0,<5.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<=1.4.41)", "types-orjson (==3.6.2)", "types-ujson (==5.5.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] [[package]] name = "feedgen" @@ -305,14 +316,15 @@ testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pyt [[package]] name = "greenlet" -version = "1.1.3.post0" +version = "2.0.0" description = "Lightweight in-process concurrent programming" category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" [package.extras] -docs = ["Sphinx"] +docs = ["Sphinx", "docutils (<0.18)"] +test = ["faulthandler", "objgraph"] [[package]] name = "gunicorn" @@ -542,7 +554,7 @@ python-versions = ">=3.5" [[package]] name = "orjson" -version = "3.8.0" +version = "3.8.1" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false @@ -628,20 +640,12 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.21.8" +version = "4.21.9" description = "" category = "main" optional = false python-versions = ">=3.7" -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - [[package]] name = "pyalpm" version = "0.10.6" @@ -697,7 +701,7 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.1.3" +version = "7.2.0" description = "pytest: simple powerful testing with Python" category = "main" optional = false @@ -706,11 +710,11 @@ python-versions = ">=3.7" [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] @@ -744,18 +748,6 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] -[[package]] -name = "pytest-forked" -version = "1.4.0" -description = "run tests in isolated forked subprocesses" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -py = "*" -pytest = ">=3.10" - [[package]] name = "pytest-tap" version = "3.3" @@ -770,7 +762,7 @@ pytest = ">=3.0" [[package]] name = "pytest-xdist" -version = "2.5.0" +version = "3.0.2" description = "pytest xdist plugin for distributed testing and loop-on-failing modes" category = "main" optional = false @@ -779,7 +771,6 @@ python-versions = ">=3.6" [package.dependencies] execnet = ">=1.1" pytest = ">=6.2.0" -pytest-forked = "*" [package.extras] psutil = ["psutil (>=3.0)"] @@ -1058,7 +1049,7 @@ h11 = ">=0.9.0,<1" [[package]] name = "zipp" -version = "3.9.0" +version = "3.10.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false @@ -1071,7 +1062,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "de9f0dc1d7e3f149a83629ad30d161da38aa1498b81aaa8bdfd2ebed50f232ab" +content-hash = "84f0bae9789174cbdc5aa672b9e72f0ef91763f63ed73e8cafb45f26efd9bb47" [metadata.files] aiofiles = [ @@ -1208,8 +1199,8 @@ click = [ {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] coverage = [ {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, @@ -1303,17 +1294,21 @@ email-validator = [ {file = "email_validator-1.3.0-py2.py3-none-any.whl", hash = "sha256:816073f2a7cffef786b29928f58ec16cdac42710a53bb18aa94317e3e145ec5c"}, {file = "email_validator-1.3.0.tar.gz", hash = "sha256:553a66f8be2ec2dea641ae1d3f29017ab89e9d603d4a25cdaac39eefa283d769"}, ] +exceptiongroup = [ + {file = "exceptiongroup-1.0.0-py3-none-any.whl", hash = "sha256:2ac84b496be68464a2da60da518af3785fff8b7ec0d090a581604bc870bdee41"}, + {file = "exceptiongroup-1.0.0.tar.gz", hash = "sha256:affbabf13fb6e98988c38d9c5650e701569fe3c1de3233cfb61c5f33774690ad"}, +] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, ] fakeredis = [ - {file = "fakeredis-1.9.4-py3-none-any.whl", hash = "sha256:61afe14095aad3e7413a0a6fe63041da1b4bc3e41d5228a33b60bd03fabf22d8"}, - {file = "fakeredis-1.9.4.tar.gz", hash = "sha256:17415645d11994061f5394f3f1c76ba4531f3f8b63f9c55a8fd2120bebcbfae9"}, + {file = "fakeredis-1.10.0-py3-none-any.whl", hash = "sha256:0be420a79fabda234963a2730c4ce609a6d44a598e8dd253ce97785bef944285"}, + {file = "fakeredis-1.10.0.tar.gz", hash = "sha256:2b02370118535893d832bcd3c099ef282de3f13b29ae3922432e2225794ec334"}, ] fastapi = [ - {file = "fastapi-0.85.1-py3-none-any.whl", hash = "sha256:de3166b6b1163dc22da4dc4ebdc3192fcbac7700dd1870a1afa44de636a636b5"}, - {file = "fastapi-0.85.1.tar.gz", hash = "sha256:1facd097189682a4ff11cbd01334a992e51b56be663b2bd50c2c09523624f144"}, + {file = "fastapi-0.85.2-py3-none-any.whl", hash = "sha256:6292db0edd4a11f0d938d6033ccec5f706e9d476958bf33b119e8ddb4e524bde"}, + {file = "fastapi-0.85.2.tar.gz", hash = "sha256:3e10ea0992c700e0b17b6de8c2092d7b9cd763ce92c49ee8d4be10fee3b2f367"}, ] feedgen = [ {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, @@ -1323,72 +1318,61 @@ filelock = [ {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, ] greenlet = [ - {file = "greenlet-1.1.3.post0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9649891ab4153f217f319914455ccf0b86986b55fc0573ce803eb998ad7d6854"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-win32.whl", hash = "sha256:11fc7692d95cc7a6a8447bb160d98671ab291e0a8ea90572d582d57361360f05"}, - {file = "greenlet-1.1.3.post0-cp27-cp27m-win_amd64.whl", hash = "sha256:05ae7383f968bba4211b1fbfc90158f8e3da86804878442b4fb6c16ccbcaa519"}, - {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ccbe7129a282ec5797df0451ca1802f11578be018a32979131065565da89b392"}, - {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a8b58232f5b72973350c2b917ea3df0bebd07c3c82a0a0e34775fc2c1f857e9"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f6661b58412879a2aa099abb26d3c93e91dedaba55a6394d1fb1512a77e85de9"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c6e942ca9835c0b97814d14f78da453241837419e0d26f7403058e8db3e38f8"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a812df7282a8fc717eafd487fccc5ba40ea83bb5b13eb3c90c446d88dbdfd2be"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a7a6560df073ec9de2b7cb685b199dfd12519bc0020c62db9d1bb522f989fa"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17a69967561269b691747e7f436d75a4def47e5efcbc3c573180fc828e176d80"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:60839ab4ea7de6139a3be35b77e22e0398c270020050458b3d25db4c7c394df5"}, - {file = "greenlet-1.1.3.post0-cp310-cp310-win_amd64.whl", hash = "sha256:8926a78192b8b73c936f3e87929931455a6a6c6c385448a07b9f7d1072c19ff3"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:c6f90234e4438062d6d09f7d667f79edcc7c5e354ba3a145ff98176f974b8132"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814f26b864ed2230d3a7efe0336f5766ad012f94aad6ba43a7c54ca88dd77cba"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fda1139d87ce5f7bd80e80e54f9f2c6fe2f47983f1a6f128c47bf310197deb6"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0643250dd0756f4960633f5359884f609a234d4066686754e834073d84e9b51"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cb863057bed786f6622982fb8b2c122c68e6e9eddccaa9fa98fd937e45ee6c4f"}, - {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8c0581077cf2734569f3e500fab09c0ff6a2ab99b1afcacbad09b3c2843ae743"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:695d0d8b5ae42c800f1763c9fce9d7b94ae3b878919379150ee5ba458a460d57"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5662492df0588a51d5690f6578f3bbbd803e7f8d99a99f3bf6128a401be9c269"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:bffba15cff4802ff493d6edcf20d7f94ab1c2aee7cfc1e1c7627c05f1102eee8"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-win32.whl", hash = "sha256:7afa706510ab079fd6d039cc6e369d4535a48e202d042c32e2097f030a16450f"}, - {file = "greenlet-1.1.3.post0-cp35-cp35m-win_amd64.whl", hash = "sha256:3a24f3213579dc8459e485e333330a921f579543a5214dbc935bc0763474ece3"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:64e10f303ea354500c927da5b59c3802196a07468332d292aef9ddaca08d03dd"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:eb6ac495dccb1520667cfea50d89e26f9ffb49fa28496dea2b95720d8b45eb54"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:88720794390002b0c8fa29e9602b395093a9a766b229a847e8d88349e418b28a"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39464518a2abe9c505a727af7c0b4efff2cf242aa168be5f0daa47649f4d7ca8"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0914f02fcaa8f84f13b2df4a81645d9e82de21ed95633765dd5cc4d3af9d7403"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96656c5f7c95fc02c36d4f6ef32f4e94bb0b6b36e6a002c21c39785a4eec5f5d"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4f74aa0092602da2069df0bc6553919a15169d77bcdab52a21f8c5242898f519"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3aeac044c324c1a4027dca0cde550bd83a0c0fbff7ef2c98df9e718a5086c194"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-win32.whl", hash = "sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04"}, - {file = "greenlet-1.1.3.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:70048d7b2c07c5eadf8393e6398595591df5f59a2f26abc2f81abca09610492f"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:66aa4e9a726b70bcbfcc446b7ba89c8cec40f405e51422c39f42dfa206a96a05"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:025b8de2273d2809f027d347aa2541651d2e15d593bbce0d5f502ca438c54136"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:82a38d7d2077128a017094aff334e67e26194f46bd709f9dcdacbf3835d47ef5"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8ece5d1a99a2adcb38f69af2f07d96fb615415d32820108cd340361f590d128"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2794eef1b04b5ba8948c72cc606aab62ac4b0c538b14806d9c0d88afd0576d6b"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a8d24eb5cb67996fb84633fdc96dbc04f2d8b12bfcb20ab3222d6be271616b67"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0120a879aa2b1ac5118bce959ea2492ba18783f65ea15821680a256dfad04754"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-win32.whl", hash = "sha256:bef49c07fcb411c942da6ee7d7ea37430f830c482bf6e4b72d92fd506dd3a427"}, - {file = "greenlet-1.1.3.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:62723e7eb85fa52e536e516ee2ac91433c7bb60d51099293671815ff49ed1c21"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d25cdedd72aa2271b984af54294e9527306966ec18963fd032cc851a725ddc1b"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:924df1e7e5db27d19b1359dc7d052a917529c95ba5b8b62f4af611176da7c8ad"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ec615d2912b9ad807afd3be80bf32711c0ff9c2b00aa004a45fd5d5dde7853d9"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0971d37ae0eaf42344e8610d340aa0ad3d06cd2eee381891a10fe771879791f9"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:325f272eb997916b4a3fc1fea7313a8adb760934c2140ce13a2117e1b0a8095d"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75afcbb214d429dacdf75e03a1d6d6c5bd1fa9c35e360df8ea5b6270fb2211c"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5c2d21c2b768d8c86ad935e404cc78c30d53dea009609c3ef3a9d49970c864b5"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:467b73ce5dcd89e381292fb4314aede9b12906c18fab903f995b86034d96d5c8"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-win32.whl", hash = "sha256:8149a6865b14c33be7ae760bcdb73548bb01e8e47ae15e013bf7ef9290ca309a"}, - {file = "greenlet-1.1.3.post0-cp38-cp38-win_amd64.whl", hash = "sha256:104f29dd822be678ef6b16bf0035dcd43206a8a48668a6cae4d2fe9c7a7abdeb"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:c8c9301e3274276d3d20ab6335aa7c5d9e5da2009cccb01127bddb5c951f8870"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:8415239c68b2ec9de10a5adf1130ee9cb0ebd3e19573c55ba160ff0ca809e012"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:3c22998bfef3fcc1b15694818fc9b1b87c6cc8398198b96b6d355a7bcb8c934e"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa1845944e62f358d63fcc911ad3b415f585612946b8edc824825929b40e59e"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:890f633dc8cb307761ec566bc0b4e350a93ddd77dc172839be122be12bae3e10"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cf37343e43404699d58808e51f347f57efd3010cc7cee134cdb9141bd1ad9ea"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5edf75e7fcfa9725064ae0d8407c849456553a181ebefedb7606bac19aa1478b"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-win32.whl", hash = "sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2"}, - {file = "greenlet-1.1.3.post0-cp39-cp39-win_amd64.whl", hash = "sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7"}, - {file = "greenlet-1.1.3.post0.tar.gz", hash = "sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c"}, + {file = "greenlet-2.0.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4be4dedbd2fa9b7c35627f322d6d3139cb125bc18d5ef2f40237990850ea446f"}, + {file = "greenlet-2.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:75c022803de010294366f3608d4bba3e346693b1b7427b79d57e3d924ed03838"}, + {file = "greenlet-2.0.0-cp27-cp27m-win32.whl", hash = "sha256:4a1953465b7651073cffde74ed7d121e602ef9a9740d09ee137b01879ac15a2f"}, + {file = "greenlet-2.0.0-cp27-cp27m-win_amd64.whl", hash = "sha256:a65205e6778142528978b4acca76888e7e7f0be261e395664e49a5c21baa2141"}, + {file = "greenlet-2.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d71feebf5c8041c80dfda76427e14e3ca00bca042481bd3e9612a9d57b2cbbf7"}, + {file = "greenlet-2.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f7edbd2957f72aea357241fe42ffc712a8e9b8c2c42f24e2ef5d97b255f66172"}, + {file = "greenlet-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79687c48e7f564be40c46b3afea6d141b8d66ffc2bc6147e026d491c6827954a"}, + {file = "greenlet-2.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a245898ec5e9ca0bc87a63e4e222cc633dc4d1f1a0769c34a625ad67edb9f9de"}, + {file = "greenlet-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:adcf45221f253b3a681c99da46fa6ac33596fa94c2f30c54368f7ee1c4563a39"}, + {file = "greenlet-2.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3dc294afebf2acfd029373dbf3d01d36fd8d6888a03f5a006e2d690f66b153d9"}, + {file = "greenlet-2.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1cfeae4dda32eb5c64df05d347c4496abfa57ad16a90082798a2bba143c6c854"}, + {file = "greenlet-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:d58d4b4dc82e2d21ebb7dd7d3a6d370693b2236a1407fe3988dc1d4ea07575f9"}, + {file = "greenlet-2.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0d7efab8418c1fb3ea00c4abb89e7b0179a952d0d53ad5fcff798ca7440f8e8"}, + {file = "greenlet-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8a10e14238407be3978fa6d190eb3724f9d766655fefc0134fd5482f1fb0108"}, + {file = "greenlet-2.0.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:98b848a0b75e76b446dc71fdbac712d9078d96bb1c1607f049562dde1f8801e1"}, + {file = "greenlet-2.0.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:8e8dbad9b4f4c3e37898914cfccb7c4f00dbe3146333cfe52a1a3103cc2ff97c"}, + {file = "greenlet-2.0.0-cp35-cp35m-win32.whl", hash = "sha256:069a8a557541a04518dc3beb9a78637e4e6b286814849a2ecfac529eaa78562b"}, + {file = "greenlet-2.0.0-cp35-cp35m-win_amd64.whl", hash = "sha256:cc211c2ff5d3b2ba8d557a71e3b4f0f0a2020067515143a9516ea43884271192"}, + {file = "greenlet-2.0.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d4e7642366e638f45d70c5111590a56fbd0ffb7f474af20c6c67c01270bcf5cf"}, + {file = "greenlet-2.0.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e7a0dca752b4e3395890ab4085c3ec3838d73714261914c01b53ed7ea23b5867"}, + {file = "greenlet-2.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8c67ecda450ad4eac7837057f5deb96effa836dacaf04747710ccf8eeb73092"}, + {file = "greenlet-2.0.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3cc1abaf47cfcfdc9ac0bdff173cebab22cd54e9e3490135a4a9302d0ff3b163"}, + {file = "greenlet-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efdbbbf7b6c8d5be52977afa65b9bb7b658bab570543280e76c0fabc647175ed"}, + {file = "greenlet-2.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:7acaa51355d5b9549d474dc71be6846ee9a8f2cb82f4936e5efa7a50bbeb94ad"}, + {file = "greenlet-2.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2be628bca0395610da08921f9376dd14317f37256d41078f5c618358467681e1"}, + {file = "greenlet-2.0.0-cp36-cp36m-win32.whl", hash = "sha256:eca9c0473de053dcc92156dd62c38c3578628b536c7f0cd66e655e211c14ac32"}, + {file = "greenlet-2.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9a4a9fea68fd98814999d91ea585e49ed68d7e199a70bef13a857439f60a4609"}, + {file = "greenlet-2.0.0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:6b28420ae290bfbf5d827f976abccc2f74f0a3f5e4fb69b66acf98f1cbe95e7e"}, + {file = "greenlet-2.0.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:2b8e1c939b363292ecc93999fb1ad53ffc5d0aac8e933e4362b62365241edda5"}, + {file = "greenlet-2.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c5ddadfe40e903c6217ed2b95a79f49e942bb98527547cc339fc7e43a424aad"}, + {file = "greenlet-2.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e5ead803b11b60b347e08e0f37234d9a595f44a6420026e47bcaf94190c3cd6"}, + {file = "greenlet-2.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b89b78ffb516c2921aa180c2794082666e26680eef05996b91f46127da24d964"}, + {file = "greenlet-2.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:939963d0137ec92540d95b68b7f795e8dbadce0a1fca53e3e7ef8ddc18ee47cb"}, + {file = "greenlet-2.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c1e93ef863810fba75faf418f0861dbf59bfe01a7b5d0a91d39603df58d3d3fa"}, + {file = "greenlet-2.0.0-cp37-cp37m-win32.whl", hash = "sha256:6fd342126d825b76bf5b49717a7c682e31ed1114906cdec7f5a0c2ff1bc737a7"}, + {file = "greenlet-2.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5392ddb893e7fba237b988f846c4a80576557cc08664d56dc1a69c5c02bdc80c"}, + {file = "greenlet-2.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b4fd73b62c1038e7ee938b1de328eaa918f76aa69c812beda3aff8a165494201"}, + {file = "greenlet-2.0.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:0ba0f2e5c4a8f141952411e356dba05d6fe0c38325ee0e4f2d0c6f4c2c3263d5"}, + {file = "greenlet-2.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8bacecee0c9348ab7c95df810e12585e9e8c331dfc1e22da4ed0bd635a5f483"}, + {file = "greenlet-2.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:341053e0a96d512315c27c34fad4672c4573caf9eb98310c39e7747645c88d8b"}, + {file = "greenlet-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fcdd8ae391ffabb3b672397b58a9737aaff6b8cae0836e8db8ff386fcea802"}, + {file = "greenlet-2.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c3aa7d3bc545162a6676445709b24a2a375284dc5e2f2432d58b80827c2bd91c"}, + {file = "greenlet-2.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9d8dca31a39dd9f25641559b8cdf9066168c682dfcfbe0f797f03e4c9718a63a"}, + {file = "greenlet-2.0.0-cp38-cp38-win32.whl", hash = "sha256:aa2b371c3633e694d043d6cec7376cb0031c6f67029f37eef40bda105fd58753"}, + {file = "greenlet-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:0fa2a66fdf0d09929e79f786ad61529d4e752f452466f7ddaa5d03caf77a603d"}, + {file = "greenlet-2.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:e7ec3f2465ba9b7d25895307abe1c1c101a257c54b9ea1522bbcbe8ca8793735"}, + {file = "greenlet-2.0.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:99e9851e40150504474915605649edcde259a4cd9bce2fcdeb4cf33ad0b5c293"}, + {file = "greenlet-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20bf68672ae14ef2e2e6d3ac1f308834db1d0b920b3b0674eef48b2dce0498dd"}, + {file = "greenlet-2.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30198bccd774f9b6b1ba7564a0d02a79dd1fe926cfeb4107856fe16c9dfb441c"}, + {file = "greenlet-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d65d7d1ff64fb300127d2ffd27db909de4d21712a5dde59a3ad241fb65ee83d7"}, + {file = "greenlet-2.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2f5d396a5457458460b0c28f738fc8ab2738ee61b00c3f845c7047a333acd96c"}, + {file = "greenlet-2.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09f00f9938eb5ae1fe203558b56081feb0ca34a2895f8374cd01129ddf4d111c"}, + {file = "greenlet-2.0.0-cp39-cp39-win32.whl", hash = "sha256:089e123d80dbc6f61fff1ff0eae547b02c343d50968832716a7b0a33bea5f792"}, + {file = "greenlet-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc283f99a4815ef70cad537110e3e03abcef56ab7d005ba9a8c6ec33054ce9c0"}, + {file = "greenlet-2.0.0.tar.gz", hash = "sha256:6c66f0da8049ee3c126b762768179820d4c0ae0ca46ae489039e4da2fae39a52"}, ] gunicorn = [ {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, @@ -1574,48 +1558,55 @@ mysqlclient = [ {file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"}, ] orjson = [ - {file = "orjson-3.8.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:9a93850a1bdc300177b111b4b35b35299f046148ba23020f91d6efd7bf6b9d20"}, - {file = "orjson-3.8.0-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:7536a2a0b41672f824912aeab545c2467a9ff5ca73a066ff04fb81043a0a177a"}, - {file = "orjson-3.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66c19399bb3b058e3236af7910b57b19a4fc221459d722ed72a7dc90370ca090"}, - {file = "orjson-3.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b391d5c2ddc2f302d22909676b306cb6521022c3ee306c861a6935670291b2c"}, - {file = "orjson-3.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bdb1042970ca5f544a047d6c235a7eb4acdb69df75441dd1dfcbc406377ab37"}, - {file = "orjson-3.8.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d189e2acb510e374700cb98cf11b54f0179916ee40f8453b836157ae293efa79"}, - {file = "orjson-3.8.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6a23b40c98889e9abac084ce5a1fb251664b41da9f6bdb40a4729e2288ed2ed4"}, - {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"}, - {file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"}, - {file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"}, - {file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"}, - {file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"}, - {file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"}, - {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"}, - {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6e3da2e4bd27c3b796519ca74132c7b9e5348fb6746315e0f6c1592bc5cf1caf"}, - {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896a21a07f1998648d9998e881ab2b6b80d5daac4c31188535e9d50460edfcf7"}, - {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:4065906ce3ad6195ac4d1bddde862fe811a42d7be237a1ff762666c3a4bb2151"}, - {file = "orjson-3.8.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:5f856279872a4449fc629924e6a083b9821e366cf98b14c63c308269336f7c14"}, - {file = "orjson-3.8.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1b1cd25acfa77935bb2e791b75211cec0cfc21227fe29387e553c545c3ff87e1"}, - {file = "orjson-3.8.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3e2459d441ab8fd8b161aa305a73d5269b3cda13b5a2a39eba58b4dd3e394f49"}, - {file = "orjson-3.8.0-cp37-none-win_amd64.whl", hash = "sha256:d2b5dafbe68237a792143137cba413447f60dd5df428e05d73dcba10c1ea6fcf"}, - {file = "orjson-3.8.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:5b072ef8520cfe7bd4db4e3c9972d94336763c2253f7c4718a49e8733bada7b8"}, - {file = "orjson-3.8.0-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e68c699471ea3e2dd1b35bfd71c6a0a0e4885b64abbe2d98fce1ef11e0afaff3"}, - {file = "orjson-3.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7225e8b08996d1a0c804d3a641a53e796685e8c9a9fd52bd428980032cad9a"}, - {file = "orjson-3.8.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f687776a03c19f40b982fb5c414221b7f3d19097841571be2223d1569a59877"}, - {file = "orjson-3.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7990a9caf3b34016ac30be5e6cfc4e7efd76aa85614a1215b0eae4f0c7e3db59"}, - {file = "orjson-3.8.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:02d638d43951ba346a80f0abd5942a872cc87db443e073f6f6fc530fee81e19b"}, - {file = "orjson-3.8.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f4b46dbdda2f0bd6480c39db90b21340a19c3b0fcf34bc4c6e465332930ca539"}, - {file = "orjson-3.8.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:655d7387a1634a9a477c545eea92a1ee902ab28626d701c6de4914e2ed0fecd2"}, - {file = "orjson-3.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5edb93cdd3eb32977633fa7aaa6a34b8ab54d9c49cdcc6b0d42c247a29091b22"}, - {file = "orjson-3.8.0-cp38-none-win_amd64.whl", hash = "sha256:03ed95814140ff09f550b3a42e6821f855d981c94d25b9cc83e8cca431525d70"}, - {file = "orjson-3.8.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7b0e72974a5d3b101226899f111368ec2c9824d3e9804af0e5b31567f53ad98a"}, - {file = "orjson-3.8.0-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6ea5fe20ef97545e14dd4d0263e4c5c3bc3d2248d39b4b0aed4b84d528dfc0af"}, - {file = "orjson-3.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6433c956f4a18112342a18281e0bec67fcd8b90be3a5271556c09226e045d805"}, - {file = "orjson-3.8.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87462791dd57de2e3e53068bf4b7169c125c50960f1bdda08ed30c797cb42a56"}, - {file = "orjson-3.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be02f6acee33bb63862eeff80548cd6b8a62e2d60ad2d8dfd5a8824cc43d8887"}, - {file = "orjson-3.8.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:a709c2249c1f2955dbf879506fd43fa08c31fdb79add9aeb891e3338b648bf60"}, - {file = "orjson-3.8.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2065b6d280dc58f131ffd93393737961ff68ae7eb6884b68879394074cc03c13"}, - {file = "orjson-3.8.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fd6cac83136e06e538a4d17117eaeabec848c1e86f5742d4811656ad7ee475f"}, - {file = "orjson-3.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:25b5e48fbb9f0b428a5e44cf740675c9281dd67816149fc33659803399adbbe8"}, - {file = "orjson-3.8.0-cp39-none-win_amd64.whl", hash = "sha256:2058653cc12b90e482beacb5c2d52dc3d7606f9e9f5a52c1c10ef49371e76f52"}, - {file = "orjson-3.8.0.tar.gz", hash = "sha256:fb42f7cf57d5804a9daa6b624e3490ec9e2631e042415f3aebe9f35a8492ba6c"}, + {file = "orjson-3.8.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:a70aaa2e56356e58c6e1b49f7b7f069df5b15e55db002a74db3ff3f7af67c7ff"}, + {file = "orjson-3.8.1-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:d45db052d01d0ab7579470141d5c3592f4402d43cfacb67f023bc1210a67b7bc"}, + {file = "orjson-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2aae92398c0023ac26a6cd026375f765ef5afe127eccabf563c78af7b572d59"}, + {file = "orjson-3.8.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0bd5b4e539db8a9635776bdf9a25c3db84e37165e65d45c8ca90437adc46d6d8"}, + {file = "orjson-3.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21efb87b168066201a120b0f54a2381f6f51ff3727e07b3908993732412b314a"}, + {file = "orjson-3.8.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:e073338e422f518c1d4d80efc713cd17f3ed6d37c8c7459af04a95459f3206d1"}, + {file = "orjson-3.8.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8f672f3987f6424f60ab2e86ea7ed76dd2806b8e9b506a373fc8499aed85ddb5"}, + {file = "orjson-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:231c30958ed99c23128a21993c5ac0a70e1e568e6a898a47f70d5d37461ca47c"}, + {file = "orjson-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59b4baf71c9f39125d7e535974b146cc180926462969f6d8821b4c5e975e11b3"}, + {file = "orjson-3.8.1-cp310-none-win_amd64.whl", hash = "sha256:fe25f50dc3d45364428baa0dbe3f613a5171c64eb0286eb775136b74e61ba58a"}, + {file = "orjson-3.8.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:6802edf98f6918e89df355f56be6e7db369b31eed64ff2496324febb8b0aa43b"}, + {file = "orjson-3.8.1-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:a4244f4199a160717f0027e434abb886e322093ceadb2f790ff0c73ed3e17662"}, + {file = "orjson-3.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6956cf7a1ac97523e96f75b11534ff851df99a6474a561ad836b6e82004acbb8"}, + {file = "orjson-3.8.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b4e3857dd2416b479f700e9bdf4fcec8c690d2716622397d2b7e848f9833e50"}, + {file = "orjson-3.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8873e490dea0f9cd975d66f84618b6fb57b1ba45ecb218313707a71173d764f"}, + {file = "orjson-3.8.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:124207d2cd04e845eaf2a6171933cde40aebcb8c2d7d3b081e01be066d3014b6"}, + {file = "orjson-3.8.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d8ed77098c2e22181fce971f49a34204c38b79ca91c01d515d07015339ae8165"}, + {file = "orjson-3.8.1-cp311-none-win_amd64.whl", hash = "sha256:8623ac25fa0850a44ac845e9333c4da9ae5707b7cec8ac87cbe9d4e41137180f"}, + {file = "orjson-3.8.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:d67a0bd0283a3b17ac43c5ab8e4a7e9d3aa758d6ec5d51c232343c408825a5ad"}, + {file = "orjson-3.8.1-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:d89ef8a4444d83e0a5171d14f2ab4895936ab1773165b020f97d29cf289a2d88"}, + {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97839a6abbebb06099294e6057d5b3061721ada08b76ae792e7041b6cb54c97f"}, + {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6071bcf51f0ae4d53b9d3e9164f7138164df4291c484a7b14562075aaa7a2b7b"}, + {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c15e7d691cee75b5192fc1fa8487bf541d463246dc25c926b9b40f5b6ab56770"}, + {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:b9abc49c014def1b832fcd53bdc670474b6fe41f373d16f40409882c0d0eccba"}, + {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:3fd5472020042482d7da4c26a0ee65dbd931f691e1c838c6cf4232823179ecc1"}, + {file = "orjson-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e399ed1b0d6f8089b9b6ff2cb3e71ba63a56d8ea88e1d95467949795cc74adfd"}, + {file = "orjson-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5e3db6496463c3000d15b7a712da5a9601c6c43682f23f81862fe1d2a338f295"}, + {file = "orjson-3.8.1-cp37-none-win_amd64.whl", hash = "sha256:0f21eed14697083c01f7e00a87e21056fc8fb5851e8a7bca98345189abcdb4d4"}, + {file = "orjson-3.8.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:5a9e324213220578d324e0858baeab47808a13d3c3fbc6ba55a3f4f069d757cf"}, + {file = "orjson-3.8.1-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:69097c50c3ccbcc61292192b045927f1688ca57ce80525dc5d120e0b91e19bb0"}, + {file = "orjson-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7822cba140f7ca48ed0256229f422dbae69e3a3475176185db0c0538cfadb57"}, + {file = "orjson-3.8.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03389e3750c521a7f3d4837de23cfd21a7f24574b4b3985c9498f440d21adb03"}, + {file = "orjson-3.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f9d9b5c6692097de07dd0b2d5ff20fd135bacd1b2fb7ea383ee717a4150c93"}, + {file = "orjson-3.8.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:c2c9ef10b6344465fd5ac002be2d34f818211274dd79b44c75b2c14a979f84f3"}, + {file = "orjson-3.8.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7adaac93678ac61f5dc070f615b18639d16ee66f6a946d5221dbf315e8b74bec"}, + {file = "orjson-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b0c1750f73658906b82cabbf4be2f74300644c17cb037fbc8b48d746c3b90c76"}, + {file = "orjson-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:da6306e1f03e7085fe0db61d4a3377f70c6fd865118d0afe17f80ae9a8f6f124"}, + {file = "orjson-3.8.1-cp38-none-win_amd64.whl", hash = "sha256:f532c2cbe8c140faffaebcfb34d43c9946599ea8138971f181a399bec7d6b123"}, + {file = "orjson-3.8.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:6a7b76d4b44bca418f7797b1e157907b56b7d31caa9091db4e99ebee51c16933"}, + {file = "orjson-3.8.1-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:f850489d89ea12be486492e68f0fd63e402fa28e426d4f0b5fc1eec0595e6109"}, + {file = "orjson-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4449e70b98f3ad3e43958360e4be1189c549865c0a128e8629ec96ce92d251c3"}, + {file = "orjson-3.8.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:45357eea9114bd41ef19280066591e9069bb4f6f5bffd533e9bfc12a439d735f"}, + {file = "orjson-3.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f5a9bc5bc4d730153529cb0584c63ff286d50663ccd48c9435423660b1bb12d"}, + {file = "orjson-3.8.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:a806aca6b80fa1d996aa16593e4995a71126a085ee1a59fff19ccad29a4e47fd"}, + {file = "orjson-3.8.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:395d02fd6be45f960da014372e7ecefc9e5f8df57a0558b7111a5fa8423c0669"}, + {file = "orjson-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:caff3c1e964cfee044a03a46244ecf6373f3c56142ad16458a1446ac6d69824a"}, + {file = "orjson-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ded261268d5dfd307078fe3370295e5eb15bdde838bbb882acf8538e061c451"}, + {file = "orjson-3.8.1-cp39-none-win_amd64.whl", hash = "sha256:45c1914795ffedb2970bfcd3ed83daf49124c7c37943ed0a7368971c6ea5e278"}, + {file = "orjson-3.8.1.tar.gz", hash = "sha256:07c42de52dfef56cdcaf2278f58e837b26f5b5af5f1fd133a68c4af203851fc7"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -1652,24 +1643,20 @@ prometheus-fastapi-instrumentator = [ {file = "prometheus_fastapi_instrumentator-5.9.1-py3-none-any.whl", hash = "sha256:b5206ea9aa6975a0b07f3bf7376932b8a1b2983164b5abb04878e75ba336d9ed"}, ] protobuf = [ - {file = "protobuf-4.21.8-cp310-abi3-win32.whl", hash = "sha256:c252c55ee15175aa1b21b7b9896e6add5162d066d5202e75c39f96136f08cce3"}, - {file = "protobuf-4.21.8-cp310-abi3-win_amd64.whl", hash = "sha256:809ca0b225d3df42655a12f311dd0f4148a943c51f1ad63c38343e457492b689"}, - {file = "protobuf-4.21.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bbececaf3cfea9ea65ebb7974e6242d310d2a7772a6f015477e0d79993af4511"}, - {file = "protobuf-4.21.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:b02eabb9ebb1a089ed20626a90ad7a69cee6bcd62c227692466054b19c38dd1f"}, - {file = "protobuf-4.21.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:4761201b93e024bb70ee3a6a6425d61f3152ca851f403ba946fb0cde88872661"}, - {file = "protobuf-4.21.8-cp37-cp37m-win32.whl", hash = "sha256:f2d55ff22ec300c4d954d3b0d1eeb185681ec8ad4fbecff8a5aee6a1cdd345ba"}, - {file = "protobuf-4.21.8-cp37-cp37m-win_amd64.whl", hash = "sha256:c5f94911dd8feb3cd3786fc90f7565c9aba7ce45d0f254afd625b9628f578c3f"}, - {file = "protobuf-4.21.8-cp38-cp38-win32.whl", hash = "sha256:b37b76efe84d539f16cba55ee0036a11ad91300333abd213849cbbbb284b878e"}, - {file = "protobuf-4.21.8-cp38-cp38-win_amd64.whl", hash = "sha256:2c92a7bfcf4ae76a8ac72e545e99a7407e96ffe52934d690eb29a8809ee44d7b"}, - {file = "protobuf-4.21.8-cp39-cp39-win32.whl", hash = "sha256:89d641be4b5061823fa0e463c50a2607a97833e9f8cfb36c2f91ef5ccfcc3861"}, - {file = "protobuf-4.21.8-cp39-cp39-win_amd64.whl", hash = "sha256:bc471cf70a0f53892fdd62f8cd4215f0af8b3f132eeee002c34302dff9edd9b6"}, - {file = "protobuf-4.21.8-py2.py3-none-any.whl", hash = "sha256:a55545ce9eec4030cf100fcb93e861c622d927ef94070c1a3c01922902464278"}, - {file = "protobuf-4.21.8-py3-none-any.whl", hash = "sha256:0f236ce5016becd989bf39bd20761593e6d8298eccd2d878eda33012645dc369"}, - {file = "protobuf-4.21.8.tar.gz", hash = "sha256:427426593b55ff106c84e4a88cac855175330cb6eb7e889e85aaa7b5652b686d"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, + {file = "protobuf-4.21.9-cp310-abi3-win32.whl", hash = "sha256:6e0be9f09bf9b6cf497b27425487706fa48c6d1632ddd94dab1a5fe11a422392"}, + {file = "protobuf-4.21.9-cp310-abi3-win_amd64.whl", hash = "sha256:a7d0ea43949d45b836234f4ebb5ba0b22e7432d065394b532cdca8f98415e3cf"}, + {file = "protobuf-4.21.9-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b5ab0b8918c136345ff045d4b3d5f719b505b7c8af45092d7f45e304f55e50a1"}, + {file = "protobuf-4.21.9-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:2c9c2ed7466ad565f18668aa4731c535511c5d9a40c6da39524bccf43e441719"}, + {file = "protobuf-4.21.9-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:e575c57dc8b5b2b2caa436c16d44ef6981f2235eb7179bfc847557886376d740"}, + {file = "protobuf-4.21.9-cp37-cp37m-win32.whl", hash = "sha256:9227c14010acd9ae7702d6467b4625b6fe853175a6b150e539b21d2b2f2b409c"}, + {file = "protobuf-4.21.9-cp37-cp37m-win_amd64.whl", hash = "sha256:a419cc95fca8694804709b8c4f2326266d29659b126a93befe210f5bbc772536"}, + {file = "protobuf-4.21.9-cp38-cp38-win32.whl", hash = "sha256:5b0834e61fb38f34ba8840d7dcb2e5a2f03de0c714e0293b3963b79db26de8ce"}, + {file = "protobuf-4.21.9-cp38-cp38-win_amd64.whl", hash = "sha256:84ea107016244dfc1eecae7684f7ce13c788b9a644cd3fca5b77871366556444"}, + {file = "protobuf-4.21.9-cp39-cp39-win32.whl", hash = "sha256:f9eae277dd240ae19bb06ff4e2346e771252b0e619421965504bd1b1bba7c5fa"}, + {file = "protobuf-4.21.9-cp39-cp39-win_amd64.whl", hash = "sha256:6e312e280fbe3c74ea9e080d9e6080b636798b5e3939242298b591064470b06b"}, + {file = "protobuf-4.21.9-py2.py3-none-any.whl", hash = "sha256:7eb8f2cc41a34e9c956c256e3ac766cf4e1a4c9c925dc757a41a01be3e852965"}, + {file = "protobuf-4.21.9-py3-none-any.whl", hash = "sha256:48e2cd6b88c6ed3d5877a3ea40df79d08374088e89bedc32557348848dff250b"}, + {file = "protobuf-4.21.9.tar.gz", hash = "sha256:61f21493d96d2a77f9ca84fefa105872550ab5ef71d21c458eb80edcf4885a99"}, ] pyalpm = [ {file = "pyalpm-0.10.6.tar.gz", hash = "sha256:99e6ec73b8c46bb12466013f228f831ee0d18e8ab664b91a01c2a3c40de07c7f"}, @@ -1760,8 +1747,8 @@ pyparsing = [ {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] pytest = [ - {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, - {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, + {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, + {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, ] pytest-asyncio = [ {file = "pytest-asyncio-0.20.1.tar.gz", hash = "sha256:626699de2a747611f3eeb64168b3575f70439b06c3d0206e6ceaeeb956e65519"}, @@ -1771,17 +1758,13 @@ pytest-cov = [ {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, ] -pytest-forked = [ - {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, - {file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"}, -] pytest-tap = [ {file = "pytest-tap-3.3.tar.gz", hash = "sha256:5f0919a147cf0396b2f10d64d365a0bf8062e06543e93c675c9d37f5605e983c"}, {file = "pytest_tap-3.3-py3-none-any.whl", hash = "sha256:4fbbc0e090c2e94f6199bee4e4f68ab3c5e176b37a72a589ad84e0f72a2fce55"}, ] pytest-xdist = [ - {file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"}, - {file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"}, + {file = "pytest-xdist-3.0.2.tar.gz", hash = "sha256:688da9b814370e891ba5de650c9327d1a9d861721a524eb917e620eec3e90291"}, + {file = "pytest_xdist-3.0.2-py3-none-any.whl", hash = "sha256:9feb9a18e1790696ea23e1434fa73b325ed4998b0e9fcb221f16fd1945e6df1b"}, ] python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, @@ -1972,6 +1955,6 @@ wsproto = [ {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, ] zipp = [ - {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, - {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, + {file = "zipp-3.10.0-py3-none-any.whl", hash = "sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1"}, + {file = "zipp-3.10.0.tar.gz", hash = "sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"}, ] diff --git a/pyproject.toml b/pyproject.toml index 3b615c73..0bf1bdf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,13 +62,13 @@ asgiref = "^3.4.1" bcrypt = "^4.0.0" bleach = "^5.0.0" email-validator = "^1.3.0" -fakeredis = "^1.6.1" +fakeredis = "^1.10.0" feedgen = "^0.9.0" httpx = "^0.23.0" itsdangerous = "^2.0.1" lxml = "^4.6.3" -orjson = "^3.6.4" -protobuf = "^4.0.0" +orjson = "^3.8.1" +protobuf = "^4.21.9" pygit2 = "^1.7.0" python-multipart = "^0.0.5" redis = "^4.0.0" @@ -89,7 +89,7 @@ uvicorn = "^0.19.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.0" prometheus-fastapi-instrumentator = "^5.7.1" -pytest-xdist = "^2.4.0" +pytest-xdist = "^3.0.2" filelock = "^3.3.2" posix-ipc = "^1.0.5" pyalpm = "^0.10.6" @@ -98,7 +98,7 @@ srcinfo = "^0.0.8" [tool.poetry.dev-dependencies] coverage = "^6.0.2" -pytest = "^7.0.0" +pytest = "^7.2.0" pytest-asyncio = "^0.20.1" pytest-cov = "^4.0.0" pytest-tap = "^3.2" From c0e806072e705652f0eb6d22dff1f64ab8735dcd Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 1 Nov 2022 18:31:37 +0000 Subject: [PATCH 1623/1891] chore: bump to v6.1.8 Signed-off-by: Leonidas Spyropoulos --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index e8ca70d9..49806738 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.7" +AURWEB_VERSION = "v6.1.8" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 0bf1bdf8..7fc0db47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.7" +version = "v6.1.8" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 4f56a0166208b781adc13da53bc001e376379b57 Mon Sep 17 00:00:00 2001 From: Lex Black Date: Fri, 4 Nov 2022 08:47:03 +0100 Subject: [PATCH 1624/1891] chore: fix mailing-lists urls Those changed after the migration to mailman3 Signed-off-by: Leonidas Spyropoulos --- templates/home.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/home.html b/templates/home.html index 6a5fca69..3a7bc76d 100644 --- a/templates/home.html +++ b/templates/home.html @@ -42,7 +42,7 @@

    {{ "If you want to discuss a request, you can use the %saur-requests%s mailing list. However, please do not use that list to file requests." | tr - | format('', "") + | format('', "") | safe }}

    @@ -72,8 +72,8 @@

    {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." | tr - | format('', "", - '', "") + | format('', "", + '', "") | safe }}

    From c248a74f80d5c72bd6a01f5dfc7ee1c05b2bc6a5 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 7 Nov 2022 14:36:34 +0100 Subject: [PATCH 1625/1891] chore: fix mailing-list URL on passreset page small addition to the patch provided in #404 Signed-off-by: moson-mo --- templates/passreset.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/passreset.html b/templates/passreset.html index d2c3c2ee..6a31109f 100644 --- a/templates/passreset.html +++ b/templates/passreset.html @@ -47,7 +47,7 @@ {% else %} - {% set url = "https://mailman.archlinux.org/mailman/listinfo/aur-general" %} + {% set url = "https://lists.archlinux.org/mailman3/lists/aur-general.lists.archlinux.org/" %} {{ "If you have forgotten the user name and the primary e-mail " "address you used to register, please send a message to the " "%saur-general%s mailing list." From 73f0bddf0b52bc79ef29b5eaf20f2af8d305528b Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 8 Nov 2022 13:14:42 +0000 Subject: [PATCH 1626/1891] fix: handle default requests when using pages The default page shows the pending requests which were working OK if one used the Filters button. This fixes the case when someone submits by using the pager (Next, Last etc). Closes: #405 Signed-off-by: Leonidas Spyropoulos --- aurweb/routers/requests.py | 10 +++++++-- test/test_requests.py | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index ca5fae73..d1f1b830 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -18,6 +18,13 @@ from aurweb.requests.util import get_pkgreq_by_id from aurweb.scripts import notify from aurweb.templates import make_context, render_template +FILTER_PARAMS = { + "filter_pending", + "filter_closed", + "filter_accepted", + "filter_rejected", +} + router = APIRouter() @@ -36,7 +43,7 @@ async def requests( context["q"] = dict(request.query_params) - if len(dict(request.query_params)) == 0: + if not dict(request.query_params).keys() & FILTER_PARAMS: filter_pending = True O, PP = util.sanitize_params(O, PP) @@ -89,7 +96,6 @@ async def requests( .offset(O) .all() ) - return render_template(request, "requests.html", context) diff --git a/test/test_requests.py b/test/test_requests.py index 344b9edc..7dfcf5e5 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -734,6 +734,52 @@ def test_requests( rows = root.xpath('//table[@class="results"]/tbody/tr') assert len(rows) == defaults.PP + # Request page 2 of the requests page. + with client as request: + resp = request.get("/requests", params={"O": 50}, cookies=cookies) # Page 2 + assert resp.status_code == int(HTTPStatus.OK) + + assert "‹ Previous" in resp.text + assert "« First" in resp.text + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 5 # There are five records left on the second page. + + +def test_requests_with_filters( + client: TestClient, + tu_user: User, + packages: list[Package], + requests: list[PackageRequest], +): + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + resp = request.get( + "/requests", + params={ + # Pass in url query parameters O, SeB and SB to exercise + # their paths inside of the pager_nav used in this request. + "O": 0, # Page 1 + "SeB": "nd", + "SB": "n", + "filter_pending": True, + "filter_closed": True, + "filter_accepted": True, + "filter_rejected": True, + }, + cookies=cookies, + ) + assert resp.status_code == int(HTTPStatus.OK) + + assert "Next ›" in resp.text + assert "Last »" in resp.text + + root = parse_root(resp.text) + # We have 55 requests, our defaults.PP is 50, so expect we have 50 rows. + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == defaults.PP + # Request page 2 of the requests page. with client as request: resp = request.get( From 50287cb066c02de5337f87508e51852d4a1e5ccb Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 7 Nov 2022 14:19:38 +0100 Subject: [PATCH 1627/1891] feat(rpc): add "by" parameters - package relations This adds new "by" search-parameters: provides, conflicts and replaces Signed-off-by: moson-mo --- aurweb/packages/search.py | 34 ++++++++++++++++++++++++++++++++++ aurweb/rpc.py | 3 +++ test/test_rpc.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 224212d1..7e767bde 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -14,6 +14,7 @@ from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_keyword import PackageKeyword from aurweb.models.package_notification import PackageNotification from aurweb.models.package_vote import PackageVote +from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID class PackageSearch: @@ -286,6 +287,9 @@ class RPCSearch(PackageSearch): "makedepends": self._search_by_makedepends, "optdepends": self._search_by_optdepends, "checkdepends": self._search_by_checkdepends, + "provides": self._search_by_provides, + "conflicts": self._search_by_conflicts, + "replaces": self._search_by_replaces, } ) @@ -304,6 +308,18 @@ class RPCSearch(PackageSearch): ) return self.query + def _join_relations(self, rel_type_id: int) -> orm.Query: + """Join Package with PackageRelation and filter results + based on `rel_type_id`. + + :param rel_type_id: RelationType ID + :returns: PackageRelation-joined orm.Query + """ + self.query = self.query.join(models.PackageRelation).filter( + models.PackageRelation.RelTypeID == rel_type_id + ) + return self.query + def _search_by_depends(self, keywords: str) -> "RPCSearch": self.query = self._join_depends(DEPENDS_ID).filter( models.PackageDependency.DepName == keywords @@ -328,6 +344,24 @@ class RPCSearch(PackageSearch): ) return self + def _search_by_provides(self, keywords: str) -> "RPCSearch": + self.query = self._join_relations(PROVIDES_ID).filter( + models.PackageRelation.RelName == keywords + ) + return self + + def _search_by_conflicts(self, keywords: str) -> "RPCSearch": + self.query = self._join_relations(CONFLICTS_ID).filter( + models.PackageRelation.RelName == keywords + ) + return self + + def _search_by_replaces(self, keywords: str) -> "RPCSearch": + self.query = self._join_relations(REPLACES_ID).filter( + models.PackageRelation.RelName == keywords + ) + return self + def search_by(self, by: str, keywords: str) -> "RPCSearch": """Override inherited search_by. In this override, we reduce the scope of what we handle within this function. We do not set `by` diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 515c6ffb..9004a51f 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -83,6 +83,9 @@ class RPC: "makedepends", "optdepends", "checkdepends", + "provides", + "conflicts", + "replaces", } # A mapping of by aliases. diff --git a/test/test_rpc.py b/test/test_rpc.py index f417d379..c5004f07 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -852,6 +852,42 @@ def test_rpc_search_checkdepends( assert result.get("Name") == packages[0].Name +def test_rpc_search_provides( + client: TestClient, packages: list[Package], relations: list[PackageRelation] +): + params = {"v": 5, "type": "search", "by": "provides", "arg": "chungus-provides"} + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == packages[0].Name + + +def test_rpc_search_conflicts( + client: TestClient, packages: list[Package], relations: list[PackageRelation] +): + params = {"v": 5, "type": "search", "by": "conflicts", "arg": "chungus-conflicts"} + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == packages[0].Name + + +def test_rpc_search_replaces( + client: TestClient, packages: list[Package], relations: list[PackageRelation] +): + params = {"v": 5, "type": "search", "by": "replaces", "arg": "chungus-replaces"} + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == packages[0].Name + + def test_rpc_incorrect_by(client: TestClient): params = {"v": 5, "type": "search", "by": "fake", "arg": "big"} with client as request: From 0583f30a53880b8908dd3746bf81b8f560bc09b2 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 7 Nov 2022 21:41:42 +0100 Subject: [PATCH 1628/1891] feat(rpc): add "by" parameter - groups Adding "by" parameter to search by "groups" Signed-off-by: moson-mo --- aurweb/packages/search.py | 17 ++++++++++++++++- aurweb/rpc.py | 1 + test/test_rpc.py | 25 ++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 7e767bde..60e9f0fc 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -3,7 +3,7 @@ from typing import Set from sqlalchemy import and_, case, or_, orm from aurweb import db, models -from aurweb.models import Package, PackageBase, User +from aurweb.models import Group, Package, PackageBase, User from aurweb.models.dependency_type import ( CHECKDEPENDS_ID, DEPENDS_ID, @@ -11,6 +11,7 @@ from aurweb.models.dependency_type import ( OPTDEPENDS_ID, ) from aurweb.models.package_comaintainer import PackageComaintainer +from aurweb.models.package_group import PackageGroup from aurweb.models.package_keyword import PackageKeyword from aurweb.models.package_notification import PackageNotification from aurweb.models.package_vote import PackageVote @@ -290,6 +291,7 @@ class RPCSearch(PackageSearch): "provides": self._search_by_provides, "conflicts": self._search_by_conflicts, "replaces": self._search_by_replaces, + "groups": self._search_by_groups, } ) @@ -320,6 +322,14 @@ class RPCSearch(PackageSearch): ) return self.query + def _join_groups(self) -> orm.Query: + """Join Package with PackageGroup and Group. + + :returns: PackageGroup/Group-joined orm.Query + """ + self.query = self.query.join(PackageGroup).join(Group) + return self.query + def _search_by_depends(self, keywords: str) -> "RPCSearch": self.query = self._join_depends(DEPENDS_ID).filter( models.PackageDependency.DepName == keywords @@ -362,6 +372,11 @@ class RPCSearch(PackageSearch): ) return self + def _search_by_groups(self, keywords: str) -> orm.Query: + self._join_groups() + self.query = self.query.filter(Group.Name == keywords) + return self + def search_by(self, by: str, keywords: str) -> "RPCSearch": """Override inherited search_by. In this override, we reduce the scope of what we handle within this function. We do not set `by` diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 9004a51f..5cdf675d 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -86,6 +86,7 @@ class RPC: "provides", "conflicts", "replaces", + "groups", } # A mapping of by aliases. diff --git a/test/test_rpc.py b/test/test_rpc.py index c5004f07..bbd74588 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -13,10 +13,12 @@ from aurweb import asgi, config, db, rpc, scripts, time from aurweb.aur_redis import redis_connection from aurweb.models.account_type import USER_ID from aurweb.models.dependency_type import DEPENDS_ID +from aurweb.models.group import Group from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency +from aurweb.models.package_group import PackageGroup from aurweb.models.package_keyword import PackageKeyword from aurweb.models.package_license import PackageLicense from aurweb.models.package_relation import PackageRelation @@ -139,11 +141,14 @@ def packages(user: User, user2: User, user3: User) -> list[Package]: output.append(pkg) # Setup a few more related records on the first package: - # a license, some keywords and some votes. + # a license, group, some keywords and some votes. with db.begin(): lic = db.create(License, Name="GPL") db.create(PackageLicense, Package=output[0], License=lic) + grp = db.create(Group, Name="testgroup") + db.create(PackageGroup, Package=output[0], Group=grp) + for keyword in ["big-chungus", "smol-chungus", "sizeable-chungus"]: db.create( PackageKeyword, PackageBase=output[0].PackageBase, Keyword=keyword @@ -326,6 +331,7 @@ def test_rpc_singular_info( "Replaces": ["chungus-replaces<=200"], "License": [pkg.package_licenses.first().License.Name], "Keywords": ["big-chungus", "sizeable-chungus", "smol-chungus"], + "Groups": ["testgroup"], } ], "resultcount": 1, @@ -888,6 +894,23 @@ def test_rpc_search_replaces( assert result.get("Name") == packages[0].Name +def test_rpc_search_groups( + client: TestClient, packages: list[Package], depends: list[PackageDependency] +): + params = { + "v": 5, + "type": "search", + "by": "groups", + "arg": "testgroup", + } + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == packages[0].Name + + def test_rpc_incorrect_by(client: TestClient): params = {"v": 5, "type": "search", "by": "fake", "arg": "big"} with client as request: From 5484e68b42392c95a90a3425841419a5782c412a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 7 Nov 2022 22:46:24 +0100 Subject: [PATCH 1629/1891] feat(rpc): add "by" parameter - submitter Add "by" parameter: submitter Signed-off-by: moson-mo --- aurweb/packages/search.py | 2 +- aurweb/rpc.py | 3 ++- test/test_rpc.py | 31 +++++++++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 60e9f0fc..51d97d8e 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -269,7 +269,7 @@ class RPCSearch(PackageSearch): sanitization done for the PackageSearch `by` argument. """ - keys_removed = ("b", "N", "B", "k", "c", "M", "s") + keys_removed = ("b", "N", "B", "k", "c", "M") def __init__(self) -> "RPCSearch": super().__init__() diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 5cdf675d..fa36486e 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -87,10 +87,11 @@ class RPC: "conflicts", "replaces", "groups", + "submitter", } # A mapping of by aliases. - BY_ALIASES = {"name-desc": "nd", "name": "n", "maintainer": "m"} + BY_ALIASES = {"name-desc": "nd", "name": "n", "maintainer": "m", "submitter": "s"} def __init__(self, version: int = 0, type: str = None) -> "RPC": self.version = version diff --git a/test/test_rpc.py b/test/test_rpc.py index bbd74588..5d59d16b 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -81,7 +81,11 @@ def packages(user: User, user2: User, user3: User) -> list[Package]: # Create package records used in our tests. with db.begin(): pkgbase = db.create( - PackageBase, Name="big-chungus", Maintainer=user, Packager=user + PackageBase, + Name="big-chungus", + Maintainer=user, + Packager=user, + Submitter=user2, ) pkg = db.create( Package, @@ -93,7 +97,11 @@ def packages(user: User, user2: User, user3: User) -> list[Package]: output.append(pkg) pkgbase = db.create( - PackageBase, Name="chungy-chungus", Maintainer=user, Packager=user + PackageBase, + Name="chungy-chungus", + Maintainer=user, + Packager=user, + Submitter=user2, ) pkg = db.create( Package, @@ -911,6 +919,25 @@ def test_rpc_search_groups( assert result.get("Name") == packages[0].Name +def test_rpc_search_submitter(client: TestClient, user2: User, packages: list[Package]): + params = {"v": 5, "type": "search", "by": "submitter", "arg": user2.Username} + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + + # user2 submitted 2 packages + assert data.get("resultcount") == 2 + names = list(sorted(r.get("Name") for r in data.get("results"))) + expected_results = ["big-chungus", "chungy-chungus"] + assert names == expected_results + + # Search for a non-existent submitter, giving us zero packages. + params["arg"] = "blah-blah" + response = request.get("/rpc", params=params) + data = response.json() + assert data.get("resultcount") == 0 + + def test_rpc_incorrect_by(client: TestClient): params = {"v": 5, "type": "search", "by": "fake", "arg": "big"} with client as request: From efd20ed2c740910996e9f1aa7e24a2337be4db11 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 8 Nov 2022 15:26:27 +0100 Subject: [PATCH 1630/1891] feat(rpc): add "by" parameter - keywords Add "by" parameter: keywords Signed-off-by: moson-mo --- aurweb/packages/search.py | 9 +++++++-- aurweb/rpc.py | 9 ++++++++- test/test_rpc.py | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 51d97d8e..37a5b6ff 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -269,7 +269,7 @@ class RPCSearch(PackageSearch): sanitization done for the PackageSearch `by` argument. """ - keys_removed = ("b", "N", "B", "k", "c", "M") + keys_removed = ("b", "N", "B", "c", "M") def __init__(self) -> "RPCSearch": super().__init__() @@ -372,11 +372,16 @@ class RPCSearch(PackageSearch): ) return self - def _search_by_groups(self, keywords: str) -> orm.Query: + def _search_by_groups(self, keywords: str) -> "RPCSearch": self._join_groups() self.query = self.query.filter(Group.Name == keywords) return self + def _search_by_keywords(self, keywords: str) -> "RPCSearch": + self._join_keywords() + self.query = self.query.filter(PackageKeyword.Keyword == keywords) + return self + def search_by(self, by: str, keywords: str) -> "RPCSearch": """Override inherited search_by. In this override, we reduce the scope of what we handle within this function. We do not set `by` diff --git a/aurweb/rpc.py b/aurweb/rpc.py index fa36486e..2a07f6c7 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -88,10 +88,17 @@ class RPC: "replaces", "groups", "submitter", + "keywords", } # A mapping of by aliases. - BY_ALIASES = {"name-desc": "nd", "name": "n", "maintainer": "m", "submitter": "s"} + BY_ALIASES = { + "name-desc": "nd", + "name": "n", + "maintainer": "m", + "submitter": "s", + "keywords": "k", + } def __init__(self, version: int = 0, type: str = None) -> "RPC": self.version = version diff --git a/test/test_rpc.py b/test/test_rpc.py index 5d59d16b..9c3ca883 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -938,6 +938,25 @@ def test_rpc_search_submitter(client: TestClient, user2: User, packages: list[Pa assert data.get("resultcount") == 0 +def test_rpc_search_keywords(client: TestClient, packages: list[Package]): + params = {"v": 5, "type": "search", "by": "keywords", "arg": "big-chungus"} + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + + # should get 2 packages + assert data.get("resultcount") == 1 + names = list(sorted(r.get("Name") for r in data.get("results"))) + expected_results = ["big-chungus"] + assert names == expected_results + + # non-existent search + params["arg"] = "blah-blah" + response = request.get("/rpc", params=params) + data = response.json() + assert data.get("resultcount") == 0 + + def test_rpc_incorrect_by(client: TestClient): params = {"v": 5, "type": "search", "by": "fake", "arg": "big"} with client as request: From bcd808ddc11c570d9259a93a69d165403e48230e Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 8 Nov 2022 16:44:59 +0100 Subject: [PATCH 1631/1891] feat(rpc): add "by" parameter - comaintainers Add "by" parameter: comaintainers Signed-off-by: moson-mo --- aurweb/packages/search.py | 2 +- aurweb/rpc.py | 2 ++ test/test_rpc.py | 31 ++++++++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 37a5b6ff..c0740cda 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -269,7 +269,7 @@ class RPCSearch(PackageSearch): sanitization done for the PackageSearch `by` argument. """ - keys_removed = ("b", "N", "B", "c", "M") + keys_removed = ("b", "N", "B", "M") def __init__(self) -> "RPCSearch": super().__init__() diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 2a07f6c7..34caf756 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -89,6 +89,7 @@ class RPC: "groups", "submitter", "keywords", + "comaintainers", } # A mapping of by aliases. @@ -98,6 +99,7 @@ class RPC: "maintainer": "m", "submitter": "s", "keywords": "k", + "comaintainers": "c", } def __init__(self, version: int = 0, type: str = None) -> "RPC": diff --git a/test/test_rpc.py b/test/test_rpc.py index 9c3ca883..4768a2da 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -17,6 +17,7 @@ from aurweb.models.group import Group from aurweb.models.license import License from aurweb.models.package import Package from aurweb.models.package_base import PackageBase +from aurweb.models.package_comaintainer import PackageComaintainer from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_group import PackageGroup from aurweb.models.package_keyword import PackageKeyword @@ -149,7 +150,7 @@ def packages(user: User, user2: User, user3: User) -> list[Package]: output.append(pkg) # Setup a few more related records on the first package: - # a license, group, some keywords and some votes. + # a license, group, some keywords, comaintainer and some votes. with db.begin(): lic = db.create(License, Name="GPL") db.create(PackageLicense, Package=output[0], License=lic) @@ -157,6 +158,13 @@ def packages(user: User, user2: User, user3: User) -> list[Package]: grp = db.create(Group, Name="testgroup") db.create(PackageGroup, Package=output[0], Group=grp) + db.create( + PackageComaintainer, + PackageBase=output[0].PackageBase, + User=user2, + Priority=1, + ) + for keyword in ["big-chungus", "smol-chungus", "sizeable-chungus"]: db.create( PackageKeyword, PackageBase=output[0].PackageBase, Keyword=keyword @@ -957,6 +965,27 @@ def test_rpc_search_keywords(client: TestClient, packages: list[Package]): assert data.get("resultcount") == 0 +def test_rpc_search_comaintainers( + client: TestClient, user2: User, packages: list[Package] +): + params = {"v": 5, "type": "search", "by": "comaintainers", "arg": user2.Username} + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + + # should get 1 package + assert data.get("resultcount") == 1 + names = list(sorted(r.get("Name") for r in data.get("results"))) + expected_results = ["big-chungus"] + assert names == expected_results + + # non-existent search + params["arg"] = "blah-blah" + response = request.get("/rpc", params=params) + data = response.json() + assert data.get("resultcount") == 0 + + def test_rpc_incorrect_by(client: TestClient): params = {"v": 5, "type": "search", "by": "fake", "arg": "big"} with client as request: From 500d6b403b827e51e602818bb17e4ecbcd2b5842 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 4 Nov 2022 14:09:09 +0000 Subject: [PATCH 1632/1891] feat: add co-maintainers to RPC Signed-off-by: Leonidas Spyropoulos --- aurweb/rpc.py | 16 ++++++++++++++++ test/test_rpc.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 34caf756..af31d2de 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -284,6 +284,22 @@ class RPC: ) .distinct() .order_by("Name"), + # Co-Maintainer + db.query(models.PackageComaintainer) + .join(models.User, models.User.ID == models.PackageComaintainer.UsersID) + .join( + models.Package, + models.Package.PackageBaseID + == models.PackageComaintainer.PackageBaseID, + ) + .with_entities( + models.Package.ID, + literal("CoMaintainers").label("Type"), + models.User.Username.label("Name"), + literal(str()).label("Cond"), + ) + .distinct() # A package could have the same co-maintainer multiple times + .order_by("Name"), ] # Union all subqueries together. diff --git a/test/test_rpc.py b/test/test_rpc.py index 4768a2da..424352db 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -272,6 +272,33 @@ def relations(user: User, packages: list[Package]) -> list[PackageRelation]: yield output +@pytest.fixture +def comaintainer( + user2: User, user3: User, packages: list[Package] +) -> list[PackageComaintainer]: + output = [] + + with db.begin(): + comaintainer = db.create( + PackageComaintainer, + User=user2, + PackageBase=packages[0].PackageBase, + Priority=1, + ) + output.append(comaintainer) + + comaintainer = db.create( + PackageComaintainer, + User=user3, + PackageBase=packages[0].PackageBase, + Priority=1, + ) + output.append(comaintainer) + + # Finally, yield the packages. + yield output + + @pytest.fixture(autouse=True) def setup(db_test): # Create some extra package relationships. @@ -321,6 +348,7 @@ def test_rpc_singular_info( packages: list[Package], depends: list[PackageDependency], relations: list[PackageRelation], + comaintainer: list[PackageComaintainer], ): # Define expected response. pkg = packages[0] @@ -343,6 +371,7 @@ def test_rpc_singular_info( "MakeDepends": ["chungus-makedepends"], "CheckDepends": ["chungus-checkdepends"], "Conflicts": ["chungus-conflicts"], + "CoMaintainers": ["user2", "user3"], "Provides": ["chungus-provides<=200"], "Replaces": ["chungus-replaces<=200"], "License": [pkg.package_licenses.first().License.Name], From bce5b81acd2b2dfcdfaf46ae962241e7dbe61ef9 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 10 Nov 2022 21:28:16 +0000 Subject: [PATCH 1633/1891] feat: allow filtering requests from maintainers These are usually easy to handle from TUs so allow to filter for them Signed-off-by: Leonidas Spyropoulos --- aurweb/routers/requests.py | 19 +++++++++++--- pytest.ini | 11 +++----- templates/requests.html | 5 ++++ test/test_requests.py | 53 ++++++++++++++++++++++++++++++++------ 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index d1f1b830..6880abd9 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -2,12 +2,12 @@ from http import HTTPStatus from fastapi import APIRouter, Form, Query, Request from fastapi.responses import RedirectResponse -from sqlalchemy import case +from sqlalchemy import case, orm from aurweb import db, defaults, time, util from aurweb.auth import creds, requires_auth from aurweb.exceptions import handle_form_exceptions -from aurweb.models import PackageRequest +from aurweb.models import PackageBase, PackageRequest, User from aurweb.models.package_request import ( ACCEPTED_ID, CLOSED_ID, @@ -23,6 +23,7 @@ FILTER_PARAMS = { "filter_closed", "filter_accepted", "filter_rejected", + "filter_maintainers_requests", } router = APIRouter() @@ -38,6 +39,7 @@ async def requests( filter_closed: bool = False, filter_accepted: bool = False, filter_rejected: bool = False, + filter_maintainer_requests: bool = False, ): context = make_context(request, "Requests") @@ -53,9 +55,17 @@ async def requests( context["filter_closed"] = filter_closed context["filter_accepted"] = filter_accepted context["filter_rejected"] = filter_rejected + context["filter_maintainer_requests"] = filter_maintainer_requests + Maintainer = orm.aliased(User) # A PackageRequest query - query = db.query(PackageRequest) + query = ( + db.query(PackageRequest) + .join(PackageBase) + .join(User, PackageRequest.UsersID == User.ID, isouter=True) + .join(Maintainer, PackageBase.MaintainerUID == Maintainer.ID, isouter=True) + ) + # query = db.query(PackageRequest).join(User) # Requests statistics context["total_requests"] = query.count() @@ -79,6 +89,9 @@ async def requests( if filter_rejected: in_filters.append(REJECTED_ID) filtered = query.filter(PackageRequest.Status.in_(in_filters)) + # Additionally filter for requests made from package maintainer + if filter_maintainer_requests: + filtered = filtered.filter(PackageRequest.UsersID == PackageBase.MaintainerUID) # If the request user is not elevated (TU or Dev), then # filter PackageRequests which are owned by the request user. if not request.user.is_elevated(): diff --git a/pytest.ini b/pytest.ini index 9f70a2bd..62d1922a 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,13 +1,8 @@ [pytest] -# Ignore the following DeprecationWarning(s): -# - asyncio.base_events -# - DeprecationWarning speaking about internal asyncio -# using the loop= argument being deprecated starting -# with python 3.8, before python 3.10. -# - Note: This is a bug in upstream filed at -# https://bugs.python.org/issue45097 filterwarnings = - ignore::DeprecationWarning:asyncio.base_events + # This is coming from https://github.com/pytest-dev/pytest-xdist/issues/825 and it's caused from pytest-cov + # Remove once fixed: https://github.com/pytest-dev/pytest-cov/issues/557 + ignore:The --rsyncdir command line argument and rsyncdirs config variable are deprecated.:DeprecationWarning # Build in coverage and pytest-xdist multiproc testing. addopts = --cov=aurweb --cov-append --dist load --dist loadfile -n auto diff --git a/templates/requests.html b/templates/requests.html index 9037855c..669b46b0 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -56,6 +56,11 @@ +

    + + +
    diff --git a/test/test_requests.py b/test/test_requests.py index 7dfcf5e5..6475fae6 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -96,7 +96,21 @@ def maintainer() -> User: @pytest.fixture -def packages(maintainer: User) -> list[Package]: +def maintainer2() -> User: + """Yield a specific User used to maintain packages.""" + with db.begin(): + maintainer = db.create( + User, + Username="test_maintainer2", + Email="test_maintainer2@example.org", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) + yield maintainer + + +@pytest.fixture +def packages(maintainer: User, maintainer2: User) -> list[Package]: """Yield 55 packages named pkg_0 .. pkg_54.""" packages_ = [] now = time.utcnow() @@ -105,7 +119,7 @@ def packages(maintainer: User) -> list[Package]: pkgbase = db.create( PackageBase, Name=f"pkg_{i}", - Maintainer=maintainer, + Maintainer=maintainer2 if i > 52 else maintainer, Packager=maintainer, Submitter=maintainer, ModifiedTS=now, @@ -117,14 +131,18 @@ def packages(maintainer: User) -> list[Package]: @pytest.fixture -def requests(user: User, packages: list[Package]) -> list[PackageRequest]: +def requests( + user: User, maintainer2: User, packages: list[Package] +) -> list[PackageRequest]: pkgreqs = [] with db.begin(): for i in range(55): pkgreq = db.create( PackageRequest, ReqTypeID=DELETION_ID, - User=user, + User=maintainer2 + if packages[i].PackageBase.Maintainer.Username == "test_maintainer2" + else user, PackageBase=packages[i].PackageBase, PackageBaseName=packages[i].Name, Comments=f"Deletion request for pkg_{i}", @@ -717,10 +735,6 @@ def test_requests( "O": 0, # Page 1 "SeB": "nd", "SB": "n", - "filter_pending": True, - "filter_closed": True, - "filter_accepted": True, - "filter_rejected": True, }, cookies=cookies, ) @@ -767,6 +781,7 @@ def test_requests_with_filters( "filter_closed": True, "filter_accepted": True, "filter_rejected": True, + "filter_maintainer_requests": False, }, cookies=cookies, ) @@ -790,6 +805,7 @@ def test_requests_with_filters( "filter_closed": True, "filter_accepted": True, "filter_rejected": True, + "filter_maintainer_requests": False, }, cookies=cookies, ) # Page 2 @@ -803,6 +819,27 @@ def test_requests_with_filters( assert len(rows) == 5 # There are five records left on the second page. +def test_requests_for_maintainer_requests( + client: TestClient, + tu_user: User, + packages: list[Package], + requests: list[PackageRequest], +): + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + resp = request.get( + "/requests", + params={"filter_maintainer_requests": True}, + cookies=cookies, + ) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + # We only expect 2 requests since we are looking for requests from the maintainers + assert len(rows) == 2 + + def test_requests_by_deleted_users( client: TestClient, user: User, tu_user: User, pkgreq: PackageRequest ): From ff92e95f7a36bd51afa7f5108c9f3ff758d43cba Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 21 Nov 2022 13:39:43 +0000 Subject: [PATCH 1634/1891] fix: delete associated ssh public keys with account deletion Signed-off-by: Leonidas Spyropoulos --- aurweb/models/ssh_pub_key.py | 2 +- test/test_accounts_routes.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/aurweb/models/ssh_pub_key.py b/aurweb/models/ssh_pub_key.py index a2af34f4..c0b59445 100644 --- a/aurweb/models/ssh_pub_key.py +++ b/aurweb/models/ssh_pub_key.py @@ -13,7 +13,7 @@ class SSHPubKey(Base): User = relationship( "User", - backref=backref("ssh_pub_keys", lazy="dynamic"), + backref=backref("ssh_pub_keys", lazy="dynamic", cascade="all, delete"), foreign_keys=[__table__.c.UserID], ) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 33baa0ea..f44fd44e 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -2032,6 +2032,37 @@ def test_account_delete_self(client: TestClient, user: User): assert record is None +def test_account_delete_self_with_ssh_public_key(client: TestClient, user: User): + username = user.Username + + with db.begin(): + db.create( + SSHPubKey, User=user, Fingerprint="testFingerprint", PubKey="testPubKey" + ) + + # Confirm that we can view our own account deletion page + cookies = {"AURSID": user.login(Request(), "testPassword")} + endpoint = f"/account/{username}/delete" + with client as request: + resp = request.get(endpoint, cookies=cookies) + assert resp.status_code == HTTPStatus.OK + + # Supply everything correctly and delete ourselves + with client as request: + resp = request.post( + endpoint, + data={"passwd": "testPassword", "confirm": True}, + cookies=cookies, + ) + assert resp.status_code == HTTPStatus.SEE_OTHER + + # Check that our User record no longer exists in the database + user_record = db.query(User).filter(User.Username == username).first() + assert user_record is None + sshpubkey_record = db.query(SSHPubKey).filter(SSHPubKey.User == user).first() + assert sshpubkey_record is None + + def test_account_delete_as_tu(client: TestClient, tu_user: User): with db.begin(): user = create_user("user2") From d5e102e3f4622b4c55edd75bb086ae9f764a71c9 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 22 Nov 2022 18:39:15 +0100 Subject: [PATCH 1635/1891] feat: add "Submitter" field to /rpc info request Signed-off-by: moson-mo --- aurweb/rpc.py | 54 +++++++++++++++++++++++++++++++++--------------- test/test_rpc.py | 5 +++++ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index af31d2de..2aa27500 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -154,6 +154,7 @@ class RPC: "PackageBase": package.PackageBaseName, # Maintainer should be set following this update if one exists. "Maintainer": package.Maintainer, + "Submitter": package.Submitter, "Version": package.Version, "Description": package.Description, "URL": package.URL, @@ -192,22 +193,35 @@ class RPC: def entities(self, query: orm.Query) -> orm.Query: """Select specific RPC columns on `query`.""" - return query.with_entities( - models.Package.ID, - models.Package.Name, - models.Package.Version, - models.Package.Description, - models.Package.URL, - models.Package.PackageBaseID, - models.PackageBase.Name.label("PackageBaseName"), - models.PackageBase.NumVotes, - models.PackageBase.Popularity, - models.PackageBase.PopularityUpdated, - models.PackageBase.OutOfDateTS, - models.PackageBase.SubmittedTS, - models.PackageBase.ModifiedTS, - models.User.Username.label("Maintainer"), - ).group_by(models.Package.ID) + Submitter = orm.aliased(models.User) + + query = ( + query.join( + Submitter, + Submitter.ID == models.PackageBase.SubmitterUID, + isouter=True, + ) + .with_entities( + models.Package.ID, + models.Package.Name, + models.Package.Version, + models.Package.Description, + models.Package.URL, + models.Package.PackageBaseID, + models.PackageBase.Name.label("PackageBaseName"), + models.PackageBase.NumVotes, + models.PackageBase.Popularity, + models.PackageBase.PopularityUpdated, + models.PackageBase.OutOfDateTS, + models.PackageBase.SubmittedTS, + models.PackageBase.ModifiedTS, + models.User.Username.label("Maintainer"), + Submitter.Username.label("Submitter"), + ) + .group_by(models.Package.ID) + ) + + return query def subquery(self, ids: set[int]): Package = models.Package @@ -367,7 +381,13 @@ class RPC: if len(results) > max_results: raise RPCError("Too many package results.") - return self._assemble_json_data(results, self.get_json_data) + data = self._assemble_json_data(results, self.get_json_data) + + # remove Submitter for search results + for pkg in data: + pkg.pop("Submitter") + + return data def _handle_msearch_type( self, args: list[str] = [], **kwargs diff --git a/test/test_rpc.py b/test/test_rpc.py index 424352db..04efd38f 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -345,6 +345,7 @@ def test_rpc_documentation_missing(): def test_rpc_singular_info( client: TestClient, user: User, + user2: User, packages: list[Package], depends: list[PackageDependency], relations: list[PackageRelation], @@ -365,6 +366,7 @@ def test_rpc_singular_info( "Popularity": float(pkg.PackageBase.Popularity), "OutOfDate": None, "Maintainer": user.Username, + "Submitter": user2.Username, "URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz", "Depends": ["chungus-depends"], "OptDepends": ["chungus-optdepends=50"], @@ -498,6 +500,7 @@ def test_rpc_mixedargs(client: TestClient, packages: list[Package]): def test_rpc_no_dependencies_omits_key( client: TestClient, user: User, + user2: User, packages: list[Package], depends: list[PackageDependency], relations: list[PackageRelation], @@ -520,6 +523,7 @@ def test_rpc_no_dependencies_omits_key( "Popularity": int(pkg.PackageBase.Popularity), "OutOfDate": None, "Maintainer": user.Username, + "Submitter": user2.Username, "URLPath": "/cgit/aur.git/snapshot/chungy-chungus.tar.gz", "Depends": ["chungy-depends"], "Conflicts": ["chungy-conflicts"], @@ -799,6 +803,7 @@ def test_rpc_search(client: TestClient, packages: list[Package]): result = data.get("results")[0] assert result.get("Name") == packages[0].Name + assert result.get("Submitter") is None # Test the If-None-Match headers. etag = response.headers.get("ETag").strip('"') From 6b0978b9a518bebb9197b9e71ff0d53f24f77bc9 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Tue, 22 Nov 2022 21:51:15 +0000 Subject: [PATCH 1636/1891] fix(deps): update dependencies from renovate Signed-off-by: Leonidas Spyropoulos --- .pre-commit-config.yaml | 4 +- poetry.lock | 598 +++++++++++++++++----------------------- pyproject.toml | 14 +- 3 files changed, 261 insertions(+), 355 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 09659269..ab4240c9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: debug-statements - repo: https://github.com/myint/autoflake - rev: v1.4 + rev: v1.7.7 hooks: - id: autoflake args: @@ -25,7 +25,7 @@ repos: - id: isort - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.10.0 hooks: - id: black diff --git a/poetry.lock b/poetry.lock index f6b79a30..22cbd3fd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -175,7 +175,7 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "38.0.1" +version = "38.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -192,20 +192,6 @@ sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] -[[package]] -name = "deprecated" -version = "1.2.13" -description = "Python @deprecated decorator to deprecate old python classes, functions or methods." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.dependencies] -wrapt = ">=1.10,<2" - -[package.extras] -dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] - [[package]] name = "dnspython" version = "2.2.1" @@ -236,7 +222,7 @@ idna = ">=2.0.0" [[package]] name = "exceptiongroup" -version = "1.0.0" +version = "1.0.4" description = "Backport of PEP 654 (exception groups)" category = "main" optional = false @@ -258,14 +244,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "1.10.0" +version = "2.0.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" [package.dependencies] -redis = "<4.4" +redis = "<4.5" sortedcontainers = ">=2.4.0,<3.0.0" [package.extras] @@ -316,7 +302,7 @@ testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pyt [[package]] name = "greenlet" -version = "2.0.0" +version = "2.0.1" description = "Lightweight in-process concurrent programming" category = "main" optional = false @@ -324,7 +310,7 @@ python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" [package.extras] docs = ["Sphinx", "docutils (<0.18)"] -test = ["faulthandler", "objgraph"] +test = ["faulthandler", "objgraph", "psutil"] [[package]] name = "gunicorn" @@ -345,11 +331,11 @@ tornado = ["tornado (>=0.2)"] [[package]] name = "h11" -version = "0.12.0" +version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "h2" @@ -373,16 +359,16 @@ python-versions = ">=3.6.1" [[package]] name = "httpcore" -version = "0.15.0" +version = "0.16.1" description = "A minimal low-level HTTP client." category = "main" optional = false python-versions = ">=3.7" [package.dependencies] -anyio = ">=3.0.0,<4.0.0" +anyio = ">=3.0,<5.0" certifi = "*" -h11 = ">=0.11,<0.13" +h11 = ">=0.13,<0.15" sniffio = ">=1.0.0,<2.0.0" [package.extras] @@ -391,7 +377,7 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" -version = "0.23.0" +version = "0.23.1" description = "The next generation HTTP client." category = "main" optional = false @@ -399,7 +385,7 @@ python-versions = ">=3.7" [package.dependencies] certifi = "*" -httpcore = ">=0.15.0,<0.16.0" +httpcore = ">=0.15.0,<0.17.0" rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" @@ -508,7 +494,7 @@ source = ["Cython (>=0.29.7)"] [[package]] name = "mako" -version = "1.2.3" +version = "1.2.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." category = "main" optional = false @@ -554,7 +540,7 @@ python-versions = ">=3.5" [[package]] name = "orjson" -version = "3.8.1" +version = "3.8.2" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false @@ -679,11 +665,11 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.10.1" +version = "1.11.1" description = "Python bindings for libgit2." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" [package.dependencies] cffi = ">=1.9.1" @@ -721,7 +707,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. [[package]] name = "pytest-asyncio" -version = "0.20.1" +version = "0.20.2" description = "Pytest support for asyncio" category = "dev" optional = false @@ -801,7 +787,7 @@ six = ">=1.4.0" [[package]] name = "redis" -version = "4.3.4" +version = "4.3.5" description = "Python client for Redis database and key-value store" category = "main" optional = false @@ -809,7 +795,6 @@ python-versions = ">=3.6" [package.dependencies] async-timeout = ">=4.0.2" -deprecated = ">=1.2.3" packaging = ">=20.4" [package.extras] @@ -850,7 +835,7 @@ idna2008 = ["idna"] [[package]] name = "setuptools" -version = "65.5.0" +version = "65.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false @@ -858,7 +843,7 @@ python-versions = ">=3.7" [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -887,7 +872,7 @@ python-versions = "*" [[package]] name = "sqlalchemy" -version = "1.4.42" +version = "1.4.44" description = "Database Abstraction Library" category = "main" optional = false @@ -993,7 +978,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.19.0" +version = "0.20.0" description = "The lightning-fast ASGI server." category = "main" optional = false @@ -1004,7 +989,7 @@ click = ">=7.0" h11 = ">=0.8" [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "webencodings" @@ -1028,14 +1013,6 @@ MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog"] -[[package]] -name = "wrapt" -version = "1.14.1" -description = "Module for decorators, wrappers and monkey patching." -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - [[package]] name = "wsproto" version = "1.2.0" @@ -1062,7 +1039,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "84f0bae9789174cbdc5aa672b9e72f0ef91763f63ed73e8cafb45f26efd9bb47" +content-hash = "b178f1fcbba93d9cbc8dd23193b25afd5e1ba971196757abf098a1dfa2666cba" [metadata.files] aiofiles = [ @@ -1255,36 +1232,32 @@ coverage = [ {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, ] cryptography = [ - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f"}, - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294"}, - {file = "cryptography-38.0.1-cp36-abi3-win32.whl", hash = "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0"}, - {file = "cryptography-38.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b"}, - {file = "cryptography-38.0.1.tar.gz", hash = "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7"}, -] -deprecated = [ - {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, - {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, + {file = "cryptography-38.0.3-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320"}, + {file = "cryptography-38.0.3-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:ed7b00096790213e09eb11c97cc6e2b757f15f3d2f85833cd2d3ec3fe37c1722"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bbf203f1a814007ce24bd4d51362991d5cb90ba0c177a9c08825f2cc304d871f"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554bec92ee7d1e9d10ded2f7e92a5d70c1f74ba9524947c0ba0c850c7b011828"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1b52c9e5f8aa2b802d48bd693190341fae201ea51c7a167d69fc48b60e8a959"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:728f2694fa743a996d7784a6194da430f197d5c58e2f4e278612b359f455e4a2"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dfb4f4dd568de1b6af9f4cda334adf7d72cf5bc052516e1b2608b683375dd95c"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5419a127426084933076132d317911e3c6eb77568a1ce23c3ac1e12d111e61e0"}, + {file = "cryptography-38.0.3-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9b24bcff7853ed18a63cfb0c2b008936a9554af24af2fb146e16d8e1aed75748"}, + {file = "cryptography-38.0.3-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:25c1d1f19729fb09d42e06b4bf9895212292cb27bb50229f5aa64d039ab29146"}, + {file = "cryptography-38.0.3-cp36-abi3-win32.whl", hash = "sha256:7f836217000342d448e1c9a342e9163149e45d5b5eca76a30e84503a5a96cab0"}, + {file = "cryptography-38.0.3-cp36-abi3-win_amd64.whl", hash = "sha256:c46837ea467ed1efea562bbeb543994c2d1f6e800785bd5a2c98bc096f5cb220"}, + {file = "cryptography-38.0.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06fc3cc7b6f6cca87bd56ec80a580c88f1da5306f505876a71c8cfa7050257dd"}, + {file = "cryptography-38.0.3-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:65535bc550b70bd6271984d9863a37741352b4aad6fb1b3344a54e6950249b55"}, + {file = "cryptography-38.0.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5e89468fbd2fcd733b5899333bc54d0d06c80e04cd23d8c6f3e0542358c6060b"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6ab9516b85bebe7aa83f309bacc5f44a61eeb90d0b4ec125d2d003ce41932d36"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:068147f32fa662c81aebab95c74679b401b12b57494872886eb5c1139250ec5d"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:402852a0aea73833d982cabb6d0c3bb582c15483d29fb7085ef2c42bfa7e38d7"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b1b35d9d3a65542ed2e9d90115dfd16bbc027b3f07ee3304fc83580f26e43249"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6addc3b6d593cd980989261dc1cce38263c76954d758c3c94de51f1e010c9a50"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:be243c7e2bfcf6cc4cb350c0d5cdf15ca6383bbcb2a8ef51d3c9411a9d4386f0"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78cf5eefac2b52c10398a42765bfa981ce2372cbc0457e6bf9658f41ec3c41d8"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:4e269dcd9b102c5a3d72be3c45d8ce20377b8076a43cbed6f660a1afe365e436"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8d41a46251bf0634e21fac50ffd643216ccecfaf3701a063257fe0b2be1b6548"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:785e4056b5a8b28f05a533fab69febf5004458e20dad7e2e13a3120d8ecec75a"}, + {file = "cryptography-38.0.3.tar.gz", hash = "sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd"}, ] dnspython = [ {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, @@ -1295,16 +1268,16 @@ email-validator = [ {file = "email_validator-1.3.0.tar.gz", hash = "sha256:553a66f8be2ec2dea641ae1d3f29017ab89e9d603d4a25cdaac39eefa283d769"}, ] exceptiongroup = [ - {file = "exceptiongroup-1.0.0-py3-none-any.whl", hash = "sha256:2ac84b496be68464a2da60da518af3785fff8b7ec0d090a581604bc870bdee41"}, - {file = "exceptiongroup-1.0.0.tar.gz", hash = "sha256:affbabf13fb6e98988c38d9c5650e701569fe3c1de3233cfb61c5f33774690ad"}, + {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"}, + {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"}, ] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, ] fakeredis = [ - {file = "fakeredis-1.10.0-py3-none-any.whl", hash = "sha256:0be420a79fabda234963a2730c4ce609a6d44a598e8dd253ce97785bef944285"}, - {file = "fakeredis-1.10.0.tar.gz", hash = "sha256:2b02370118535893d832bcd3c099ef282de3f13b29ae3922432e2225794ec334"}, + {file = "fakeredis-2.0.0-py3-none-any.whl", hash = "sha256:fb3186cbbe4c549f922b0f08eb84b09c0e51ecf8efbed3572d20544254f93a97"}, + {file = "fakeredis-2.0.0.tar.gz", hash = "sha256:6d1dc2417921b7ce56a80877afa390d6335a3154146f201a86e3a14417bdc79e"}, ] fastapi = [ {file = "fastapi-0.85.2-py3-none-any.whl", hash = "sha256:6292db0edd4a11f0d938d6033ccec5f706e9d476958bf33b119e8ddb4e524bde"}, @@ -1318,69 +1291,74 @@ filelock = [ {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, ] greenlet = [ - {file = "greenlet-2.0.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4be4dedbd2fa9b7c35627f322d6d3139cb125bc18d5ef2f40237990850ea446f"}, - {file = "greenlet-2.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:75c022803de010294366f3608d4bba3e346693b1b7427b79d57e3d924ed03838"}, - {file = "greenlet-2.0.0-cp27-cp27m-win32.whl", hash = "sha256:4a1953465b7651073cffde74ed7d121e602ef9a9740d09ee137b01879ac15a2f"}, - {file = "greenlet-2.0.0-cp27-cp27m-win_amd64.whl", hash = "sha256:a65205e6778142528978b4acca76888e7e7f0be261e395664e49a5c21baa2141"}, - {file = "greenlet-2.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d71feebf5c8041c80dfda76427e14e3ca00bca042481bd3e9612a9d57b2cbbf7"}, - {file = "greenlet-2.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f7edbd2957f72aea357241fe42ffc712a8e9b8c2c42f24e2ef5d97b255f66172"}, - {file = "greenlet-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79687c48e7f564be40c46b3afea6d141b8d66ffc2bc6147e026d491c6827954a"}, - {file = "greenlet-2.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a245898ec5e9ca0bc87a63e4e222cc633dc4d1f1a0769c34a625ad67edb9f9de"}, - {file = "greenlet-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:adcf45221f253b3a681c99da46fa6ac33596fa94c2f30c54368f7ee1c4563a39"}, - {file = "greenlet-2.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3dc294afebf2acfd029373dbf3d01d36fd8d6888a03f5a006e2d690f66b153d9"}, - {file = "greenlet-2.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1cfeae4dda32eb5c64df05d347c4496abfa57ad16a90082798a2bba143c6c854"}, - {file = "greenlet-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:d58d4b4dc82e2d21ebb7dd7d3a6d370693b2236a1407fe3988dc1d4ea07575f9"}, - {file = "greenlet-2.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0d7efab8418c1fb3ea00c4abb89e7b0179a952d0d53ad5fcff798ca7440f8e8"}, - {file = "greenlet-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8a10e14238407be3978fa6d190eb3724f9d766655fefc0134fd5482f1fb0108"}, - {file = "greenlet-2.0.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:98b848a0b75e76b446dc71fdbac712d9078d96bb1c1607f049562dde1f8801e1"}, - {file = "greenlet-2.0.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:8e8dbad9b4f4c3e37898914cfccb7c4f00dbe3146333cfe52a1a3103cc2ff97c"}, - {file = "greenlet-2.0.0-cp35-cp35m-win32.whl", hash = "sha256:069a8a557541a04518dc3beb9a78637e4e6b286814849a2ecfac529eaa78562b"}, - {file = "greenlet-2.0.0-cp35-cp35m-win_amd64.whl", hash = "sha256:cc211c2ff5d3b2ba8d557a71e3b4f0f0a2020067515143a9516ea43884271192"}, - {file = "greenlet-2.0.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d4e7642366e638f45d70c5111590a56fbd0ffb7f474af20c6c67c01270bcf5cf"}, - {file = "greenlet-2.0.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e7a0dca752b4e3395890ab4085c3ec3838d73714261914c01b53ed7ea23b5867"}, - {file = "greenlet-2.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8c67ecda450ad4eac7837057f5deb96effa836dacaf04747710ccf8eeb73092"}, - {file = "greenlet-2.0.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3cc1abaf47cfcfdc9ac0bdff173cebab22cd54e9e3490135a4a9302d0ff3b163"}, - {file = "greenlet-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efdbbbf7b6c8d5be52977afa65b9bb7b658bab570543280e76c0fabc647175ed"}, - {file = "greenlet-2.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:7acaa51355d5b9549d474dc71be6846ee9a8f2cb82f4936e5efa7a50bbeb94ad"}, - {file = "greenlet-2.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2be628bca0395610da08921f9376dd14317f37256d41078f5c618358467681e1"}, - {file = "greenlet-2.0.0-cp36-cp36m-win32.whl", hash = "sha256:eca9c0473de053dcc92156dd62c38c3578628b536c7f0cd66e655e211c14ac32"}, - {file = "greenlet-2.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9a4a9fea68fd98814999d91ea585e49ed68d7e199a70bef13a857439f60a4609"}, - {file = "greenlet-2.0.0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:6b28420ae290bfbf5d827f976abccc2f74f0a3f5e4fb69b66acf98f1cbe95e7e"}, - {file = "greenlet-2.0.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:2b8e1c939b363292ecc93999fb1ad53ffc5d0aac8e933e4362b62365241edda5"}, - {file = "greenlet-2.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c5ddadfe40e903c6217ed2b95a79f49e942bb98527547cc339fc7e43a424aad"}, - {file = "greenlet-2.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e5ead803b11b60b347e08e0f37234d9a595f44a6420026e47bcaf94190c3cd6"}, - {file = "greenlet-2.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b89b78ffb516c2921aa180c2794082666e26680eef05996b91f46127da24d964"}, - {file = "greenlet-2.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:939963d0137ec92540d95b68b7f795e8dbadce0a1fca53e3e7ef8ddc18ee47cb"}, - {file = "greenlet-2.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c1e93ef863810fba75faf418f0861dbf59bfe01a7b5d0a91d39603df58d3d3fa"}, - {file = "greenlet-2.0.0-cp37-cp37m-win32.whl", hash = "sha256:6fd342126d825b76bf5b49717a7c682e31ed1114906cdec7f5a0c2ff1bc737a7"}, - {file = "greenlet-2.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5392ddb893e7fba237b988f846c4a80576557cc08664d56dc1a69c5c02bdc80c"}, - {file = "greenlet-2.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b4fd73b62c1038e7ee938b1de328eaa918f76aa69c812beda3aff8a165494201"}, - {file = "greenlet-2.0.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:0ba0f2e5c4a8f141952411e356dba05d6fe0c38325ee0e4f2d0c6f4c2c3263d5"}, - {file = "greenlet-2.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8bacecee0c9348ab7c95df810e12585e9e8c331dfc1e22da4ed0bd635a5f483"}, - {file = "greenlet-2.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:341053e0a96d512315c27c34fad4672c4573caf9eb98310c39e7747645c88d8b"}, - {file = "greenlet-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fcdd8ae391ffabb3b672397b58a9737aaff6b8cae0836e8db8ff386fcea802"}, - {file = "greenlet-2.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c3aa7d3bc545162a6676445709b24a2a375284dc5e2f2432d58b80827c2bd91c"}, - {file = "greenlet-2.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9d8dca31a39dd9f25641559b8cdf9066168c682dfcfbe0f797f03e4c9718a63a"}, - {file = "greenlet-2.0.0-cp38-cp38-win32.whl", hash = "sha256:aa2b371c3633e694d043d6cec7376cb0031c6f67029f37eef40bda105fd58753"}, - {file = "greenlet-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:0fa2a66fdf0d09929e79f786ad61529d4e752f452466f7ddaa5d03caf77a603d"}, - {file = "greenlet-2.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:e7ec3f2465ba9b7d25895307abe1c1c101a257c54b9ea1522bbcbe8ca8793735"}, - {file = "greenlet-2.0.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:99e9851e40150504474915605649edcde259a4cd9bce2fcdeb4cf33ad0b5c293"}, - {file = "greenlet-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20bf68672ae14ef2e2e6d3ac1f308834db1d0b920b3b0674eef48b2dce0498dd"}, - {file = "greenlet-2.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30198bccd774f9b6b1ba7564a0d02a79dd1fe926cfeb4107856fe16c9dfb441c"}, - {file = "greenlet-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d65d7d1ff64fb300127d2ffd27db909de4d21712a5dde59a3ad241fb65ee83d7"}, - {file = "greenlet-2.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2f5d396a5457458460b0c28f738fc8ab2738ee61b00c3f845c7047a333acd96c"}, - {file = "greenlet-2.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09f00f9938eb5ae1fe203558b56081feb0ca34a2895f8374cd01129ddf4d111c"}, - {file = "greenlet-2.0.0-cp39-cp39-win32.whl", hash = "sha256:089e123d80dbc6f61fff1ff0eae547b02c343d50968832716a7b0a33bea5f792"}, - {file = "greenlet-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc283f99a4815ef70cad537110e3e03abcef56ab7d005ba9a8c6ec33054ce9c0"}, - {file = "greenlet-2.0.0.tar.gz", hash = "sha256:6c66f0da8049ee3c126b762768179820d4c0ae0ca46ae489039e4da2fae39a52"}, + {file = "greenlet-2.0.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:9ed358312e63bf683b9ef22c8e442ef6c5c02973f0c2a939ec1d7b50c974015c"}, + {file = "greenlet-2.0.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4f09b0010e55bec3239278f642a8a506b91034f03a4fb28289a7d448a67f1515"}, + {file = "greenlet-2.0.1-cp27-cp27m-win32.whl", hash = "sha256:1407fe45246632d0ffb7a3f4a520ba4e6051fc2cbd61ba1f806900c27f47706a"}, + {file = "greenlet-2.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:3001d00eba6bbf084ae60ec7f4bb8ed375748f53aeaefaf2a37d9f0370558524"}, + {file = "greenlet-2.0.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d566b82e92ff2e09dd6342df7e0eb4ff6275a3f08db284888dcd98134dbd4243"}, + {file = "greenlet-2.0.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0722c9be0797f544a3ed212569ca3fe3d9d1a1b13942d10dd6f0e8601e484d26"}, + {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d37990425b4687ade27810e3b1a1c37825d242ebc275066cfee8cb6b8829ccd"}, + {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be35822f35f99dcc48152c9839d0171a06186f2d71ef76dc57fa556cc9bf6b45"}, + {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c140e7eb5ce47249668056edf3b7e9900c6a2e22fb0eaf0513f18a1b2c14e1da"}, + {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d21681f09e297a5adaa73060737e3aa1279a13ecdcfcc6ef66c292cb25125b2d"}, + {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fb412b7db83fe56847df9c47b6fe3f13911b06339c2aa02dcc09dce8bbf582cd"}, + {file = "greenlet-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6a08799e9e88052221adca55741bf106ec7ea0710bca635c208b751f0d5b617"}, + {file = "greenlet-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e112e03d37987d7b90c1e98ba5e1b59e1645226d78d73282f45b326f7bddcb9"}, + {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56961cfca7da2fdd178f95ca407fa330c64f33289e1804b592a77d5593d9bd94"}, + {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13ba6e8e326e2116c954074c994da14954982ba2795aebb881c07ac5d093a58a"}, + {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bf633a50cc93ed17e494015897361010fc08700d92676c87931d3ea464123ce"}, + {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9f2c221eecb7ead00b8e3ddb913c67f75cba078fd1d326053225a3f59d850d72"}, + {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:13ebf93c343dd8bd010cd98e617cb4c1c1f352a0cf2524c82d3814154116aa82"}, + {file = "greenlet-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:6f61d71bbc9b4a3de768371b210d906726535d6ca43506737682caa754b956cd"}, + {file = "greenlet-2.0.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:2d0bac0385d2b43a7bd1d651621a4e0f1380abc63d6fb1012213a401cbd5bf8f"}, + {file = "greenlet-2.0.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:f6327b6907b4cb72f650a5b7b1be23a2aab395017aa6f1adb13069d66360eb3f"}, + {file = "greenlet-2.0.1-cp35-cp35m-win32.whl", hash = "sha256:81b0ea3715bf6a848d6f7149d25bf018fd24554a4be01fcbbe3fdc78e890b955"}, + {file = "greenlet-2.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:38255a3f1e8942573b067510f9611fc9e38196077b0c8eb7a8c795e105f9ce77"}, + {file = "greenlet-2.0.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:04957dc96669be041e0c260964cfef4c77287f07c40452e61abe19d647505581"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:4aeaebcd91d9fee9aa768c1b39cb12214b30bf36d2b7370505a9f2165fedd8d9"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974a39bdb8c90a85982cdb78a103a32e0b1be986d411303064b28a80611f6e51"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dca09dedf1bd8684767bc736cc20c97c29bc0c04c413e3276e0962cd7aeb148"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c0757db9bd08470ff8277791795e70d0bf035a011a528ee9a5ce9454b6cba2"}, + {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:5067920de254f1a2dee8d3d9d7e4e03718e8fd2d2d9db962c8c9fa781ae82a39"}, + {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5a8e05057fab2a365c81abc696cb753da7549d20266e8511eb6c9d9f72fe3e92"}, + {file = "greenlet-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:3d75b8d013086b08e801fbbb896f7d5c9e6ccd44f13a9241d2bf7c0df9eda928"}, + {file = "greenlet-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:097e3dae69321e9100202fc62977f687454cd0ea147d0fd5a766e57450c569fd"}, + {file = "greenlet-2.0.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:cb242fc2cda5a307a7698c93173d3627a2a90d00507bccf5bc228851e8304963"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:72b00a8e7c25dcea5946692a2485b1a0c0661ed93ecfedfa9b6687bd89a24ef5"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5b0ff9878333823226d270417f24f4d06f235cb3e54d1103b71ea537a6a86ce"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be9e0fb2ada7e5124f5282d6381903183ecc73ea019568d6d63d33f25b2a9000"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b493db84d124805865adc587532ebad30efa68f79ad68f11b336e0a51ec86c2"}, + {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0459d94f73265744fee4c2d5ec44c6f34aa8a31017e6e9de770f7bcf29710be9"}, + {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a20d33124935d27b80e6fdacbd34205732660e0a1d35d8b10b3328179a2b51a1"}, + {file = "greenlet-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:ea688d11707d30e212e0110a1aac7f7f3f542a259235d396f88be68b649e47d1"}, + {file = "greenlet-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:afe07421c969e259e9403c3bb658968702bc3b78ec0b6fde3ae1e73440529c23"}, + {file = "greenlet-2.0.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:cd4ccc364cf75d1422e66e247e52a93da6a9b73cefa8cad696f3cbbb75af179d"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c8b1c43e75c42a6cafcc71defa9e01ead39ae80bd733a2608b297412beede68"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:659f167f419a4609bc0516fb18ea69ed39dbb25594934bd2dd4d0401660e8a1e"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:356e4519d4dfa766d50ecc498544b44c0249b6de66426041d7f8b751de4d6b48"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811e1d37d60b47cb8126e0a929b58c046251f28117cb16fcd371eed61f66b764"}, + {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d38ffd0e81ba8ef347d2be0772e899c289b59ff150ebbbbe05dc61b1246eb4e0"}, + {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0109af1138afbfb8ae647e31a2b1ab030f58b21dd8528c27beaeb0093b7938a9"}, + {file = "greenlet-2.0.1-cp38-cp38-win32.whl", hash = "sha256:88c8d517e78acdf7df8a2134a3c4b964415b575d2840a2746ddb1cc6175f8608"}, + {file = "greenlet-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d6ee1aa7ab36475035eb48c01efae87d37936a8173fc4d7b10bb02c2d75dd8f6"}, + {file = "greenlet-2.0.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:b1992ba9d4780d9af9726bbcef6a1db12d9ab1ccc35e5773685a24b7fb2758eb"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:b5e83e4de81dcc9425598d9469a624826a0b1211380ac444c7c791d4a2137c19"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:505138d4fa69462447a562a7c2ef723c6025ba12ac04478bc1ce2fcc279a2db5"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cce1e90dd302f45716a7715517c6aa0468af0bf38e814ad4eab58e88fc09f7f7"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e9744c657d896c7b580455e739899e492a4a452e2dd4d2b3e459f6b244a638d"}, + {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:662e8f7cad915ba75d8017b3e601afc01ef20deeeabf281bd00369de196d7726"}, + {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:41b825d65f31e394b523c84db84f9383a2f7eefc13d987f308f4663794d2687e"}, + {file = "greenlet-2.0.1-cp39-cp39-win32.whl", hash = "sha256:db38f80540083ea33bdab614a9d28bcec4b54daa5aff1668d7827a9fc769ae0a"}, + {file = "greenlet-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b23d2a46d53210b498e5b701a1913697671988f4bf8e10f935433f6e7c332fb6"}, + {file = "greenlet-2.0.1.tar.gz", hash = "sha256:42e602564460da0e8ee67cb6d7236363ee5e131aa15943b6670e44e5c2ed0f67"}, ] gunicorn = [ {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, ] h11 = [ - {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, - {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] h2 = [ {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, @@ -1391,12 +1369,12 @@ hpack = [ {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, ] httpcore = [ - {file = "httpcore-0.15.0-py3-none-any.whl", hash = "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6"}, - {file = "httpcore-0.15.0.tar.gz", hash = "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b"}, + {file = "httpcore-0.16.1-py3-none-any.whl", hash = "sha256:8d393db683cc8e35cc6ecb02577c5e1abfedde52b38316d038932a84b4875ecb"}, + {file = "httpcore-0.16.1.tar.gz", hash = "sha256:3d3143ff5e1656a5740ea2f0c167e8e9d48c5a9bbd7f00ad1f8cff5711b08543"}, ] httpx = [ - {file = "httpx-0.23.0-py3-none-any.whl", hash = "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b"}, - {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, + {file = "httpx-0.23.1-py3-none-any.whl", hash = "sha256:0b9b1f0ee18b9978d637b0776bfd7f54e2ca278e063e3586d8f01cda89e042a8"}, + {file = "httpx-0.23.1.tar.gz", hash = "sha256:202ae15319be24efe9a8bd4ed4360e68fde7b38bcc2ce87088d416f026667d19"}, ] hypercorn = [ {file = "Hypercorn-0.14.3-py3-none-any.whl", hash = "sha256:7c491d5184f28ee960dcdc14ab45d14633ca79d72ddd13cf4fcb4cb854d679ab"}, @@ -1499,8 +1477,8 @@ lxml = [ {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, ] mako = [ - {file = "Mako-1.2.3-py3-none-any.whl", hash = "sha256:c413a086e38cd885088d5e165305ee8eed04e8b3f8f62df343480da0a385735f"}, - {file = "Mako-1.2.3.tar.gz", hash = "sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd"}, + {file = "Mako-1.2.4-py3-none-any.whl", hash = "sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818"}, + {file = "Mako-1.2.4.tar.gz", hash = "sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34"}, ] markdown = [ {file = "Markdown-3.4.1-py3-none-any.whl", hash = "sha256:08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186"}, @@ -1558,55 +1536,55 @@ mysqlclient = [ {file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"}, ] orjson = [ - {file = "orjson-3.8.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:a70aaa2e56356e58c6e1b49f7b7f069df5b15e55db002a74db3ff3f7af67c7ff"}, - {file = "orjson-3.8.1-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:d45db052d01d0ab7579470141d5c3592f4402d43cfacb67f023bc1210a67b7bc"}, - {file = "orjson-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2aae92398c0023ac26a6cd026375f765ef5afe127eccabf563c78af7b572d59"}, - {file = "orjson-3.8.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0bd5b4e539db8a9635776bdf9a25c3db84e37165e65d45c8ca90437adc46d6d8"}, - {file = "orjson-3.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21efb87b168066201a120b0f54a2381f6f51ff3727e07b3908993732412b314a"}, - {file = "orjson-3.8.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:e073338e422f518c1d4d80efc713cd17f3ed6d37c8c7459af04a95459f3206d1"}, - {file = "orjson-3.8.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8f672f3987f6424f60ab2e86ea7ed76dd2806b8e9b506a373fc8499aed85ddb5"}, - {file = "orjson-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:231c30958ed99c23128a21993c5ac0a70e1e568e6a898a47f70d5d37461ca47c"}, - {file = "orjson-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59b4baf71c9f39125d7e535974b146cc180926462969f6d8821b4c5e975e11b3"}, - {file = "orjson-3.8.1-cp310-none-win_amd64.whl", hash = "sha256:fe25f50dc3d45364428baa0dbe3f613a5171c64eb0286eb775136b74e61ba58a"}, - {file = "orjson-3.8.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:6802edf98f6918e89df355f56be6e7db369b31eed64ff2496324febb8b0aa43b"}, - {file = "orjson-3.8.1-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:a4244f4199a160717f0027e434abb886e322093ceadb2f790ff0c73ed3e17662"}, - {file = "orjson-3.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6956cf7a1ac97523e96f75b11534ff851df99a6474a561ad836b6e82004acbb8"}, - {file = "orjson-3.8.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b4e3857dd2416b479f700e9bdf4fcec8c690d2716622397d2b7e848f9833e50"}, - {file = "orjson-3.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8873e490dea0f9cd975d66f84618b6fb57b1ba45ecb218313707a71173d764f"}, - {file = "orjson-3.8.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:124207d2cd04e845eaf2a6171933cde40aebcb8c2d7d3b081e01be066d3014b6"}, - {file = "orjson-3.8.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d8ed77098c2e22181fce971f49a34204c38b79ca91c01d515d07015339ae8165"}, - {file = "orjson-3.8.1-cp311-none-win_amd64.whl", hash = "sha256:8623ac25fa0850a44ac845e9333c4da9ae5707b7cec8ac87cbe9d4e41137180f"}, - {file = "orjson-3.8.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:d67a0bd0283a3b17ac43c5ab8e4a7e9d3aa758d6ec5d51c232343c408825a5ad"}, - {file = "orjson-3.8.1-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:d89ef8a4444d83e0a5171d14f2ab4895936ab1773165b020f97d29cf289a2d88"}, - {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97839a6abbebb06099294e6057d5b3061721ada08b76ae792e7041b6cb54c97f"}, - {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6071bcf51f0ae4d53b9d3e9164f7138164df4291c484a7b14562075aaa7a2b7b"}, - {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c15e7d691cee75b5192fc1fa8487bf541d463246dc25c926b9b40f5b6ab56770"}, - {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:b9abc49c014def1b832fcd53bdc670474b6fe41f373d16f40409882c0d0eccba"}, - {file = "orjson-3.8.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:3fd5472020042482d7da4c26a0ee65dbd931f691e1c838c6cf4232823179ecc1"}, - {file = "orjson-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e399ed1b0d6f8089b9b6ff2cb3e71ba63a56d8ea88e1d95467949795cc74adfd"}, - {file = "orjson-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5e3db6496463c3000d15b7a712da5a9601c6c43682f23f81862fe1d2a338f295"}, - {file = "orjson-3.8.1-cp37-none-win_amd64.whl", hash = "sha256:0f21eed14697083c01f7e00a87e21056fc8fb5851e8a7bca98345189abcdb4d4"}, - {file = "orjson-3.8.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:5a9e324213220578d324e0858baeab47808a13d3c3fbc6ba55a3f4f069d757cf"}, - {file = "orjson-3.8.1-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:69097c50c3ccbcc61292192b045927f1688ca57ce80525dc5d120e0b91e19bb0"}, - {file = "orjson-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7822cba140f7ca48ed0256229f422dbae69e3a3475176185db0c0538cfadb57"}, - {file = "orjson-3.8.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03389e3750c521a7f3d4837de23cfd21a7f24574b4b3985c9498f440d21adb03"}, - {file = "orjson-3.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f9d9b5c6692097de07dd0b2d5ff20fd135bacd1b2fb7ea383ee717a4150c93"}, - {file = "orjson-3.8.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:c2c9ef10b6344465fd5ac002be2d34f818211274dd79b44c75b2c14a979f84f3"}, - {file = "orjson-3.8.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7adaac93678ac61f5dc070f615b18639d16ee66f6a946d5221dbf315e8b74bec"}, - {file = "orjson-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b0c1750f73658906b82cabbf4be2f74300644c17cb037fbc8b48d746c3b90c76"}, - {file = "orjson-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:da6306e1f03e7085fe0db61d4a3377f70c6fd865118d0afe17f80ae9a8f6f124"}, - {file = "orjson-3.8.1-cp38-none-win_amd64.whl", hash = "sha256:f532c2cbe8c140faffaebcfb34d43c9946599ea8138971f181a399bec7d6b123"}, - {file = "orjson-3.8.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:6a7b76d4b44bca418f7797b1e157907b56b7d31caa9091db4e99ebee51c16933"}, - {file = "orjson-3.8.1-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:f850489d89ea12be486492e68f0fd63e402fa28e426d4f0b5fc1eec0595e6109"}, - {file = "orjson-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4449e70b98f3ad3e43958360e4be1189c549865c0a128e8629ec96ce92d251c3"}, - {file = "orjson-3.8.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:45357eea9114bd41ef19280066591e9069bb4f6f5bffd533e9bfc12a439d735f"}, - {file = "orjson-3.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f5a9bc5bc4d730153529cb0584c63ff286d50663ccd48c9435423660b1bb12d"}, - {file = "orjson-3.8.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:a806aca6b80fa1d996aa16593e4995a71126a085ee1a59fff19ccad29a4e47fd"}, - {file = "orjson-3.8.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:395d02fd6be45f960da014372e7ecefc9e5f8df57a0558b7111a5fa8423c0669"}, - {file = "orjson-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:caff3c1e964cfee044a03a46244ecf6373f3c56142ad16458a1446ac6d69824a"}, - {file = "orjson-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ded261268d5dfd307078fe3370295e5eb15bdde838bbb882acf8538e061c451"}, - {file = "orjson-3.8.1-cp39-none-win_amd64.whl", hash = "sha256:45c1914795ffedb2970bfcd3ed83daf49124c7c37943ed0a7368971c6ea5e278"}, - {file = "orjson-3.8.1.tar.gz", hash = "sha256:07c42de52dfef56cdcaf2278f58e837b26f5b5af5f1fd133a68c4af203851fc7"}, + {file = "orjson-3.8.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:43e69b360c2851b45c7dbab3b95f7fa8469df73fab325a683f7389c4db63aa71"}, + {file = "orjson-3.8.2-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:64c5da5c9679ef3d85e9bbcbb62f4ccdc1f1975780caa20f2ec1e37b4da6bd36"}, + {file = "orjson-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c632a2157fa9ec098d655287e9e44809615af99837c49f53d96bfbca453c5bd"}, + {file = "orjson-3.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f63da6309c282a2b58d4a846f0717f6440356b4872838b9871dc843ed1fe2b38"}, + {file = "orjson-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c9be25c313ba2d5478829d949165445c3bd36c62e07092b4ba8dbe5426574d1"}, + {file = "orjson-3.8.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:4bcce53e9e088f82633f784f79551fcd7637943ab56c51654aaf9d4c1d5cfa54"}, + {file = "orjson-3.8.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:33edb5379c6e6337f9383c85fe4080ce3aa1057cc2ce29345b7239461f50cbd6"}, + {file = "orjson-3.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:da35d347115758bbc8bfaf39bb213c42000f2a54e3f504c84374041d20835cd6"}, + {file = "orjson-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d755d94a90a941b91b4d39a6b02e289d8ba358af2d1a911edf266be7942609dc"}, + {file = "orjson-3.8.2-cp310-none-win_amd64.whl", hash = "sha256:7ea96923e26390b2142602ebb030e2a4db9351134696e0b219e5106bddf9b48e"}, + {file = "orjson-3.8.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:a0d89de876e6f1cef917a2338378a60a98584e1c2e1c67781e20b6ed1c512478"}, + {file = "orjson-3.8.2-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:8d47e7592fe938aec898eb22ea4946298c018133df084bc78442ff18e2c6347c"}, + {file = "orjson-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3d9f1043f618d0c64228aab9711e5bd822253c50b6c56223951e32b51f81d62"}, + {file = "orjson-3.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed10600e8b08f1e87b656ad38ab316191ce94f2c9adec57035680c0dc9e93c81"}, + {file = "orjson-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99c49e49a04bf61fee7aaea6d92ac2b1fcf6507aea894bbdf3fbb25fe792168c"}, + {file = "orjson-3.8.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:1463674f8efe6984902473d7b5ce3edf444c1fcd09dc8aa4779638a28fb9ca01"}, + {file = "orjson-3.8.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:c1ef75f1d021d817e5c60a42da0b4b7e3123b1b37415260b8415666ddacc7cd7"}, + {file = "orjson-3.8.2-cp311-none-win_amd64.whl", hash = "sha256:b6007e1ac8564b13b2521720929e8bb3ccd3293d9fdf38f28728dcc06db6248f"}, + {file = "orjson-3.8.2-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:a02c13ae523221576b001071354380e277346722cc6b7fdaacb0fd6db5154b3e"}, + {file = "orjson-3.8.2-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:fa2e565cf8ffdb37ce1887bd1592709ada7f701e61aa4b1e710be94b0aecbab4"}, + {file = "orjson-3.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1d8864288f7c5fccc07b43394f83b721ddc999f25dccfb5d0651671a76023f5"}, + {file = "orjson-3.8.2-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1874c05d0bb994601fa2d51605cb910d09343c6ebd36e84a573293523fab772a"}, + {file = "orjson-3.8.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:349387ed6989e5db22e08c9af8d7ca14240803edc50de451d48d41a0e7be30f6"}, + {file = "orjson-3.8.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:4e42b19619d6e97e201053b865ca4e62a48da71165f4081508ada8e1b91c6a30"}, + {file = "orjson-3.8.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:bc112c17e607c59d1501e72afb44226fa53d947d364aed053f0c82d153e29616"}, + {file = "orjson-3.8.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6fda669211f2ed1fc2c8130187ec90c96b4f77b6a250004e666d2ef8ed524e5f"}, + {file = "orjson-3.8.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:aebd4e80fea0f20578fd0452908b9206a6a0d5ae9f5c99b6e665bbcd989e56cd"}, + {file = "orjson-3.8.2-cp37-none-win_amd64.whl", hash = "sha256:9f3cd0394eb6d265beb2a1572b5663bc910883ddbb5cdfbcb660f5a0444e7fd8"}, + {file = "orjson-3.8.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:74e7d54d11b3da42558d69a23bf92c2c48fabf69b38432d5eee2c5b09cd4c433"}, + {file = "orjson-3.8.2-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:8cbadc9be748a823f9c743c7631b1ee95d3925a9c0b21de4e862a1d57daa10ec"}, + {file = "orjson-3.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a07d5a8c69a2947d9554a00302734fe3d8516415c8b280963c92bc1033477890"}, + {file = "orjson-3.8.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6b364ea01d1b71b9f97bf97af9eb79ebee892df302e127a9e2e4f8eaa74d6b98"}, + {file = "orjson-3.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b98a8c825a59db94fbe8e0cce48618624c5a6fb1436467322d90667c08a0bf80"}, + {file = "orjson-3.8.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:ab63103f60b516c0fce9b62cb4773f689a82ab56e19ef2387b5a3182f80c0d78"}, + {file = "orjson-3.8.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:73ab3f4288389381ae33ab99f914423b69570c88d626d686764634d5e0eeb909"}, + {file = "orjson-3.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2ab3fd8728e12c36e20c6d9d70c9e15033374682ce5acb6ed6a08a80dacd254d"}, + {file = "orjson-3.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cde11822cf71a7f0daaa84223249b2696a2b6cda7fa587e9fd762dff1a8848e4"}, + {file = "orjson-3.8.2-cp38-none-win_amd64.whl", hash = "sha256:b14765ea5aabfeab1a194abfaa0be62c9fee6480a75ac8c6974b4eeede3340b4"}, + {file = "orjson-3.8.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:6068a27d59d989d4f2864c2fc3440eb7126a0cfdfaf8a4ad136b0ffd932026ae"}, + {file = "orjson-3.8.2-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6bf36fa759a1b941fc552ad76b2d7fb10c1d2a20c056be291ea45eb6ae1da09b"}, + {file = "orjson-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f436132e62e647880ca6988974c8e3165a091cb75cbed6c6fd93e931630c22fa"}, + {file = "orjson-3.8.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3ecd8936259a5920b52a99faf62d4efeb9f5e25a0aacf0cce1e9fa7c37af154f"}, + {file = "orjson-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c13114b345cda33644f64e92fe5d8737828766cf02fbbc7d28271a95ea546832"}, + {file = "orjson-3.8.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6e43cdc3ddf96bdb751b748b1984b701125abacca8fc2226b808d203916e8cba"}, + {file = "orjson-3.8.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ee39071da2026b11e4352d6fc3608a7b27ee14bc699fd240f4e604770bc7a255"}, + {file = "orjson-3.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1c3833976ebbeb3b5b6298cb22e23bf18453f6b80802103b7d08f7dd8a61611d"}, + {file = "orjson-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b9a34519d3d70935e1cd3797fbed8fbb6f61025182bea0140ca84d95b6f8fbe5"}, + {file = "orjson-3.8.2-cp39-none-win_amd64.whl", hash = "sha256:2734086d9a3dd9591c4be7d05aff9beccc086796d3f243685e56b7973ebac5bc"}, + {file = "orjson-3.8.2.tar.gz", hash = "sha256:a2fb95a45031ccf278e44341027b3035ab99caa32aa173279b1f0a06324f434b"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -1704,43 +1682,37 @@ pydantic = [ {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, ] pygit2 = [ - {file = "pygit2-1.10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e3f60e47c6a7a87f18a112753eb98848f4c5333986bec1940558ce09cdaf53bf"}, - {file = "pygit2-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f0f69ea42231bebf08006c85cd5aa233c9c047c5a88b7fcfb4b639476b70e31b"}, - {file = "pygit2-1.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0097b6631ef05c837c4800fad559d0865a90c55475a18f38c6f2f5a12750e914"}, - {file = "pygit2-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb3b5bdcdfae205d9cc0c80bc53fad222a5ba67e66fd336ef223f86b0ac5835"}, - {file = "pygit2-1.10.1-cp310-cp310-win32.whl", hash = "sha256:3efd2a2ab2bb443e1b758525546d74a5a12fe27006194d3c02b3e6ecc1e101e6"}, - {file = "pygit2-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:11225811194ae6b9dbb34c2e8900e0eba6eacc180d82766e3dbddcbd2c6e6454"}, - {file = "pygit2-1.10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:73e251d0b73f1010ad28c20bcdcf33e312fb363f10b7268ad2bcfa09770f9ac2"}, - {file = "pygit2-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cb73f7967207a9ac485722ef0e517e5ca482f3c1308a0ac934707cb267b0ac7a"}, - {file = "pygit2-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b115bef251af4daf18f2f967287b56da2eae2941d5389dc1666bd0160892d769"}, - {file = "pygit2-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd55a6cf7ad6276fb5772e5c60c51fca2d9a5e68ea3e7237847421c10080a68"}, - {file = "pygit2-1.10.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:33138c256ad0ff084f5d8a82ab7d280f9ed6706ebb000ac82e3d133e2d82b366"}, - {file = "pygit2-1.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f4f507e5cd775f6d5d95ec65761af4cdb33b2f859af15bf10a06d11efd0d3b2"}, - {file = "pygit2-1.10.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:752f844d5379081fae5ef78e3bf6f0f35ae9b11aafc37e5e03e1c3607b196806"}, - {file = "pygit2-1.10.1-cp37-cp37m-win32.whl", hash = "sha256:b31ffdbc87629613ae03a533e01eee79112a12f66faf375fa08934074044a664"}, - {file = "pygit2-1.10.1-cp37-cp37m-win_amd64.whl", hash = "sha256:e09386b71ad474f2c2c02b6b251fa904b1145dabfe9095955ab30a789aaf84c0"}, - {file = "pygit2-1.10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:564e832e750f889aea3bb3e82674e1c860c9b89a141404530271e1341723a258"}, - {file = "pygit2-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43bb910272866eb822e930dbd0feecc340e0c24934143aab651fa180cc5ebfb0"}, - {file = "pygit2-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e4905cbb87db598b1cb38800ff995c0ba1f58745e2f52af4d54dbc93b9bda8"}, - {file = "pygit2-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb1f4689ce38cd62a7000d38602ba4d704df5cec708e5d98dadaffcf510f3317"}, - {file = "pygit2-1.10.1-cp38-cp38-win32.whl", hash = "sha256:b67ef30f3c022be1d6da9ef0188f60fc2d20639bff44693ef5653818e887001b"}, - {file = "pygit2-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:dcd849c44bd743d829dbd9dc9d7e13c14cf31a47c22e2e3f9e98fa845a8b8b28"}, - {file = "pygit2-1.10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e8bb9002924975271d64e8869b44ea97f068e85b5edd03e802e4917b770aaf2d"}, - {file = "pygit2-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:889ca83528c0649afd970da700cc6ed47dc340481f146a39ba5bfbeca1ddd6f8"}, - {file = "pygit2-1.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5465db21c6fd481ec29aa7afcca9a85b1fdb19b2f2d09a31b4bdba2f1bd0e75"}, - {file = "pygit2-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ceecd5d30583f9db56aadcd7238bb3c76a2934d8a932de47aed77fe3c188e7"}, - {file = "pygit2-1.10.1-cp39-cp39-win32.whl", hash = "sha256:9d6e1270b91e7bf70185bb4c3686e04cca87a385c8a2d5c74eec8770091531be"}, - {file = "pygit2-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:d4251830276018c2346ddccad4b4ce06ed1d983b002a633c4d894b13669052d0"}, - {file = "pygit2-1.10.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7eb2cee54a1cb468b5502493ee4f3ec2f1f82db9c46fab7dacaa37afc4fcde8e"}, - {file = "pygit2-1.10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:411dc8af5f25c30a0c3d79ee1e22fb892d6fd6ccb54d4c1fb7746e6274e36426"}, - {file = "pygit2-1.10.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe41da630f4e7cb290dc7e97edf30a59d634426af52a89d4ab5c0fb1ea9ccfe4"}, - {file = "pygit2-1.10.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9da53c6f5c08308450059d7dfb3067d59c45f14bee99743e536c5f9d9823f154"}, - {file = "pygit2-1.10.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb49f9469a893f75f105cdf2c79254859aaf2fdce1078c38514ca12fe185a759"}, - {file = "pygit2-1.10.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff838665d6410b5a605f53c1ccd2d2f87ca30de59e89773e7cb5e10211426f90"}, - {file = "pygit2-1.10.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9d23bb613f5692da78c09a79ae40d6ced57b772ae9153aed23a9aa1889a16c85"}, - {file = "pygit2-1.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3a3cc867fa6907bfc78d7d1322f3dabd4107b16238205df7e2dec9ee265f0c0"}, - {file = "pygit2-1.10.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb3eb2f1d437db6e115d5f56d122f2f3737fa2e6063aa42e4d856ca76d785ce6"}, - {file = "pygit2-1.10.1.tar.gz", hash = "sha256:354651bf062c02d1f08041d6fbf1a9b4bf7a93afce65979bdc08bdc65653aa2e"}, + {file = "pygit2-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:263e05ac655a4ce0a1083aaaedfd0a900b8dee2c3bb3ecf4f4e504a404467d1f"}, + {file = "pygit2-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ee6b4a0e181c576cdb64b1568bfbff3d1c2cd7e99808f578c8b08875c0f43739"}, + {file = "pygit2-1.11.1-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:d1b5fcaac1f29337f2d1465fa095e2e375b76a06385bda9391cb418c7937fb54"}, + {file = "pygit2-1.11.1-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:96ff745d3199909d06cab5e419a6b953be99992414a08ec4dddb682f395de8f1"}, + {file = "pygit2-1.11.1-cp310-cp310-win32.whl", hash = "sha256:b3c8726f0c9a2b0e04aac37b18027c58c2697b9c021d3458b28bc250b9b6aecf"}, + {file = "pygit2-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:f42409d25bbfc090fd1af1f5f47584d7e0c4212b037a7f86639a02c30420c6ee"}, + {file = "pygit2-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29f89d96bbb404ca1566418463521039903094fad2f81a76d7083810d2ea3aad"}, + {file = "pygit2-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d5c158b9430c5e76ca728b1a214bf21d355af6ac6e2da86ed17775b870b6c6eb"}, + {file = "pygit2-1.11.1-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:6c3434b143e7570ec45cd1a0e344fe7a12e64b99e7155fa38b74f724c8fc243c"}, + {file = "pygit2-1.11.1-cp311-cp311-manylinux_2_24_x86_64.whl", hash = "sha256:550aa503c86ef0061ce64d61c3672b15b500c2b1e4224c405acecfac2211b5d9"}, + {file = "pygit2-1.11.1-cp311-cp311-win32.whl", hash = "sha256:f270f86a0185ca2064e1aa6b8db3bb677b1bf76ee35f48ca5ce28a921fad5632"}, + {file = "pygit2-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:56b9deeab214653805214f05337f5e9552b47bf268c285551f20ea51a6056c3e"}, + {file = "pygit2-1.11.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3c5838e6516abc4384498f4b4c7f88578221596dc2ba8db2320ff2cfebe9787e"}, + {file = "pygit2-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a886aab5aae8d8db572e20b9f56c13cd506775265222ea7f35b2c781e4fa3a5e"}, + {file = "pygit2-1.11.1-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:3be4534180edd53e3e1da93c5b091975566bfdffdc73f21930d79fef096a25d2"}, + {file = "pygit2-1.11.1-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:4d6209c703764ae0ba57b17038482f3e54f432f80f88ccd490d7f8b70b167db6"}, + {file = "pygit2-1.11.1-cp38-cp38-win32.whl", hash = "sha256:ddb032fa71d4b4a64bf101e37eaa21f5369f20a862b5e34bbc33854a3a35f641"}, + {file = "pygit2-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8de0091e5eeaea2004f63f7dcb4540780f2124f68c0bcb670ae0fa9ada8bf66"}, + {file = "pygit2-1.11.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b44674e53efa9eca36e44f2f3d1a29e53e78649ba13105ae0b037d557f2c076"}, + {file = "pygit2-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0170f31c2efb15f6779689df328c05a8005ecb2b92784a37ff967d713cdafe82"}, + {file = "pygit2-1.11.1-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:960a55ff78f48887a7aa8ece952aad0f52f0a2ba1ad7bddd7064fbbefd85dfbb"}, + {file = "pygit2-1.11.1-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:df722c90fb54a42fa019dcf8d8f82961c3099c3024f1fda46c53e0886ff8f0f3"}, + {file = "pygit2-1.11.1-cp39-cp39-win32.whl", hash = "sha256:3b091e7fd00dd2a2cd3a6b5e235b6cbfbc1c07f15ee83a5cb3f188e1d6d1bca1"}, + {file = "pygit2-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:da040dc28800831bcbefef0850466739f103bfc769d952bd10c449646d52ce8f"}, + {file = "pygit2-1.11.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:585daa3956f1dc10d08e3459c20b57be42c7f9c0fbde21e797b3a00b5948f061"}, + {file = "pygit2-1.11.1-pp38-pypy38_pp73-manylinux_2_24_aarch64.whl", hash = "sha256:273878adeced2aec7885745b73fffb91a8e67868c105bf881b61008d42497ad6"}, + {file = "pygit2-1.11.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:48cfd72283a08a9226aca115870799ee92898d692699f541a3b3f519805108ec"}, + {file = "pygit2-1.11.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a9ca4cb2481d2df14d23c765facef325f717d9a3966a986b86e88d92eef11929"}, + {file = "pygit2-1.11.1-pp39-pypy39_pp73-manylinux_2_24_aarch64.whl", hash = "sha256:d5f64a424d9123b047458b0107c5dd33559184b56a1f58b10056ea5cbac74360"}, + {file = "pygit2-1.11.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f13e190cc080bde093138e12bcb609500276227e3e8e8bd8765a2fd49ae2efb8"}, + {file = "pygit2-1.11.1.tar.gz", hash = "sha256:793f583fd33620f0ac38376db0f57768ef2922b89b459e75b1ac440377eb64ec"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, @@ -1751,8 +1723,8 @@ pytest = [ {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.20.1.tar.gz", hash = "sha256:626699de2a747611f3eeb64168b3575f70439b06c3d0206e6ceaeeb956e65519"}, - {file = "pytest_asyncio-0.20.1-py3-none-any.whl", hash = "sha256:2c85a835df33fda40fe3973b451e0c194ca11bc2c007eabff90bb3d156fc172b"}, + {file = "pytest-asyncio-0.20.2.tar.gz", hash = "sha256:32a87a9836298a881c0ec637ebcc952cfe23a56436bdc0d09d1511941dd8a812"}, + {file = "pytest_asyncio-0.20.2-py3-none-any.whl", hash = "sha256:07e0abf9e6e6b95894a39f688a4a875d63c2128f76c02d03d16ccbc35bcc0f8a"}, ] pytest-cov = [ {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, @@ -1774,8 +1746,8 @@ python-multipart = [ {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, ] redis = [ - {file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"}, - {file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"}, + {file = "redis-4.3.5-py3-none-any.whl", hash = "sha256:46652271dc7525cd5a9667e5b0ca983c848c75b2b8f7425403395bb8379dcf25"}, + {file = "redis-4.3.5.tar.gz", hash = "sha256:30c07511627a4c5c4d970e060000772f323174f75e745a26938319817ead7a12"}, ] requests = [ {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, @@ -1786,8 +1758,8 @@ rfc3986 = [ {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, ] setuptools = [ - {file = "setuptools-65.5.0-py3-none-any.whl", hash = "sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356"}, - {file = "setuptools-65.5.0.tar.gz", hash = "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17"}, + {file = "setuptools-65.6.0-py3-none-any.whl", hash = "sha256:6211d2f5eddad8757bd0484923ca7c0a6302ebc4ab32ea5e94357176e0ca0840"}, + {file = "setuptools-65.6.0.tar.gz", hash = "sha256:d1eebf881c6114e51df1664bc2c9133d022f78d12d5f4f665b9191f084e2862d"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, @@ -1802,47 +1774,47 @@ sortedcontainers = [ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] sqlalchemy = [ - {file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27m-win32.whl", hash = "sha256:1d0c23ecf7b3bc81e29459c34a3f4c68ca538de01254e24718a7926810dc39a6"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27m-win_amd64.whl", hash = "sha256:6c9d004eb78c71dd4d3ce625b80c96a827d2e67af9c0d32b1c1e75992a7916cc"}, - {file = "SQLAlchemy-1.4.42-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9e3a65ce9ed250b2f096f7b559fe3ee92e6605fab3099b661f0397a9ac7c8d95"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:2e56dfed0cc3e57b2f5c35719d64f4682ef26836b81067ee6cfad062290fd9e2"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b42c59ffd2d625b28cdb2ae4cde8488543d428cba17ff672a543062f7caee525"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22459fc1718785d8a86171bbe7f01b5c9d7297301ac150f508d06e62a2b4e8d2"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df76e9c60879fdc785a34a82bf1e8691716ffac32e7790d31a98d7dec6e81545"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-win32.whl", hash = "sha256:e7e740453f0149437c101ea4fdc7eea2689938c5760d7dcc436c863a12f1f565"}, - {file = "SQLAlchemy-1.4.42-cp310-cp310-win_amd64.whl", hash = "sha256:effc89e606165ca55f04f3f24b86d3e1c605e534bf1a96e4e077ce1b027d0b71"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:97ff50cd85bb907c2a14afb50157d0d5486a4b4639976b4a3346f34b6d1b5272"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12c6949bae10f1012ab5c0ea52ab8db99adcb8c7b717938252137cdf694c775"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11b2ec26c5d2eefbc3e6dca4ec3d3d95028be62320b96d687b6e740424f83b7d"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-win32.whl", hash = "sha256:6045b3089195bc008aee5c273ec3ba9a93f6a55bc1b288841bd4cfac729b6516"}, - {file = "SQLAlchemy-1.4.42-cp311-cp311-win_amd64.whl", hash = "sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6e39e97102f8e26c6c8550cb368c724028c575ec8bc71afbbf8faaffe2b2092a"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15d878929c30e41fb3d757a5853b680a561974a0168cd33a750be4ab93181628"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fa5b7eb2051e857bf83bade0641628efe5a88de189390725d3e6033a1fff4257"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1c5f8182b4f89628d782a183d44db51b5af84abd6ce17ebb9804355c88a7b5"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-win32.whl", hash = "sha256:a7dd5b7b34a8ba8d181402d824b87c5cee8963cb2e23aa03dbfe8b1f1e417cde"}, - {file = "SQLAlchemy-1.4.42-cp36-cp36m-win_amd64.whl", hash = "sha256:5ede1495174e69e273fad68ad45b6d25c135c1ce67723e40f6cf536cb515e20b"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:9256563506e040daddccaa948d055e006e971771768df3bb01feeb4386c242b0"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4948b6c5f4e56693bbeff52f574279e4ff972ea3353f45967a14c30fb7ae2beb"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1811a0b19a08af7750c0b69e38dec3d46e47c4ec1d74b6184d69f12e1c99a5e0"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b01d9cd2f9096f688c71a3d0f33f3cd0af8549014e66a7a7dee6fc214a7277d"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-win32.whl", hash = "sha256:bd448b262544b47a2766c34c0364de830f7fb0772d9959c1c42ad61d91ab6565"}, - {file = "SQLAlchemy-1.4.42-cp37-cp37m-win_amd64.whl", hash = "sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3ab7c158f98de6cb4f1faab2d12973b330c2878d0c6b689a8ca424c02d66e1b3"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:934472bb7d8666727746a75670a1f8d91a9cae8c464bba79da30a0f6faccd9e1"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb94a3d1ba77ff2ef11912192c066f01e68416f554c194d769391638c8ad09a"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-win32.whl", hash = "sha256:f0f574465b78f29f533976c06b913e54ab4980b9931b69aa9d306afff13a9471"}, - {file = "SQLAlchemy-1.4.42-cp38-cp38-win_amd64.whl", hash = "sha256:a85723c00a636eed863adb11f1e8aaa36ad1c10089537823b4540948a8429798"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5ce6929417d5dce5ad1d3f147db81735a4a0573b8fb36e3f95500a06eaddd93e"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723e3b9374c1ce1b53564c863d1a6b2f1dc4e97b1c178d9b643b191d8b1be738"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:876eb185911c8b95342b50a8c4435e1c625944b698a5b4a978ad2ffe74502908"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd49af453e590884d9cdad3586415922a8e9bb669d874ee1dc55d2bc425aacd"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-win32.whl", hash = "sha256:e4ef8cb3c5b326f839bfeb6af5f406ba02ad69a78c7aac0fbeeba994ad9bb48a"}, - {file = "SQLAlchemy-1.4.42-cp39-cp39-win_amd64.whl", hash = "sha256:5f966b64c852592469a7eb759615bbd351571340b8b344f1d3fa2478b5a4c934"}, - {file = "SQLAlchemy-1.4.42.tar.gz", hash = "sha256:177e41914c476ed1e1b77fd05966ea88c094053e17a85303c4ce007f88eff363"}, + {file = "SQLAlchemy-1.4.44-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:da60b98b0f6f0df9fbf8b72d67d13b73aa8091923a48af79a951d4088530a239"}, + {file = "SQLAlchemy-1.4.44-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:95f4f8d62589755b507218f2e3189475a4c1f5cc9db2aec772071a7dc6cd5726"}, + {file = "SQLAlchemy-1.4.44-cp27-cp27m-win32.whl", hash = "sha256:afd1ac99179d1864a68c06b31263a08ea25a49df94e272712eb2824ef151e294"}, + {file = "SQLAlchemy-1.4.44-cp27-cp27m-win_amd64.whl", hash = "sha256:f8e5443295b218b08bef8eb85d31b214d184b3690d99a33b7bd8e5591e2b0aa1"}, + {file = "SQLAlchemy-1.4.44-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:53f90a2374f60e703c94118d21533765412da8225ba98659de7dd7998641ab17"}, + {file = "SQLAlchemy-1.4.44-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:65a0ad931944fcb0be12a8e0ac322dbd3ecf17c53f088bc10b6da8f0caac287b"}, + {file = "SQLAlchemy-1.4.44-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b185041a4dc5c685283ea98c2f67bbfa47bb28e4a4f5b27ebf40684e7a9f8"}, + {file = "SQLAlchemy-1.4.44-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:80ead36fb1d676cc019586ffdc21c7e906ce4bf243fe4021e4973dae332b6038"}, + {file = "SQLAlchemy-1.4.44-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68e0cd5d32a32c4395168d42f2fefbb03b817ead3a8f3704b8bd5697c0b26c24"}, + {file = "SQLAlchemy-1.4.44-cp310-cp310-win32.whl", hash = "sha256:ae1ed1ebc407d2f66c6f0ec44ef7d56e3f455859df5494680e2cf89dad8e3ae0"}, + {file = "SQLAlchemy-1.4.44-cp310-cp310-win_amd64.whl", hash = "sha256:6f0ea4d7348feb5e5d0bf317aace92e28398fa9a6e38b7be9ec1f31aad4a8039"}, + {file = "SQLAlchemy-1.4.44-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f5e8ed9cde48b76318ab989deeddc48f833d2a6a7b7c393c49b704f67dedf01d"}, + {file = "SQLAlchemy-1.4.44-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c857676d810ca196be73c98eb839125d6fa849bfa3589be06201a6517f9961c"}, + {file = "SQLAlchemy-1.4.44-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c56e6899fa6e767e4be5d106941804a4201c5cb9620a409c0b80448ec70b656"}, + {file = "SQLAlchemy-1.4.44-cp311-cp311-win32.whl", hash = "sha256:c46322354c58d4dc039a2c982d28284330f8919f31206894281f4b595b9d8dbe"}, + {file = "SQLAlchemy-1.4.44-cp311-cp311-win_amd64.whl", hash = "sha256:7313e4acebb9ae88dbde14a8a177467a7625b7449306c03a3f9f309b30e163d0"}, + {file = "SQLAlchemy-1.4.44-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:17aee7bfcef7bf0dea92f10e5dfdd67418dcf6fe0759f520e168b605855c003e"}, + {file = "SQLAlchemy-1.4.44-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9470633395e5f24d6741b4c8a6e905bce405a28cf417bba4ccbaadf3dab0111d"}, + {file = "SQLAlchemy-1.4.44-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:393f51a09778e8984d735b59a810731394308b4038acdb1635397c2865dae2b6"}, + {file = "SQLAlchemy-1.4.44-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7e3b9e01fdbe1ce3a165cc7e1ff52b24813ee79c6df6dee0d1e13888a97817e"}, + {file = "SQLAlchemy-1.4.44-cp36-cp36m-win32.whl", hash = "sha256:6a06c2506c41926d2769f7968759995f2505e31c5b5a0821e43ca5a3ddb0e8ae"}, + {file = "SQLAlchemy-1.4.44-cp36-cp36m-win_amd64.whl", hash = "sha256:3ca21b35b714ce36f4b8d1ee8d15f149db8eb43a472cf71600bf18dae32286e7"}, + {file = "SQLAlchemy-1.4.44-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:3cbdbed8cdcae0f83640a9c44fa02b45a6c61e149c58d45a63c9581aba62850f"}, + {file = "SQLAlchemy-1.4.44-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a22208c1982f1fe2ae82e5e4c3d4a6f2445a7a0d65fb7983a3d7cbbe3983f5a4"}, + {file = "SQLAlchemy-1.4.44-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d3b9ac11f36ab9a726097fba7c7f6384f0129aedb017f1d4d1d4fce9052a1320"}, + {file = "SQLAlchemy-1.4.44-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d654870a66027af3a26df1372cf7f002e161c6768ebe4c9c6fdc0da331cb5173"}, + {file = "SQLAlchemy-1.4.44-cp37-cp37m-win32.whl", hash = "sha256:0be9b479c5806cece01f1581726573a8d6515f8404e082c375b922c45cfc2a7b"}, + {file = "SQLAlchemy-1.4.44-cp37-cp37m-win_amd64.whl", hash = "sha256:3eba07f740488c3a125f17c092a81eeae24a6c7ec32ac9dbc52bf7afaf0c4f16"}, + {file = "SQLAlchemy-1.4.44-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:ad5f966623905ee33694680dda1b735544c99c7638f216045d21546d3d8c6f5b"}, + {file = "SQLAlchemy-1.4.44-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f68eab46649504eb95be36ca529aea16cd199f080726c28cbdbcbf23d20b2a2"}, + {file = "SQLAlchemy-1.4.44-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:21f3df74a0ab39e1255e94613556e33c1dc3b454059fe0b365ec3bbb9ed82e4a"}, + {file = "SQLAlchemy-1.4.44-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8080bc51a775627865e0f1dbfc0040ff4ace685f187f6036837e1727ba2ed10"}, + {file = "SQLAlchemy-1.4.44-cp38-cp38-win32.whl", hash = "sha256:b6a337a2643a41476fb6262059b8740f4b9a2ec29bf00ffb18c18c080f6e0aed"}, + {file = "SQLAlchemy-1.4.44-cp38-cp38-win_amd64.whl", hash = "sha256:b737fbeb2f78926d1f59964feb287bbbd050e7904766f87c8ce5cfb86e6d840c"}, + {file = "SQLAlchemy-1.4.44-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:c9aa372b295a36771cffc226b6517df3011a7d146ac22d19fa6a75f1cdf9d7e6"}, + {file = "SQLAlchemy-1.4.44-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:237067ba0ef45a518b64606e1807f7229969ad568288b110ed5f0ca714a3ed3a"}, + {file = "SQLAlchemy-1.4.44-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6d7e1b28342b45f19e3dea7873a9479e4a57e15095a575afca902e517fb89652"}, + {file = "SQLAlchemy-1.4.44-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c0093678001f5d79f2dcbf3104c54d6c89e41ab50d619494c503a4d3f1aef2"}, + {file = "SQLAlchemy-1.4.44-cp39-cp39-win32.whl", hash = "sha256:7cf7c7adbf4417e3f46fc5a2dbf8395a5a69698217337086888f79700a12e93a"}, + {file = "SQLAlchemy-1.4.44-cp39-cp39-win_amd64.whl", hash = "sha256:d3b6d4588994da73567bb00af9d7224a16c8027865a8aab53ae9be83f9b7cbd1"}, + {file = "SQLAlchemy-1.4.44.tar.gz", hash = "sha256:2dda5f96719ae89b3ec0f1b79698d86eb9aecb1d54e990abb3fdd92c04b46a90"}, ] srcinfo = [ {file = "srcinfo-0.0.8-py3-none-any.whl", hash = "sha256:0922ee4302b927d7ddea74c47e539b226a0a7738dc89f95b66404a28d07f3f6b"}, @@ -1873,8 +1845,8 @@ urllib3 = [ {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, ] uvicorn = [ - {file = "uvicorn-0.19.0-py3-none-any.whl", hash = "sha256:cc277f7e73435748e69e075a721841f7c4a95dba06d12a72fe9874acced16f6f"}, - {file = "uvicorn-0.19.0.tar.gz", hash = "sha256:cf538f3018536edb1f4a826311137ab4944ed741d52aeb98846f52215de57f25"}, + {file = "uvicorn-0.20.0-py3-none-any.whl", hash = "sha256:c3ed1598a5668208723f2bb49336f4509424ad198d6ab2615b7783db58d919fd"}, + {file = "uvicorn-0.20.0.tar.gz", hash = "sha256:a4e12017b940247f836bc90b72e725d7dfd0c8ed1c51eb365f5ba30d9f5127d8"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, @@ -1884,72 +1856,6 @@ werkzeug = [ {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"}, {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"}, ] -wrapt = [ - {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, - {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, - {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, - {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, - {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, - {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, - {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, - {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, - {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, - {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, - {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, - {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, - {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, - {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, - {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, - {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, -] wsproto = [ {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, diff --git a/pyproject.toml b/pyproject.toml index 7fc0db47..e977ad4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,16 +62,16 @@ asgiref = "^3.4.1" bcrypt = "^4.0.0" bleach = "^5.0.0" email-validator = "^1.3.0" -fakeredis = "^1.10.0" +fakeredis = "^2.0.0" feedgen = "^0.9.0" -httpx = "^0.23.0" +httpx = "^0.23.1" itsdangerous = "^2.0.1" lxml = "^4.6.3" -orjson = "^3.8.1" +orjson = "^3.8.2" protobuf = "^4.21.9" -pygit2 = "^1.7.0" +pygit2 = "^1.11.1" python-multipart = "^0.0.5" -redis = "^4.0.0" +redis = "^4.3.5" requests = "^2.28.1" paginate = "^0.5.6" @@ -85,7 +85,7 @@ Werkzeug = "^2.0.2" SQLAlchemy = "^1.4.26" # ASGI -uvicorn = "^0.19.0" +uvicorn = "^0.20.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.0" prometheus-fastapi-instrumentator = "^5.7.1" @@ -99,7 +99,7 @@ srcinfo = "^0.0.8" [tool.poetry.dev-dependencies] coverage = "^6.0.2" pytest = "^7.2.0" -pytest-asyncio = "^0.20.1" +pytest-asyncio = "^0.20.2" pytest-cov = "^4.0.0" pytest-tap = "^3.2" From 512ba0238914c28a4e445d04ae08b714bd14558c Mon Sep 17 00:00:00 2001 From: renovate Date: Wed, 23 Nov 2022 00:25:31 +0000 Subject: [PATCH 1637/1891] fix(deps): update dependency fastapi to ^0.87.0 --- poetry.lock | 80 +++++++++++++++++++------------------------------- pyproject.toml | 2 +- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/poetry.lock b/poetry.lock index 22cbd3fd..12770f64 100644 --- a/poetry.lock +++ b/poetry.lock @@ -69,7 +69,7 @@ python-versions = ">=3.5" dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "authlib" @@ -138,7 +138,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode-backport = ["unicodedata2"] +unicode_backport = ["unicodedata2"] [[package]] name = "click" @@ -260,7 +260,7 @@ lua = ["lupa (>=1.13,<2.0)"] [[package]] name = "fastapi" -version = "0.85.2" +version = "0.87.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -268,13 +268,13 @@ python-versions = ">=3.7" [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.20.4" +starlette = "0.21.0" [package.extras] -all = ["email-validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] -dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] +all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.114)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer[all] (>=0.6.1,<0.7.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "pytest-cov (>=2.12.0,<5.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<=1.4.41)", "types-orjson (==3.6.2)", "types-ujson (==5.5.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.8.0)", "coverage[toml] (>=6.5.0,<7.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.114)", "sqlalchemy (>=1.3.18,<=1.4.41)", "types-orjson (==3.6.2)", "types-ujson (==5.5.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] [[package]] name = "feedgen" @@ -309,7 +309,7 @@ optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" [package.extras] -docs = ["Sphinx", "docutils (<0.18)"] +docs = ["docutils (<0.18)", "sphinx"] test = ["faulthandler", "objgraph", "psutil"] [[package]] @@ -320,9 +320,6 @@ category = "main" optional = false python-versions = ">=3.5" -[package.dependencies] -setuptools = ">=3.0" - [package.extras] eventlet = ["eventlet (>=0.24.1)"] gevent = ["gevent (>=1.4.0)"] @@ -411,7 +408,7 @@ toml = "*" wsproto = ">=0.14.0" [package.extras] -docs = ["pydata_sphinx_theme"] +docs = ["pydata-sphinx-theme"] h3 = ["aioquic (>=0.9.0,<1.0)"] trio = ["trio (>=0.11.0)"] uvloop = ["uvloop"] @@ -489,7 +486,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] -htmlsoup = ["BeautifulSoup4"] +htmlsoup = ["beautifulsoup4"] source = ["Cython (>=0.29.7)"] [[package]] @@ -504,7 +501,7 @@ python-versions = ">=3.7" MarkupSafe = ">=0.9.2" [package.extras] -babel = ["Babel"] +babel = ["babel"] lingua = ["lingua"] testing = ["pytest"] @@ -817,7 +814,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rfc3986" @@ -833,19 +830,6 @@ idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} [package.extras] idna2008 = ["idna"] -[[package]] -name = "setuptools" -version = "65.6.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" version = "1.16.0" @@ -886,21 +870,21 @@ aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] +mssql_pymssql = ["pymssql"] +mssql_pyodbc = ["pyodbc"] mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] +mysql_connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql_psycopg2binary = ["psycopg2-binary"] +postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3_binary"] +sqlcipher = ["sqlcipher3-binary"] [[package]] name = "srcinfo" @@ -915,7 +899,7 @@ parse = "*" [[package]] name = "starlette" -version = "0.20.4" +version = "0.21.0" description = "The little ASGI library that shines." category = "main" optional = false @@ -926,10 +910,10 @@ anyio = ">=3.4.0,<5" typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] -full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] [[package]] -name = "tap-py" +name = "tap.py" version = "3.1" description = "Test Anything Protocol (TAP) tools" category = "dev" @@ -1039,7 +1023,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.9,<3.11" -content-hash = "b178f1fcbba93d9cbc8dd23193b25afd5e1ba971196757abf098a1dfa2666cba" +content-hash = "02d70de5b58cf84a7b9015fc1d1a598bdb139b32f7239846183eb924e336ce86" [metadata.files] aiofiles = [ @@ -1280,8 +1264,8 @@ fakeredis = [ {file = "fakeredis-2.0.0.tar.gz", hash = "sha256:6d1dc2417921b7ce56a80877afa390d6335a3154146f201a86e3a14417bdc79e"}, ] fastapi = [ - {file = "fastapi-0.85.2-py3-none-any.whl", hash = "sha256:6292db0edd4a11f0d938d6033ccec5f706e9d476958bf33b119e8ddb4e524bde"}, - {file = "fastapi-0.85.2.tar.gz", hash = "sha256:3e10ea0992c700e0b17b6de8c2092d7b9cd763ce92c49ee8d4be10fee3b2f367"}, + {file = "fastapi-0.87.0-py3-none-any.whl", hash = "sha256:254453a2e22f64e2a1b4e1d8baf67d239e55b6c8165c079d25746a5220c81bb4"}, + {file = "fastapi-0.87.0.tar.gz", hash = "sha256:07032e53df9a57165047b4f38731c38bdcc3be5493220471015e2b4b51b486a4"}, ] feedgen = [ {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, @@ -1757,10 +1741,6 @@ rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, ] -setuptools = [ - {file = "setuptools-65.6.0-py3-none-any.whl", hash = "sha256:6211d2f5eddad8757bd0484923ca7c0a6302ebc4ab32ea5e94357176e0ca0840"}, - {file = "setuptools-65.6.0.tar.gz", hash = "sha256:d1eebf881c6114e51df1664bc2c9133d022f78d12d5f4f665b9191f084e2862d"}, -] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -1821,10 +1801,10 @@ srcinfo = [ {file = "srcinfo-0.0.8.tar.gz", hash = "sha256:5ac610cf8b15d4b0a0374bd1f7ad301675c2938f0414addf3ef7d7e3fcaf5c65"}, ] starlette = [ - {file = "starlette-0.20.4-py3-none-any.whl", hash = "sha256:c0414d5a56297d37f3db96a84034d61ce29889b9eaccf65eb98a0b39441fcaa3"}, - {file = "starlette-0.20.4.tar.gz", hash = "sha256:42fcf3122f998fefce3e2c5ad7e5edbf0f02cf685d646a83a08d404726af5084"}, + {file = "starlette-0.21.0-py3-none-any.whl", hash = "sha256:0efc058261bbcddeca93cad577efd36d0c8a317e44376bcfc0e097a2b3dc24a7"}, + {file = "starlette-0.21.0.tar.gz", hash = "sha256:b1b52305ee8f7cfc48cde383496f7c11ab897cd7112b33d998b1317dc8ef9027"}, ] -tap-py = [ +"tap.py" = [ {file = "tap.py-3.1-py3-none-any.whl", hash = "sha256:928c852f3361707b796c93730cc5402c6378660b161114461066acf53d65bf5d"}, {file = "tap.py-3.1.tar.gz", hash = "sha256:3c0cd45212ad5a25b35445964e2517efa000a118a1bfc3437dae828892eaf1e1"}, ] diff --git a/pyproject.toml b/pyproject.toml index e977ad4e..762a52c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,7 @@ pytest-xdist = "^3.0.2" filelock = "^3.3.2" posix-ipc = "^1.0.5" pyalpm = "^0.10.6" -fastapi = "^0.85.1" +fastapi = "^0.87.0" srcinfo = "^0.0.8" [tool.poetry.dev-dependencies] From 1216399d53b3f3163eccc2ea0aacaeaf23562373 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 24 Nov 2022 22:23:37 +0100 Subject: [PATCH 1638/1891] fix(test): FastAPI 0.87.0 - error fixes FastAPI 0.87.0 switched to the httpx library for their TestClient * allow_redirects is deprecated and replaced by follow_redirects Signed-off-by: moson-mo --- test/test_accounts_routes.py | 78 ++++++--------- test/test_auth_routes.py | 28 +++--- test/test_homepage.py | 9 +- test/test_packages_routes.py | 45 +++++---- test/test_pkgbase_routes.py | 163 +++++++++++++++++-------------- test/test_requests.py | 31 +++--- test/test_routes.py | 8 +- test/test_trusted_user_routes.py | 82 +++++++--------- 8 files changed, 218 insertions(+), 226 deletions(-) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index f44fd44e..44226627 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -70,6 +70,9 @@ def client() -> TestClient: # Necessary for forged login CSRF protection on the login route. Set here # instead of only on the necessary requests for convenience. client.headers.update(TEST_REFERER) + + # disable redirects for our tests + client.follow_redirects = False yield client @@ -104,9 +107,7 @@ def test_get_passreset_authed_redirects(client: TestClient, user: User): assert sid is not None with client as request: - response = request.get( - "/passreset", cookies={"AURSID": sid}, allow_redirects=False - ) + response = request.get("/passreset", cookies={"AURSID": sid}) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -140,7 +141,7 @@ def test_get_passreset_translation(client: TestClient): def test_get_passreset_with_resetkey(client: TestClient): with client as request: - response = request.get("/passreset", data={"resetkey": "abcd"}) + response = request.get("/passreset", params={"resetkey": "abcd"}) assert response.status_code == int(HTTPStatus.OK) @@ -153,7 +154,6 @@ def test_post_passreset_authed_redirects(client: TestClient, user: User): "/passreset", cookies={"AURSID": sid}, data={"user": "blah"}, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -323,7 +323,7 @@ def post_register(request, **kwargs): for k, v in args.items(): data[k] = v - return request.post("/register", data=data, allow_redirects=False) + return request.post("/register", data=data) def test_post_register(client: TestClient): @@ -737,7 +737,7 @@ def test_get_account_edit_unauthorized(client: TestClient, user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: # Try to edit `test2` while authenticated as `test`. - response = request.get(endpoint, cookies={"AURSID": sid}, allow_redirects=False) + response = request.get(endpoint, cookies={"AURSID": sid}) assert response.status_code == int(HTTPStatus.SEE_OTHER) expected = f"/account/{user2.Username}" @@ -755,7 +755,6 @@ def test_post_account_edit(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -841,9 +840,7 @@ def test_post_account_edit_dev(client: TestClient, tu_user: User): endpoint = f"/account/{tu_user.Username}/edit" with client as request: - response = request.post( - endpoint, cookies={"AURSID": sid}, data=post_data, allow_redirects=False - ) + response = request.post(endpoint, cookies={"AURSID": sid}, data=post_data) assert response.status_code == int(HTTPStatus.OK) expected = "The account, test, " @@ -867,7 +864,6 @@ def test_post_account_edit_language(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -897,7 +893,6 @@ def test_post_account_edit_timezone(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -914,7 +909,6 @@ def test_post_account_edit_error_missing_password(client: TestClient, user: User "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -934,7 +928,6 @@ def test_post_account_edit_error_invalid_password(client: TestClient, user: User "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1039,9 +1032,7 @@ def test_post_account_edit_error_unauthorized(client: TestClient, user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: # Attempt to edit 'test2' while logged in as 'test'. - response = request.post( - endpoint, cookies={"AURSID": sid}, data=post_data, allow_redirects=False - ) + response = request.post(endpoint, cookies={"AURSID": sid}, data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) expected = f"/account/{user2.Username}" @@ -1064,7 +1055,6 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -1077,7 +1067,6 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -1099,7 +1088,6 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -1116,7 +1104,6 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -1133,9 +1120,7 @@ def test_post_account_edit_invalid_ssh_pubkey(client: TestClient, user: User): } cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.post( - "/account/test/edit", data=data, cookies=cookies, allow_redirects=False - ) + response = request.post("/account/test/edit", data=data, cookies=cookies) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1157,7 +1142,6 @@ def test_post_account_edit_password(client: TestClient, user: User): "/account/test/edit", cookies={"AURSID": sid}, data=post_data, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -1197,7 +1181,7 @@ def test_post_account_edit_other_user_as_user(client: TestClient, user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/account/{user2.Username}" @@ -1208,7 +1192,7 @@ def test_post_account_edit_self_type_as_tu(client: TestClient, tu_user: User): # We cannot see the Account Type field on our own edit page. with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) assert "id_type" in resp.text @@ -1239,7 +1223,7 @@ def test_post_account_edit_other_user_type_as_tu( # As a TU, we can see the Account Type field for other users. with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) assert "id_type" in resp.text @@ -1277,19 +1261,20 @@ def test_post_account_edit_other_user_suspend_as_tu(client: TestClient, tu_user: # apart from `tu_user`s during our testing. user_client = TestClient(app=app) user_client.headers.update(TEST_REFERER) + user_client.follow_redirects = False # Test that `user` can view their account edit page while logged in. user_cookies = {"AURSID": sid} with client as request: endpoint = f"/account/{user.Username}/edit" - resp = request.get(endpoint, cookies=user_cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=user_cookies) assert resp.status_code == HTTPStatus.OK cookies = {"AURSID": tu_user.login(Request(), "testPassword")} assert cookies is not None # This is useless, we create the dict here ^ # As a TU, we can see the Account for other users. with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) # As a TU, we can modify other user's account types. data = { @@ -1299,12 +1284,13 @@ def test_post_account_edit_other_user_suspend_as_tu(client: TestClient, tu_user: "passwd": "testPassword", } with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.OK) # Test that `user` no longer has a session. with user_client as request: - resp = request.get(endpoint, cookies=user_cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=user_cookies) assert resp.status_code == HTTPStatus.SEE_OTHER # Since user is now suspended, they should not be able to login. @@ -1341,9 +1327,7 @@ def test_get_account(client: TestClient, user: User): sid = user.login(request, "testPassword") with client as request: - response = request.get( - "/account/test", cookies={"AURSID": sid}, allow_redirects=False - ) + response = request.get("/account/test", cookies={"AURSID": sid}) assert response.status_code == int(HTTPStatus.OK) @@ -1353,16 +1337,14 @@ def test_get_account_not_found(client: TestClient, user: User): sid = user.login(request, "testPassword") with client as request: - response = request.get( - "/account/not_found", cookies={"AURSID": sid}, allow_redirects=False - ) + response = request.get("/account/not_found", cookies={"AURSID": sid}) assert response.status_code == int(HTTPStatus.NOT_FOUND) def test_get_account_unauthenticated(client: TestClient, user: User): with client as request: - response = request.get("/account/test", allow_redirects=False) + response = request.get("/account/test") assert response.status_code == int(HTTPStatus.UNAUTHORIZED) content = response.content.decode() @@ -1832,7 +1814,7 @@ def test_get_terms_of_service(client: TestClient, user: User): ) with client as request: - response = request.get("/tos", allow_redirects=False) + response = request.get("/tos") assert response.status_code == int(HTTPStatus.SEE_OTHER) request = Request() @@ -1842,12 +1824,12 @@ def test_get_terms_of_service(client: TestClient, user: User): # First of all, let's test that we get redirected to /tos # when attempting to browse authenticated without accepting terms. with client as request: - response = request.get("/", cookies=cookies, allow_redirects=False) + response = request.get("/", cookies=cookies) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tos" with client as request: - response = request.get("/tos", cookies=cookies, allow_redirects=False) + response = request.get("/tos", cookies=cookies) assert response.status_code == int(HTTPStatus.OK) with db.begin(): @@ -1856,7 +1838,7 @@ def test_get_terms_of_service(client: TestClient, user: User): ) with client as request: - response = request.get("/tos", cookies=cookies, allow_redirects=False) + response = request.get("/tos", cookies=cookies) # We accepted the term, there's nothing left to accept. assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -1865,7 +1847,7 @@ def test_get_terms_of_service(client: TestClient, user: User): term.Revision = 2 with client as request: - response = request.get("/tos", cookies=cookies, allow_redirects=False) + response = request.get("/tos", cookies=cookies) # This time, we have a modified term Revision that hasn't # yet been agreed to via AcceptedTerm update. assert response.status_code == int(HTTPStatus.OK) @@ -1874,7 +1856,7 @@ def test_get_terms_of_service(client: TestClient, user: User): accepted_term.Revision = term.Revision with client as request: - response = request.get("/tos", cookies=cookies, allow_redirects=False) + response = request.get("/tos", cookies=cookies) # We updated the term revision, there's nothing left to accept. assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -1931,7 +1913,7 @@ def test_post_terms_of_service(client: TestClient, user: User): # Now, see that GET redirects us to / with no terms left to accept. with client as request: - response = request.get("/tos", cookies=cookies, allow_redirects=False) + response = request.get("/tos", cookies=cookies) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -1946,7 +1928,7 @@ def test_account_comments_not_found(client: TestClient, user: User): def test_accounts_unauthorized(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get("/accounts", cookies=cookies, allow_redirects=False) + resp = request.get("/accounts", cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 87ad86f6..150625cd 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -33,6 +33,9 @@ def client() -> TestClient: # Necessary for forged login CSRF protection on the login route. Set here # instead of only on the necessary requests for convenience. client.headers.update(TEST_REFERER) + + # disable redirects for our tests + client.follow_redirects = False yield client @@ -58,21 +61,20 @@ def test_login_logout(client: TestClient, user: User): response = request.get("/login") assert response.status_code == int(HTTPStatus.OK) - response = request.post("/login", data=post_data, allow_redirects=False) + response = request.post("/login", data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) # Simulate following the redirect location from above's response. response = request.get(response.headers.get("location")) assert response.status_code == int(HTTPStatus.OK) - response = request.post("/logout", data=post_data, allow_redirects=False) + response = request.post("/logout", data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) response = request.post( "/logout", data=post_data, cookies={"AURSID": response.cookies.get("AURSID")}, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -94,7 +96,7 @@ def test_login_email(client: TestClient, user: user): post_data = {"user": user.Email, "passwd": "testPassword", "next": "/"} with client as request: - resp = request.post("/login", data=post_data, allow_redirects=False) + resp = request.post("/login", data=post_data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert "AURSID" in resp.cookies @@ -119,14 +121,14 @@ def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User): # Perform a login request with the data matching our user. with client as request: - response = request.post("/login", data=post_data, allow_redirects=False) + response = request.post("/login", data=post_data) # Make sure we got the expected status out of it. assert response.status_code == int(HTTPStatus.SEE_OTHER) # Let's check what we got in terms of cookies for AURSID. # Make sure that a secure cookie got passed to us. - cookie = next(c for c in response.cookies if c.name == "AURSID") + cookie = next(c for c in response.cookies.jar if c.name == "AURSID") assert cookie.secure is False assert cookie.has_nonstandard_attr("HttpOnly") is False assert cookie.has_nonstandard_attr("SameSite") is True @@ -160,14 +162,14 @@ def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User): # Perform a login request with the data matching our user. with client as request: - response = request.post("/login", data=post_data, allow_redirects=False) + response = request.post("/login", data=post_data) # Make sure we got the expected status out of it. assert response.status_code == int(HTTPStatus.SEE_OTHER) # Let's check what we got in terms of cookies for AURSID. # Make sure that a secure cookie got passed to us. - cookie = next(c for c in response.cookies if c.name == "AURSID") + cookie = next(c for c in response.cookies.jar if c.name == "AURSID") assert cookie.secure is True assert cookie.has_nonstandard_attr("HttpOnly") is True assert cookie.has_nonstandard_attr("SameSite") is True @@ -186,7 +188,7 @@ def test_authenticated_login(client: TestClient, user: User): with client as request: # Try to login. - response = request.post("/login", data=post_data, allow_redirects=False) + response = request.post("/login", data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -194,9 +196,7 @@ def test_authenticated_login(client: TestClient, user: User): # when requesting GET /login as an authenticated user. # Now, let's verify that we receive 403 Forbidden when we # try to get /login as an authenticated user. - response = request.get( - "/login", cookies=response.cookies, allow_redirects=False - ) + response = request.get("/login", cookies=response.cookies) assert response.status_code == int(HTTPStatus.OK) assert "Logged-in as: test" in response.text @@ -205,7 +205,7 @@ def test_unauthenticated_logout_unauthorized(client: TestClient): with client as request: # Alright, let's verify that attempting to /logout when not # authenticated returns 401 Unauthorized. - response = request.post("/logout", allow_redirects=False) + response = request.post("/logout") assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location").startswith("/login") @@ -232,7 +232,7 @@ def test_login_remember_me(client: TestClient, user: User): } with client as request: - response = request.post("/login", data=post_data, allow_redirects=False) + response = request.post("/login", data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert "AURSID" in response.cookies diff --git a/test/test_homepage.py b/test/test_homepage.py index 521f71c4..1aad30f7 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -253,7 +253,8 @@ def test_homepage_dashboard_requests(redis, packages, user): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.get("/", cookies=cookies) + request.cookies = cookies + response = request.get("/") assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -270,7 +271,8 @@ def test_homepage_dashboard_flagged_packages(redis, packages, user): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.get("/", cookies=cookies) + request.cookies = cookies + response = request.get("/") assert response.status_code == int(HTTPStatus.OK) # Check to see that the package showed up in the Flagged Packages table. @@ -293,7 +295,8 @@ def test_homepage_dashboard_flagged(user: User, user2: User, package: Package): # flagged co-maintained packages. comaint_cookies = {"AURSID": user2.login(Request(), "testPassword")} with client as request: - resp = request.get("/", cookies=comaint_cookies) + request.cookies = comaint_cookies + resp = request.get("/") assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 3b717783..29872cb8 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -65,7 +65,11 @@ def setup(db_test): @pytest.fixture def client() -> TestClient: """Yield a FastAPI TestClient.""" - yield TestClient(app=asgi.app) + client = TestClient(app=asgi.app) + + # disable redirects for our tests + client.follow_redirects = False + yield client def create_user(username: str) -> User: @@ -1142,7 +1146,6 @@ def test_packages_post_unknown_action(client: TestClient, user: User, package: P "/packages", data={"action": "unknown"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1159,7 +1162,6 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): "/packages", data={"action": "stub"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1180,7 +1182,6 @@ def test_packages_post(client: TestClient, user: User, package: Package): "/packages", data={"action": "stub"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.OK) @@ -1203,7 +1204,8 @@ def test_packages_post_unflag( # Don't supply any packages. post_data = {"action": "unflag", "IDs": []} with client as request: - resp = request.post("/packages", data=post_data, cookies=cookies) + request.cookies = cookies + resp = request.post("/packages", data=post_data) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to unflag." @@ -1212,7 +1214,8 @@ def test_packages_post_unflag( # Unflag the package as `user`. post_data = {"action": "unflag", "IDs": [package.ID]} with client as request: - resp = request.post("/packages", data=post_data, cookies=cookies) + request.cookies = cookies + resp = request.post("/packages", data=post_data) assert resp.status_code == int(HTTPStatus.OK) assert package.PackageBase.Flagger is None successes = get_successes(resp.text) @@ -1229,7 +1232,8 @@ def test_packages_post_unflag( maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} post_data = {"action": "unflag", "IDs": [package.ID]} with client as request: - resp = request.post("/packages", data=post_data, cookies=maint_cookies) + request.cookies = maint_cookies + resp = request.post("/packages", data=post_data) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to unflag." @@ -1387,7 +1391,8 @@ def test_packages_post_disown_as_maintainer( # Try to run the disown action with no IDs; get an error. cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "disown"}, cookies=cookies) + request.cookies = cookies + resp = request.post("/packages", data={"action": "disown"}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to disown." @@ -1396,9 +1401,8 @@ def test_packages_post_disown_as_maintainer( # Try to disown `package` without giving the confirm argument. with client as request: - resp = request.post( - "/packages", data={"action": "disown", "IDs": [package.ID]}, cookies=cookies - ) + request.cookies = cookies + resp = request.post("/packages", data={"action": "disown", "IDs": [package.ID]}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) assert package.PackageBase.Maintainer is not None errors = get_errors(resp.text) @@ -1411,10 +1415,10 @@ def test_packages_post_disown_as_maintainer( # Now, try to disown `package` without credentials (as `user`). user_cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = user_cookies resp = request.post( "/packages", data={"action": "disown", "IDs": [package.ID], "confirm": True}, - cookies=user_cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) assert package.PackageBase.Maintainer is not None @@ -1424,10 +1428,10 @@ def test_packages_post_disown_as_maintainer( # Now, let's really disown `package` as `maintainer`. with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "disown", "IDs": [package.ID], "confirm": True}, - cookies=cookies, ) assert package.PackageBase.Maintainer is None @@ -1463,9 +1467,8 @@ def test_packages_post_delete( # First, let's try to use the delete action with no packages IDs. user_cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post( - "/packages", data={"action": "delete"}, cookies=user_cookies - ) + request.cookies = user_cookies + resp = request.post("/packages", data={"action": "delete"}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to delete." @@ -1473,10 +1476,10 @@ def test_packages_post_delete( # Now, let's try to delete real packages without supplying "confirm". with client as request: + request.cookies = user_cookies resp = request.post( "/packages", data={"action": "delete", "IDs": [package.ID]}, - cookies=user_cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1488,10 +1491,10 @@ def test_packages_post_delete( # And again, with everything, but `user` doesn't have permissions. with client as request: + request.cookies = user_cookies resp = request.post( "/packages", data={"action": "delete", "IDs": [package.ID], "confirm": True}, - cookies=user_cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1503,10 +1506,10 @@ def test_packages_post_delete( # an invalid package ID. tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: + request.cookies = tu_cookies resp = request.post( "/packages", data={"action": "delete", "IDs": [0], "confirm": True}, - cookies=tu_cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1516,10 +1519,10 @@ def test_packages_post_delete( # Whoo. Now, let's finally make a valid request as `tu_user` # to delete `package`. with client as request: + request.cookies = tu_cookies resp = request.post( "/packages", data={"action": "delete", "IDs": [package.ID], "confirm": True}, - cookies=tu_cookies, ) assert resp.status_code == int(HTTPStatus.OK) successes = get_successes(resp.text) @@ -1541,7 +1544,7 @@ def test_account_comments_unauthorized(client: TestClient, user: User): leverage existing fixtures.""" endpoint = f"/account/{user.Username}/comments" with client as request: - resp = request.get(endpoint, allow_redirects=False) + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location").startswith("/login") diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index 18c11626..dd92d72d 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -59,7 +59,11 @@ def setup(db_test): @pytest.fixture def client() -> TestClient: """Yield a FastAPI TestClient.""" - yield TestClient(app=asgi.app) + client = TestClient(app=asgi.app) + + # disable redirects for our tests + client.follow_redirects = False + yield client def create_user(username: str) -> User: @@ -245,7 +249,7 @@ def test_pkgbase_not_found(client: TestClient): def test_pkgbase_redirect(client: TestClient, package: Package): with client as request: - resp = request.get(f"/pkgbase/{package.Name}", allow_redirects=False) + resp = request.get(f"/pkgbase/{package.Name}") assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/packages/{package.Name}" @@ -256,7 +260,7 @@ def test_pkgbase(client: TestClient, package: Package): expected = [package.Name, second.Name] with client as request: - resp = request.get(f"/pkgbase/{package.Name}", allow_redirects=False) + resp = request.get(f"/pkgbase/{package.Name}") assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -287,7 +291,7 @@ def test_pkgbase_maintainer( ) with client as request: - resp = request.get(f"/pkgbase/{package.Name}") + resp = request.get(f"/pkgbase/{package.Name}", follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -308,7 +312,7 @@ def test_pkgbase_voters(client: TestClient, tu_user: User, package: Package): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) # We should've gotten one link to the voter, tu_user. @@ -327,7 +331,7 @@ def test_pkgbase_voters_unauthorized(client: TestClient, user: User, package: Pa db.create(PackageVote, User=user, PackageBase=pkgbase, VoteTS=now) with client as request: - resp = request.get(endpoint, allow_redirects=False) + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -420,7 +424,7 @@ def test_pkgbase_comments( assert resp.headers.get("location")[:prefix_len] == expected_prefix with client as request: - resp = request.get(resp.headers.get("location")) + resp = request.get(resp.headers.get("location"), follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -461,7 +465,7 @@ def test_pkgbase_comments( assert resp.status_code == int(HTTPStatus.SEE_OTHER) with client as request: - resp = request.get(resp.headers.get("location")) + resp = request.get(resp.headers.get("location"), follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -527,7 +531,8 @@ def test_pkgbase_comment_delete( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/delete" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) expected = f"/pkgbase/{pkgbasename}" @@ -537,12 +542,14 @@ def test_pkgbase_comment_delete( maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/undelete" with client as request: - resp = request.post(endpoint, cookies=maint_cookies) + request.cookies = maint_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) # And move on to undeleting it. with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -670,7 +677,7 @@ def test_pkgbase_comaintainers_not_found(client: TestClient, maintainer: User): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = "/pkgbase/fake/comaintainers" with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -678,7 +685,7 @@ def test_pkgbase_comaintainers_post_not_found(client: TestClient, maintainer: Us cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = "/pkgbase/fake/comaintainers" with client as request: - resp = request.post(endpoint, cookies=cookies, allow_redirects=False) + resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -689,7 +696,7 @@ def test_pkgbase_comaintainers_unauthorized( endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -701,7 +708,7 @@ def test_pkgbase_comaintainers_post_unauthorized( endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=cookies, allow_redirects=False) + resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -713,9 +720,7 @@ def test_pkgbase_comaintainers_post_invalid_user( endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post( - endpoint, data={"users": "\nfake\n"}, cookies=cookies, allow_redirects=False - ) + resp = request.post(endpoint, data={"users": "\nfake\n"}, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -737,7 +742,6 @@ def test_pkgbase_comaintainers( endpoint, data={"users": f"\n{user.Username}\n{maintainer.Username}\n"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -748,7 +752,6 @@ def test_pkgbase_comaintainers( endpoint, data={"users": f"\n{user.Username}\n{maintainer.Username}\n"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -757,7 +760,7 @@ def test_pkgbase_comaintainers( # let's perform a GET request to make sure that the backend produces # the user we added in the users textarea. with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -766,14 +769,12 @@ def test_pkgbase_comaintainers( # Finish off by removing all the comaintainers. with client as request: - resp = request.post( - endpoint, data={"users": str()}, cookies=cookies, allow_redirects=False - ) + resp = request.post(endpoint, data={"users": str()}, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -856,7 +857,6 @@ def test_pkgbase_request_post_merge_not_found_error( "comments": "We want to merge this.", }, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.OK) @@ -880,7 +880,6 @@ def test_pkgbase_request_post_merge_no_merge_into_error( "comments": "We want to merge this.", }, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.OK) @@ -904,7 +903,6 @@ def test_pkgbase_request_post_merge_self_error( "comments": "We want to merge this.", }, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.OK) @@ -927,26 +925,28 @@ def test_pkgbase_flag( # Get the flag page. with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) # Now, let's check the /pkgbase/{name}/flag-comment route. flag_comment_endpoint = f"/pkgbase/{pkgbase.Name}/flag-comment" with client as request: - resp = request.get( - flag_comment_endpoint, cookies=cookies, allow_redirects=False - ) + request.cookies = cookies + resp = request.get(flag_comment_endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" # Try to flag it without a comment. with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) # Flag it with a valid comment. with client as request: - resp = request.post(endpoint, data={"comments": "Test"}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"comments": "Test"}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger == user assert pkgbase.FlaggerComment == "Test" @@ -957,15 +957,15 @@ def test_pkgbase_flag( # Now, let's check the /pkgbase/{name}/flag-comment route. flag_comment_endpoint = f"/pkgbase/{pkgbase.Name}/flag-comment" with client as request: - resp = request.get( - flag_comment_endpoint, cookies=cookies, allow_redirects=False - ) + request.cookies = cookies + resp = request.get(flag_comment_endpoint) assert resp.status_code == int(HTTPStatus.OK) # Now try to perform a get; we should be redirected because # it's already flagged. with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) with db.begin(): @@ -982,27 +982,29 @@ def test_pkgbase_flag( user2_cookies = {"AURSID": user2.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/unflag" with client as request: - resp = request.post(endpoint, cookies=user2_cookies) + request.cookies = user2_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger == user # Now, test that the 'maintainer' user can. maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=maint_cookies) + request.cookies = maint_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger is None # Flag it again. with client as request: - resp = request.post( - f"/pkgbase/{pkgbase.Name}/flag", data={"comments": "Test"}, cookies=cookies - ) + request.cookies = cookies + resp = request.post(f"/pkgbase/{pkgbase.Name}/flag", data={"comments": "Test"}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Now, unflag it for real. with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgbase.Flagger is None @@ -1113,7 +1115,7 @@ def test_pkgbase_disown_as_maint_with_comaint( maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: resp = request.post( - endp, data=post_data, cookies=maint_cookies, allow_redirects=True + endp, data=post_data, cookies=maint_cookies, follow_redirects=True ) assert resp.status_code == int(HTTPStatus.OK) @@ -1145,52 +1147,62 @@ def test_pkgbase_disown( # GET as a normal user, which is rejected for lack of credentials. with client as request: - resp = request.get(endpoint, cookies=user_cookies, allow_redirects=False) + request.cookies = user_cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # GET as a comaintainer. with client as request: - resp = request.get(endpoint, cookies=comaint_cookies, allow_redirects=False) + request.cookies = comaint_cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) # Ensure that the comaintainer can see "Disown Package" link with client as request: - resp = request.get(pkgbase_endp, cookies=comaint_cookies) + request.cookies = comaint_cookies + resp = request.get(pkgbase_endp, follow_redirects=True) assert "Disown Package" in resp.text # GET as the maintainer. with client as request: - resp = request.get(endpoint, cookies=maint_cookies) + request.cookies = maint_cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) # Ensure that the maintainer can see "Disown Package" link with client as request: - resp = request.get(pkgbase_endp, cookies=maint_cookies) + request.cookies = maint_cookies + resp = request.get(pkgbase_endp, follow_redirects=True) assert "Disown Package" in resp.text # POST as a normal user, which is rejected for lack of credentials. with client as request: - resp = request.post(endpoint, cookies=user_cookies) + request.cookies = user_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # POST as the comaintainer without "confirm". with client as request: - resp = request.post(endpoint, cookies=comaint_cookies) + request.cookies = comaint_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) # POST as the maintainer without "confirm". with client as request: - resp = request.post(endpoint, cookies=maint_cookies) + request.cookies = maint_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) # POST as the comaintainer with "confirm". with client as request: - resp = request.post(endpoint, data={"confirm": True}, cookies=comaint_cookies) + request.cookies = comaint_cookies + resp = request.post(endpoint, data={"confirm": True}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # POST as the maintainer with "confirm". with client as request: - resp = request.post(endpoint, data={"confirm": True}, cookies=maint_cookies) + request.cookies = maint_cookies + resp = request.post(endpoint, data={"confirm": True}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -1207,21 +1219,21 @@ def test_pkgbase_adopt( # Adopt the package base. with client as request: - resp = request.post(endpoint, cookies=cookies, allow_redirects=False) + resp = request.post(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == maintainer # Try to adopt it when it already has a maintainer; nothing changes. user_cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=user_cookies, allow_redirects=False) + resp = request.post(endpoint, cookies=user_cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == maintainer # Steal the package as a TU. tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=tu_cookies, allow_redirects=False) + resp = request.post(endpoint, cookies=tu_cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == tu_user @@ -1233,7 +1245,7 @@ def test_pkgbase_delete_unauthorized(client: TestClient, user: User, package: Pa # Test GET. with client as request: - resp = request.get(endpoint, cookies=cookies, allow_redirects=False) + resp = request.get(endpoint, cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -1308,7 +1320,6 @@ def test_packages_post_unknown_action(client: TestClient, user: User, package: P "/packages", data={"action": "unknown"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1325,7 +1336,6 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): "/packages", data={"action": "stub"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1346,7 +1356,6 @@ def test_packages_post(client: TestClient, user: User, package: Package): "/packages", data={"action": "stub"}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.OK) @@ -1521,7 +1530,7 @@ def test_pkgbase_merge_post( def test_pkgbase_keywords(client: TestClient, user: User, package: Package): endpoint = f"/pkgbase/{package.PackageBase.Name}" with client as request: - resp = request.get(endpoint) + resp = request.get(endpoint, follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -1532,13 +1541,16 @@ def test_pkgbase_keywords(client: TestClient, user: User, package: Package): cookies = {"AURSID": maint.login(Request(), "testPassword")} post_endpoint = f"{endpoint}/keywords" with client as request: + request.cookies = cookies resp = request.post( - post_endpoint, data={"keywords": "abc test"}, cookies=cookies + post_endpoint, + data={"keywords": "abc test"}, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) with client as request: - resp = request.get(resp.headers.get("location")) + request.cookies = {} + resp = request.get(resp.headers.get("location"), follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -1552,7 +1564,8 @@ def test_pkgbase_keywords(client: TestClient, user: User, package: Package): def test_pkgbase_empty_keywords(client: TestClient, user: User, package: Package): endpoint = f"/pkgbase/{package.PackageBase.Name}" with client as request: - resp = request.get(endpoint) + request.cookies = {} + resp = request.get(endpoint, follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -1563,15 +1576,16 @@ def test_pkgbase_empty_keywords(client: TestClient, user: User, package: Package cookies = {"AURSID": maint.login(Request(), "testPassword")} post_endpoint = f"{endpoint}/keywords" with client as request: + request.cookies = cookies resp = request.post( post_endpoint, data={"keywords": "abc test foo bar "}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) with client as request: - resp = request.get(resp.headers.get("location")) + request.cookies = {} + resp = request.get(resp.headers.get("location"), follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -1608,12 +1622,12 @@ def test_independent_user_unflag(client: TestClient, user: User, package: Packag pkgbase = package.PackageBase cookies = {"AURSID": flagger.login(Request(), "testPassword")} with client as request: + request.cookies = cookies endp = f"/pkgbase/{pkgbase.Name}/flag" response = request.post( endp, data={"comments": "This thing needs a flag!"}, - cookies=cookies, - allow_redirects=True, + follow_redirects=True, ) assert response.status_code == HTTPStatus.OK @@ -1622,7 +1636,8 @@ def test_independent_user_unflag(client: TestClient, user: User, package: Packag # page when browsing as that `flagger` user. with client as request: endp = f"/pkgbase/{pkgbase.Name}" - response = request.get(endp, cookies=cookies, allow_redirects=True) + request.cookies = cookies + response = request.get(endp, follow_redirects=True) assert response.status_code == HTTPStatus.OK # Assert that the "Unflag package" link appears in the DOM. @@ -1633,7 +1648,8 @@ def test_independent_user_unflag(client: TestClient, user: User, package: Packag # Now, unflag the package by "clicking" the "Unflag package" link. with client as request: endp = f"/pkgbase/{pkgbase.Name}/unflag" - response = request.post(endp, cookies=cookies, allow_redirects=True) + request.cookies = cookies + response = request.post(endp, follow_redirects=True) assert response.status_code == HTTPStatus.OK # For the last time, let's check the GET response. The package should @@ -1641,7 +1657,8 @@ def test_independent_user_unflag(client: TestClient, user: User, package: Packag # should be missing. with client as request: endp = f"/pkgbase/{pkgbase.Name}" - response = request.get(endp, cookies=cookies, allow_redirects=True) + request.cookies = cookies + response = request.get(endp, follow_redirects=True) assert response.status_code == HTTPStatus.OK # Assert that the "Unflag package" link does not appear in the DOM. diff --git a/test/test_requests.py b/test/test_requests.py index 6475fae6..1d681d58 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -29,7 +29,11 @@ def setup(db_test) -> None: @pytest.fixture def client() -> TestClient: """Yield a TestClient.""" - yield TestClient(app=asgi.app) + client = TestClient(app=asgi.app) + + # disable redirects for our tests + client.follow_redirects = False + yield client def create_user(username: str, email: str) -> User: @@ -321,7 +325,8 @@ def test_request_post_deletion_autoaccept( endpoint = f"/pkgbase/{pkgbase.Name}/request" data = {"comments": "Test request.", "type": "deletion"} with client as request: - resp = request.post(endpoint, data=data, cookies=auser.cookies) + request.cookies = auser.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) pkgreq = ( @@ -642,7 +647,8 @@ def test_request_post_orphan_autoaccept( "comments": "Test request.", } with client as request: - resp = request.post(endpoint, data=data, cookies=auser.cookies) + request.cookies = auser.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) pkgreq = pkgbase.requests.first() @@ -715,7 +721,7 @@ def test_pkgreq_by_id_not_found(): def test_requests_unauthorized(client: TestClient): with client as request: - resp = request.get("/requests", allow_redirects=False) + resp = request.get("/requests") assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -879,9 +885,7 @@ def test_requests_selfmade( def test_requests_close(client: TestClient, user: User, pkgreq: PackageRequest): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get( - f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False - ) + resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies) assert resp.status_code == int(HTTPStatus.OK) @@ -890,9 +894,7 @@ def test_requests_close_unauthorized( ): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.get( - f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False - ) + resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" @@ -906,7 +908,6 @@ def test_requests_close_post_unauthorized( f"/requests/{pkgreq.ID}/close", data={"reason": ACCEPTED_ID}, cookies=cookies, - allow_redirects=False, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" @@ -915,9 +916,7 @@ def test_requests_close_post_unauthorized( def test_requests_close_post(client: TestClient, user: User, pkgreq: PackageRequest): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post( - f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False - ) + resp = request.post(f"/requests/{pkgreq.ID}/close", cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgreq.Status == REJECTED_ID @@ -930,9 +929,7 @@ def test_requests_close_post_rejected( ): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post( - f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False - ) + resp = request.post(f"/requests/{pkgreq.ID}/close", cookies=cookies) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgreq.Status == REJECTED_ID diff --git a/test/test_routes.py b/test/test_routes.py index 78b0a65b..b4bc30ee 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -20,7 +20,11 @@ def setup(db_test): @pytest.fixture def client() -> TestClient: - yield TestClient(app=app) + client = TestClient(app=app) + + # disable redirects for our tests + client.follow_redirects = False + yield client @pytest.fixture @@ -66,7 +70,7 @@ def test_favicon(client: TestClient): """Test the favicon route at '/favicon.ico'.""" with client as request: response1 = request.get("/static/images/favicon.ico") - response2 = request.get("/favicon.ico") + response2 = request.get("/favicon.ico", follow_redirects=True) assert response1.status_code == int(HTTPStatus.OK) assert response1.content == response2.content diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index 203008e3..dc468808 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -81,7 +81,11 @@ def setup(db_test): def client(): from aurweb.asgi import app - yield TestClient(app=app) + client = TestClient(app=app) + + # disable redirects for our tests + client.follow_redirects = False + yield client @pytest.fixture @@ -151,7 +155,7 @@ def proposal(user, tu_user): def test_tu_index_guest(client): headers = {"referer": config.get("options", "aur_location") + "/tu"} with client as request: - response = request.get("/tu", allow_redirects=False, headers=headers) + response = request.get("/tu", headers=headers) assert response.status_code == int(HTTPStatus.SEE_OTHER) params = filters.urlencode({"next": "/tu"}) @@ -162,7 +166,7 @@ def test_tu_index_unauthorized(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: # Login as a normal user, not a TU. - response = request.get("/tu", cookies=cookies, allow_redirects=False) + response = request.get("/tu", cookies=cookies) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -173,7 +177,7 @@ def test_tu_empty_index(client, tu_user): # Make a default get request to /tu. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies, allow_redirects=False) + response = request.get("/tu", cookies=cookies) assert response.status_code == int(HTTPStatus.OK) # Parse lxml root. @@ -226,7 +230,6 @@ def test_tu_index(client, tu_user): "/tu", cookies=cookies, params={"cby": "BAD!", "pby": "blah"}, - allow_redirects=False, ) assert response.status_code == int(HTTPStatus.OK) @@ -292,7 +295,7 @@ def test_tu_index(client, tu_user): def test_tu_stats(client: TestClient, tu_user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies, allow_redirects=False) + response = request.get("/tu", cookies=cookies) assert response.status_code == HTTPStatus.OK root = parse_root(response.text) @@ -313,7 +316,7 @@ def test_tu_stats(client: TestClient, tu_user: User): tu_user.InactivityTS = time.utcnow() with client as request: - response = request.get("/tu", cookies=cookies, allow_redirects=False) + response = request.get("/tu", cookies=cookies) assert response.status_code == HTTPStatus.OK root = parse_root(response.text) @@ -361,7 +364,7 @@ def test_tu_index_table_paging(client, tu_user): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies, allow_redirects=False) + response = request.get("/tu", cookies=cookies) assert response.status_code == int(HTTPStatus.OK) # Parse lxml.etree root. @@ -391,9 +394,7 @@ def test_tu_index_table_paging(client, tu_user): # Now, get the next page of current votes. offset = 10 # Specify coff=10 with client as request: - response = request.get( - "/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False - ) + response = request.get("/tu", cookies=cookies, params={"coff": offset}) assert response.status_code == int(HTTPStatus.OK) old_rows = rows @@ -420,9 +421,7 @@ def test_tu_index_table_paging(client, tu_user): offset = 20 # Specify coff=10 with client as request: - response = request.get( - "/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False - ) + response = request.get("/tu", cookies=cookies, params={"coff": offset}) assert response.status_code == int(HTTPStatus.OK) # Do it again, we only have five left. @@ -471,7 +470,7 @@ def test_tu_index_sorting(client, tu_user): # Make a default request to /tu. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies, allow_redirects=False) + response = request.get("/tu", cookies=cookies) assert response.status_code == int(HTTPStatus.OK) # Get lxml handles of the document. @@ -498,9 +497,7 @@ def test_tu_index_sorting(client, tu_user): # Make another request; one that sorts the current votes # in ascending order instead of the default descending order. with client as request: - response = request.get( - "/tu", cookies=cookies, params={"cby": "asc"}, allow_redirects=False - ) + response = request.get("/tu", cookies=cookies, params={"cby": "asc"}) assert response.status_code == int(HTTPStatus.OK) # Get lxml handles of the document. @@ -573,7 +570,8 @@ def test_tu_index_last_votes( def test_tu_proposal_not_found(client, tu_user): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", params={"id": 1}, cookies=cookies) + request.cookies = cookies + response = request.get("/tu", params={"id": 1}, follow_redirects=True) assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -583,14 +581,12 @@ def test_tu_proposal_unauthorized( cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/tu/{proposal[2].ID}" with client as request: - response = request.get(endpoint, cookies=cookies, allow_redirects=False) + response = request.get(endpoint, cookies=cookies) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" with client as request: - response = request.post( - endpoint, cookies=cookies, data={"decision": False}, allow_redirects=False - ) + response = request.post(endpoint, cookies=cookies, data={"decision": False}) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" @@ -606,7 +602,9 @@ def test_tu_running_proposal( proposal_id = voteinfo.ID cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get(f"/tu/{proposal_id}", cookies=cookies) + response = request.get( + f"/tu/{proposal_id}", cookies=cookies, follow_redirects=True + ) assert response.status_code == int(HTTPStatus.OK) # Alright, now let's continue on to verifying some markup. @@ -676,7 +674,9 @@ def test_tu_running_proposal( # Make another request now that we've voted. with client as request: - response = request.get("/tu", params={"id": voteinfo.ID}, cookies=cookies) + response = request.get( + "/tu", params={"id": voteinfo.ID}, cookies=cookies, follow_redirects=True + ) assert response.status_code == int(HTTPStatus.OK) # Parse our new root. @@ -734,9 +734,7 @@ def test_tu_proposal_vote_not_found(client, tu_user): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post( - "/tu/1", cookies=cookies, data=data, allow_redirects=False - ) + response = request.post("/tu/1", cookies=cookies, data=data) assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -777,9 +775,7 @@ def test_tu_proposal_vote_unauthorized( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post( - f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False - ) + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) assert response.status_code == int(HTTPStatus.UNAUTHORIZED) root = parse_root(response.text) @@ -788,9 +784,7 @@ def test_tu_proposal_vote_unauthorized( with client as request: data = {"decision": "Yes"} - response = request.get( - f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False - ) + response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, params=data) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -808,9 +802,7 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post( - f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False - ) + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) root = parse_root(response.text) @@ -819,9 +811,7 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): with client as request: data = {"decision": "Yes"} - response = request.get( - f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False - ) + response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, params=data) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -840,9 +830,7 @@ def test_tu_proposal_vote_already_voted(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post( - f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False - ) + response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) root = parse_root(response.text) @@ -851,9 +839,7 @@ def test_tu_proposal_vote_already_voted(client, proposal): with client as request: data = {"decision": "Yes"} - response = request.get( - f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False - ) + response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, params=data) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -884,12 +870,12 @@ def test_tu_addvote_unauthorized( ): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.get("/addvote", cookies=cookies, allow_redirects=False) + response = request.get("/addvote", cookies=cookies) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" with client as request: - response = request.post("/addvote", cookies=cookies, allow_redirects=False) + response = request.post("/addvote", cookies=cookies) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" From a832b3cddb999f8b31a54b111ae6340c64f07cd0 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 24 Nov 2022 22:43:31 +0100 Subject: [PATCH 1639/1891] fix(test): FastAPI 0.87.0 - warning fixes FastAPI 0.87.0 switched to the httpx library for their TestClient * cookies need to be defined on the request instance instead of method calls Signed-off-by: moson-mo --- test/test_accounts_routes.py | 263 +++++++++++++++++++------------ test/test_auth_routes.py | 9 +- test/test_git_archives.py | 3 +- test/test_homepage.py | 6 +- test/test_html.py | 15 +- test/test_packages_routes.py | 59 +++---- test/test_pkgbase_routes.py | 200 ++++++++++++++--------- test/test_requests.py | 74 ++++++--- test/test_routes.py | 4 +- test/test_trusted_user_routes.py | 111 ++++++++----- 10 files changed, 463 insertions(+), 281 deletions(-) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 44226627..d3ddb174 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -107,7 +107,8 @@ def test_get_passreset_authed_redirects(client: TestClient, user: User): assert sid is not None with client as request: - response = request.get("/passreset", cookies={"AURSID": sid}) + request.cookies = {"AURSID": sid} + response = request.get("/passreset") assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -122,7 +123,8 @@ def test_get_passreset(client: TestClient): def test_get_passreset_translation(client: TestClient): # Test that translation works; set it to de. with client as request: - response = request.get("/passreset", cookies={"AURLANG": "de"}) + request.cookies = {"AURLANG": "de"} + response = request.get("/passreset") # The header title should be translated. assert "Passwort zurücksetzen" in response.text @@ -136,7 +138,8 @@ def test_get_passreset_translation(client: TestClient): # Restore english. with client as request: - response = request.get("/passreset", cookies={"AURLANG": "en"}) + request.cookies = {"AURLANG": "en"} + response = request.get("/passreset") def test_get_passreset_with_resetkey(client: TestClient): @@ -150,9 +153,9 @@ def test_post_passreset_authed_redirects(client: TestClient, user: User): assert sid is not None with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/passreset", - cookies={"AURSID": sid}, data={"user": "blah"}, ) @@ -652,7 +655,8 @@ def test_get_account_edit_tu_as_tu(client: TestClient, tu_user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: - response = request.get(endpoint, cookies=cookies) + request.cookies = cookies + response = request.get(endpoint) assert response.status_code == int(HTTPStatus.OK) # Verify that we have an account type selection and that the @@ -677,7 +681,8 @@ def test_get_account_edit_as_tu(client: TestClient, tu_user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: - response = request.get(endpoint, cookies=cookies) + request.cookies = cookies + response = request.get(endpoint) assert response.status_code == int(HTTPStatus.OK) # Verify that we have an account type selection and that the @@ -700,7 +705,8 @@ def test_get_account_edit_type(client: TestClient, user: User): endpoint = f"/account/{user.Username}/edit" with client as request: - response = request.get(endpoint, cookies=cookies) + request.cookies = cookies + response = request.get(endpoint) assert response.status_code == int(HTTPStatus.OK) assert "id_type" not in response.text @@ -713,7 +719,8 @@ def test_get_account_edit_type_as_tu(client: TestClient, tu_user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: - response = request.get(endpoint, cookies=cookies) + request.cookies = cookies + response = request.get(endpoint) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -737,7 +744,8 @@ def test_get_account_edit_unauthorized(client: TestClient, user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: # Try to edit `test2` while authenticated as `test`. - response = request.get(endpoint, cookies={"AURSID": sid}) + request.cookies = {"AURSID": sid} + response = request.get(endpoint) assert response.status_code == int(HTTPStatus.SEE_OTHER) expected = f"/account/{user2.Username}" @@ -751,9 +759,9 @@ def test_post_account_edit(client: TestClient, user: User): post_data = {"U": "test", "E": "test666@example.org", "passwd": "testPassword"} with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -777,7 +785,8 @@ def test_post_account_edit_type_as_tu(client: TestClient, tu_user: User): "passwd": "testPassword", } with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.OK) @@ -795,7 +804,8 @@ def test_post_account_edit_type_as_dev(client: TestClient, tu_user: User): "passwd": "testPassword", } with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.OK) assert user2.AccountTypeID == at.DEVELOPER_ID @@ -814,7 +824,8 @@ def test_post_account_edit_invalid_type_as_tu(client: TestClient, tu_user: User) "passwd": "testPassword", } with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) assert user2.AccountTypeID == at.USER_ID @@ -840,7 +851,8 @@ def test_post_account_edit_dev(client: TestClient, tu_user: User): endpoint = f"/account/{tu_user.Username}/edit" with client as request: - response = request.post(endpoint, cookies={"AURSID": sid}, data=post_data) + request.cookies = {"AURSID": sid} + response = request.post(endpoint, data=post_data) assert response.status_code == int(HTTPStatus.OK) expected = "The account, test, " @@ -860,9 +872,9 @@ def test_post_account_edit_language(client: TestClient, user: User): } with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -889,9 +901,9 @@ def test_post_account_edit_timezone(client: TestClient, user: User): } with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -905,9 +917,9 @@ def test_post_account_edit_error_missing_password(client: TestClient, user: User post_data = {"U": "test", "E": "test@example.org", "TZ": "CET", "passwd": ""} with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -924,9 +936,9 @@ def test_post_account_edit_error_invalid_password(client: TestClient, user: User post_data = {"U": "test", "E": "test@example.org", "TZ": "CET", "passwd": "invalid"} with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -945,9 +957,8 @@ def test_post_account_edit_suspend_unauthorized(client: TestClient, user: User): "passwd": "testPassword", } with client as request: - resp = request.post( - f"/account/{user.Username}/edit", data=post_data, cookies=cookies - ) + request.cookies = cookies + resp = request.post(f"/account/{user.Username}/edit", data=post_data) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -968,9 +979,8 @@ def test_post_account_edit_inactivity(client: TestClient, user: User): "passwd": "testPassword", } with client as request: - resp = request.post( - f"/account/{user.Username}/edit", data=post_data, cookies=cookies - ) + request.cookies = cookies + resp = request.post(f"/account/{user.Username}/edit", data=post_data) assert resp.status_code == int(HTTPStatus.OK) # Make sure the user record got updated correctly. @@ -978,9 +988,8 @@ def test_post_account_edit_inactivity(client: TestClient, user: User): post_data.update({"J": False}) with client as request: - resp = request.post( - f"/account/{user.Username}/edit", data=post_data, cookies=cookies - ) + request.cookies = cookies + resp = request.post(f"/account/{user.Username}/edit", data=post_data) assert resp.status_code == int(HTTPStatus.OK) assert user.InactivityTS == 0 @@ -1000,7 +1009,8 @@ def test_post_account_edit_suspended(client: TestClient, user: User): } endpoint = f"/account/{user.Username}/edit" with client as request: - resp = request.post(endpoint, data=post_data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=post_data) assert resp.status_code == int(HTTPStatus.OK) # Make sure the user record got updated correctly. @@ -1032,7 +1042,8 @@ def test_post_account_edit_error_unauthorized(client: TestClient, user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: # Attempt to edit 'test2' while logged in as 'test'. - response = request.post(endpoint, cookies={"AURSID": sid}, data=post_data) + request.cookies = {"AURSID": sid} + response = request.post(endpoint, data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) expected = f"/account/{user2.Username}" @@ -1051,9 +1062,9 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): } with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -1063,9 +1074,9 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): post_data["PK"] = make_ssh_pubkey() with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -1084,9 +1095,9 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): } with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -1100,9 +1111,9 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): } with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -1120,7 +1131,8 @@ def test_post_account_edit_invalid_ssh_pubkey(client: TestClient, user: User): } cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.post("/account/test/edit", data=data, cookies=cookies) + request.cookies = cookies + response = request.post("/account/test/edit", data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1138,9 +1150,9 @@ def test_post_account_edit_password(client: TestClient, user: User): } with client as request: + request.cookies = {"AURSID": sid} response = request.post( "/account/test/edit", - cookies={"AURSID": sid}, data=post_data, ) @@ -1154,7 +1166,8 @@ def test_post_account_edit_self_type_as_user(client: TestClient, user: User): endpoint = f"/account/{user.Username}/edit" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) assert "id_type" not in resp.text @@ -1165,7 +1178,8 @@ def test_post_account_edit_self_type_as_user(client: TestClient, user: User): "passwd": "testPassword", } with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1181,7 +1195,8 @@ def test_post_account_edit_other_user_as_user(client: TestClient, user: User): endpoint = f"/account/{user2.Username}/edit" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/account/{user2.Username}" @@ -1192,7 +1207,8 @@ def test_post_account_edit_self_type_as_tu(client: TestClient, tu_user: User): # We cannot see the Account Type field on our own edit page. with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) assert "id_type" in resp.text @@ -1204,7 +1220,8 @@ def test_post_account_edit_self_type_as_tu(client: TestClient, tu_user: User): "passwd": "testPassword", } with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.OK) assert tu_user.AccountTypeID == USER_ID @@ -1223,7 +1240,8 @@ def test_post_account_edit_other_user_type_as_tu( # As a TU, we can see the Account Type field for other users. with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) assert "id_type" in resp.text @@ -1234,8 +1252,10 @@ def test_post_account_edit_other_user_type_as_tu( "T": TRUSTED_USER_ID, "passwd": "testPassword", } + with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.OK) # Let's make sure the DB got updated properly. @@ -1267,14 +1287,16 @@ def test_post_account_edit_other_user_suspend_as_tu(client: TestClient, tu_user: user_cookies = {"AURSID": sid} with client as request: endpoint = f"/account/{user.Username}/edit" - resp = request.get(endpoint, cookies=user_cookies) + request.cookies = user_cookies + resp = request.get(endpoint) assert resp.status_code == HTTPStatus.OK cookies = {"AURSID": tu_user.login(Request(), "testPassword")} assert cookies is not None # This is useless, we create the dict here ^ # As a TU, we can see the Account for other users. with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) # As a TU, we can modify other user's account types. data = { @@ -1290,7 +1312,8 @@ def test_post_account_edit_other_user_suspend_as_tu(client: TestClient, tu_user: # Test that `user` no longer has a session. with user_client as request: - resp = request.get(endpoint, cookies=user_cookies) + request.cookies = user_cookies + resp = request.get(endpoint) assert resp.status_code == HTTPStatus.SEE_OTHER # Since user is now suspended, they should not be able to login. @@ -1314,7 +1337,8 @@ def test_post_account_edit_other_user_type_as_tu_invalid_type( # As a TU, we can modify other user's account types. data = {"U": user2.Username, "E": user2.Email, "T": 0, "passwd": "testPassword"} with client as request: - resp = request.post(endpoint, data=data, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1327,7 +1351,8 @@ def test_get_account(client: TestClient, user: User): sid = user.login(request, "testPassword") with client as request: - response = request.get("/account/test", cookies={"AURSID": sid}) + request.cookies = {"AURSID": sid} + response = request.get("/account/test") assert response.status_code == int(HTTPStatus.OK) @@ -1337,7 +1362,8 @@ def test_get_account_not_found(client: TestClient, user: User): sid = user.login(request, "testPassword") with client as request: - response = request.get("/account/not_found", cookies={"AURSID": sid}) + request.cookies = {"AURSID": sid} + response = request.get("/account/not_found") assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -1358,7 +1384,8 @@ def test_get_accounts(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.get("/accounts", cookies=cookies) + request.cookies = cookies + response = request.get("/accounts") assert response.status_code == int(HTTPStatus.OK) parser = lxml.etree.HTMLParser() @@ -1426,7 +1453,8 @@ def test_post_accounts(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies) + request.cookies = cookies + response = request.post("/accounts") assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1468,7 +1496,8 @@ def test_post_accounts_username(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies, data={"U": user.Username}) + request.cookies = cookies + response = request.post("/accounts", data={"U": user.Username}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1501,13 +1530,15 @@ def test_post_accounts_account_type(client: TestClient, user: User, tu_user: Use # Expect no entries; we marked our only user as a User type. with client as request: - response = request.post("/accounts", cookies=cookies, data={"T": "t"}) + request.cookies = cookies + response = request.post("/accounts", data={"T": "t"}) assert response.status_code == int(HTTPStatus.OK) assert len(get_rows(response.text)) == 0 # So, let's also ensure that specifying "u" returns our user. with client as request: - response = request.post("/accounts", cookies=cookies, data={"T": "u"}) + request.cookies = cookies + response = request.post("/accounts", data={"T": "u"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1525,7 +1556,8 @@ def test_post_accounts_account_type(client: TestClient, user: User, tu_user: Use ) with client as request: - response = request.post("/accounts", cookies=cookies, data={"T": "t"}) + request.cookies = cookies + response = request.post("/accounts", data={"T": "t"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1542,7 +1574,8 @@ def test_post_accounts_account_type(client: TestClient, user: User, tu_user: Use ) with client as request: - response = request.post("/accounts", cookies=cookies, data={"T": "d"}) + request.cookies = cookies + response = request.post("/accounts", data={"T": "d"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1559,7 +1592,8 @@ def test_post_accounts_account_type(client: TestClient, user: User, tu_user: Use ) with client as request: - response = request.post("/accounts", cookies=cookies, data={"T": "td"}) + request.cookies = cookies + response = request.post("/accounts", data={"T": "td"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1577,7 +1611,8 @@ def test_post_accounts_status(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies) + request.cookies = cookies + response = request.post("/accounts") assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1591,7 +1626,8 @@ def test_post_accounts_status(client: TestClient, user: User, tu_user: User): user.Suspended = True with client as request: - response = request.post("/accounts", cookies=cookies, data={"S": True}) + request.cookies = cookies + response = request.post("/accounts", data={"S": True}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1608,7 +1644,8 @@ def test_post_accounts_email(client: TestClient, user: User, tu_user: User): # Search via email. with client as request: - response = request.post("/accounts", cookies=cookies, data={"E": user.Email}) + request.cookies = cookies + response = request.post("/accounts", data={"E": user.Email}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1621,7 +1658,8 @@ def test_post_accounts_realname(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies, data={"R": user.RealName}) + request.cookies = cookies + response = request.post("/accounts", data={"R": user.RealName}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1634,7 +1672,8 @@ def test_post_accounts_irc(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies, data={"I": user.IRCNick}) + request.cookies = cookies + response = request.post("/accounts", data={"I": user.IRCNick}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1652,14 +1691,16 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): # Show that "u" is the default search order, by username. with client as request: - response = request.post("/accounts", cookies=cookies) + request.cookies = cookies + response = request.post("/accounts") assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 first_rows = rows with client as request: - response = request.post("/accounts", cookies=cookies, data={"SB": "u"}) + request.cookies = cookies + response = request.post("/accounts", data={"SB": "u"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1671,7 +1712,8 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): assert compare_text_values(0, first_rows, rows) is True with client as request: - response = request.post("/accounts", cookies=cookies, data={"SB": "i"}) + request.cookies = cookies + response = request.post("/accounts", data={"SB": "i"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1681,7 +1723,8 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): # Sort by "i" -> RealName. with client as request: - response = request.post("/accounts", cookies=cookies, data={"SB": "r"}) + request.cookies = cookies + response = request.post("/accounts", data={"SB": "r"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1696,7 +1739,8 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): # Fetch first_rows again with our new AccountType ordering. with client as request: - response = request.post("/accounts", cookies=cookies) + request.cookies = cookies + response = request.post("/accounts") assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1704,7 +1748,8 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User): # Sort by "t" -> AccountType. with client as request: - response = request.post("/accounts", cookies=cookies, data={"SB": "t"}) + request.cookies = cookies + response = request.post("/accounts", data={"SB": "t"}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) assert len(rows) == 2 @@ -1722,7 +1767,8 @@ def test_post_accounts_pgp_key(client: TestClient, user: User, tu_user: User): # Search via PGPKey. with client as request: - response = request.post("/accounts", cookies=cookies, data={"K": user.PGPKey}) + request.cookies = cookies + response = request.post("/accounts", data={"K": user.PGPKey}) assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1749,7 +1795,8 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): cookies = {"AURSID": sid} with client as request: - response = request.post("/accounts", cookies=cookies) + request.cookies = cookies + response = request.post("/accounts") assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1775,9 +1822,8 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): assert "disabled" not in page_next.attrib with client as request: - response = request.post( - "/accounts", cookies=cookies, data={"O": 50} - ) # +50 offset. + request.cookies = cookies + response = request.post("/accounts", data={"O": 50}) # +50 offset. assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1791,9 +1837,8 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User): assert username.text.strip() == _user.Username with client as request: - response = request.post( - "/accounts", cookies=cookies, data={"O": 101} - ) # Last page. + request.cookies = cookies + response = request.post("/accounts", data={"O": 101}) # Last page. assert response.status_code == int(HTTPStatus.OK) rows = get_rows(response.text) @@ -1824,12 +1869,14 @@ def test_get_terms_of_service(client: TestClient, user: User): # First of all, let's test that we get redirected to /tos # when attempting to browse authenticated without accepting terms. with client as request: - response = request.get("/", cookies=cookies) + request.cookies = cookies + response = request.get("/") assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tos" with client as request: - response = request.get("/tos", cookies=cookies) + request.cookies = cookies + response = request.get("/tos") assert response.status_code == int(HTTPStatus.OK) with db.begin(): @@ -1838,7 +1885,8 @@ def test_get_terms_of_service(client: TestClient, user: User): ) with client as request: - response = request.get("/tos", cookies=cookies) + request.cookies = cookies + response = request.get("/tos") # We accepted the term, there's nothing left to accept. assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -1847,7 +1895,8 @@ def test_get_terms_of_service(client: TestClient, user: User): term.Revision = 2 with client as request: - response = request.get("/tos", cookies=cookies) + request.cookies = cookies + response = request.get("/tos") # This time, we have a modified term Revision that hasn't # yet been agreed to via AcceptedTerm update. assert response.status_code == int(HTTPStatus.OK) @@ -1856,7 +1905,8 @@ def test_get_terms_of_service(client: TestClient, user: User): accepted_term.Revision = term.Revision with client as request: - response = request.get("/tos", cookies=cookies) + request.cookies = cookies + response = request.get("/tos") # We updated the term revision, there's nothing left to accept. assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -1876,17 +1926,20 @@ def test_post_terms_of_service(client: TestClient, user: User): # Test that the term we just created is listed. with client as request: - response = request.get("/tos", cookies=cookies) + request.cookies = cookies + response = request.get("/tos") assert response.status_code == int(HTTPStatus.OK) # Make a POST request to /tos with the agree checkbox disabled (False). with client as request: - response = request.post("/tos", data={"accept": False}, cookies=cookies) + request.cookies = cookies + response = request.post("/tos", data={"accept": False}) assert response.status_code == int(HTTPStatus.OK) # Make a POST request to /tos with the agree checkbox enabled (True). with client as request: - response = request.post("/tos", data=data, cookies=cookies) + request.cookies = cookies + response = request.post("/tos", data=data) assert response.status_code == int(HTTPStatus.SEE_OTHER) # Query the db for the record created by the post request. @@ -1900,12 +1953,14 @@ def test_post_terms_of_service(client: TestClient, user: User): # A GET request gives us the new revision to accept. with client as request: - response = request.get("/tos", cookies=cookies) + request.cookies = cookies + response = request.get("/tos") assert response.status_code == int(HTTPStatus.OK) # Let's POST again and agree to the new term revision. with client as request: - response = request.post("/tos", data=data, cookies=cookies) + request.cookies = cookies + response = request.post("/tos", data=data) assert response.status_code == int(HTTPStatus.SEE_OTHER) # Check that the records ended up matching. @@ -1913,7 +1968,8 @@ def test_post_terms_of_service(client: TestClient, user: User): # Now, see that GET redirects us to / with no terms left to accept. with client as request: - response = request.get("/tos", cookies=cookies) + request.cookies = cookies + response = request.get("/tos") assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -1921,14 +1977,16 @@ def test_post_terms_of_service(client: TestClient, user: User): def test_account_comments_not_found(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get("/account/non-existent/comments", cookies=cookies) + request.cookies = cookies + resp = request.get("/account/non-existent/comments") assert resp.status_code == int(HTTPStatus.NOT_FOUND) def test_accounts_unauthorized(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get("/accounts", cookies=cookies) + request.cookies = cookies + resp = request.get("/accounts") assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" @@ -1941,16 +1999,18 @@ def test_account_delete_self_unauthorized(client: TestClient, tu_user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/account/{user2.Username}/delete" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == HTTPStatus.UNAUTHORIZED - resp = request.post(endpoint, cookies=cookies) + resp = request.post(endpoint) assert resp.status_code == HTTPStatus.UNAUTHORIZED # But a TU does have access cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with TestClient(app=app) as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == HTTPStatus.OK @@ -1958,10 +2018,11 @@ def test_account_delete_self_not_found(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = "/account/non-existent-user/delete" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == HTTPStatus.NOT_FOUND - resp = request.post(endpoint, cookies=cookies) + resp = request.post(endpoint) assert resp.status_code == HTTPStatus.NOT_FOUND @@ -1972,15 +2033,16 @@ def test_account_delete_self(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/account/{username}/delete" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == HTTPStatus.OK # The checkbox must be checked with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"passwd": "fakePassword", "confirm": False}, - cookies=cookies, ) assert resp.status_code == HTTPStatus.BAD_REQUEST errors = get_errors(resp.text) @@ -1991,10 +2053,10 @@ def test_account_delete_self(client: TestClient, user: User): # The correct password must be supplied with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"passwd": "fakePassword", "confirm": True}, - cookies=cookies, ) assert resp.status_code == HTTPStatus.BAD_REQUEST errors = get_errors(resp.text) @@ -2002,10 +2064,10 @@ def test_account_delete_self(client: TestClient, user: User): # Supply everything correctly and delete ourselves with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"passwd": "testPassword", "confirm": True}, - cookies=cookies, ) assert resp.status_code == HTTPStatus.SEE_OTHER @@ -2026,15 +2088,16 @@ def test_account_delete_self_with_ssh_public_key(client: TestClient, user: User) cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/account/{username}/delete" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == HTTPStatus.OK # Supply everything correctly and delete ourselves with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"passwd": "testPassword", "confirm": True}, - cookies=cookies, ) assert resp.status_code == HTTPStatus.SEE_OTHER @@ -2055,10 +2118,10 @@ def test_account_delete_as_tu(client: TestClient, tu_user: User): # Delete the user with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"passwd": "testPassword", "confirm": True}, - cookies=cookies, ) assert resp.status_code == HTTPStatus.SEE_OTHER diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py index 150625cd..066457c4 100644 --- a/test/test_auth_routes.py +++ b/test/test_auth_routes.py @@ -71,10 +71,10 @@ def test_login_logout(client: TestClient, user: User): response = request.post("/logout", data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) + request.cookies = {"AURSID": response.cookies.get("AURSID")} response = request.post( "/logout", data=post_data, - cookies={"AURSID": response.cookies.get("AURSID")}, ) assert response.status_code == int(HTTPStatus.SEE_OTHER) @@ -196,7 +196,9 @@ def test_authenticated_login(client: TestClient, user: User): # when requesting GET /login as an authenticated user. # Now, let's verify that we receive 403 Forbidden when we # try to get /login as an authenticated user. - response = request.get("/login", cookies=response.cookies) + request.cookies = response.cookies + response = request.get("/login") + assert response.status_code == int(HTTPStatus.OK) assert "Logged-in as: test" in response.text @@ -356,7 +358,8 @@ def test_generate_unique_sid_exhausted( with mock.patch(generate_unique_sid_, mock_generate_sid): with client as request: # Set cookies = {} to remove any previous login kept by TestClient. - response = request.post("/login", data=post_data, cookies={}) + request.cookies = {} + response = request.post("/login", data=post_data) assert response.status_code == int(HTTPStatus.INTERNAL_SERVER_ERROR) assert "500 - Internal Server Error" in response.text diff --git a/test/test_git_archives.py b/test/test_git_archives.py index 8ee4c2ba..c90706a4 100644 --- a/test/test_git_archives.py +++ b/test/test_git_archives.py @@ -197,7 +197,8 @@ def test_metadata_change( with client as request: endp = f"/pkgbase/{pkgbasename}/keywords" post_data = {"keywords": "abc def"} - resp = request.post(endp, data=post_data, cookies=cookies, allow_redirects=True) + request.cookies = cookies + resp = request.post(endp, data=post_data) assert resp.status_code == HTTPStatus.OK # Run main() again, which should now produce a new commit with the diff --git a/test/test_homepage.py b/test/test_homepage.py index 1aad30f7..a573bdd6 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -210,7 +210,8 @@ def test_homepage_dashboard(redis, packages, user): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.get("/", cookies=cookies) + request.cookies = cookies + response = request.get("/") assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -307,7 +308,8 @@ def test_homepage_dashboard_flagged(user: User, user2: User, package: Package): # flagged maintained packages. cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get("/", cookies=cookies) + request.cookies = cookies + resp = request.get("/") assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) diff --git a/test/test_html.py b/test/test_html.py index 88c75a7c..681bd245 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -71,7 +71,8 @@ def test_archdev_navbar_authenticated(client: TestClient, user: User): expected = ["Dashboard", "Packages", "Requests", "My Account", "Logout"] cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get("/", cookies=cookies) + request.cookies = cookies + resp = request.get("/") assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -92,7 +93,8 @@ def test_archdev_navbar_authenticated_tu(client: TestClient, trusted_user: User) ] cookies = {"AURSID": trusted_user.login(Request(), "testPassword")} with client as request: - resp = request.get("/", cookies=cookies) + request.cookies = cookies + resp = request.get("/") assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -173,9 +175,12 @@ def test_rtl(client: TestClient): expected = [[], [], ["rtl"], ["rtl"]] with client as request: responses["default"] = request.get("/") - responses["de"] = request.get("/", cookies={"AURLANG": "de"}) - responses["he"] = request.get("/", cookies={"AURLANG": "he"}) - responses["ar"] = request.get("/", cookies={"AURLANG": "ar"}) + request.cookies = {"AURLANG": "de"} + responses["de"] = request.get("/") + request.cookies = {"AURLANG": "he"} + responses["he"] = request.get("/") + request.cookies = {"AURLANG": "ar"} + responses["ar"] = request.get("/") for i, (lang, resp) in enumerate(responses.items()): assert resp.status_code == int(HTTPStatus.OK) t = parse_root(resp.text) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 29872cb8..0da6cfab 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -410,7 +410,8 @@ def test_package_comments(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(package_endpoint(package), cookies=cookies) + request.cookies = cookies + resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -465,7 +466,8 @@ def test_package_authenticated(client: TestClient, user: User, package: Package) This process also occurs when pkgbase.html is rendered.""" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(package_endpoint(package), cookies=cookies) + request.cookies = cookies + resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) expected = [ @@ -493,7 +495,8 @@ def test_package_authenticated_maintainer( ): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.get(package_endpoint(package), cookies=cookies) + request.cookies = cookies + resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) expected = [ @@ -515,7 +518,8 @@ def test_package_authenticated_maintainer( def test_package_authenticated_tu(client: TestClient, tu_user: User, package: Package): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.get(package_endpoint(package), cookies=cookies) + request.cookies = cookies + resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) expected = [ @@ -941,10 +945,10 @@ def test_packages_sort_by_voted( # Test that, by default, the first result is what we just set above. cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: + request.cookies = cookies response = request.get( "/packages", params={"SB": "w", "SO": "d"}, # Voted # Descending, Voted first. - cookies=cookies, ) assert response.status_code == int(HTTPStatus.OK) @@ -966,10 +970,10 @@ def test_packages_sort_by_notify( # Test that, by default, the first result is what we just set above. cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: + request.cookies = cookies response = request.get( "/packages", params={"SB": "o", "SO": "d"}, # Voted # Descending, Voted first. - cookies=cookies, ) assert response.status_code == int(HTTPStatus.OK) @@ -1142,10 +1146,10 @@ def test_packages_post_unknown_action(client: TestClient, user: User, package: P cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "unknown"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1158,10 +1162,10 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "stub"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1178,10 +1182,10 @@ def test_packages_post(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "stub"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -1250,7 +1254,8 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package): # an error to be rendered. cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "notify"}, cookies=cookies) + request.cookies = cookies + resp = request.post("/packages", data={"action": "notify"}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to be notified about." @@ -1258,9 +1263,8 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package): # Now let's actually enable notifications on `package`. with client as request: - resp = request.post( - "/packages", data={"action": "notify", "IDs": [package.ID]}, cookies=cookies - ) + request.cookies = cookies + resp = request.post("/packages", data={"action": "notify", "IDs": [package.ID]}) assert resp.status_code == int(HTTPStatus.OK) expected = "The selected packages' notifications have been enabled." successes = get_successes(resp.text) @@ -1269,9 +1273,8 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package): # Try to enable notifications when they're already enabled, # causing an error to be rendered. with client as request: - resp = request.post( - "/packages", data={"action": "notify", "IDs": [package.ID]}, cookies=cookies - ) + request.cookies = cookies + resp = request.post("/packages", data={"action": "notify", "IDs": [package.ID]}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to be notified about." @@ -1289,7 +1292,8 @@ def test_packages_post_unnotify(client: TestClient, user: User, package: Package # Request removal of the notification without any IDs. cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "unnotify"}, cookies=cookies) + request.cookies = cookies + resp = request.post("/packages", data={"action": "unnotify"}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages for notification removal." @@ -1297,10 +1301,10 @@ def test_packages_post_unnotify(client: TestClient, user: User, package: Package # Request removal of the notification; really. with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "unnotify", "IDs": [package.ID]}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) successes = get_successes(resp.text) @@ -1315,10 +1319,10 @@ def test_packages_post_unnotify(client: TestClient, user: User, package: Package # Try it again. The notif no longer exists. with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "unnotify", "IDs": [package.ID]}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1331,7 +1335,8 @@ def test_packages_post_adopt(client: TestClient, user: User, package: Package): # Try to adopt an empty list of packages. cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post("/packages", data={"action": "adopt"}, cookies=cookies) + request.cookies = cookies + resp = request.post("/packages", data={"action": "adopt"}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "You did not select any packages to adopt." @@ -1339,10 +1344,10 @@ def test_packages_post_adopt(client: TestClient, user: User, package: Package): # Now, let's try to adopt a package that's already maintained. with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "adopt", "IDs": [package.ID], "confirm": True}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1356,9 +1361,8 @@ def test_packages_post_adopt(client: TestClient, user: User, package: Package): # Now, let's try to adopt without confirming. with client as request: - resp = request.post( - "/packages", data={"action": "adopt", "IDs": [package.ID]}, cookies=cookies - ) + request.cookies = cookies + resp = request.post("/packages", data={"action": "adopt", "IDs": [package.ID]}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = ( @@ -1369,10 +1373,10 @@ def test_packages_post_adopt(client: TestClient, user: User, package: Package): # Let's do it again now that there is no maintainer. with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "adopt", "IDs": [package.ID], "confirm": True}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) successes = get_successes(resp.text) @@ -1446,10 +1450,10 @@ def test_packages_post_disown( """Disown packages as a Trusted User, which cannot bypass idle time.""" cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "disown", "IDs": [package.ID], "confirm": True}, - cookies=cookies, ) errors = get_errors(resp.text) @@ -1576,7 +1580,8 @@ def test_account_comments(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/account/{user.Username}/comments" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py index dd92d72d..124eb71f 100644 --- a/test/test_pkgbase_routes.py +++ b/test/test_pkgbase_routes.py @@ -312,7 +312,8 @@ def test_pkgbase_voters(client: TestClient, tu_user: User, package: Package): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) # We should've gotten one link to the voter, tu_user. @@ -343,7 +344,8 @@ def test_pkgbase_comment_not_found( comment_id = 12345 # A non-existing comment. endpoint = f"/pkgbase/{package.PackageBase.Name}/comments/{comment_id}" with client as request: - resp = request.post(endpoint, data={"comment": "Failure"}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"comment": "Failure"}) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -365,7 +367,8 @@ def test_pkgbase_comment_form_unauthorized( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/form" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) @@ -377,7 +380,8 @@ def test_pkgbase_comment_form_not_found( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/form" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -387,7 +391,8 @@ def test_pkgbase_comments_missing_comment( cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/comments" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -409,10 +414,10 @@ def test_pkgbase_comments( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments" with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"comment": "Test comment.", "enable_notifications": True}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -440,7 +445,8 @@ def test_pkgbase_comments( # Test the non-javascript version of comment editing by # visiting the /pkgbase/{name}/comments/{id}/edit route. with client as request: - resp = request.get(f"{endpoint}/{comment_id}/edit", cookies=cookies) + request.cookies = cookies + resp = request.get(f"{endpoint}/{comment_id}/edit") assert resp.status_code == int(HTTPStatus.OK) # Clear up the PackageNotification. This doubles as testing @@ -457,10 +463,10 @@ def test_pkgbase_comments( comment_id = int(headers[0].attrib["id"].split("-")[-1]) endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}" with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"comment": "Edited comment.", "enable_notifications": True}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -485,14 +491,16 @@ def test_pkgbase_comments( # Don't supply a comment; should return BAD_REQUEST. with client as request: - fail_resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + fail_resp = request.post(endpoint) assert fail_resp.status_code == int(HTTPStatus.BAD_REQUEST) # Now, test the form route, which should return form markup # via JSON. endpoint = f"{endpoint}/form" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) data = resp.json() @@ -510,11 +518,11 @@ def test_pkgbase_comment_edit_unauthorized( cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: + request.cookies = cookies endp = f"/pkgbase/{pkgbase.Name}/comments/{comment.ID}" response = request.post( endp, data={"comment": "abcd im trying to change this comment."}, - cookies=cookies, ) assert response.status_code == HTTPStatus.UNAUTHORIZED @@ -561,7 +569,8 @@ def test_pkgbase_comment_delete_unauthorized( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/delete" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) @@ -573,7 +582,8 @@ def test_pkgbase_comment_delete_not_found( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/delete" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -585,7 +595,8 @@ def test_pkgbase_comment_undelete_not_found( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/undelete" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -607,7 +618,8 @@ def test_pkgbase_comment_pin_as_co( endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/pin" cookies = {"AURSID": comaint.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Assert that PinnedTS got set. @@ -616,7 +628,8 @@ def test_pkgbase_comment_pin_as_co( # Unpin the comment we just pinned. endpoint = f"/pkgbase/{pkgbasename}/comments/{comment.ID}/unpin" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Let's assert that PinnedTS was unset. @@ -633,7 +646,8 @@ def test_pkgbase_comment_pin( # Pin the comment. endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/pin" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Assert that PinnedTS got set. @@ -642,7 +656,8 @@ def test_pkgbase_comment_pin( # Unpin the comment we just pinned. endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/unpin" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Let's assert that PinnedTS was unset. @@ -657,7 +672,8 @@ def test_pkgbase_comment_pin_unauthorized( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/pin" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) @@ -669,7 +685,8 @@ def test_pkgbase_comment_unpin_unauthorized( pkgbasename = package.PackageBase.Name endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}/unpin" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) @@ -677,7 +694,8 @@ def test_pkgbase_comaintainers_not_found(client: TestClient, maintainer: User): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = "/pkgbase/fake/comaintainers" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -685,7 +703,8 @@ def test_pkgbase_comaintainers_post_not_found(client: TestClient, maintainer: Us cookies = {"AURSID": maintainer.login(Request(), "testPassword")} endpoint = "/pkgbase/fake/comaintainers" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -696,7 +715,8 @@ def test_pkgbase_comaintainers_unauthorized( endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -708,7 +728,8 @@ def test_pkgbase_comaintainers_post_unauthorized( endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -720,7 +741,8 @@ def test_pkgbase_comaintainers_post_invalid_user( endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers" cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, data={"users": "\nfake\n"}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"users": "\nfake\n"}) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -738,20 +760,20 @@ def test_pkgbase_comaintainers( # Start off by adding user as a comaintainer to package. # The maintainer username given should be ignored. with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"users": f"\n{user.Username}\n{maintainer.Username}\n"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" # Do it again to exercise the last_priority bump path. with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"users": f"\n{user.Username}\n{maintainer.Username}\n"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -760,7 +782,8 @@ def test_pkgbase_comaintainers( # let's perform a GET request to make sure that the backend produces # the user we added in the users textarea. with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -769,12 +792,14 @@ def test_pkgbase_comaintainers( # Finish off by removing all the comaintainers. with client as request: - resp = request.post(endpoint, data={"users": str()}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"users": str()}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) @@ -788,7 +813,8 @@ def test_pkgbase_request_not_found(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -798,16 +824,16 @@ def test_pkgbase_request(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) def test_pkgbase_request_post_not_found(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post( - "/pkgbase/fake/request", data={"type": "fake"}, cookies=cookies - ) + request.cookies = cookies + resp = request.post("/pkgbase/fake/request", data={"type": "fake"}) assert resp.status_code == int(HTTPStatus.NOT_FOUND) @@ -817,7 +843,8 @@ def test_pkgbase_request_post_invalid_type( endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, data={"type": "fake"}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"type": "fake"}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -827,13 +854,13 @@ def test_pkgbase_request_post_no_comment_error( endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( endpoint, data={ "type": "deletion", "comments": "", # An empty comment field causes an error. }, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -849,6 +876,7 @@ def test_pkgbase_request_post_merge_not_found_error( endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( endpoint, data={ @@ -856,7 +884,6 @@ def test_pkgbase_request_post_merge_not_found_error( "merge_into": "fake", # There is no PackageBase.Name "fake" "comments": "We want to merge this.", }, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -872,6 +899,7 @@ def test_pkgbase_request_post_merge_no_merge_into_error( endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( endpoint, data={ @@ -879,7 +907,6 @@ def test_pkgbase_request_post_merge_no_merge_into_error( "merge_into": "", # There is no PackageBase.Name "fake" "comments": "We want to merge this.", }, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -895,6 +922,7 @@ def test_pkgbase_request_post_merge_self_error( endpoint = f"/pkgbase/{package.PackageBase.Name}/request" cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( endpoint, data={ @@ -902,7 +930,6 @@ def test_pkgbase_request_post_merge_self_error( "merge_into": package.PackageBase.Name, "comments": "We want to merge this.", }, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -1017,7 +1044,8 @@ def test_pkgbase_flag_vcs(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(f"/pkgbase/{package.PackageBase.Name}/flag", cookies=cookies) + request.cookies = cookies + resp = request.get(f"/pkgbase/{package.PackageBase.Name}/flag") assert resp.status_code == int(HTTPStatus.OK) expected = ( @@ -1042,7 +1070,8 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/notify" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first() @@ -1051,7 +1080,8 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package): # Disable notifications. endpoint = f"/pkgbase/{pkgbase.Name}/unnotify" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first() @@ -1069,7 +1099,8 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/vote" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() @@ -1079,7 +1110,8 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package): # Remove vote. endpoint = f"/pkgbase/{pkgbase.Name}/unvote" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() @@ -1096,7 +1128,8 @@ def test_pkgbase_disown_as_sole_maintainer( # But we do here. with client as request: - resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"confirm": True}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -1114,9 +1147,8 @@ def test_pkgbase_disown_as_maint_with_comaint( maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.post( - endp, data=post_data, cookies=maint_cookies, follow_redirects=True - ) + request.cookies = maint_cookies + resp = request.post(endp, data=post_data, follow_redirects=True) assert resp.status_code == int(HTTPStatus.OK) package = db.refresh(package) @@ -1219,21 +1251,24 @@ def test_pkgbase_adopt( # Adopt the package base. with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == maintainer # Try to adopt it when it already has a maintainer; nothing changes. user_cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=user_cookies) + request.cookies = user_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == maintainer # Steal the package as a TU. tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.post(endpoint, cookies=tu_cookies) + request.cookies = tu_cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert package.PackageBase.Maintainer == tu_user @@ -1245,13 +1280,15 @@ def test_pkgbase_delete_unauthorized(client: TestClient, user: User, package: Pa # Test GET. with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" # Test POST. with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -1263,17 +1300,20 @@ def test_pkgbase_delete(client: TestClient, tu_user: User, package: Package): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/delete" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) # Test that POST works and denies us because we haven't confirmed. with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) # Test that we can actually delete the pkgbase. with client as request: - resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"confirm": True}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Let's assert that the package base record got removed. @@ -1300,7 +1340,8 @@ def test_pkgbase_delete_with_request( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{pkgbase.Name}/delete" with client as request: - resp = request.post(endpoint, data={"confirm": True}, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint, data={"confirm": True}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/packages" @@ -1316,10 +1357,10 @@ def test_pkgbase_delete_with_request( def test_packages_post_unknown_action(client: TestClient, user: User, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "unknown"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1332,10 +1373,10 @@ def test_packages_post_error(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "stub"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) @@ -1352,10 +1393,10 @@ def test_packages_post(client: TestClient, user: User, package: Package): with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( "/packages", data={"action": "stub"}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -1368,7 +1409,8 @@ def test_pkgbase_merge_unauthorized(client: TestClient, user: User, package: Pac cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) @@ -1376,7 +1418,8 @@ def test_pkgbase_merge(client: TestClient, tu_user: User, package: Package): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.get(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) assert not get_errors(resp.text) @@ -1387,7 +1430,8 @@ def test_pkgbase_merge_post_unauthorized( cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.UNAUTHORIZED) @@ -1397,7 +1441,8 @@ def test_pkgbase_merge_post_unconfirmed( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = ( @@ -1413,9 +1458,8 @@ def test_pkgbase_merge_post_invalid_into( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.post( - endpoint, data={"into": "not_real", "confirm": True}, cookies=cookies - ) + request.cookies = cookies + resp = request.post(endpoint, data={"into": "not_real", "confirm": True}) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) expected = "Cannot find package to merge votes and comments into." @@ -1428,10 +1472,10 @@ def test_pkgbase_merge_post_self_invalid( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: + request.cookies = cookies resp = request.post( endpoint, data={"into": package.PackageBase.Name, "confirm": True}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -1461,20 +1505,24 @@ def test_pkgbase_merge_post( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} endpoint = f"/pkgbase/{package.PackageBase.Name}/vote" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Enable notifications. endpoint = f"/pkgbase/{package.PackageBase.Name}/notify" with client as request: - resp = request.post(endpoint, cookies=cookies) + request.cookies = cookies + resp = request.post(endpoint) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Comment on the package. endpoint = f"/pkgbase/{package.PackageBase.Name}/comments" with client as request: + request.cookies = cookies resp = request.post( - endpoint, data={"comment": "Test comment."}, cookies=cookies + endpoint, + data={"comment": "Test comment."}, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) @@ -1486,9 +1534,8 @@ def test_pkgbase_merge_post( # Merge the package into target. endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" with client as request: - resp = request.post( - endpoint, data={"into": target.Name, "confirm": True}, cookies=cookies - ) + request.cookies = cookies + resp = request.post(endpoint, data={"into": target.Name, "confirm": True}) assert resp.status_code == int(HTTPStatus.SEE_OTHER) loc = resp.headers.get("location") assert loc == f"/pkgbase/{target.Name}" @@ -1604,9 +1651,10 @@ def test_unauthorized_pkgbase_keywords(client: TestClient, package: Package): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies pkgbase = package.PackageBase endp = f"/pkgbase/{pkgbase.Name}/keywords" - response = request.post(endp, cookies=cookies) + response = request.post(endp) assert response.status_code == HTTPStatus.UNAUTHORIZED diff --git a/test/test_requests.py b/test/test_requests.py index 1d681d58..18b860f2 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -254,7 +254,8 @@ def test_request(client: TestClient, auser: User, pkgbase: PackageBase): """Test the standard pkgbase request route GET method.""" endpoint = f"/pkgbase/{pkgbase.Name}/request" with client as request: - resp = request.get(endpoint, cookies=auser.cookies) + request.cookies = auser.cookies + resp = request.get(endpoint) assert resp.status_code == int(HTTPStatus.OK) @@ -263,7 +264,8 @@ def test_request_post_deletion(client: TestClient, auser2: User, pkgbase: Packag endpoint = f"/pkgbase/{pkgbase.Name}/request" data = {"comments": "Test request.", "type": "deletion"} with client as request: - resp = request.post(endpoint, data=data, cookies=auser2.cookies) + request.cookies = auser2.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) pkgreq = pkgbase.requests.first() @@ -285,7 +287,8 @@ def test_request_post_deletion_as_maintainer( endpoint = f"/pkgbase/{pkgbase.Name}/request" data = {"comments": "Test request.", "type": "deletion"} with client as request: - resp = request.post(endpoint, data=data, cookies=auser.cookies) + request.cookies = auser.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) # Check the pkgreq record got created and accepted. @@ -368,7 +371,8 @@ def test_request_post_merge( "comments": "Test request.", } with client as request: - resp = request.post(endpoint, data=data, cookies=auser.cookies) + request.cookies = auser.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) pkgreq = pkgbase.requests.first() @@ -392,7 +396,8 @@ def test_request_post_orphan(client: TestClient, auser: User, pkgbase: PackageBa "comments": "Test request.", } with client as request: - resp = request.post(endpoint, data=data, cookies=auser.cookies) + request.cookies = auser.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) pkgreq = pkgbase.requests.first() @@ -428,7 +433,8 @@ def test_deletion_request( comments = "Test closure." data = {"comments": comments, "confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=tu_user.cookies) + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/packages" @@ -460,7 +466,8 @@ def test_deletion_autorequest(client: TestClient, tu_user: User, pkgbase: Packag endpoint = f"/pkgbase/{pkgbase.Name}/delete" data = {"confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=tu_user.cookies) + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/packages" @@ -498,7 +505,8 @@ def test_merge_request( comments = "Test merge closure." data = {"into": target.Name, "comments": comments, "confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=tu_user.cookies) + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{target.Name}" @@ -545,7 +553,8 @@ def test_merge_autorequest( endpoint = f"/pkgbase/{pkgbase.Name}/merge" data = {"into": target.Name, "confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=tu_user.cookies) + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{target.Name}" @@ -582,7 +591,8 @@ def test_orphan_request( comments = "Test orphan closure." data = {"comments": comments, "confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=tu_user.cookies) + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -615,7 +625,8 @@ def test_request_post_orphan_autogenerated_closure( endpoint = f"/pkgbase/{pkgbase.Name}/disown" data = {"confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=tu_user.cookies) + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -677,7 +688,8 @@ def test_orphan_as_maintainer(client: TestClient, auser: User, pkgbase: PackageB endpoint = f"/pkgbase/{pkgbase.Name}/disown" data = {"confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=auser.cookies) + request.cookies = auser.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" @@ -694,7 +706,8 @@ def test_orphan_without_requests( endpoint = f"/pkgbase/{pkgbase.Name}/disown" data = {"confirm": True} with client as request: - resp = request.post(endpoint, data=data, cookies=tu_user.cookies) + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) assert resp.status_code == int(HTTPStatus.BAD_REQUEST) errors = get_errors(resp.text) @@ -733,6 +746,7 @@ def test_requests( ): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.get( "/requests", params={ @@ -742,7 +756,6 @@ def test_requests( "SeB": "nd", "SB": "n", }, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -756,7 +769,8 @@ def test_requests( # Request page 2 of the requests page. with client as request: - resp = request.get("/requests", params={"O": 50}, cookies=cookies) # Page 2 + request.cookies = cookies + resp = request.get("/requests", params={"O": 50}) # Page 2 assert resp.status_code == int(HTTPStatus.OK) assert "‹ Previous" in resp.text @@ -775,6 +789,7 @@ def test_requests_with_filters( ): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.get( "/requests", params={ @@ -789,7 +804,6 @@ def test_requests_with_filters( "filter_rejected": True, "filter_maintainer_requests": False, }, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -803,6 +817,7 @@ def test_requests_with_filters( # Request page 2 of the requests page. with client as request: + request.cookies = cookies resp = request.get( "/requests", params={ @@ -813,7 +828,6 @@ def test_requests_with_filters( "filter_rejected": True, "filter_maintainer_requests": False, }, - cookies=cookies, ) # Page 2 assert resp.status_code == int(HTTPStatus.OK) @@ -833,10 +847,10 @@ def test_requests_for_maintainer_requests( ): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.get( "/requests", params={"filter_maintainer_requests": True}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.OK) @@ -854,7 +868,8 @@ def test_requests_by_deleted_users( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - resp = request.get("/requests", cookies=cookies) + request.cookies = cookies + resp = request.get("/requests") assert resp.status_code == HTTPStatus.OK root = parse_root(resp.text) @@ -867,7 +882,8 @@ def test_requests_selfmade( ): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get("/requests", cookies=cookies) + request.cookies = cookies + resp = request.get("/requests") assert resp.status_code == int(HTTPStatus.OK) # As the user who creates all of the requests, we should see all of them. @@ -885,7 +901,8 @@ def test_requests_selfmade( def test_requests_close(client: TestClient, user: User, pkgreq: PackageRequest): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies) + request.cookies = cookies + resp = request.get(f"/requests/{pkgreq.ID}/close") assert resp.status_code == int(HTTPStatus.OK) @@ -894,7 +911,10 @@ def test_requests_close_unauthorized( ): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: - resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies) + request.cookies = cookies + resp = request.get( + f"/requests/{pkgreq.ID}/close", + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" @@ -904,10 +924,10 @@ def test_requests_close_post_unauthorized( ): cookies = {"AURSID": maintainer.login(Request(), "testPassword")} with client as request: + request.cookies = cookies resp = request.post( f"/requests/{pkgreq.ID}/close", data={"reason": ACCEPTED_ID}, - cookies=cookies, ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.headers.get("location") == "/" @@ -916,7 +936,8 @@ def test_requests_close_post_unauthorized( def test_requests_close_post(client: TestClient, user: User, pkgreq: PackageRequest): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(f"/requests/{pkgreq.ID}/close", cookies=cookies) + request.cookies = cookies + resp = request.post(f"/requests/{pkgreq.ID}/close") assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgreq.Status == REJECTED_ID @@ -929,7 +950,10 @@ def test_requests_close_post_rejected( ): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - resp = request.post(f"/requests/{pkgreq.ID}/close", cookies=cookies) + request.cookies = cookies + resp = request.post( + f"/requests/{pkgreq.ID}/close", + ) assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert pkgreq.Status == REJECTED_ID diff --git a/test/test_routes.py b/test/test_routes.py index b4bc30ee..c104211e 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -99,7 +99,8 @@ def test_user_language(client: TestClient, user: User): assert sid is not None with client as req: - response = req.post("/language", data=post_data, cookies={"AURSID": sid}) + req.cookies = {"AURSID": sid} + response = req.post("/language", data=post_data) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert user.LangPreference == "de" @@ -154,6 +155,5 @@ def test_id_redirect(client: TestClient): "key": "value", # Test that this param persists. "key2": "value2", # And this one. }, - allow_redirects=False, ) assert response.headers.get("location") == "/test?key=value&key2=value2" diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py index dc468808..0bb9523e 100644 --- a/test/test_trusted_user_routes.py +++ b/test/test_trusted_user_routes.py @@ -166,7 +166,8 @@ def test_tu_index_unauthorized(client: TestClient, user: User): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: # Login as a normal user, not a TU. - response = request.get("/tu", cookies=cookies) + request.cookies = cookies + response = request.get("/tu") assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/" @@ -177,7 +178,8 @@ def test_tu_empty_index(client, tu_user): # Make a default get request to /tu. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies) + request.cookies = cookies + response = request.get("/tu") assert response.status_code == int(HTTPStatus.OK) # Parse lxml root. @@ -226,9 +228,9 @@ def test_tu_index(client, tu_user): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: # Pass an invalid cby and pby; let them default to "desc". + request.cookies = cookies response = request.get( "/tu", - cookies=cookies, params={"cby": "BAD!", "pby": "blah"}, ) @@ -295,7 +297,8 @@ def test_tu_index(client, tu_user): def test_tu_stats(client: TestClient, tu_user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies) + request.cookies = cookies + response = request.get("/tu") assert response.status_code == HTTPStatus.OK root = parse_root(response.text) @@ -316,7 +319,8 @@ def test_tu_stats(client: TestClient, tu_user: User): tu_user.InactivityTS = time.utcnow() with client as request: - response = request.get("/tu", cookies=cookies) + request.cookies = cookies + response = request.get("/tu") assert response.status_code == HTTPStatus.OK root = parse_root(response.text) @@ -364,7 +368,8 @@ def test_tu_index_table_paging(client, tu_user): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies) + request.cookies = cookies + response = request.get("/tu") assert response.status_code == int(HTTPStatus.OK) # Parse lxml.etree root. @@ -394,7 +399,8 @@ def test_tu_index_table_paging(client, tu_user): # Now, get the next page of current votes. offset = 10 # Specify coff=10 with client as request: - response = request.get("/tu", cookies=cookies, params={"coff": offset}) + request.cookies = cookies + response = request.get("/tu", params={"coff": offset}) assert response.status_code == int(HTTPStatus.OK) old_rows = rows @@ -421,7 +427,8 @@ def test_tu_index_table_paging(client, tu_user): offset = 20 # Specify coff=10 with client as request: - response = request.get("/tu", cookies=cookies, params={"coff": offset}) + request.cookies = cookies + response = request.get("/tu", params={"coff": offset}) assert response.status_code == int(HTTPStatus.OK) # Do it again, we only have five left. @@ -470,7 +477,8 @@ def test_tu_index_sorting(client, tu_user): # Make a default request to /tu. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies) + request.cookies = cookies + response = request.get("/tu") assert response.status_code == int(HTTPStatus.OK) # Get lxml handles of the document. @@ -497,7 +505,8 @@ def test_tu_index_sorting(client, tu_user): # Make another request; one that sorts the current votes # in ascending order instead of the default descending order. with client as request: - response = request.get("/tu", cookies=cookies, params={"cby": "asc"}) + request.cookies = cookies + response = request.get("/tu", params={"cby": "asc"}) assert response.status_code == int(HTTPStatus.OK) # Get lxml handles of the document. @@ -548,7 +557,8 @@ def test_tu_index_last_votes( # Now, check that tu_user got populated in the .last-votes table. cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/tu", cookies=cookies) + request.cookies = cookies + response = request.get("/tu") assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -581,12 +591,14 @@ def test_tu_proposal_unauthorized( cookies = {"AURSID": user.login(Request(), "testPassword")} endpoint = f"/tu/{proposal[2].ID}" with client as request: - response = request.get(endpoint, cookies=cookies) + request.cookies = cookies + response = request.get(endpoint) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" with client as request: - response = request.post(endpoint, cookies=cookies, data={"decision": False}) + request.cookies = cookies + response = request.post(endpoint, data={"decision": False}) assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" @@ -602,9 +614,8 @@ def test_tu_running_proposal( proposal_id = voteinfo.ID cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get( - f"/tu/{proposal_id}", cookies=cookies, follow_redirects=True - ) + request.cookies = cookies + response = request.get(f"/tu/{proposal_id}") assert response.status_code == int(HTTPStatus.OK) # Alright, now let's continue on to verifying some markup. @@ -674,9 +685,8 @@ def test_tu_running_proposal( # Make another request now that we've voted. with client as request: - response = request.get( - "/tu", params={"id": voteinfo.ID}, cookies=cookies, follow_redirects=True - ) + request.cookies = cookies + response = request.get("/tu", params={"id": voteinfo.ID}, follow_redirects=True) assert response.status_code == int(HTTPStatus.OK) # Parse our new root. @@ -702,7 +712,8 @@ def test_tu_ended_proposal(client, proposal): proposal_id = voteinfo.ID cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get(f"/tu/{proposal_id}", cookies=cookies) + request.cookies = cookies + response = request.get(f"/tu/{proposal_id}") assert response.status_code == int(HTTPStatus.OK) # Alright, now let's continue on to verifying some markup. @@ -734,7 +745,8 @@ def test_tu_proposal_vote_not_found(client, tu_user): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post("/tu/1", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/tu/1", data=data) assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -747,7 +759,8 @@ def test_tu_proposal_vote(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) + request.cookies = cookies + response = request.post(f"/tu/{voteinfo.ID}", data=data) assert response.status_code == int(HTTPStatus.OK) # Check that the proposal record got updated. @@ -775,7 +788,8 @@ def test_tu_proposal_vote_unauthorized( cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) + request.cookies = cookies + response = request.post(f"/tu/{voteinfo.ID}", data=data) assert response.status_code == int(HTTPStatus.UNAUTHORIZED) root = parse_root(response.text) @@ -784,7 +798,8 @@ def test_tu_proposal_vote_unauthorized( with client as request: data = {"decision": "Yes"} - response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, params=data) + request.cookies = cookies + response = request.get(f"/tu/{voteinfo.ID}", params=data) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -802,7 +817,8 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) + request.cookies = cookies + response = request.post(f"/tu/{voteinfo.ID}", data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) root = parse_root(response.text) @@ -811,7 +827,8 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal): with client as request: data = {"decision": "Yes"} - response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, params=data) + request.cookies = cookies + response = request.get(f"/tu/{voteinfo.ID}", params=data) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -830,7 +847,8 @@ def test_tu_proposal_vote_already_voted(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "Yes"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) + request.cookies = cookies + response = request.post(f"/tu/{voteinfo.ID}", data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) root = parse_root(response.text) @@ -839,7 +857,8 @@ def test_tu_proposal_vote_already_voted(client, proposal): with client as request: data = {"decision": "Yes"} - response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies, params=data) + request.cookies = cookies + response = request.get(f"/tu/{voteinfo.ID}", params=data) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -853,7 +872,8 @@ def test_tu_proposal_vote_invalid_decision(client, proposal): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: data = {"decision": "EVIL"} - response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data) + request.cookies = cookies + response = request.post(f"/tu/{voteinfo.ID}", data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) assert response.text == "Invalid 'decision' value." @@ -861,7 +881,8 @@ def test_tu_proposal_vote_invalid_decision(client, proposal): def test_tu_addvote(client: TestClient, tu_user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/addvote", cookies=cookies) + request.cookies = cookies + response = request.get("/addvote") assert response.status_code == int(HTTPStatus.OK) @@ -870,12 +891,14 @@ def test_tu_addvote_unauthorized( ): cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: - response = request.get("/addvote", cookies=cookies) + request.cookies = cookies + response = request.get("/addvote") assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" with client as request: - response = request.post("/addvote", cookies=cookies) + request.cookies = cookies + response = request.post("/addvote") assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.headers.get("location") == "/tu" @@ -883,7 +906,8 @@ def test_tu_addvote_unauthorized( def test_tu_addvote_invalid_type(client: TestClient, tu_user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: - response = request.get("/addvote", params={"type": "faketype"}, cookies=cookies) + request.cookies = cookies + response = request.get("/addvote", params={"type": "faketype"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -897,7 +921,8 @@ def test_tu_addvote_post(client: TestClient, tu_user: User, user: User): data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"} with client as request: - response = request.post("/addvote", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/addvote", data=data) assert response.status_code == int(HTTPStatus.SEE_OTHER) voteinfo = db.query(TUVoteInfo, TUVoteInfo.Agenda == "Blah").first() @@ -912,14 +937,16 @@ def test_tu_addvote_post_cant_duplicate_username( data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"} with client as request: - response = request.post("/addvote", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/addvote", data=data) assert response.status_code == int(HTTPStatus.SEE_OTHER) voteinfo = db.query(TUVoteInfo, TUVoteInfo.Agenda == "Blah").first() assert voteinfo is not None with client as request: - response = request.post("/addvote", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/addvote", data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -927,7 +954,8 @@ def test_tu_addvote_post_invalid_username(client: TestClient, tu_user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} data = {"user": "fakeusername"} with client as request: - response = request.post("/addvote", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/addvote", data=data) assert response.status_code == int(HTTPStatus.NOT_FOUND) @@ -935,7 +963,8 @@ def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User, user: U cookies = {"AURSID": tu_user.login(Request(), "testPassword")} data = {"user": user.Username} with client as request: - response = request.post("/addvote", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/addvote", data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -943,7 +972,8 @@ def test_tu_addvote_post_invalid_agenda(client: TestClient, tu_user: User, user: cookies = {"AURSID": tu_user.login(Request(), "testPassword")} data = {"user": user.Username, "type": "add_tu"} with client as request: - response = request.post("/addvote", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/addvote", data=data) assert response.status_code == int(HTTPStatus.BAD_REQUEST) @@ -952,5 +982,6 @@ def test_tu_addvote_post_bylaws(client: TestClient, tu_user: User): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} data = {"type": "bylaws", "agenda": "Blah blah!"} with client as request: - response = request.post("/addvote", cookies=cookies, data=data) + request.cookies = cookies + response = request.post("/addvote", data=data) assert response.status_code == int(HTTPStatus.SEE_OTHER) From a08681ba2391b955cc39a8f62dbddcc153ea6cca Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 25 Nov 2022 12:24:04 +0100 Subject: [PATCH 1640/1891] fix: Add "Show more..." link for "Required by" Fix glitch on the package page: "Show more..." not displayed for the "Required by" list Fix test case: Function name does not start with "test" hence it was never executed during test runs Issue report: #363 Signed-off-by: moson-mo --- templates/partials/packages/package_metadata.html | 10 ++++++---- test/test_packages_routes.py | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html index 123b994d..50d38b48 100644 --- a/templates/partials/packages/package_metadata.html +++ b/templates/partials/packages/package_metadata.html @@ -62,10 +62,12 @@ {{ dep | dep_extra }} {% endfor %} - {% if not all_reqs and (required_by | length) > max_listing %} - - {{ "Show %d more" | tr | format(reqs_count - (required_by | length)) }}... - + {% if not all_reqs and reqs_count > max_listing %} +
  • + + {{ "Show %d more" | tr | format(reqs_count - (required_by | length)) }}... + +
  • {% endif %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 0da6cfab..c8986b9c 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -352,7 +352,7 @@ def test_package_split_description(client: TestClient, user: User): assert row.text == pkg_b.Description -def paged_depends_required(client: TestClient, package: Package): +def test_paged_depends_required(client: TestClient, package: Package): maint = package.PackageBase.Maintainer new_pkgs = [] @@ -360,7 +360,7 @@ def paged_depends_required(client: TestClient, package: Package): # Create 25 new packages that'll be used to depend on our package. for i in range(26): base = db.create(PackageBase, Name=f"new_pkg{i}", Maintainer=maint) - new_pkgs.append(db.create(Package, Name=base.Name)) + new_pkgs.append(db.create(Package, Name=base.Name, PackageBase=base)) # Create 25 deps. for i in range(25): From 7864ac6dfeafd3995063e3b58cfbd393fb1b6551 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 27 Nov 2022 10:33:58 +0100 Subject: [PATCH 1641/1891] fix: search-by parameter for keyword links Fixes: Keyword-links on the package page pass wrong query-parameter. Thus a name/description search is performed instead of keywords Issue report: #397 Signed-off-by: moson-mo --- templates/partials/packages/details.html | 2 +- test/test_packages_routes.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/templates/partials/packages/details.html b/templates/partials/packages/details.html index 8ecf9bd8..697ef724 100644 --- a/templates/partials/packages/details.html +++ b/templates/partials/packages/details.html @@ -53,7 +53,7 @@ {% for keyword in pkgbase.keywords.all() %} {{ keyword.Keyword }} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index c8986b9c..bf179963 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -271,6 +271,13 @@ def test_package(client: TestClient, package: Package): db.create(PackageLicense, PackageID=package.ID, License=licenses[0]) db.create(PackageLicense, PackageID=package.ID, License=licenses[1]) + # Create some keywords + keywords = ["test1", "test2"] + for keyword in keywords: + db.create( + PackageKeyword, PackageBaseID=package.PackageBaseID, Keyword=keyword + ) + with client as request: resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) @@ -307,6 +314,11 @@ def test_package(client: TestClient, package: Package): expected = ["test_conflict1", "test_conflict2"] assert conflicts[0].text.strip() == ", ".join(expected) + keywords = root.xpath('//a[@class="keyword"]') + expected = ["test1", "test2"] + for i, keyword in enumerate(expected): + assert keywords[i].text.strip() == keyword + def test_package_split_description(client: TestClient, user: User): From c74772cb3610c7f5be270f0edb1416fc9d1476ed Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sun, 27 Nov 2022 10:34:07 +0000 Subject: [PATCH 1642/1891] chore: bump to v6.1.9 Signed-off-by: Leonidas Spyropoulos --- aurweb/config.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 49806738..8130376d 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -5,7 +5,7 @@ from typing import Any # Publicly visible version of aurweb. This is used to display # aurweb versioning in the footer and must be maintained. # Todo: Make this dynamic/automated. -AURWEB_VERSION = "v6.1.8" +AURWEB_VERSION = "v6.1.9" _parser = None diff --git a/pyproject.toml b/pyproject.toml index 762a52c1..ce5b0b43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.1.8" +version = "v6.1.9" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 8027ff936c030ebcd43bf4d8ae3a244fb3d28a56 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 28 Nov 2022 16:57:27 +0100 Subject: [PATCH 1643/1891] fix: alignment of pagination element pagination for comments should appear on the right instead of center Issue report: #390 Signed-off-by: moson-mo --- templates/partials/packages/comments.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/partials/packages/comments.html b/templates/partials/packages/comments.html index 9d49bc86..f00d62f2 100644 --- a/templates/partials/packages/comments.html +++ b/templates/partials/packages/comments.html @@ -39,7 +39,7 @@ {% if pages > 1 %}

    {{ page | pager_nav(comments_total, prefix) | safe }} -

    +

    {% endif %} {% for comment in comments.all() %} From 2b8dedb3a2dcfa4442591bf589e1586105064866 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 28 Nov 2022 17:01:44 +0100 Subject: [PATCH 1644/1891] feat: add pagination element below comments other pages like the "package search" have this as well. Issue report: #390 Signed-off-by: moson-mo --- templates/partials/packages/comments.html | 7 +++++++ web/html/css/aurweb.css | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/templates/partials/packages/comments.html b/templates/partials/packages/comments.html index f00d62f2..55421bfa 100644 --- a/templates/partials/packages/comments.html +++ b/templates/partials/packages/comments.html @@ -45,5 +45,12 @@ {% for comment in comments.all() %} {% include "partials/packages/comment.html" %} {% endfor %} + {% endif %} diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 59f7ed1e..64a65742 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -193,6 +193,11 @@ label.confirmation { align-self: flex-end; } +.comments-footer { + display: flex; + justify-content: flex-end; +} + .comment-header { clear: both; font-size: 1em; From d8e91d058cd494dfb7812994796d1a46eb532f6b Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 22 Dec 2022 12:41:29 +0100 Subject: [PATCH 1645/1891] fix(rpc): provides search should return name match We need to return packages matching on the name as well. (A package always provides itself) Signed-off-by: moson-mo --- aurweb/rpc.py | 12 +++++++++++- test/test_rpc.py | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 2aa27500..1440703a 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -376,8 +376,18 @@ class RPC: search.search_by(by, arg) max_results = config.getint("options", "max_rpc_results") - results = self.entities(search.results()).limit(max_results + 1).all() + query = self.entities(search.results()).limit(max_results + 1) + + # For "provides", we need to union our relation search + # with an exact search since a package always provides itself. + # Turns out that doing this with an OR statement is extremely slow + if by == "provides": + search = RPCSearch() + search._search_by_exact_name(arg) + query = query.union(self.entities(search.results())) + + results = query.all() if len(results) > max_results: raise RPCError("Too many package results.") diff --git a/test/test_rpc.py b/test/test_rpc.py index 04efd38f..92714ff1 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -920,6 +920,19 @@ def test_rpc_search_provides( assert result.get("Name") == packages[0].Name +def test_rpc_search_provides_self( + client: TestClient, packages: list[Package], relations: list[PackageRelation] +): + params = {"v": 5, "type": "search", "by": "provides", "arg": "big-chungus"} + with client as request: + response = request.get("/rpc", params=params) + data = response.json() + # expected to return "big-chungus" + assert data.get("resultcount") == 1 + result = data.get("results")[0] + assert result.get("Name") == packages[0].Name + + def test_rpc_search_conflicts( client: TestClient, packages: list[Package], relations: list[PackageRelation] ): From 7a9448a3e52e216f4f11b996be12ab87b99fe4bc Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 29 Nov 2022 14:45:24 +0100 Subject: [PATCH 1646/1891] perf: improve packages search-query Improves performance for queries with large result sets. The "group by" clause can be removed for all search types but the keywords. Signed-off-by: moson-mo --- aurweb/packages/search.py | 5 ++++- aurweb/routers/packages.py | 28 ++++++++++++---------------- test/test_packages_routes.py | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index c0740cda..d5e00110 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -136,7 +136,10 @@ class PackageSearch: self._join_user() self._join_keywords() keywords = set(k.lower() for k in keywords) - self.query = self.query.filter(PackageKeyword.Keyword.in_(keywords)) + self.query = self.query.filter(PackageKeyword.Keyword.in_(keywords)).group_by( + models.Package.Name + ) + return self def _search_by_maintainer(self, keywords: str) -> orm.Query: diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index a4aac496..6a943dbf 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -93,22 +93,18 @@ async def packages_get( search.sort_by(sort_by, sort_order) # Insert search results into the context. - results = ( - search.results() - .with_entities( - models.Package.ID, - models.Package.Name, - models.Package.PackageBaseID, - models.Package.Version, - models.Package.Description, - models.PackageBase.Popularity, - models.PackageBase.NumVotes, - models.PackageBase.OutOfDateTS, - models.User.Username.label("Maintainer"), - models.PackageVote.PackageBaseID.label("Voted"), - models.PackageNotification.PackageBaseID.label("Notify"), - ) - .group_by(models.Package.Name) + results = search.results().with_entities( + models.Package.ID, + models.Package.Name, + models.Package.PackageBaseID, + models.Package.Version, + models.Package.Description, + models.PackageBase.Popularity, + models.PackageBase.NumVotes, + models.PackageBase.OutOfDateTS, + models.User.Username.label("Maintainer"), + models.PackageVote.PackageBaseID.label("Voted"), + models.PackageNotification.PackageBaseID.label("Notify"), ) packages = results.limit(per_page).offset(offset) diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index bf179963..f9cea694 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -740,6 +740,23 @@ def test_packages_search_by_keywords(client: TestClient, packages: list[Package] rows = root.xpath('//table[@class="results"]/tbody/tr') assert len(rows) == 1 + # Now let's add another keyword to the same package + with db.begin(): + db.create( + PackageKeyword, PackageBase=package.PackageBase, Keyword="testKeyword2" + ) + + # And request packages with both keywords, we should still get 1 result. + with client as request: + response = request.get( + "/packages", params={"SeB": "k", "K": "testKeyword testKeyword2"} + ) + assert response.status_code == int(HTTPStatus.OK) + + root = parse_root(response.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + assert len(rows) == 1 + def test_packages_search_by_maintainer( client: TestClient, maintainer: User, package: Package From 413de914caa20f1dd848c9b59e6d8d065a3b8230 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:28:17 -0800 Subject: [PATCH 1647/1891] fix: remove trailing whitespace lint check for ./po Signed-off-by: Kevin Morris --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ab4240c9..b2baec65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,6 +8,7 @@ repos: - id: check-toml - id: end-of-file-fixer - id: trailing-whitespace + exclude: ^po/ - id: debug-statements - repo: https://github.com/myint/autoflake From 65266d752b2671a8d175e85aafd8b27ae638aba0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:13 -0800 Subject: [PATCH 1648/1891] update-ar translations --- po/ar.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ar.po b/po/ar.po index ea0e03cf..1fed4f4f 100644 --- a/po/ar.po +++ b/po/ar.po @@ -1,17 +1,17 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # safa1996alfulaij , 2015 # صفا الفليج , 2015-2016 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: صفا الفليج , 2015-2016\n" "Language-Team: Arabic (http://www.transifex.com/lfleischer/aurweb/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 3a13eeb744e603d06bbe57025af5ebabaf3ba615 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:16 -0800 Subject: [PATCH 1649/1891] update-az translations --- po/az.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/az.po b/po/az.po index 1c7ca207..df14a5b0 100644 --- a/po/az.po +++ b/po/az.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Azerbaijani (http://www.transifex.com/lfleischer/aurweb/language/az/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From b89fe9eb1397529982c6ab099abef30214e7ce2e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:19 -0800 Subject: [PATCH 1650/1891] update-az_AZ translations --- po/az_AZ.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/az_AZ.po b/po/az_AZ.po index 2f5ceabd..293d7b0d 100644 --- a/po/az_AZ.po +++ b/po/az_AZ.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Azerbaijani (Azerbaijan) (http://www.transifex.com/lfleischer/aurweb/language/az_AZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 9229220e2107833846565f54f7cf814086f8b04d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:22 -0800 Subject: [PATCH 1651/1891] update-bg translations --- po/bg.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/bg.po b/po/bg.po index c7c70021..f373b761 100644 --- a/po/bg.po +++ b/po/bg.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Bulgarian (http://www.transifex.com/lfleischer/aurweb/language/bg/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From d6661403aae6ebc40d68a2b47170bbd626a79f8e Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:26 -0800 Subject: [PATCH 1652/1891] update-ca translations --- po/ca.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ca.po b/po/ca.po index d43c84dc..86d77e56 100644 --- a/po/ca.po +++ b/po/ca.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Adolfo Jayme-Barrientos, 2014 # Hector Mtz-Seara , 2011,2013 @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Ícar , 2021\n" "Language-Team: Catalan (http://www.transifex.com/lfleischer/aurweb/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 618a382e6c32e3eef2efc20b3a15877754518cb4 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:29 -0800 Subject: [PATCH 1653/1891] update-ca_ES translations --- po/ca_ES.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ca_ES.po b/po/ca_ES.po index aac7b03f..5c05ba0c 100644 --- a/po/ca_ES.po +++ b/po/ca_ES.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Catalan (Spain) (http://www.transifex.com/lfleischer/aurweb/language/ca_ES/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From da458ae70ab1c1c05c1d0965bb31990f09769676 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:33 -0800 Subject: [PATCH 1654/1891] update-cs translations --- po/cs.po | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/po/cs.po b/po/cs.po index 59a24007..9086bd75 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,11 +1,11 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Daniel Milde , 2017 # Daniel Peukert , 2021 -# Daniel Peukert , 2021 +# Daniel Peukert , 2021-2022 # Jaroslav Lichtblau , 2015-2016 # Jaroslav Lichtblau , 2014 # Jiří Vírava , 2017-2018 @@ -15,10 +15,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Daniel Peukert , 2021-2022\n" "Language-Team: Czech (http://www.transifex.com/lfleischer/aurweb/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -763,7 +763,7 @@ msgstr "Hlasující" msgid "" "Account registration has been disabled for your IP address, probably due to " "sustained spam attacks. Sorry for the inconvenience." -msgstr "Registrace účtu byla pro vaši IP adresu zakázána, pravděpodobně kvůli trvalým spamovým útokům. Omluvám se za nepříjemnost." +msgstr "Registrace účtu byla pro vaši IP adresu zakázána, pravděpodobně kvůli trvalým spamovým útokům. Za nepříjemnosti se omlouváme." #: lib/acctfuncs.inc.php msgid "Missing User ID" @@ -978,7 +978,7 @@ msgstr "Informace o balíčku nebyly nalezeny." #: aurweb/routers/auth.py msgid "Bad Referer header." -msgstr "" +msgstr "Chybná hlavička Referer" #: aurweb/routers/packages.py msgid "You did not select any packages to be notified about." @@ -2322,33 +2322,33 @@ msgstr "Pro změnu typu tohoto účtu na %s nemáte oprávnění." #: aurweb/packages/requests.py msgid "No due existing orphan requests to accept for %s." -msgstr "" +msgstr "Žádné žádosti o odebrání vlastnictví balíčku %s momentálně neexistují." #: aurweb/asgi.py msgid "Internal Server Error" -msgstr "" +msgstr "Interní chyba serveru" #: templates/errors/500.html msgid "A fatal error has occurred." -msgstr "" +msgstr "Došlo k fatální chybě." #: templates/errors/500.html msgid "" "Details have been logged and will be reviewed by the postmaster posthaste. " "We apologize for any inconvenience this may have caused." -msgstr "" +msgstr "Detaily chyby byly zalogovány a budou co nejdříve zkontrolovány administrátorem. Za jakékoli způsobené nepříjemnosti se omlouváme." #: aurweb/scripts/notify.py msgid "AUR Server Error" -msgstr "" +msgstr "Chyba serveru AUR" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "Komentáře k uzavření žádostí vztahujících se k tomuto balíčku..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Tato akce uzavře všechny žádosti čekající na vyřízení vztahující se k tomuto balíčku. Pokud není vyplněno textové Pole %sKomentáře\"%s, komentář k uzavření žádostí bude vygenerován automaticky." From 5a7a9c2c9f8734842510cadc70b2e090a77c03dd Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:36 -0800 Subject: [PATCH 1655/1891] update-da translations --- po/da.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/da.po b/po/da.po index 822b5506..89f6a635 100644 --- a/po/da.po +++ b/po/da.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Linuxbruger , 2018 # Louis Tim Larsen , 2015 @@ -9,10 +9,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Linuxbruger , 2018\n" "Language-Team: Danish (http://www.transifex.com/lfleischer/aurweb/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 791e715aee661d67152ca2bf20714d9697586590 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:39 -0800 Subject: [PATCH 1656/1891] update-de translations --- po/de.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/de.po b/po/de.po index a0f8fb0f..894494c6 100644 --- a/po/de.po +++ b/po/de.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # 9d91e189c22376bb4ee81489bc27fc28, 2013 # 9d91e189c22376bb4ee81489bc27fc28, 2013-2014 @@ -27,10 +27,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Stefan Auditor , 2021\n" "Language-Team: German (http://www.transifex.com/lfleischer/aurweb/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 6bf408775c249f0938ce7dd59066bc91a2c872a7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:43 -0800 Subject: [PATCH 1657/1891] update-el translations --- po/el.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/po/el.po b/po/el.po index 37db785c..2b665c34 100644 --- a/po/el.po +++ b/po/el.po @@ -1,23 +1,23 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Achilleas Pipinellis, 2014 # Achilleas Pipinellis, 2013 # Achilleas Pipinellis, 2013 # Achilleas Pipinellis, 2011 # Achilleas Pipinellis, 2012 -# Leonidas Spyropoulos, 2021 +# Leonidas Spyropoulos, 2021-2022 # Lukas Fleischer , 2011 # flamelab , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Leonidas Spyropoulos, 2021-2022\n" "Language-Team: Greek (http://www.transifex.com/lfleischer/aurweb/language/el/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "Μας συγχωρείτε, η σελίδα που ζητήσατε δ #: html/404.php template/pkgreq_close_form.php msgid "Note" -msgstr "" +msgstr "Σημείωση" #: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." From aeb38b599d68ac1c7cf50b3fdd22a3b222db688c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:46 -0800 Subject: [PATCH 1658/1891] update-es translations --- po/es.po | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/po/es.po b/po/es.po index 9cbe98a6..b6035d5b 100644 --- a/po/es.po +++ b/po/es.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Adolfo Jayme-Barrientos, 2015 # Angel Velasquez , 2011 @@ -9,25 +9,25 @@ # Lukas Fleischer , 2011 # neiko , 2011 # Nicolás de la Torre , 2012 -# prflr88 , 2012 -# prflr88 , 2016-2017 -# prflr88 , 2013-2016 -# prflr88 , 2016-2017 -# prflr88 , 2016 -# prflr88 , 2019 +# Pablo Lezaeta Reyes , 2012 +# Pablo Lezaeta Reyes , 2016-2017 +# Pablo Lezaeta Reyes , 2013-2016 +# Pablo Lezaeta Reyes , 2016-2017 +# Pablo Lezaeta Reyes , 2016 +# Pablo Lezaeta Reyes , 2019 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Pablo Lezaeta Reyes , 2019\n" "Language-Team: Spanish (http://www.transifex.com/lfleischer/aurweb/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: html/404.php msgid "Page Not Found" @@ -1590,6 +1590,7 @@ msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "Hay %d solicitud pendiente" msgstr[1] "Hay %d solicitudes pendientes" +msgstr[2] "Hay %d solicitudes pendientes" #: template/pkgbase_actions.php msgid "Adopt Package" @@ -1864,6 +1865,7 @@ msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "Se encontró %d solicitud para el paquete." msgstr[1] "Se encontraron %d solicitudes para el paquete." +msgstr[2] "Se encontraron %d solicitudes para el paquete." #: template/pkgreq_results.php template/pkg_search_results.php #, php-format @@ -1888,6 +1890,7 @@ msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d día restante" msgstr[1] "~%d días restantes" +msgstr[2] "~%d días restantes" #: template/pkgreq_results.php #, php-format @@ -1895,6 +1898,7 @@ msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "Aprox. %d hora restante" msgstr[1] "Aprox. %d horas restantes" +msgstr[2] "Aprox. %d horas restantes" #: template/pkgreq_results.php msgid "<1 hour left" @@ -2023,6 +2027,7 @@ msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquete fue encontrado." msgstr[1] "%d paquetes fueron encontrados." +msgstr[2] "%d paquetes fueron encontrados." #: template/pkg_search_results.php msgid "Version" From 076245e061786e762cc705fa5ad49f7292b456db Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:49 -0800 Subject: [PATCH 1659/1891] update-et translations --- po/et.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/et.po b/po/et.po index 44f2b3a0..4092823b 100644 --- a/po/et.po +++ b/po/et.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Estonian (http://www.transifex.com/lfleischer/aurweb/language/et/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From bce9bedaf460b8efd8c5e2eb9e9cde5da4384f7c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:53 -0800 Subject: [PATCH 1660/1891] update-fi translations --- po/fi.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/fi.po b/po/fi.po index 636681b7..98b3a03b 100644 --- a/po/fi.po +++ b/po/fi.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Elias Autio, 2016 # Jesse Jaara , 2011-2012,2015 @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Nikolay Korotkiy , 2018-2019\n" "Language-Team: Finnish (http://www.transifex.com/lfleischer/aurweb/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 3fa9047864d1a872f20027f26837ac1dfd9c971f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:56 -0800 Subject: [PATCH 1661/1891] update-fi_FI translations --- po/fi_FI.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/fi_FI.po b/po/fi_FI.po index 17a58b4a..cd516edc 100644 --- a/po/fi_FI.po +++ b/po/fi_FI.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Finnish (Finland) (http://www.transifex.com/lfleischer/aurweb/language/fi_FI/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From ff01947f3d260981bfdecf8488b54a9995256a6b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:08:59 -0800 Subject: [PATCH 1662/1891] update-fr translations --- po/fr.po | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/po/fr.po b/po/fr.po index 03192d48..2b0c5bab 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Alexandre Macabies , 2018 # Antoine Lubineau , 2012 @@ -10,7 +10,7 @@ # demostanis , 2020 # Kristien , 2020 # lordheavy , 2011 -# lordheavy , 2013-2014,2018 +# lordheavy , 2013-2014,2018,2022 # lordheavy , 2011-2012 # Lukas Fleischer , 2011 # Thibault , 2020 @@ -18,16 +18,16 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: lordheavy , 2013-2014,2018,2022\n" "Language-Team: French (http://www.transifex.com/lfleischer/aurweb/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: html/404.php msgid "Page Not Found" @@ -1590,6 +1590,7 @@ msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requête en attente" msgstr[1] "%d requêtes en attente" +msgstr[2] "%d requêtes en attente" #: template/pkgbase_actions.php msgid "Adopt Package" @@ -1864,6 +1865,7 @@ msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d paquet demandé trouvé." msgstr[1] "%d paquets demandés trouvés." +msgstr[2] "%d paquets demandés trouvés." #: template/pkgreq_results.php template/pkg_search_results.php #, php-format @@ -1888,6 +1890,7 @@ msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d jour restant" msgstr[1] "~%d jours restants" +msgstr[2] "~%d jours restants" #: template/pkgreq_results.php #, php-format @@ -1895,6 +1898,7 @@ msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d heure restante" msgstr[1] "%d heures restantes" +msgstr[2] "%d heures restantes" #: template/pkgreq_results.php msgid "<1 hour left" @@ -2023,6 +2027,7 @@ msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d paquet trouvé." msgstr[1] "%d paquets trouvés." +msgstr[2] "%d paquets trouvés." #: template/pkg_search_results.php msgid "Version" @@ -2319,7 +2324,7 @@ msgstr "" #: aurweb/asgi.py msgid "Internal Server Error" -msgstr "" +msgstr "Erreur interne du serveur" #: templates/errors/500.html msgid "A fatal error has occurred." From 9385c14f77d18d28ade7e2fa681412133f3daea5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:03 -0800 Subject: [PATCH 1663/1891] update-he translations --- po/he.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/po/he.po b/po/he.po index 936e93a1..88f2fddd 100644 --- a/po/he.po +++ b/po/he.po @@ -1,18 +1,18 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: -# GenghisKhan , 2016 +# gk , 2016 # Lukas Fleischer , 2011 # Yaron Shahrabani , 2016-2022 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Yaron Shahrabani , 2016-2022\n" "Language-Team: Hebrew (http://www.transifex.com/lfleischer/aurweb/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2339,10 +2339,10 @@ msgstr "שגיאת שרת ה־AUR" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "הערות הסגירה התואמות של בקשת החבילה…" #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "פעולה זו תסגור בקשות חבילות ממתינות שקשורות אליה. אם %sתגובות%s מושמטות, תיווצר תגובת סגירה אוטומטית." From b209cd962c25f0f51ea31625b7ede3784407c16c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:06 -0800 Subject: [PATCH 1664/1891] update-hi_IN translations --- po/hi_IN.po | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/po/hi_IN.po b/po/hi_IN.po index 114c9461..1ba83dae 100644 --- a/po/hi_IN.po +++ b/po/hi_IN.po @@ -1,16 +1,16 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: -# Panwar108 , 2018,2020-2021 +# Panwar108 , 2018,2020-2022 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Panwar108 , 2018,2020-2022\n" "Language-Team: Hindi (India) (http://www.transifex.com/lfleischer/aurweb/language/hi_IN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -897,7 +897,7 @@ msgstr "अनुचित उपयोक्ता नाम या कूट #: lib/acctfuncs.inc.php msgid "An error occurred trying to generate a user session." -msgstr "उपयोक्ता सत्र बनाने हेतु त्रुटि।" +msgstr "उपयोक्ता सत्र बनाने समय त्रुटि हुई।" #: lib/acctfuncs.inc.php msgid "Invalid e-mail and reset key combination." @@ -2308,29 +2308,29 @@ msgstr "%s स्वीकारनें हेतु कोई निरर् #: aurweb/asgi.py msgid "Internal Server Error" -msgstr "" +msgstr "आंतरिक सर्वर त्रुटि" #: templates/errors/500.html msgid "A fatal error has occurred." -msgstr "" +msgstr "गंभीर त्रुटि हुई।" #: templates/errors/500.html msgid "" "Details have been logged and will be reviewed by the postmaster posthaste. " "We apologize for any inconvenience this may have caused." -msgstr "" +msgstr "संबंधित सूचना लॉग फाइल में दर्ज की जा चुकी है एवं अतिशीघ्र ही पोस्ट प्रबंधक द्वारा उसकी समीक्षा की जाएगी। इस कारण हुई किसी भी प्रकार की असुविधा हेतु खेद है।" #: aurweb/scripts/notify.py msgid "AUR Server Error" -msgstr "" +msgstr "AUR सर्वर त्रुटि" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "पैकेज अनुरोध समापन संबंधी टिप्पणियाँ..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "इस कार्य द्वारा संबंधित सभी लंबित पैकेज अनुरोध बंद हो जाएँगे। %sटिप्पणियाँ%s न होने की स्थिति में एक समापन टिप्पणी का स्वतः ही सृजन होगा।" From bf348fa5721dd79800d152477e3056d15ff3d0b0 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:09 -0800 Subject: [PATCH 1665/1891] update-hr translations --- po/hr.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/hr.po b/po/hr.po index fe1857c1..a0474e23 100644 --- a/po/hr.po +++ b/po/hr.po @@ -1,16 +1,16 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Lukas Fleischer , 2011\n" "Language-Team: Croatian (http://www.transifex.com/lfleischer/aurweb/language/hr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 5f71e58db16e0f22db0261cf07741d35fd3b79e7 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:13 -0800 Subject: [PATCH 1666/1891] update-hu translations --- po/hu.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/hu.po b/po/hu.po index e6ebd451..7459a716 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Balló György , 2013 # Balló György , 2011,2013-2016 @@ -11,10 +11,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: PB, 2020\n" "Language-Team: Hungarian (http://www.transifex.com/lfleischer/aurweb/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 28e8b312110e917e72505bebc122be61d38a37ee Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:16 -0800 Subject: [PATCH 1667/1891] update-id translations --- po/id.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/id.po b/po/id.po index 103c47e6..96059ac9 100644 --- a/po/id.po +++ b/po/id.po @@ -1,17 +1,17 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # se7entime , 2013 # se7entime , 2016 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: se7entime , 2016\n" "Language-Team: Indonesian (http://www.transifex.com/lfleischer/aurweb/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 3a460faa6e97296cc8b308416c30bda68b13c016 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:19 -0800 Subject: [PATCH 1668/1891] update-id_ID translations --- po/id_ID.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/id_ID.po b/po/id_ID.po index c3acb167..f0612399 100644 --- a/po/id_ID.po +++ b/po/id_ID.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Indonesian (Indonesia) (http://www.transifex.com/lfleischer/aurweb/language/id_ID/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 0d950a0c9fe355f1ccb667181d6313da769f671d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:23 -0800 Subject: [PATCH 1669/1891] update-is translations --- po/is.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/is.po b/po/is.po index aee80ce5..0f3a3fcb 100644 --- a/po/is.po +++ b/po/is.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Icelandic (http://www.transifex.com/lfleischer/aurweb/language/is/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From a12dbd191a9d857f3474c3b8557cb3cd787fb603 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:26 -0800 Subject: [PATCH 1670/1891] update-it translations --- po/it.po | 132 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 63 deletions(-) diff --git a/po/it.po b/po/it.po index f583cb2f..466d486a 100644 --- a/po/it.po +++ b/po/it.po @@ -1,26 +1,27 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Fanfurlio Farolfi , 2021-2022 -# Giovanni Scafora , 2011-2015 +# Giovanni Scafora , 2011-2015,2022 +# Giovanni Scafora , 2022 # Lorenzo Porta , 2014 # Lukas Fleischer , 2011 # mattia_b89 , 2019 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Giovanni Scafora , 2022\n" "Language-Team: Italian (http://www.transifex.com/lfleischer/aurweb/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: it\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: html/404.php msgid "Page Not Found" @@ -41,12 +42,12 @@ msgstr "Le URL per clonare un repository git non sono visualizzabili nel browser #: html/404.php #, php-format msgid "To clone the Git repository of %s, run %s." -msgstr "Per clonare il reposiroty git di %s, esegui %s." +msgstr "Per clonare il repository git di %s, esegui %s." #: html/404.php #, php-format msgid "Click %shere%s to return to the %s details page." -msgstr "Clicca %squi%s per tornare alla pagina dei dettagli di %s." +msgstr "Clicca %squi%s per ritornare alla pagina dei dettagli di %s." #: html/503.php msgid "Service Unavailable" @@ -79,7 +80,7 @@ msgstr "Non hai i permessi necessari per modificare questo account." #: html/account.php lib/acctfuncs.inc.php msgid "Invalid password." -msgstr "Password non valida." +msgstr "La password non è valida." #: html/account.php msgid "Use this form to search existing accounts." @@ -169,7 +170,7 @@ msgstr "Edita il commento" #: html/home.php template/header.php msgid "Dashboard" -msgstr "Cruscotto" +msgstr "Pannello" #: html/home.php template/header.php msgid "Home" @@ -573,7 +574,7 @@ msgstr "Solo i TU e gli sviluppatori possono abbandonare i pacchetti." #: html/pkgflagcomment.php msgid "Flag Comment" -msgstr "Segnala Commento" +msgstr "Segnala il commento" #: html/pkgflag.php msgid "Flag Package Out-Of-Date" @@ -585,7 +586,7 @@ msgid "" " package version in the AUR does not match the most recent commit. Flagging " "this package should only be done if the sources moved or changes in the " "PKGBUILD are required because of recent upstream changes." -msgstr "Questo appare essere un pacchetto da VCS. Per favore %snon%s marcarlo come non aggiornato se la versione in AUR non corrisponde con il commit più recente, Questo pacchetto dovrebbe essere marcato solo se i sorgenti sono stati spostati o se sono necessari dei cambiamenti al PKGBUILD a causa delle recenti modifiche al sorgente." +msgstr "Sembra un pacchetto VCS. Fai %snon%s segnalarlo come non aggiornato, se la versione in AUR non corrisponde con il commit più recente. Questo pacchetto dovrebbe essere segnalato solo se i sorgenti vengono spostati o se sono necessarie delle modifiche al PKGBUILD a causa delle recenti modifiche al sorgente." #: html/pkgflag.php #, php-format @@ -699,12 +700,12 @@ msgstr "Usa questo modulo per creare un account." #: html/tos.php msgid "Terms of Service" -msgstr "Termini del Servizio" +msgstr "Termini di servizio" #: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "I seguenti documenti sono stati aggiornati. Per favore riesaminali correttamente:" +msgstr "I seguenti documenti sono stati aggiornati. Riesaminali attentamente:" #: html/tos.php #, php-format @@ -784,7 +785,7 @@ msgstr "Può contenere solo un punto, un trattino basso o un trattino." #: lib/acctfuncs.inc.php msgid "Please confirm your new password." -msgstr "Per favore conferma la tua nuova password." +msgstr "Conferma la tua nuova password." #: lib/acctfuncs.inc.php msgid "The email address is invalid." @@ -796,7 +797,7 @@ msgstr "L'indirizzo email di scorta non è valido." #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." -msgstr "La homepage non è valida, per favore specificare l'URL HTTP(s) completo." +msgstr "La homepage non è valida, specifica l'URL HTTP(s) completo." #: lib/acctfuncs.inc.php msgid "The PGP key fingerprint is invalid." @@ -816,7 +817,7 @@ msgstr "Lingua attualmente non supportata." #: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." -msgstr "Fuso orario non attualmente supportato." +msgstr "Il fuso orario non è attualmente supportato." #: lib/acctfuncs.inc.php #, php-format @@ -835,15 +836,15 @@ msgstr "La chiave pubblica SSH %s%s%s, è già in uso." #: lib/acctfuncs.inc.php msgid "The CAPTCHA is missing." -msgstr "Manca la risposta CAPTCHA." +msgstr "Manca il CAPTCHA." #: lib/acctfuncs.inc.php msgid "This CAPTCHA has expired. Please try again." -msgstr "Il CAPTCHA è scaduto, Per favore riprova." +msgstr "Il CAPTCHA è scaduto. Riprova." #: lib/acctfuncs.inc.php msgid "The entered CAPTCHA answer is invalid." -msgstr "La risposta CAPTCHA inserita non è valida." +msgstr "Il CAPTCHA inserito non è valido." #: lib/acctfuncs.inc.php #, php-format @@ -885,7 +886,7 @@ msgstr "Account sospeso" #: aurweb/routers/accounts.py msgid "You do not have permission to suspend accounts." -msgstr "Non hai il permesso per sospendere account." +msgstr "Non hai il permesso per sospendere gli account." #: lib/acctfuncs.inc.php #, php-format @@ -946,7 +947,7 @@ msgstr "Manca l'ID del commento." #: lib/pkgbasefuncs.inc.php msgid "No more than 5 comments can be pinned." -msgstr "Non possono essere inseriti più di 5 commenti." +msgstr "Non possono essere evidenziati più di 5 commenti." #: lib/pkgbasefuncs.inc.php msgid "You are not allowed to pin this comment." @@ -958,11 +959,11 @@ msgstr "Non sei autorizzato a rimuovere questo commento." #: lib/pkgbasefuncs.inc.php msgid "Comment has been pinned." -msgstr "Il commento è stato rimosso." +msgstr "Il commento è ora in evidenza." #: lib/pkgbasefuncs.inc.php msgid "Comment has been unpinned." -msgstr "I commenti sono stati rimossi." +msgstr "I commenti non sono più in evidenza." #: lib/pkgbasefuncs.inc.php lib/pkgfuncs.inc.php msgid "Error retrieving package details." @@ -1296,7 +1297,7 @@ msgstr "Modifica l'account di quest'utente" #: template/account_details.php msgid "List this user's comments" -msgstr "Elenca i commenti di quest'utente" +msgstr "Elenca i commenti di questo utente" #: template/account_edit_form.php #, php-format @@ -1306,7 +1307,7 @@ msgstr "Clicca %squi%s se vuoi eliminare definitivamente questo account." #: template/account_edit_form.php #, php-format msgid "Click %shere%s for user details." -msgstr "Click %squì%s per il dettagli dell'utente." +msgstr "Click %squì%s per visualizzare i dettagli dell'utente." #: template/account_edit_form.php #, php-format @@ -1364,7 +1365,7 @@ msgstr "Indirizzo email di scorta" msgid "" "Optionally provide a secondary email address that can be used to restore " "your account in case you lose access to your primary email address." -msgstr "Puoi fornire un secondo indirizzo email che potrà essere usato per ripristinare il tuo account, nel caso tu perda l'accesso al tuo indirizzo email primario." +msgstr "Puoi fornire un secondo indirizzo email che potrà essere usato per ripristinare il tuo account, nel caso tu perdessi l'accesso al tuo indirizzo email primario." #: template/account_edit_form.php msgid "" @@ -1391,7 +1392,7 @@ msgstr "Fuso orario" msgid "" "If you want to change the password, enter a new password and confirm the new" " password by entering it again." -msgstr "Se vuoi cambiare la tua password, inseriscine una nuova e confermala inserendola di nuovo." +msgstr "Se vuoi cambiare la tua password, inseriscine una nuova e confermala digitandola di nuovo." #: template/account_edit_form.php msgid "Re-type password" @@ -1409,7 +1410,7 @@ msgstr "Chiave pubblica SSH" #: template/account_edit_form.php msgid "Notification settings" -msgstr "Impostazioni notifiche" +msgstr "Impostazioni delle notifiche" #: template/account_edit_form.php msgid "Notify of new comments" @@ -1421,11 +1422,11 @@ msgstr "Notifica degli aggiornamenti dei pacchetti" #: template/account_edit_form.php msgid "Notify of ownership changes" -msgstr "Notifica cambiamenti di proprietà" +msgstr "Notifica dei cambiamenti di proprietà" #: template/account_edit_form.php msgid "To confirm the profile changes, please enter your current password:" -msgstr "Per confermare le modifiche al profilo, per favore inserisci la tua password:" +msgstr "Per confermare le modifiche al profilo, inserisci la tua password:" #: template/account_edit_form.php msgid "Your current password" @@ -1499,7 +1500,7 @@ msgstr "Salva" #: template/flag_comment.php #, php-format msgid "Flagged Out-of-Date Comment: %s" -msgstr "Commento per la marcatura come Non Aggiornato: %s" +msgstr "Commento per la segnalazione come Non Aggiornato: %s" #: template/flag_comment.php #, php-format @@ -1513,7 +1514,7 @@ msgstr "%s%s%s non è segnalato come non aggiornato." #: template/flag_comment.php msgid "Return to Details" -msgstr "Ritorna ai Dettagli" +msgstr "Ritorna ai dettagli" #: template/footer.php #, php-format @@ -1583,6 +1584,7 @@ msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d richiesta in attesa" msgstr[1] "%d richieste in attesa" +msgstr[2] "%d richieste in attesa" #: template/pkgbase_actions.php msgid "Adopt Package" @@ -1654,7 +1656,7 @@ msgstr "Aggiungi un commento" msgid "" "Git commit identifiers referencing commits in the AUR package repository and" " URLs are converted to links automatically." -msgstr "Gli identificatori dei commit Git nel repository dei pacchetti AUR e le URL vengono convertite automaticamente in link." +msgstr "Gli identificatori dei commit Git nel repository dei pacchetti AUR e le URL vengono convertiti automaticamente in link." #: template/pkg_comment_form.php #, php-format @@ -1663,7 +1665,7 @@ msgstr "La %ssintassi Markdown%s è parzialmente supportata." #: template/pkg_comments.php msgid "Pinned Comments" -msgstr "Elimina i commenti" +msgstr "Commenti in evidenza" #: template/pkg_comments.php msgid "Latest Comments" @@ -1676,7 +1678,7 @@ msgstr "Commenti per" #: template/pkg_comments.php #, php-format msgid "%s commented on %s" -msgstr "%s ha commentato su %s" +msgstr "%s ha commentato il %s" #: template/pkg_comments.php #, php-format @@ -1686,27 +1688,27 @@ msgstr "Commento anonimo su %s" #: template/pkg_comments.php #, php-format msgid "Commented on package %s on %s" -msgstr "Ha commentato sul pacchetto %s su %s" +msgstr "Ha commentato sul pacchetto %s il %s" #: template/pkg_comments.php #, php-format msgid "deleted on %s by %s" -msgstr "Eliminato su %s da %s" +msgstr "eliminato il %s da %s" #: template/pkg_comments.php #, php-format msgid "deleted on %s" -msgstr "cancellato su %s" +msgstr "eliminato il %s" #: template/pkg_comments.php #, php-format msgid "edited on %s by %s" -msgstr "modificato su %s da %s" +msgstr "modificato il %s da %s" #: template/pkg_comments.php #, php-format msgid "edited on %s" -msgstr "modificato su %s" +msgstr "modificato il %s" #: template/pkg_comments.php msgid "Undelete comment" @@ -1829,7 +1831,7 @@ msgid "" "By submitting a deletion request, you ask a Trusted User to delete the " "package base. This type of request should be used for duplicates, software " "abandoned by upstream, as well as illegal and irreparably broken packages." -msgstr "Inserendo una richiesta di cancellazione, stai chiedendo ad un Trusted User di cancellare il pacchetto base. Questo tipo di richiesta dovrebbe essere usato per duplicati, software abbandonati dall'autore, sotware illegalmente distribuiti o pacchetti irreparabili." +msgstr "Inserendo una richiesta di cancellazione, stai chiedendo ad un Trusted User di cancellare il pacchetto base. Questo tipo di richiesta dovrebbe essere usata per i duplicati, per software abbandonati dall'autore, per sotware illegalmente distribuiti oppure per pacchetti irreparabili." #: template/pkgreq_form.php msgid "" @@ -1845,7 +1847,7 @@ msgid "" "package base. Please only do this if the package needs maintainer action, " "the maintainer is MIA and you already tried to contact the maintainer " "previously." -msgstr "Inserendo una richiesta di abbandono, stai chiedendo ad un Trusted User di rimuovere la proprietà del pacchetto base. Per favore procedi soltanto se il pacchetto necessita di manutenzione, il manutentore attuale non risponde, e hai già provato a contattarlo precedentemente." +msgstr "Inserendo una richiesta di abbandono, stai chiedendo ad un Trusted User di rimuovere la proprietà del pacchetto base. Procedi soltanto se il pacchetto necessita di manutenzione, se il manutentore attuale non risponde e se hai già provato a contattarlo precedentemente." #: template/pkgreq_results.php msgid "No requests matched your search criteria." @@ -1857,6 +1859,7 @@ msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." +msgstr[2] "Sono stati trovati %d pacchetti." #: template/pkgreq_results.php template/pkg_search_results.php #, php-format @@ -1881,6 +1884,7 @@ msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d giorno rimanente" msgstr[1] "~%d giorni rimanenti" +msgstr[2] "~%d giorni rimanenti" #: template/pkgreq_results.php #, php-format @@ -1888,6 +1892,7 @@ msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d ora rimanente" msgstr[1] "~%d ore rimanenti" +msgstr[2] "~%d ore rimanenti" #: template/pkgreq_results.php msgid "<1 hour left" @@ -2016,6 +2021,7 @@ msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "È stato trovato %d pacchetto." msgstr[1] "Sono stati trovati %d pacchetti." +msgstr[2] "Sono stati trovati %d pacchetti." #: template/pkg_search_results.php msgid "Version" @@ -2026,7 +2032,7 @@ msgstr "Versione" msgid "" "Popularity is calculated as the sum of all votes with each vote being " "weighted with a factor of %.2f per day since its creation." -msgstr "La popolarità è calcolata come somma di tutti i voti pesati con un fattore di %.2f al giorno, dalla sua creazione." +msgstr "La popolarità è calcolata come somma di tutti i voti ponderati con un fattore di %.2f al giorno dalla sua creazione." #: template/pkg_search_results.php template/tu_details.php #: template/tu_list.php @@ -2172,7 +2178,7 @@ msgstr "Precedente" #: scripts/notify.py msgid "AUR Password Reset" -msgstr "Ripristino Password di AUR" +msgstr "Ripristino della password di AUR" #: scripts/notify.py #, python-brace-format @@ -2180,18 +2186,18 @@ msgid "" "A password reset request was submitted for the account {user} associated " "with your email address. If you wish to reset your password follow the link " "[1] below, otherwise ignore this message and nothing will happen." -msgstr "È stata inviata una richiesta per ripristinare la password dell'account {user} associato al tuo indirizzo e-mail. Se desideri ripristinare la tua password, clicca sul link [1] sottostante, altrimenti ignora questo messaggio e non succederà nulla." +msgstr "È stata inviata una richiesta per ripristinare la password dell'account {user} associato al tuo indirizzo email. Se desideri ripristinare la tua password, clicca sul link [1] sottostante, altrimenti ignora questo messaggio e non succederà nulla." #: scripts/notify.py msgid "Welcome to the Arch User Repository" -msgstr "Benvenuto nel Arch User Repository" +msgstr "Benvenuto nell' Arch User Repository" #: scripts/notify.py msgid "" "Welcome to the Arch User Repository! In order to set an initial password for" " your new account, please click the link [1] below. If the link does not " "work, try copying and pasting it into your browser." -msgstr "Benvenuto nel Arch User Repository! Per impostare una password iniziale per il tuo nuovo account, per favore segui il collegamento [1] sottostante. Se il collegamento non funziona, prova a copiarlo e incollarlo nel tuo browser." +msgstr "Benvenuto nell' Arch User Repository! Per impostare una password iniziale per il tuo nuovo account, clicca sul link [1] sottostante. Se il link non funzionasse, prova a copiarlo e ad incollarlo nella barra degli indirizzi del tuo browser." #: scripts/notify.py #, python-brace-format @@ -2208,12 +2214,12 @@ msgstr "{user} [1] ha commentato su {pkgbase} [2]:" msgid "" "If you no longer wish to receive notifications about this package, please go" " to the package page [2] and select \"{label}\"." -msgstr "Se non vuoi più ricevere notifiche su questo pacchetto, per favore vai alla pagina del pacchetto [2] e seleziona \"{label}\"." +msgstr "Se non vuoi più ricevere notifiche su questo pacchetto, vai alla pagina del pacchetto [2] e seleziona \"{label}\"." #: scripts/notify.py #, python-brace-format msgid "AUR Package Update: {pkgbase}" -msgstr "Aggiornamento pachetto base: {pkgbase}" +msgstr "Aggiornamento del pacchetto base: {pkgbase}" #: scripts/notify.py #, python-brace-format @@ -2223,7 +2229,7 @@ msgstr "{user} [1] ha inviato un nuovo commit su {pkgbase} [2]." #: scripts/notify.py #, python-brace-format msgid "AUR Out-of-date Notification for {pkgbase}" -msgstr "Notifica AUR per pacchetto {pkgbase} non aggiornato" +msgstr "Notifica AUR per il pacchetto {pkgbase} non aggiornato" #: scripts/notify.py #, python-brace-format @@ -2233,7 +2239,7 @@ msgstr "Il tuo pacchetto {pkgbase} [1] è stato marcato come non aggiornato dall #: scripts/notify.py #, python-brace-format msgid "AUR Ownership Notification for {pkgbase}" -msgstr "Notifica AUR di proprietà per pacchetto {pkgbase} " +msgstr "Notifica AUR di proprietà del pacchetto {pkgbase} " #: scripts/notify.py #, python-brace-format @@ -2248,7 +2254,7 @@ msgstr "Il pacchetto {pkgbase} [1] è stato abbandonato da {user} [2]." #: scripts/notify.py #, python-brace-format msgid "AUR Co-Maintainer Notification for {pkgbase}" -msgstr "Notifica AUR di co-manutenzione per pacchetto {pkgbase} " +msgstr "Notifica AUR di co-manutenzione per il pacchetto {pkgbase} " #: scripts/notify.py #, python-brace-format @@ -2272,7 +2278,7 @@ msgid "" "\n" "-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "{user} [1] ha unito {old} [2] in {new} [3].\n\n-- \nSe non vuoi più ricevere notifiche sul nuovo pacchetto, per favore vai a [3] e clicca su \"{label}\"." +msgstr "{user} [1] ha unito {old} [2] in {new} [3].\n\n-- \nSe non desideri più ricevere notifiche sul nuovo pacchetto, vai a [3] e clicca su \"{label}\"." #: scripts/notify.py #, python-brace-format @@ -2280,7 +2286,7 @@ msgid "" "{user} [1] deleted {pkgbase} [2].\n" "\n" "You will no longer receive notifications about this package." -msgstr "{user} [1] ha eliminato {pkgbase} [2].\n\nNon riceverai più notifiche su questo pacchetto." +msgstr "{user} [1] ha eliminato {pkgbase} [2].\n\nNon riceverai più notifiche per questo pacchetto." #: scripts/notify.py #, python-brace-format @@ -2292,19 +2298,19 @@ msgstr "Promemoria per voto TU: Proposta {id}" msgid "" "Please remember to cast your vote on proposal {id} [1]. The voting period " "ends in less than 48 hours." -msgstr "Per favore ricordati di votare sulla proposta {id} [1]. La finestra di voto si chiude fra meno di 48 ore." +msgstr "Ricordati di votare la proposta di {id} [1]. La finestra di voto si chiude fra meno di 48 ore." #: aurweb/routers/accounts.py msgid "Invalid account type provided." -msgstr "Tipo di account non valido." +msgstr "L' account fornito non è valido." #: aurweb/routers/accounts.py msgid "You do not have permission to change account types." -msgstr "Non hai il permesso per cambiare il tipo di account." +msgstr "Non hai il permesso per modificare il tipo di account." #: aurweb/routers/accounts.py msgid "You do not have permission to change this user's account type to %s." -msgstr "Non hai il permesso per cambiare il tipo di account di questo utente in %s." +msgstr "Non hai il permesso per modificare il tipo di account di questo utente in %s." #: aurweb/packages/requests.py msgid "No due existing orphan requests to accept for %s." @@ -2322,19 +2328,19 @@ msgstr "Si è verificato un errore irreversibile." msgid "" "Details have been logged and will be reviewed by the postmaster posthaste. " "We apologize for any inconvenience this may have caused." -msgstr "I dettagli sono stati registrati e verranno visionati da postmaster velocemente. Ci scusiamo per l'inconvenienza che questo possa aver causato." +msgstr "I dettagli sono stati registrati e verranno visionati al più presto dal postmaster. Ci scusiamo per gli eventuali disagi causati." #: aurweb/scripts/notify.py msgid "AUR Server Error" -msgstr "Errore server AUR" +msgstr "Errore del server di AUR" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "Commenti relativi alla richiesta di chiusura del pacchetto..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Questa azione chiuderà tutte le richieste in sospeso dei pacchetti ad essa correlate. Se %scommenti%s vengono omessi, verrà generato automaticamente un commento di chiusura." From 08af8cad8d2c085770633a11198e4acd7a2774f1 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:29 -0800 Subject: [PATCH 1671/1891] update-ja translations --- po/ja.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/po/ja.po b/po/ja.po index 280edb46..40349f28 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # kusakata, 2013 # kusakata, 2013 @@ -10,10 +10,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: kusakata, 2013-2018,2020-2022\n" "Language-Team: Japanese (http://www.transifex.com/lfleischer/aurweb/language/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2325,10 +2325,10 @@ msgstr "AUR サーバーエラー" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "関連するパッケージリクエストの取り消しコメント..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "このアクションは関連するパッケージリクエストをすべて取り消します。%sコメント%sを省略した場合、自動的にコメントが生成されます。" From e6d36101d9f26f7e71570bd02961b3ed3a21fa3c Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:33 -0800 Subject: [PATCH 1672/1891] update-ko translations --- po/ko.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ko.po b/po/ko.po index 6da57759..a4c694c9 100644 --- a/po/ko.po +++ b/po/ko.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Korean (http://www.transifex.com/lfleischer/aurweb/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From e5137e0c4297a82bfe420228a38465fb396a34eb Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:36 -0800 Subject: [PATCH 1673/1891] update-lt translations --- po/lt.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/lt.po b/po/lt.po index c9f55632..627fefd0 100644 --- a/po/lt.po +++ b/po/lt.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Lithuanian (http://www.transifex.com/lfleischer/aurweb/language/lt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From d20dbbcf7419c8b76eb338384467172db4af9189 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:39 -0800 Subject: [PATCH 1674/1891] update-nb translations --- po/nb.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/nb.po b/po/nb.po index 307a80d6..b503de85 100644 --- a/po/nb.po +++ b/po/nb.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Alexander F. Rødseth , 2015,2017-2019 # Alexander F. Rødseth , 2011,2013-2014 @@ -12,10 +12,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Alexander F. Rødseth , 2015,2017-2019\n" "Language-Team: Norwegian Bokmål (http://www.transifex.com/lfleischer/aurweb/language/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 57a2b4b516a43a33182399b8fdaa4473cfa91e6f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:43 -0800 Subject: [PATCH 1675/1891] update-nb_NO translations --- po/nb_NO.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/nb_NO.po b/po/nb_NO.po index 5d958172..49d2eccf 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -1,17 +1,17 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Kim Nordmo , 2017,2019 # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Kim Nordmo , 2017,2019\n" "Language-Team: Norwegian Bokmål (Norway) (http://www.transifex.com/lfleischer/aurweb/language/nb_NO/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 05c6266986ac6652a1755a89f229427195a7305d Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:46 -0800 Subject: [PATCH 1676/1891] update-nl translations --- po/nl.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/po/nl.po b/po/nl.po index 54519d21..d23fe04a 100644 --- a/po/nl.po +++ b/po/nl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Heimen Stoffels , 2021-2022 # Heimen Stoffels , 2015,2021 @@ -13,10 +13,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Heimen Stoffels , 2021-2022\n" "Language-Team: Dutch (http://www.transifex.com/lfleischer/aurweb/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2333,10 +2333,10 @@ msgstr "AUR-serverfout" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "Gerelateerde pakketverzoekreacties…" #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Met deze actie sluit u elk gerelateerd openstaand verzoek. Als %s reacties%s genegeerd worden, dan wordt er een automatische afsluitreactie geplaatst." From e572b86fd3d2acf041c0882ba669ad6a5bcfac0f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:50 -0800 Subject: [PATCH 1677/1891] update-pl translations --- po/pl.po | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/po/pl.po b/po/pl.po index 94a6fb67..97c7d730 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Bartłomiej Piotrowski , 2011 # Bartłomiej Piotrowski , 2014 @@ -13,16 +13,16 @@ # marcin mikołajczak , 2017 # Michal T , 2016 # Nuc1eoN , 2014 -# Piotr Strębski , 2017-2018 +# Piotr Strębski , 2017-2018,2022 # Piotr Strębski , 2013-2016 # Przemyslaw Ka. , 2021 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Piotr Strębski , 2017-2018,2022\n" "Language-Team: Polish (http://www.transifex.com/lfleischer/aurweb/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -712,7 +712,7 @@ msgstr "Zasady korzystania" #: html/tos.php msgid "" "The following documents have been updated. Please review them carefully:" -msgstr "" +msgstr "Zaktualizowano następujące dokumenty. Przejrzyj je dokładnie:" #: html/tos.php #, php-format @@ -792,7 +792,7 @@ msgstr "Może zawierać tylko jedną kropkę, podkreślnik lub myślnik." #: lib/acctfuncs.inc.php msgid "Please confirm your new password." -msgstr "" +msgstr "Potwierdź nowe hasło." #: lib/acctfuncs.inc.php msgid "The email address is invalid." @@ -800,7 +800,7 @@ msgstr "Adres e-mail jest nieprawidłowy." #: lib/acctfuncs.inc.php msgid "The backup email address is invalid." -msgstr "" +msgstr "Zapasowy adres e-mail jest nieprawidłowy." #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." @@ -824,7 +824,7 @@ msgstr "Język nie jest obecnie obsługiwany." #: lib/acctfuncs.inc.php msgid "Timezone is not currently supported." -msgstr "" +msgstr "Strefa czasowa nie jest obecnie obsługiwana." #: lib/acctfuncs.inc.php #, php-format From 6ee7598211d5358cf94bf4b8936f486b439add45 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:53 -0800 Subject: [PATCH 1678/1891] update-pt translations --- po/pt.po | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/po/pt.po b/po/pt.po index aed32031..05778859 100644 --- a/po/pt.po +++ b/po/pt.po @@ -1,22 +1,22 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Lukas Fleischer , 2011\n" "Language-Team: Portuguese (http://www.transifex.com/lfleischer/aurweb/language/pt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: html/404.php msgid "Page Not Found" @@ -1579,6 +1579,7 @@ msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "" msgstr[1] "" +msgstr[2] "" #: template/pkgbase_actions.php msgid "Adopt Package" @@ -1853,6 +1854,7 @@ msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "" msgstr[1] "" +msgstr[2] "" #: template/pkgreq_results.php template/pkg_search_results.php #, php-format @@ -1877,6 +1879,7 @@ msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +msgstr[2] "" #: template/pkgreq_results.php #, php-format @@ -1884,6 +1887,7 @@ msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +msgstr[2] "" #: template/pkgreq_results.php msgid "<1 hour left" @@ -2012,6 +2016,7 @@ msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "" msgstr[1] "" +msgstr[2] "" #: template/pkg_search_results.php msgid "Version" From bb00a4ecfde887741f1bab5b8f71e902e5fee252 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:09:56 -0800 Subject: [PATCH 1679/1891] update-pt_BR translations --- po/pt_BR.po | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/po/pt_BR.po b/po/pt_BR.po index d29a9448..6bc6a596 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Albino Biasutti Neto Bino , 2011 # Fábio Nogueira , 2016 @@ -13,16 +13,16 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Rafael Fontenelle , 2011,2015-2018,2020-2022\n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/lfleischer/aurweb/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: html/404.php msgid "Page Not Found" @@ -1585,6 +1585,7 @@ msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d requisição pendente" msgstr[1] "%d requisições pendentes" +msgstr[2] "%d requisições pendentes" #: template/pkgbase_actions.php msgid "Adopt Package" @@ -1859,6 +1860,7 @@ msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d requisição de pacote encontrada." msgstr[1] "%d requisições de pacotes encontradas." +msgstr[2] "%d requisições de pacotes encontradas." #: template/pkgreq_results.php template/pkg_search_results.php #, php-format @@ -1883,6 +1885,7 @@ msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "~%d dia restante" msgstr[1] "~%d dias restantes" +msgstr[2] "~%d dias restantes" #: template/pkgreq_results.php #, php-format @@ -1890,6 +1893,7 @@ msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "~%d hora restante" msgstr[1] "~%d horas restantes" +msgstr[2] "~%d horas restantes" #: template/pkgreq_results.php msgid "<1 hour left" @@ -2018,6 +2022,7 @@ msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." +msgstr[2] "%d pacotes encontrados." #: template/pkg_search_results.php msgid "Version" @@ -2333,10 +2338,10 @@ msgstr "Erro do Servidor AUR" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "Comentários relacionados ao fechamento de requisição de pacote..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Esta ação fechará todas as requisições de pacote pendentes relacionadas a ela. Se %sComentários%s for omitido, um comentário de encerramento será gerado automaticamente." From e7bcf2fc9786afcb761e98ec5d6cde0b6efa9396 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:00 -0800 Subject: [PATCH 1680/1891] update-pt_PT translations --- po/pt_PT.po | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/po/pt_PT.po b/po/pt_PT.po index 7f6ea67a..5d2ff7de 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Christophe Silva , 2018 # Gaspar Santos , 2011 @@ -12,16 +12,16 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Christophe Silva , 2018\n" "Language-Team: Portuguese (Portugal) (http://www.transifex.com/lfleischer/aurweb/language/pt_PT/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_PT\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" #: html/404.php msgid "Page Not Found" @@ -1584,6 +1584,7 @@ msgid "%d pending request" msgid_plural "%d pending requests" msgstr[0] "%d pedido por atender" msgstr[1] "%d pedidos por atender" +msgstr[2] "%d pedidos por atender" #: template/pkgbase_actions.php msgid "Adopt Package" @@ -1858,6 +1859,7 @@ msgid "%d package request found." msgid_plural "%d package requests found." msgstr[0] "%d pedido de pacote encontrado." msgstr[1] "%d pedidos de pacotes encontrados." +msgstr[2] "%d pedidos de pacotes encontrados." #: template/pkgreq_results.php template/pkg_search_results.php #, php-format @@ -1882,6 +1884,7 @@ msgid "~%d day left" msgid_plural "~%d days left" msgstr[0] "" msgstr[1] "" +msgstr[2] "" #: template/pkgreq_results.php #, php-format @@ -1889,6 +1892,7 @@ msgid "~%d hour left" msgid_plural "~%d hours left" msgstr[0] "" msgstr[1] "" +msgstr[2] "" #: template/pkgreq_results.php msgid "<1 hour left" @@ -2017,6 +2021,7 @@ msgid "%d package found." msgid_plural "%d packages found." msgstr[0] "%d pacote encontrado." msgstr[1] "%d pacotes encontrados." +msgstr[2] "%d pacotes encontrados." #: template/pkg_search_results.php msgid "Version" From fa20a3b5d81cd7554da6b1cd1ca52ddb76681b43 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:03 -0800 Subject: [PATCH 1681/1891] update-ro translations --- po/ro.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ro.po b/po/ro.po index 4409b698..ecee97fd 100644 --- a/po/ro.po +++ b/po/ro.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Arthur Țițeică , 2013-2015 # Lukas Fleischer , 2011 @@ -9,10 +9,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Arthur Țițeică , 2013-2015\n" "Language-Team: Romanian (http://www.transifex.com/lfleischer/aurweb/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From ebae0d43045de2f38a2b9e09d7e847b044fc05f9 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:06 -0800 Subject: [PATCH 1682/1891] update-ru translations --- po/ru.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ru.po b/po/ru.po index 44f000dd..4a8a18f7 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Alex , 2021 # Evgeniy Alekseev , 2014-2015 @@ -18,10 +18,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Kevin Morris , 2021\n" "Language-Team: Russian (http://www.transifex.com/lfleischer/aurweb/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 8ee843b7b1f00e18b42f43984bf57b8d35dad695 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:10 -0800 Subject: [PATCH 1683/1891] update-sk translations --- po/sk.po | 62 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/po/sk.po b/po/sk.po index 853fc198..ca124981 100644 --- a/po/sk.po +++ b/po/sk.po @@ -1,18 +1,18 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # archetyp , 2013-2016 -# Jose Riha , 2018 +# Jose Riha , 2018,2022 # Matej Ľach , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Jose Riha , 2018,2022\n" "Language-Team: Slovak (http://www.transifex.com/lfleischer/aurweb/language/sk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,7 +77,7 @@ msgstr "Nemáte potrebné oprávnenia, pre úpravu tohoto účtu. " #: html/account.php lib/acctfuncs.inc.php msgid "Invalid password." -msgstr "" +msgstr "Neplatné heslo." #: html/account.php msgid "Use this form to search existing accounts." @@ -167,7 +167,7 @@ msgstr "Editovať komentár" #: html/home.php template/header.php msgid "Dashboard" -msgstr "" +msgstr "Nástenka" #: html/home.php template/header.php msgid "Home" @@ -175,11 +175,11 @@ msgstr "Domov" #: html/home.php msgid "My Flagged Packages" -msgstr "" +msgstr "Moje označené balíčky" #: html/home.php msgid "My Requests" -msgstr "" +msgstr "Moje požiadavky" #: html/home.php msgid "My Packages" @@ -187,15 +187,15 @@ msgstr "Moje balíčky" #: html/home.php msgid "Search for packages I maintain" -msgstr "" +msgstr "Hľadať balíčky, ktoré spravujem" #: html/home.php msgid "Co-Maintained Packages" -msgstr "" +msgstr "Spoločne spravované balíčky" #: html/home.php msgid "Search for packages I co-maintain" -msgstr "" +msgstr "Hľadať balíčky, v ktorých pôsobím ako spolupracovník" #: html/home.php #, php-format @@ -239,7 +239,7 @@ msgstr "Podpora" #: html/home.php msgid "Package Requests" -msgstr "Žiadosti ohľadom balíčkov" +msgstr "Žiadosti týkajúce sa balíčkov" #: html/home.php #, php-format @@ -325,7 +325,7 @@ msgid "" "our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface" " %sonly%s. To report packaging bugs contact the package maintainer or leave " "a comment on the appropriate package page." -msgstr "Ak nájdete chybu vo webovom rozhradní AUR, pošlite prosím správu o chybe na náš %sbug tracker%s. Posielajte sem %slen%s chyby webového rozhrania AUR. Pre nahlásenie chýb balíčkov kontaktujte správcu balíčka alebo zanechate komentár na príslušnej stránke balíčka." +msgstr "Ak nájdete chybu vo webovom rozhraní AUR, pošlite prosím správu o chybe na náš %sbug tracker%s. Posielajte sem %slen%s chyby webového rozhrania AUR. Pre nahlásenie chýb balíčkov kontaktujte správcu balíčka alebo zanechate komentár na príslušnej stránke balíčka." #: html/home.php msgid "Package Search" @@ -374,7 +374,7 @@ msgstr "Zadajte prihlasovacie údaje" #: html/login.php msgid "User name or primary email address" -msgstr "" +msgstr "Meno používateľa alebo primárna e-mailová adresa" #: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" @@ -438,7 +438,7 @@ msgstr "Heslo bolo úspešne obnovené." #: html/passreset.php msgid "Confirm your user name or primary e-mail address:" -msgstr "" +msgstr "Potvrďte vaše meno používateľa alebo primárnu e-mailovú adresu:" #: html/passreset.php msgid "Enter your new password:" @@ -707,7 +707,7 @@ msgstr "" #: html/tos.php #, php-format msgid "revision %d" -msgstr "" +msgstr "revízia: %d" #: html/tos.php msgid "I accept the terms and conditions above." @@ -790,7 +790,7 @@ msgstr "E-mailová adresa nie je platná." #: lib/acctfuncs.inc.php msgid "The backup email address is invalid." -msgstr "" +msgstr "Záložná e-mailová adresa nie je platná." #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." @@ -1256,7 +1256,7 @@ msgstr "PGP otlačok kľúča" #: template/account_details.php template/account_search_results.php #: template/pkgreq_results.php msgid "Status" -msgstr "Status" +msgstr "Stav" #: template/account_details.php msgid "Inactive since" @@ -1520,7 +1520,7 @@ msgstr "Copyright %s 2004-%d aurweb Development Team." #: template/header.php msgid " My Account" -msgstr "Môj účet" +msgstr " Môj účet" #: template/pkgbase_actions.php msgid "Package Actions" @@ -1814,7 +1814,7 @@ msgstr "Typ žiadosti" #: template/pkgreq_form.php msgid "Deletion" -msgstr "Vymazanie" +msgstr "Vymazať" #: template/pkgreq_form.php msgid "Orphan" @@ -1855,10 +1855,10 @@ msgstr "" #, php-format msgid "%d package request found." msgid_plural "%d package requests found." -msgstr[0] "Bola nájdená %d požiadavka ohľadom balíčkov." -msgstr[1] "Boli nájdené %d požiadavky ohľadom balíčkov." -msgstr[2] "Bolo nájdených %d požiadaviek ohľadom balíčkov." -msgstr[3] "Bolo nájdených %d požiadaviek ohľadom balíčkov." +msgstr[0] "Bola nájdená %d požiadavka týkajúc sa balíčka." +msgstr[1] "Boli nájdené %d požiadavky týkajúcich sa balíčkov." +msgstr[2] "Bolo nájdených %d požiadaviek týkajúcich sa balíčkov." +msgstr[3] "Bolo nájdených %d požiadaviek týkajúcich sa balíčkov." #: template/pkgreq_results.php template/pkg_search_results.php #, php-format @@ -1986,7 +1986,7 @@ msgstr "Vyhľadávať podľa" #: template/pkg_search_form.php template/stats/user_table.php msgid "Out of Date" -msgstr "Neaktuálny" +msgstr "Neaktuálne" #: template/pkg_search_form.php template/search_accounts_form.php msgid "Sort by" @@ -2216,7 +2216,7 @@ msgstr "" msgid "" "If you no longer wish to receive notifications about this package, please go" " to the package page [2] and select \"{label}\"." -msgstr "" +msgstr "Ak si už viac neželáte dostávať upozornenia na tento balíček, prejdite prosím na stránku balíčku [2] a vyberte \"{label}\"." #: scripts/notify.py #, python-brace-format @@ -2280,7 +2280,7 @@ msgid "" "\n" "-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "" +msgstr "{user} [1] zlúčil(a) {old} [2] do {new} [3].\n\n-- \nAk si už viac neželáte dostávať upozornenia na tento balíček, prejdite prosím na stránku balíčku [2] a vyberte \"{label}\"." #: scripts/notify.py #, python-brace-format @@ -2288,7 +2288,7 @@ msgid "" "{user} [1] deleted {pkgbase} [2].\n" "\n" "You will no longer receive notifications about this package." -msgstr "" +msgstr "{user} [1] odstránil(a) {pkgbase} [2].\n\nUpozornenia na tento balíček už viac nebudete dostávať." #: scripts/notify.py #, python-brace-format @@ -2339,10 +2339,10 @@ msgstr "" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "Súvisiace komentáre k žiadosti o uzatvorenie balíčka..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Táto operácia uzavrie všetky súvisiace nevybavené žiadosti balíčkov. Ak %sComments%s vynecháte, použije sa automaticky generovaný komentár." From 46c925bc82722c35c7a0d55c5135e4174c8ec94f Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:13 -0800 Subject: [PATCH 1684/1891] update-sr translations --- po/sr.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/sr.po b/po/sr.po index 426ce599..4054d7df 100644 --- a/po/sr.po +++ b/po/sr.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 # Slobodan Terzić , 2011-2012,2015-2017 @@ -9,10 +9,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Slobodan Terzić , 2011-2012,2015-2017\n" "Language-Team: Serbian (http://www.transifex.com/lfleischer/aurweb/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 8592bada16bec50a167b5c81ede867d5c8bc7b43 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:17 -0800 Subject: [PATCH 1685/1891] update-sr_RS translations --- po/sr_RS.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/sr_RS.po b/po/sr_RS.po index b7560965..a924dc4c 100644 --- a/po/sr_RS.po +++ b/po/sr_RS.po @@ -1,16 +1,16 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Nikola Stojković , 2013 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Nikola Stojković , 2013\n" "Language-Team: Serbian (Serbia) (http://www.transifex.com/lfleischer/aurweb/language/sr_RS/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 5609ddf791192a1d4b2d9a37b4af6d68b78b2839 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:20 -0800 Subject: [PATCH 1686/1891] update-sv_SE translations --- po/sv_SE.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/sv_SE.po b/po/sv_SE.po index 4887fdde..6abb8452 100644 --- a/po/sv_SE.po +++ b/po/sv_SE.po @@ -1,7 +1,7 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Johannes Löthberg , 2015-2016 # Kevin Morris , 2022 From b36cbd526b7cd6203401f30e11a3f6715725b9b5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:23 -0800 Subject: [PATCH 1687/1891] update-tr translations --- po/tr.po | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/po/tr.po b/po/tr.po index 559a0008..b36c04f4 100644 --- a/po/tr.po +++ b/po/tr.po @@ -1,11 +1,11 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # tarakbumba , 2011,2013-2015 # tarakbumba , 2012,2014 -# Demiray Muhterem , 2015,2020-2021 +# Demiray Muhterem , 2015,2020-2022 # Koray Biçer , 2020 # Lukas Fleischer , 2011 # Samed Beyribey , 2012 @@ -15,10 +15,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Demiray Muhterem , 2015,2020-2022\n" "Language-Team: Turkish (http://www.transifex.com/lfleischer/aurweb/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2316,29 +2316,29 @@ msgstr "%s için kabul edilecek sahipsize gereksinim yok." #: aurweb/asgi.py msgid "Internal Server Error" -msgstr "" +msgstr "İç Sunucu Hatası" #: templates/errors/500.html msgid "A fatal error has occurred." -msgstr "" +msgstr "Önemli bir hata oluştu." #: templates/errors/500.html msgid "" "Details have been logged and will be reviewed by the postmaster posthaste. " "We apologize for any inconvenience this may have caused." -msgstr "" +msgstr "Ayrıntılar günlüğe kaydedildi ve posta yöneticisi tarafından gözden geçirilecek. Bunun neden olabileceği rahatsızlıktan dolayı özür dileriz." #: aurweb/scripts/notify.py msgid "AUR Server Error" -msgstr "" +msgstr "AUR Sunucu Hatası" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "İlgili paket isteği kapatma yorumları..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Bu eylem, kendisiyle ilgili bekleyen paket isteklerini kapatacaktır. %s Yorum %s atlanırsa, bir kapatma yorumu otomatik olarak oluşturulur." From 4cff1e500bd3491947a90b4559d7eac40e1f24fc Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:27 -0800 Subject: [PATCH 1688/1891] update-uk translations --- po/uk.po | 110 +++++++++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/po/uk.po b/po/uk.po index 3bffe4f6..13f3ab90 100644 --- a/po/uk.po +++ b/po/uk.po @@ -1,21 +1,21 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Lukas Fleischer , 2011 # Rax Garfield , 2012 # Rax Garfield , 2012 # Vladislav Glinsky , 2019 -# Yarema aka Knedlyk , 2011-2018 +# Yarema aka Knedlyk , 2011-2018,2022 # Данило Коростіль , 2011 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Yarema aka Knedlyk , 2011-2018,2022\n" "Language-Team: Ukrainian (http://www.transifex.com/lfleischer/aurweb/language/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -80,7 +80,7 @@ msgstr "У вас недостатньо прав для редагування #: html/account.php lib/acctfuncs.inc.php msgid "Invalid password." -msgstr "" +msgstr "Неправильний пароль" #: html/account.php msgid "Use this form to search existing accounts." @@ -377,7 +377,7 @@ msgstr "Увійдіть, ввівши облікові дані." #: html/login.php msgid "User name or primary email address" -msgstr "" +msgstr "Назва користувача або адреса електронної пошти" #: html/login.php template/account_delete.php template/account_edit_form.php msgid "Password" @@ -441,7 +441,7 @@ msgstr "Ваш пароль успішно скинуто." #: html/passreset.php msgid "Confirm your user name or primary e-mail address:" -msgstr "" +msgstr "Підтвердити назву користувача або адреса електронної пошти:" #: html/passreset.php msgid "Enter your new password:" @@ -460,11 +460,11 @@ msgstr "Продовжити" msgid "" "If you have forgotten the user name and the primary e-mail address you used " "to register, please send a message to the %saur-general%s mailing list." -msgstr "" +msgstr "Якщо Ви забули назву користувача і адресу електронної пошти, використану при реєстрації, зверніться до списку розсилання %saur-general%s." #: html/passreset.php msgid "Enter your user name or your primary e-mail address:" -msgstr "" +msgstr "Введіть назву користувача або адресу електронної пошти:" #: html/pkgbase.php msgid "Package Bases" @@ -480,7 +480,7 @@ msgstr "Вибрані пакунки все ще мають власника, msgid "" "The selected packages have not been adopted, check the confirmation " "checkbox." -msgstr "" +msgstr "Обрані пакунки не прийнято, перевірте, чи поставлено галочку в полі підтвердження." #: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." @@ -586,7 +586,7 @@ msgid "" " package version in the AUR does not match the most recent commit. Flagging " "this package should only be done if the sources moved or changes in the " "PKGBUILD are required because of recent upstream changes." -msgstr "" +msgstr "Здається, це пакет VCS. Будь ласка, %sне%s позначайте його як застарілий, якщо версія пакета в AUR не відповідає останньому коміту. Позначити цей пакунок слід лише в тому випадку, якщо джерела переміщено або потрібні зміни в PKGBUILD в зв'язку з останніми змінами." #: html/pkgflag.php #, php-format @@ -785,7 +785,7 @@ msgstr "Може містити тільки один період, підкре #: lib/acctfuncs.inc.php msgid "Please confirm your new password." -msgstr "" +msgstr "Підтвердіть новий пароль, будь ласка." #: lib/acctfuncs.inc.php msgid "The email address is invalid." @@ -793,7 +793,7 @@ msgstr "Адреса електронної пошти неправильна." #: lib/acctfuncs.inc.php msgid "The backup email address is invalid." -msgstr "" +msgstr "Неправильна адреса електронної пошти для відновлення." #: lib/acctfuncs.inc.php msgid "The home page is invalid, please specify the full HTTP(s) URL." @@ -836,15 +836,15 @@ msgstr "Публічний ключ SSH, %s%s%s, вже використовує #: lib/acctfuncs.inc.php msgid "The CAPTCHA is missing." -msgstr "" +msgstr "Пропущено CAPTCHA." #: lib/acctfuncs.inc.php msgid "This CAPTCHA has expired. Please try again." -msgstr "" +msgstr "Термін дії цієї CAPTCHA закінчився. Будь ласка, спробуйте ще раз." #: lib/acctfuncs.inc.php msgid "The entered CAPTCHA answer is invalid." -msgstr "" +msgstr "Введена відповідь CAPTCHA недійсна." #: lib/acctfuncs.inc.php #, php-format @@ -886,7 +886,7 @@ msgstr "Обліковий запис вилучено" #: aurweb/routers/accounts.py msgid "You do not have permission to suspend accounts." -msgstr "" +msgstr " \nВи не маєте дозволу на призупинення облікових записів." #: lib/acctfuncs.inc.php #, php-format @@ -975,27 +975,27 @@ msgstr "Інформації про пакунок не знайдено." #: aurweb/routers/auth.py msgid "Bad Referer header." -msgstr "" +msgstr "Поганий заголовок Referer." #: aurweb/routers/packages.py msgid "You did not select any packages to be notified about." -msgstr "" +msgstr "Ви не вибрали жодних пакунків, про які потрібно сповіщати." #: aurweb/routers/packages.py msgid "The selected packages' notifications have been enabled." -msgstr "" +msgstr "Сповіщення для вибраних пакунків увімкнено." #: aurweb/routers/packages.py msgid "You did not select any packages for notification removal." -msgstr "" +msgstr "Ви не вибрали жодних пакунків для видалення сповіщень." #: aurweb/routers/packages.py msgid "A package you selected does not have notifications enabled." -msgstr "" +msgstr "У вибраному вами пакунку не ввімкнено сповіщення." #: aurweb/routers/packages.py msgid "The selected packages' notifications have been removed." -msgstr "" +msgstr "Сповіщення для вибраних пакунків видалено." #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." @@ -1035,7 +1035,7 @@ msgstr "Не вибрано жодного пакунку для вилучен #: aurweb/routers/packages.py msgid "One of the packages you selected does not exist." -msgstr "" +msgstr "Один із вибраних Вами пакунків не існує." #: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." @@ -1047,7 +1047,7 @@ msgstr "Для перейняття пакунків слід увійти." #: aurweb/routers/package.py msgid "You are not allowed to adopt one of the packages you selected." -msgstr "" +msgstr "У Вас немає дозволу прийняти один з вибраних Вами пакунків." #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." @@ -1055,7 +1055,7 @@ msgstr "Для зречення пакунків слід увійти." #: aurweb/routers/packages.py msgid "You are not allowed to disown one of the packages you selected." -msgstr "" +msgstr "У Вас немає дозволу відмовитися від одного з вибраних Вами пакунків" #: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." @@ -1297,7 +1297,7 @@ msgstr "Редагувати обліковий запис цього корис #: template/account_details.php msgid "List this user's comments" -msgstr "" +msgstr "Показати коментарі цього користувача" #: template/account_edit_form.php #, php-format @@ -1312,7 +1312,7 @@ msgstr "Клацніть %sтут%s, щоб дізнатися більше пр #: template/account_edit_form.php #, php-format msgid "Click %shere%s to list the comments made by this account." -msgstr "" +msgstr "Натисніть %sтут%s, щоб показати коментарі, зроблені цим обліковим записом." #: template/account_edit_form.php msgid "required" @@ -1355,30 +1355,30 @@ msgid "" "If you do not hide your email address, it is visible to all registered AUR " "users. If you hide your email address, it is visible to members of the Arch " "Linux staff only." -msgstr "" +msgstr "Якщо ви не приховаєте свою адресу електронної пошти, тоді її можуть бачити всі зареєстровані користувачі AUR. Якщо Ви приховаєте свою адресу електронної пошти, тоді її зможуть бачити лише співробітники Arch Linux." #: template/account_edit_form.php msgid "Backup Email Address" -msgstr "" +msgstr "Резервна адреса електронної пошти" #: template/account_edit_form.php msgid "" "Optionally provide a secondary email address that can be used to restore " "your account in case you lose access to your primary email address." -msgstr "" +msgstr "За бажанням вкажіть додаткову адресу електронної пошти, яку можна використовувати для відновлення облікового запису на випадок втрати доступу до своєї основної електронної адреси." #: template/account_edit_form.php msgid "" "Password reset links are always sent to both your primary and your backup " "email address." -msgstr "" +msgstr "Посилання для скидання пароля завжди надсилаються як на вашу основну, так і на резервну адресу електронної пошти." #: template/account_edit_form.php #, php-format msgid "" "Your backup email address is always only visible to members of the Arch " "Linux staff, independent of the %s setting." -msgstr "" +msgstr "Вашу резервну електронну адресу завжди бачать лише співробітники Arch Linux, незалежно від налаштувань. %s ." #: template/account_edit_form.php msgid "Language" @@ -1392,7 +1392,7 @@ msgstr "Часова зона" msgid "" "If you want to change the password, enter a new password and confirm the new" " password by entering it again." -msgstr "" +msgstr "Якщо Ви бажаєте змінити пароль, введіть новий пароль і підтвердьте новий пароль, ввівши його ще раз." #: template/account_edit_form.php msgid "Re-type password" @@ -1426,21 +1426,21 @@ msgstr "Сповіщення про зміну власника" #: template/account_edit_form.php msgid "To confirm the profile changes, please enter your current password:" -msgstr "" +msgstr "Щоб підтвердити зміни профілю, введіть поточний пароль:" #: template/account_edit_form.php msgid "Your current password" -msgstr "" +msgstr "Ваш поточний пароль" #: template/account_edit_form.php msgid "" "To protect the AUR against automated account creation, we kindly ask you to " "provide the output of the following command:" -msgstr "" +msgstr "Щоб захистити AUR від автоматичного створення облікового запису, ми просимо Вас надати результат такої команди:" #: template/account_edit_form.php msgid "Answer" -msgstr "" +msgstr "Відповідь" #: template/account_edit_form.php template/pkgbase_details.php #: template/pkg_details.php @@ -1605,7 +1605,7 @@ msgstr "тільки для читання" #: template/pkgbase_details.php template/pkg_details.php msgid "click to copy" -msgstr "" +msgstr "натисніть, щоб скопіювати" #: template/pkgbase_details.php template/pkg_details.php #: template/pkg_search_form.php @@ -1657,12 +1657,12 @@ msgstr "Додати коментар" msgid "" "Git commit identifiers referencing commits in the AUR package repository and" " URLs are converted to links automatically." -msgstr "" +msgstr "Відповідні відсилачі комітів до ідентифікаторів комітів Git в сховищі пакунків AUR та URL-адреси автоматично перетворюються на посилання." #: template/pkg_comment_form.php #, php-format msgid "%sMarkdown syntax%s is partially supported." -msgstr "" +msgstr "%sСинтакс Markdown%s підтримується частково." #: template/pkg_comments.php msgid "Pinned Comments" @@ -1674,7 +1674,7 @@ msgstr "Останні коментарі" #: template/pkg_comments.php msgid "Comments for" -msgstr "" +msgstr "Коментарі для" #: template/pkg_comments.php #, php-format @@ -1689,7 +1689,7 @@ msgstr "Анонімний коментар про %s" #: template/pkg_comments.php #, php-format msgid "Commented on package %s on %s" -msgstr "" +msgstr "Коментовано пакунок %s з датою %s" #: template/pkg_comments.php #, php-format @@ -2283,7 +2283,7 @@ msgid "" "\n" "-- \n" "If you no longer wish receive notifications about the new package, please go to [3] and click \"{label}\"." -msgstr "" +msgstr "{user} [1] з'єднав {old} [2] до {new} [3].\n\n-- \nЯкщо Ви не бажаєте більше отримувати сповіщення про новий пакунок, перейдіть на сторінку [3] і натисніть \"{label}\"." #: scripts/notify.py #, python-brace-format @@ -2307,45 +2307,45 @@ msgstr "Будь ласка, не забудьте подати свій гол #: aurweb/routers/accounts.py msgid "Invalid account type provided." -msgstr "" +msgstr "Вказано недійсний тип облікового запису." #: aurweb/routers/accounts.py msgid "You do not have permission to change account types." -msgstr "" +msgstr "У Вас немає дозволу змінювати типи облікових записів." #: aurweb/routers/accounts.py msgid "You do not have permission to change this user's account type to %s." -msgstr "" +msgstr "Ви не маєте дозволу змінити тип облікового запису цього користувача на %s." #: aurweb/packages/requests.py msgid "No due existing orphan requests to accept for %s." -msgstr "" +msgstr "Немає наявних запитів на прийняття для %s." #: aurweb/asgi.py msgid "Internal Server Error" -msgstr "" +msgstr "Внутрішня помилка сервера" #: templates/errors/500.html msgid "A fatal error has occurred." -msgstr "" +msgstr "Сталася фатальна помилка." #: templates/errors/500.html msgid "" "Details have been logged and will be reviewed by the postmaster posthaste. " "We apologize for any inconvenience this may have caused." -msgstr "" +msgstr "Подробиці зареєстровані та будуть переглянуті поштмейстером posthaste. Просимо вибачення за можливі незручності." #: aurweb/scripts/notify.py msgid "AUR Server Error" -msgstr "" +msgstr "Помилка сервера AUR" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "Пов'язані коментарі щодо закриття запиту на пакунок..." #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "Ця дія закриє всі запити на пакет, що очікують на розгляд. Якщо %sКоментарі%s пропущено, тоді буде автоматично згенеровано коментар закриття." From 2770952dfbaf2bf819d3670e885990f73da35078 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:30 -0800 Subject: [PATCH 1689/1891] update-vi translations --- po/vi.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/vi.po b/po/vi.po index 87f7faac..a71c9ed5 100644 --- a/po/vi.po +++ b/po/vi.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Vietnamese (http://www.transifex.com/lfleischer/aurweb/language/vi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From ef0e3b9f357a34577eeeb49bd32162ff12f8af62 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:33 -0800 Subject: [PATCH 1690/1891] update-zh translations --- po/zh.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/zh.po b/po/zh.po index c932df9c..77f31fe4 100644 --- a/po/zh.po +++ b/po/zh.po @@ -1,15 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" "Language-Team: Chinese (http://www.transifex.com/lfleischer/aurweb/language/zh/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" From 65d364fe9066e19f2a0c1dbad50642e9ed680096 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:36 -0800 Subject: [PATCH 1691/1891] update-zh_CN translations --- po/zh_CN.po | 93 +++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/po/zh_CN.po b/po/zh_CN.po index 675d15a3..a61781fb 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1,13 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # Feng Chao , 2015-2016 # dongfengweixiao , 2015 # dongfengweixiao , 2015 # Felix Yan , 2014,2021 # Feng Chao , 2012,2021 +# lakejason0 , 2022 # Lukas Fleischer , 2011 # pingplug , 2017-2018 # Feng Chao , 2012 @@ -17,10 +18,10 @@ msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: lakejason0 , 2022\n" "Language-Team: Chinese (China) (http://www.transifex.com/lfleischer/aurweb/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -42,7 +43,7 @@ msgstr "提示" #: html/404.php msgid "Git clone URLs are not meant to be opened in a browser." -msgstr "Git clone URLs 并不意味着能被浏览器打开。" +msgstr "Git clone URL 并不应该使用浏览器打开。" #: html/404.php #, php-format @@ -65,11 +66,11 @@ msgstr "别慌!本站正在维护中,不久后将恢复。" #: html/account.php msgid "Account" -msgstr "帐户" +msgstr "账户" #: html/account.php template/header.php msgid "Accounts" -msgstr "帐户" +msgstr "账户" #: html/account.php html/addvote.php msgid "You are not allowed to access this area." @@ -81,7 +82,7 @@ msgstr "无法获取指定用户的信息。" #: html/account.php msgid "You do not have permission to edit this account." -msgstr "您没有权限编辑此帐户。" +msgstr "您没有权限编辑此账户。" #: html/account.php lib/acctfuncs.inc.php msgid "Invalid password." @@ -89,11 +90,11 @@ msgstr "密码无效。" #: html/account.php msgid "Use this form to search existing accounts." -msgstr "使用此表单查找存在的帐户。" +msgstr "使用此表单查找存在的账户。" #: html/account.php msgid "You must log in to view user information." -msgstr "您需要登录后才能察看用户信息。" +msgstr "您需要登录后才能查看用户信息。" #: html/addvote.php template/tu_list.php msgid "Add Proposal" @@ -485,7 +486,7 @@ msgstr "选中的软件包未被弃置,请检查确认复选框。" msgid "" "The selected packages have not been adopted, check the confirmation " "checkbox." -msgstr "" +msgstr "选中的软件包未被接管,请检查确认复选框。" #: html/pkgbase.php lib/pkgreqfuncs.inc.php msgid "Cannot find package to merge votes and comments into." @@ -591,7 +592,7 @@ msgid "" " package version in the AUR does not match the most recent commit. Flagging " "this package should only be done if the sources moved or changes in the " "PKGBUILD are required because of recent upstream changes." -msgstr "" +msgstr "这似乎是 VCS 软件包。请%s不要%s因为 AUR 中的软件包版本与最新的 commit 不匹配就将其标记为过期。仅当来源移动或由于最新上游更改需要更改 PKGBUILD 时才标记此软件包。" #: html/pkgflag.php #, php-format @@ -701,7 +702,7 @@ msgstr "注册" #: html/register.php msgid "Use this form to create an account." -msgstr "使用此表单创建帐号。" +msgstr "使用此表单创建账户。" #: html/tos.php msgid "Terms of Service" @@ -854,12 +855,12 @@ msgstr "输入的验证码无效。" #: lib/acctfuncs.inc.php #, php-format msgid "Error trying to create account, %s%s%s." -msgstr "尝试创建帐户 %s%s%s 失败。" +msgstr "尝试创建账户 %s%s%s 失败。" #: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully created." -msgstr "帐户 %s%s%s 创建成功。" +msgstr "账户 %s%s%s 创建成功。" #: lib/acctfuncs.inc.php msgid "A password reset key has been sent to your e-mail address." @@ -867,7 +868,7 @@ msgstr "密码重置密钥已经发送到您的邮箱。" #: lib/acctfuncs.inc.php msgid "Click on the Login link above to use your account." -msgstr "点击上方的登录链接以使用您的帐号。" +msgstr "点击上方的登录链接以使用您的账户。" #: lib/acctfuncs.inc.php #, php-format @@ -877,7 +878,7 @@ msgstr "账户 %s%s%s 没有被修改。" #: lib/acctfuncs.inc.php #, php-format msgid "The account, %s%s%s, has been successfully modified." -msgstr "帐号 %s%s%s 已被成功修改。" +msgstr "账户 %s%s%s 已被成功修改。" #: lib/acctfuncs.inc.php msgid "" @@ -887,11 +888,11 @@ msgstr "登录表单目前对您所使用的 IP 地址禁用,原因可能是 #: lib/acctfuncs.inc.php msgid "Account suspended" -msgstr "帐号被停用" +msgstr "账户被停用" #: aurweb/routers/accounts.py msgid "You do not have permission to suspend accounts." -msgstr "" +msgstr "您没有权限停用此账户。" #: lib/acctfuncs.inc.php #, php-format @@ -980,27 +981,27 @@ msgstr "无法找到软件包的详细信息。" #: aurweb/routers/auth.py msgid "Bad Referer header." -msgstr "" +msgstr "错误的 Referer 消息头。" #: aurweb/routers/packages.py msgid "You did not select any packages to be notified about." -msgstr "" +msgstr "您没有选择要接受通知的软件包。" #: aurweb/routers/packages.py msgid "The selected packages' notifications have been enabled." -msgstr "" +msgstr "选中的软件包的通知已被启用。" #: aurweb/routers/packages.py msgid "You did not select any packages for notification removal." -msgstr "" +msgstr "您没有选择要移除通知的软件包。" #: aurweb/routers/packages.py msgid "A package you selected does not have notifications enabled." -msgstr "" +msgstr "所选中的软件包并没有启用通知。" #: aurweb/routers/packages.py msgid "The selected packages' notifications have been removed." -msgstr "" +msgstr "选中的软件包的通知已被移除。" #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." @@ -1040,7 +1041,7 @@ msgstr "您没有选择要删除的软件包。" #: aurweb/routers/packages.py msgid "One of the packages you selected does not exist." -msgstr "" +msgstr "选中的其中一个软件包不存在。" #: lib/pkgbasefuncs.inc.php msgid "The selected packages have been deleted." @@ -1052,7 +1053,7 @@ msgstr "您需要登录后才能接管软件包。" #: aurweb/routers/package.py msgid "You are not allowed to adopt one of the packages you selected." -msgstr "" +msgstr "您不被允许接管选中的其中一个软件包。" #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can disown packages." @@ -1060,7 +1061,7 @@ msgstr "您需要登录后才能弃置软件包。" #: aurweb/routers/packages.py msgid "You are not allowed to disown one of the packages you selected." -msgstr "" +msgstr "您不被允许弃置选中的其中一个软件包。" #: lib/pkgbasefuncs.inc.php msgid "You did not select any packages to adopt." @@ -1197,7 +1198,7 @@ msgstr "请求关闭成功。" #: template/account_delete.php #, php-format msgid "You can use this form to permanently delete the AUR account %s." -msgstr "您可以使用这个表单永久删除 AUR 帐号 %s。" +msgstr "您可以使用这个表单永久删除 AUR 账号 %s。" #: template/account_delete.php #, php-format @@ -1216,7 +1217,7 @@ msgstr "用户名" #: template/account_details.php template/account_edit_form.php #: template/search_accounts_form.php msgid "Account Type" -msgstr "帐户类别" +msgstr "账户类别" #: template/account_details.php template/tu_details.php #: template/tu_last_votes_list.php template/tu_list.php @@ -1298,7 +1299,7 @@ msgstr "查看这个用户提交的软件包" #: template/account_details.php msgid "Edit this user's account" -msgstr "编辑此用户的帐号" +msgstr "编辑此用户的账户" #: template/account_details.php msgid "List this user's comments" @@ -1307,7 +1308,7 @@ msgstr "显示此用户的评论" #: template/account_edit_form.php #, php-format msgid "Click %shere%s if you want to permanently delete this account." -msgstr "如果你想永久删除这个帐号,请点击 %s这里%s。" +msgstr "如果你想永久删除这个账户,请点击 %s这里%s。" #: template/account_edit_form.php #, php-format @@ -1339,7 +1340,7 @@ msgstr "受信用户" #: template/account_edit_form.php template/search_accounts_form.php msgid "Account Suspended" -msgstr "帐户被暂停" +msgstr "账户被停用" #: template/account_edit_form.php msgid "Inactive" @@ -1370,7 +1371,7 @@ msgstr "备用邮件地址" msgid "" "Optionally provide a secondary email address that can be used to restore " "your account in case you lose access to your primary email address." -msgstr "选择性的提供的备用的邮件地址。该邮件地址将在你的主要邮件地址不可用时用于恢复你的帐号。" +msgstr "选择性的提供的备用的邮件地址。该邮件地址将在你的主要邮件地址不可用时用于恢复你的账户。" #: template/account_edit_form.php msgid "" @@ -1466,7 +1467,7 @@ msgstr "没有结果符合您的搜索条件。" #: template/account_search_results.php msgid "Edit Account" -msgstr "编辑帐户" +msgstr "编辑账户" #: template/account_search_results.php msgid "Suspended" @@ -1528,7 +1529,7 @@ msgstr "版权所有 %s 2004-%d aurweb 开发组。" #: template/header.php msgid " My Account" -msgstr " 我的帐户" +msgstr " 我的账户" #: template/pkgbase_actions.php msgid "Package Actions" @@ -2297,45 +2298,45 @@ msgstr "请记得为提案 {id} [1] 投票,投票时段将于48小时内结束 #: aurweb/routers/accounts.py msgid "Invalid account type provided." -msgstr "" +msgstr "提供的账户类别无效。" #: aurweb/routers/accounts.py msgid "You do not have permission to change account types." -msgstr "" +msgstr "您没有权限更改账户类别。" #: aurweb/routers/accounts.py msgid "You do not have permission to change this user's account type to %s." -msgstr "" +msgstr "您没有权限将此用户的账户类别更改为%s。" #: aurweb/packages/requests.py msgid "No due existing orphan requests to accept for %s." -msgstr "" +msgstr "没有为 %s 接受的现有孤立请求。" #: aurweb/asgi.py msgid "Internal Server Error" -msgstr "" +msgstr "内部服务器错误" #: templates/errors/500.html msgid "A fatal error has occurred." -msgstr "" +msgstr "发生了严重的错误。" #: templates/errors/500.html msgid "" "Details have been logged and will be reviewed by the postmaster posthaste. " "We apologize for any inconvenience this may have caused." -msgstr "" +msgstr "详细信息已被记录,并会交由 Postmaster 尽快调查。对您造成的不便,我们深感抱歉。" #: aurweb/scripts/notify.py msgid "AUR Server Error" -msgstr "" +msgstr "AUR 服务器错误" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "相关软件包请求关闭评论…" #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "此操作将关闭任何有关的未处理的软件包请求。若省略%s评论%s,将会自动生成关闭评论。" From 154bb239bfb047ca6a6bc0ab244835570f6d14f5 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Tue, 10 Jan 2023 14:10:40 -0800 Subject: [PATCH 1692/1891] update-zh_TW translations --- po/zh_TW.po | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/po/zh_TW.po b/po/zh_TW.po index 1526b4a9..56014aac 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -1,18 +1,19 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the AURWEB package. -# +# # Translators: # pan93412 , 2018 +# Cycatz , 2022 # 黃柏諺 , 2014-2017 # 黃柏諺 , 2020-2022 msgid "" msgstr "" "Project-Id-Version: aurweb\n" -"Report-Msgid-Bugs-To: https://bugs.archlinux.org/index.php?project=2\n" +"Report-Msgid-Bugs-To: https://gitlab.archlinux.org/archlinux/aurweb/-/issues\n" "POT-Creation-Date: 2020-01-31 09:29+0100\n" -"PO-Revision-Date: 2022-01-18 17:18+0000\n" -"Last-Translator: Kevin Morris \n" +"PO-Revision-Date: 2011-04-10 13:21+0000\n" +"Last-Translator: Cycatz , 2022\n" "Language-Team: Chinese (Taiwan) (http://www.transifex.com/lfleischer/aurweb/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1990,7 +1991,7 @@ msgstr "每頁顯示" #: template/pkg_search_form.php template/pkg_search_results.php msgid "Go" -msgstr "到" +msgstr "搜尋" #: template/pkg_search_form.php msgid "Orphans" @@ -2324,10 +2325,10 @@ msgstr "AUR 伺服器錯誤" #: templates/pkgbase/merge.html templates/packages/delete.html #: templates/packages/disown.html msgid "Related package request closure comments..." -msgstr "" +msgstr "相關軟體包請求關閉留言……" #: templates/pkgbase/merge.html templates/packages/delete.html msgid "" "This action will close any pending package requests related to it. If " "%sComments%s are omitted, a closure comment will be autogenerated." -msgstr "" +msgstr "此動作將會關閉任何關於此的擱置中軟體包請求。若省略%s留言%s,將會自動產生關閉留言。" From ff44eb02de7b45bf193b66a0695bca82dd8896b8 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Wed, 11 Jan 2023 20:12:28 +0100 Subject: [PATCH 1693/1891] feat: add link to mailing list article on requests page Provides a convenient way to check for responses on the mailing list prior to Accepting/Rejecting requests. We compute the Message-ID hash that can be used to link back to the article in the mailing list archive. Signed-off-by: moson-mo --- aurweb/models/package_request.py | 18 +++++++++++++- conf/config.defaults | 1 + templates/requests.html | 5 +++- test/test_package_request.py | 40 +++++++++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/aurweb/models/package_request.py b/aurweb/models/package_request.py index 31071df4..94ff064b 100644 --- a/aurweb/models/package_request.py +++ b/aurweb/models/package_request.py @@ -1,7 +1,10 @@ +import base64 +import hashlib + from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import backref, relationship -from aurweb import schema +from aurweb import config, schema from aurweb.models.declarative import Base from aurweb.models.package_base import PackageBase as _PackageBase from aurweb.models.request_type import RequestType as _RequestType @@ -103,3 +106,16 @@ class PackageRequest(Base): def status_display(self) -> str: """Return a display string for the Status column.""" return self.STATUS_DISPLAY[self.Status] + + def ml_message_id_hash(self) -> str: + """Return the X-Message-ID-Hash that is used in the mailing list archive.""" + # X-Message-ID-Hash is a base32 encoded SHA1 hash + msgid = f"pkg-request-{str(self.ID)}@aur.archlinux.org" + sha1 = hashlib.sha1(msgid.encode()).digest() + + return base64.b32encode(sha1).decode() + + def ml_message_url(self) -> str: + """Return the mailing list URL for the request.""" + url = config.get("options", "ml_thread_url") % (self.ml_message_id_hash()) + return url diff --git a/conf/config.defaults b/conf/config.defaults index 6cdffe65..06e73afe 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -25,6 +25,7 @@ max_rpc_results = 5000 max_search_results = 2500 max_depends = 1000 aur_request_ml = aur-requests@lists.archlinux.org +ml_thread_url = https://lists.archlinux.org/archives/list/aur-requests@lists.archlinux.org/thread/%s request_idle_time = 1209600 request_archive_time = 15552000 auto_orphan_age = 15552000 diff --git a/templates/requests.html b/templates/requests.html index 669b46b0..697fbedb 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -115,8 +115,11 @@ {% if result.User %} {{ result.User.Username }} - +   {% endif %} + + (PRQ#{{ result.ID }}) + {% set idle_time = config_getint("options", "request_idle_time") %} {% set time_delta = (utcnow - result.RequestTS) | int %} diff --git a/test/test_package_request.py b/test/test_package_request.py index a69a0617..2bbf56c2 100644 --- a/test/test_package_request.py +++ b/test/test_package_request.py @@ -1,7 +1,7 @@ import pytest from sqlalchemy.exc import IntegrityError -from aurweb import db, time +from aurweb import config, db, time from aurweb.models.account_type import USER_ID from aurweb.models.package_base import PackageBase from aurweb.models.package_request import ( @@ -190,3 +190,41 @@ def test_package_request_status_display(user: User, pkgbase: PackageBase): pkgreq.Status = 124 with pytest.raises(KeyError): pkgreq.status_display() + + +def test_package_request_ml_message_id_hash(user: User, pkgbase: PackageBase): + with db.begin(): + pkgreq = db.create( + PackageRequest, + ID=1, + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), + ClosureComment=str(), + Status=PENDING_ID, + ) + + # A hash composed with ID=1 should result in BNNNRWOFDRSQP4LVPT77FF2GUFR45KW5 + assert pkgreq.ml_message_id_hash() == "BNNNRWOFDRSQP4LVPT77FF2GUFR45KW5" + + +def test_package_request_ml_message_url(user: User, pkgbase: PackageBase): + with db.begin(): + pkgreq = db.create( + PackageRequest, + ID=1, + ReqTypeID=MERGE_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + Comments=str(), + ClosureComment=str(), + Status=PENDING_ID, + ) + + assert ( + config.get("options", "ml_thread_url") % (pkgreq.ml_message_id_hash()) + == pkgreq.ml_message_url() + ) From 2150f8bc191e92a0b4e99b438388add88963d827 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 13 Jan 2023 10:14:53 +0100 Subject: [PATCH 1694/1891] fix(docker): nginx health check nginx health check always results in "unhealthy": There is no such option "--no-verify" for curl. We can use "-k" or "--insecure" for disabling SSL checks. Signed-off-by: moson-mo --- docker/health/nginx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/health/nginx.sh b/docker/health/nginx.sh index c530103d..df76bc2b 100755 --- a/docker/health/nginx.sh +++ b/docker/health/nginx.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec curl --no-verify -q https://localhost:8444 +exec curl -k -q https://localhost:8444 From f6c4891415766b1030fa20f2d69af78a4482cc95 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 14 Jan 2023 13:12:33 +0100 Subject: [PATCH 1695/1891] feat: add Support section to Dashboard Adds the "Support" section (displayed on "Home") to the "Dashboard" page as well. Signed-off-by: moson-mo --- templates/dashboard.html | 3 ++ templates/home.html | 66 +-------------------------------- templates/partials/support.html | 65 ++++++++++++++++++++++++++++++++ test/test_homepage.py | 40 +++++++++++++------- 4 files changed, 96 insertions(+), 78 deletions(-) create mode 100644 templates/partials/support.html diff --git a/templates/dashboard.html b/templates/dashboard.html index 48f42dc6..e88fde4a 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -62,6 +62,9 @@ {% endwith %} {% endif %} +
    + {% include 'partials/support.html' %} +
    diff --git a/templates/home.html b/templates/home.html index 3a7bc76d..e8296239 100644 --- a/templates/home.html +++ b/templates/home.html @@ -24,71 +24,7 @@

    {% trans %}Learn more...{% endtrans %}

    -

    {% trans %}Support{% endtrans %}

    -

    {% trans %}Package Requests{% endtrans %}

    -
    -

    - {{ "There are three types of requests that can be filed in the %sPackage Actions%s box on the package details page:" - | tr - | format("", "") - | safe - }} -

    -
      -
    • {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
    • -
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
    • -
    • {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}
    • -
    -

    - {{ "If you want to discuss a request, you can use the %saur-requests%s mailing list. However, please do not use that list to file requests." - | tr - | format('', "") - | safe - }} -

    -
    -

    {% trans %}Submitting Packages{% endtrans %}

    -
    -

    - {{ "Git over SSH is now used to submit packages to the AUR. See the %sSubmitting packages%s section of the Arch User Repository ArchWiki page for more details." - | tr - | format('', "") - | safe - }} -

    - {% if ssh_fingerprints %} -

    - {% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %} -

    -

      - {% for keytype in ssh_fingerprints %} -
    • {{ keytype }}: {{ ssh_fingerprints[keytype] }} - {% endfor %} -
    - {% endif %} -
    -

    {% trans %}Discussion{% endtrans %}

    -
    -

    - {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." - | tr - | format('', "", - '', "") - | safe - }} -

    -

    -

    {% trans %}Bug Reporting{% endtrans %}

    -
    -

    - {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page." - | tr - | format('', "", - "", "") - | safe - }} -

    -
    + {% include 'partials/support.html' %}
    diff --git a/templates/partials/support.html b/templates/partials/support.html new file mode 100644 index 00000000..a2890cc5 --- /dev/null +++ b/templates/partials/support.html @@ -0,0 +1,65 @@ +

    {% trans %}Support{% endtrans %}

    +

    {% trans %}Package Requests{% endtrans %}

    +
    +

    + {{ "There are three types of requests that can be filed in the %sPackage Actions%s box on the package details page:" + | tr + | format("", "") + | safe + }} +

    +
      +
    • {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
    • +
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
    • +
    • {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}
    • +
    +

    +{{ "If you want to discuss a request, you can use the %saur-requests%s mailing list. However, please do not use that list to file requests." + | tr + | format('', "") + | safe + }} +

    +
    +

    {% trans %}Submitting Packages{% endtrans %}

    +
    +

    + {{ "Git over SSH is now used to submit packages to the AUR. See the %sSubmitting packages%s section of the Arch User Repository ArchWiki page for more details." + | tr + | format('', "") + | safe + }} +

    +{% if ssh_fingerprints %} +

    + {% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %} +

    +

      + {% for keytype in ssh_fingerprints %} +
    • {{ keytype }}: {{ ssh_fingerprints[keytype] }} + {% endfor %} +
    +{% endif %} +
    +

    {% trans %}Discussion{% endtrans %}

    +
    +

    + {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." + | tr + | format('', "", + '', "") + | safe + }} +

    +

    +

    {% trans %}Bug Reporting{% endtrans %}

    +
    +

    + {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page." + | tr + | format('', "", + "", "") + | safe + }} +

    +
    diff --git a/test/test_homepage.py b/test/test_homepage.py index a573bdd6..08c52c09 100644 --- a/test/test_homepage.py +++ b/test/test_homepage.py @@ -125,33 +125,47 @@ def test_homepage(): @patch("aurweb.util.get_ssh_fingerprints") -def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock): +def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock, user): fingerprints = {"Ed25519": "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"} get_ssh_fingerprints_mock.return_value = fingerprints + # without authentication (Home) with client as request: response = request.get("/") - for key, value in fingerprints.items(): - assert key in response.content.decode() - assert value in response.content.decode() - assert ( - "The following SSH fingerprints are used for the AUR" - in response.content.decode() - ) + # with authentication (Dashboard) + with client as auth_request: + auth_request.cookies = {"AURSID": user.login(Request(), "testPassword")} + auth_response = auth_request.get("/") + + for resp in [response, auth_response]: + for key, value in fingerprints.items(): + assert key in resp.content.decode() + assert value in resp.content.decode() + assert ( + "The following SSH fingerprints are used for the AUR" + in resp.content.decode() + ) @patch("aurweb.util.get_ssh_fingerprints") -def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock): +def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock, user): get_ssh_fingerprints_mock.return_value = {} + # without authentication (Home) with client as request: response = request.get("/") - assert ( - "The following SSH fingerprints are used for the AUR" - not in response.content.decode() - ) + # with authentication (Dashboard) + with client as auth_request: + auth_request.cookies = {"AURSID": user.login(Request(), "testPassword")} + auth_response = auth_request.get("/") + + for resp in [response, auth_response]: + assert ( + "The following SSH fingerprints are used for the AUR" + not in resp.content.decode() + ) def test_homepage_stats(redis, packages): From 4d0a982c519cb087b4855922f65d73dbece45d33 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 14 Jan 2023 11:22:03 +0200 Subject: [PATCH 1696/1891] fix: assert offset and per_page are positive Signed-off-by: Leonidas Spyropoulos --- aurweb/routers/requests.py | 2 +- aurweb/util.py | 6 +++--- test/test_util.py | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 6880abd9..713f88d2 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -48,7 +48,7 @@ async def requests( if not dict(request.query_params).keys() & FILTER_PARAMS: filter_pending = True - O, PP = util.sanitize_params(O, PP) + O, PP = util.sanitize_params(str(O), str(PP)) context["O"] = O context["PP"] = PP context["filter_pending"] = filter_pending diff --git a/aurweb/util.py b/aurweb/util.py index 7b997609..abf48938 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -96,14 +96,14 @@ def apply_all(iterable: Iterable, fn: Callable): return iterable -def sanitize_params(offset: str, per_page: str) -> Tuple[int, int]: +def sanitize_params(offset_str: str, per_page_str: str) -> Tuple[int, int]: try: - offset = int(offset) + offset = defaults.O if int(offset_str) < 0 else int(offset_str) except ValueError: offset = defaults.O try: - per_page = int(per_page) + per_page = defaults.PP if int(per_page_str) < 0 else int(per_page_str) except ValueError: per_page = defaults.PP diff --git a/test/test_util.py b/test/test_util.py index fd7d8655..fefa659a 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -121,6 +121,21 @@ fRSo6OFcejKc= assert_multiple_keys(pks) +@pytest.mark.parametrize( + "offset_str, per_page_str, expected", + [ + ("5", "100", (5, 100)), + ("", "100", (0, 100)), + ("5", "", (5, 50)), + ("", "", (0, 50)), + ("-1", "100", (0, 100)), + ("5", "-100", (5, 50)), + ], +) +def test_sanitize_params(offset_str: str, per_page_str: str, expected: tuple[int, int]): + assert util.sanitize_params(offset_str, per_page_str) == expected + + def assert_multiple_keys(pks): keys = util.parse_ssh_keys(pks) assert len(keys) == 2 From 0e44687ab11da81c611a2668b1249405d32cdb7f Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 12 Jan 2023 11:47:00 +0200 Subject: [PATCH 1697/1891] fix: only try to show dependencies if object exists Signed-off-by: Leonidas Spyropoulos --- templates/partials/packages/package_metadata.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html index 50d38b48..ebbfe3f9 100644 --- a/templates/partials/packages/package_metadata.html +++ b/templates/partials/packages/package_metadata.html @@ -48,6 +48,7 @@

    {{ "Required by" | tr }} ({{ reqs_count }})

    {% if form_type == "UpdateAccount" %} diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index e4818837..faac0753 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -6,6 +6,7 @@ {% endif %} {% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %} +{% if not (request.user.HideDeletedComments and comment.DelTS) %}

    {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} {% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %} @@ -41,3 +42,4 @@ {% include "partials/comment_content.html" %} {% endif %} +{% endif %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index d4b0babc..21ccdd7b 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -122,6 +122,22 @@ def tu_user(): yield tu_user +@pytest.fixture +def user_who_hates_grey_comments() -> User: + """Yield a specific User who doesn't like grey comments.""" + account_type = db.query(AccountType, AccountType.ID == USER_ID).first() + with db.begin(): + user_who_hates_grey_comments = db.create( + User, + Username="test_hater", + Email="test_hater@example.org", + Passwd="testPassword", + AccountType=account_type, + HideDeletedComments=True, + ) + yield user_who_hates_grey_comments + + @pytest.fixture def package(maintainer: User) -> Package: """Yield a Package created by user.""" @@ -193,6 +209,23 @@ def comment(user: User, package: Package) -> PackageComment: yield comment +@pytest.fixture +def deleted_comment(user: User, package: Package) -> PackageComment: + pkgbase = package.PackageBase + now = time.utcnow() + with db.begin(): + comment = db.create( + PackageComment, + User=user, + PackageBase=pkgbase, + Comments="Test comment.", + RenderedComment=str(), + CommentTS=now, + DelTS=now, + ) + yield comment + + @pytest.fixture def packages(maintainer: User) -> list[Package]: """Yield 55 packages named pkg_0 .. pkg_54.""" @@ -409,7 +442,9 @@ def test_paged_depends_required(client: TestClient, package: Package): assert "Show 6 more" not in resp.text -def test_package_comments(client: TestClient, user: User, package: Package): +def test_package_comments( + client: TestClient, user: User, user_who_hates_grey_comments: User, package: Package +): now = time.utcnow() with db.begin(): comment = db.create( @@ -419,6 +454,14 @@ def test_package_comments(client: TestClient, user: User, package: Package): Comments="Test comment", CommentTS=now, ) + deleted_comment = db.create( + PackageComment, + PackageBase=package.PackageBase, + User=user, + Comments="Deleted Test comment", + CommentTS=now, + DelTS=now - 1, + ) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -426,12 +469,29 @@ def test_package_comments(client: TestClient, user: User, package: Package): resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) + root = parse_root(resp.text) + expected = [comment.Comments, deleted_comment.Comments] + comments = root.xpath( + './/div[contains(@class, "package-comments")]' + '/div[@class="article-content"]/div/text()' + ) + assert len(comments) == 2 + for i, row in enumerate(expected): + assert comments[i].strip() == row + + cookies = {"AURSID": user_who_hates_grey_comments.login(Request(), "testPassword")} + with client as request: + request.cookies = cookies + resp = request.get(package_endpoint(package)) + assert resp.status_code == int(HTTPStatus.OK) + root = parse_root(resp.text) expected = [comment.Comments] comments = root.xpath( './/div[contains(@class, "package-comments")]' '/div[@class="article-content"]/div/text()' ) + assert len(comments) == 1 # Deleted comment is hidden for i, row in enumerate(expected): assert comments[i].strip() == row From 1325c71712a12c529d7a3defa9cbabfad296922e Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 21 Apr 2023 23:55:02 +0100 Subject: [PATCH 1732/1891] chore: update poetry.lock Signed-off-by: Leonidas Spyropoulos --- poetry.lock | 616 ++++++++++++++++++++++++++-------------------------- 1 file changed, 302 insertions(+), 314 deletions(-) diff --git a/poetry.lock b/poetry.lock index fe81898e..1b98a5b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. [[package]] name = "aiofiles" @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.10.2" +version = "1.10.3" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.10.2-py3-none-any.whl", hash = "sha256:8b48368f6533c064b39c024e1daba15ae7f947eac84185c28c06bbe1301a5497"}, - {file = "alembic-1.10.2.tar.gz", hash = "sha256:457eafbdc0769d855c2c92cbafe6b7f319f916c80cf4ed02b8f394f38b51b89d"}, + {file = "alembic-1.10.3-py3-none-any.whl", hash = "sha256:b2e0a6cfd3a8ce936a1168320bcbe94aefa3f4463cd773a968a55071beb3cd37"}, + {file = "alembic-1.10.3.tar.gz", hash = "sha256:32a69b13a613aeb7e8093f242da60eff9daed13c0df02fff279c1b06c32965d2"}, ] [package.dependencies] @@ -80,25 +80,6 @@ files = [ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] -[[package]] -name = "attrs" -version = "22.2.0" -description = "Classes Without Boilerplate" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] - [[package]] name = "authlib" version = "1.2.0" @@ -371,63 +352,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.1" +version = "7.2.3" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49567ec91fc5e0b15356da07a2feabb421d62f52a9fff4b1ec40e9e19772f5f8"}, - {file = "coverage-7.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2ef6cae70168815ed91388948b5f4fcc69681480a0061114db737f957719f03"}, - {file = "coverage-7.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3004765bca3acd9e015794e5c2f0c9a05587f5e698127ff95e9cfba0d3f29339"}, - {file = "coverage-7.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cca7c0b7f5881dfe0291ef09ba7bb1582cb92ab0aeffd8afb00c700bf692415a"}, - {file = "coverage-7.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2167d116309f564af56f9aa5e75ef710ef871c5f9b313a83050035097b56820"}, - {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cb5f152fb14857cbe7f3e8c9a5d98979c4c66319a33cad6e617f0067c9accdc4"}, - {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:87dc37f16fb5e3a28429e094145bf7c1753e32bb50f662722e378c5851f7fdc6"}, - {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e191a63a05851f8bce77bc875e75457f9b01d42843f8bd7feed2fc26bbe60833"}, - {file = "coverage-7.2.1-cp310-cp310-win32.whl", hash = "sha256:e3ea04b23b114572b98a88c85379e9e9ae031272ba1fb9b532aa934c621626d4"}, - {file = "coverage-7.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:0cf557827be7eca1c38a2480484d706693e7bb1929e129785fe59ec155a59de6"}, - {file = "coverage-7.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:570c21a29493b350f591a4b04c158ce1601e8d18bdcd21db136fbb135d75efa6"}, - {file = "coverage-7.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e872b082b32065ac2834149dc0adc2a2e6d8203080501e1e3c3c77851b466f9"}, - {file = "coverage-7.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac6343bae03b176e9b58104a9810df3cdccd5cfed19f99adfa807ffbf43cf9b"}, - {file = "coverage-7.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abacd0a738e71b20e224861bc87e819ef46fedba2fb01bc1af83dfd122e9c319"}, - {file = "coverage-7.2.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9256d4c60c4bbfec92721b51579c50f9e5062c21c12bec56b55292464873508"}, - {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:80559eaf6c15ce3da10edb7977a1548b393db36cbc6cf417633eca05d84dd1ed"}, - {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0bd7e628f6c3ec4e7d2d24ec0e50aae4e5ae95ea644e849d92ae4805650b4c4e"}, - {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09643fb0df8e29f7417adc3f40aaf379d071ee8f0350ab290517c7004f05360b"}, - {file = "coverage-7.2.1-cp311-cp311-win32.whl", hash = "sha256:1b7fb13850ecb29b62a447ac3516c777b0e7a09ecb0f4bb6718a8654c87dfc80"}, - {file = "coverage-7.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:617a94ada56bbfe547aa8d1b1a2b8299e2ec1ba14aac1d4b26a9f7d6158e1273"}, - {file = "coverage-7.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8649371570551d2fd7dee22cfbf0b61f1747cdfb2b7587bb551e4beaaa44cb97"}, - {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d2b9b5e70a21474c105a133ba227c61bc95f2ac3b66861143ce39a5ea4b3f84"}, - {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82c988954722fa07ec5045c57b6d55bc1a0890defb57cf4a712ced65b26ddd"}, - {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:861cc85dfbf55a7a768443d90a07e0ac5207704a9f97a8eb753292a7fcbdfcfc"}, - {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0339dc3237c0d31c3b574f19c57985fcbe494280153bbcad33f2cdf469f4ac3e"}, - {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5928b85416a388dd557ddc006425b0c37e8468bd1c3dc118c1a3de42f59e2a54"}, - {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8d3843ca645f62c426c3d272902b9de90558e9886f15ddf5efe757b12dd376f5"}, - {file = "coverage-7.2.1-cp37-cp37m-win32.whl", hash = "sha256:6a034480e9ebd4e83d1aa0453fd78986414b5d237aea89a8fdc35d330aa13bae"}, - {file = "coverage-7.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6fce673f79a0e017a4dc35e18dc7bb90bf6d307c67a11ad5e61ca8d42b87cbff"}, - {file = "coverage-7.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f099da6958ddfa2ed84bddea7515cb248583292e16bb9231d151cd528eab657"}, - {file = "coverage-7.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:97a3189e019d27e914ecf5c5247ea9f13261d22c3bb0cfcfd2a9b179bb36f8b1"}, - {file = "coverage-7.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a81dbcf6c6c877986083d00b834ac1e84b375220207a059ad45d12f6e518a4e3"}, - {file = "coverage-7.2.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2c3dde4c0b9be4b02067185136b7ee4681978228ad5ec1278fa74f5ca3e99"}, - {file = "coverage-7.2.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a209d512d157379cc9ab697cbdbb4cfd18daa3e7eebaa84c3d20b6af0037384"}, - {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f3d07edb912a978915576a776756069dede66d012baa503022d3a0adba1b6afa"}, - {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8dca3c1706670297851bca1acff9618455122246bdae623be31eca744ade05ec"}, - {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b1991a6d64231a3e5bbe3099fb0dd7c9aeaa4275ad0e0aeff4cb9ef885c62ba2"}, - {file = "coverage-7.2.1-cp38-cp38-win32.whl", hash = "sha256:22c308bc508372576ffa3d2dbc4824bb70d28eeb4fcd79d4d1aed663a06630d0"}, - {file = "coverage-7.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:b0c0d46de5dd97f6c2d1b560bf0fcf0215658097b604f1840365296302a9d1fb"}, - {file = "coverage-7.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4dd34a935de268a133e4741827ae951283a28c0125ddcdbcbba41c4b98f2dfef"}, - {file = "coverage-7.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0f8318ed0f3c376cfad8d3520f496946977abde080439d6689d7799791457454"}, - {file = "coverage-7.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:834c2172edff5a08d78e2f53cf5e7164aacabeb66b369f76e7bb367ca4e2d993"}, - {file = "coverage-7.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4d70c853f0546855f027890b77854508bdb4d6a81242a9d804482e667fff6e6"}, - {file = "coverage-7.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a6450da4c7afc4534305b2b7d8650131e130610cea448ff240b6ab73d7eab63"}, - {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:99f4dd81b2bb8fc67c3da68b1f5ee1650aca06faa585cbc6818dbf67893c6d58"}, - {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bdd3f2f285ddcf2e75174248b2406189261a79e7fedee2ceeadc76219b6faa0e"}, - {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f29351393eb05e6326f044a7b45ed8e38cb4dcc38570d12791f271399dc41431"}, - {file = "coverage-7.2.1-cp39-cp39-win32.whl", hash = "sha256:e2b50ebc2b6121edf352336d503357321b9d8738bb7a72d06fc56153fd3f4cd8"}, - {file = "coverage-7.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd5a12239c0006252244f94863f1c518ac256160cd316ea5c47fb1a11b25889a"}, - {file = "coverage-7.2.1-pp37.pp38.pp39-none-any.whl", hash = "sha256:436313d129db7cf5b4ac355dd2bd3f7c7e5294af077b090b85de75f8458b8616"}, - {file = "coverage-7.2.1.tar.gz", hash = "sha256:c77f2a9093ccf329dd523a9b2b3c854c20d2a3d968b6def3b820272ca6732242"}, + {file = "coverage-7.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5"}, + {file = "coverage-7.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4"}, + {file = "coverage-7.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2"}, + {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013"}, + {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa"}, + {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b"}, + {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257"}, + {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535"}, + {file = "coverage-7.2.3-cp310-cp310-win32.whl", hash = "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91"}, + {file = "coverage-7.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e"}, + {file = "coverage-7.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79"}, + {file = "coverage-7.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc"}, + {file = "coverage-7.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df"}, + {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623"}, + {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d"}, + {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93"}, + {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312"}, + {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4"}, + {file = "coverage-7.2.3-cp311-cp311-win32.whl", hash = "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925"}, + {file = "coverage-7.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910"}, + {file = "coverage-7.2.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c"}, + {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9"}, + {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1"}, + {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1"}, + {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21"}, + {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841"}, + {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48"}, + {file = "coverage-7.2.3-cp37-cp37m-win32.whl", hash = "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1"}, + {file = "coverage-7.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f"}, + {file = "coverage-7.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab"}, + {file = "coverage-7.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040"}, + {file = "coverage-7.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1"}, + {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911"}, + {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462"}, + {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c"}, + {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd"}, + {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152"}, + {file = "coverage-7.2.3-cp38-cp38-win32.whl", hash = "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22"}, + {file = "coverage-7.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367"}, + {file = "coverage-7.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235"}, + {file = "coverage-7.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21"}, + {file = "coverage-7.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934"}, + {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859"}, + {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9"}, + {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539"}, + {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe"}, + {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4"}, + {file = "coverage-7.2.3-cp39-cp39-win32.whl", hash = "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30"}, + {file = "coverage-7.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a"}, + {file = "coverage-7.2.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0"}, + {file = "coverage-7.2.3.tar.gz", hash = "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259"}, ] [package.dependencies] @@ -438,35 +419,31 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "39.0.2" +version = "40.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "cryptography-39.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:2725672bb53bb92dc7b4150d233cd4b8c59615cd8288d495eaa86db00d4e5c06"}, - {file = "cryptography-39.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:23df8ca3f24699167daf3e23e51f7ba7334d504af63a94af468f468b975b7dd7"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:eb40fe69cfc6f5cdab9a5ebd022131ba21453cf7b8a7fd3631f45bbf52bed612"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc0521cce2c1d541634b19f3ac661d7a64f9555135e9d8af3980965be717fd4a"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffd394c7896ed7821a6d13b24657c6a34b6e2650bd84ae063cf11ccffa4f1a97"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:e8a0772016feeb106efd28d4a328e77dc2edae84dfbac06061319fdb669ff828"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8f35c17bd4faed2bc7797d2a66cbb4f986242ce2e30340ab832e5d99ae60e011"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b49a88ff802e1993b7f749b1eeb31134f03c8d5c956e3c125c75558955cda536"}, - {file = "cryptography-39.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c682e736513db7d04349b4f6693690170f95aac449c56f97415c6980edef5"}, - {file = "cryptography-39.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:d7d84a512a59f4412ca8549b01f94be4161c94efc598bf09d027d67826beddc0"}, - {file = "cryptography-39.0.2-cp36-abi3-win32.whl", hash = "sha256:c43ac224aabcbf83a947eeb8b17eaf1547bce3767ee2d70093b461f31729a480"}, - {file = "cryptography-39.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:788b3921d763ee35dfdb04248d0e3de11e3ca8eb22e2e48fef880c42e1f3c8f9"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d15809e0dbdad486f4ad0979753518f47980020b7a34e9fc56e8be4f60702fac"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:50cadb9b2f961757e712a9737ef33d89b8190c3ea34d0fb6675e00edbe35d074"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:103e8f7155f3ce2ffa0049fe60169878d47a4364b277906386f8de21c9234aa1"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6236a9610c912b129610eb1a274bdc1350b5df834d124fa84729ebeaf7da42c3"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e944fe07b6f229f4c1a06a7ef906a19652bdd9fd54c761b0ff87e83ae7a30354"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:35d658536b0a4117c885728d1a7032bdc9a5974722ae298d6c533755a6ee3915"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:30b1d1bfd00f6fc80d11300a29f1d8ab2b8d9febb6ed4a38a76880ec564fae84"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e029b844c21116564b8b61216befabca4b500e6816fa9f0ba49527653cae2108"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fa507318e427169ade4e9eccef39e9011cdc19534f55ca2f36ec3f388c1f70f3"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8bc0008ef798231fac03fe7d26e82d601d15bd16f3afaad1c6113771566570f3"}, - {file = "cryptography-39.0.2.tar.gz", hash = "sha256:bc5b871e977c8ee5a1bbc42fa8d19bcc08baf0c51cbf1586b0e87a2694dde42f"}, + {file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:8f79b5ff5ad9d3218afb1e7e20ea74da5f76943ee5edb7f76e56ec5161ec782b"}, + {file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:05dc219433b14046c476f6f09d7636b92a1c3e5808b9a6536adf4932b3b2c440"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df2af28d7bedc84fe45bd49bc35d710aede676e2a4cb7fc6d103a2adc8afe4d"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dcca15d3a19a66e63662dc8d30f8036b07be851a8680eda92d079868f106288"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a04386fb7bc85fab9cd51b6308633a3c271e3d0d3eae917eebab2fac6219b6d2"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:adc0d980fd2760c9e5de537c28935cc32b9353baaf28e0814df417619c6c8c3b"}, + {file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d5a1bd0e9e2031465761dfa920c16b0065ad77321d8a8c1f5ee331021fda65e9"}, + {file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a95f4802d49faa6a674242e25bfeea6fc2acd915b5e5e29ac90a32b1139cae1c"}, + {file = "cryptography-40.0.2-cp36-abi3-win32.whl", hash = "sha256:aecbb1592b0188e030cb01f82d12556cf72e218280f621deed7d806afd2113f9"}, + {file = "cryptography-40.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:b12794f01d4cacfbd3177b9042198f3af1c856eedd0a98f10f141385c809a14b"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:142bae539ef28a1c76794cca7f49729e7c54423f615cfd9b0b1fa90ebe53244b"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:956ba8701b4ffe91ba59665ed170a2ebbdc6fc0e40de5f6059195d9f2b33ca0e"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f01c9863da784558165f5d4d916093737a75203a5c5286fde60e503e4276c7a"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3daf9b114213f8ba460b829a02896789751626a2a4e7a43a28ee77c04b5e4958"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48f388d0d153350f378c7f7b41497a54ff1513c816bcbbcafe5b829e59b9ce5b"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c0764e72b36a3dc065c155e5b22f93df465da9c39af65516fe04ed3c68c92636"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cbaba590180cba88cb99a5f76f90808a624f18b169b90a4abb40c1fd8c19420e"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7a38250f433cd41df7fcb763caa3ee9362777fdb4dc642b9a349721d2bf47404"}, + {file = "cryptography-40.0.2.tar.gz", hash = "sha256:c33c0d32b8594fa647d2e01dbccc303478e16fdd7cf98652d5b3ed11aa5e5c99"}, ] [package.dependencies] @@ -475,10 +452,10 @@ cffi = ">=1.12" [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] -pep8test = ["black", "check-manifest", "mypy", "ruff", "types-pytz", "types-requests"] +pep8test = ["black", "check-manifest", "mypy", "ruff"] sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist", "pytz"] +test = ["iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist"] test-randomorder = ["pytest-randomly"] tox = ["tox"] @@ -551,18 +528,18 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.10.0" +version = "2.11.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false -python-versions = ">=3.8,<4.0" +python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.10.0-py3-none-any.whl", hash = "sha256:7e66c96793688703a1da41256323ddaa1b3a2cab4ef793866839a937bb273915"}, - {file = "fakeredis-2.10.0.tar.gz", hash = "sha256:722644759bba4ad61fa38f0bb34939b7657f166ba35892f747e282407a196845"}, + {file = "fakeredis-2.11.0-py3-none-any.whl", hash = "sha256:156ef67713dd53000c28dd341be61a365c20230bc17c8fb8320b0c123e667aff"}, + {file = "fakeredis-2.11.0.tar.gz", hash = "sha256:d25883dc52c31546e586b6ec3c49c5999b3025bfc4812532d71dedcfed56fee1"}, ] [package.dependencies] -redis = ">=4,<5" +redis = ">=4" sortedcontainers = ">=2.4,<3.0" [package.extras] @@ -608,19 +585,19 @@ python-dateutil = "*" [[package]] name = "filelock" -version = "3.9.1" +version = "3.12.0" description = "A platform independent file lock." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.9.1-py3-none-any.whl", hash = "sha256:4427cdda14a1c68e264845142842d6de2d0fa2c15ba31571a3d9c9a1ec9d191c"}, - {file = "filelock-3.9.1.tar.gz", hash = "sha256:e393782f76abea324dee598d2ea145b857a20df0e0ee4f80fcf35e72a341d2c7"}, + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.1)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "greenlet" @@ -854,14 +831,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.0.0" +version = "6.6.0" description = "Read metadata from Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, - {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, + {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, + {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, ] [package.dependencies] @@ -1029,14 +1006,14 @@ testing = ["pytest"] [[package]] name = "markdown" -version = "3.4.1" -description = "Python implementation of Markdown." +version = "3.4.3" +description = "Python implementation of John Gruber's Markdown." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Markdown-3.4.1-py3-none-any.whl", hash = "sha256:08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186"}, - {file = "Markdown-3.4.1.tar.gz", hash = "sha256:3b809086bb6efad416156e00a0da66fe47618a5d6918dd688f53f40c8e4cfeff"}, + {file = "Markdown-3.4.3-py3-none-any.whl", hash = "sha256:065fd4df22da73a625f14890dd77eb8040edcbd68794bcd35943be14490608b2"}, + {file = "Markdown-3.4.3.tar.gz", hash = "sha256:8bf101198e004dc93e84a12a7395e31aac6a9c9942848ae1d99b9d72cf9b3520"}, ] [package.dependencies] @@ -1124,68 +1101,80 @@ files = [ [[package]] name = "orjson" -version = "3.8.7" +version = "3.8.10" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">= 3.7" files = [ - {file = "orjson-3.8.7-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:f98c82850b7b4b7e27785ca43706fa86c893cdb88d54576bbb9b0d9c1070e421"}, - {file = "orjson-3.8.7-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1dee503c6c1a0659c5b46f5f39d9ca9d3657b11ca8bb4af8506086df416887d9"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc4fa83831f42ce5c938f8cefc2e175fa1df6f661fdeaba3badf26d2b8cfcf73"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e432c6c9c8b97ad825276d5795286f7cc9689f377a97e3b7ecf14918413303f"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee519964a5a0efb9633f38b1129fd242807c5c57162844efeeaab1c8de080051"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:109b539ce5bf60a121454d008fa67c3b67e5a3249e47d277012645922cf74bd0"}, - {file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ad4d441fbde4133af6fee37f67dbf23181b9c537ecc317346ec8c3b4c8ec7705"}, - {file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:89dc786419e1ce2588345f58dd6a434e6728bce66b94989644234bcdbe39b603"}, - {file = "orjson-3.8.7-cp310-none-win_amd64.whl", hash = "sha256:697abde7350fb8076d44bcb6b4ab3ce415ae2b5a9bb91efc460e5ab0d96bb5d3"}, - {file = "orjson-3.8.7-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:1c19f47b35b9966a3abadf341b18ee4a860431bf2b00fd8d58906d51cf78aa70"}, - {file = "orjson-3.8.7-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:3ffaabb380cd0ee187b4fc362516df6bf739808130b1339445c7d8878fca36e7"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d88837002c5a8af970745b8e0ca1b0fdb06aafbe7f1279e110d338ea19f3d23"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff60187d1b7e0bfab376b6002b08c560b7de06c87cf3a8ac639ecf58f84c5f3b"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0110970aed35dec293f30ed1e09f8604afd5d15c5ef83de7f6c427619b3ba47b"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:51b275475d4e36118b65ad56f9764056a09d985c5d72e64579bf8816f1356a5e"}, - {file = "orjson-3.8.7-cp311-none-win_amd64.whl", hash = "sha256:63144d27735f3b60f079f247ac9a289d80dfe49a7f03880dfa0c0ba64d6491d5"}, - {file = "orjson-3.8.7-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:a16273d77db746bb1789a2bbfded81148a60743fd6f9d5185e02d92e3732fa18"}, - {file = "orjson-3.8.7-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:5bb32259ea22cc9dd47a6fdc4b8f9f1e2f798fcf56c7c1122a7df0f4c5d33bf3"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad02e9102d4ba67db30a136e631e32aeebd1dce26c9f5942a457b02df131c5d0"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dbcfcec2b7ac52deb7be3685b551addc28ee8fa454ef41f8b714df6ba0e32a27"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a0e5504a5fc86083cc210c6946e8d61e13fe9f1d7a7bf81b42f7050a49d4fb"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:7bd4fd37adb03b1f2a1012d43c9f95973a02164e131dfe3ff804d7e180af5653"}, - {file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:188ed9f9a781333ad802af54c55d5a48991e292239aef41bd663b6e314377eb8"}, - {file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cc52f58c688cb10afd810280e450f56fbcb27f52c053463e625c8335c95db0dc"}, - {file = "orjson-3.8.7-cp37-none-win_amd64.whl", hash = "sha256:403c8c84ac8a02c40613b0493b74d5256379e65196d39399edbf2ed3169cbeb5"}, - {file = "orjson-3.8.7-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:7d6ac5f8a2a17095cd927c4d52abbb38af45918e0d3abd60fb50cfd49d71ae24"}, - {file = "orjson-3.8.7-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:0295a7bfd713fa89231fd0822c995c31fc2343c59a1d13aa1b8b6651335654f5"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feb32aaaa34cf2f891eb793ad320d4bb6731328496ae59b6c9eb1b620c42b529"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7a3ab1a473894e609b6f1d763838c6689ba2b97620c256a32c4d9f10595ac179"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e8c430d82b532c5ab95634e034bbf6ca7432ffe175a3e63eadd493e00b3a555"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:366cc75f7e09106f9dac95a675aef413367b284f25507d21e55bd7f45f445e80"}, - {file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:84d154d07e8b17d97e990d5d710b719a031738eb1687d8a05b9089f0564ff3e0"}, - {file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06180014afcfdc167ca984b312218aa62ce20093965c437c5f9166764cb65ef7"}, - {file = "orjson-3.8.7-cp38-none-win_amd64.whl", hash = "sha256:41244431ba13f2e6ef22b52c5cf0202d17954489f4a3c0505bd28d0e805c3546"}, - {file = "orjson-3.8.7-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:b20f29fa8371b8023f1791df035a2c3ccbd98baa429ac3114fc104768f7db6f8"}, - {file = "orjson-3.8.7-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:226bfc1da2f21ee74918cee2873ea9a0fec1a8830e533cb287d192d593e99d02"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75c11023ac29e29fd3e75038d0e8dd93f9ea24d7b9a5e871967a8921a88df24"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78604d3acfd7cd502f6381eea0c42281fe2b74755b334074ab3ebc0224100be1"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7129a6847f0494aa1427167486ef6aea2e835ba05f6c627df522692ee228f65"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1a1a8f4980059f48483782c608145b0f74538c266e01c183d9bcd9f8b71dbada"}, - {file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d60304172a33705ce4bd25a6261ab84bed2dab0b3d3b79672ea16c7648af4832"}, - {file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4f733062d84389c32c0492e5a4929056fac217034a94523debe0430bcc602cda"}, - {file = "orjson-3.8.7-cp39-none-win_amd64.whl", hash = "sha256:010e2970ec9e826c332819e0da4b14b29b19641da0f1a6af4cec91629ef9b988"}, - {file = "orjson-3.8.7.tar.gz", hash = "sha256:8460c8810652dba59c38c80d27c325b5092d189308d8d4f3e688dbd8d4f3b2dc"}, + {file = "orjson-3.8.10-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4dfe0651e26492d5d929bbf4322de9afbd1c51ac2e3947a7f78492b20359711d"}, + {file = "orjson-3.8.10-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bc30de5c7b3a402eb59cc0656b8ee53ca36322fc52ab67739c92635174f88336"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c08b426fae7b9577b528f99af0f7e0ff3ce46858dd9a7d1bf86d30f18df89a4c"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bce970f293825e008dbf739268dfa41dfe583aa2a1b5ef4efe53a0e92e9671ea"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b23fb0264bbdd7218aa685cb6fc71f0dcecf34182f0a8596a3a0dff010c06f9"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0826ad2dc1cea1547edff14ce580374f0061d853cbac088c71162dbfe2e52205"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7bce6e61cea6426309259b04c6ee2295b3f823ea51a033749459fe2dd0423b2"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0b470d31244a6f647e5402aac7d2abaf7bb4f52379acf67722a09d35a45c9417"}, + {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:48824649019a25d3e52f6454435cf19fe1eb3d05ee697e65d257f58ae3aa94d9"}, + {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:faee89e885796a9cc493c930013fa5cfcec9bfaee431ddf00f0fbfb57166a8b3"}, + {file = "orjson-3.8.10-cp310-none-win_amd64.whl", hash = "sha256:3cfe32b1227fe029a5ad989fbec0b453a34e5e6d9a977723f7c3046d062d3537"}, + {file = "orjson-3.8.10-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:2073b62822738d6740bd2492f6035af5c2fd34aa198322b803dc0e70559a17b7"}, + {file = "orjson-3.8.10-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b2c4faf20b6bb5a2d7ac0c16f58eb1a3800abcef188c011296d1dc2bb2224d48"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c1825997232a324911d11c75d91e1e0338c7b723c149cf53a5fc24496c048a4"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7e85d4682f3ed7321d36846cad0503e944ea9579ef435d4c162e1b73ead8ac9"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8cdaacecb92997916603ab232bb096d0fa9e56b418ca956b9754187d65ca06"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ddabc5e44702d13137949adee3c60b7091e73a664f6e07c7b428eebb2dea7bbf"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27bb26e171e9cfdbec39c7ca4739b6bef8bd06c293d56d92d5e3a3fc017df17d"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1810e5446fe68d61732e9743592da0ec807e63972eef076d09e02878c2f5958e"}, + {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:61e2e51cefe7ef90c4fbbc9fd38ecc091575a3ea7751d56fad95cbebeae2a054"}, + {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f3e9ac9483c2b4cd794e760316966b7bd1e6afb52b0218f068a4e80c9b2db4f6"}, + {file = "orjson-3.8.10-cp311-none-win_amd64.whl", hash = "sha256:26aee557cf8c93b2a971b5a4a8e3cca19780573531493ce6573aa1002f5c4378"}, + {file = "orjson-3.8.10-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:11ae68f995a50724032af297c92f20bcde31005e0bf3653b12bff9356394615b"}, + {file = "orjson-3.8.10-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:35d879b46b8029e1e01e9f6067928b470a4efa1ca749b6d053232b873c2dcf66"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:345e41abd1d9e3ecfb554e1e75ff818cf42e268bd06ad25a96c34e00f73a327e"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:45a5afc9cda6b8aac066dd50d8194432fbc33e71f7164f95402999b725232d78"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad632dc330a7b39da42530c8d146f76f727d476c01b719dc6743c2b5701aaf6b"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bf2556ba99292c4dc550560384dd22e88b5cdbe6d98fb4e202e902b5775cf9f"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b88afd662190f19c3bb5036a903589f88b1d2c2608fbb97281ce000db6b08897"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:abce8d319aae800fd2d774db1106f926dee0e8a5ca85998fd76391fcb58ef94f"}, + {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e999abca892accada083f7079612307d94dd14cc105a699588a324f843216509"}, + {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3fdee68c4bb3c5d6f89ed4560f1384b5d6260e48fbf868bae1a245a3c693d4d"}, + {file = "orjson-3.8.10-cp37-none-win_amd64.whl", hash = "sha256:e5d7f82506212e047b184c06e4bcd48c1483e101969013623cebcf51cf12cad9"}, + {file = "orjson-3.8.10-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:d953e6c2087dcd990e794f8405011369ee11cf13e9aaae3172ee762ee63947f2"}, + {file = "orjson-3.8.10-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:81aa3f321d201bff0bd0f4014ea44e51d58a9a02d8f2b0eeab2cee22611be8e1"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d27b6182f75896dd8c10ea0f78b9265a3454be72d00632b97f84d7031900dd4"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1486600bc1dd1db26c588dd482689edba3d72d301accbe4301db4b2b28bd7aa4"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344ea91c556a2ce6423dc13401b83ab0392aa697a97fa4142c2c63a6fd0bbfef"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:979f231e3bad1c835627eef1a30db12a8af58bfb475a6758868ea7e81897211f"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa3a26dcf0f5f2912a8ce8e87273e68b2a9526854d19fd09ea671b154418e88"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:b6e79d8864794635974b18821b49a7f27859d17b93413d4603efadf2e92da7a5"}, + {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ce49999bcbbc14791c61844bc8a69af44f5205d219be540e074660038adae6bf"}, + {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2ef690335b24f9272dbf6639353c1ffc3f196623a92b851063e28e9515cf7dd"}, + {file = "orjson-3.8.10-cp38-none-win_amd64.whl", hash = "sha256:5a0b1f4e4fa75e26f814161196e365fc0e1a16e3c07428154505b680a17df02f"}, + {file = "orjson-3.8.10-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:af7601a78b99f0515af2f8ab12c955c0072ffcc1e437fb2556f4465783a4d813"}, + {file = "orjson-3.8.10-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6bbd7b3a3e2030b03c68c4d4b19a2ef5b89081cbb43c05fe2010767ef5e408db"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4355c9aedfefe60904e8bd7901315ebbc8bb828f665e4c9bc94b1432e67cb6f7"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b0ba074375e25c1594e770e2215941e2017c3cd121889150737fa1123e8bfe"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34b6901c110c06ab9e8d7d0496db4bc9a0c162ca8d77f67539d22cb39e0a1ef4"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb62ec16a1c26ad9487727b529103cb6a94a1d4969d5b32dd0eab5c3f4f5a6f2"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595e1e7d04aaaa3d41113e4eb9f765ab642173c4001182684ae9ddc621bb11c8"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:64ffd92328473a2f9af059410bd10c703206a4bbc7b70abb1bedcd8761e39eb8"}, + {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b1f648ec89c6a426098868460c0ef8c86b457ce1378d7569ff4acb6c0c454048"}, + {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6a286ad379972e4f46579e772f0477e6b505f1823aabcd64ef097dbb4549e1a4"}, + {file = "orjson-3.8.10-cp39-none-win_amd64.whl", hash = "sha256:d2874cee6856d7c386b596e50bc517d1973d73dc40b2bd6abec057b5e7c76b2f"}, + {file = "orjson-3.8.10.tar.gz", hash = "sha256:dcf6adb4471b69875034afab51a14b64f1026bc968175a2bb02c5f6b358bd413"}, ] [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] @@ -1271,14 +1260,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.11.1" +version = "5.11.2" description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus_fastapi_instrumentator-5.11.1-py3-none-any.whl", hash = "sha256:8a58dc34b75620f634bd9c9d77978172bc5a6de05b921e301a1e4de896ca97ce"}, - {file = "prometheus_fastapi_instrumentator-5.11.1.tar.gz", hash = "sha256:34026f8735aff89a08ed71bd16a1f454d5eaaec20a9a52eb5c40aa2d585dfbba"}, + {file = "prometheus_fastapi_instrumentator-5.11.2-py3-none-any.whl", hash = "sha256:c84ae3dc98bebb44f29d0af0c17c9f0782c2fb964ef83353664d9858a632cf81"}, + {file = "prometheus_fastapi_instrumentator-5.11.2.tar.gz", hash = "sha256:9d8d0df8de7d6a73ae387121629dbf32fe022cdfc63e8bacd51f4b8ff21059ea"}, ] [package.dependencies] @@ -1287,25 +1276,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.22.1" +version = "4.22.3" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.22.1-cp310-abi3-win32.whl", hash = "sha256:85aa9acc5a777adc0c21b449dafbc40d9a0b6413ff3a4f77ef9df194be7f975b"}, - {file = "protobuf-4.22.1-cp310-abi3-win_amd64.whl", hash = "sha256:8bc971d76c03f1dd49f18115b002254f2ddb2d4b143c583bb860b796bb0d399e"}, - {file = "protobuf-4.22.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:5917412347e1da08ce2939eb5cd60650dfb1a9ab4606a415b9278a1041fb4d19"}, - {file = "protobuf-4.22.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9e12e2810e7d297dbce3c129ae5e912ffd94240b050d33f9ecf023f35563b14f"}, - {file = "protobuf-4.22.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:953fc7904ef46900262a26374b28c2864610b60cdc8b272f864e22143f8373c4"}, - {file = "protobuf-4.22.1-cp37-cp37m-win32.whl", hash = "sha256:6e100f7bc787cd0a0ae58dbf0ab8bbf1ee7953f862b89148b6cf5436d5e9eaa1"}, - {file = "protobuf-4.22.1-cp37-cp37m-win_amd64.whl", hash = "sha256:87a6393fa634f294bf24d1cfe9fdd6bb605cbc247af81b9b10c4c0f12dfce4b3"}, - {file = "protobuf-4.22.1-cp38-cp38-win32.whl", hash = "sha256:e3fb58076bdb550e75db06ace2a8b3879d4c4f7ec9dd86e4254656118f4a78d7"}, - {file = "protobuf-4.22.1-cp38-cp38-win_amd64.whl", hash = "sha256:651113695bc2e5678b799ee5d906b5d3613f4ccfa61b12252cfceb6404558af0"}, - {file = "protobuf-4.22.1-cp39-cp39-win32.whl", hash = "sha256:67b7d19da0fda2733702c2299fd1ef6cb4b3d99f09263eacaf1aa151d9d05f02"}, - {file = "protobuf-4.22.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8700792f88e59ccecfa246fa48f689d6eee6900eddd486cdae908ff706c482b"}, - {file = "protobuf-4.22.1-py3-none-any.whl", hash = "sha256:3e19dcf4adbf608924d3486ece469dd4f4f2cf7d2649900f0efcd1a84e8fd3ba"}, - {file = "protobuf-4.22.1.tar.gz", hash = "sha256:dce7a55d501c31ecf688adb2f6c3f763cf11bc0be815d1946a84d74772ab07a7"}, + {file = "protobuf-4.22.3-cp310-abi3-win32.whl", hash = "sha256:8b54f56d13ae4a3ec140076c9d937221f887c8f64954673d46f63751209e839a"}, + {file = "protobuf-4.22.3-cp310-abi3-win_amd64.whl", hash = "sha256:7760730063329d42a9d4c4573b804289b738d4931e363ffbe684716b796bde51"}, + {file = "protobuf-4.22.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:d14fc1a41d1a1909998e8aff7e80d2a7ae14772c4a70e4bf7db8a36690b54425"}, + {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:70659847ee57a5262a65954538088a1d72dfc3e9882695cab9f0c54ffe71663b"}, + {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:13233ee2b9d3bd9a5f216c1fa2c321cd564b93d8f2e4f521a85b585447747997"}, + {file = "protobuf-4.22.3-cp37-cp37m-win32.whl", hash = "sha256:ecae944c6c2ce50dda6bf76ef5496196aeb1b85acb95df5843cd812615ec4b61"}, + {file = "protobuf-4.22.3-cp37-cp37m-win_amd64.whl", hash = "sha256:d4b66266965598ff4c291416be429cef7989d8fae88b55b62095a2331511b3fa"}, + {file = "protobuf-4.22.3-cp38-cp38-win32.whl", hash = "sha256:f08aa300b67f1c012100d8eb62d47129e53d1150f4469fd78a29fa3cb68c66f2"}, + {file = "protobuf-4.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:f2f4710543abec186aee332d6852ef5ae7ce2e9e807a3da570f36de5a732d88e"}, + {file = "protobuf-4.22.3-cp39-cp39-win32.whl", hash = "sha256:7cf56e31907c532e460bb62010a513408e6cdf5b03fb2611e4b67ed398ad046d"}, + {file = "protobuf-4.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:e0e630d8e6a79f48c557cd1835865b593d0547dce221c66ed1b827de59c66c97"}, + {file = "protobuf-4.22.3-py3-none-any.whl", hash = "sha256:52f0a78141078077cfe15fe333ac3e3a077420b9a3f5d1bf9b5fe9d286b4d881"}, + {file = "protobuf-4.22.3.tar.gz", hash = "sha256:23452f2fdea754a8251d0fc88c0317735ae47217e0d27bf330a30eec2848811a"}, ] [[package]] @@ -1333,48 +1322,48 @@ files = [ [[package]] name = "pydantic" -version = "1.10.6" +version = "1.10.7" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9289065611c48147c1dd1fd344e9d57ab45f1d99b0fb26c51f1cf72cd9bcd31"}, - {file = "pydantic-1.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c32b6bba301490d9bb2bf5f631907803135e8085b6aa3e5fe5a770d46dd0160"}, - {file = "pydantic-1.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd9b9e98068fa1068edfc9eabde70a7132017bdd4f362f8b4fd0abed79c33083"}, - {file = "pydantic-1.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c84583b9df62522829cbc46e2b22e0ec11445625b5acd70c5681ce09c9b11c4"}, - {file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b41822064585fea56d0116aa431fbd5137ce69dfe837b599e310034171996084"}, - {file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61f1f08adfaa9cc02e0cbc94f478140385cbd52d5b3c5a657c2fceb15de8d1fb"}, - {file = "pydantic-1.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:32937835e525d92c98a1512218db4eed9ddc8f4ee2a78382d77f54341972c0e7"}, - {file = "pydantic-1.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bbd5c531b22928e63d0cb1868dee76123456e1de2f1cb45879e9e7a3f3f1779b"}, - {file = "pydantic-1.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e277bd18339177daa62a294256869bbe84df1fb592be2716ec62627bb8d7c81d"}, - {file = "pydantic-1.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f15277d720aa57e173954d237628a8d304896364b9de745dcb722f584812c7"}, - {file = "pydantic-1.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b243b564cea2576725e77aeeda54e3e0229a168bc587d536cd69941e6797543d"}, - {file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3ce13a558b484c9ae48a6a7c184b1ba0e5588c5525482681db418268e5f86186"}, - {file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ac1cd4deed871dfe0c5f63721e29debf03e2deefa41b3ed5eb5f5df287c7b70"}, - {file = "pydantic-1.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:b1eb6610330a1dfba9ce142ada792f26bbef1255b75f538196a39e9e90388bf4"}, - {file = "pydantic-1.10.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ca83739c1263a044ec8b79df4eefc34bbac87191f0a513d00dd47d46e307a65"}, - {file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea4e2a7cb409951988e79a469f609bba998a576e6d7b9791ae5d1e0619e1c0f2"}, - {file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53de12b4608290992a943801d7756f18a37b7aee284b9ffa794ee8ea8153f8e2"}, - {file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:60184e80aac3b56933c71c48d6181e630b0fbc61ae455a63322a66a23c14731a"}, - {file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:415a3f719ce518e95a92effc7ee30118a25c3d032455d13e121e3840985f2efd"}, - {file = "pydantic-1.10.6-cp37-cp37m-win_amd64.whl", hash = "sha256:72cb30894a34d3a7ab6d959b45a70abac8a2a93b6480fc5a7bfbd9c935bdc4fb"}, - {file = "pydantic-1.10.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3091d2eaeda25391405e36c2fc2ed102b48bac4b384d42b2267310abae350ca6"}, - {file = "pydantic-1.10.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:751f008cd2afe812a781fd6aa2fb66c620ca2e1a13b6a2152b1ad51553cb4b77"}, - {file = "pydantic-1.10.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12e837fd320dd30bd625be1b101e3b62edc096a49835392dcf418f1a5ac2b832"}, - {file = "pydantic-1.10.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d92831d0115874d766b1f5fddcdde0c5b6c60f8c6111a394078ec227fca6d"}, - {file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:476f6674303ae7965730a382a8e8d7fae18b8004b7b69a56c3d8fa93968aa21c"}, - {file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3a2be0a0f32c83265fd71a45027201e1278beaa82ea88ea5b345eea6afa9ac7f"}, - {file = "pydantic-1.10.6-cp38-cp38-win_amd64.whl", hash = "sha256:0abd9c60eee6201b853b6c4be104edfba4f8f6c5f3623f8e1dba90634d63eb35"}, - {file = "pydantic-1.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6195ca908045054dd2d57eb9c39a5fe86409968b8040de8c2240186da0769da7"}, - {file = "pydantic-1.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43cdeca8d30de9a897440e3fb8866f827c4c31f6c73838e3a01a14b03b067b1d"}, - {file = "pydantic-1.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c19eb5163167489cb1e0161ae9220dadd4fc609a42649e7e84a8fa8fff7a80f"}, - {file = "pydantic-1.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:012c99a9c0d18cfde7469aa1ebff922e24b0c706d03ead96940f5465f2c9cf62"}, - {file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:528dcf7ec49fb5a84bf6fe346c1cc3c55b0e7603c2123881996ca3ad79db5bfc"}, - {file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:163e79386c3547c49366e959d01e37fc30252285a70619ffc1b10ede4758250a"}, - {file = "pydantic-1.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:189318051c3d57821f7233ecc94708767dd67687a614a4e8f92b4a020d4ffd06"}, - {file = "pydantic-1.10.6-py3-none-any.whl", hash = "sha256:acc6783751ac9c9bc4680379edd6d286468a1dc8d7d9906cd6f1186ed682b2b0"}, - {file = "pydantic-1.10.6.tar.gz", hash = "sha256:cf95adb0d1671fc38d8c43dd921ad5814a735e7d9b4d9e437c088002863854fd"}, + {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, + {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, + {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, + {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, + {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, + {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, + {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, + {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, + {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, + {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, + {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, + {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, + {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, + {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, + {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, + {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, + {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, + {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, + {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, + {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, + {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, + {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, + {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, + {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, + {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, + {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, + {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, + {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, + {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, + {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, + {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, + {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, + {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, + {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, + {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, + {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, ] [package.dependencies] @@ -1386,43 +1375,43 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.11.1" +version = "1.12.0" description = "Python bindings for libgit2." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pygit2-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:263e05ac655a4ce0a1083aaaedfd0a900b8dee2c3bb3ecf4f4e504a404467d1f"}, - {file = "pygit2-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ee6b4a0e181c576cdb64b1568bfbff3d1c2cd7e99808f578c8b08875c0f43739"}, - {file = "pygit2-1.11.1-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:d1b5fcaac1f29337f2d1465fa095e2e375b76a06385bda9391cb418c7937fb54"}, - {file = "pygit2-1.11.1-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:96ff745d3199909d06cab5e419a6b953be99992414a08ec4dddb682f395de8f1"}, - {file = "pygit2-1.11.1-cp310-cp310-win32.whl", hash = "sha256:b3c8726f0c9a2b0e04aac37b18027c58c2697b9c021d3458b28bc250b9b6aecf"}, - {file = "pygit2-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:f42409d25bbfc090fd1af1f5f47584d7e0c4212b037a7f86639a02c30420c6ee"}, - {file = "pygit2-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29f89d96bbb404ca1566418463521039903094fad2f81a76d7083810d2ea3aad"}, - {file = "pygit2-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d5c158b9430c5e76ca728b1a214bf21d355af6ac6e2da86ed17775b870b6c6eb"}, - {file = "pygit2-1.11.1-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:6c3434b143e7570ec45cd1a0e344fe7a12e64b99e7155fa38b74f724c8fc243c"}, - {file = "pygit2-1.11.1-cp311-cp311-manylinux_2_24_x86_64.whl", hash = "sha256:550aa503c86ef0061ce64d61c3672b15b500c2b1e4224c405acecfac2211b5d9"}, - {file = "pygit2-1.11.1-cp311-cp311-win32.whl", hash = "sha256:f270f86a0185ca2064e1aa6b8db3bb677b1bf76ee35f48ca5ce28a921fad5632"}, - {file = "pygit2-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:56b9deeab214653805214f05337f5e9552b47bf268c285551f20ea51a6056c3e"}, - {file = "pygit2-1.11.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3c5838e6516abc4384498f4b4c7f88578221596dc2ba8db2320ff2cfebe9787e"}, - {file = "pygit2-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a886aab5aae8d8db572e20b9f56c13cd506775265222ea7f35b2c781e4fa3a5e"}, - {file = "pygit2-1.11.1-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:3be4534180edd53e3e1da93c5b091975566bfdffdc73f21930d79fef096a25d2"}, - {file = "pygit2-1.11.1-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:4d6209c703764ae0ba57b17038482f3e54f432f80f88ccd490d7f8b70b167db6"}, - {file = "pygit2-1.11.1-cp38-cp38-win32.whl", hash = "sha256:ddb032fa71d4b4a64bf101e37eaa21f5369f20a862b5e34bbc33854a3a35f641"}, - {file = "pygit2-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8de0091e5eeaea2004f63f7dcb4540780f2124f68c0bcb670ae0fa9ada8bf66"}, - {file = "pygit2-1.11.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b44674e53efa9eca36e44f2f3d1a29e53e78649ba13105ae0b037d557f2c076"}, - {file = "pygit2-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0170f31c2efb15f6779689df328c05a8005ecb2b92784a37ff967d713cdafe82"}, - {file = "pygit2-1.11.1-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:960a55ff78f48887a7aa8ece952aad0f52f0a2ba1ad7bddd7064fbbefd85dfbb"}, - {file = "pygit2-1.11.1-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:df722c90fb54a42fa019dcf8d8f82961c3099c3024f1fda46c53e0886ff8f0f3"}, - {file = "pygit2-1.11.1-cp39-cp39-win32.whl", hash = "sha256:3b091e7fd00dd2a2cd3a6b5e235b6cbfbc1c07f15ee83a5cb3f188e1d6d1bca1"}, - {file = "pygit2-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:da040dc28800831bcbefef0850466739f103bfc769d952bd10c449646d52ce8f"}, - {file = "pygit2-1.11.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:585daa3956f1dc10d08e3459c20b57be42c7f9c0fbde21e797b3a00b5948f061"}, - {file = "pygit2-1.11.1-pp38-pypy38_pp73-manylinux_2_24_aarch64.whl", hash = "sha256:273878adeced2aec7885745b73fffb91a8e67868c105bf881b61008d42497ad6"}, - {file = "pygit2-1.11.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:48cfd72283a08a9226aca115870799ee92898d692699f541a3b3f519805108ec"}, - {file = "pygit2-1.11.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a9ca4cb2481d2df14d23c765facef325f717d9a3966a986b86e88d92eef11929"}, - {file = "pygit2-1.11.1-pp39-pypy39_pp73-manylinux_2_24_aarch64.whl", hash = "sha256:d5f64a424d9123b047458b0107c5dd33559184b56a1f58b10056ea5cbac74360"}, - {file = "pygit2-1.11.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f13e190cc080bde093138e12bcb609500276227e3e8e8bd8765a2fd49ae2efb8"}, - {file = "pygit2-1.11.1.tar.gz", hash = "sha256:793f583fd33620f0ac38376db0f57768ef2922b89b459e75b1ac440377eb64ec"}, + {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b44a3b38e62dbf8cb559a40d2b39506a638d13542502ddb927f1c05565048f27"}, + {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:834cf5b54d9b49c562669ec986be54c7915585638690c11f1dc4e6a55bc5d79d"}, + {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecb096cdbbf142d8787cf879ab927fc9777d36580d2e5758d02c9474a3b015c"}, + {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15620696743ffac71cfdaf270944d9363b70442c1fbe96f5e4a69639c2fe7c23"}, + {file = "pygit2-1.12.0-cp310-cp310-win32.whl", hash = "sha256:de21194e18e4d93f793740b2b979dbe9dd6607f342a4fad3ecedeaf26ec743df"}, + {file = "pygit2-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:0a9d49f71bec7c4f2ff8273e0c7caba4b2f21bfc56e2071e429028b20ab9d762"}, + {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a428970b44827b703cc3267de8d71648f491546d5b9276505ef5f232a921a34e"}, + {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2bb7b674124a38b12a5aaacca3b8c1e29674f3b46cb907af0b3ba75d90e5952a"}, + {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de46940b46bee12f4c938aadf4f59617798f704c8ac5f08b5a84914459d604be"}, + {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fbfb3ebe7f57fe7873d86e84b476869f407d6bb204a39a3e7d04e4a7f0e43c1"}, + {file = "pygit2-1.12.0-cp311-cp311-win32.whl", hash = "sha256:db98978d559d6e84187d463fb3aa83cf6120dadf62058e3d05a97457f9f27247"}, + {file = "pygit2-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8734a44e0dab8a5e6668e4a926f7171b59b87d65981bd3732efba57c327cec6d"}, + {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1bb73ffb345400f8c6fe391431e06b93e26bc4d2048b1ac3f7c54dae5f7b6dc2"}, + {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fdeaf1631803616d303b808cd644ee17164fb675241ab1b0bb243d4a3d3de59f"}, + {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652b3f0510ad21ec6275b246aa3e7a2e20f2f9c37a9844804887fabc2db49ca3"}, + {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2419cd1034bf593847466b188a65bd9d512e13b7da0e8c3a74b487d8014a6c1"}, + {file = "pygit2-1.12.0-cp38-cp38-win32.whl", hash = "sha256:6a445a537de152364b334e73047af9225fe8c6f54c7d815d8c751cb23b79cbef"}, + {file = "pygit2-1.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:ad1cca4533beee034277fe01f0d4029da40d2bd1a944a8cd17bffccc0331cc53"}, + {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ad7b21e35e759d033dede5dc4971f6c9b3408f9096b26fabc7cedb49e319680"}, + {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e303aa9d7de6039cc4450a1fbd5911fab22867dc4e05f148b0cd7c56f7b84b2"}, + {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:869e68cfae7e0e00a799efa26bba3f829bdeafa1462225a7db1317dacb4e6a4e"}, + {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c779c15bf6ebce986cb753c8113ccfb329c12d4a73b303ee7ac2c8961288b8cd"}, + {file = "pygit2-1.12.0-cp39-cp39-win32.whl", hash = "sha256:c6ac2fd8ed30016235b06aacc28e5f10e1a17d0f02eab35f5f503138bbee763d"}, + {file = "pygit2-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2483e4aa8bb4290ab157d575b00b830528c669869d710646a1d4af7209d59e81"}, + {file = "pygit2-1.12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8fca4ca59928436fca5df3d54a7d591e7aa12ebaeaeb1801a99e09970fb8f1d3"}, + {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0746791741ba1879faafd12be0b7fb8edd06633508bbf8aabfd28415f1c0b13f"}, + {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b9d8b7e1d143415d462d82fc5d9dd5922c527474871c7b3c3a8aec009b74b1c"}, + {file = "pygit2-1.12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:69ee34f8b77fc60dcf93524fd843eacc416be906b7471746d2ee8214d5a591a0"}, + {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c290dadcf42e9d857ea20c37781168de1d1ac31b196b450400f962279aa405f"}, + {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d9bdd2837f9f1cacb571889ac4226844a41476509c325732af06b622293782"}, + {file = "pygit2-1.12.0.tar.gz", hash = "sha256:e9440d08665e35278989939590a53f37a938eada4f9446844930aa2ee30d73be"}, ] [package.dependencies] @@ -1430,18 +1419,17 @@ cffi = ">=1.9.1" [[package]] name = "pytest" -version = "7.2.2" +version = "7.3.1" description = "pytest: simple powerful testing with Python" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"}, - {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"}, + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" @@ -1450,7 +1438,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -1559,18 +1547,18 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc [[package]] name = "redis" -version = "4.5.1" +version = "4.5.4" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.1-py3-none-any.whl", hash = "sha256:5deb072d26e67d2be1712603bfb7947ec3431fb0eec9c578994052e33035af6d"}, - {file = "redis-4.5.1.tar.gz", hash = "sha256:1eec3741cda408d3a5f84b78d089c8b8d895f21b3b050988351e925faf202864"}, + {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, + {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, ] [package.dependencies] -async-timeout = ">=4.0.2" +async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1618,14 +1606,14 @@ idna2008 = ["idna"] [[package]] name = "setuptools" -version = "67.6.0" +version = "67.7.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.6.0-py3-none-any.whl", hash = "sha256:b78aaa36f6b90a074c1fa651168723acbf45d14cb1196b6f02c0fd07f17623b2"}, - {file = "setuptools-67.6.0.tar.gz", hash = "sha256:2ee892cd5f29f3373097f5a814697e397cf3ce313616df0af11231e2ad118077"}, + {file = "setuptools-67.7.1-py3-none-any.whl", hash = "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67"}, + {file = "setuptools-67.7.1.tar.gz", hash = "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c"}, ] [package.extras] @@ -1671,53 +1659,53 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.46" +version = "1.4.47" description = "Database Abstraction Library" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.46-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c7a46639ba058d320c9f53a81db38119a74b8a7a1884df44d09fbe807d028aaf"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27m-win32.whl", hash = "sha256:c04144a24103135ea0315d459431ac196fe96f55d3213bfd6d39d0247775c854"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27m-win_amd64.whl", hash = "sha256:7b81b1030c42b003fc10ddd17825571603117f848814a344d305262d370e7c34"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:939f9a018d2ad04036746e15d119c0428b1e557470361aa798e6e7d7f5875be0"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b7f4b6aa6e87991ec7ce0e769689a977776db6704947e562102431474799a857"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf17ac9a61e7a3f1c7ca47237aac93cabd7f08ad92ac5b96d6f8dea4287fc1"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7f8267682eb41a0584cf66d8a697fef64b53281d01c93a503e1344197f2e01fe"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cb0ad8a190bc22d2112001cfecdec45baffdf41871de777239da6a28ed74b6"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-win32.whl", hash = "sha256:5f752676fc126edc1c4af0ec2e4d2adca48ddfae5de46bb40adbd3f903eb2120"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-win_amd64.whl", hash = "sha256:31de1e2c45e67a5ec1ecca6ec26aefc299dd5151e355eb5199cd9516b57340be"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d68e1762997bfebf9e5cf2a9fd0bcf9ca2fdd8136ce7b24bbd3bbfa4328f3e4a"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d112b0f3c1bc5ff70554a97344625ef621c1bfe02a73c5d97cac91f8cd7a41e"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69fac0a7054d86b997af12dc23f581cf0b25fb1c7d1fed43257dee3af32d3d6d"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-win32.whl", hash = "sha256:887865924c3d6e9a473dc82b70977395301533b3030d0f020c38fd9eba5419f2"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-win_amd64.whl", hash = "sha256:984ee13543a346324319a1fb72b698e521506f6f22dc37d7752a329e9cd00a32"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:9167d4227b56591a4cc5524f1b79ccd7ea994f36e4c648ab42ca995d28ebbb96"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d61e9ecc849d8d44d7f80894ecff4abe347136e9d926560b818f6243409f3c86"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3ec187acf85984263299a3f15c34a6c0671f83565d86d10f43ace49881a82718"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9883f5fae4fd8e3f875adc2add69f8b945625811689a6c65866a35ee9c0aea23"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-win32.whl", hash = "sha256:535377e9b10aff5a045e3d9ada8a62d02058b422c0504ebdcf07930599890eb0"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-win_amd64.whl", hash = "sha256:18cafdb27834fa03569d29f571df7115812a0e59fd6a3a03ccb0d33678ec8420"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:a1ad90c97029cc3ab4ffd57443a20fac21d2ec3c89532b084b073b3feb5abff3"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4847f4b1d822754e35707db913396a29d874ee77b9c3c3ef3f04d5a9a6209618"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5a99282848b6cae0056b85da17392a26b2d39178394fc25700bcf967e06e97a"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4b1cc7835b39835c75cf7c20c926b42e97d074147c902a9ebb7cf2c840dc4e2"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-win32.whl", hash = "sha256:c522e496f9b9b70296a7675272ec21937ccfc15da664b74b9f58d98a641ce1b6"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-win_amd64.whl", hash = "sha256:ae067ab639fa499f67ded52f5bc8e084f045d10b5ac7bb928ae4ca2b6c0429a5"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:e3c1808008124850115a3f7e793a975cfa5c8a26ceeeb9ff9cbb4485cac556df"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d164df3d83d204c69f840da30b292ac7dc54285096c6171245b8d7807185aa"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b33ffbdbbf5446cf36cd4cc530c9d9905d3c2fe56ed09e25c22c850cdb9fac92"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d94682732d1a0def5672471ba42a29ff5e21bb0aae0afa00bb10796fc1e28dd"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-win32.whl", hash = "sha256:f8cb80fe8d14307e4124f6fad64dfd87ab749c9d275f82b8b4ec84c84ecebdbe"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-win_amd64.whl", hash = "sha256:07e48cbcdda6b8bc7a59d6728bd3f5f574ffe03f2c9fb384239f3789c2d95c2e"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1b1e5e96e2789d89f023d080bee432e2fef64d95857969e70d3cadec80bd26f0"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3714e5b33226131ac0da60d18995a102a17dddd42368b7bdd206737297823ad"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:955162ad1a931fe416eded6bb144ba891ccbf9b2e49dc7ded39274dd9c5affc5"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6e4cb5c63f705c9d546a054c60d326cbde7421421e2d2565ce3e2eee4e1a01f"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-win32.whl", hash = "sha256:51e1ba2884c6a2b8e19109dc08c71c49530006c1084156ecadfaadf5f9b8b053"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-win_amd64.whl", hash = "sha256:315676344e3558f1f80d02535f410e80ea4e8fddba31ec78fe390eff5fb8f466"}, - {file = "SQLAlchemy-1.4.46.tar.gz", hash = "sha256:6913b8247d8a292ef8315162a51931e2b40ce91681f1b6f18f697045200c4a30"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:dcfb480bfc9e1fab726003ae00a6bfc67a29bad275b63a4e36d17fe7f13a624e"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28fda5a69d6182589892422c5a9b02a8fd1125787aab1d83f1392aa955bf8d0a"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-win32.whl", hash = "sha256:45e799c1a41822eba6bee4e59b0e38764e1a1ee69873ab2889079865e9ea0e23"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-win_amd64.whl", hash = "sha256:10edbb92a9ef611f01b086e271a9f6c1c3e5157c3b0c5ff62310fb2187acbd4a"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7a4df53472c9030a8ddb1cce517757ba38a7a25699bbcabd57dcc8a5d53f324e"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:511d4abc823152dec49461209607bbfb2df60033c8c88a3f7c93293b8ecbb13d"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbe57f39f531c5d68d5594ea4613daa60aba33bb51a8cc42f96f17bbd6305e8d"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca8ab6748e3ec66afccd8b23ec2f92787a58d5353ce9624dccd770427ee67c82"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299b5c5c060b9fbe51808d0d40d8475f7b3873317640b9b7617c7f988cf59fda"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-win32.whl", hash = "sha256:684e5c773222781775c7f77231f412633d8af22493bf35b7fa1029fdf8066d10"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-win_amd64.whl", hash = "sha256:2bba39b12b879c7b35cde18b6e14119c5f1a16bd064a48dd2ac62d21366a5e17"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:795b5b9db573d3ed61fae74285d57d396829e3157642794d3a8f72ec2a5c719b"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:989c62b96596b7938cbc032e39431e6c2d81b635034571d6a43a13920852fb65"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b67bda733da1dcdccaf354e71ef01b46db483a4f6236450d3f9a61efdba35a"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-win32.whl", hash = "sha256:9a198f690ac12a3a807e03a5a45df6a30cd215935f237a46f4248faed62e69c8"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-win_amd64.whl", hash = "sha256:03be6f3cb66e69fb3a09b5ea89d77e4bc942f3bf84b207dba84666a26799c166"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:16ee6fea316790980779268da47a9260d5dd665c96f225d28e7750b0bb2e2a04"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:557675e0befafa08d36d7a9284e8761c97490a248474d778373fb96b0d7fd8de"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb2797fee8a7914fb2c3dc7de404d3f96eb77f20fc60e9ee38dc6b0ca720f2c2"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28297aa29e035f29cba6b16aacd3680fbc6a9db682258d5f2e7b49ec215dbe40"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-win32.whl", hash = "sha256:998e782c8d9fd57fa8704d149ccd52acf03db30d7dd76f467fd21c1c21b414fa"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-win_amd64.whl", hash = "sha256:dde4d02213f1deb49eaaf8be8a6425948963a7af84983b3f22772c63826944de"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e98ef1babe34f37f443b7211cd3ee004d9577a19766e2dbacf62fce73c76245a"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14a3879853208a242b5913f3a17c6ac0eae9dc210ff99c8f10b19d4a1ed8ed9b"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7120a2f72599d4fed7c001fa1cbbc5b4d14929436135768050e284f53e9fbe5e"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:048509d7f3ac27b83ad82fd96a1ab90a34c8e906e4e09c8d677fc531d12c23c5"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-win32.whl", hash = "sha256:6572d7c96c2e3e126d0bb27bfb1d7e2a195b68d951fcc64c146b94f088e5421a"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-win_amd64.whl", hash = "sha256:a6c3929df5eeaf3867724003d5c19fed3f0c290f3edc7911616616684f200ecf"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71d4bf7768169c4502f6c2b0709a02a33703544f611810fb0c75406a9c576ee1"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd45c60cc4f6d68c30d5179e2c2c8098f7112983532897566bb69c47d87127d3"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fdbb8e9d4e9003f332a93d6a37bca48ba8095086c97a89826a136d8eddfc455"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f216a51451a0a0466e082e163591f6dcb2f9ec182adb3f1f4b1fd3688c7582c"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-win32.whl", hash = "sha256:bd988b3362d7e586ef581eb14771bbb48793a4edb6fcf62da75d3f0f3447060b"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-win_amd64.whl", hash = "sha256:32ab09f2863e3de51529aa84ff0e4fe89a2cb1bfbc11e225b6dbc60814e44c94"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:07764b240645627bc3e82596435bd1a1884646bfc0721642d24c26b12f1df194"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e2a42017984099ef6f56438a6b898ce0538f6fadddaa902870c5aa3e1d82583"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6b6d807c76c20b4bc143a49ad47782228a2ac98bdcdcb069da54280e138847fc"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a94632ba26a666e7be0a7d7cc3f7acab622a04259a3aa0ee50ff6d44ba9df0d"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-win32.whl", hash = "sha256:f80915681ea9001f19b65aee715115f2ad310730c8043127cf3e19b3009892dd"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-win_amd64.whl", hash = "sha256:fc700b862e0a859a37faf85367e205e7acaecae5a098794aff52fdd8aea77b12"}, + {file = "SQLAlchemy-1.4.47.tar.gz", hash = "sha256:95fc02f7fc1f3199aaa47a8a757437134cf618e9d994c84effd53f530c38586f"}, ] [package.dependencies] @@ -1819,14 +1807,14 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.6" +version = "0.11.7" description = "Style preserving TOML library" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"}, - {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"}, + {file = "tomlkit-0.11.7-py3-none-any.whl", hash = "sha256:5325463a7da2ef0c6bbfefb62a3dc883aebe679984709aee32a317907d0a8d3c"}, + {file = "tomlkit-0.11.7.tar.gz", hash = "sha256:f392ef70ad87a672f02519f99967d28a4d3047133e2d1df936511465fbb3791d"}, ] [[package]] @@ -1860,14 +1848,14 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.21.0" +version = "0.21.1" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "uvicorn-0.21.0-py3-none-any.whl", hash = "sha256:e69e955cb621ae7b75f5590a814a4fcbfb14cb8f44a36dfe3c5c75ab8aee3ad5"}, - {file = "uvicorn-0.21.0.tar.gz", hash = "sha256:8635a388062222082f4b06225b867b74a7e4ef942124453d4d1d1a5cb3750932"}, + {file = "uvicorn-0.21.1-py3-none-any.whl", hash = "sha256:e47cac98a6da10cd41e6fd036d472c6f58ede6c5dbee3dbee3ef7a100ed97742"}, + {file = "uvicorn-0.21.1.tar.gz", hash = "sha256:0fac9cb342ba099e0d582966005f3fdba5b0290579fed4a6266dc702ca7bb032"}, ] [package.dependencies] From 97d0eac303190f4af34d0814c77757e602f1384c Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 22 Apr 2023 11:39:00 +0200 Subject: [PATCH 1733/1891] housekeep: copy static files we copy static files used by PHP and Python versions into /static preparation work for the removal of the PHP version Signed-off-by: moson-mo --- aurweb/asgi.py | 6 +- static/css/archnavbar/archlogo.png | Bin 0 -> 5359 bytes static/css/archnavbar/archnavbar.css | 26 + static/css/archnavbar/aurlogo.png | Bin 0 -> 5997 bytes static/css/archweb.css | 1255 ++++++++++++++++++++++++ static/css/aurweb.css | 292 ++++++ static/css/cgit.css | 866 ++++++++++++++++ static/images/ICON-LICENSE | 26 + static/images/action-undo.min.svg | 3 + static/images/action-undo.svg | 32 + static/images/ajax-loader.gif | Bin 0 -> 723 bytes static/images/favicon.ico | Bin 0 -> 575 bytes static/images/pencil.min.svg | 3 + static/images/pencil.svg | 55 ++ static/images/pin.min.svg | 1 + static/images/pin.svg | 3 + static/images/rss.svg | 3 + static/images/unpin.min.svg | 1 + static/images/unpin.svg | 4 + static/images/x.min.svg | 3 + static/images/x.svg | 31 + static/js/comment-edit.js | 61 ++ static/js/copy.js | 9 + static/js/typeahead-home.js | 6 + static/js/typeahead-pkgbase-merge.js | 6 + static/js/typeahead-pkgbase-request.js | 36 + static/js/typeahead.js | 151 +++ 27 files changed, 2874 insertions(+), 5 deletions(-) create mode 100644 static/css/archnavbar/archlogo.png create mode 100644 static/css/archnavbar/archnavbar.css create mode 100644 static/css/archnavbar/aurlogo.png create mode 100644 static/css/archweb.css create mode 100644 static/css/aurweb.css create mode 100644 static/css/cgit.css create mode 100644 static/images/ICON-LICENSE create mode 100644 static/images/action-undo.min.svg create mode 100644 static/images/action-undo.svg create mode 100644 static/images/ajax-loader.gif create mode 100644 static/images/favicon.ico create mode 100644 static/images/pencil.min.svg create mode 100644 static/images/pencil.svg create mode 100644 static/images/pin.min.svg create mode 100644 static/images/pin.svg create mode 100644 static/images/rss.svg create mode 100644 static/images/unpin.min.svg create mode 100644 static/images/unpin.svg create mode 100644 static/images/x.min.svg create mode 100644 static/images/x.svg create mode 100644 static/js/comment-edit.js create mode 100644 static/js/copy.js create mode 100644 static/js/typeahead-home.js create mode 100644 static/js/typeahead-pkgbase-merge.js create mode 100644 static/js/typeahead-pkgbase-request.js create mode 100644 static/js/typeahead.js diff --git a/aurweb/asgi.py b/aurweb/asgi.py index b6578f33..eb02413b 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -79,11 +79,7 @@ async def app_startup(): "endpoint is disabled." ) - app.mount("/static/css", StaticFiles(directory="web/html/css"), name="static_css") - app.mount("/static/js", StaticFiles(directory="web/html/js"), name="static_js") - app.mount( - "/static/images", StaticFiles(directory="web/html/images"), name="static_images" - ) + app.mount("/static", StaticFiles(directory="static"), name="static_files") # Add application routes. def add_router(module): diff --git a/static/css/archnavbar/archlogo.png b/static/css/archnavbar/archlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2cd40fb499b2b37651ea67ec6f3b4400e3d157 GIT binary patch literal 5359 zcmZ{IS2!Hp_w|^fM(@4%HcCVgz4tPMgkaQ&HhM3EFiH?fM506sq7yX?BLq=`i12C| zL~o;a{(hI=#rK@O&w9?>10<3$laUEN!Q#6008Pn zbXOpBG|m5lHpl75-vVhpC(a!4x$h*`V2lakNUt?{-fw^e?ODm zN2l+hb*}S!PafO;yvB^)?EDQ@iLzn>_b!b9fT^^f*w@{?%2`uO4TKQ2Smxg5ikKW2 zQ*A?S8C;#@KdJ0k753J9XG*F&MOl%LT4?kK&;(>rVhi9U1?;<+SJ-zbGm)>gYnJLH z%w}?U0WeGe;1*6<3W^4axh(3Rm06q~vz;20p9m)iop2}sG)ey@z5ZEzGBay7^^(hv zOFvOQpz-HtC(no`dwszCljyn5{FA6S0{1JalqoLl^-)5KLk=qdBTC!pRYl~Zu4~eY z`jm=y&G7{n7Ek2g)hM=KE?#h6uBwFA4#F~l!gQh1QhEZ zVRX6TH*Dt7a2hD-{!i`M-_>j)z6g%ca~xCE?`N$AK|HXr$u$Q&P^B$#;&T%7mJM zuo8+h+l1P5KqsF_FkI5xbvE#m)@W=uI^t;J3`eFie;MX?$(u}bW!*u-&#nH?kt^%d zx|YaA-ExCV9U&V&;SIrCEb(@465tV50>|q>SR zoU@zOxr=q~2E8QP8G}nzeV$%*DuQQq|Tc`gx!LmYDeG= zxKY+=D~=fjPC4|=pTYudRG(20hFb0uLqD#-tI}K=Ka;(+@i-pI>=l)p6i$ z&9-~lq-@(Seb}1YT!Fy^x8xB-=ujz?L)W!@=ax`=LLfUDA2ZdD#!`(EzFdkzMFYWBytXn;~HGS8jwD~p^JH9 z(yY!Xaf-vSL#cK0=xru5#$e>dlTyIaB33aiIEI-;90sCX`viJ zA0i;5`@2n-HiiSnJS{XdI4WF@Dm#>@7=~DhfH|<5T9m?3X2M$XEY_)Boxvz8R1=d+ zB`^*2^JpfC?3HnEWQFUvg3{}9;A~0gk4%RM(^LTtAnciRWj)K8EL1z=nCL`vFJ0_8 z!lUO+=S6*pjK~uS5pwKHtY(>*-;1v^W&;MohRce{DXIOkviW#BfZjD`@$7ik~xbg$=6paDPdGZM^={xaJ@@q2g3F_z3%7tZk`C zur_-ZmzZiRoB!k5KDqsu&zw`4dhk;}>?d+hUXaSqbmfQjyn1xNf=oQU%Ay=+y!NUKi@<_oc32aa9U%msvJaVpldpOC0k^?27Mr#?k`zim@2j!tQM8L z>5NktPROk;Vy)csIG|uk19*2kOGxmT0O-PQd40OA%-8}209F~HZf=Td#(;;6XTF|h zGG5=G!a^xRAc~u#SS3Xwrx^tTPhb|}T=HW#cvOeJbg_ZtCNaD3TxyjDGOH`2F&N~i zK7%H?&d0K(b}N}2LKXZU=#8)o@P$KnIRtT-efg^}&%OhchdWNi^uZJJ5~ zsROEr60OfOob6dz%ll^ zw`BJj(gPB=SuLcx+ZjhamX2)_&8oO;QyKpP14>$%p2EHQWqkkVu`xg(V}oVi}Ri1z*S+I zg&vwS4$uun2<^C{X&aMF^DN3nO)lxHR>1oQ{Z?T`8iK%gj1M1j_B(}M{>u?&qPqCf z@uD>bS$InQJq`cN+P@oOa_&vEnx|U=u1hPu{XyV*CC>MBy&6G%>l26W*t=CBlXDDG z6=*#pihOP#lTE22?q`sZa3sigQ^t;7EsE0h^Jrtf7+{UX`CfGHD~LprH&0G2mS><_ zyZVj0jd5Wx@9sBtbgeo`9e}YJXj8`SWrhXbgC%E!X(`q$mp5gTKS>%Vl39a^@Fnh> zrQ}ro+g6k_&$ppZg>ZU`g8U#2p%uT|JE^pGL@X@KOl6nXY1 zV10N_gQU6nR({-gHmuQc?o@7=>Vm(tjfji_s`T&NmFf5I7ZHuF&zOH)4_MS*J1a5m zj^ydAYi5p=oW5!qyL@3mnsD;>k10{nJhlr|3H{Ut`O+P9Pj*qF5;xUngQOxl>`5OT z&)Tz_Gd^M50N7Kn(8`Ba!k$|~2>J){l{t}mhqLb8Xs!=Mz(vm42#U*y-ogL-AGoQQ8XB4ez$vAk@nHI82! z8d9IJr16mXG{~R@PZ>x}nY`_B1tCNdc4powbO1}zff z9u12=;9MC{dh4p~e6-0|uF6$`Pj{xAt0Jr+{39w6dq}am5a(PV>Um-HRfEPPS(G*8 z$>LlpE%mSB?%8W)=@7LK^+u-e%_XBp-gtU|1On9feMMGxLNVz3l0l#Z3wFJUrNZNq z=)&0bq%9%iA`=U@3afIyi?UKitiEN7$7@|MhLB9j`y0^mougfz51B1v%7Z-$^ZfI} zwQvKT$?R|7l%b=L+n|c)ZRmSslV|r|ir*yXkw!=j;o4)`)&9i&vQr`V;o?N7*4H~GRuFf>EYM8 z75NO70;8S&Z%M)#lxvZ-#&%;@_oFzzNuu?^L#dErg-H6l?T#=CR>*qr2Eb5oAS$-@ zoE>VjIJo&!`uPMVZlxmZYekd=eC_k5UPV}Oh21VDP6mFwYue2SrxK|*7%OfVUP{Lv z7Bo(pkXOYoC0`Q$Sho|f75Vm$&E>1!MS3I*0bA3=k`Ptq=` zl*jVdmYB(g`_Havu^{x)3A!sO&}>gg5Ju%aw8 z(+7dG`wX8zE`;xWtj@Ubij)aeaF&b*7q5Q`Z~xCB_jWZqY}f9 zM}Pd%k?O0iHVeBp^{Oh54+%Wb2-_%_+x|9(b-|WRit}c1S4wB}MUelnUs-3h^6Frg zO7;Vl?oT<|9WI z)L({xmKW)r8PZaTJv->_F7ufCkdUk_BqyGHn~#)mOu!*2f>+oWe;qhvDVW%|*AkrR zayWjz;XR8b51uDI6FGJC4NKRFx5m9Y>Jzus5nG5Cf@hoBqcE(*=Ir#pclmAOe)M@2 zY!S#sdBv{GRi1=+VAzIO^2(O7+;kBPd+Z|GuYN*qfJY~^SL6Ev(d0jSf^2IT>)CNT zZOqG06m_S5M@gi7+;62DdcmB@|KU<9sJEIwx(XDPyb?&a1H>~(pjJx$s`>iHwm@^- zh!zD$RqscY>gW+nnFhN?DKq<;laZ)~N3zETIFxNm7^d7(t?+14rhU(;bbM*VOZ%#q zn(GTJgf2XNsNRAaXk)G===ivdH|CQ1DJhk#!=yN9+%k33o3K-4GdEp*XQ|{0J)n)t zTUfA*VW55-_bEY^pleU?%!MJBBgK8ZE+d*_Yk`vF+dT5^v^R!j_S}SPDTDiJ4?&(a zdc)daUl3HUDW{@wn4x6v>y}V|;WQ1pVny=fX%=Tx=-I7HeC4#0q!Cd0sM3e7iim?E zr7WdCd-HrNeH@ZKjYy)>XB@q|?n>!{etU;K*_GiBSDEmy0qk1e`FXOHeiKL%&%M+) z84ChG>x!ZQ%&yHHk!p)30$b1nh^Uz~G}Q0kz?9BQmgBy=9b#6FI6KVC%gc#Lgdfj8 zlf8g_RGi3+ql39R3HP<(a1aLVeycB!uGTgx@KHD+5XB+kEmcJeuV>BU-?lNBnVz=>k(&9qn^S z7K2hxxY;uFiO@8m`**ob>EWLwtBYq-B*Bhvd_c|b{kywN<`Ue${v}YPZI;N(=AMsp zzt1^8&0lz`)WB6GE>KH_W~`CJ@i=Fd0~3=aTlTL?Hczl?@$ z@BcaT9p-r6)8HIU)FCvs6%bfX!F*8Cl4U^mgjr53K-SB@l%^OGPh^%ysA(2-InjRn z$L4ZSPF6O)%j7mrM<%UT_P5z%%R(~R3>Bb?TCPj$qsIG3j1jdM5^PKT%K)ZkYU%22 z1FY>E0pB-&9$NH}opdQ%zkIw&ZP?oUs>HGwsnzl+n&H;4zXZ4K8iH(%P-W&KX`Mvp4;W6k)w(@UKYq)zF%33UvR9^Vdk;p ze$x>&*Dolow}vb2^iK)dv>3j$e1f8)W_(v<&u&_R%F8QT-6et_4ugjT&e^(?)N74! zr2@lX=dG9+Sa7}CgE(~DW}Y>ntw@+ubsO7+u?M(0S$DLMecn?v9e*-+#A%EEo@0ha zx1FYSOT>&~{e@o~9eQl@oW}S|=?ihQX2$xo?Hbho4LBM{?XUEs)~MWMDzsd_Ps+)0 zm$z=F_RZ-tIx4Az(0(TKH&Tul@?vg`BH_PBN0ag(jz+7MvRw$+cbVT)b^MMkF%N^0 zn5`K-mQgtGmis_K@Q}hlM3J)?0H`$WM2|iBb-}+ajxO6#NnsY(sC%|`T~uY-SX@1z zc^lz?q7d#;BCtY4ota^k=$|s_$$Mft&vLi!yeM$eeL2pU1KwfN)Z!}^#Df}xSuXc8 zTfCh8LxwYVEYH_>0H3#aLxqFxW-=j4V+dh50`aTcMAjU=$Hd*a56>BsM}a|~4`SbF z%r@~aN+OVEgjMv158JDSyJK%X8vjgDdw4FyHQamUm-I~e{67C1Q|Jw27am{KRPd4G z&e!7)(6SD2Mg+JhIQhBU0YDlm^*|gda~Civ83m}cf~>44^q~S2+5z&A{(l5sKF;p0 zq5pruh}}fmoq+j&9V~oY1A-BLE`Z?RUR4J?A{`Jpl*=BG%MU(F5+Sz{!V)16=3lFeiZt5(_0ZH-#a$v|q>+9uvDnZ60#RRUswf)x%7pUU@TJ6OOWbM)&`B92~4tQuME0y@Gmst2;XK94s^n zOY~5t;;Ej-k{P77BRBGneohUNW?QAO@!S)DzanT>G*-OhvoI?qWZM!lNM3EPB9`nD zyJBe`KY7x%L9a*_I#up|5gPmq^ZIK(9<@pGQpA!ffzE%TS%+q{ei-rjQdEk0!ZJry zTXd3-a8k#059OQ@U)ANA+YCd-I$O~0cy00o9b_mb!drm{T2yvd!cFcj(d*vdh^4#I zu;)d>&D~98cZtN-UmX|;Z--uuZ^PUt;@HIcP-(d@hIQ3!NfmFS-C@YgXA^P-DA@QQ z?v7PKM|sozZ~EcQ59IXp1f>Q9RmMcX5tBbMHy4wdO8x1}mx7|AuDW>38n(|`qaz~< zO+D6CtQ64-$%TX0aIG>dYrM;sjFr0S}w*ye$Eo(&BRtdf#+HTHu_Q0Vh8B{sZ} z_G0bK#O!QmJ{CHOHfts^3zoV1WD|7Ss=4Kg`htw{mel`go zHR0&!DEjCq_{$d>2}Tk}M@Q(xeSpF1*NB3GPUd3aDDp6{B3(q#ODyV0($~+0zZj7+ z5F>kOvd(cyoPV^n$y?jlAWtNce>b?TlhM#bw)kJH)eOrCH$EH>JhR#8P2!wxZfU8q z=^+7w!D(+@ot?v9aAGNvrHMJyQ}dgIp-_;Tvxu-T+CYnX7bX%Wsj#>>B1o-Cje*0% z{asXieE0eO{Oamz2ZYww*LS8ZP~K(nXBYT&4fFEK29e#22ws_1`vK&jvD;J8VdZ2b zR%XQzHbRS`7r~{pE{JJz0Ya%Pv5GE29g&zNMHC@1?9jR0ceOi>0;qEatn6Nzd|vhU z2}+W&h;tI$wgdWJm!hMeYK)+gx|=ED6x-nEs9d?8L!xwWOlPeOy9$Tog2_$jWGcD! zY_*++R`mk4xVZS1kMfy?DTeUb)*P+N$~Hpvh+y`$kHNogH($By;T7&W@vsii%}- z939qJEp$~0hVH-(eIk?~Ti4E{eX+XRWRpF^Z;t;Kxv^o`U@l8iT|-P2 z8CmyR6vZqSp*RUzonU|mh|qC?Bx2 z2s%1Ce1R{7wIJd@4x6hzYq|SXS8inM;CxN(RZfBAH>*hPEYQq*gy-di5tyH$ppfz%#vb zjQ0L^OTOUycM_aX3^q14^uA%zw-l0$arB}D zMiu6wyGI|Dp~_fw&hruaB|3D9KLc*OYKFbMy&nq;Q#uUir~*V0p(ifXdrCn;k(io_ zBQGyc_2|)RLf~z|tfYp;Y>U5m>*X3DM1($N*Z<-`RZR^iObO9<*50lVArg7NJYX5Y za|(NgHT=l&5bD!=Posl;9TzaPW7vLoyF79kJ2;{lp}f0;9iKlsv7YjYser^vh>H!R zL2!{LxETOx?i`Ujc->%jT{a90PpIn~0EL7N4C=3(iMDeQ!(KyWJPtbZ+*u;jhRGW4 z(fkWBLPzLEgCN`VZBY`beDkoIE}}?KTT2U*Yx5D#-#_W0D=U^Y!yB8Mh}PB|wb*O= z5J_M33Wnh~V=Ia&4^L0kw{IEuXMxy$d)r9y@#9C%X;TvuD3AiZwnBVws=)wvL(N@% zDZGHp-~mt)VsP>71D4&!3yE3-1>HB8ARmcU`8@BW5dMmA)EJ_KW)h(x zMkRQ{V#@k5Dw2{q*q}DlG?3CU7cZ#Ly=7`*KX>!;|# zZTmU#_kN3;9)Y7kR_JTzH7Jb2S)b6uum3Nwr*n%&QO*rt;#dl@2+Jdg$MrDLIQ9nU zx7R%y#8uyqrUAZsL^%_ae4xOH9!uOpYe1&g;J`qv z*M9$J-pivN7A8YiBcm^mUXX&`hIy8a=XMhrzu2+FsnkY0aR1eV)8EEe>oN+Mm>U!O z-mc}K<~J)ke2vAw-ZPV-i5Z!JO0R7adOdP7^7CrW48Ga_nN|)aVUyKVT-=RQqA_a+ zz1#ddm`Nfk;j}MA`#xPkXq%N!?!Vb-OWYSO$mu=!>VK6iQ_6=s#4)=>=7XXQpK_T! z0!gEGJmPYQv0g#~ox%93e_$Fz@9WEbK70_`H}UnAtgfzx9xOHG%P zvbw$fuIt_GU&Qq|BS^Q@z$e2xw&VQx{GNGYZ)cbFB>bzKK_p6)@0a<4Fb#*NW5dFq z&dy75zkIoAcgC??F@Kos@FZJP`A zvfL;WJ64u?`7L}1HCm9%9ffNYA;Qp6WhoR|Aa%EPgr(LRZtd5K7lX2(eSlvs?B;2l zk7Kp6^K|X-AdyVPQ31Z~U4J$=vg8AqwTi~}PCkGB+~9xlU0K0Fz>S}Wr{6IQRjQw@ z4&q80SOX#={gGsbJbG-llHppUYEqJK1 zl*GSp5pDw@j7~TG`r41aH~kX+?4w}M;66gCtE=mWim;K9(Km~>CC6Eym6$Z&_a#t- z5&y7HH0b#TpXb*A!XR_J@S;MIE+_23sz4E90DX4LI2N+VI+2ZvOVhECJ$Nj`OzPs| z(oGuKDL6aMM@8U_1^3^B**s=?5|b9}e|H}%y55t}1GL*gxhAiDlZK`y=|UtE6B9QN zkC61%FL#7MD_{%%i+AzF(7DMV&{3DwfU@SCFRlWR#RPYgO`> zD_DHSl^{t;$**N)N-&sA@r(2jfS>d};YtYnAe`!9&w*6_sF;|1WKMB$vGwsrpM={Q z*k!qu__J1cW#w}YPELBt+2rKpcKezt_?=%jm7Th7wt2te*6AnDIiVGdykW=kgHbKv zSmIiByoNz<{`wSKMM=kqt1C>ushBy=3eXHA-ho+I-f`9Vs*y#+iXn!9mHtR-CDE9^ z={x)KNym>YpS7@oAbvIA!2@GTNJ}dtbd7O=2w;|{{wcr0NEV*|NJ#K&R}zw$hBMjw zG_?i32SeXmNuv`OB|~T|U`bw7>IMc>`T6;@1KHBvBtWq0GuJQlkQd8=ET;7?MRakw zxw(_CC*O@1uZp)_5zF18m78|z`Lp_dTQadsZZ`#WB~71)iQrR|C2AT5S48<2^$70N z%HmR;h8p=V@Q!HRcI-eROh@5@bTC_&0v*0dFuRVumvKYm2vonSz9J#bd$!;-NDGv(0aUB8_Q2oJ%KsgfT!q* z@9bl2Z0z3N%4hreWn~2Z=X+I|J2MjGmT4yx_Cfy<#~)k>!o7^7FB9|#q&kc9ZGQM( zmp;16d-9G+iXE^tvS6i(BAX%cYA!#>bA`8+427vVL24)wG8z~Ts#fuwqDv1&Vk$}(M_$J2ZEpkH~B=sEdsrq+A67-u)z<0VG`JxxCr=u?Gb;gaMbk;H%m zw#Tp^PGZi5Uq2liA9uU^xi391lp`CvIq;>Rw6xFV#r)b4KIgii6U4HRzOKqoKRcgy zIjCq)vmC-wPj*HqueLkk@uTM!6RDqya9i?+z_v;MX<&ei63bHm6=>spC!C{L!o&I+CglBl+hVD*AY+J32r|rH z1lsB!pN=_cj#cUysmN*#Q{yF3n2tIkGcc=e9B;ec;RX6@^VQ$XG)ebj!N{C^?)B8R zZ{PR~jEvSNO7$U*j!J+K;o;?dWoD+$fa$vU)9$#6^UE^}H4_v1Vx8<5-;=*=tgIk7 z9Nzt^$opm$NU_B9^uDk9CF2MnT;7LEU4TDw#%VP{s@d5+Sxh{2gl6z|?8}eo`BiRu zvWl83$1Fzgc=#OBg(0H6y?8V=@7*F_Yr>D`?%<#Y z4(|RUro3hE8`7UT{p;rPkWX$rwUP?R=+v_x)1A9BYW4|ss+TZ1SU|ul3kz2vibM|l zV1;(tU7FY~h?A4M#zrJ7o{z7uV#Rbpnkw2~h<4i=jt zGcqzT+~5S@eXwYZ<(Vy*6uO&}!v!vVC74BYlZ4O{|%qlSPK(q;obF zh^-4<9O#CpW$DI0v>Cr|$ekzLYT6RyP(Bt3>ppr)J^zB{Y;2tQ=~+(x_T9U8+1SVp@nyl70Pk=u;Pzy zV|_Y<4c{j<sl&c$9-HNKd(mT zg$D8m!2IyJ`1+KFkKWuv3=zZSy@tr zGW6qmW-%&mclblGnsLQf41bV1Ry+s#wt_=1N6?v%Wbhh#lw5Qe(UWvru5lPLAbr>z zT3s!)v9+a)G-Md(hrwXzDO1y0^SnbVJL0k{<4H#v7$N*Q>J2ce2Gg(efN7pxV-kO}7OPc2p82W-!_+6}IHYu}A zUTrojo`|TZ)%o6RgZoyzoAi!CI5Efs!6l{4l^Mox^{9)?OqRq;J*Cs)x#Fu8(NCe% zx+JT$l)5Tyc(2hM>u@tWWA?Z3KUk)-w||10yf+)XjlO7{`nXl(<$>Dn&ng7pjdA?$ z>av>p_67(_w-6GE1gI?%@~x?fVQ6Rw^yiQc#T#%qpYNJiKKH`;ut{@i=||kXvpk?Z z#>U3bJLMHh<&$ft+rh4?9Kkt-Y>9k9`Rx?~;nPRUih2z<(Lp)(zS&5!+y_ka9x)7q`OqmVRAgktG+dcw001Puhs9E#IcjKHk zJDs&o)4ImSQA0yIw`UcBUB{aPA8+CZ`uq1>Ist9t`q~0;4pS8tq`*c+O})0!m-3vJ zXr|GfD^MaV5?a!5!PV zm#>VBA^|H81dUBxd|GabJmZ|X%eg^y`0z4Xb)Otu>n-tipw*vKwoQdSSPAj`Z^|jD zVA-Uj$vuf?G8&BzQbJVvF-9Y;ChxBSsfs?Ewpecu#`=d)6?XFd7cA7V*wHFV1COdF zyqta&rf7=2p9z|+aj*eM>ve{Gvqiw?;@%~E_wXT|Bx-E;ERL$%^7)Lm>)vR|`1YSV z{fg;K?5{<2^Awxa*r#AcR&j9}>nd6c_*Ky&Nf2~H-iJ9kFktn_2bkQc1q8_Qr<`rE zpZpzE1}siYZ0tU1B@srT#ywLw<4y?MmG`FyT-<}Z*hdaU3&3C;q^YW-@?FU? a.headerlink { + visibility: visible; +} + +/* headings */ +h2 { + font-size: 1.5em; + margin-bottom: 0.5em; + border-bottom: 1px solid #888; +} + +h3 { + font-size: 1.25em; + margin-top: .5em; +} + +h4 { + font-size: 1.15em; + margin-top: 1em; +} + +h5 { + font-size: 1em; + margin-top: 1em; +} + +/* general layout */ +[dir="rtl"] #content { + text-align: right; +} + +#content { + width: 95%; + margin: 0 auto; + text-align: left; +} + +[dir="rtl"] #content-left-wrapper { + float: right; +} + +#content-left-wrapper { + float: left; + width: 100%; /* req to keep content above sidebar in source code */ +} + +[dir="rtl"] #content-left { + margin: 0 0 0 340px; +} + +#content-left { + margin: 0 340px 0 0; +} + +[dir="rtl"] #content-right { + float: right; + margin-right: -300px; +} + +#content-right { + float: left; + width: 300px; + margin-left: -300px; +} + +div.box { + margin-bottom: 1.5em; + padding: 0.65em; + background: #ecf2f5; + border: 1px solid #bcd; +} + +#footer { + clear: both; + margin: 2em 0 1em; +} + + #footer p { + margin: 0; + text-align: center; + font-size: 0.85em; + } + +/* alignment */ +div.center, +table.center, +img.center { + width: auto; + margin-left: auto; + margin-right: auto; +} + +p.center, +td.center, +th.center { + text-align: center; +} + +/* table generics */ +table { + width: 100%; + border-collapse: collapse; +} + + table .wrap { + white-space: normal; + } + +[dir="rtl"] th, +[dir="rtl"] td { + text-align: right; +} + +th, +td { + white-space: nowrap; + text-align: left; +} + + th { + vertical-align: middle; + font-weight: bold; + } + + td { + vertical-align: top; + } + +/* table pretty styles */ +table.pretty2 { + width: auto; + margin-top: 0.25em; + margin-bottom: 0.5em; + border-collapse: collapse; + border: 1px solid #bbb; +} + + .pretty2 th { + padding: 0.35em; + background: #eee; + border: 1px solid #bbb; + } + + .pretty2 td { + padding: 0.35em; + border: 1px dotted #bbb; + } + +table.compact { + width: auto; +} + + .compact td { + padding: 0.25em 0 0.25em 1.5em; + } + + +/* definition lists */ +dl { + clear: both; +} + + dl dt, + dl dd { + margin-bottom: 4px; + padding: 8px 0 4px; + font-weight: bold; + border-top: 1px dotted #bbb; + } + + [dir="rtl"] dl dt { + float: right; + padding-left: 15px; + } + dl dt { + color: #333; + float: left; + padding-right: 15px; + } + +/* forms and input styling */ +form p { + margin: 0.5em 0; +} + +fieldset { + border: 0; +} + +label { + width: 12em; + vertical-align: top; + display: inline-block; + font-weight: bold; +} + +input[type=text], +input[type=password], +input[type=email], +textarea { + padding: 0.10em; +} + +form.general-form label, +form.general-form .form-help { + width: 10em; + vertical-align: top; + display: inline-block; +} + +form.general-form input[type=text], +form.general-form textarea { + width: 45%; +} + +/* archdev navbar */ +#archdev-navbar { + margin: 1.5em 0; +} + + #archdev-navbar ul { + list-style: none; + margin: -0.5em 0; + padding: 0; + } + + #archdev-navbar li { + display: inline; + margin: 0; + padding: 0; + font-size: 0.9em; + } + + #archdev-navbar li a { + padding: 0 0.5em; + color: #07b; + } + +/* error/info messages (x pkg is already flagged out-of-date, etc) */ +#sys-message { + width: 35em; + text-align: center; + margin: 1em auto; + padding: 0.5em; + background: #fff; + border: 1px solid #f00; +} + + #sys-message p { + margin: 0; + } + +ul.errorlist { + color: red; +} + +form ul.errorlist { + margin: 0.5em 0; +} + +/* JS sorting via tablesorter */ +[dir="rtl"] table th.tablesorter-header { + padding-left: 20px; + background-position: center left ; +} +table th.tablesorter-header { + padding-right: 20px; + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + background-repeat: no-repeat; + background-position: center right; + cursor: pointer; +} + +table thead th.tablesorter-headerAsc { + background-color: #e4eeff; + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +} + +table thead th.tablesorter-headerDesc { + background-color: #e4eeff; + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); +} + +table thead th.sorter-false { + background-image: none; + cursor: default; +} + +.tablesorter-header:focus { + outline: none; +} + +/** + * PAGE SPECIFIC STYLES + */ + +/* home: introduction */ +[dir="rtl"] #intro p.readmore { + text-align: left; +} +#intro p.readmore { + margin: -0.5em 0 0 0; + font-size: .9em; + text-align: right; +} + +/* home: news */ +#news { + margin-top: 1.5em; +} + + [dir="rtl"] #news h3 { + float: right; + } + #news h3 { + float: left; + padding-bottom: .5em + } + + #news div { + margin-bottom: 1em; + } + + #news div p { + margin-bottom: 0.5em; + } + + #news .more { + font-weight: normal; + } + [dir="rtl"] #news .rss-icon { + float: left; + } + #news .rss-icon { + float: right; + margin-top: 1em; + } + + #news h4 { + clear: both; + font-size: 1em; + margin-top: 1.5em; + border-bottom: 1px dotted #bbb; + } + [dir="rtl"] #news .timestamp { + float: left; + margin: -1.8em 0 0 0.5em; + } + #news .timestamp { + float: right; + font-size: 0.85em; + margin: -1.8em 0.5em 0 0; + } + +/* home: arrowed headings */ +#news h3 a { + display: block; + background: #1794D1; + font-size: 15px; + padding: 2px 10px; + color: white; +} + + #news a:active { + color: white; + } + +h3 span.arrow { + display: block; + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #1794D1; + margin: 0 auto; + font-size: 0; + line-height: 0px; +} + +/* home: pkgsearch box */ +#pkgsearch { + padding: 1em 0.75em; + background: #3ad; + color: #fff; + border: 1px solid #08b; +} + + #pkgsearch label { + width: auto; + padding: 0.1em 0; + } + + [dir="rtl"] #pkgsearch input { + float: left; + } + #pkgsearch input { + width: 10em; + float: right; + font-size: 1em; + color: #000; + background: #fff; + border: 1px solid #09c; + } + + [dir="rtl"] .pkgsearch-typeahead { + right: 0; + float: right; + text-align: right; + } + + .pkgsearch-typeahead { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + padding: 0.15em 0.1em; + margin: 0; + min-width: 10em; + font-size: 1em; + text-align: left; + list-style: none; + background-color: #f6f9fc; + border: 1px solid #09c; + } + + .pkgsearch-typeahead li a { + color: #000; + } + + .pkgsearch-typeahead li:hover a, + .pkgsearch-typeahead li.active a { + color: #07b; + } + +/* home: recent pkg updates */ +#pkg-updates h3 { + margin: 0 0 0.3em; +} + + #pkg-updates .more { + font-weight: normal; + } + [dir="rtl"] #pkg-updates .rss-icon { + float: left; + } + #pkg-updates .rss-icon { + float: right; + margin: -2em 0 0 0; + } + + [dir="rtl"] #pkg-updates .rss-icon.latest { + margin-left: 1em; + } + #pkg-updates .rss-icon.latest { + margin-right: 1em; + } + + #pkg-updates table { + margin: 0; + direction: ltr; + } + + #pkg-updates td.pkg-name { + white-space: normal; + text-align: left; + } + + [dir="rtl"] #pkg-updates td.pkg-arch { + text-align: left; + } + #pkg-updates td.pkg-arch { + text-align: right; + } + + #pkg-updates span.testing { + font-style: italic; + } + + #pkg-updates span.staging { + font-style: italic; + color: #ff8040; + } + +/* home: sidebar navigation */ +[dir="rtl"] #nav-sidebar ul { + margin: 0.5em 1em 0.5em 0; +} + +#nav-sidebar ul { + list-style: none; + margin: 0.5em 0 0.5em 1em; + padding: 0; +} + +/* home: sponsor banners */ +#arch-sponsors img { + padding: 0.3em 0; +} + +/* home: sidebar components (navlist, sponsors, pkgsearch, etc) */ +div.widget { + margin-bottom: 1.5em; +} + +/* feeds page */ +[dir="rtl"] #rss-feeds .rss { + padding-left: 20px; + background: url(rss.png) top left no-repeat; +} + +#rss-feeds .rss { + padding-right: 20px; + background: url(rss.png) top right no-repeat; +} + +/* artwork: logo images */ +#artwork img.inverted { + background: #333; + padding: 0; +} + +#artwork div.imagelist img { + display: inline; + margin: 0.75em; +} + +/* news: article list */ +[dir="rtl"] .news-nav { + float: left; +} +.news-nav { + float: right; + margin-top: -2.2em; +} + + .news-nav .prev, + .news-nav .next { + margin: 0 1em; + } + +/* news: article pages */ +div.news-article .article-info { + margin: 0; + color: #999; +} + +/* news: add/edit article */ +#newsform { + width: 60em; +} + + #newsform input[type=text], + #newsform textarea { + width: 75%; + } + +#news-preview { + display: none; +} + +/* todolists: list */ +[dir="rtl"] .todolist-nav { + float: left; +} +.todolist-nav { + float: right; + margin-top: -2.2em; +} + + .todolist-nav .prev, + .todolist-nav .next { + margin: 0 1em; + } + +/* donate: donor list */ +#donor-list ul { + width: 100%; +} + /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ + [dir="rtl"] #donor-list li { + float: right; + } + #donor-list li { + float: left; + width: 25%; + min-width: 20em; + } + +/* download page */ +#arch-downloads h3 { + border-bottom: 1px dotted #bbb; +} + +/* pkglists/devlists */ +table.results { + font-size: 0.846em; + border-top: 1px dotted #999; + border-bottom: 1px dotted #999; + direction: ltr; +} + + [dir="rtl"] .results th {text-align: center; direction:rtl;} + .results th { + padding: 0.5em 1em 0.25em 0.25em; + border-bottom: 1px solid #999; + white-space: nowrap; + background-color:#fff; + } + + .results td { + padding: .3em 1em .3em 3px; + text-align: left; + } + + .results .flagged { + color: red; + } + + .results tr.empty td { + text-align: center; + } + +/* pkglist: layout */ +#pkglist-about { + margin-top: 1.5em; +} + +/* pkglist: results navigation */ +.pkglist-stats { + font-size: 0.85em; +} + +[dir="rtl"] #pkglist-results .pkglist-nav { + float: left; +} +#pkglist-results .pkglist-nav { + float: right; + margin-top: -2.2em; +} + +[dir="rtl"] .pkglist-nav .prev { + margin-left: 1em; +} + +.pkglist-nav .prev { + margin-right: 1em; +} + +[dir="rtl"] .pkglist-nav .next { + margin-left: 1em; +} +.pkglist-nav .next { + margin-right: 1em; +} + +/* search fields and other filter selections */ +.filter-criteria { + margin-bottom: 1em; +} + +.filter-criteria h3 { + font-size: 1em; + margin-top: 0; +} +[dir="rtl"] .filter-criteria div { + float: right; + margin-left: 1.65em; +} +.filter-criteria div { + float: left; + margin-right: 1.65em; + font-size: 0.85em; +} + +.filter-criteria legend { + display: none; +} + +.filter-criteria label { + width: auto; + display: block; + font-weight: normal; +} + +/* pkgdetails: details links that float on the right */ +[dir="rtl"] #pkgdetails #detailslinks { + float: left; +} +#pkgdetails #detailslinks { + float: right; +} + + #pkgdetails #detailslinks h4 { + margin-top: 0; + margin-bottom: 0.25em; + } + + #pkgdetails #detailslinks ul { + list-style: none; + padding: 0; + margin-bottom: 0; + font-size: 0.846em; + } + + #pkgdetails #detailslinks > div { + padding: 0.5em; + margin-bottom: 1em; + background: #eee; + border: 1px solid #bbb; + } + +#pkgdetails #actionlist .flagged { + color: red; + font-size: 0.9em; + font-style: italic; +} + +/* pkgdetails: pkg info */ +#pkgdetails #pkginfo { + width: auto; +} + +[dir="rtl"] #pkgdetails td { + padding: 0.25em 1.5em 0.25em 0; + } + + #pkgdetails #pkginfo td { + padding: 0.25em 0 0.25em 1.5em; + } + + #pkgdetails #pkginfo .userdata { + font-size: 0.85em; + padding: 0.5em; + } + +/* pkgdetails: flag package */ +#flag-pkg-form label { + width: 10em; +} + +#flag-pkg-form textarea, +#flag-pkg-form input[type=text] { + width: 45%; +} + +#flag-pkg-form #id_website { + display: none; +} + +/* pkgdetails: deps, required by and file lists */ +#pkgdetails #metadata { + clear: both; +} + +#pkgdetails #metadata h3 { + background: #555; + color: #fff; + font-size: 1em; + margin-bottom: 0.5em; + padding: 0.2em 0.35em; +} + +#pkgdetails #metadata ul { + list-style: none; + margin: 0; + padding: 0; +} + +[dir="rtl"] #pkgdetails #metadata li { + padding-right: 0.5em; +} + +#pkgdetails #metadata li { + padding-left: 0.5em; +} + +[dir="rtl"] #pkgdetails #metadata p { + padding-right: 0.5em; +} +#pkgdetails #metadata p { + padding-left: 0.5em; +} + +#pkgdetails #metadata .message { + font-style: italic; +} + +#pkgdetails #metadata br { + clear: both; +} + +[dir="rtl"] #pkgdetails #pkgdeps { + float: right; + width: 48%; + margin-left: 2%; + +} +#pkgdetails #pkgdeps { + float: left; + width: 48%; + margin-right: 2%; +} + +#pkgdetails #metadata .virtual-dep, +#pkgdetails #metadata .testing-dep, +#pkgdetails #metadata .staging-dep, +#pkgdetails #metadata .opt-dep, +#pkgdetails #metadata .make-dep, +#pkgdetails #metadata .check-dep, +#pkgdetails #metadata .dep-desc { + font-style: italic; +} + +[dir="rtl"] #pkgdetails #pkgreqs { + float: right; + width: 48%; +} + +#pkgdetails #pkgreqs { + float: left; + width: 50%; +} + +#pkgdetails #pkgfiles { + clear: both; + padding-top: 1em; +} + +#pkgfilelist li.d { + color: #666; +} + +#pkgfilelist li.f { +} + +/* mirror stuff */ +table td.country { + white-space: normal; +} + +#list-generator div ul { + list-style: none; + display: inline; + padding-left: 0; +} + + #list-generator div ul li { + display: inline; + } + +.visualize-mirror .axis path, +.visualize-mirror .axis line { + fill: none; + stroke: #000; + stroke-width: 3px; + shape-rendering: crispEdges; +} + +.visualize-mirror .url-dot { + stroke: #000; +} + +.visualize-mirror .url-line { + fill: none; + stroke-width: 1.5px; +} + +/* dev/TU biographies */ +#arch-bio-toc { + width: 75%; + margin: 0 auto; + text-align: center; +} + + #arch-bio-toc a { + white-space: nowrap; + } + +.arch-bio-entry { + width: 75%; + min-width: 640px; + margin: 0 auto; +} + .arch-bio-entry td.pic { + padding-left: 15px; + } + .arch-bio-entry td.pic { + vertical-align: top; + padding-right: 15px; + padding-top: 2.25em; + } + + .arch-bio-entry td.pic img { + padding: 4px; + border: 1px solid #ccc; + } + + .arch-bio-entry td h3 { + border-bottom: 1px dotted #ccc; + margin-bottom: 0.5em; + } + + .arch-bio-entry table.bio { + margin-bottom: 2em; + } + [dir="rtl"] .arch-bio-entry table.bio th { + text-align: left; + padding-left: 0.5em; + } + + .arch-bio-entry table.bio th { + color: #666; + font-weight: normal; + text-align: right; + padding-right: 0.5em; + vertical-align: top; + white-space: nowrap; + } + + .arch-bio-entry table.bio td { + width: 100%; + padding-bottom: 0.25em; + white-space: normal; + } + +/* dev: login/out */ +#dev-login { + width: auto; +} + +/* tables rows: highlight on mouse-vover */ +#article-list tr:hover, +#clocks-table tr:hover, +#dev-dashboard tr:hover, +#dev-todo-lists tr:hover, +#dev-todo-pkglist tr:hover, +#pkglist-results tr:hover, +#stats-area tr:hover { + background: #ffd; +} + +.results tr:nth-child(even), +#article-list tr:nth-child(even) { + background: #e4eeff; +} + +.results tr:nth-child(odd), +#article-list tr:nth-child(odd) { + background: #fff; +} + +/* dev dashboard: */ +table.dash-stats .key { + width: 50%; +} + +/* dev dashboard: admin actions (add news items, todo list, etc) */ +[dir="rtl"] ul.admin-actions { + float: left; +} +ul.admin-actions { + float: right; + list-style: none; + margin-top: -2.5em; +} + + ul.admin-actions li { + display: inline; + padding-left: 1.5em; + } + +/* colored yes/no type values */ +.todo-table .complete, +.signoff-yes, +#key-status .signed-yes, +#release-list .available-yes { + color: green; +} + +.todo-table .incomplete, +.signoff-no, +#key-status .signed-no, +#release-list .available-no { + color: red; +} + +.todo-table .inprogress, +.signoff-bad { + color: darkorange; +} + + +/* todo lists (public and private) */ +.todo-info { + color: #999; + border-bottom: 1px dotted #bbb; +} + +.todo-description { + margin-top: 1em; + padding-left: 2em; + max-width: 900px; +} + +.todo-pkgbases { + border-top: 1px dotted #bbb; +} + +.todo-list h4 { + margin-top: 0; + margin-bottom: 0.4em; +} + +/* dev: signoff page */ +#dev-signoffs tr:hover { + background: #ffd; +} + +ul.signoff-list { + list-style: none; + margin: 0; + padding: 0; +} + +.signoff-yes { + font-weight: bold; +} + +.signoff-disabled { + color: gray; +} + +/* highlight current website in the navbar */ +#archnavbar.anb-home ul li#anb-home a, +#archnavbar.anb-packages ul li#anb-packages a, +#archnavbar.anb-download ul li#anb-download a { + color: white !important; +} + +/* visualizations page */ +.visualize-buttons { + margin: 0.5em 0.33em; +} + +.visualize-chart { + position: relative; + height: 500px; + margin: 0.33em; +} + +#visualize-archrepo .treemap-cell { + border: solid 1px white; + overflow: hidden; + position: absolute; +} + + #visualize-archrepo .treemap-cell span { + padding: 3px; + font-size: 0.85em; + line-height: 1em; + } + +#visualize-keys svg { + width: 100%; + height: 100%; +} + +/* releases */ +#release-table th:first-of-type { + width: 30px; +} + +/* itemprops */ +.itemprop { + display: none; +} diff --git a/static/css/aurweb.css b/static/css/aurweb.css new file mode 100644 index 00000000..64a65742 --- /dev/null +++ b/static/css/aurweb.css @@ -0,0 +1,292 @@ +/* aurweb-specific customizations to archweb.css */ + +#archnavbar.anb-aur ul li#anb-aur a { + color: white !important; +} + +#archnavbarlogo { + background: url('archnavbar/aurlogo.png') !important; +} + +[dir="rtl"] #lang_sub { + float: left; + } +#lang_sub { + float: right; +} + +.pkglist-nav .page { + margin: 0 .25em; +} + +#pkg-stats td.stat-desc { + white-space: normal; +} + +#actionlist form { + margin: 0; + padding: 0; +} + +.arch-bio-entry ul { + list-style: none; + padding: 0; +} + +#pkg-updates table { + table-layout: fixed; + width:100%; +} + +#pkg-updates td.pkg-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +[dir="rtl"] #pkg-updates td.pkg-date { + text-align:left; +} +#pkg-updates td.pkg-date { + text-align:right; +} + +[dir="rtl"] .keyword:link, .keyword:visited { + float: right; +} + +.keyword:link, .keyword:visited { + float: left; + margin: 1px .5ex 1px 0; + padding: 0 1em; + color: white; + background-color: #36a; + border: 1px solid transparent; + border-radius: 2px; +} + +.keyword:hover { + cursor: pointer; +} + +.keyword:focus { + border: 1px dotted #000; +} + +.text-button { + background: transparent; + border: none !important; + margin: 0 !important; + padding: 0 !important; + font: normal 100% sans-serif; + text-decoration: none; + color: #07b; + cursor: pointer; +} + +.text-button:hover { + text-decoration: underline; + color: #666; +} + +.text-button::-moz-focus-inner { + padding: 0; + border: none; +} + +.comment-deleted { + color: #999; +} + +.edited { + font-size: 0.9em; + color: #999; +} + +[dir="rtl"] .delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { + float: left; + margin-right: 8px; +} + +.delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { + float: right; + margin-left: 8px; +} + +.edit-comment { + height: 11px; + position: relative; + top: 1px; +} + +.comment-enable-notifications { + display: inline-block; + margin-left: 1em; +} + +.rss-icon, .delete-comment, .undelete-comment, .edit-comment, .pin-comment { + filter: grayscale(100%); + opacity: 0.6; +} + +.rss-icon:hover, .delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { + filter: none; + opacity: 1; +} + +[dir="rtl"] .ajax-loader { + float: left; +} + +.ajax-loader { + float: right; + position: relative; + top: 4px; +} + +.flagged a { + color: inherit; +} + +legend { + padding: 1em 0; +} + +p.important { + font-weight: bold; +} + +span.hover-help { + border-bottom: 1px dotted black; + cursor:help; +} + +label.confirmation { + width: auto; +} + +#pkgdepslist .broken { + color: red; + font-weight: bold; +} + +.package-comments { + margin-top: 1.5em; +} + +.comments-header { + display: flex; + justify-content: space-between; + align-items: flex-start; +} + +/* arrowed headings */ +.comments-header h3 span.text { + display: block; + background: #1794D1; + font-size: 15px; + padding: 2px 10px; + color: white; +} + +.comments-header .comments-header-nav { + align-self: flex-end; +} + +.comments-footer { + display: flex; + justify-content: flex-end; +} + +.comment-header { + clear: both; + font-size: 1em; + margin-top: 1.5em; + border-bottom: 1px dotted #bbb; +} + +.comments div { + margin-bottom: 1em; +} + +.comments div p { + margin-bottom: 0.5em; +} + +.comments .more { + font-weight: normal; +} + +.error { + color: red; +} + +.article-content > div { + overflow: hidden; + transition: height 1s; +} + +.proposal.details { + margin: .33em 0 1em; +} + +button[type="submit"], +button[type="reset"] { + padding: 0 0.6em; +} + +.results tr td[align="left"] fieldset { + text-align: left; +} + +.results tr td[align="right"] fieldset { + text-align: right; +} + +input#search-action-submit { + width: 80px; +} + +.success { + color: green; +} + +/* Styling used to clone styles for a form.link button. */ +form.link, form.link button { + display: inline; + font-family: sans-serif; +} +form.link button { + padding: 0 0.5em; + color: #07b; + background: none; + border: none; + font-family: inherit; + font-size: inherit; +} +form.link button:hover { + cursor: pointer; + text-decoration: underline; +} + +/* Customize form.link when used inside of a page. */ +div.box form.link p { + margin: .33em 0 1em; +} +div.box form.link button { + padding: 0; +} + +pre.traceback { + /* https://css-tricks.com/snippets/css/make-pre-text-wrap/ */ + white-space: pre-wrap; + word-wrap: break-all; +} + +/* By default, tables use 100% width, which we do not always want. */ +table.no-width { + width: auto; +} +table.no-width > tbody > tr > td { + padding-right: 2px; +} diff --git a/static/css/cgit.css b/static/css/cgit.css new file mode 100644 index 00000000..429b5f54 --- /dev/null +++ b/static/css/cgit.css @@ -0,0 +1,866 @@ +/* + * ARCH GLOBAL NAVBAR + * We're forcing all generic selectors with !important + * to help prevent other stylesheets from interfering. + */ + +/* container for the entire bar */ +#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } +#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url('archnavbar/archlogo.png') no-repeat !important; } + +/* move the heading text offscreen */ +#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } + +/* make the link the same size as the logo */ +#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } + +/* display the list inline, float it to the right and style it */ +#archnavbarlist { display: inline !important; float: right !important; list-style: none !important; margin: 0 !important; padding: 0 !important; } +#archnavbarlist li { float: left !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 45px !important; padding-right: 15px !important; padding-left: 15px !important; } + +/* style the links */ +#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } +#archnavbarlist li a:hover { color: white !important; text-decoration: underline !important; } + +/* END ARCH GLOBAL NAVBAR */ + +#footer { + clear: both; + margin: 0; +} + +#footer p { + margin: 1em; +} + +#archnavbar.anb-aur ul li#anb-aur a { + color: white !important; +} + +#archnavbarlogo { + background: url('archnavbar/aurlogo.png') !important; +} + +body { + padding: 0; + margin: 0; + font-family: sans-serif; + font-size: 10pt; + color: #333; + background: white; +} + +div#cgit a { + color: blue; + text-decoration: none; +} + +div#cgit a:hover { + text-decoration: underline; +} + +div#cgit table { + border-collapse: collapse; +} + +div#cgit table#header { + width: 100%; + margin-bottom: 1em; +} + +div#cgit table#header td.logo { + width: 96px; + vertical-align: top; +} + +div#cgit table#header td.main { + font-size: 250%; + padding-left: 10px; + white-space: nowrap; +} + +div#cgit table#header td.main a { + color: #000; +} + +div#cgit table#header td.form { + text-align: right; + vertical-align: bottom; + padding-right: 1em; + padding-bottom: 2px; + white-space: nowrap; +} + +div#cgit table#header td.form form, +div#cgit table#header td.form input, +div#cgit table#header td.form select { + font-size: 90%; +} + +div#cgit table#header td.sub { + color: #777; + border-top: solid 1px #ccc; + padding-left: 10px; +} + +div#cgit table.tabs { + border-bottom: solid 3px #ccc; + border-collapse: collapse; + margin-top: 2em; + margin-bottom: 0px; + width: 100%; +} + +div#cgit table.tabs td { + padding: 0px 1em; + vertical-align: bottom; +} + +div#cgit table.tabs td a { + padding: 2px 0.75em; + color: #777; + font-size: 110%; +} + +div#cgit table.tabs td a.active { + color: #000; + background-color: #ccc; +} + +div#cgit table.tabs td.form { + text-align: right; +} + +div#cgit table.tabs td.form form { + padding-bottom: 2px; + font-size: 90%; + white-space: nowrap; +} + +div#cgit table.tabs td.form input, +div#cgit table.tabs td.form select { + font-size: 90%; +} + +div#cgit div.path { + margin: 0px; + padding: 5px 2em 2px 2em; + color: #000; + background-color: #eee; +} + +div#cgit div.content { + margin: 0px; + padding: 2em; + border-bottom: solid 3px #ccc; +} + + +div#cgit table.list { + width: 100%; + border: none; + border-collapse: collapse; +} + +div#cgit table.list tr { + background: white; +} + +div#cgit table.list tr.logheader { + background: #eee; +} + +div#cgit table.list tr:hover { + background: #eee; +} + +div#cgit table.list tr.nohover:hover { + background: white; +} + +div#cgit table.list th { + font-weight: bold; + /* color: #888; + border-top: dashed 1px #888; + border-bottom: dashed 1px #888; + */ + padding: 0.1em 0.5em 0.05em 0.5em; + vertical-align: baseline; +} + +div#cgit table.list td { + border: none; + padding: 0.1em 0.5em 0.1em 0.5em; +} + +div#cgit table.list td.commitgraph { + font-family: monospace; + white-space: pre; +} + +div#cgit table.list td.commitgraph .column1 { + color: #a00; +} + +div#cgit table.list td.commitgraph .column2 { + color: #0a0; +} + +div#cgit table.list td.commitgraph .column3 { + color: #aa0; +} + +div#cgit table.list td.commitgraph .column4 { + color: #00a; +} + +div#cgit table.list td.commitgraph .column5 { + color: #a0a; +} + +div#cgit table.list td.commitgraph .column6 { + color: #0aa; +} + +div#cgit table.list td.logsubject { + font-family: monospace; + font-weight: bold; +} + +div#cgit table.list td.logmsg { + font-family: monospace; + white-space: pre; + padding: 0 0.5em; +} + +div#cgit table.list td a { + color: black; +} + +div#cgit table.list td a.ls-dir { + font-weight: bold; + color: #00f; +} + +div#cgit table.list td a:hover { + color: #00f; +} + +div#cgit img { + border: none; +} + +div#cgit input#switch-btn { + margin: 2px 0px 0px 0px; +} + +div#cgit td#sidebar input.txt { + width: 100%; + margin: 2px 0px 0px 0px; +} + +div#cgit table#grid { + margin: 0px; +} + +div#cgit td#content { + vertical-align: top; + padding: 1em 2em 1em 1em; + border: none; +} + +div#cgit div#summary { + vertical-align: top; + margin-bottom: 1em; +} + +div#cgit table#downloads { + float: right; + border-collapse: collapse; + border: solid 1px #777; + margin-left: 0.5em; + margin-bottom: 0.5em; +} + +div#cgit table#downloads th { + background-color: #ccc; +} + +div#cgit div#blob { + border: solid 1px black; +} + +div#cgit div.error { + color: red; + font-weight: bold; + margin: 1em 2em; +} + +div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit a.ls-mod { + font-family: monospace; +} + +div#cgit td.ls-size { + text-align: right; + font-family: monospace; + width: 10em; +} + +div#cgit td.ls-mode { + font-family: monospace; + width: 10em; +} + +div#cgit table.blob { + margin-top: 0.5em; + border-top: solid 1px black; +} + +div#cgit table.blob td.lines { + margin: 0; padding: 0 0 0 0.5em; + vertical-align: top; + color: black; +} + +div#cgit table.blob td.linenumbers { + margin: 0; padding: 0 0.5em 0 0.5em; + vertical-align: top; + text-align: right; + border-right: 1px solid gray; +} + +div#cgit table.blob pre { + padding: 0; margin: 0; +} + +div#cgit table.blob a.no, div#cgit table.ssdiff a.no { + color: gray; + text-align: right; + text-decoration: none; +} + +div#cgit table.blob a.no a:hover { + color: black; +} + +div#cgit table.bin-blob { + margin-top: 0.5em; + border: solid 1px black; +} + +div#cgit table.bin-blob th { + font-family: monospace; + white-space: pre; + border: solid 1px #777; + padding: 0.5em 1em; +} + +div#cgit table.bin-blob td { + font-family: monospace; + white-space: pre; + border-left: solid 1px #777; + padding: 0em 1em; +} + +div#cgit table.nowrap td { + white-space: nowrap; +} + +div#cgit table.commit-info { + border-collapse: collapse; + margin-top: 1.5em; +} + +div#cgit div.cgit-panel { + float: right; + margin-top: 1.5em; +} + +div#cgit div.cgit-panel table { + border-collapse: collapse; + border: solid 1px #aaa; + background-color: #eee; +} + +div#cgit div.cgit-panel th { + text-align: center; +} + +div#cgit div.cgit-panel td { + padding: 0.25em 0.5em; +} + +div#cgit div.cgit-panel td.label { + padding-right: 0.5em; +} + +div#cgit div.cgit-panel td.ctrl { + padding-left: 0.5em; +} + +div#cgit table.commit-info th { + text-align: left; + font-weight: normal; + padding: 0.1em 1em 0.1em 0.1em; + vertical-align: top; +} + +div#cgit table.commit-info td { + font-weight: normal; + padding: 0.1em 1em 0.1em 0.1em; +} + +div#cgit div.commit-subject { + font-weight: bold; + font-size: 125%; + margin: 1.5em 0em 0.5em 0em; + padding: 0em; +} + +div#cgit div.commit-msg { + white-space: pre; + font-family: monospace; +} + +div#cgit div.notes-header { + font-weight: bold; + padding-top: 1.5em; +} + +div#cgit div.notes { + white-space: pre; + font-family: monospace; + border: solid 1px #ee9; + background-color: #ffd; + padding: 0.3em 2em 0.3em 1em; + float: left; +} + +div#cgit div.notes-footer { + clear: left; +} + +div#cgit div.diffstat-header { + font-weight: bold; + padding-top: 1.5em; +} + +div#cgit table.diffstat { + border-collapse: collapse; + border: solid 1px #aaa; + background-color: #eee; +} + +div#cgit table.diffstat th { + font-weight: normal; + text-align: left; + text-decoration: underline; + padding: 0.1em 1em 0.1em 0.1em; + font-size: 100%; +} + +div#cgit table.diffstat td { + padding: 0.2em 0.2em 0.1em 0.1em; + font-size: 100%; + border: none; +} + +div#cgit table.diffstat td.mode { + white-space: nowrap; +} + +div#cgit table.diffstat td span.modechange { + padding-left: 1em; + color: red; +} + +div#cgit table.diffstat td.add a { + color: green; +} + +div#cgit table.diffstat td.del a { + color: red; +} + +div#cgit table.diffstat td.upd a { + color: blue; +} + +div#cgit table.diffstat td.graph { + width: 500px; + vertical-align: middle; +} + +div#cgit table.diffstat td.graph table { + border: none; +} + +div#cgit table.diffstat td.graph td { + padding: 0px; + border: 0px; + height: 7pt; +} + +div#cgit table.diffstat td.graph td.add { + background-color: #5c5; +} + +div#cgit table.diffstat td.graph td.rem { + background-color: #c55; +} + +div#cgit div.diffstat-summary { + color: #888; + padding-top: 0.5em; +} + +div#cgit table.diff { + width: 100%; +} + +div#cgit table.diff td { + font-family: monospace; + white-space: pre; +} + +div#cgit table.diff td div.head { + font-weight: bold; + margin-top: 1em; + color: black; +} + +div#cgit table.diff td div.hunk { + color: #009; +} + +div#cgit table.diff td div.add { + color: green; +} + +div#cgit table.diff td div.del { + color: red; +} + +div#cgit .sha1 { + font-family: monospace; + font-size: 90%; +} + +div#cgit .left { + text-align: left; +} + +div#cgit .right { + text-align: right; + float: none !important; + width: auto !important; + padding: 0 !important; +} + +div#cgit table.list td.reposection { + font-style: italic; + color: #888; +} + +div#cgit a.button { + font-size: 80%; + padding: 0em 0.5em; +} + +div#cgit a.primary { + font-size: 100%; +} + +div#cgit a.secondary { + font-size: 90%; +} + +div#cgit td.toplevel-repo { + +} + +div#cgit table.list td.sublevel-repo { + padding-left: 1.5em; +} + +div#cgit ul.pager { + list-style-type: none; + text-align: center; + margin: 1em 0em 0em 0em; + padding: 0; +} + +div#cgit ul.pager li { + display: inline-block; + margin: 0.25em 0.5em; +} + +div#cgit ul.pager a { + color: #777; +} + +div#cgit ul.pager .current { + font-weight: bold; +} + +div#cgit span.age-mins { + font-weight: bold; + color: #080; +} + +div#cgit span.age-hours { + color: #080; +} + +div#cgit span.age-days { + color: #040; +} + +div#cgit span.age-weeks { + color: #444; +} + +div#cgit span.age-months { + color: #888; +} + +div#cgit span.age-years { + color: #bbb; +} +div#cgit div.footer { + margin-top: 0.5em; + text-align: center; + font-size: 80%; + color: #ccc; +} +div#cgit a.branch-deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #88ff88; + border: solid 1px #007700; +} +div#cgit a.tag-deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #ffff88; + border: solid 1px #777700; +} +div#cgit a.remote-deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #ccccff; + border: solid 1px #000077; +} +div#cgit a.deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #ff8888; + border: solid 1px #770000; +} + +div#cgit div.commit-subject a.branch-deco, +div#cgit div.commit-subject a.tag-deco, +div#cgit div.commit-subject a.remote-deco, +div#cgit div.commit-subject a.deco { + margin-left: 1em; + font-size: 75%; +} + +div#cgit table.stats { + border: solid 1px black; + border-collapse: collapse; +} + +div#cgit table.stats th { + text-align: left; + padding: 1px 0.5em; + background-color: #eee; + border: solid 1px black; +} + +div#cgit table.stats td { + text-align: right; + padding: 1px 0.5em; + border: solid 1px black; +} + +div#cgit table.stats td.total { + font-weight: bold; + text-align: left; +} + +div#cgit table.stats td.sum { + color: #c00; + font-weight: bold; +/* background-color: #eee; */ +} + +div#cgit table.stats td.left { + text-align: left; +} + +div#cgit table.vgraph { + border-collapse: separate; + border: solid 1px black; + height: 200px; +} + +div#cgit table.vgraph th { + background-color: #eee; + font-weight: bold; + border: solid 1px white; + padding: 1px 0.5em; +} + +div#cgit table.vgraph td { + vertical-align: bottom; + padding: 0px 10px; +} + +div#cgit table.vgraph div.bar { + background-color: #eee; +} + +div#cgit table.hgraph { + border: solid 1px black; + width: 800px; +} + +div#cgit table.hgraph th { + background-color: #eee; + font-weight: bold; + border: solid 1px black; + padding: 1px 0.5em; +} + +div#cgit table.hgraph td { + vertical-align: middle; + padding: 2px 2px; +} + +div#cgit table.hgraph div.bar { + background-color: #eee; + height: 1em; +} + +div#cgit table.ssdiff { + width: 100%; +} + +div#cgit table.ssdiff td { + font-size: 75%; + font-family: monospace; + white-space: pre; + padding: 1px 4px 1px 4px; + border-left: solid 1px #aaa; + border-right: solid 1px #aaa; +} + +div#cgit table.ssdiff td.add { + color: black; + background: #cfc; + min-width: 50%; +} + +div#cgit table.ssdiff td.add_dark { + color: black; + background: #aca; + min-width: 50%; +} + +div#cgit table.ssdiff span.add { + background: #cfc; + font-weight: bold; +} + +div#cgit table.ssdiff td.del { + color: black; + background: #fcc; + min-width: 50%; +} + +div#cgit table.ssdiff td.del_dark { + color: black; + background: #caa; + min-width: 50%; +} + +div#cgit table.ssdiff span.del { + background: #fcc; + font-weight: bold; +} + +div#cgit table.ssdiff td.changed { + color: black; + background: #ffc; + min-width: 50%; +} + +div#cgit table.ssdiff td.changed_dark { + color: black; + background: #cca; + min-width: 50%; +} + +div#cgit table.ssdiff td.lineno { + color: black; + background: #eee; + text-align: right; + width: 3em; + min-width: 3em; +} + +div#cgit table.ssdiff td.hunk { + color: black; + background: #ccf; + border-top: solid 1px #aaa; + border-bottom: solid 1px #aaa; +} + +div#cgit table.ssdiff td.head { + border-top: solid 1px #aaa; + border-bottom: solid 1px #aaa; +} + +div#cgit table.ssdiff td.head div.head { + font-weight: bold; + color: black; +} + +div#cgit table.ssdiff td.foot { + border-top: solid 1px #aaa; + border-left: none; + border-right: none; + border-bottom: none; +} + +div#cgit table.ssdiff td.space { + border: none; +} + +div#cgit table.ssdiff td.space div { + min-height: 3em; +} + +/* + * Style definitions generated by highlight 3.14, http://www.andre-simon.de/ + * Highlighting theme: Kwrite Editor + */ +div#cgit table.blob .num { color:#b07e00; } +div#cgit table.blob .esc { color:#ff00ff; } +div#cgit table.blob .str { color:#bf0303; } +div#cgit table.blob .pps { color:#818100; } +div#cgit table.blob .slc { color:#838183; font-style:italic; } +div#cgit table.blob .com { color:#838183; font-style:italic; } +div#cgit table.blob .ppc { color:#008200; } +div#cgit table.blob .opt { color:#000000; } +div#cgit table.blob .ipl { color:#0057ae; } +div#cgit table.blob .lin { color:#555555; } +div#cgit table.blob .kwa { color:#000000; font-weight:bold; } +div#cgit table.blob .kwb { color:#0057ae; } +div#cgit table.blob .kwc { color:#000000; font-weight:bold; } +div#cgit table.blob .kwd { color:#010181; } diff --git a/static/images/ICON-LICENSE b/static/images/ICON-LICENSE new file mode 100644 index 00000000..6b39f6fd --- /dev/null +++ b/static/images/ICON-LICENSE @@ -0,0 +1,26 @@ +The icons used in aurweb originate from the Open Iconic project and are +licensed under the following terms: + +---- +The MIT License (MIT) + +Copyright (c) 2014 Waybury + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +---- diff --git a/static/images/action-undo.min.svg b/static/images/action-undo.min.svg new file mode 100644 index 00000000..eb47bc47 --- /dev/null +++ b/static/images/action-undo.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/action-undo.svg b/static/images/action-undo.svg new file mode 100644 index 00000000..b93ebb78 --- /dev/null +++ b/static/images/action-undo.svg @@ -0,0 +1,32 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/static/images/ajax-loader.gif b/static/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..df07e7ec2076177c99b53d4d29a45f0db6b06a9a GIT binary patch literal 723 zcmZ?wbhEHb6kyWo5uik&V|NP^(AHU+;_dI&}>C3lYM=m|vboAbp zdv88|`N04KivPL&TtkAL9RpmA^bD98f#Qn)q@0UV6H8K46v{J8G87WC5-W1@6I1ju z^V0Ge6o0aCasyTAfJ^{6l7UrML7^`tbKa5#T#rsMt#c4)wm4&2aJl;4?H%*^*q;ct zZ+YZ!f=91--8C-PwbPuinV^!8D8ZUAZ$+j|`^0?*ZXH_r=F;-s=Wq7D-W{Q@F^9F$ zTCh`s37bYUpw-=pI*&V4IF+P$l9wbc(l{x7eoOCbBdG(^nGZDWjsAGTTd?u$#mhT{ z{bn8t<<=6J=66T{n^C4fqn2>E3WhNCJ~l~G@x1uTreFAcY2|b4S-i`cPqf%2ZE*i3 z+J9zZu_cRCJ%=P)K~y-6jgvo!6G0Tle=|GDx_9PaSMatt8xuJ=jueWZ*0zF( zjc8@z38oPY2!}RWYjKN}g`kaCi1-H-uCNkOgxf0BeA-5$w9LxMMtXHz@2@3 zyz+UJPuh|vi*mtJavK=cNwf1dpEbZ!a<``>o|1IZ?Bv;J>;8WS9J=%2sOyMVt`f_h zlJvCko4lXZH(|7*(w!f`Tnu;_ptK?Jqw7?)K+hZAu%R^ukDjFp75q4Pbjddz93wNAlTi;8fmk1LdSvP5vdgJg^M# zaG-vgp9c5>)Q7GRMsXQ9!>~RL)NlL5fD7Ck3IMJGg}hz^t^pqh0-C^eU>&Fc%V89s z01(qlD|><0z!Ts~QmejXjKU~B2rL4Jfq5~#v~m%6p46(=A2%lGz#nlao8kSq3cLUS N002ovPDHLkV1na%{Dc4i literal 0 HcmV?d00001 diff --git a/static/images/pencil.min.svg b/static/images/pencil.min.svg new file mode 100644 index 00000000..06125ae0 --- /dev/null +++ b/static/images/pencil.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/pencil.svg b/static/images/pencil.svg new file mode 100644 index 00000000..91f08991 --- /dev/null +++ b/static/images/pencil.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/static/images/pin.min.svg b/static/images/pin.min.svg new file mode 100644 index 00000000..ac08903d --- /dev/null +++ b/static/images/pin.min.svg @@ -0,0 +1 @@ + diff --git a/static/images/pin.svg b/static/images/pin.svg new file mode 100644 index 00000000..b4ee9eb7 --- /dev/null +++ b/static/images/pin.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/rss.svg b/static/images/rss.svg new file mode 100644 index 00000000..3c7f6ba1 --- /dev/null +++ b/static/images/rss.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/unpin.min.svg b/static/images/unpin.min.svg new file mode 100644 index 00000000..3cf2413c --- /dev/null +++ b/static/images/unpin.min.svg @@ -0,0 +1 @@ + diff --git a/static/images/unpin.svg b/static/images/unpin.svg new file mode 100644 index 00000000..de897152 --- /dev/null +++ b/static/images/unpin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/static/images/x.min.svg b/static/images/x.min.svg new file mode 100644 index 00000000..833d4f22 --- /dev/null +++ b/static/images/x.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/x.svg b/static/images/x.svg new file mode 100644 index 00000000..e323fe19 --- /dev/null +++ b/static/images/x.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/static/js/comment-edit.js b/static/js/comment-edit.js new file mode 100644 index 00000000..23ffdd34 --- /dev/null +++ b/static/js/comment-edit.js @@ -0,0 +1,61 @@ +function add_busy_indicator(sibling) { + const img = document.createElement('img'); + img.src = "/static/images/ajax-loader.gif"; + img.classList.add('ajax-loader'); + img.style.height = 11; + img.style.width = 16; + img.alt = "Busy…"; + + sibling.insertAdjacentElement('afterend', img); +} + +function remove_busy_indicator(sibling) { + const elem = sibling.nextElementSibling; + elem.parentNode.removeChild(elem); +} + +function getParentsUntil(elem, className) { + // Limit to 10 depth + for ( ; elem && elem !== document; elem = elem.parentNode) { + if (elem.matches(className)) { + break; + } + } + + return elem; +} + +function handleEditCommentClick(event, pkgbasename) { + event.preventDefault(); + const parent_element = getParentsUntil(event.target, '.comment-header'); + const parent_id = parent_element.id; + const comment_id = parent_id.substr(parent_id.indexOf('-') + 1); + // The div class="article-content" which contains the comment + const edit_form = parent_element.nextElementSibling; + + const url = "/pkgbase/" + pkgbasename + "/comments/" + comment_id + "/form?"; + + add_busy_indicator(event.target); + + fetch(url + new URLSearchParams({ next: window.location.pathname }), { + method: 'GET', + credentials: 'same-origin' + }) + .then(function(response) { + if (!response.ok) { + throw Error(response.statusText); + } + return response.json(); + }) + .then(function(data) { + remove_busy_indicator(event.target); + edit_form.innerHTML = data.form; + edit_form.querySelector('textarea').focus(); + }) + .catch(function(error) { + remove_busy_indicator(event.target); + console.error(error); + }); + + return false; +} diff --git a/static/js/copy.js b/static/js/copy.js new file mode 100644 index 00000000..3b659270 --- /dev/null +++ b/static/js/copy.js @@ -0,0 +1,9 @@ +document.addEventListener('DOMContentLoaded', function() { + let elements = document.querySelectorAll('.copy'); + elements.forEach(function(el) { + el.addEventListener('click', function(e) { + e.preventDefault(); + navigator.clipboard.writeText(e.target.text); + }); + }); +}); diff --git a/static/js/typeahead-home.js b/static/js/typeahead-home.js new file mode 100644 index 00000000..5af51c53 --- /dev/null +++ b/static/js/typeahead-home.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + const input = document.getElementById('pkgsearch-field'); + const form = document.getElementById('pkgsearch-form'); + const type = 'suggest'; + typeahead.init(type, input, form); +}); diff --git a/static/js/typeahead-pkgbase-merge.js b/static/js/typeahead-pkgbase-merge.js new file mode 100644 index 00000000..a8c87e4f --- /dev/null +++ b/static/js/typeahead-pkgbase-merge.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + const input = document.getElementById('merge_into'); + const form = document.getElementById('merge-form'); + const type = "suggest-pkgbase"; + typeahead.init(type, input, form, false); +}); diff --git a/static/js/typeahead-pkgbase-request.js b/static/js/typeahead-pkgbase-request.js new file mode 100644 index 00000000..e012d55f --- /dev/null +++ b/static/js/typeahead-pkgbase-request.js @@ -0,0 +1,36 @@ +function showHideMergeSection() { + const elem = document.getElementById('id_type'); + const merge_section = document.getElementById('merge_section'); + if (elem.value == 'merge') { + merge_section.style.display = ''; + } else { + merge_section.style.display = 'none'; + } +} + +function showHideRequestHints() { + document.getElementById('deletion_hint').style.display = 'none'; + document.getElementById('merge_hint').style.display = 'none'; + document.getElementById('orphan_hint').style.display = 'none'; + + const elem = document.getElementById('id_type'); + document.getElementById(elem.value + '_hint').style.display = ''; +} + +document.addEventListener('DOMContentLoaded', function() { + showHideMergeSection(); + showHideRequestHints(); + + const input = document.getElementById('id_merge_into'); + const form = document.getElementById('request-form'); + const type = "suggest-pkgbase"; + + typeahead.init(type, input, form, false); +}); + +// Bind the change event here, otherwise we have to inline javascript, +// which angers CSP (Content Security Policy). +document.getElementById("id_type").addEventListener("change", function() { + showHideMergeSection(); + showHideRequestHints(); +}); diff --git a/static/js/typeahead.js b/static/js/typeahead.js new file mode 100644 index 00000000..bfd3d156 --- /dev/null +++ b/static/js/typeahead.js @@ -0,0 +1,151 @@ +"use strict"; + +const typeahead = (function() { + var input; + var form; + var suggest_type; + var list; + var submit = true; + + function resetResults() { + if (!list) return; + list.style.display = "none"; + list.innerHTML = ""; + } + + function getCompleteList() { + if (!list) { + list = document.createElement("UL"); + list.setAttribute("class", "pkgsearch-typeahead"); + form.appendChild(list); + setListLocation(); + } + return list; + } + + function onListClick(e) { + let target = e.target; + while (!target.getAttribute('data-value')) { + target = target.parentNode; + } + input.value = target.getAttribute('data-value'); + if (submit) { + form.submit(); + } + } + + function setListLocation() { + if (!list) return; + const rects = input.getClientRects()[0]; + list.style.top = (rects.top + rects.height) + "px"; + list.style.left = rects.left + "px"; + } + + function loadData(letter, data) { + const pkgs = data.slice(0, 10); // Show maximum of 10 results + + resetResults(); + + if (pkgs.length === 0) { + return; + } + + const ul = getCompleteList(); + ul.style.display = "block"; + const fragment = document.createDocumentFragment(); + + for (let i = 0; i < pkgs.length; i++) { + const item = document.createElement("li"); + const text = pkgs[i].replace(letter, '' + letter + ''); + item.innerHTML = '' + text + ''; + item.setAttribute('data-value', pkgs[i]); + fragment.appendChild(item); + } + + ul.appendChild(fragment); + ul.addEventListener('click', onListClick); + } + + function fetchData(letter) { + const url = '/rpc?v=5&type=' + suggest_type + '&arg=' + letter; + fetch(url).then(function(response) { + return response.json(); + }).then(function(data) { + loadData(letter, data); + }); + } + + function onInputClick() { + if (input.value === "") { + resetResults(); + return; + } + fetchData(input.value); + } + + function onKeyDown(e) { + if (!list) return; + + const elem = document.querySelector(".pkgsearch-typeahead li.active"); + switch(e.keyCode) { + case 13: // enter + if (!submit) { + return; + } + if (elem) { + input.value = elem.getAttribute('data-value'); + form.submit(); + } else { + form.submit(); + } + e.preventDefault(); + break; + case 38: // up + if (elem && elem.previousElementSibling) { + elem.className = ""; + elem.previousElementSibling.className = "active"; + } + e.preventDefault(); + break; + case 40: // down + if (elem && elem.nextElementSibling) { + elem.className = ""; + elem.nextElementSibling.className = "active"; + } else if (!elem && list.childElementCount !== 0) { + list.children[0].className = "active"; + } + e.preventDefault(); + break; + } + } + + // debounce https://davidwalsh.name/javascript-debounce-function + function debounce(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + } + + return { + init: function(type, inputfield, formfield, submitdata = true) { + suggest_type = type; + input = inputfield; + form = formfield; + submit = submitdata; + + input.addEventListener("input", onInputClick); + input.addEventListener("keydown", onKeyDown); + window.addEventListener('resize', debounce(setListLocation, 150)); + document.addEventListener("click", resetResults); + } + } +}()); From 8ca63075e907609ad6c81decff3bc7d027e1cde2 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 28 Apr 2023 16:10:32 +0200 Subject: [PATCH 1734/1891] housekeep: remove PHP implementation removal of the PHP codebase Signed-off-by: moson-mo --- .editorconfig | 3 - .env | 1 - .gitlab-ci.yml | 1 - CONTRIBUTING.md | 1 - INSTALL | 3 +- README.md | 1 - TESTING | 1 - aurweb/db.py | 4 +- aurweb/spawn.py | 59 +- conf/config.defaults | 16 +- conf/config.dev | 11 - doc/docker.md | 20 +- doc/maintenance.txt | 2 +- docker-compose.aur-dev.yml | 16 - docker-compose.override.yml | 14 - docker-compose.yml | 76 +- docker/README.md | 3 +- docker/config/nginx.conf | 52 - docker/health/memcached.sh | 2 - docker/health/php.sh | 2 - docker/mariadb-entrypoint.sh | 2 +- docker/php-entrypoint.sh | 32 - docker/scripts/install-deps.sh | 5 +- docker/scripts/run-memcached.sh | 2 - docker/scripts/run-nginx.sh | 2 - docker/scripts/run-php.sh | 4 - po/Makefile | 16 +- test/test_spawn.py | 35 +- web/html/404.php | 47 - web/html/503.php | 14 - web/html/account.php | 223 --- web/html/addvote.php | 116 -- web/html/comaintainers.php | 16 - web/html/commentedit.php | 18 - web/html/css/archnavbar/archlogo.png | Bin 5359 -> 0 bytes web/html/css/archnavbar/archnavbar.css | 26 - web/html/css/archnavbar/aurlogo.png | Bin 5997 -> 0 bytes web/html/css/archweb.css | 1255 ---------------- web/html/css/aurweb.css | 292 ---- web/html/css/cgit.css | 866 ----------- web/html/home.php | 215 --- web/html/images/ICON-LICENSE | 26 - web/html/images/action-undo.min.svg | 3 - web/html/images/action-undo.svg | 32 - web/html/images/ajax-loader.gif | Bin 723 -> 0 bytes web/html/images/favicon.ico | Bin 575 -> 0 bytes web/html/images/pencil.min.svg | 3 - web/html/images/pencil.svg | 55 - web/html/images/pin.min.svg | 1 - web/html/images/pin.svg | 3 - web/html/images/rss.svg | 3 - web/html/images/unpin.min.svg | 1 - web/html/images/unpin.svg | 4 - web/html/images/x.min.svg | 3 - web/html/images/x.svg | 31 - web/html/index.php | 205 --- web/html/js/comment-edit.js | 61 - web/html/js/copy.js | 9 - web/html/js/typeahead-home.js | 6 - web/html/js/typeahead-pkgbase-merge.js | 6 - web/html/js/typeahead-pkgbase-request.js | 36 - web/html/js/typeahead.js | 151 -- web/html/login.php | 68 - web/html/logout.php | 31 - web/html/modified-rss.php | 62 - web/html/packages.php | 173 --- web/html/passreset.php | 100 -- web/html/pkgbase.php | 195 --- web/html/pkgdel.php | 45 - web/html/pkgdisown.php | 59 - web/html/pkgflag.php | 91 -- web/html/pkgflagcomment.php | 16 - web/html/pkgmerge.php | 58 - web/html/pkgreq.php | 83 -- web/html/register.php | 87 -- web/html/rpc.php | 17 - web/html/rss.php | 61 - web/html/tos.php | 50 - web/html/tu.php | 122 -- web/html/voters.php | 34 - web/lib/DB.class.php | 59 - web/lib/acctfuncs.inc.php | 1522 ------------------- web/lib/aur.inc.php | 774 ---------- web/lib/aurjson.class.php | 710 --------- web/lib/cachefuncs.inc.php | 99 -- web/lib/confparser.inc.php | 59 - web/lib/credentials.inc.php | 91 -- web/lib/feedcreator.class.php | 1546 -------------------- web/lib/gettext.php | 432 ------ web/lib/pkgbasefuncs.inc.php | 1253 ---------------- web/lib/pkgfuncs.inc.php | 957 ------------ web/lib/pkgreqfuncs.inc.php | 260 ---- web/lib/routing.inc.php | 85 -- web/lib/stats.inc.php | 108 -- web/lib/streams.php | 167 --- web/lib/timezone.inc.php | 63 - web/lib/translator.inc.php | 139 -- web/lib/version.inc.php | 2 - web/locale/README | 5 - web/template/account_delete.php | 29 - web/template/account_details.php | 93 -- web/template/account_edit_form.php | 222 --- web/template/account_search_results.php | 87 -- web/template/cgit/footer.html | 6 - web/template/cgit/header.html | 15 - web/template/comaintainers_form.php | 19 - web/template/flag_comment.php | 26 - web/template/footer.php | 13 - web/template/header.php | 82 -- web/template/pkg_comment_box.php | 4 - web/template/pkg_comment_form.php | 28 - web/template/pkg_comments.php | 239 --- web/template/pkg_details.php | 317 ---- web/template/pkg_search_form.php | 120 -- web/template/pkg_search_results.php | 153 -- web/template/pkgbase_actions.php | 49 - web/template/pkgbase_details.php | 146 -- web/template/pkgreq_close_form.php | 31 - web/template/pkgreq_form.php | 81 - web/template/pkgreq_results.php | 129 -- web/template/search_accounts_form.php | 52 - web/template/stats/general_stats_table.php | 36 - web/template/stats/updates_table.php | 19 - web/template/stats/user_table.php | 21 - web/template/template.phps | 19 - web/template/tu_details.php | 123 -- web/template/tu_last_votes_list.php | 36 - web/template/tu_list.php | 82 -- 128 files changed, 27 insertions(+), 16046 deletions(-) delete mode 100755 docker/health/memcached.sh delete mode 100755 docker/health/php.sh delete mode 100755 docker/php-entrypoint.sh delete mode 100755 docker/scripts/run-memcached.sh delete mode 100755 docker/scripts/run-php.sh delete mode 100644 web/html/404.php delete mode 100644 web/html/503.php delete mode 100644 web/html/account.php delete mode 100644 web/html/addvote.php delete mode 100644 web/html/comaintainers.php delete mode 100644 web/html/commentedit.php delete mode 100644 web/html/css/archnavbar/archlogo.png delete mode 100644 web/html/css/archnavbar/archnavbar.css delete mode 100644 web/html/css/archnavbar/aurlogo.png delete mode 100644 web/html/css/archweb.css delete mode 100644 web/html/css/aurweb.css delete mode 100644 web/html/css/cgit.css delete mode 100644 web/html/home.php delete mode 100644 web/html/images/ICON-LICENSE delete mode 100644 web/html/images/action-undo.min.svg delete mode 100644 web/html/images/action-undo.svg delete mode 100644 web/html/images/ajax-loader.gif delete mode 100644 web/html/images/favicon.ico delete mode 100644 web/html/images/pencil.min.svg delete mode 100644 web/html/images/pencil.svg delete mode 100644 web/html/images/pin.min.svg delete mode 100644 web/html/images/pin.svg delete mode 100644 web/html/images/rss.svg delete mode 100644 web/html/images/unpin.min.svg delete mode 100644 web/html/images/unpin.svg delete mode 100644 web/html/images/x.min.svg delete mode 100644 web/html/images/x.svg delete mode 100644 web/html/index.php delete mode 100644 web/html/js/comment-edit.js delete mode 100644 web/html/js/copy.js delete mode 100644 web/html/js/typeahead-home.js delete mode 100644 web/html/js/typeahead-pkgbase-merge.js delete mode 100644 web/html/js/typeahead-pkgbase-request.js delete mode 100644 web/html/js/typeahead.js delete mode 100644 web/html/login.php delete mode 100644 web/html/logout.php delete mode 100644 web/html/modified-rss.php delete mode 100644 web/html/packages.php delete mode 100644 web/html/passreset.php delete mode 100644 web/html/pkgbase.php delete mode 100644 web/html/pkgdel.php delete mode 100644 web/html/pkgdisown.php delete mode 100644 web/html/pkgflag.php delete mode 100644 web/html/pkgflagcomment.php delete mode 100644 web/html/pkgmerge.php delete mode 100644 web/html/pkgreq.php delete mode 100644 web/html/register.php delete mode 100644 web/html/rpc.php delete mode 100644 web/html/rss.php delete mode 100644 web/html/tos.php delete mode 100644 web/html/tu.php delete mode 100644 web/html/voters.php delete mode 100644 web/lib/DB.class.php delete mode 100644 web/lib/acctfuncs.inc.php delete mode 100644 web/lib/aur.inc.php delete mode 100644 web/lib/aurjson.class.php delete mode 100644 web/lib/cachefuncs.inc.php delete mode 100644 web/lib/confparser.inc.php delete mode 100644 web/lib/credentials.inc.php delete mode 100644 web/lib/feedcreator.class.php delete mode 100644 web/lib/gettext.php delete mode 100644 web/lib/pkgbasefuncs.inc.php delete mode 100644 web/lib/pkgfuncs.inc.php delete mode 100644 web/lib/pkgreqfuncs.inc.php delete mode 100644 web/lib/routing.inc.php delete mode 100644 web/lib/stats.inc.php delete mode 100644 web/lib/streams.php delete mode 100644 web/lib/timezone.inc.php delete mode 100644 web/lib/translator.inc.php delete mode 100644 web/lib/version.inc.php delete mode 100644 web/locale/README delete mode 100644 web/template/account_delete.php delete mode 100644 web/template/account_details.php delete mode 100644 web/template/account_edit_form.php delete mode 100644 web/template/account_search_results.php delete mode 100644 web/template/cgit/footer.html delete mode 100644 web/template/cgit/header.html delete mode 100644 web/template/comaintainers_form.php delete mode 100644 web/template/flag_comment.php delete mode 100644 web/template/footer.php delete mode 100644 web/template/header.php delete mode 100644 web/template/pkg_comment_box.php delete mode 100644 web/template/pkg_comment_form.php delete mode 100644 web/template/pkg_comments.php delete mode 100644 web/template/pkg_details.php delete mode 100644 web/template/pkg_search_form.php delete mode 100644 web/template/pkg_search_results.php delete mode 100644 web/template/pkgbase_actions.php delete mode 100644 web/template/pkgbase_details.php delete mode 100644 web/template/pkgreq_close_form.php delete mode 100644 web/template/pkgreq_form.php delete mode 100644 web/template/pkgreq_results.php delete mode 100644 web/template/search_accounts_form.php delete mode 100644 web/template/stats/general_stats_table.php delete mode 100644 web/template/stats/updates_table.php delete mode 100644 web/template/stats/user_table.php delete mode 100644 web/template/template.phps delete mode 100644 web/template/tu_details.php delete mode 100644 web/template/tu_last_votes_list.php delete mode 100644 web/template/tu_list.php diff --git a/.editorconfig b/.editorconfig index 5a751aad..95f2c7dd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,3 @@ root = true end_of_line = lf insert_final_newline = true charset = utf-8 - -[*.{php,t}] -indent_style = tab diff --git a/.env b/.env index 22846cb4..bf6c48c4 100644 --- a/.env +++ b/.env @@ -1,7 +1,6 @@ FASTAPI_BACKEND="uvicorn" FASTAPI_WORKERS=2 MARIADB_SOCKET_DIR="/var/run/mysqld/" -AURWEB_PHP_PREFIX=https://localhost:8443 AURWEB_FASTAPI_PREFIX=https://localhost:8444 AURWEB_SSHD_PREFIX=ssh://aur@localhost:2222 GIT_DATA_DIR="./aur.git/" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index af722d99..10dd1787 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -71,7 +71,6 @@ deploy: variables: FASTAPI_BACKEND: gunicorn FASTAPI_WORKERS: 5 - AURWEB_PHP_PREFIX: https://aur-dev.archlinux.org AURWEB_FASTAPI_PREFIX: https://aur-dev.archlinux.org AURWEB_SSHD_PREFIX: ssh://aur@aur-dev.archlinux.org:2222 COMMIT_HASH: $CI_COMMIT_SHA diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8d4f90d..a91e3eec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,7 +91,6 @@ browser if desired. Accessible services (on the host): - https://localhost:8444 (python via nginx) -- https://localhost:8443 (php via nginx) - localhost:13306 (mariadb) - localhost:16379 (redis) diff --git a/INSTALL b/INSTALL index 03459726..107fab4b 100644 --- a/INSTALL +++ b/INSTALL @@ -14,8 +14,7 @@ read the instructions below. $ cd aurweb $ poetry install -2) Setup a web server with PHP and MySQL. Configure the web server to redirect - all URLs to /index.php/foo/bar/. The following block can be used with nginx: +2) Setup a web server with MySQL. The following block can be used with nginx: server { # https is preferred and can be done easily with LetsEncrypt diff --git a/README.md b/README.md index 2741efa2..4d732bb2 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ Directory Layout * `schema`: schema for the SQL database * `test`: test suite and test cases * `upgrading`: instructions for upgrading setups from one release to another -* `web`: PHP-based web interface for the AUR Documentation ------------- diff --git a/TESTING b/TESTING index cb34c0e9..078d330b 100644 --- a/TESTING +++ b/TESTING @@ -29,7 +29,6 @@ docker-compose 4) Browse to local aurweb development server. Python: https://localhost:8444/ - PHP: https://localhost:8443/ 5) [Optionally] populate the database with dummy data: diff --git a/aurweb/db.py b/aurweb/db.py index ab0f80b8..8311f2be 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -364,7 +364,7 @@ class ConnectionExecutor: def execute(self, query, params=()): # pragma: no cover # TODO: SQLite support has been removed in FastAPI. It remains - # here to fund its support for PHP until it is removed. + # here to fund its support for the Sharness testsuite. if self._paramstyle in ("format", "pyformat"): query = query.replace("%", "%%").replace("?", "%s") elif self._paramstyle == "qmark": @@ -410,7 +410,7 @@ class Connection: ) elif aur_db_backend == "sqlite": # pragma: no cover # TODO: SQLite support has been removed in FastAPI. It remains - # here to fund its support for PHP until it is removed. + # here to fund its support for Sharness testsuite. import math import sqlite3 diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 29162f33..442d89a9 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -20,7 +20,6 @@ from typing import Iterable import aurweb.config import aurweb.schema -from aurweb.exceptions import AurwebException children = [] temporary_dir = None @@ -28,9 +27,6 @@ verbosity = 0 asgi_backend = "" workers = 1 -PHP_BINARY = os.environ.get("PHP_BINARY", "php") -PHP_MODULES = ["pdo_mysql", "pdo_sqlite"] -PHP_NGINX_PORT = int(os.environ.get("PHP_NGINX_PORT", 8001)) FASTAPI_NGINX_PORT = int(os.environ.get("FASTAPI_NGINX_PORT", 8002)) @@ -47,42 +43,12 @@ class ProcessExceptions(Exception): super().__init__("\n- ".join(messages)) -def validate_php_config() -> None: - """ - Perform a validation check against PHP_BINARY's configuration. - - AurwebException is raised here if checks fail to pass. We require - the 'pdo_mysql' and 'pdo_sqlite' modules to be enabled. - - :raises: AurwebException - :return: None - """ - try: - proc = subprocess.Popen( - [PHP_BINARY, "-m"], stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - out, _ = proc.communicate() - except FileNotFoundError: - raise AurwebException(f"Unable to locate the '{PHP_BINARY}' " "executable.") - - assert proc.returncode == 0, ( - "Received non-zero error code " f"{proc.returncode} from '{PHP_BINARY}'." - ) - - modules = out.decode().splitlines() - for module in PHP_MODULES: - if module not in modules: - raise AurwebException(f"PHP does not have the '{module}' module enabled.") - - def generate_nginx_config(): """ Generate an nginx configuration based on aurweb's configuration. The file is generated under `temporary_dir`. Returns the path to the created configuration file. """ - php_bind = aurweb.config.get("php", "bind_address") - php_host = php_bind.split(":")[0] fastapi_bind = aurweb.config.get("fastapi", "bind_address") fastapi_host = fastapi_bind.split(":")[0] config_path = os.path.join(temporary_dir, "nginx.conf") @@ -101,12 +67,6 @@ def generate_nginx_config(): fastcgi_temp_path {os.path.join(temporary_dir, "fastcgi")}1 2; uwsgi_temp_path {os.path.join(temporary_dir, "uwsgi")}; scgi_temp_path {os.path.join(temporary_dir, "scgi")}; - server {{ - listen {php_host}:{PHP_NGINX_PORT}; - location / {{ - proxy_pass http://{php_bind}; - }} - }} server {{ listen {fastapi_host}:{FASTAPI_NGINX_PORT}; location / {{ @@ -154,7 +114,7 @@ def start(): terminal_width = 80 print( "{ruler}\n" - "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n" + "Spawing FastAPI, then nginx as a reverse proxy.\n" "Check out {aur_location}\n" "Hit ^C to terminate everything.\n" "{ruler}".format( @@ -163,12 +123,6 @@ def start(): ) ) - # PHP - php_address = aurweb.config.get("php", "bind_address") - php_host = php_address.split(":")[0] - htmldir = aurweb.config.get("php", "htmldir") - spawn_child(["php", "-S", php_address, "-t", htmldir]) - # FastAPI fastapi_host, fastapi_port = aurweb.config.get("fastapi", "bind_address").rsplit( ":", 1 @@ -210,10 +164,7 @@ def start(): f""" > Started nginx. > - > PHP backend: http://{php_address} - > FastAPI backend: http://{fastapi_host}:{fastapi_port} - > - > PHP frontend: http://{php_host}:{PHP_NGINX_PORT} + > FastAPI backend: http://{fastapi_host}:{fastapi_port} > FastAPI frontend: http://{fastapi_host}:{FASTAPI_NGINX_PORT} > > Frontends are hosted via nginx and should be preferred. @@ -307,12 +258,6 @@ if __name__ == "__main__": ) args = parser.parse_args() - try: - validate_php_config() - except AurwebException as exc: - print(f"error: {str(exc)}") - sys.exit(1) - verbosity = args.verbose asgi_backend = args.backend workers = args.workers diff --git a/conf/config.defaults b/conf/config.defaults index 06e73afe..0cd4b9d4 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -38,11 +38,9 @@ enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 render-comment-cmd = /usr/bin/aurweb-rendercomment localedir = /srv/http/aurweb/web/locale/ -; memcache, apc, or redis -; memcache/apc are supported in PHP, redis is supported in Python. +; cache: redis is supported in Python. cache = none cache_pkginfo_ttl = 86400 -memcache_servers = 127.0.0.1:11211 salt_rounds = 12 redis_address = redis://localhost ; Toggles traceback display in templates/errors/500.html. @@ -125,12 +123,12 @@ sync-dbs = core extra community multilib testing community-testing server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] -archivedir = /srv/http/aurweb/web/html -packagesfile = /srv/http/aurweb/web/html/packages.gz -packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz -packagesmetaextfile = /srv/http/aurweb/web/html/packages-meta-ext-v1.json.gz -pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz -userfile = /srv/http/aurweb/web/html/users.gz +archivedir = /srv/http/aurweb/archives +packagesfile = /srv/http/aurweb/archives/packages.gz +packagesmetafile = /srv/http/aurweb/archives/packages-meta-v1.json.gz +packagesmetaextfile = /srv/http/aurweb/archives/packages-meta-ext-v1.json.gz +pkgbasefile = /srv/http/aurweb/archives/pkgbase.gz +userfile = /srv/http/aurweb/archives/users.gz [git-archive] author = git_archive.py diff --git a/conf/config.dev b/conf/config.dev index b36bfe77..f3b0ee21 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -6,7 +6,6 @@ ; development-specific options too. [database] -; PHP options: mysql, sqlite. ; FastAPI options: mysql. backend = mysql @@ -31,9 +30,6 @@ localedir = YOUR_AUR_ROOT/web/locale salt_rounds = 4 ; See config.defaults comment about cache. cache = none -; In docker, the memcached host is available. On a user's system, -; this should be set to localhost (most likely). -memcache_servers = memcached:11211 ; If cache = 'redis' this address is used to connect to Redis. redis_address = redis://127.0.0.1 aur_request_ml = aur-requests@localhost @@ -51,13 +47,6 @@ openid_configuration = http://127.0.0.1:8083/auth/realms/aurweb/.well-known/open client_id = aurweb client_secret = -[php] -; Address PHP should bind when spawned in development mode by aurweb.spawn. -bind_address = 127.0.0.1:8081 - -; Directory containing aurweb's PHP code, required by aurweb.spawn. -htmldir = YOUR_AUR_ROOT/web/html - [fastapi] ; Address uvicorn should bind when spawned in development mode by aurweb.spawn. bind_address = 127.0.0.1:8082 diff --git a/doc/docker.md b/doc/docker.md index 22505f7a..c54184b8 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -65,12 +65,9 @@ Services | [mariadb](#mariadb) | 127.0.0.1:13306 | | [git](#git) | 127.0.0.1:2222 | | redis | 127.0.0.1:16379 | -| [php-fpm](#php-fpm) | 127.0.0.1:19000 | -| cgit-php | | | [fastapi](#fastapi) | 127.0.0.1:18000 | | cgit-fastapi | | | [nginx](#nginx) (fastapi) | 127.0.0.1:8444 | -| [nginx](#nginx) (php) | 127.0.0.1:8443 | There are more services which have not been referred to here; the services listed above encompass all notable services. Some @@ -113,16 +110,6 @@ to be used for the AUR. This service will perform setup in either case if the repository is not yet initialized. -#### php-fpm - -When running any services which use the _php-fpm_ backend or other -php-related services, users should define: - -- `AURWEB_PHP_PREFIX` - - Default: `https://localhost:8443` -- `AURWEB_SSHD_PREFIX` - - Default: `ssh://aur@localhost:2222` - #### fastapi The _fastapi_ service hosts a `gunicorn`, `uvicorn` or `hypercorn` @@ -145,20 +132,17 @@ backend or other fastapi-related services, users should define: #### nginx -The _nginx_ service binds to two host endpoints: 127.0.0.1:8444 (fastapi) -and 127.0.0.1:8443 (php). Each instance is available over the `https` +The _nginx_ service binds to host endpoint: 127.0.0.1:8444 (fastapi). +The instance is available over the `https` protocol as noted in the table below. | Impl | Host Binding | URL | |--------|----------------|------------------------| | Python | 127.0.0.1:8444 | https://localhost:8444 | -| PHP | 127.0.0.1:8443 | https://localhost:8443 | When running this service, the following variables should be defined: - `AURWEB_FASTAPI_PREFIX` - Default: `https://localhost:8444` -- `AURWEB_PHP_PREFIX` - - Default: `https://localhost:8443` - `AURWEB_SSHD_PREFIX` - Default: `ssh://aur@localhost:2222` diff --git a/doc/maintenance.txt b/doc/maintenance.txt index dacf2b60..39642f21 100644 --- a/doc/maintenance.txt +++ b/doc/maintenance.txt @@ -21,7 +21,7 @@ The RPC interface can be used to query package information via HTTP. Installation ------------ -The web backend requires a web server with PHP and an SQL database. The Git/SSH +The web backend requires a web server and an SQL database. The Git/SSH interface requires Python, several Python modules and an up-to-date version of Git. APCu or memcached can be used to reduce load on the database server. diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 0b91dd93..1763f427 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -6,9 +6,6 @@ services: - data:/data - step:/root/.step - memcached: - restart: always - redis: restart: always @@ -32,11 +29,6 @@ services: - data:/data - smartgit_run:/var/run/smartgit - cgit-php: - restart: always - volumes: - - ${GIT_DATA_DIR}:/aurweb/aur.git - cgit-fastapi: restart: always volumes: @@ -48,14 +40,6 @@ services: - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives - php-fpm: - restart: always - environment: - - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - volumes: - - data:/data - fastapi: restart: always environment: diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 1e466730..6580de30 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -25,26 +25,12 @@ services: mariadb: condition: service_healthy - php-fpm: - volumes: - - ./data:/data - - ./aurweb:/aurweb/aurweb - - ./migrations:/aurweb/migrations - - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - ./templates:/aurweb/templates - fastapi: volumes: - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates nginx: diff --git a/docker-compose.yml b/docker-compose.yml index a1c2bb42..0973fc0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,11 +10,9 @@ # - `ca` - Certificate Authority generation # - `git` - `port 2222` - Git over SSH server # - `fastapi` - hypercorn service for aurweb's FastAPI app -# - `php-fpm` - Execution server for PHP aurweb -# - `nginx` - `ports 8444 (FastAPI), 8443 (PHP)` - Everything -# - You can reach `nginx` via FastAPI at `https://localhost:8444/` -# or via PHP at `https://localhost:8443/`. CGit can be reached -# via the `/cgit/` request uri on either server. +# - `nginx` - `port 8444 (FastAPI) +# - You can reach `nginx` via FastAPI at `https://localhost:8444/`. +# CGit can be reached via the `/cgit/` request uri on either server. # # Copyright (C) 2021 aurweb Development # All Rights Reserved. @@ -36,14 +34,6 @@ services: volumes: - step:/root/.step - memcached: - image: aurweb:latest - init: true - command: /docker/scripts/run-memcached.sh - healthcheck: - test: "bash /docker/health/memcached.sh" - interval: 3s - redis: image: aurweb:latest init: true @@ -133,26 +123,6 @@ services: test: "bash /docker/health/smartgit.sh" interval: 3s - cgit-php: - image: aurweb:latest - init: true - environment: - - AUR_CONFIG=/aurweb/conf/config - - CGIT_CLONE_PREFIX=${AURWEB_PHP_PREFIX} - - CGIT_CSS=/css/cgit.css - entrypoint: /docker/cgit-entrypoint.sh - command: /docker/scripts/run-cgit.sh 3000 - healthcheck: - test: "bash /docker/health/cgit.sh 3000" - interval: 3s - depends_on: - git: - condition: service_healthy - ports: - - "127.0.0.1:13000:3000" - volumes: - - git_data:/aurweb/aur.git - cgit-fastapi: image: aurweb:latest init: true @@ -189,32 +159,6 @@ services: - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives - php-fpm: - image: aurweb:latest - init: true - environment: - - AUR_CONFIG=/aurweb/conf/config - - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - - AUR_CONFIG_IMMUTABLE=${AUR_CONFIG_IMMUTABLE:-0} - entrypoint: /docker/php-entrypoint.sh - command: /docker/scripts/run-php.sh - healthcheck: - test: "bash /docker/health/php.sh" - interval: 3s - depends_on: - git: - condition: service_healthy - memcached: - condition: service_healthy - cron: - condition: service_started - volumes: - - mariadb_run:/var/run/mysqld - - archives:/var/lib/aurweb/archives - ports: - - "127.0.0.1:19000:9000" - fastapi: image: aurweb:latest init: true @@ -252,7 +196,6 @@ services: entrypoint: /docker/nginx-entrypoint.sh command: /docker/scripts/run-nginx.sh ports: - - "127.0.0.1:8443:8443" # PHP - "127.0.0.1:8444:8444" # FastAPI healthcheck: test: "bash /docker/health/nginx.sh" @@ -260,16 +203,12 @@ services: depends_on: ca: condition: service_healthy - cgit-php: - condition: service_healthy cgit-fastapi: condition: service_healthy smartgit: condition: service_healthy fastapi: condition: service_healthy - php-fpm: - condition: service_healthy sharness: image: aurweb:latest @@ -290,9 +229,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates pytest-mysql: @@ -319,9 +255,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates test: @@ -346,9 +279,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates volumes: diff --git a/docker/README.md b/docker/README.md index cc1f5df0..51e485f6 100644 --- a/docker/README.md +++ b/docker/README.md @@ -55,8 +55,7 @@ can proceed. ### Querying the RPC -The Fast (Python) API runs on Port 8444, while the legacy PHP version runs -on 8443. You can query one like so: +The Fast (Python) API runs on Port 8444. You can query one like so: ```sh curl -k "https://localhost:8444/rpc/?v=5&type=search&arg=python" diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index 99804d1d..9b167553 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -27,10 +27,6 @@ http { server fastapi:8000; } - upstream cgit-php { - server cgit-php:3000; - } - upstream cgit-fastapi { server cgit-fastapi:3000; } @@ -39,54 +35,6 @@ http { server unix:/var/run/smartgit/smartgit.sock; } - server { - listen 8443 ssl http2; - server_name localhost default_server; - - ssl_certificate /etc/ssl/certs/web.cert.pem; - ssl_certificate_key /etc/ssl/private/web.key.pem; - - root /aurweb/web/html; - index index.php; - - location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { - include uwsgi_params; - uwsgi_pass smartgit; - uwsgi_modifier1 9; - uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; - uwsgi_param PATH_INFO /aur.git/$3; - uwsgi_param GIT_HTTP_EXPORT_ALL ""; - uwsgi_param GIT_NAMESPACE $1; - uwsgi_param GIT_PROJECT_ROOT /aurweb; - } - - location ~ ^/cgit { - include uwsgi_params; - rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=$1&$2 last; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG /etc/cgitrc; - uwsgi_pass uwsgi://cgit-php; - } - - location ~ ^/[^/]+\.php($|/) { - fastcgi_pass php-fpm:9000; - fastcgi_index index.php; - fastcgi_split_path_info ^(/[^/]+\.php)(/.*)$; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - include fastcgi_params; - } - - location ~ .+\.(css|js?|jpe?g|png|svg|ico)/?$ { - try_files $uri =404; - } - - location ~ .* { - rewrite ^/(.*)$ /index.php/$1 last; - } - - } - server { listen 8444 ssl http2; server_name localhost default_server; diff --git a/docker/health/memcached.sh b/docker/health/memcached.sh deleted file mode 100755 index 00f8cd98..00000000 --- a/docker/health/memcached.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec pgrep memcached diff --git a/docker/health/php.sh b/docker/health/php.sh deleted file mode 100755 index 7325946b..00000000 --- a/docker/health/php.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec printf "" >>/dev/tcp/127.0.0.1/9000 diff --git a/docker/mariadb-entrypoint.sh b/docker/mariadb-entrypoint.sh index a00f6106..a6fb9a76 100755 --- a/docker/mariadb-entrypoint.sh +++ b/docker/mariadb-entrypoint.sh @@ -12,7 +12,7 @@ while ! mysqladmin ping 2>/dev/null; do done # Configure databases. -DATABASE="aurweb" # Persistent database for fastapi/php-fpm. +DATABASE="aurweb" # Persistent database for fastapi. echo "Taking care of primary database '${DATABASE}'..." mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'localhost' IDENTIFIED BY 'aur';" diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh deleted file mode 100755 index dc1a91de..00000000 --- a/docker/php-entrypoint.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -eou pipefail - -for archive in packages pkgbase users packages-meta-v1.json packages-meta-ext-v1.json; do - ln -vsf /var/lib/aurweb/archives/${archive}.gz /aurweb/web/html/${archive}.gz -done - -# Setup database. -NO_INITDB=1 /docker/mariadb-init-entrypoint.sh - -# Setup some other options. -aurweb-config set options cache 'memcache' -aurweb-config set options aur_location "$AURWEB_PHP_PREFIX" -aurweb-config set options git_clone_uri_anon "${AURWEB_PHP_PREFIX}/%s.git" -aurweb-config set options git_clone_uri_priv "${AURWEB_SSHD_PREFIX}/%s.git" - -# Listen on :9000. -sed -ri 's/^(listen).*/\1 = 0.0.0.0:9000/' /etc/php/php-fpm.d/www.conf -sed -ri 's/^;?(clear_env).*/\1 = no/' /etc/php/php-fpm.d/www.conf - -# Log to stderr. View logs via `docker-compose logs php-fpm`. -sed -ri 's|^(error_log) = .*$|\1 = /proc/self/fd/2|g' /etc/php/php-fpm.conf -sed -ri 's|^;?(access\.log) = .*$|\1 = /proc/self/fd/2|g' \ - /etc/php/php-fpm.d/www.conf - -sed -ri 's/^;?(extension=pdo_mysql)/\1/' /etc/php/php.ini -sed -ri 's/^;?(open_basedir).*$/\1 = \//' /etc/php/php.ini - -# Use the sqlite3 extension line for memcached. -sed -ri 's/^;(extension)=sqlite3$/\1=memcached/' /etc/php/php.ini - -exec "$@" diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 85403969..7aa225fa 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -15,9 +15,8 @@ pacman -Sy --noconfirm --noprogressbar archlinux-keyring pacman -Syu --noconfirm --noprogressbar \ --cachedir .pkg-cache git gpgme nginx redis openssh \ mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \ - php php-fpm memcached php-memcached python-pip pyalpm \ - python-srcinfo curl libeatmydata cronie python-poetry \ - python-poetry-core step-cli step-ca asciidoc \ + python-pip pyalpm python-srcinfo curl libeatmydata cronie \ + python-poetry python-poetry-core step-cli step-ca asciidoc \ python-virtualenv python-pre-commit exec "$@" diff --git a/docker/scripts/run-memcached.sh b/docker/scripts/run-memcached.sh deleted file mode 100755 index 90784b0f..00000000 --- a/docker/scripts/run-memcached.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec /usr/bin/memcached -u memcached -m 64 -c 1024 -l 0.0.0.0 diff --git a/docker/scripts/run-nginx.sh b/docker/scripts/run-nginx.sh index 6ece3303..e976f67d 100755 --- a/docker/scripts/run-nginx.sh +++ b/docker/scripts/run-nginx.sh @@ -5,8 +5,6 @@ echo echo " Services:" echo " - FastAPI : https://localhost:8444/" echo " (cgit) : https://localhost:8444/cgit/" -echo " - PHP : https://localhost:8443/" -echo " (cgit) : https://localhost:8443/cgit/" echo echo " Note: Copy root CA (./data/ca.root.pem) to ca-certificates or browser." echo diff --git a/docker/scripts/run-php.sh b/docker/scripts/run-php.sh deleted file mode 100755 index b86f8ce5..00000000 --- a/docker/scripts/run-php.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -eou pipefail - -exec php-fpm --fpm-config /etc/php/php-fpm.conf --nodaemonize diff --git a/po/Makefile b/po/Makefile index 0b579f48..8fd17515 100644 --- a/po/Makefile +++ b/po/Makefile @@ -48,20 +48,12 @@ all: ${MOFILES} lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ msgmerge -U --no-location --lang="$$lang" $< aurweb.pot -POTFILES-php: - find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES-php - POTFILES-py: find ../aurweb -type f -name '*.py' -printf '%P\n' | sort >POTFILES-py -update-pot: POTFILES-php POTFILES-py +update-pot: POTFILES-py pkgname=AURWEB; \ - pkgver=`sed -n 's/.*"AURWEB_VERSION", "\(.*\)".*/\1/p' ../web/lib/version.inc.php`; \ - xgettext --default-domain=aurweb -L php --keyword=__ --keyword=_n:1,2 \ - --add-location=file --add-comments=TRANSLATORS: \ - --package-name="$$pkgname" --package-version="$$pkgver" \ - --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ - --directory ../web --files-from POTFILES-php -o aurweb.pot; \ + pkgver=`sed -n 's/version\s*=\s*"\(.*\)"/\1/p' ../pyproject.toml`; \ xgettext --default-domain=aurweb -L python --join-existing \ --keyword=translate \ --add-location=file --add-comments=TRANSLATORS: \ @@ -73,7 +65,7 @@ update-po: ${MAKE} ${UPDATEPOFILES} clean: - rm -f *.mo *.po\~ POTFILES-php POTFILES-py + rm -f *.mo *.po\~ POTFILES-py install: all for l in ${LOCALES}; do mkdir -p ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done @@ -82,4 +74,4 @@ install: all uninstall: for l in ${LOCALES}; do rm -rf ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done -.PHONY: all update-pot update-po clean install uninstall POTFILES-php POTFILES-py +.PHONY: all update-pot update-po clean install uninstall POTFILES-py diff --git a/test/test_spawn.py b/test/test_spawn.py index 25b9ebfc..c57c9b52 100644 --- a/test/test_spawn.py +++ b/test/test_spawn.py @@ -7,10 +7,9 @@ import pytest import aurweb.config import aurweb.spawn -from aurweb.exceptions import AurwebException # Some os.environ overrides we use in this suite. -TEST_ENVIRONMENT = {"PHP_NGINX_PORT": "8001", "FASTAPI_NGINX_PORT": "8002"} +TEST_ENVIRONMENT = {"FASTAPI_NGINX_PORT": "8002"} class FakeProcess: @@ -49,34 +48,6 @@ class MockFakeProcess: return proc -@mock.patch("aurweb.spawn.PHP_BINARY", "does-not-exist") -def test_spawn(): - match = r"^Unable to locate the '.*' executable\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - -@mock.patch("subprocess.Popen", side_effect=MockFakeProcess(1).process) -def test_spawn_non_zero_php_binary(fake_process: FakeProcess): - match = r"^Received non-zero error code.*$" - with pytest.raises(AssertionError, match=match): - aurweb.spawn.validate_php_config() - - -def test_spawn_missing_modules(): - side_effect = MockFakeProcess(stdout=b"pdo_sqlite").process - with mock.patch("subprocess.Popen", side_effect=side_effect): - match = r"PHP does not have the 'pdo_mysql' module enabled\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - side_effect = MockFakeProcess(stdout=b"pdo_mysql").process - with mock.patch("subprocess.Popen", side_effect=side_effect): - match = r"PHP does not have the 'pdo_sqlite' module enabled\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - @mock.patch.dict("os.environ", TEST_ENVIRONMENT) def test_spawn_generate_nginx_config(): ctx = tempfile.TemporaryDirectory() @@ -86,13 +57,9 @@ def test_spawn_generate_nginx_config(): with open(nginx_config_path) as f: nginx_config = f.read().rstrip() - php_address = aurweb.config.get("php", "bind_address") - php_host = php_address.split(":")[0] fastapi_address = aurweb.config.get("fastapi", "bind_address") fastapi_host = fastapi_address.split(":")[0] expected_content = [ - f'listen {php_host}:{TEST_ENVIRONMENT.get("PHP_NGINX_PORT")}', - f"proxy_pass http://{php_address}", f'listen {fastapi_host}:{TEST_ENVIRONMENT.get("FASTAPI_NGINX_PORT")}', f"proxy_pass http://{fastapi_address}", ] diff --git a/web/html/404.php b/web/html/404.php deleted file mode 100644 index 9f81d115..00000000 --- a/web/html/404.php +++ /dev/null @@ -1,47 +0,0 @@ - - -
    -

    404 -

    -

    - -
      -
    • - : - -
    • -
    • - ' . htmlspecialchars($gitpkg) . '', - '' . htmlspecialchars($gitcmd) . '') ?> -
    • -
    • - ', '', - '' . htmlspecialchars($gitpkg) . '') ?> -
    • -
    - -
    - - - -
    -

    503 -

    -

    -
    - -\n"; -echo "

    ".__("Accounts")."

    \n"; - -if (isset($_COOKIE["AURSID"])) { - if ($action == "SearchAccounts") { - - # security check - # - if (has_credential(CRED_ACCOUNT_SEARCH)) { - # the user has entered search criteria, find any matching accounts - # - search_results_page(in_request("O"), in_request("SB"), - in_request("U"), in_request("T"), in_request("S"), - in_request("E"), in_request("R"), in_request("I"), - in_request("K")); - - } else { - # a non-privileged user is trying to access the search page - # - print __("You are not allowed to access this area.")."
    \n"; - } - - } elseif ($action == "DisplayAccount") { - # the user has clicked 'edit', display the account details in a form - # - if (empty($row)) { - print __("Could not retrieve information for the specified user."); - } else { - /* Verify user has permission to edit the account */ - if (can_edit_account($row)) { - display_account_form("UpdateAccount", - $row["Username"], - $row["AccountTypeID"], - $row["Suspended"], - $row["Email"], - $row["BackupEmail"], - $row["HideEmail"], - "", - "", - $row["RealName"], - $row["LangPreference"], - $row["Timezone"], - $row["Homepage"], - $row["IRCNick"], - $row["PGPKey"], - $PK, - $row["InactivityTS"] ? 1 : 0, - $row["CommentNotify"], - $row["UpdateNotify"], - $row["OwnershipNotify"], - $row["ID"], - $row["Username"]); - } else { - print __("You do not have permission to edit this account."); - } - } - - } elseif ($action == "DeleteAccount") { - /* Details for account being deleted. */ - if ($row && can_edit_account($row)) { - $uid_removal = $row['ID']; - $uid_session = uid_from_sid($_COOKIE['AURSID']); - $username = $row['Username']; - - if (in_request('confirm') && check_token()) { - if (check_passwd($uid_session, $_REQUEST['passwd']) == 1) { - user_delete($uid_removal); - header('Location: /'); - } else { - echo "
    • "; - echo __("Invalid password."); - echo "
    "; - include("account_delete.php"); - } - } else { - include("account_delete.php"); - } - } else { - print __("You do not have permission to edit this account."); - } - } elseif ($action == "AccountInfo") { - # no editing, just looking up user info - # - if (empty($row)) { - print __("Could not retrieve information for the specified user."); - } else { - include("account_details.php"); - } - - } elseif ($action == "UpdateAccount") { - print $update_account_message; - - if ($row && !$success) { - display_account_form("UpdateAccount", - in_request("U"), - in_request("T"), - in_request("S"), - in_request("E"), - in_request("BE"), - in_request("H"), - in_request("P"), - in_request("C"), - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - in_request("J"), - in_request("CN"), - in_request("UN"), - in_request("ON"), - in_request("ID"), - $row["Username"]); - } - - } elseif ($action == "ListComments") { - if ($row && has_credential(CRED_ACCOUNT_LIST_COMMENTS, array($row["ID"]))) { - # display the comment list if they're a TU/dev - - $total_comment_count = account_comments_count($row["ID"]); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $username = $row["Username"]; - $uid = $row["ID"]; - $comments = account_comments($uid, $per_page, $offset); - - $comment_section = "account"; - include('pkg_comments.php'); - - } else { - print __("You are not allowed to access this area."); - } - - } else { - if (has_credential(CRED_ACCOUNT_SEARCH)) { - # display the search page if they're a TU/dev - # - print __("Use this form to search existing accounts.")."
    \n"; - include('search_accounts_form.php'); - - } else { - print __("You are not allowed to access this area."); - } - } - -} else { - # visitor is not logged in - # - print __("You must log in to view user information."); -} - -echo ""; - -html_footer(AURWEB_VERSION); - -?> diff --git a/web/html/addvote.php b/web/html/addvote.php deleted file mode 100644 index 4b52a3bb..00000000 --- a/web/html/addvote.php +++ /dev/null @@ -1,116 +0,0 @@ -" . __("New proposal submitted.") . "

    \n"; - } else { -?> - - -

    - - -
    -

    - -
    -

    - - - -

    -

    - - -

    -

    -
    -
    - - - " /> -

    -
    -
    ->10<3$laUEN!Q#6008Pn zbXOpBG|m5lHpl75-vVhpC(a!4x$h*`V2lakNUt?{-fw^e?ODm zN2l+hb*}S!PafO;yvB^)?EDQ@iLzn>_b!b9fT^^f*w@{?%2`uO4TKQ2Smxg5ikKW2 zQ*A?S8C;#@KdJ0k753J9XG*F&MOl%LT4?kK&;(>rVhi9U1?;<+SJ-zbGm)>gYnJLH z%w}?U0WeGe;1*6<3W^4axh(3Rm06q~vz;20p9m)iop2}sG)ey@z5ZEzGBay7^^(hv zOFvOQpz-HtC(no`dwszCljyn5{FA6S0{1JalqoLl^-)5KLk=qdBTC!pRYl~Zu4~eY z`jm=y&G7{n7Ek2g)hM=KE?#h6uBwFA4#F~l!gQh1QhEZ zVRX6TH*Dt7a2hD-{!i`M-_>j)z6g%ca~xCE?`N$AK|HXr$u$Q&P^B$#;&T%7mJM zuo8+h+l1P5KqsF_FkI5xbvE#m)@W=uI^t;J3`eFie;MX?$(u}bW!*u-&#nH?kt^%d zx|YaA-ExCV9U&V&;SIrCEb(@465tV50>|q>SR zoU@zOxr=q~2E8QP8G}nzeV$%*DuQQq|Tc`gx!LmYDeG= zxKY+=D~=fjPC4|=pTYudRG(20hFb0uLqD#-tI}K=Ka;(+@i-pI>=l)p6i$ z&9-~lq-@(Seb}1YT!Fy^x8xB-=ujz?L)W!@=ax`=LLfUDA2ZdD#!`(EzFdkzMFYWBytXn;~HGS8jwD~p^JH9 z(yY!Xaf-vSL#cK0=xru5#$e>dlTyIaB33aiIEI-;90sCX`viJ zA0i;5`@2n-HiiSnJS{XdI4WF@Dm#>@7=~DhfH|<5T9m?3X2M$XEY_)Boxvz8R1=d+ zB`^*2^JpfC?3HnEWQFUvg3{}9;A~0gk4%RM(^LTtAnciRWj)K8EL1z=nCL`vFJ0_8 z!lUO+=S6*pjK~uS5pwKHtY(>*-;1v^W&;MohRce{DXIOkviW#BfZjD`@$7ik~xbg$=6paDPdGZM^={xaJ@@q2g3F_z3%7tZk`C zur_-ZmzZiRoB!k5KDqsu&zw`4dhk;}>?d+hUXaSqbmfQjyn1xNf=oQU%Ay=+y!NUKi@<_oc32aa9U%msvJaVpldpOC0k^?27Mr#?k`zim@2j!tQM8L z>5NktPROk;Vy)csIG|uk19*2kOGxmT0O-PQd40OA%-8}209F~HZf=Td#(;;6XTF|h zGG5=G!a^xRAc~u#SS3Xwrx^tTPhb|}T=HW#cvOeJbg_ZtCNaD3TxyjDGOH`2F&N~i zK7%H?&d0K(b}N}2LKXZU=#8)o@P$KnIRtT-efg^}&%OhchdWNi^uZJJ5~ zsROEr60OfOob6dz%ll^ zw`BJj(gPB=SuLcx+ZjhamX2)_&8oO;QyKpP14>$%p2EHQWqkkVu`xg(V}oVi}Ri1z*S+I zg&vwS4$uun2<^C{X&aMF^DN3nO)lxHR>1oQ{Z?T`8iK%gj1M1j_B(}M{>u?&qPqCf z@uD>bS$InQJq`cN+P@oOa_&vEnx|U=u1hPu{XyV*CC>MBy&6G%>l26W*t=CBlXDDG z6=*#pihOP#lTE22?q`sZa3sigQ^t;7EsE0h^Jrtf7+{UX`CfGHD~LprH&0G2mS><_ zyZVj0jd5Wx@9sBtbgeo`9e}YJXj8`SWrhXbgC%E!X(`q$mp5gTKS>%Vl39a^@Fnh> zrQ}ro+g6k_&$ppZg>ZU`g8U#2p%uT|JE^pGL@X@KOl6nXY1 zV10N_gQU6nR({-gHmuQc?o@7=>Vm(tjfji_s`T&NmFf5I7ZHuF&zOH)4_MS*J1a5m zj^ydAYi5p=oW5!qyL@3mnsD;>k10{nJhlr|3H{Ut`O+P9Pj*qF5;xUngQOxl>`5OT z&)Tz_Gd^M50N7Kn(8`Ba!k$|~2>J){l{t}mhqLb8Xs!=Mz(vm42#U*y-ogL-AGoQQ8XB4ez$vAk@nHI82! z8d9IJr16mXG{~R@PZ>x}nY`_B1tCNdc4powbO1}zff z9u12=;9MC{dh4p~e6-0|uF6$`Pj{xAt0Jr+{39w6dq}am5a(PV>Um-HRfEPPS(G*8 z$>LlpE%mSB?%8W)=@7LK^+u-e%_XBp-gtU|1On9feMMGxLNVz3l0l#Z3wFJUrNZNq z=)&0bq%9%iA`=U@3afIyi?UKitiEN7$7@|MhLB9j`y0^mougfz51B1v%7Z-$^ZfI} zwQvKT$?R|7l%b=L+n|c)ZRmSslV|r|ir*yXkw!=j;o4)`)&9i&vQr`V;o?N7*4H~GRuFf>EYM8 z75NO70;8S&Z%M)#lxvZ-#&%;@_oFzzNuu?^L#dErg-H6l?T#=CR>*qr2Eb5oAS$-@ zoE>VjIJo&!`uPMVZlxmZYekd=eC_k5UPV}Oh21VDP6mFwYue2SrxK|*7%OfVUP{Lv z7Bo(pkXOYoC0`Q$Sho|f75Vm$&E>1!MS3I*0bA3=k`Ptq=` zl*jVdmYB(g`_Havu^{x)3A!sO&}>gg5Ju%aw8 z(+7dG`wX8zE`;xWtj@Ubij)aeaF&b*7q5Q`Z~xCB_jWZqY}f9 zM}Pd%k?O0iHVeBp^{Oh54+%Wb2-_%_+x|9(b-|WRit}c1S4wB}MUelnUs-3h^6Frg zO7;Vl?oT<|9WI z)L({xmKW)r8PZaTJv->_F7ufCkdUk_BqyGHn~#)mOu!*2f>+oWe;qhvDVW%|*AkrR zayWjz;XR8b51uDI6FGJC4NKRFx5m9Y>Jzus5nG5Cf@hoBqcE(*=Ir#pclmAOe)M@2 zY!S#sdBv{GRi1=+VAzIO^2(O7+;kBPd+Z|GuYN*qfJY~^SL6Ev(d0jSf^2IT>)CNT zZOqG06m_S5M@gi7+;62DdcmB@|KU<9sJEIwx(XDPyb?&a1H>~(pjJx$s`>iHwm@^- zh!zD$RqscY>gW+nnFhN?DKq<;laZ)~N3zETIFxNm7^d7(t?+14rhU(;bbM*VOZ%#q zn(GTJgf2XNsNRAaXk)G===ivdH|CQ1DJhk#!=yN9+%k33o3K-4GdEp*XQ|{0J)n)t zTUfA*VW55-_bEY^pleU?%!MJBBgK8ZE+d*_Yk`vF+dT5^v^R!j_S}SPDTDiJ4?&(a zdc)daUl3HUDW{@wn4x6v>y}V|;WQ1pVny=fX%=Tx=-I7HeC4#0q!Cd0sM3e7iim?E zr7WdCd-HrNeH@ZKjYy)>XB@q|?n>!{etU;K*_GiBSDEmy0qk1e`FXOHeiKL%&%M+) z84ChG>x!ZQ%&yHHk!p)30$b1nh^Uz~G}Q0kz?9BQmgBy=9b#6FI6KVC%gc#Lgdfj8 zlf8g_RGi3+ql39R3HP<(a1aLVeycB!uGTgx@KHD+5XB+kEmcJeuV>BU-?lNBnVz=>k(&9qn^S z7K2hxxY;uFiO@8m`**ob>EWLwtBYq-B*Bhvd_c|b{kywN<`Ue${v}YPZI;N(=AMsp zzt1^8&0lz`)WB6GE>KH_W~`CJ@i=Fd0~3=aTlTL?Hczl?@$ z@BcaT9p-r6)8HIU)FCvs6%bfX!F*8Cl4U^mgjr53K-SB@l%^OGPh^%ysA(2-InjRn z$L4ZSPF6O)%j7mrM<%UT_P5z%%R(~R3>Bb?TCPj$qsIG3j1jdM5^PKT%K)ZkYU%22 z1FY>E0pB-&9$NH}opdQ%zkIw&ZP?oUs>HGwsnzl+n&H;4zXZ4K8iH(%P-W&KX`Mvp4;W6k)w(@UKYq)zF%33UvR9^Vdk;p ze$x>&*Dolow}vb2^iK)dv>3j$e1f8)W_(v<&u&_R%F8QT-6et_4ugjT&e^(?)N74! zr2@lX=dG9+Sa7}CgE(~DW}Y>ntw@+ubsO7+u?M(0S$DLMecn?v9e*-+#A%EEo@0ha zx1FYSOT>&~{e@o~9eQl@oW}S|=?ihQX2$xo?Hbho4LBM{?XUEs)~MWMDzsd_Ps+)0 zm$z=F_RZ-tIx4Az(0(TKH&Tul@?vg`BH_PBN0ag(jz+7MvRw$+cbVT)b^MMkF%N^0 zn5`K-mQgtGmis_K@Q}hlM3J)?0H`$WM2|iBb-}+ajxO6#NnsY(sC%|`T~uY-SX@1z zc^lz?q7d#;BCtY4ota^k=$|s_$$Mft&vLi!yeM$eeL2pU1KwfN)Z!}^#Df}xSuXc8 zTfCh8LxwYVEYH_>0H3#aLxqFxW-=j4V+dh50`aTcMAjU=$Hd*a56>BsM}a|~4`SbF z%r@~aN+OVEgjMv158JDSyJK%X8vjgDdw4FyHQamUm-I~e{67C1Q|Jw27am{KRPd4G z&e!7)(6SD2Mg+JhIQhBU0YDlm^*|gda~Civ83m}cf~>44^q~S2+5z&A{(l5sKF;p0 zq5pruh}}fmoq+j&9V~oY1A-BLE`Z?RUR4J?A{`Jpl*=BG%MU(F5+Sz{!V)16=3lFeiZt5(_0ZH-#a$v|q>+9uvDnZ60#RRUswf)x%7pUU@TJ6OOWbM)&`B92~4tQuME0y@Gmst2;XK94s^n zOY~5t;;Ej-k{P77BRBGneohUNW?QAO@!S)DzanT>G*-OhvoI?qWZM!lNM3EPB9`nD zyJBe`KY7x%L9a*_I#up|5gPmq^ZIK(9<@pGQpA!ffzE%TS%+q{ei-rjQdEk0!ZJry zTXd3-a8k#059OQ@U)ANA+YCd-I$O~0cy00o9b_mb!drm{T2yvd!cFcj(d*vdh^4#I zu;)d>&D~98cZtN-UmX|;Z--uuZ^PUt;@HIcP-(d@hIQ3!NfmFS-C@YgXA^P-DA@QQ z?v7PKM|sozZ~EcQ59IXp1f>Q9RmMcX5tBbMHy4wdO8x1}mx7|AuDW>38n(|`qaz~< zO+D6CtQ64-$%TX0aIG>dYrM;sjFr0S}w*ye$Eo(&BRtdf#+HTHu_Q0Vh8B{sZ} z_G0bK#O!QmJ{CHOHfts^3zoV1WD|7Ss=4Kg`htw{mel`go zHR0&!DEjCq_{$d>2}Tk}M@Q(xeSpF1*NB3GPUd3aDDp6{B3(q#ODyV0($~+0zZj7+ z5F>kOvd(cyoPV^n$y?jlAWtNce>b?TlhM#bw)kJH)eOrCH$EH>JhR#8P2!wxZfU8q z=^+7w!D(+@ot?v9aAGNvrHMJyQ}dgIp-_;Tvxu-T+CYnX7bX%Wsj#>>B1o-Cje*0% z{asXieE0eO{Oamz2ZYww*LS8ZP~K(nXBYT&4fFEK29e#22ws_1`vK&jvD;J8VdZ2b zR%XQzHbRS`7r~{pE{JJz0Ya%Pv5GE29g&zNMHC@1?9jR0ceOi>0;qEatn6Nzd|vhU z2}+W&h;tI$wgdWJm!hMeYK)+gx|=ED6x-nEs9d?8L!xwWOlPeOy9$Tog2_$jWGcD! zY_*++R`mk4xVZS1kMfy?DTeUb)*P+N$~Hpvh+y`$kHNogH($By;T7&W@vsii%}- z939qJEp$~0hVH-(eIk?~Ti4E{eX+XRWRpF^Z;t;Kxv^o`U@l8iT|-P2 z8CmyR6vZqSp*RUzonU|mh|qC?Bx2 z2s%1Ce1R{7wIJd@4x6hzYq|SXS8inM;CxN(RZfBAH>*hPEYQq*gy-di5tyH$ppfz%#vb zjQ0L^OTOUycM_aX3^q14^uA%zw-l0$arB}D zMiu6wyGI|Dp~_fw&hruaB|3D9KLc*OYKFbMy&nq;Q#uUir~*V0p(ifXdrCn;k(io_ zBQGyc_2|)RLf~z|tfYp;Y>U5m>*X3DM1($N*Z<-`RZR^iObO9<*50lVArg7NJYX5Y za|(NgHT=l&5bD!=Posl;9TzaPW7vLoyF79kJ2;{lp}f0;9iKlsv7YjYser^vh>H!R zL2!{LxETOx?i`Ujc->%jT{a90PpIn~0EL7N4C=3(iMDeQ!(KyWJPtbZ+*u;jhRGW4 z(fkWBLPzLEgCN`VZBY`beDkoIE}}?KTT2U*Yx5D#-#_W0D=U^Y!yB8Mh}PB|wb*O= z5J_M33Wnh~V=Ia&4^L0kw{IEuXMxy$d)r9y@#9C%X;TvuD3AiZwnBVws=)wvL(N@% zDZGHp-~mt)VsP>71D4&!3yE3-1>HB8ARmcU`8@BW5dMmA)EJ_KW)h(x zMkRQ{V#@k5Dw2{q*q}DlG?3CU7cZ#Ly=7`*KX>!;|# zZTmU#_kN3;9)Y7kR_JTzH7Jb2S)b6uum3Nwr*n%&QO*rt;#dl@2+Jdg$MrDLIQ9nU zx7R%y#8uyqrUAZsL^%_ae4xOH9!uOpYe1&g;J`qv z*M9$J-pivN7A8YiBcm^mUXX&`hIy8a=XMhrzu2+FsnkY0aR1eV)8EEe>oN+Mm>U!O z-mc}K<~J)ke2vAw-ZPV-i5Z!JO0R7adOdP7^7CrW48Ga_nN|)aVUyKVT-=RQqA_a+ zz1#ddm`Nfk;j}MA`#xPkXq%N!?!Vb-OWYSO$mu=!>VK6iQ_6=s#4)=>=7XXQpK_T! z0!gEGJmPYQv0g#~ox%93e_$Fz@9WEbK70_`H}UnAtgfzx9xOHG%P zvbw$fuIt_GU&Qq|BS^Q@z$e2xw&VQx{GNGYZ)cbFB>bzKK_p6)@0a<4Fb#*NW5dFq z&dy75zkIoAcgC??F@Kos@FZJP`A zvfL;WJ64u?`7L}1HCm9%9ffNYA;Qp6WhoR|Aa%EPgr(LRZtd5K7lX2(eSlvs?B;2l zk7Kp6^K|X-AdyVPQ31Z~U4J$=vg8AqwTi~}PCkGB+~9xlU0K0Fz>S}Wr{6IQRjQw@ z4&q80SOX#={gGsbJbG-llHppUYEqJK1 zl*GSp5pDw@j7~TG`r41aH~kX+?4w}M;66gCtE=mWim;K9(Km~>CC6Eym6$Z&_a#t- z5&y7HH0b#TpXb*A!XR_J@S;MIE+_23sz4E90DX4LI2N+VI+2ZvOVhECJ$Nj`OzPs| z(oGuKDL6aMM@8U_1^3^B**s=?5|b9}e|H}%y55t}1GL*gxhAiDlZK`y=|UtE6B9QN zkC61%FL#7MD_{%%i+AzF(7DMV&{3DwfU@SCFRlWR#RPYgO`> zD_DHSl^{t;$**N)N-&sA@r(2jfS>d};YtYnAe`!9&w*6_sF;|1WKMB$vGwsrpM={Q z*k!qu__J1cW#w}YPELBt+2rKpcKezt_?=%jm7Th7wt2te*6AnDIiVGdykW=kgHbKv zSmIiByoNz<{`wSKMM=kqt1C>ushBy=3eXHA-ho+I-f`9Vs*y#+iXn!9mHtR-CDE9^ z={x)KNym>YpS7@oAbvIA!2@GTNJ}dtbd7O=2w;|{{wcr0NEV*|NJ#K&R}zw$hBMjw zG_?i32SeXmNuv`OB|~T|U`bw7>IMc>`T6;@1KHBvBtWq0GuJQlkQd8=ET;7?MRakw zxw(_CC*O@1uZp)_5zF18m78|z`Lp_dTQadsZZ`#WB~71)iQrR|C2AT5S48<2^$70N z%HmR;h8p=V@Q!HRcI-eROh@5@bTC_&0v*0dFuRVumvKYm2vonSz9J#bd$!;-NDGv(0aUB8_Q2oJ%KsgfT!q* z@9bl2Z0z3N%4hreWn~2Z=X+I|J2MjGmT4yx_Cfy<#~)k>!o7^7FB9|#q&kc9ZGQM( zmp;16d-9G+iXE^tvS6i(BAX%cYA!#>bA`8+427vVL24)wG8z~Ts#fuwqDv1&Vk$}(M_$J2ZEpkH~B=sEdsrq+A67-u)z<0VG`JxxCr=u?Gb;gaMbk;H%m zw#Tp^PGZi5Uq2liA9uU^xi391lp`CvIq;>Rw6xFV#r)b4KIgii6U4HRzOKqoKRcgy zIjCq)vmC-wPj*HqueLkk@uTM!6RDqya9i?+z_v;MX<&ei63bHm6=>spC!C{L!o&I+CglBl+hVD*AY+J32r|rH z1lsB!pN=_cj#cUysmN*#Q{yF3n2tIkGcc=e9B;ec;RX6@^VQ$XG)ebj!N{C^?)B8R zZ{PR~jEvSNO7$U*j!J+K;o;?dWoD+$fa$vU)9$#6^UE^}H4_v1Vx8<5-;=*=tgIk7 z9Nzt^$opm$NU_B9^uDk9CF2MnT;7LEU4TDw#%VP{s@d5+Sxh{2gl6z|?8}eo`BiRu zvWl83$1Fzgc=#OBg(0H6y?8V=@7*F_Yr>D`?%<#Y z4(|RUro3hE8`7UT{p;rPkWX$rwUP?R=+v_x)1A9BYW4|ss+TZ1SU|ul3kz2vibM|l zV1;(tU7FY~h?A4M#zrJ7o{z7uV#Rbpnkw2~h<4i=jt zGcqzT+~5S@eXwYZ<(Vy*6uO&}!v!vVC74BYlZ4O{|%qlSPK(q;obF zh^-4<9O#CpW$DI0v>Cr|$ekzLYT6RyP(Bt3>ppr)J^zB{Y;2tQ=~+(x_T9U8+1SVp@nyl70Pk=u;Pzy zV|_Y<4c{j<sl&c$9-HNKd(mT zg$D8m!2IyJ`1+KFkKWuv3=zZSy@tr zGW6qmW-%&mclblGnsLQf41bV1Ry+s#wt_=1N6?v%Wbhh#lw5Qe(UWvru5lPLAbr>z zT3s!)v9+a)G-Md(hrwXzDO1y0^SnbVJL0k{<4H#v7$N*Q>J2ce2Gg(efN7pxV-kO}7OPc2p82W-!_+6}IHYu}A zUTrojo`|TZ)%o6RgZoyzoAi!CI5Efs!6l{4l^Mox^{9)?OqRq;J*Cs)x#Fu8(NCe% zx+JT$l)5Tyc(2hM>u@tWWA?Z3KUk)-w||10yf+)XjlO7{`nXl(<$>Dn&ng7pjdA?$ z>av>p_67(_w-6GE1gI?%@~x?fVQ6Rw^yiQc#T#%qpYNJiKKH`;ut{@i=||kXvpk?Z z#>U3bJLMHh<&$ft+rh4?9Kkt-Y>9k9`Rx?~;nPRUih2z<(Lp)(zS&5!+y_ka9x)7q`OqmVRAgktG+dcw001Puhs9E#IcjKHk zJDs&o)4ImSQA0yIw`UcBUB{aPA8+CZ`uq1>Ist9t`q~0;4pS8tq`*c+O})0!m-3vJ zXr|GfD^MaV5?a!5!PV zm#>VBA^|H81dUBxd|GabJmZ|X%eg^y`0z4Xb)Otu>n-tipw*vKwoQdSSPAj`Z^|jD zVA-Uj$vuf?G8&BzQbJVvF-9Y;ChxBSsfs?Ewpecu#`=d)6?XFd7cA7V*wHFV1COdF zyqta&rf7=2p9z|+aj*eM>ve{Gvqiw?;@%~E_wXT|Bx-E;ERL$%^7)Lm>)vR|`1YSV z{fg;K?5{<2^Awxa*r#AcR&j9}>nd6c_*Ky&Nf2~H-iJ9kFktn_2bkQc1q8_Qr<`rE zpZpzE1}siYZ0tU1B@srT#ywLw<4y?MmG`FyT-<}Z*hdaU3&3C;q^YW-@?FU? a.headerlink { - visibility: visible; -} - -/* headings */ -h2 { - font-size: 1.5em; - margin-bottom: 0.5em; - border-bottom: 1px solid #888; -} - -h3 { - font-size: 1.25em; - margin-top: .5em; -} - -h4 { - font-size: 1.15em; - margin-top: 1em; -} - -h5 { - font-size: 1em; - margin-top: 1em; -} - -/* general layout */ -[dir="rtl"] #content { - text-align: right; -} - -#content { - width: 95%; - margin: 0 auto; - text-align: left; -} - -[dir="rtl"] #content-left-wrapper { - float: right; -} - -#content-left-wrapper { - float: left; - width: 100%; /* req to keep content above sidebar in source code */ -} - -[dir="rtl"] #content-left { - margin: 0 0 0 340px; -} - -#content-left { - margin: 0 340px 0 0; -} - -[dir="rtl"] #content-right { - float: right; - margin-right: -300px; -} - -#content-right { - float: left; - width: 300px; - margin-left: -300px; -} - -div.box { - margin-bottom: 1.5em; - padding: 0.65em; - background: #ecf2f5; - border: 1px solid #bcd; -} - -#footer { - clear: both; - margin: 2em 0 1em; -} - - #footer p { - margin: 0; - text-align: center; - font-size: 0.85em; - } - -/* alignment */ -div.center, -table.center, -img.center { - width: auto; - margin-left: auto; - margin-right: auto; -} - -p.center, -td.center, -th.center { - text-align: center; -} - -/* table generics */ -table { - width: 100%; - border-collapse: collapse; -} - - table .wrap { - white-space: normal; - } - -[dir="rtl"] th, -[dir="rtl"] td { - text-align: right; -} - -th, -td { - white-space: nowrap; - text-align: left; -} - - th { - vertical-align: middle; - font-weight: bold; - } - - td { - vertical-align: top; - } - -/* table pretty styles */ -table.pretty2 { - width: auto; - margin-top: 0.25em; - margin-bottom: 0.5em; - border-collapse: collapse; - border: 1px solid #bbb; -} - - .pretty2 th { - padding: 0.35em; - background: #eee; - border: 1px solid #bbb; - } - - .pretty2 td { - padding: 0.35em; - border: 1px dotted #bbb; - } - -table.compact { - width: auto; -} - - .compact td { - padding: 0.25em 0 0.25em 1.5em; - } - - -/* definition lists */ -dl { - clear: both; -} - - dl dt, - dl dd { - margin-bottom: 4px; - padding: 8px 0 4px; - font-weight: bold; - border-top: 1px dotted #bbb; - } - - [dir="rtl"] dl dt { - float: right; - padding-left: 15px; - } - dl dt { - color: #333; - float: left; - padding-right: 15px; - } - -/* forms and input styling */ -form p { - margin: 0.5em 0; -} - -fieldset { - border: 0; -} - -label { - width: 12em; - vertical-align: top; - display: inline-block; - font-weight: bold; -} - -input[type=text], -input[type=password], -input[type=email], -textarea { - padding: 0.10em; -} - -form.general-form label, -form.general-form .form-help { - width: 10em; - vertical-align: top; - display: inline-block; -} - -form.general-form input[type=text], -form.general-form textarea { - width: 45%; -} - -/* archdev navbar */ -#archdev-navbar { - margin: 1.5em 0; -} - - #archdev-navbar ul { - list-style: none; - margin: -0.5em 0; - padding: 0; - } - - #archdev-navbar li { - display: inline; - margin: 0; - padding: 0; - font-size: 0.9em; - } - - #archdev-navbar li a { - padding: 0 0.5em; - color: #07b; - } - -/* error/info messages (x pkg is already flagged out-of-date, etc) */ -#sys-message { - width: 35em; - text-align: center; - margin: 1em auto; - padding: 0.5em; - background: #fff; - border: 1px solid #f00; -} - - #sys-message p { - margin: 0; - } - -ul.errorlist { - color: red; -} - -form ul.errorlist { - margin: 0.5em 0; -} - -/* JS sorting via tablesorter */ -[dir="rtl"] table th.tablesorter-header { - padding-left: 20px; - background-position: center left ; -} -table th.tablesorter-header { - padding-right: 20px; - background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); - background-repeat: no-repeat; - background-position: center right; - cursor: pointer; -} - -table thead th.tablesorter-headerAsc { - background-color: #e4eeff; - background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); -} - -table thead th.tablesorter-headerDesc { - background-color: #e4eeff; - background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); -} - -table thead th.sorter-false { - background-image: none; - cursor: default; -} - -.tablesorter-header:focus { - outline: none; -} - -/** - * PAGE SPECIFIC STYLES - */ - -/* home: introduction */ -[dir="rtl"] #intro p.readmore { - text-align: left; -} -#intro p.readmore { - margin: -0.5em 0 0 0; - font-size: .9em; - text-align: right; -} - -/* home: news */ -#news { - margin-top: 1.5em; -} - - [dir="rtl"] #news h3 { - float: right; - } - #news h3 { - float: left; - padding-bottom: .5em - } - - #news div { - margin-bottom: 1em; - } - - #news div p { - margin-bottom: 0.5em; - } - - #news .more { - font-weight: normal; - } - [dir="rtl"] #news .rss-icon { - float: left; - } - #news .rss-icon { - float: right; - margin-top: 1em; - } - - #news h4 { - clear: both; - font-size: 1em; - margin-top: 1.5em; - border-bottom: 1px dotted #bbb; - } - [dir="rtl"] #news .timestamp { - float: left; - margin: -1.8em 0 0 0.5em; - } - #news .timestamp { - float: right; - font-size: 0.85em; - margin: -1.8em 0.5em 0 0; - } - -/* home: arrowed headings */ -#news h3 a { - display: block; - background: #1794D1; - font-size: 15px; - padding: 2px 10px; - color: white; -} - - #news a:active { - color: white; - } - -h3 span.arrow { - display: block; - width: 0; - height: 0; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #1794D1; - margin: 0 auto; - font-size: 0; - line-height: 0px; -} - -/* home: pkgsearch box */ -#pkgsearch { - padding: 1em 0.75em; - background: #3ad; - color: #fff; - border: 1px solid #08b; -} - - #pkgsearch label { - width: auto; - padding: 0.1em 0; - } - - [dir="rtl"] #pkgsearch input { - float: left; - } - #pkgsearch input { - width: 10em; - float: right; - font-size: 1em; - color: #000; - background: #fff; - border: 1px solid #09c; - } - - [dir="rtl"] .pkgsearch-typeahead { - right: 0; - float: right; - text-align: right; - } - - .pkgsearch-typeahead { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - padding: 0.15em 0.1em; - margin: 0; - min-width: 10em; - font-size: 1em; - text-align: left; - list-style: none; - background-color: #f6f9fc; - border: 1px solid #09c; - } - - .pkgsearch-typeahead li a { - color: #000; - } - - .pkgsearch-typeahead li:hover a, - .pkgsearch-typeahead li.active a { - color: #07b; - } - -/* home: recent pkg updates */ -#pkg-updates h3 { - margin: 0 0 0.3em; -} - - #pkg-updates .more { - font-weight: normal; - } - [dir="rtl"] #pkg-updates .rss-icon { - float: left; - } - #pkg-updates .rss-icon { - float: right; - margin: -2em 0 0 0; - } - - [dir="rtl"] #pkg-updates .rss-icon.latest { - margin-left: 1em; - } - #pkg-updates .rss-icon.latest { - margin-right: 1em; - } - - #pkg-updates table { - margin: 0; - direction: ltr; - } - - #pkg-updates td.pkg-name { - white-space: normal; - text-align: left; - } - - [dir="rtl"] #pkg-updates td.pkg-arch { - text-align: left; - } - #pkg-updates td.pkg-arch { - text-align: right; - } - - #pkg-updates span.testing { - font-style: italic; - } - - #pkg-updates span.staging { - font-style: italic; - color: #ff8040; - } - -/* home: sidebar navigation */ -[dir="rtl"] #nav-sidebar ul { - margin: 0.5em 1em 0.5em 0; -} - -#nav-sidebar ul { - list-style: none; - margin: 0.5em 0 0.5em 1em; - padding: 0; -} - -/* home: sponsor banners */ -#arch-sponsors img { - padding: 0.3em 0; -} - -/* home: sidebar components (navlist, sponsors, pkgsearch, etc) */ -div.widget { - margin-bottom: 1.5em; -} - -/* feeds page */ -[dir="rtl"] #rss-feeds .rss { - padding-left: 20px; - background: url(rss.png) top left no-repeat; -} - -#rss-feeds .rss { - padding-right: 20px; - background: url(rss.png) top right no-repeat; -} - -/* artwork: logo images */ -#artwork img.inverted { - background: #333; - padding: 0; -} - -#artwork div.imagelist img { - display: inline; - margin: 0.75em; -} - -/* news: article list */ -[dir="rtl"] .news-nav { - float: left; -} -.news-nav { - float: right; - margin-top: -2.2em; -} - - .news-nav .prev, - .news-nav .next { - margin: 0 1em; - } - -/* news: article pages */ -div.news-article .article-info { - margin: 0; - color: #999; -} - -/* news: add/edit article */ -#newsform { - width: 60em; -} - - #newsform input[type=text], - #newsform textarea { - width: 75%; - } - -#news-preview { - display: none; -} - -/* todolists: list */ -[dir="rtl"] .todolist-nav { - float: left; -} -.todolist-nav { - float: right; - margin-top: -2.2em; -} - - .todolist-nav .prev, - .todolist-nav .next { - margin: 0 1em; - } - -/* donate: donor list */ -#donor-list ul { - width: 100%; -} - /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ - [dir="rtl"] #donor-list li { - float: right; - } - #donor-list li { - float: left; - width: 25%; - min-width: 20em; - } - -/* download page */ -#arch-downloads h3 { - border-bottom: 1px dotted #bbb; -} - -/* pkglists/devlists */ -table.results { - font-size: 0.846em; - border-top: 1px dotted #999; - border-bottom: 1px dotted #999; - direction: ltr; -} - - [dir="rtl"] .results th {text-align: center; direction:rtl;} - .results th { - padding: 0.5em 1em 0.25em 0.25em; - border-bottom: 1px solid #999; - white-space: nowrap; - background-color:#fff; - } - - .results td { - padding: .3em 1em .3em 3px; - text-align: left; - } - - .results .flagged { - color: red; - } - - .results tr.empty td { - text-align: center; - } - -/* pkglist: layout */ -#pkglist-about { - margin-top: 1.5em; -} - -/* pkglist: results navigation */ -.pkglist-stats { - font-size: 0.85em; -} - -[dir="rtl"] #pkglist-results .pkglist-nav { - float: left; -} -#pkglist-results .pkglist-nav { - float: right; - margin-top: -2.2em; -} - -[dir="rtl"] .pkglist-nav .prev { - margin-left: 1em; -} - -.pkglist-nav .prev { - margin-right: 1em; -} - -[dir="rtl"] .pkglist-nav .next { - margin-left: 1em; -} -.pkglist-nav .next { - margin-right: 1em; -} - -/* search fields and other filter selections */ -.filter-criteria { - margin-bottom: 1em; -} - -.filter-criteria h3 { - font-size: 1em; - margin-top: 0; -} -[dir="rtl"] .filter-criteria div { - float: right; - margin-left: 1.65em; -} -.filter-criteria div { - float: left; - margin-right: 1.65em; - font-size: 0.85em; -} - -.filter-criteria legend { - display: none; -} - -.filter-criteria label { - width: auto; - display: block; - font-weight: normal; -} - -/* pkgdetails: details links that float on the right */ -[dir="rtl"] #pkgdetails #detailslinks { - float: left; -} -#pkgdetails #detailslinks { - float: right; -} - - #pkgdetails #detailslinks h4 { - margin-top: 0; - margin-bottom: 0.25em; - } - - #pkgdetails #detailslinks ul { - list-style: none; - padding: 0; - margin-bottom: 0; - font-size: 0.846em; - } - - #pkgdetails #detailslinks > div { - padding: 0.5em; - margin-bottom: 1em; - background: #eee; - border: 1px solid #bbb; - } - -#pkgdetails #actionlist .flagged { - color: red; - font-size: 0.9em; - font-style: italic; -} - -/* pkgdetails: pkg info */ -#pkgdetails #pkginfo { - width: auto; -} - -[dir="rtl"] #pkgdetails td { - padding: 0.25em 1.5em 0.25em 0; - } - - #pkgdetails #pkginfo td { - padding: 0.25em 0 0.25em 1.5em; - } - - #pkgdetails #pkginfo .userdata { - font-size: 0.85em; - padding: 0.5em; - } - -/* pkgdetails: flag package */ -#flag-pkg-form label { - width: 10em; -} - -#flag-pkg-form textarea, -#flag-pkg-form input[type=text] { - width: 45%; -} - -#flag-pkg-form #id_website { - display: none; -} - -/* pkgdetails: deps, required by and file lists */ -#pkgdetails #metadata { - clear: both; -} - -#pkgdetails #metadata h3 { - background: #555; - color: #fff; - font-size: 1em; - margin-bottom: 0.5em; - padding: 0.2em 0.35em; -} - -#pkgdetails #metadata ul { - list-style: none; - margin: 0; - padding: 0; -} - -[dir="rtl"] #pkgdetails #metadata li { - padding-right: 0.5em; -} - -#pkgdetails #metadata li { - padding-left: 0.5em; -} - -[dir="rtl"] #pkgdetails #metadata p { - padding-right: 0.5em; -} -#pkgdetails #metadata p { - padding-left: 0.5em; -} - -#pkgdetails #metadata .message { - font-style: italic; -} - -#pkgdetails #metadata br { - clear: both; -} - -[dir="rtl"] #pkgdetails #pkgdeps { - float: right; - width: 48%; - margin-left: 2%; - -} -#pkgdetails #pkgdeps { - float: left; - width: 48%; - margin-right: 2%; -} - -#pkgdetails #metadata .virtual-dep, -#pkgdetails #metadata .testing-dep, -#pkgdetails #metadata .staging-dep, -#pkgdetails #metadata .opt-dep, -#pkgdetails #metadata .make-dep, -#pkgdetails #metadata .check-dep, -#pkgdetails #metadata .dep-desc { - font-style: italic; -} - -[dir="rtl"] #pkgdetails #pkgreqs { - float: right; - width: 48%; -} - -#pkgdetails #pkgreqs { - float: left; - width: 50%; -} - -#pkgdetails #pkgfiles { - clear: both; - padding-top: 1em; -} - -#pkgfilelist li.d { - color: #666; -} - -#pkgfilelist li.f { -} - -/* mirror stuff */ -table td.country { - white-space: normal; -} - -#list-generator div ul { - list-style: none; - display: inline; - padding-left: 0; -} - - #list-generator div ul li { - display: inline; - } - -.visualize-mirror .axis path, -.visualize-mirror .axis line { - fill: none; - stroke: #000; - stroke-width: 3px; - shape-rendering: crispEdges; -} - -.visualize-mirror .url-dot { - stroke: #000; -} - -.visualize-mirror .url-line { - fill: none; - stroke-width: 1.5px; -} - -/* dev/TU biographies */ -#arch-bio-toc { - width: 75%; - margin: 0 auto; - text-align: center; -} - - #arch-bio-toc a { - white-space: nowrap; - } - -.arch-bio-entry { - width: 75%; - min-width: 640px; - margin: 0 auto; -} - .arch-bio-entry td.pic { - padding-left: 15px; - } - .arch-bio-entry td.pic { - vertical-align: top; - padding-right: 15px; - padding-top: 2.25em; - } - - .arch-bio-entry td.pic img { - padding: 4px; - border: 1px solid #ccc; - } - - .arch-bio-entry td h3 { - border-bottom: 1px dotted #ccc; - margin-bottom: 0.5em; - } - - .arch-bio-entry table.bio { - margin-bottom: 2em; - } - [dir="rtl"] .arch-bio-entry table.bio th { - text-align: left; - padding-left: 0.5em; - } - - .arch-bio-entry table.bio th { - color: #666; - font-weight: normal; - text-align: right; - padding-right: 0.5em; - vertical-align: top; - white-space: nowrap; - } - - .arch-bio-entry table.bio td { - width: 100%; - padding-bottom: 0.25em; - white-space: normal; - } - -/* dev: login/out */ -#dev-login { - width: auto; -} - -/* tables rows: highlight on mouse-vover */ -#article-list tr:hover, -#clocks-table tr:hover, -#dev-dashboard tr:hover, -#dev-todo-lists tr:hover, -#dev-todo-pkglist tr:hover, -#pkglist-results tr:hover, -#stats-area tr:hover { - background: #ffd; -} - -.results tr:nth-child(even), -#article-list tr:nth-child(even) { - background: #e4eeff; -} - -.results tr:nth-child(odd), -#article-list tr:nth-child(odd) { - background: #fff; -} - -/* dev dashboard: */ -table.dash-stats .key { - width: 50%; -} - -/* dev dashboard: admin actions (add news items, todo list, etc) */ -[dir="rtl"] ul.admin-actions { - float: left; -} -ul.admin-actions { - float: right; - list-style: none; - margin-top: -2.5em; -} - - ul.admin-actions li { - display: inline; - padding-left: 1.5em; - } - -/* colored yes/no type values */ -.todo-table .complete, -.signoff-yes, -#key-status .signed-yes, -#release-list .available-yes { - color: green; -} - -.todo-table .incomplete, -.signoff-no, -#key-status .signed-no, -#release-list .available-no { - color: red; -} - -.todo-table .inprogress, -.signoff-bad { - color: darkorange; -} - - -/* todo lists (public and private) */ -.todo-info { - color: #999; - border-bottom: 1px dotted #bbb; -} - -.todo-description { - margin-top: 1em; - padding-left: 2em; - max-width: 900px; -} - -.todo-pkgbases { - border-top: 1px dotted #bbb; -} - -.todo-list h4 { - margin-top: 0; - margin-bottom: 0.4em; -} - -/* dev: signoff page */ -#dev-signoffs tr:hover { - background: #ffd; -} - -ul.signoff-list { - list-style: none; - margin: 0; - padding: 0; -} - -.signoff-yes { - font-weight: bold; -} - -.signoff-disabled { - color: gray; -} - -/* highlight current website in the navbar */ -#archnavbar.anb-home ul li#anb-home a, -#archnavbar.anb-packages ul li#anb-packages a, -#archnavbar.anb-download ul li#anb-download a { - color: white !important; -} - -/* visualizations page */ -.visualize-buttons { - margin: 0.5em 0.33em; -} - -.visualize-chart { - position: relative; - height: 500px; - margin: 0.33em; -} - -#visualize-archrepo .treemap-cell { - border: solid 1px white; - overflow: hidden; - position: absolute; -} - - #visualize-archrepo .treemap-cell span { - padding: 3px; - font-size: 0.85em; - line-height: 1em; - } - -#visualize-keys svg { - width: 100%; - height: 100%; -} - -/* releases */ -#release-table th:first-of-type { - width: 30px; -} - -/* itemprops */ -.itemprop { - display: none; -} diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css deleted file mode 100644 index 64a65742..00000000 --- a/web/html/css/aurweb.css +++ /dev/null @@ -1,292 +0,0 @@ -/* aurweb-specific customizations to archweb.css */ - -#archnavbar.anb-aur ul li#anb-aur a { - color: white !important; -} - -#archnavbarlogo { - background: url('archnavbar/aurlogo.png') !important; -} - -[dir="rtl"] #lang_sub { - float: left; - } -#lang_sub { - float: right; -} - -.pkglist-nav .page { - margin: 0 .25em; -} - -#pkg-stats td.stat-desc { - white-space: normal; -} - -#actionlist form { - margin: 0; - padding: 0; -} - -.arch-bio-entry ul { - list-style: none; - padding: 0; -} - -#pkg-updates table { - table-layout: fixed; - width:100%; -} - -#pkg-updates td.pkg-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -[dir="rtl"] #pkg-updates td.pkg-date { - text-align:left; -} -#pkg-updates td.pkg-date { - text-align:right; -} - -[dir="rtl"] .keyword:link, .keyword:visited { - float: right; -} - -.keyword:link, .keyword:visited { - float: left; - margin: 1px .5ex 1px 0; - padding: 0 1em; - color: white; - background-color: #36a; - border: 1px solid transparent; - border-radius: 2px; -} - -.keyword:hover { - cursor: pointer; -} - -.keyword:focus { - border: 1px dotted #000; -} - -.text-button { - background: transparent; - border: none !important; - margin: 0 !important; - padding: 0 !important; - font: normal 100% sans-serif; - text-decoration: none; - color: #07b; - cursor: pointer; -} - -.text-button:hover { - text-decoration: underline; - color: #666; -} - -.text-button::-moz-focus-inner { - padding: 0; - border: none; -} - -.comment-deleted { - color: #999; -} - -.edited { - font-size: 0.9em; - color: #999; -} - -[dir="rtl"] .delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { - float: left; - margin-right: 8px; -} - -.delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { - float: right; - margin-left: 8px; -} - -.edit-comment { - height: 11px; - position: relative; - top: 1px; -} - -.comment-enable-notifications { - display: inline-block; - margin-left: 1em; -} - -.rss-icon, .delete-comment, .undelete-comment, .edit-comment, .pin-comment { - filter: grayscale(100%); - opacity: 0.6; -} - -.rss-icon:hover, .delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { - filter: none; - opacity: 1; -} - -[dir="rtl"] .ajax-loader { - float: left; -} - -.ajax-loader { - float: right; - position: relative; - top: 4px; -} - -.flagged a { - color: inherit; -} - -legend { - padding: 1em 0; -} - -p.important { - font-weight: bold; -} - -span.hover-help { - border-bottom: 1px dotted black; - cursor:help; -} - -label.confirmation { - width: auto; -} - -#pkgdepslist .broken { - color: red; - font-weight: bold; -} - -.package-comments { - margin-top: 1.5em; -} - -.comments-header { - display: flex; - justify-content: space-between; - align-items: flex-start; -} - -/* arrowed headings */ -.comments-header h3 span.text { - display: block; - background: #1794D1; - font-size: 15px; - padding: 2px 10px; - color: white; -} - -.comments-header .comments-header-nav { - align-self: flex-end; -} - -.comments-footer { - display: flex; - justify-content: flex-end; -} - -.comment-header { - clear: both; - font-size: 1em; - margin-top: 1.5em; - border-bottom: 1px dotted #bbb; -} - -.comments div { - margin-bottom: 1em; -} - -.comments div p { - margin-bottom: 0.5em; -} - -.comments .more { - font-weight: normal; -} - -.error { - color: red; -} - -.article-content > div { - overflow: hidden; - transition: height 1s; -} - -.proposal.details { - margin: .33em 0 1em; -} - -button[type="submit"], -button[type="reset"] { - padding: 0 0.6em; -} - -.results tr td[align="left"] fieldset { - text-align: left; -} - -.results tr td[align="right"] fieldset { - text-align: right; -} - -input#search-action-submit { - width: 80px; -} - -.success { - color: green; -} - -/* Styling used to clone styles for a form.link button. */ -form.link, form.link button { - display: inline; - font-family: sans-serif; -} -form.link button { - padding: 0 0.5em; - color: #07b; - background: none; - border: none; - font-family: inherit; - font-size: inherit; -} -form.link button:hover { - cursor: pointer; - text-decoration: underline; -} - -/* Customize form.link when used inside of a page. */ -div.box form.link p { - margin: .33em 0 1em; -} -div.box form.link button { - padding: 0; -} - -pre.traceback { - /* https://css-tricks.com/snippets/css/make-pre-text-wrap/ */ - white-space: pre-wrap; - word-wrap: break-all; -} - -/* By default, tables use 100% width, which we do not always want. */ -table.no-width { - width: auto; -} -table.no-width > tbody > tr > td { - padding-right: 2px; -} diff --git a/web/html/css/cgit.css b/web/html/css/cgit.css deleted file mode 100644 index 429b5f54..00000000 --- a/web/html/css/cgit.css +++ /dev/null @@ -1,866 +0,0 @@ -/* - * ARCH GLOBAL NAVBAR - * We're forcing all generic selectors with !important - * to help prevent other stylesheets from interfering. - */ - -/* container for the entire bar */ -#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } -#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url('archnavbar/archlogo.png') no-repeat !important; } - -/* move the heading text offscreen */ -#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } - -/* make the link the same size as the logo */ -#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } - -/* display the list inline, float it to the right and style it */ -#archnavbarlist { display: inline !important; float: right !important; list-style: none !important; margin: 0 !important; padding: 0 !important; } -#archnavbarlist li { float: left !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 45px !important; padding-right: 15px !important; padding-left: 15px !important; } - -/* style the links */ -#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } -#archnavbarlist li a:hover { color: white !important; text-decoration: underline !important; } - -/* END ARCH GLOBAL NAVBAR */ - -#footer { - clear: both; - margin: 0; -} - -#footer p { - margin: 1em; -} - -#archnavbar.anb-aur ul li#anb-aur a { - color: white !important; -} - -#archnavbarlogo { - background: url('archnavbar/aurlogo.png') !important; -} - -body { - padding: 0; - margin: 0; - font-family: sans-serif; - font-size: 10pt; - color: #333; - background: white; -} - -div#cgit a { - color: blue; - text-decoration: none; -} - -div#cgit a:hover { - text-decoration: underline; -} - -div#cgit table { - border-collapse: collapse; -} - -div#cgit table#header { - width: 100%; - margin-bottom: 1em; -} - -div#cgit table#header td.logo { - width: 96px; - vertical-align: top; -} - -div#cgit table#header td.main { - font-size: 250%; - padding-left: 10px; - white-space: nowrap; -} - -div#cgit table#header td.main a { - color: #000; -} - -div#cgit table#header td.form { - text-align: right; - vertical-align: bottom; - padding-right: 1em; - padding-bottom: 2px; - white-space: nowrap; -} - -div#cgit table#header td.form form, -div#cgit table#header td.form input, -div#cgit table#header td.form select { - font-size: 90%; -} - -div#cgit table#header td.sub { - color: #777; - border-top: solid 1px #ccc; - padding-left: 10px; -} - -div#cgit table.tabs { - border-bottom: solid 3px #ccc; - border-collapse: collapse; - margin-top: 2em; - margin-bottom: 0px; - width: 100%; -} - -div#cgit table.tabs td { - padding: 0px 1em; - vertical-align: bottom; -} - -div#cgit table.tabs td a { - padding: 2px 0.75em; - color: #777; - font-size: 110%; -} - -div#cgit table.tabs td a.active { - color: #000; - background-color: #ccc; -} - -div#cgit table.tabs td.form { - text-align: right; -} - -div#cgit table.tabs td.form form { - padding-bottom: 2px; - font-size: 90%; - white-space: nowrap; -} - -div#cgit table.tabs td.form input, -div#cgit table.tabs td.form select { - font-size: 90%; -} - -div#cgit div.path { - margin: 0px; - padding: 5px 2em 2px 2em; - color: #000; - background-color: #eee; -} - -div#cgit div.content { - margin: 0px; - padding: 2em; - border-bottom: solid 3px #ccc; -} - - -div#cgit table.list { - width: 100%; - border: none; - border-collapse: collapse; -} - -div#cgit table.list tr { - background: white; -} - -div#cgit table.list tr.logheader { - background: #eee; -} - -div#cgit table.list tr:hover { - background: #eee; -} - -div#cgit table.list tr.nohover:hover { - background: white; -} - -div#cgit table.list th { - font-weight: bold; - /* color: #888; - border-top: dashed 1px #888; - border-bottom: dashed 1px #888; - */ - padding: 0.1em 0.5em 0.05em 0.5em; - vertical-align: baseline; -} - -div#cgit table.list td { - border: none; - padding: 0.1em 0.5em 0.1em 0.5em; -} - -div#cgit table.list td.commitgraph { - font-family: monospace; - white-space: pre; -} - -div#cgit table.list td.commitgraph .column1 { - color: #a00; -} - -div#cgit table.list td.commitgraph .column2 { - color: #0a0; -} - -div#cgit table.list td.commitgraph .column3 { - color: #aa0; -} - -div#cgit table.list td.commitgraph .column4 { - color: #00a; -} - -div#cgit table.list td.commitgraph .column5 { - color: #a0a; -} - -div#cgit table.list td.commitgraph .column6 { - color: #0aa; -} - -div#cgit table.list td.logsubject { - font-family: monospace; - font-weight: bold; -} - -div#cgit table.list td.logmsg { - font-family: monospace; - white-space: pre; - padding: 0 0.5em; -} - -div#cgit table.list td a { - color: black; -} - -div#cgit table.list td a.ls-dir { - font-weight: bold; - color: #00f; -} - -div#cgit table.list td a:hover { - color: #00f; -} - -div#cgit img { - border: none; -} - -div#cgit input#switch-btn { - margin: 2px 0px 0px 0px; -} - -div#cgit td#sidebar input.txt { - width: 100%; - margin: 2px 0px 0px 0px; -} - -div#cgit table#grid { - margin: 0px; -} - -div#cgit td#content { - vertical-align: top; - padding: 1em 2em 1em 1em; - border: none; -} - -div#cgit div#summary { - vertical-align: top; - margin-bottom: 1em; -} - -div#cgit table#downloads { - float: right; - border-collapse: collapse; - border: solid 1px #777; - margin-left: 0.5em; - margin-bottom: 0.5em; -} - -div#cgit table#downloads th { - background-color: #ccc; -} - -div#cgit div#blob { - border: solid 1px black; -} - -div#cgit div.error { - color: red; - font-weight: bold; - margin: 1em 2em; -} - -div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit a.ls-mod { - font-family: monospace; -} - -div#cgit td.ls-size { - text-align: right; - font-family: monospace; - width: 10em; -} - -div#cgit td.ls-mode { - font-family: monospace; - width: 10em; -} - -div#cgit table.blob { - margin-top: 0.5em; - border-top: solid 1px black; -} - -div#cgit table.blob td.lines { - margin: 0; padding: 0 0 0 0.5em; - vertical-align: top; - color: black; -} - -div#cgit table.blob td.linenumbers { - margin: 0; padding: 0 0.5em 0 0.5em; - vertical-align: top; - text-align: right; - border-right: 1px solid gray; -} - -div#cgit table.blob pre { - padding: 0; margin: 0; -} - -div#cgit table.blob a.no, div#cgit table.ssdiff a.no { - color: gray; - text-align: right; - text-decoration: none; -} - -div#cgit table.blob a.no a:hover { - color: black; -} - -div#cgit table.bin-blob { - margin-top: 0.5em; - border: solid 1px black; -} - -div#cgit table.bin-blob th { - font-family: monospace; - white-space: pre; - border: solid 1px #777; - padding: 0.5em 1em; -} - -div#cgit table.bin-blob td { - font-family: monospace; - white-space: pre; - border-left: solid 1px #777; - padding: 0em 1em; -} - -div#cgit table.nowrap td { - white-space: nowrap; -} - -div#cgit table.commit-info { - border-collapse: collapse; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel { - float: right; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel table { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit div.cgit-panel th { - text-align: center; -} - -div#cgit div.cgit-panel td { - padding: 0.25em 0.5em; -} - -div#cgit div.cgit-panel td.label { - padding-right: 0.5em; -} - -div#cgit div.cgit-panel td.ctrl { - padding-left: 0.5em; -} - -div#cgit table.commit-info th { - text-align: left; - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; - vertical-align: top; -} - -div#cgit table.commit-info td { - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; -} - -div#cgit div.commit-subject { - font-weight: bold; - font-size: 125%; - margin: 1.5em 0em 0.5em 0em; - padding: 0em; -} - -div#cgit div.commit-msg { - white-space: pre; - font-family: monospace; -} - -div#cgit div.notes-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit div.notes { - white-space: pre; - font-family: monospace; - border: solid 1px #ee9; - background-color: #ffd; - padding: 0.3em 2em 0.3em 1em; - float: left; -} - -div#cgit div.notes-footer { - clear: left; -} - -div#cgit div.diffstat-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit table.diffstat { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit table.diffstat th { - font-weight: normal; - text-align: left; - text-decoration: underline; - padding: 0.1em 1em 0.1em 0.1em; - font-size: 100%; -} - -div#cgit table.diffstat td { - padding: 0.2em 0.2em 0.1em 0.1em; - font-size: 100%; - border: none; -} - -div#cgit table.diffstat td.mode { - white-space: nowrap; -} - -div#cgit table.diffstat td span.modechange { - padding-left: 1em; - color: red; -} - -div#cgit table.diffstat td.add a { - color: green; -} - -div#cgit table.diffstat td.del a { - color: red; -} - -div#cgit table.diffstat td.upd a { - color: blue; -} - -div#cgit table.diffstat td.graph { - width: 500px; - vertical-align: middle; -} - -div#cgit table.diffstat td.graph table { - border: none; -} - -div#cgit table.diffstat td.graph td { - padding: 0px; - border: 0px; - height: 7pt; -} - -div#cgit table.diffstat td.graph td.add { - background-color: #5c5; -} - -div#cgit table.diffstat td.graph td.rem { - background-color: #c55; -} - -div#cgit div.diffstat-summary { - color: #888; - padding-top: 0.5em; -} - -div#cgit table.diff { - width: 100%; -} - -div#cgit table.diff td { - font-family: monospace; - white-space: pre; -} - -div#cgit table.diff td div.head { - font-weight: bold; - margin-top: 1em; - color: black; -} - -div#cgit table.diff td div.hunk { - color: #009; -} - -div#cgit table.diff td div.add { - color: green; -} - -div#cgit table.diff td div.del { - color: red; -} - -div#cgit .sha1 { - font-family: monospace; - font-size: 90%; -} - -div#cgit .left { - text-align: left; -} - -div#cgit .right { - text-align: right; - float: none !important; - width: auto !important; - padding: 0 !important; -} - -div#cgit table.list td.reposection { - font-style: italic; - color: #888; -} - -div#cgit a.button { - font-size: 80%; - padding: 0em 0.5em; -} - -div#cgit a.primary { - font-size: 100%; -} - -div#cgit a.secondary { - font-size: 90%; -} - -div#cgit td.toplevel-repo { - -} - -div#cgit table.list td.sublevel-repo { - padding-left: 1.5em; -} - -div#cgit ul.pager { - list-style-type: none; - text-align: center; - margin: 1em 0em 0em 0em; - padding: 0; -} - -div#cgit ul.pager li { - display: inline-block; - margin: 0.25em 0.5em; -} - -div#cgit ul.pager a { - color: #777; -} - -div#cgit ul.pager .current { - font-weight: bold; -} - -div#cgit span.age-mins { - font-weight: bold; - color: #080; -} - -div#cgit span.age-hours { - color: #080; -} - -div#cgit span.age-days { - color: #040; -} - -div#cgit span.age-weeks { - color: #444; -} - -div#cgit span.age-months { - color: #888; -} - -div#cgit span.age-years { - color: #bbb; -} -div#cgit div.footer { - margin-top: 0.5em; - text-align: center; - font-size: 80%; - color: #ccc; -} -div#cgit a.branch-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #88ff88; - border: solid 1px #007700; -} -div#cgit a.tag-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ffff88; - border: solid 1px #777700; -} -div#cgit a.remote-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ccccff; - border: solid 1px #000077; -} -div#cgit a.deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ff8888; - border: solid 1px #770000; -} - -div#cgit div.commit-subject a.branch-deco, -div#cgit div.commit-subject a.tag-deco, -div#cgit div.commit-subject a.remote-deco, -div#cgit div.commit-subject a.deco { - margin-left: 1em; - font-size: 75%; -} - -div#cgit table.stats { - border: solid 1px black; - border-collapse: collapse; -} - -div#cgit table.stats th { - text-align: left; - padding: 1px 0.5em; - background-color: #eee; - border: solid 1px black; -} - -div#cgit table.stats td { - text-align: right; - padding: 1px 0.5em; - border: solid 1px black; -} - -div#cgit table.stats td.total { - font-weight: bold; - text-align: left; -} - -div#cgit table.stats td.sum { - color: #c00; - font-weight: bold; -/* background-color: #eee; */ -} - -div#cgit table.stats td.left { - text-align: left; -} - -div#cgit table.vgraph { - border-collapse: separate; - border: solid 1px black; - height: 200px; -} - -div#cgit table.vgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px white; - padding: 1px 0.5em; -} - -div#cgit table.vgraph td { - vertical-align: bottom; - padding: 0px 10px; -} - -div#cgit table.vgraph div.bar { - background-color: #eee; -} - -div#cgit table.hgraph { - border: solid 1px black; - width: 800px; -} - -div#cgit table.hgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px black; - padding: 1px 0.5em; -} - -div#cgit table.hgraph td { - vertical-align: middle; - padding: 2px 2px; -} - -div#cgit table.hgraph div.bar { - background-color: #eee; - height: 1em; -} - -div#cgit table.ssdiff { - width: 100%; -} - -div#cgit table.ssdiff td { - font-size: 75%; - font-family: monospace; - white-space: pre; - padding: 1px 4px 1px 4px; - border-left: solid 1px #aaa; - border-right: solid 1px #aaa; -} - -div#cgit table.ssdiff td.add { - color: black; - background: #cfc; - min-width: 50%; -} - -div#cgit table.ssdiff td.add_dark { - color: black; - background: #aca; - min-width: 50%; -} - -div#cgit table.ssdiff span.add { - background: #cfc; - font-weight: bold; -} - -div#cgit table.ssdiff td.del { - color: black; - background: #fcc; - min-width: 50%; -} - -div#cgit table.ssdiff td.del_dark { - color: black; - background: #caa; - min-width: 50%; -} - -div#cgit table.ssdiff span.del { - background: #fcc; - font-weight: bold; -} - -div#cgit table.ssdiff td.changed { - color: black; - background: #ffc; - min-width: 50%; -} - -div#cgit table.ssdiff td.changed_dark { - color: black; - background: #cca; - min-width: 50%; -} - -div#cgit table.ssdiff td.lineno { - color: black; - background: #eee; - text-align: right; - width: 3em; - min-width: 3em; -} - -div#cgit table.ssdiff td.hunk { - color: black; - background: #ccf; - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head { - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head div.head { - font-weight: bold; - color: black; -} - -div#cgit table.ssdiff td.foot { - border-top: solid 1px #aaa; - border-left: none; - border-right: none; - border-bottom: none; -} - -div#cgit table.ssdiff td.space { - border: none; -} - -div#cgit table.ssdiff td.space div { - min-height: 3em; -} - -/* - * Style definitions generated by highlight 3.14, http://www.andre-simon.de/ - * Highlighting theme: Kwrite Editor - */ -div#cgit table.blob .num { color:#b07e00; } -div#cgit table.blob .esc { color:#ff00ff; } -div#cgit table.blob .str { color:#bf0303; } -div#cgit table.blob .pps { color:#818100; } -div#cgit table.blob .slc { color:#838183; font-style:italic; } -div#cgit table.blob .com { color:#838183; font-style:italic; } -div#cgit table.blob .ppc { color:#008200; } -div#cgit table.blob .opt { color:#000000; } -div#cgit table.blob .ipl { color:#0057ae; } -div#cgit table.blob .lin { color:#555555; } -div#cgit table.blob .kwa { color:#000000; font-weight:bold; } -div#cgit table.blob .kwb { color:#0057ae; } -div#cgit table.blob .kwc { color:#000000; font-weight:bold; } -div#cgit table.blob .kwd { color:#010181; } diff --git a/web/html/home.php b/web/html/home.php deleted file mode 100644 index 5ea79ee9..00000000 --- a/web/html/home.php +++ /dev/null @@ -1,215 +0,0 @@ - - -
    -
    - -
    -

    -

    - 50, - 'SeB' => 'M', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'outdated' => 'on', - 'SB' => 'l', - 'SO' => 'a' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -

    - -
    -
    -

    -

    ">

    - 50, - 'SeB' => 'm', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'SB' => 'l', - 'SO' => 'd' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -
    -
    -

    -

    ">

    - 50, - 'SeB' => 'c', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'SB' => 'l', - 'SO' => 'd' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -
    - -
    -

    AUR

    -

    - ', - '', - '', - '' - ); - ?> - ', '', - '', - '' - ); - ?> - - -

    -

    - : - -

    -

    -
    -
    -

    -

    -
    -

    - ', - '' - ); - ?> -

    -
      -
    • :
    • -
    • :
    • -
    • :
    • -
    -

    - ', - '' - ); - ?> -

    -
    -

    -
    -

    - ', - '' - ); - ?> -

    - -

    - -

    -
      - $fingerprint): ?> -
    • :
    • - -
    - -
    -

    -
    -

    - ', - '', - '', - '' - ); - ?> -

    -
    -

    -
    -

    - ', - '', - '', - '' - ); - ?> -

    -
    -
    - -
    -
    -
    -
    -
    -
    - - - " maxlength="35" autocomplete="off"/> -
    -
    -
    -
    - -
    -
    - -
    - -
    - -
    - - -
    - - - - - diff --git a/web/html/images/action-undo.svg b/web/html/images/action-undo.svg deleted file mode 100644 index b93ebb78..00000000 --- a/web/html/images/action-undo.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/web/html/images/ajax-loader.gif b/web/html/images/ajax-loader.gif deleted file mode 100644 index df07e7ec2076177c99b53d4d29a45f0db6b06a9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 723 zcmZ?wbhEHb6kyWo5uik&V|NP^(AHU+;_dI&}>C3lYM=m|vboAbp zdv88|`N04KivPL&TtkAL9RpmA^bD98f#Qn)q@0UV6H8K46v{J8G87WC5-W1@6I1ju z^V0Ge6o0aCasyTAfJ^{6l7UrML7^`tbKa5#T#rsMt#c4)wm4&2aJl;4?H%*^*q;ct zZ+YZ!f=91--8C-PwbPuinV^!8D8ZUAZ$+j|`^0?*ZXH_r=F;-s=Wq7D-W{Q@F^9F$ zTCh`s37bYUpw-=pI*&V4IF+P$l9wbc(l{x7eoOCbBdG(^nGZDWjsAGTTd?u$#mhT{ z{bn8t<<=6J=66T{n^C4fqn2>E3WhNCJ~l~G@x1uTreFAcY2|b4S-i`cPqf%2ZE*i3 z+J9zZu_cRCJ%=P)K~y-6jgvo!6G0Tle=|GDx_9PaSMatt8xuJ=jueWZ*0zF( zjc8@z38oPY2!}RWYjKN}g`kaCi1-H-uCNkOgxf0BeA-5$w9LxMMtXHz@2@3 zyz+UJPuh|vi*mtJavK=cNwf1dpEbZ!a<``>o|1IZ?Bv;J>;8WS9J=%2sOyMVt`f_h zlJvCko4lXZH(|7*(w!f`Tnu;_ptK?Jqw7?)K+hZAu%R^ukDjFp75q4Pbjddz93wNAlTi;8fmk1LdSvP5vdgJg^M# zaG-vgp9c5>)Q7GRMsXQ9!>~RL)NlL5fD7Ck3IMJGg}hz^t^pqh0-C^eU>&Fc%V89s z01(qlD|><0z!Ts~QmejXjKU~B2rL4Jfq5~#v~m%6p46(=A2%lGz#nlao8kSq3cLUS N002ovPDHLkV1na%{Dc4i diff --git a/web/html/images/pencil.min.svg b/web/html/images/pencil.min.svg deleted file mode 100644 index 06125ae0..00000000 --- a/web/html/images/pencil.min.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/pencil.svg b/web/html/images/pencil.svg deleted file mode 100644 index 91f08991..00000000 --- a/web/html/images/pencil.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/web/html/images/pin.min.svg b/web/html/images/pin.min.svg deleted file mode 100644 index ac08903d..00000000 --- a/web/html/images/pin.min.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/html/images/pin.svg b/web/html/images/pin.svg deleted file mode 100644 index b4ee9eb7..00000000 --- a/web/html/images/pin.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/rss.svg b/web/html/images/rss.svg deleted file mode 100644 index 3c7f6ba1..00000000 --- a/web/html/images/rss.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/unpin.min.svg b/web/html/images/unpin.min.svg deleted file mode 100644 index 3cf2413c..00000000 --- a/web/html/images/unpin.min.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/html/images/unpin.svg b/web/html/images/unpin.svg deleted file mode 100644 index de897152..00000000 --- a/web/html/images/unpin.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/web/html/images/x.min.svg b/web/html/images/x.min.svg deleted file mode 100644 index 833d4f22..00000000 --- a/web/html/images/x.min.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/x.svg b/web/html/images/x.svg deleted file mode 100644 index e323fe19..00000000 --- a/web/html/images/x.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/web/html/index.php b/web/html/index.php deleted file mode 100644 index dc435162..00000000 --- a/web/html/index.php +++ /dev/null @@ -1,205 +0,0 @@ - '1'); - } - } - - include get_route('/' . $tokens[1]); -} elseif (!empty($tokens[1]) && '/' . $tokens[1] == get_pkgreq_route()) { - if (!empty($tokens[2])) { - /* TODO: Create a proper data structure to pass variables from - * the routing framework to the individual pages instead of - * initializing arbitrary variables here. */ - if (!empty($tokens[3]) && $tokens[3] == 'close') { - $pkgreq_id = $tokens[2]; - } else { - $pkgreq_id = null; - } - - if (!$pkgreq_id) { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - } - - include get_route('/' . $tokens[1]); -} elseif (!empty($tokens[1]) && '/' . $tokens[1] == get_user_route()) { - if (!empty($tokens[2])) { - $_REQUEST['ID'] = uid_from_username($tokens[2]); - - if (!$_REQUEST['ID']) { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - - if (!empty($tokens[3])) { - if ($tokens[3] == 'edit') { - $_REQUEST['Action'] = "DisplayAccount"; - } elseif ($tokens[3] == 'update') { - $_REQUEST['Action'] = "UpdateAccount"; - } elseif ($tokens[3] == 'delete') { - $_REQUEST['Action'] = "DeleteAccount"; - } elseif ($tokens[3] == 'comments') { - $_REQUEST['Action'] = "ListComments"; - } else { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - } else { - $_REQUEST['Action'] = "AccountInfo"; - } - } - include get_route('/' . $tokens[1]); -} elseif (get_route($path) !== NULL) { - include get_route($path); -} else { - switch ($path) { - case "/css/archweb.css": - case "/css/aurweb.css": - case "/css/cgit.css": - case "/css/archnavbar/archnavbar.css": - header("Content-Type: text/css"); - readfile("./$path"); - break; - case "/images/ajax-loader.gif": - header("Content-Type: image/gif"); - readfile("./$path"); - break; - case "/css/archnavbar/archlogo.png": - case "/css/archnavbar/aurlogo.png": - case "/images/favicon.ico": - header("Content-Type: image/png"); - readfile("./$path"); - break; - case "/images/x.min.svg": - case "/images/action-undo.min.svg": - case "/images/pencil.min.svg": - case "/images/pin.min.svg": - case "/images/unpin.min.svg": - case "/images/rss.svg": - header("Content-Type: image/svg+xml"); - readfile("./$path"); - break; - case "/js/typeahead.js": - header("Content-Type: application/javascript"); - readfile("./$path"); - break; - case "/packages.gz": - case "/packages-meta-v1.json.gz": - case "/packages-meta-ext-v1.json.gz": - case "/pkgbase.gz": - case "/users.gz": - header("Content-Type: text/plain"); - header("Content-Encoding: gzip"); - readfile("./$path"); - break; - default: - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - break; - } -} diff --git a/web/html/js/comment-edit.js b/web/html/js/comment-edit.js deleted file mode 100644 index 23ffdd34..00000000 --- a/web/html/js/comment-edit.js +++ /dev/null @@ -1,61 +0,0 @@ -function add_busy_indicator(sibling) { - const img = document.createElement('img'); - img.src = "/static/images/ajax-loader.gif"; - img.classList.add('ajax-loader'); - img.style.height = 11; - img.style.width = 16; - img.alt = "Busy…"; - - sibling.insertAdjacentElement('afterend', img); -} - -function remove_busy_indicator(sibling) { - const elem = sibling.nextElementSibling; - elem.parentNode.removeChild(elem); -} - -function getParentsUntil(elem, className) { - // Limit to 10 depth - for ( ; elem && elem !== document; elem = elem.parentNode) { - if (elem.matches(className)) { - break; - } - } - - return elem; -} - -function handleEditCommentClick(event, pkgbasename) { - event.preventDefault(); - const parent_element = getParentsUntil(event.target, '.comment-header'); - const parent_id = parent_element.id; - const comment_id = parent_id.substr(parent_id.indexOf('-') + 1); - // The div class="article-content" which contains the comment - const edit_form = parent_element.nextElementSibling; - - const url = "/pkgbase/" + pkgbasename + "/comments/" + comment_id + "/form?"; - - add_busy_indicator(event.target); - - fetch(url + new URLSearchParams({ next: window.location.pathname }), { - method: 'GET', - credentials: 'same-origin' - }) - .then(function(response) { - if (!response.ok) { - throw Error(response.statusText); - } - return response.json(); - }) - .then(function(data) { - remove_busy_indicator(event.target); - edit_form.innerHTML = data.form; - edit_form.querySelector('textarea').focus(); - }) - .catch(function(error) { - remove_busy_indicator(event.target); - console.error(error); - }); - - return false; -} diff --git a/web/html/js/copy.js b/web/html/js/copy.js deleted file mode 100644 index 3b659270..00000000 --- a/web/html/js/copy.js +++ /dev/null @@ -1,9 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - let elements = document.querySelectorAll('.copy'); - elements.forEach(function(el) { - el.addEventListener('click', function(e) { - e.preventDefault(); - navigator.clipboard.writeText(e.target.text); - }); - }); -}); diff --git a/web/html/js/typeahead-home.js b/web/html/js/typeahead-home.js deleted file mode 100644 index 5af51c53..00000000 --- a/web/html/js/typeahead-home.js +++ /dev/null @@ -1,6 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - const input = document.getElementById('pkgsearch-field'); - const form = document.getElementById('pkgsearch-form'); - const type = 'suggest'; - typeahead.init(type, input, form); -}); diff --git a/web/html/js/typeahead-pkgbase-merge.js b/web/html/js/typeahead-pkgbase-merge.js deleted file mode 100644 index a8c87e4f..00000000 --- a/web/html/js/typeahead-pkgbase-merge.js +++ /dev/null @@ -1,6 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - const input = document.getElementById('merge_into'); - const form = document.getElementById('merge-form'); - const type = "suggest-pkgbase"; - typeahead.init(type, input, form, false); -}); diff --git a/web/html/js/typeahead-pkgbase-request.js b/web/html/js/typeahead-pkgbase-request.js deleted file mode 100644 index e012d55f..00000000 --- a/web/html/js/typeahead-pkgbase-request.js +++ /dev/null @@ -1,36 +0,0 @@ -function showHideMergeSection() { - const elem = document.getElementById('id_type'); - const merge_section = document.getElementById('merge_section'); - if (elem.value == 'merge') { - merge_section.style.display = ''; - } else { - merge_section.style.display = 'none'; - } -} - -function showHideRequestHints() { - document.getElementById('deletion_hint').style.display = 'none'; - document.getElementById('merge_hint').style.display = 'none'; - document.getElementById('orphan_hint').style.display = 'none'; - - const elem = document.getElementById('id_type'); - document.getElementById(elem.value + '_hint').style.display = ''; -} - -document.addEventListener('DOMContentLoaded', function() { - showHideMergeSection(); - showHideRequestHints(); - - const input = document.getElementById('id_merge_into'); - const form = document.getElementById('request-form'); - const type = "suggest-pkgbase"; - - typeahead.init(type, input, form, false); -}); - -// Bind the change event here, otherwise we have to inline javascript, -// which angers CSP (Content Security Policy). -document.getElementById("id_type").addEventListener("change", function() { - showHideMergeSection(); - showHideRequestHints(); -}); diff --git a/web/html/js/typeahead.js b/web/html/js/typeahead.js deleted file mode 100644 index bfd3d156..00000000 --- a/web/html/js/typeahead.js +++ /dev/null @@ -1,151 +0,0 @@ -"use strict"; - -const typeahead = (function() { - var input; - var form; - var suggest_type; - var list; - var submit = true; - - function resetResults() { - if (!list) return; - list.style.display = "none"; - list.innerHTML = ""; - } - - function getCompleteList() { - if (!list) { - list = document.createElement("UL"); - list.setAttribute("class", "pkgsearch-typeahead"); - form.appendChild(list); - setListLocation(); - } - return list; - } - - function onListClick(e) { - let target = e.target; - while (!target.getAttribute('data-value')) { - target = target.parentNode; - } - input.value = target.getAttribute('data-value'); - if (submit) { - form.submit(); - } - } - - function setListLocation() { - if (!list) return; - const rects = input.getClientRects()[0]; - list.style.top = (rects.top + rects.height) + "px"; - list.style.left = rects.left + "px"; - } - - function loadData(letter, data) { - const pkgs = data.slice(0, 10); // Show maximum of 10 results - - resetResults(); - - if (pkgs.length === 0) { - return; - } - - const ul = getCompleteList(); - ul.style.display = "block"; - const fragment = document.createDocumentFragment(); - - for (let i = 0; i < pkgs.length; i++) { - const item = document.createElement("li"); - const text = pkgs[i].replace(letter, '' + letter + ''); - item.innerHTML = '' + text + ''; - item.setAttribute('data-value', pkgs[i]); - fragment.appendChild(item); - } - - ul.appendChild(fragment); - ul.addEventListener('click', onListClick); - } - - function fetchData(letter) { - const url = '/rpc?v=5&type=' + suggest_type + '&arg=' + letter; - fetch(url).then(function(response) { - return response.json(); - }).then(function(data) { - loadData(letter, data); - }); - } - - function onInputClick() { - if (input.value === "") { - resetResults(); - return; - } - fetchData(input.value); - } - - function onKeyDown(e) { - if (!list) return; - - const elem = document.querySelector(".pkgsearch-typeahead li.active"); - switch(e.keyCode) { - case 13: // enter - if (!submit) { - return; - } - if (elem) { - input.value = elem.getAttribute('data-value'); - form.submit(); - } else { - form.submit(); - } - e.preventDefault(); - break; - case 38: // up - if (elem && elem.previousElementSibling) { - elem.className = ""; - elem.previousElementSibling.className = "active"; - } - e.preventDefault(); - break; - case 40: // down - if (elem && elem.nextElementSibling) { - elem.className = ""; - elem.nextElementSibling.className = "active"; - } else if (!elem && list.childElementCount !== 0) { - list.children[0].className = "active"; - } - e.preventDefault(); - break; - } - } - - // debounce https://davidwalsh.name/javascript-debounce-function - function debounce(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; - } - - return { - init: function(type, inputfield, formfield, submitdata = true) { - suggest_type = type; - input = inputfield; - form = formfield; - submit = submitdata; - - input.addEventListener("input", onInputClick); - input.addEventListener("keydown", onKeyDown); - window.addEventListener('resize', debounce(setListLocation, 150)); - document.addEventListener("click", resetResults); - } - } -}()); diff --git a/web/html/login.php b/web/html/login.php deleted file mode 100644 index 3f3d66cc..00000000 --- a/web/html/login.php +++ /dev/null @@ -1,68 +0,0 @@ - -
    -

    AUR

    - -

    - ' . username_from_sid($_COOKIE["AURSID"]) . ''); ?> - [] -

    - -
    -
    - - -
    - -

    - - -

    -

    - - -

    -

    - - -

    -

    - " /> - [] - - [] - - - - -

    -
    -
    - -

    - ', ''); ?> -

    - -
    -query("SELECT SSOAccountID FROM Users WHERE ID = " . $dbh->quote($uid)) - ->fetchColumn(); - if ($sso_account_id) - $redirect_uri = '/sso/logout'; - } -} - -header("Location: $redirect_uri"); diff --git a/web/html/modified-rss.php b/web/html/modified-rss.php deleted file mode 100644 index 4c5c47e0..00000000 --- a/web/html/modified-rss.php +++ /dev/null @@ -1,62 +0,0 @@ -cssStyleSheet = false; -$rss->xslStyleSheet = false; - -# Use UTF-8 (fixes FS#10706). -$rss->encoding = "UTF-8"; - -#All the general RSS setup -$rss->title = "AUR Latest Modified Packages"; -$rss->description = "The latest modified packages in the AUR"; -$rss->link = "${protocol}://{$host}"; -$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); -$image = new FeedImage(); -$image->title = "AUR Latest Modified Packages"; -$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; -$image->link = $rss->link; -$image->description = "AUR Latest Modified Packages Feed"; -$rss->image = $image; - -#Get the latest packages and add items for them -$packages = latest_modified_pkgs(100); - -foreach ($packages as $indx => $row) { - $item = new FeedItem(); - $item->title = $row["Name"]; - $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); - $item->description = $row["Description"]; - $item->date = intval($row["ModifiedTS"]); - $item->source = "{$protocol}://{$host}"; - $item->author = username_from_id($row["MaintainerUID"]); - $item->guidIsPermaLink = true; - $item->guid = $row["Name"] . "-" . $row["ModifiedTS"]; - $rss->addItem($item); -} - -#save it so that useCached() can find it -$feedContent = $rss->createFeed(); -set_cache_value($feed_key, $feedContent, 600); -echo $feedContent; -?> diff --git a/web/html/packages.php b/web/html/packages.php deleted file mode 100644 index 24d1f82e..00000000 --- a/web/html/packages.php +++ /dev/null @@ -1,173 +0,0 @@ - - - - -\n"; - } -} else { - if (!isset($_GET['K']) && !isset($_GET['SB'])) { - $_GET['SB'] = 'p'; - $_GET['SO'] = 'd'; - } - echo '
    '; - if (isset($_COOKIE["AURSID"])) { - pkg_search_page($_GET, true, $_COOKIE["AURSID"]); - } else { - pkg_search_page($_GET, true); - } - echo '
    '; -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/passreset.php b/web/html/passreset.php deleted file mode 100644 index 26b9bbbb..00000000 --- a/web/html/passreset.php +++ /dev/null @@ -1,100 +0,0 @@ - - -
    -

    - - -

    - -

    - - -
    - -
    - - - - - - - - - - - - - -
    -
    - -
    - -

    ', - ''); ?>

    - -
    - -
    -

    -

    - -
    - -
    - - $i) { - $id = intval($id); - if ($id > 0) { - $ids[] = $id; - } - } -} - -/* Perform package base actions. */ -$via = isset($_POST['via']) ? $_POST['via'] : NULL; -$return_to = isset($_POST['return_to']) ? $_POST['return_to'] : NULL; -$ret = false; -$output = ""; -$fragment = ""; -if (check_token()) { - if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); - } elseif (current_action("do_UnFlag")) { - list($ret, $output) = pkgbase_unflag($ids); - } elseif (current_action("do_Adopt")) { - list($ret, $output) = pkgbase_adopt($ids, true, NULL); - } elseif (current_action("do_Disown")) { - if (isset($_POST['confirm'])) { - list($ret, $output) = pkgbase_adopt($ids, false, $via); - } else { - $output = __("The selected packages have not been disowned, check the confirmation checkbox."); - $ret = false; - } - } elseif (current_action("do_DisownComaintainer")) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - list($ret, $output) = pkgbase_remove_comaintainer($base_id, $uid); - } elseif (current_action("do_Vote")) { - list($ret, $output) = pkgbase_vote($ids, true); - } elseif (current_action("do_UnVote")) { - list($ret, $output) = pkgbase_vote($ids, false); - } elseif (current_action("do_Delete")) { - if (isset($_POST['confirm'])) { - if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) { - list($ret, $output) = pkgbase_delete($ids, NULL, $via); - unset($_GET['ID']); - unset($base_id); - } - else { - $merge_base_id = pkgbase_from_name($_POST['merge_Into']); - if (!$merge_base_id) { - $output = __("Cannot find package to merge votes and comments into."); - $ret = false; - } elseif (in_array($merge_base_id, $ids)) { - $output = __("Cannot merge a package base with itself."); - $ret = false; - } else { - list($ret, $output) = pkgbase_delete($ids, $merge_base_id, $via); - unset($_GET['ID']); - unset($base_id); - } - } - } - else { - $output = __("The selected packages have not been deleted, check the confirmation checkbox."); - $ret = false; - } - } elseif (current_action("do_Notify")) { - list($ret, $output) = pkgbase_notify($ids); - } elseif (current_action("do_UnNotify")) { - list($ret, $output) = pkgbase_notify($ids, false); - } elseif (current_action("do_DeleteComment")) { - list($ret, $output) = pkgbase_delete_comment(); - } elseif (current_action("do_UndeleteComment")) { - list($ret, $output) = pkgbase_delete_comment(true); - if ($ret && isset($_POST["comment_id"])) { - $fragment = '#comment-' . intval($_POST["comment_id"]); - } - } elseif (current_action("do_PinComment")) { - list($ret, $output) = pkgbase_pin_comment(); - } elseif (current_action("do_UnpinComment")) { - list($ret, $output) = pkgbase_pin_comment(true); - } elseif (current_action("do_SetKeywords")) { - list($ret, $output) = pkgbase_set_keywords($base_id, preg_split("/[\s,;]+/", $_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY)); - } elseif (current_action("do_FileRequest")) { - list($ret, $output) = pkgreq_file($ids, $_POST['type'], $_POST['merge_into'], $_POST['comments']); - } elseif (current_action("do_CloseRequest")) { - list($ret, $output) = pkgreq_close($_POST['reqid'], $_POST['reason'], $_POST['comments']); - } elseif (current_action("do_EditComaintainers")) { - list($ret, $output) = pkgbase_set_comaintainers($base_id, explode("\n", $_POST['users'])); - } elseif (current_action("do_AddComment")) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - list($ret, $output) = pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); - if ($ret && isset($_REQUEST['enable_notifications'])) { - list($ret, $output) = pkgbase_notify(array($base_id)); - } - $fragment = '#news'; - } elseif (current_action("do_EditComment")) { - list($ret, $output) = pkgbase_edit_comment($_REQUEST['comment']); - if ($ret && isset($_POST["comment_id"])) { - $fragment = '#comment-' . intval($_POST["comment_id"]); - } - } - - if ($ret) { - if (current_action("do_CloseRequest") || - (current_action("do_Delete") && $via)) { - /* Redirect back to package request page on success. */ - header('Location: ' . get_pkgreq_route()); - exit(); - } elseif ((current_action("do_DeleteComment") || - current_action("do_UndeleteComment")) && $return_to) { - header('Location: ' . $return_to); - exit(); - } elseif (current_action("do_PinComment") && $return_to) { - header('Location: ' . $return_to); - exit(); - } elseif (isset($base_id)) { - /* Redirect back to package base page on success. */ - header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); - exit(); - } else { - /* Redirect back to package search page. */ - header('Location: ' . get_pkg_route()); - exit(); - } - } -} - -if (isset($base_id)) { - $pkgs = pkgbase_get_pkgnames($base_id); - if (!$output && count($pkgs) == 1) { - /* Not a split package. Redirect to the package page. */ - if (empty($_SERVER['QUERY_STRING'])) { - header('Location: ' . get_pkg_uri($pkgs[0]) . $fragment); - } else { - header('Location: ' . get_pkg_uri($pkgs[0]) . '?' . $_SERVER['QUERY_STRING'] . $fragment); - } - } - - $details = pkgbase_get_details($base_id); -} else { - $details = array(); -} -html_header($title, $details); -?> - - - -

    - -
    - - - - -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
      - -
    • - -
    -

    - - -

    -
    -
    - - - - - - -

    -

    " />

    -
    -
    -
    - - -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
      - -
    • - -
    -

    - - - - 0 && !has_credential(CRED_PKGBASE_DISOWN)): ?> - ', $comaintainers[0], ''); ?> - - - -

    -
    -
    - - - - - - -

    " />

    -
    -
    -
    - - $i) { - $id = intval($id); - if ($id > 0) { - $ids[] = $id; - } - } -} - -/* Perform package base actions. */ -$ret = false; -$output = ""; -if (check_token()) { - if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); - } - - if ($ret) { - header('Location: ' . get_pkgbase_uri($pkgbase_name)); - exit(); - } -} - -/* Get default comment. */ -$comment = ''; -if (isset($_POST['comments'])) { - $comment = $_POST['comments']; -} - -html_header(__("Flag Package Out-Of-Date")); - -if (has_credential(CRED_PKGBASE_FLAG)): ?> -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
      - -
    • - -
    - -

    - This seems to be a VCS package. Please do not - flag it out-of-date if the package version in the AUR does not - match the most recent commit. Flagging this package should only - be done if the sources moved or changes in the PKGBUILD are - required because of recent upstream changes. -

    - -

    - ', ''); ?> - -

    - - -
    - - -
    -
    - - - -

    - - -

    -

    " />

    -
    -
    -
    - - -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> - -

    -
      - -
    • - -
    -

    - - - -

    -
    -
    - - - - - - - - -

    -

    -

    -

    " />

    -
    -
    -
    - - 0) ? $_GET['PP'] : 50; - $current = ceil($first / $per_page); - $pages = ceil($total / $per_page); - $templ_pages = array(); - - if ($current > 1) { - $templ_pages['« ' . __('First')] = 0; - $templ_pages['‹ ' . __('Previous')] = ($current - 2) * $per_page; - } - - if ($current - 5 > 1) - $templ_pages["..."] = false; - - for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) { - $templ_pages[$i] = ($i - 1) * $per_page; - } - - if ($current + 5 < $pages) - $templ_pages["... "] = false; - - if ($current < $pages) { - $templ_pages[__('Next') . ' ›'] = $current * $per_page; - $templ_pages[__('Last') . ' »'] = ($pages - 1) * $per_page; - } - - $SID = $_COOKIE['AURSID']; - - html_header(__("Requests")); - echo '
    '; - $show_headers = true; - include('pkgreq_results.php'); - echo '
    '; -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/register.php b/web/html/register.php deleted file mode 100644 index fee0a68f..00000000 --- a/web/html/register.php +++ /dev/null @@ -1,87 +0,0 @@ -'; -echo '

    ' . __('Register') . '

    '; - -if (in_request("Action") == "NewAccount") { - list($success, $message) = process_account_form( - "new", - "NewAccount", - in_request("U"), - 1, - 0, - in_request("E"), - in_request("BE"), - in_request("H"), - '', - '', - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - 0, - in_request("CN"), - in_request("UN"), - in_request("ON"), - 0, - "", - '', - in_request("captcha_salt"), - in_request("captcha"), - ); - - print $message; - - if (!$success) { - display_account_form("NewAccount", - in_request("U"), - 1, - 0, - in_request("E"), - in_request("BE"), - in_request("H"), - '', - '', - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - 0, - in_request("CN"), - in_request("UN"), - in_request("ON"), - 0, - "", - '', - in_request("captcha_salt"), - in_request("captcha") - ); - } -} else { - print '

    ' . __("Use this form to create an account.") . '

    '; - display_account_form("NewAccount", "", "", "", "", "", "", "", "", "", $LANG); -} - -echo ''; - -html_footer(AURWEB_VERSION); - -?> diff --git a/web/html/rpc.php b/web/html/rpc.php deleted file mode 100644 index 64c95622..00000000 --- a/web/html/rpc.php +++ /dev/null @@ -1,17 +0,0 @@ -handle($_GET); -} -else { - echo file_get_contents('../../doc/rpc.html'); -} -?> diff --git a/web/html/rss.php b/web/html/rss.php deleted file mode 100644 index 1e6335cf..00000000 --- a/web/html/rss.php +++ /dev/null @@ -1,61 +0,0 @@ -cssStyleSheet = false; -$rss->xslStyleSheet = false; - -# Use UTF-8 (fixes FS#10706). -$rss->encoding = "UTF-8"; - -#All the general RSS setup -$rss->title = "AUR Newest Packages"; -$rss->description = "The latest and greatest packages in the AUR"; -$rss->link = "${protocol}://{$host}"; -$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); -$image = new FeedImage(); -$image->title = "AUR Newest Packages"; -$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; -$image->link = $rss->link; -$image->description = "AUR Newest Packages Feed"; -$rss->image = $image; - -#Get the latest packages and add items for them -$packages = latest_pkgs(100); - -foreach ($packages as $indx => $row) { - $item = new FeedItem(); - $item->title = $row["Name"]; - $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); - $item->description = $row["Description"]; - $item->date = intval($row["SubmittedTS"]); - $item->source = "{$protocol}://{$host}"; - $item->author = username_from_id($row["MaintainerUID"]); - $item->guid = $item->link; - $rss->addItem($item); -} - -#save it so that useCached() can find it -$feedContent = $rss->createFeed(); -set_cache_value($feed_key, $feedContent, 600); -echo $feedContent; -?> diff --git a/web/html/tos.php b/web/html/tos.php deleted file mode 100644 index fc5d8765..00000000 --- a/web/html/tos.php +++ /dev/null @@ -1,50 +0,0 @@ - -
    -

    AUR

    - -
    -
    -

    - ' . username_from_sid($_COOKIE["AURSID"]) . ''); ?> -

    -

    - -

    -
      - -
    • "> ()
    • - -
    -

    - - ]" value="" /> - - -

    -

    - " /> -

    -
    -
    - -
    - time() ? 1 : 0; - - # List voters of a proposal. - $whovoted = voter_list($row['ID']); - - $canvote = 1; - $hasvoted = 0; - $errorvote = ""; - if ($isrunning == 0) { - $canvote = 0; - $errorvote = __("Voting is closed for this proposal."); - } else if (!has_credential(CRED_TU_VOTE)) { - $canvote = 0; - $errorvote = __("Only Trusted Users are allowed to vote."); - } else if ($row['User'] == username_from_sid($_COOKIE["AURSID"])) { - $canvote = 0; - $errorvote = __("You cannot vote in an proposal about you."); - } - if (tu_voted($row['ID'], uid_from_sid($_COOKIE["AURSID"]))) { - $canvote = 0; - $hasvoted = 1; - if ($isrunning) { - $errorvote = __("You've already voted for this proposal."); - } - } - - if ($canvote == 1) { - if (isset($_POST['doVote']) && check_token()) { - if (isset($_POST['voteYes'])) { - $myvote = "Yes"; - } else if (isset($_POST['voteNo'])) { - $myvote = "No"; - } else if (isset($_POST['voteAbstain'])) { - $myvote = "Abstain"; - } - - cast_proposal_vote($row['ID'], uid_from_sid($_COOKIE["AURSID"]), $myvote, $row[$myvote] + 1); - - # Can't vote anymore - # - $canvote = 0; - $errorvote = __("You've already voted for this proposal."); - - # Update if they voted - if (tu_voted($row['ID'], uid_from_sid($_COOKIE["AURSID"]))) { - $hasvoted = 1; - } - $row = vote_details($_GET['id']); - } - } - include("tu_details.php"); - } - } else { - print __("Vote ID not valid."); - } - - } else { - $limit = $pp; - if (isset($_GET['off'])) - $offset = $_GET['off']; - - if (isset($_GET['by'])) - $by = $_GET['by']; - else - $by = 'desc'; - - if (!empty($offset) && is_numeric($offset)) { - if ($offset >= 1) { - $off = $offset; - } else { - $off = 0; - } - } else { - $off = 0; - } - - $order = ($by == 'asc') ? 'ASC' : 'DESC'; - $lim = ($limit > 0) ? " LIMIT $limit OFFSET $off" : ""; - $by_next = ($by == 'desc') ? 'asc' : 'desc'; - - $result = current_proposal_list($order); - $type = __("Current Votes"); - $nextresult = 0; - include("tu_list.php"); - - $result = past_proposal_list($order, $lim); - $type = __("Past Votes"); - $nextresult = proposal_count(); - include("tu_list.php"); - - $result = last_votes_list(); - include("tu_last_votes_list.php"); - } -} -else { - header('Location: /'); -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/voters.php b/web/html/voters.php deleted file mode 100644 index bacbcfc8..00000000 --- a/web/html/voters.php +++ /dev/null @@ -1,34 +0,0 @@ - - -
    -

    Votes for

    -
    -
      - $row): ?> -
    • - - 0): ?> - () - -
    • - -
    -
    -
    - -exec("SET NAMES 'utf8' COLLATE 'utf8_general_ci';"); - } else if ($backend == "sqlite") { - $dsn = $backend . - ":" . $name; - - self::$dbh = new PDO($dsn, null, null); - } else { - die("Error - " . $backend . " is not supported by aurweb"); - } - - } catch (PDOException $e) { - die('Error - Could not connect to AUR database'); - } - } - - return self::$dbh; - } -} diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php deleted file mode 100644 index 0d021f99..00000000 --- a/web/lib/acctfuncs.inc.php +++ /dev/null @@ -1,1522 +0,0 @@ -\n" - . "
  • " . __("It must be between %s and %s characters long", $length_min, $length_max) - . "
  • " - . "
  • " . __("Start and end with a letter or number") . "
  • " - . "
  • " . __("Can contain only one period, underscore or hyphen.") - . "
  • \n"; - } - - if (!$error && $P && !$C) { - $error = __("Please confirm your new password."); - } - if (!$error && $P && $P != $C) { - $error = __("Password fields do not match."); - } - if (!$error && $P != '' && !good_passwd($P)) { - $length_min = config_get_int('options', 'passwd_min_len'); - $error = __("Your password must be at least %s characters.", - $length_min); - } - - if (!$error && !valid_email($E)) { - $error = __("The email address is invalid."); - } - if (!$error && $BE && !valid_email($BE)) { - $error = __("The backup email address is invalid."); - } - - if (!$error && !empty($HP) && !valid_homepage($HP)) { - $error = __("The home page is invalid, please specify the full HTTP(s) URL."); - } - - if (!$error && $K != '' && !valid_pgp_fingerprint($K)) { - $error = __("The PGP key fingerprint is invalid."); - } - - if (!$error && !empty($PK)) { - $ssh_keys = array_filter(array_map('trim', explode("\n", $PK))); - $ssh_fingerprints = array(); - - foreach ($ssh_keys as &$ssh_key) { - if (!valid_ssh_pubkey($ssh_key)) { - $error = __("The SSH public key is invalid."); - break; - } - - $ssh_fingerprint = ssh_key_fingerprint($ssh_key); - if (!$ssh_fingerprint) { - $error = __("The SSH public key is invalid."); - break; - } - - $tokens = explode(" ", $ssh_key); - $ssh_key = $tokens[0] . " " . $tokens[1]; - - $ssh_fingerprints[] = $ssh_fingerprint; - } - - /* - * Destroy last reference to prevent accidentally overwriting - * an array element. - */ - unset($ssh_key); - } - - if (isset($_COOKIE['AURSID'])) { - $atype = account_from_sid($_COOKIE['AURSID']); - if (($atype == "User" && $T > 1) || ($atype == "Trusted User" && $T > 2)) { - $error = __("Cannot increase account permissions."); - } - } - - if (!$error && !array_key_exists($L, $SUPPORTED_LANGS)) { - $error = __("Language is not currently supported."); - } - if (!$error && !array_key_exists($TZ, generate_timezone_list())) { - $error = __("Timezone is not currently supported."); - } - if (!$error) { - /* - * Check whether the user name is available. - * TODO: Fix race condition. - */ - $q = "SELECT COUNT(*) AS CNT FROM Users "; - $q.= "WHERE Username = " . $dbh->quote($U); - if ($TYPE == "edit") { - $q.= " AND ID != ".intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row[0]) { - $error = __("The username, %s%s%s, is already in use.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } - } - if (!$error) { - /* - * Check whether the e-mail address is available. - * TODO: Fix race condition. - */ - $q = "SELECT COUNT(*) AS CNT FROM Users "; - $q.= "WHERE Email = " . $dbh->quote($E); - if ($TYPE == "edit") { - $q.= " AND ID != ".intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row[0]) { - $error = __("The address, %s%s%s, is already in use.", - "", htmlspecialchars($E,ENT_QUOTES), ""); - } - } - if (!$error && isset($ssh_keys) && count($ssh_keys) > 0) { - /* - * Check whether any of the SSH public keys is already in use. - * TODO: Fix race condition. - */ - $q = "SELECT Fingerprint FROM SSHPubKeys "; - $q.= "WHERE Fingerprint IN ("; - $q.= implode(',', array_map(array($dbh, 'quote'), $ssh_fingerprints)); - $q.= ")"; - if ($TYPE == "edit") { - $q.= " AND UserID != " . intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - $error = __("The SSH public key, %s%s%s, is already in use.", - "", htmlspecialchars($row[0], ENT_QUOTES), ""); - } - } - - if (!$error && $TYPE == "new" && empty($captcha)) { - $error = __("The CAPTCHA is missing."); - } - - if (!$error && $TYPE == "new" && !in_array($captcha_salt, get_captcha_salts())) { - $error = __("This CAPTCHA has expired. Please try again."); - } - - if (!$error && $TYPE == "new" && $captcha != get_captcha_answer($captcha_salt)) { - $error = __("The entered CAPTCHA answer is invalid."); - } - - if ($error) { - $message = "
    • ".$error."
    \n"; - return array(false, $message); - } - - if ($TYPE == "new") { - /* Create an unprivileged user. */ - if (empty($P)) { - $send_resetkey = true; - $email = $E; - } else { - $send_resetkey = false; - $P = password_hash($P, PASSWORD_DEFAULT); - } - $U = $dbh->quote($U); - $E = $dbh->quote($E); - $BE = $dbh->quote($BE); - $P = $dbh->quote($P); - $R = $dbh->quote($R); - $L = $dbh->quote($L); - $TZ = $dbh->quote($TZ); - $HP = $dbh->quote($HP); - $I = $dbh->quote($I); - $K = $dbh->quote(str_replace(" ", "", $K)); - $q = "INSERT INTO Users (AccountTypeID, Suspended, "; - $q.= "InactivityTS, Username, Email, BackupEmail, Passwd , "; - $q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) "; - $q.= "VALUES (1, 0, 0, $U, $E, $BE, $P, $R, $L, $TZ, "; - $q.= "$HP, $I, $K)"; - $result = $dbh->exec($q); - if (!$result) { - $message = __("Error trying to create account, %s%s%s.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - return array(false, $message); - } - - $uid = $dbh->lastInsertId(); - if (isset($ssh_keys) && count($ssh_keys) > 0) { - account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints); - } - - $message = __("The account, %s%s%s, has been successfully created.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - $message .= "

    \n"; - - if ($send_resetkey) { - send_resetkey($email, true); - $message .= __("A password reset key has been sent to your e-mail address."); - $message .= "

    \n"; - } else { - $message .= __("Click on the Login link above to use your account."); - $message .= "

    \n"; - } - } else { - /* Modify an existing account. */ - $q = "SELECT InactivityTS FROM Users WHERE "; - $q.= "ID = " . intval($UID); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - if ($row[0] && $J) { - $inactivity_ts = $row[0]; - } elseif ($J) { - $inactivity_ts = time(); - } else { - $inactivity_ts = 0; - } - - $q = "UPDATE Users SET "; - $q.= "Username = " . $dbh->quote($U); - if ($T) { - $q.= ", AccountTypeID = ".intval($T); - } - if ($S) { - /* Ensure suspended users can't keep an active session */ - delete_user_sessions($UID); - $q.= ", Suspended = 1"; - } else { - $q.= ", Suspended = 0"; - } - $q.= ", Email = " . $dbh->quote($E); - $q.= ", BackupEmail = " . $dbh->quote($BE); - if ($H) { - $q.= ", HideEmail = 1"; - } else { - $q.= ", HideEmail = 0"; - } - if ($P) { - $hash = password_hash($P, PASSWORD_DEFAULT); - $q .= ", Passwd = " . $dbh->quote($hash); - } - $q.= ", RealName = " . $dbh->quote($R); - $q.= ", LangPreference = " . $dbh->quote($L); - $q.= ", Timezone = " . $dbh->quote($TZ); - $q.= ", Homepage = " . $dbh->quote($HP); - $q.= ", IRCNick = " . $dbh->quote($I); - $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K)); - $q.= ", InactivityTS = " . $inactivity_ts; - $q.= ", CommentNotify = " . ($CN ? "1" : "0"); - $q.= ", UpdateNotify = " . ($UN ? "1" : "0"); - $q.= ", OwnershipNotify = " . ($ON ? "1" : "0"); - $q.= " WHERE ID = ".intval($UID); - $result = $dbh->exec($q); - - if (isset($ssh_keys) && count($ssh_keys) > 0) { - $ssh_key_result = account_set_ssh_keys($UID, $ssh_keys, $ssh_fingerprints); - } else { - $ssh_key_result = true; - } - - if (isset($_COOKIE["AURTZ"]) && ($_COOKIE["AURTZ"] != $TZ)) { - /* set new cookie for timezone */ - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURTZ", $TZ, $cookie_time, "/"); - } - - if (isset($_COOKIE["AURLANG"]) && ($_COOKIE["AURLANG"] != $L)) { - /* set new cookie for language */ - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURLANG", $L, $cookie_time, "/"); - } - - if ($result === false || $ssh_key_result === false) { - $message = __("No changes were made to the account, %s%s%s.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } else { - $message = __("The account, %s%s%s, has been successfully modified.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } - } - - return array(true, $message); -} - -/** - * Display the search results page - * - * @param string $O The offset for the results page - * @param string $SB The column to sort the results page by - * @param string $U The username search criteria - * @param string $T The account type search criteria - * @param string $S Whether the account is suspended search criteria - * @param string $E The e-mail address search criteria - * @param string $R The real name search criteria - * @param string $I The IRC nickname search criteria - * @param string $K The PGP key fingerprint search criteria - * - * @return void - */ -function search_results_page($O=0,$SB="",$U="",$T="", - $S="",$E="",$R="",$I="",$K="") { - - $HITS_PER_PAGE = 50; - if ($O) { - $OFFSET = intval($O); - } else { - $OFFSET = 0; - } - if ($OFFSET < 0) { - $OFFSET = 0; - } - $search_vars = array(); - - $dbh = DB::connect(); - - $q = "SELECT Users.*, AccountTypes.AccountType "; - $q.= "FROM Users, AccountTypes "; - $q.= "WHERE AccountTypes.ID = Users.AccountTypeID "; - if ($T == "u") { - $q.= "AND AccountTypes.ID = 1 "; - $search_vars[] = "T"; - } elseif ($T == "t") { - $q.= "AND AccountTypes.ID = 2 "; - $search_vars[] = "T"; - } elseif ($T == "d") { - $q.= "AND AccountTypes.ID = 3 "; - $search_vars[] = "T"; - } elseif ($T == "td") { - $q.= "AND AccountTypes.ID = 4 "; - $search_vars[] = "T"; - } - if ($S) { - $q.= "AND Users.Suspended = 1 "; - $search_vars[] = "S"; - } - if ($U) { - $U = "%" . addcslashes($U, '%_') . "%"; - $q.= "AND Username LIKE " . $dbh->quote($U) . " "; - $search_vars[] = "U"; - } - if ($E) { - $E = "%" . addcslashes($E, '%_') . "%"; - $q.= "AND Email LIKE " . $dbh->quote($E) . " "; - $search_vars[] = "E"; - } - if ($R) { - $R = "%" . addcslashes($R, '%_') . "%"; - $q.= "AND RealName LIKE " . $dbh->quote($R) . " "; - $search_vars[] = "R"; - } - if ($I) { - $I = "%" . addcslashes($I, '%_') . "%"; - $q.= "AND IRCNick LIKE " . $dbh->quote($I) . " "; - $search_vars[] = "I"; - } - if ($K) { - $K = "%" . addcslashes(str_replace(" ", "", $K), '%_') . "%"; - $q.= "AND PGPKey LIKE " . $dbh->quote($K) . " "; - $search_vars[] = "K"; - } - switch ($SB) { - case 't': - $q.= "ORDER BY AccountTypeID, Username "; - break; - case 'r': - $q.= "ORDER BY RealName, AccountTypeID "; - break; - case 'i': - $q.= "ORDER BY IRCNick, AccountTypeID "; - break; - default: - $q.= "ORDER BY Username, AccountTypeID "; - break; - } - $search_vars[] = "SB"; - $q.= "LIMIT " . $HITS_PER_PAGE . " OFFSET " . $OFFSET; - - $dbh = DB::connect(); - - $result = $dbh->query($q); - - $userinfo = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $userinfo[] = $row; - } - } - - include("account_search_results.php"); - return; -} - -/** - * Attempt to login and generate a session - * - * @return array Session ID for user, error message if applicable - */ -function try_login() { - $login_error = ""; - $new_sid = ""; - $userID = null; - - if (!isset($_REQUEST['user']) && !isset($_REQUEST['passwd'])) { - return array('SID' => '', 'error' => null); - } - - if (is_ipbanned()) { - $login_error = __('The login form is currently disabled ' . - 'for your IP address, probably due ' . - 'to sustained spam attacks. Sorry for the ' . - 'inconvenience.'); - return array('SID' => '', 'error' => $login_error); - } - - $dbh = DB::connect(); - $userID = uid_from_loginname($_REQUEST['user']); - - if (user_suspended($userID)) { - $login_error = __('Account suspended'); - return array('SID' => '', 'error' => $login_error); - } - - switch (check_passwd($userID, $_REQUEST['passwd'])) { - case -1: - $login_error = __('Your password has been reset. ' . - 'If you just created a new account, please ' . - 'use the link from the confirmation email ' . - 'to set an initial password. Otherwise, ' . - 'please request a reset key on the %s' . - 'Password Reset%s page.', '', - ''); - return array('SID' => '', 'error' => $login_error); - case 0: - $login_error = __("Bad username or password."); - return array('SID' => '', 'error' => $login_error); - case 1: - break; - } - - $logged_in = 0; - $num_tries = 0; - - /* Generate a session ID and store it. */ - while (!$logged_in && $num_tries < 5) { - $new_sid = new_sid(); - $q = "INSERT INTO Sessions (UsersID, SessionID, LastUpdateTS)" - ." VALUES (" . $userID . ", '" . $new_sid . "', " . strval(time()) . ")"; - $result = $dbh->exec($q); - - /* Query will fail if $new_sid is not unique. */ - if ($result) { - $logged_in = 1; - break; - } - - $num_tries++; - } - - if (!$logged_in) { - $login_error = __('An error occurred trying to generate a user session.'); - return array('SID' => $new_sid, 'error' => $login_error); - } - - $q = "UPDATE Users SET LastLogin = " . strval(time()) . ", "; - $q.= "LastLoginIPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']) . " "; - $q.= "WHERE ID = $userID"; - $dbh->exec($q); - - /* Set the SID cookie. */ - if (isset($_POST['remember_me']) && $_POST['remember_me'] == "on") { - /* Set cookies for 30 days. */ - $timeout = config_get_int('options', 'persistent_cookie_timeout'); - $cookie_time = time() + $timeout; - - /* Set session for 30 days. */ - $q = "UPDATE Sessions SET LastUpdateTS = $cookie_time "; - $q.= "WHERE SessionID = '$new_sid'"; - $dbh->exec($q); - } else { - $cookie_time = 0; - } - - setcookie("AURSID", $new_sid, $cookie_time, "/", null, !empty($_SERVER['HTTPS']), true); - - $referer = in_request('referer'); - if (strpos($referer, aur_location()) !== 0) { - $referer = '/'; - } - header("Location: " . get_uri($referer)); - $login_error = ""; - return array('SID' => $new_sid, 'error' => null); -} - -/** - * Determine if the user is using a banned IP address - * - * @return bool True if IP address is banned, otherwise false - */ -function is_ipbanned() { - $dbh = DB::connect(); - - $q = "SELECT * FROM Bans WHERE IPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']); - $result = $dbh->query($q); - - return ($result->fetchColumn() ? true : false); -} - -/** - * Validate a username against a collection of rules - * - * The username must be longer or equal to the configured minimum length. It - * must be shorter or equal to the configured maximum length. It must start and - * end with either a letter or a number. It can contain one period, hypen, or - * underscore. Returns boolean of whether name is valid. - * - * @param string $user Username to validate - * - * @return bool True if username meets criteria, otherwise false - */ -function valid_username($user) { - $length_min = config_get_int('options', 'username_min_len'); - $length_max = config_get_int('options', 'username_max_len'); - - if (strlen($user) < $length_min || strlen($user) > $length_max) { - return false; - } else if (!preg_match("/^[a-z0-9]+[.\-_]?[a-z0-9]+$/Di", $user)) { - return false; - } - - return true; -} - -/** - * Determine if a user already has a proposal open about themselves - * - * @param string $user Username to checkout for open proposal - * - * @return bool True if there is an open proposal about the user, otherwise false - */ -function open_user_proposals($user) { - $dbh = DB::connect(); - $q = "SELECT * FROM TU_VoteInfo WHERE User = " . $dbh->quote($user) . " "; - $q.= "AND End > " . strval(time()); - $result = $dbh->query($q); - - return ($result->fetchColumn() ? true : false); -} - -/** - * Add a new Trusted User proposal to the database - * - * @param string $agenda The agenda of the vote - * @param string $user The use the vote is about - * @param int $votelength The length of time for the vote to last - * @param string $submitteruid The user ID of the individual who submitted the proposal - * - * @return void - */ -function add_tu_proposal($agenda, $user, $votelength, $quorum, $submitteruid) { - $dbh = DB::connect(); - - $q = "SELECT COUNT(*) FROM Users WHERE (AccountTypeID = 2 OR AccountTypeID = 4)"; - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - $active_tus = $row[0]; - - $q = "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End, Quorum, "; - $q.= "SubmitterID, ActiveTUs) VALUES "; - $q.= "(" . $dbh->quote($agenda) . ", " . $dbh->quote($user) . ", "; - $q.= strval(time()) . ", " . strval(time()) . " + " . $dbh->quote($votelength); - $q.= ", " . $dbh->quote($quorum) . ", " . $submitteruid . ", "; - $q.= $active_tus . ")"; - $result = $dbh->exec($q); -} - -/** - * Add a reset key to the database for a specified user - * - * @param string $resetkey A password reset key to be stored in database - * @param string $uid The user ID to store the reset key for - * - * @return void - */ -function create_resetkey($resetkey, $uid) { - $dbh = DB::connect(); - $q = "UPDATE Users "; - $q.= "SET ResetKey = '" . $resetkey . "' "; - $q.= "WHERE ID = " . $uid; - $dbh->exec($q); -} - -/** - * Send a reset key to a specific e-mail address - * - * @param string $user User name or email address of the user - * @param bool $welcome Whether to use the welcome message - * - * @return void - */ -function send_resetkey($user, $welcome=false) { - $uid = uid_from_loginname($user); - if ($uid == null) { - return; - } - - /* We (ab)use new_sid() to get a random 32 characters long string. */ - $resetkey = new_sid(); - create_resetkey($resetkey, $uid); - - /* Send e-mail with confirmation link. */ - notify(array($welcome ? 'welcome' : 'send-resetkey', $uid)); -} - -/** - * Change a user's password in the database if reset key and e-mail are correct - * - * @param string $password The new password - * @param string $resetkey Code e-mailed to a user to reset a password - * @param string $user User name or email address of the user - * - * @return string|void Redirect page if successful, otherwise return error message - */ -function password_reset($password, $resetkey, $user) { - $hash = password_hash($password, PASSWORD_DEFAULT); - - $dbh = DB::connect(); - $q = "UPDATE Users SET "; - $q.= "Passwd = " . $dbh->quote($hash) . ", "; - $q.= "ResetKey = '' "; - $q.= "WHERE ResetKey != '' "; - $q.= "AND ResetKey = " . $dbh->quote($resetkey) . " "; - $q.= "AND (Email = " . $dbh->quote($user) . " OR "; - $q.= "UserName = " . $dbh->quote($user) . ")"; - $result = $dbh->exec($q); - - if (!$result) { - $error = __('Invalid e-mail and reset key combination.'); - return $error; - } else { - header('Location: ' . get_uri('/passreset/') . '?step=complete'); - exit(); - } -} - -/** - * Determine if the password is longer than the minimum length - * - * @param string $passwd The password to check - * - * @return bool True if longer than minimum length, otherwise false - */ -function good_passwd($passwd) { - $length_min = config_get_int('options', 'passwd_min_len'); - return (strlen($passwd) >= $length_min); -} - -/** - * Determine if the password is correct and salt it if it hasn't been already - * - * @param int $user_id The user ID to check the password against - * @param string $passwd The password the visitor sent - * - * @return int Positive if password is correct, negative if password is unset - */ -function check_passwd($user_id, $passwd) { - $dbh = DB::connect(); - - /* Get password hash and salt. */ - $q = "SELECT Passwd, Salt FROM Users WHERE ID = " . intval($user_id); - $result = $dbh->query($q); - if (!$result) { - return 0; - } - $row = $result->fetch(PDO::FETCH_ASSOC); - if (!$row) { - return 0; - } - $hash = $row['Passwd']; - $salt = $row['Salt']; - if (!$hash) { - return -1; - } - - /* Verify the password hash. */ - if (!password_verify($passwd, $hash)) { - /* Invalid password, fall back to MD5. */ - if (md5($salt . $passwd) != $hash) { - return 0; - } - } - - /* Password correct, migrate the hash if necessary. */ - if (password_needs_rehash($hash, PASSWORD_DEFAULT)) { - $hash = password_hash($passwd, PASSWORD_DEFAULT); - - $q = "UPDATE Users SET Passwd = " . $dbh->quote($hash) . " "; - $q.= "WHERE ID = " . intval($user_id); - $dbh->query($q); - } - - return 1; -} - -/** - * Determine if the PGP key fingerprint is valid (must be 40 hexadecimal digits) - * - * @param string $fingerprint PGP fingerprint to check if valid - * - * @return bool True if the fingerprint is 40 hexadecimal digits, otherwise false - */ -function valid_pgp_fingerprint($fingerprint) { - $fingerprint = str_replace(" ", "", $fingerprint); - return (strlen($fingerprint) == 40 && ctype_xdigit($fingerprint)); -} - -/** - * Determine if the SSH public key is valid - * - * @param string $pubkey SSH public key to check - * - * @return bool True if the SSH public key is valid, otherwise false - */ -function valid_ssh_pubkey($pubkey) { - $valid_prefixes = explode(' ', config_get('auth', 'valid-keytypes')); - - $has_valid_prefix = false; - foreach ($valid_prefixes as $prefix) { - if (strpos($pubkey, $prefix . " ") === 0) { - $has_valid_prefix = true; - break; - } - } - if (!$has_valid_prefix) { - return false; - } - - $tokens = explode(" ", $pubkey); - if (empty($tokens[1])) { - return false; - } - - return (base64_encode(base64_decode($tokens[1], true)) == $tokens[1]); -} - -/** - * Determine if the user account has been suspended - * - * @param string $id The ID of user to check if suspended - * - * @return bool True if the user is suspended, otherwise false - */ -function user_suspended($id) { - $dbh = DB::connect(); - if (!$id) { - return false; - } - $q = "SELECT Suspended FROM Users WHERE ID = " . $id; - $result = $dbh->query($q); - if ($result) { - $row = $result->fetch(PDO::FETCH_NUM); - if ($row[0]) { - return true; - } - } - return false; -} - -/** - * Delete a specified user account from the database - * - * @param int $id The user ID of the account to be deleted - * - * @return void - */ -function user_delete($id) { - $dbh = DB::connect(); - $id = intval($id); - - /* - * These are normally already taken care of by propagation constraints - * but it is better to be explicit here. - */ - $fields_delete = array( - array("Sessions", "UsersID"), - array("PackageVotes", "UsersID"), - array("PackageNotifications", "UserID") - ); - - $fields_set_null = array( - array("PackageBases", "SubmitterUID"), - array("PackageBases", "MaintainerUID"), - array("PackageBases", "PackagerUID"), - array("PackageComments", "UsersID"), - array("PackageComments", "DelUsersID"), - array("PackageRequests", "UsersID"), - array("TU_VoteInfo", "SubmitterID"), - array("TU_Votes", "UserID") - ); - - foreach($fields_delete as list($table, $field)) { - $q = "DELETE FROM " . $table . " "; - $q.= "WHERE " . $field . " = " . $id; - $dbh->query($q); - } - - foreach($fields_set_null as list($table, $field)) { - $q = "UPDATE " . $table . " SET " . $field . " = NULL "; - $q.= "WHERE " . $field . " = " . $id; - $dbh->query($q); - } - - $q = "DELETE FROM Users WHERE ID = " . $id; - $dbh->query($q); - return; -} - -/** - * Remove the session from the database on logout - * - * @param string $sid User's session ID - * - * @return void - */ -function delete_session_id($sid) { - $dbh = DB::connect(); - - $q = "DELETE FROM Sessions WHERE SessionID = " . $dbh->quote($sid); - $dbh->query($q); -} - -/** - * Remove all sessions belonging to a particular user - * - * @param int $uid ID of user to remove all sessions for - * - * @return void - */ -function delete_user_sessions($uid) { - $dbh = DB::connect(); - - $q = "DELETE FROM Sessions WHERE UsersID = " . intval($uid); - $dbh->exec($q); -} - -/** - * Remove sessions from the database that have exceed the timeout - * - * @return void - */ -function clear_expired_sessions() { - $dbh = DB::connect(); - - $timeout = config_get_int('options', 'login_timeout'); - $q = "DELETE FROM Sessions WHERE LastUpdateTS < (" . strval(time()) . " - " . $timeout . ")"; - $dbh->query($q); - - return; -} - -/** - * Get account details for a specific user - * - * @param string $uid The User ID of account to get information for - * @param string $username The username of the account to get for - * - * @return array Account details for the specified user - */ -function account_details($uid, $username) { - $dbh = DB::connect(); - $q = "SELECT Users.*, AccountTypes.AccountType "; - $q.= "FROM Users, AccountTypes "; - $q.= "WHERE AccountTypes.ID = Users.AccountTypeID "; - if (!empty($uid)) { - $q.= "AND Users.ID = ".intval($uid); - } else { - $q.= "AND Users.Username = " . $dbh->quote($username); - } - $result = $dbh->query($q); - - if ($result) { - $row = $result->fetch(PDO::FETCH_ASSOC); - } - - return $row; -} - -/** - * Determine if a user has already voted on a specific proposal - * - * @param string $voteid The ID of the Trusted User proposal - * @param string $uid The ID to check if the user already voted - * - * @return bool True if the user has already voted, otherwise false - */ -function tu_voted($voteid, $uid) { - $dbh = DB::connect(); - - $q = "SELECT COUNT(*) FROM TU_Votes "; - $q.= "WHERE VoteID = " . intval($voteid) . " AND UserID = " . intval($uid); - $result = $dbh->query($q); - if ($result->fetchColumn() > 0) { - return true; - } - else { - return false; - } -} - -/** - * Get all current Trusted User proposals from the database - * - * @param string $order Ascending or descending order for the proposal listing - * - * @return array The details for all current Trusted User proposals - */ -function current_proposal_list($order) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo WHERE End > " . time() . " ORDER BY Submitted " . $order; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Get a subset of all past Trusted User proposals from the database - * - * @param string $order Ascending or descending order for the proposal listing - * @param string $lim The number of proposals to list with the offset - * - * @return array The details for the subset of past Trusted User proposals - */ -function past_proposal_list($order, $lim) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo WHERE End < " . time() . " ORDER BY Submitted " . $order . $lim; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Get the vote ID of the last vote of all Trusted Users - * - * @return array The vote ID of the last vote of each Trusted User - */ -function last_votes_list() { - $dbh = DB::connect(); - - $q = "SELECT UserID, MAX(VoteID) AS LastVote FROM TU_Votes, "; - $q .= "TU_VoteInfo, Users WHERE TU_VoteInfo.ID = TU_Votes.VoteID AND "; - $q .= "TU_VoteInfo.End < " . strval(time()) . " AND "; - $q .= "Users.ID = TU_Votes.UserID AND (Users.AccountTypeID = 2 OR Users.AccountTypeID = 4) "; - $q .= "GROUP BY UserID ORDER BY LastVote DESC, UserName ASC"; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Determine the total number of Trusted User proposals - * - * @return string The total number of Trusted User proposals - */ -function proposal_count() { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM TU_VoteInfo"; - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - return $row[0]; -} - -/** - * Get all details related to a specific vote from the database - * - * @param string $voteid The ID of the Trusted User proposal - * - * @return array All stored details for a specific vote - */ -function vote_details($voteid) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo "; - $q.= "WHERE ID = " . intval($voteid); - - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_ASSOC); - - return $row; -} - -/** - * Get an alphabetical list of users who voted for a proposal with HTML links - * - * @param string $voteid The ID of the Trusted User proposal - * - * @return array All users who voted for a specific proposal - */ -function voter_list($voteid) { - $dbh = DB::connect(); - - $whovoted = array(); - - $q = "SELECT tv.UserID,U.Username "; - $q.= "FROM TU_Votes tv, Users U "; - $q.= "WHERE tv.VoteID = " . intval($voteid); - $q.= " AND tv.UserID = U.ID "; - $q.= "ORDER BY Username"; - - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $whovoted[] = $row['Username']; - } - } - return $whovoted; -} - -/** - * Cast a vote for a specific user proposal - * - * @param string $voteid The ID of the proposal being voted on - * @param string $uid The user ID of the individual voting - * @param string $vote Vote position, either "Yes", "No", or "Abstain" - * @param int $newtotal The total number of votes after the user has voted - * - * @return void - */ -function cast_proposal_vote($voteid, $uid, $vote, $newtotal) { - $dbh = DB::connect(); - - $q = "UPDATE TU_VoteInfo SET " . $vote . " = (" . $newtotal . ") WHERE ID = " . $voteid; - $result = $dbh->exec($q); - - $q = "INSERT INTO TU_Votes (VoteID, UserID) VALUES (" . intval($voteid) . ", " . intval($uid) . ")"; - $result = $dbh->exec($q); -} - -/** - * Verify a user has the proper permissions to edit an account - * - * @param array $acctinfo User account information for edited account - * - * @return bool True if permission to edit the account, otherwise false - */ -function can_edit_account($acctinfo) { - if ($acctinfo['AccountType'] == 'Developer' || - $acctinfo['AccountType'] == 'Trusted User & Developer') { - return has_credential(CRED_ACCOUNT_EDIT_DEV); - } - - $uid = $acctinfo['ID']; - return has_credential(CRED_ACCOUNT_EDIT, array($uid)); -} - -/* - * Compute the fingerprint of an SSH key. - * - * @param string $ssh_key The SSH public key to retrieve the fingerprint for - * - * @return string The SSH key fingerprint - */ -function ssh_key_fingerprint($ssh_key) { - $tmpfile = tempnam(sys_get_temp_dir(), "aurweb"); - file_put_contents($tmpfile, $ssh_key); - - /* - * The -l option of ssh-keygen can be used to show the fingerprint of - * the specified public key file. Expected output format: - * - * 2048 SHA256:uBBTXmCNjI2CnLfkuz9sG8F+e9/T4C+qQQwLZWIODBY user@host (RSA) - * - * ... where 2048 is the key length, the second token is the actual - * fingerprint, followed by the key comment and the key type. - */ - - $cmd = "/usr/bin/ssh-keygen -l -f " . escapeshellarg($tmpfile); - exec($cmd, $out, $ret); - if ($ret !== 0 || count($out) !== 1) { - return false; - } - - unlink($tmpfile); - - $tokens = explode(' ', $out[0]); - if (count($tokens) < 4) { - return false; - } - - $tokens = explode(':', $tokens[1]); - if (count($tokens) != 2 || $tokens[0] != 'SHA256') { - return false; - } - - return $tokens[1]; -} - -/* - * Get the SSH public keys associated with an account. - * - * @param int $uid The user ID of the account to retrieve the keys for. - * - * @return array An array representing the keys - */ -function account_get_ssh_keys($uid) { - $dbh = DB::connect(); - $q = "SELECT PubKey FROM SSHPubKeys WHERE UserID = " . intval($uid); - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/* - * Set the SSH public keys associated with an account. - * - * @param int $uid The user ID of the account to assign the keys to. - * @param array $ssh_keys The SSH public keys. - * @param array $ssh_fingerprints The corresponding SSH key fingerprints. - * - * @return bool Boolean flag indicating success or failure. - */ -function account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints) { - $dbh = DB::connect(); - - $q = sprintf("DELETE FROM SSHPubKeys WHERE UserID = %d", $uid); - $dbh->exec($q); - - $ssh_fingerprint = reset($ssh_fingerprints); - foreach ($ssh_keys as $ssh_key) { - $q = sprintf( - "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) " . - "VALUES (%d, %s, %s)", $uid, - $dbh->quote($ssh_fingerprint), $dbh->quote($ssh_key) - ); - $dbh->exec($q); - $ssh_fingerprint = next($ssh_fingerprints); - } - - return true; -} - -/* - * Invoke the email notification script. - * - * @param string $params Command line parameters for the script. - * - * @return void - */ -function notify($params) { - $cmd = config_get('notifications', 'notify-cmd'); - foreach ($params as $param) { - $cmd .= ' ' . escapeshellarg($param); - } - - $descspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); - - $p = proc_open($cmd, $descspec, $pipes); - - if (!is_resource($p)) { - return false; - } - - fclose($pipes[0]); - fclose($pipes[1]); - - return proc_close($p); -} - -/* - * Obtain a list of terms a given user has not yet accepted. - * - * @param int $uid The ID of the user to obtain terms for. - * - * @return array A list of terms the user has not yet accepted. - */ -function fetch_updated_terms($uid) { - $dbh = DB::connect(); - - $q = "SELECT ID, Terms.Revision, Description, URL "; - $q .= "FROM Terms LEFT JOIN AcceptedTerms "; - $q .= "ON AcceptedTerms.TermsID = Terms.ID "; - $q .= "AND AcceptedTerms.UsersID = " . intval($uid) . " "; - $q .= "WHERE AcceptedTerms.Revision IS NULL OR "; - $q .= "AcceptedTerms.Revision < Terms.Revision"; - - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(); - } else { - return array(); - } -} - -/* - * Accept a list of given terms. - * - * @param int $uid The ID of the user to accept the terms. - * @param array $termrev An array mapping each term to the accepted revision. - * - * @return void - */ -function accept_terms($uid, $termrev) { - $dbh = DB::connect(); - - $q = "SELECT TermsID, Revision FROM AcceptedTerms "; - $q .= "WHERE UsersID = " . intval($uid); - - $result = $dbh->query($q); - - if (!$result) { - return; - } - - $termrev_update = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $id = $row['TermsID']; - if (!array_key_exists($id, $termrev)) { - continue; - } - if ($row['Revision'] < $termrev[$id]) { - $termrev_update[$id] = $termrev[$id]; - } - } - $termrev_add = array_diff_key($termrev, $termrev_update); - - foreach ($termrev_add as $id => $rev) { - $q = "INSERT INTO AcceptedTerms (TermsID, UsersID, Revision) "; - $q .= "VALUES (" . intval($id) . ", " . intval($uid) . ", "; - $q .= intval($rev) . ")"; - $dbh->exec($q); - } - - foreach ($termrev_update as $id => $rev) { - $q = "UPDATE AcceptedTerms "; - $q .= "SET Revision = " . intval($rev) . " "; - $q .= "WHERE TermsID = " . intval($id) . " AND "; - $q .= "UsersID = " . intval($uid); - $dbh->exec($q); - } -} - -function account_comments($uid, $limit, $offset=0) { - $dbh = DB::connect(); - $q = "SELECT PackageComments.ID, Comments, UsersID, "; - $q.= "PackageBaseId, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "PinnedTS, "; - $q.= "C.UserName as DelUserName, RenderedComment, "; - $q.= "PB.ID as PackageBaseID, PB.Name as PackageBaseName "; - $q.= "FROM PackageComments "; - $q.= "LEFT JOIN PackageBases PB ON PackageComments.PackageBaseID = PB.ID "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; - $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; - $q.= "WHERE A.ID = " . $dbh->quote($uid) . " "; - $q.= "ORDER BY CommentTS DESC"; - - if ($limit > 0) { - $q.=" LIMIT " . intval($limit); - } - - if ($offset > 0) { - $q.=" OFFSET " . intval($offset); - } - - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return $result->fetchAll(); -} - -function account_comments_count($uid) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) "; - $q.= "FROM PackageComments "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "WHERE A.ID = " . $dbh->quote($uid); - - $result = $dbh->query($q); - return $result->fetchColumn(); -} - -/* - * Compute the list of active CAPTCHA salts. The salt changes based on the - * number of registered users. This ensures that new users always use a - * different salt and protects against hardcoding the CAPTCHA response. - * - * The first CAPTCHA in the list is the most recent one and should be used for - * new CAPTCHA challenges. The other ones are slightly outdated but may still - * be valid for recent challenges that were created before the number of users - * increased. The current implementation ensures that we can still use our - * CAPTCHA salt, even if five new users registered since the CAPTCHA challenge - * was created. - * - * @return string The list of active salts, the first being the most recent - * one. - */ -function get_captcha_salts() { - $dbh = DB::connect(); - $q = "SELECT count(*) FROM Users"; - $result = $dbh->query($q); - $user_count = $result->fetchColumn(); - - $ret = array(); - for ($i = 0; $i <= 5; $i++) { - array_push($ret, 'aurweb-' . ($user_count - $i)); - } - return $ret; -} - -/* - * Return the CAPTCHA challenge for a given salt. - * - * @param string $salt The salt to be used for the CAPTCHA computation. - * - * @return string The challenge as a string. - */ -function get_captcha_challenge($salt) { - $token = substr(md5($salt), 0, 3); - return "LC_ALL=C pacman -V|sed -r 's#[0-9]+#" . $token . "#g'|md5sum|cut -c1-6"; -} - -/* - * Compute CAPTCHA answer for a given salt. - * - * @param string $salt The salt to be used for the CAPTCHA computation. - * - * @return string The correct answer as a string. - */ -function get_captcha_answer($salt) { - $token = substr(md5($salt), 0, 3); - $text = <<quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if (!$row) { - # Invalid SessionID - hacker alert! - # - $failed = 1; - } else { - $last_update = $row[0]; - if ($last_update + $timeout <= $row[1]) { - $failed = 2; - } - } - - if ($failed == 1) { - # clear out the hacker's cookie, and send them to a naughty page - # why do you have to be so harsh on these people!? - # - setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); - unset($_COOKIE['AURSID']); - } elseif ($failed == 2) { - # session id timeout was reached and they must login again. - # - delete_session_id($_COOKIE["AURSID"]); - - setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); - unset($_COOKIE['AURSID']); - } else { - # still logged in and haven't reached the timeout, go ahead - # and update the idle timestamp - - # Only update the timestamp if it is less than the - # current time plus $timeout. - # - # This keeps 'remembered' sessions from being - # overwritten. - if ($last_update < time() + $timeout) { - $q = "UPDATE Sessions SET LastUpdateTS = " . strval(time()) . " "; - $q.= "WHERE SessionID = " . $dbh->quote($_COOKIE["AURSID"]); - $dbh->exec($q); - } - } - } - return; -} - -/** - * Redirect user to the Terms of Service agreement if there are updated terms. - * - * @return void - */ -function check_tos() { - if (!isset($_COOKIE["AURSID"])) { - return; - } - - $path = $_SERVER['PATH_INFO']; - $route = get_route($path); - if (!$route || $route == "tos.php") { - return; - } - - if (count(fetch_updated_terms(uid_from_sid($_COOKIE["AURSID"]))) > 0) { - header('Location: ' . get_uri('/tos')); - exit(); - } -} - -/** - * Verify the supplied CSRF token matches expected token - * - * @return bool True if the CSRF token is the same as the cookie SID, otherwise false - */ -function check_token() { - if (isset($_POST['token']) && isset($_COOKIE['AURSID'])) { - return ($_POST['token'] == $_COOKIE['AURSID']); - } else { - return false; - } -} - -/** - * Verify a user supplied e-mail against RFC 3696 and DNS records - * - * @param string $addy E-mail address being validated in foo@example.com format - * - * @return bool True if e-mail passes validity checks, otherwise false - */ -function valid_email($addy) { - // check against RFC 3696 - if (filter_var($addy, FILTER_VALIDATE_EMAIL) === false) { - return false; - } - - // check dns for mx, a, aaaa records - list($local, $domain) = explode('@', $addy); - if (!(checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A') || checkdnsrr($domain, 'AAAA'))) { - return false; - } - - return true; -} - -/** - * Verify that a given URL is valid and uses the HTTP(s) protocol - * - * @param string $url URL of the home page to be validated - * - * @return bool True if URL passes validity checks, false otherwise - */ -function valid_homepage($url) { - if (filter_var($url, FILTER_VALIDATE_URL) === false) { - return false; - } - - $url_components = parse_url($url); - if (!in_array($url_components['scheme'], array('http', 'https'))) { - return false; - } - - return true; -} - -/** - * Generate a unique session ID - * - * @return string MD5 hash of the concatenated user IP, random number, and current time - */ -function new_sid() { - return md5($_SERVER['REMOTE_ADDR'] . uniqid(mt_rand(), true)); -} - -/** - * Determine the user's username in the database using a user ID - * - * @param string $id User's ID - * - * @return string Username if it exists, otherwise null - */ -function username_from_id($id) { - $id = intval($id); - - $dbh = DB::connect(); - $q = "SELECT Username FROM Users WHERE ID = " . $dbh->quote($id); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's username in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string Username of the visitor - */ -function username_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Username "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Format a user name for inclusion in HTML data - * - * @param string $username The user name to format - * - * @return string The generated HTML code for the account link - */ -function html_format_username($username) { - $username_fmt = $username ? htmlspecialchars($username, ENT_QUOTES) : __("None"); - - if ($username && isset($_COOKIE["AURSID"])) { - $link = '' . $username_fmt . ''; - return $link; - } else { - return $username_fmt; - } -} - -/** - * Format the maintainer and co-maintainers for inclusion in HTML data - * - * @param string $maintainer The user name of the maintainer - * @param array $comaintainers The list of co-maintainer user names - * - * @return string The generated HTML code for the account links - */ -function html_format_maintainers($maintainer, $comaintainers) { - $code = html_format_username($maintainer); - - if (count($comaintainers) > 0) { - $code .= ' ('; - foreach ($comaintainers as $comaintainer) { - $code .= html_format_username($comaintainer); - if ($comaintainer !== end($comaintainers)) { - $code .= ', '; - } - } - $code .= ')'; - } - - return $code; -} - -/** - * Format a link in the package actions box - * - * @param string $uri The link target - * @param string $inner The HTML code to use for the link label - * - * @return string The generated HTML code for the action link - */ -function html_action_link($uri, $inner) { - if (isset($_COOKIE["AURSID"])) { - $code = ''; - } else { - $code = ''; - } - $code .= $inner . ''; - - return $code; -} - -/** - * Format a form in the package actions box - * - * @param string $uri The link target - * @param string $action The action name (passed as HTTP POST parameter) - * @param string $inner The HTML code to use for the link label - * - * @return string The generated HTML code for the action link - */ -function html_action_form($uri, $action, $inner) { - if (isset($_COOKIE["AURSID"])) { - $code = '
    '; - $code .= ''; - $code .= '
    '; - } else { - $code = ''; - $code .= $inner . ''; - } - - return $code; -} - -/** - * Determine the user's e-mail address in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string User's e-mail address as given during registration - */ -function email_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Email "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's account type in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string Account type of user ("User", "Trusted User", or "Developer") - */ -function account_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT AccountType "; - $q.= "FROM Users, AccountTypes, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND AccountTypes.ID = Users.AccountTypeID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's ID in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string|int The user's name, 0 on query failure - */ -function uid_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Users.ID "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return 0; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Common AUR header displayed on all pages - * - * @global string $LANG Language selected by the visitor - * @global array $SUPPORTED_LANGS Languages that are supported by the AUR - * @param string $title Name of the AUR page to be displayed on browser - * - * @return void - */ -function html_header($title="", $details=array()) { - global $LANG; - global $SUPPORTED_LANGS; - - include('header.php'); - return; -} - -/** - * Common AUR footer displayed on all pages - * - * @param string $ver The AUR version - * - * @return void - */ -function html_footer($ver="") { - include('footer.php'); - return; -} - -/** - * Determine if a user has permission to submit a package - * - * @param string $name Name of the package to be submitted - * @param string $sid User's session ID - * - * @return int 0 if the user can't submit, 1 if the user can submit - */ -function can_submit_pkgbase($name="", $sid="") { - if (!$name || !$sid) {return 0;} - $dbh = DB::connect(); - $q = "SELECT MaintainerUID "; - $q.= "FROM PackageBases WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if (!$row[0]) { - return 1; - } - $my_uid = uid_from_sid($sid); - - if ($row[0] === NULL || $row[0] == $my_uid) { - return 1; - } - - return 0; -} - -/** - * Determine if a package can be overwritten by some package base - * - * @param string $name Name of the package to be submitted - * @param int $base_id The ID of the package base - * - * @return bool True if the package can be overwritten, false if not - */ -function can_submit_pkg($name, $base_id) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM Packages WHERE "; - $q.= "Name = " . $dbh->quote($name) . " AND "; - $q.= "PackageBaseID <> " . intval($base_id); - $result = $dbh->query($q); - - if (!$result) return false; - return ($result->fetchColumn() == 0); -} - -/** - * Recursively delete a directory - * - * @param string $dirname Name of the directory to be removed - * - * @return void - */ -function rm_tree($dirname) { - if (empty($dirname) || !is_dir($dirname)) return; - - foreach (scandir($dirname) as $item) { - if ($item != '.' && $item != '..') { - $path = $dirname . '/' . $item; - if (is_file($path) || is_link($path)) { - unlink($path); - } - else { - rm_tree($path); - } - } - } - - rmdir($dirname); - - return; -} - - /** - * Determine the user's ID in the database using a username - * - * @param string $username The username of an account - * - * @return string Return user ID if exists for username, otherwise null - */ -function uid_from_username($username) { - $dbh = DB::connect(); - $q = "SELECT ID FROM Users WHERE Username = " . $dbh->quote($username); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's ID in the database using a username or email address - * - * @param string $username The username or email address of an account - * - * @return string Return user ID if exists, otherwise null - */ -function uid_from_loginname($loginname) { - $uid = uid_from_username($loginname); - if (!$uid) { - $uid = uid_from_email($loginname); - } - return $uid; -} - -/** - * Determine the user's ID in the database using an e-mail address - * - * @param string $email An e-mail address in foo@example.com format - * - * @return string The user's ID - */ -function uid_from_email($email) { - $dbh = DB::connect(); - $q = "SELECT ID FROM Users WHERE Email = " . $dbh->quote($email); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Generate clean url with edited/added user values - * - * Makes a clean string of variables for use in URLs based on current $_GET and - * list of values to edit/add to that. Any empty variables are discarded. - * - * @example print "http://example.com/test.php?" . mkurl("foo=bar&bar=baz") - * - * @param string $append string of variables and values formatted as in URLs - * - * @return string clean string of variables to append to URL, urlencoded - */ -function mkurl($append) { - $get = $_GET; - $append = explode('&', $append); - $uservars = array(); - $out = ''; - - foreach ($append as $i) { - $ex = explode('=', $i); - $uservars[$ex[0]] = $ex[1]; - } - - foreach ($uservars as $k => $v) { $get[$k] = $v; } - - foreach ($get as $k => $v) { - if ($v !== '') { - $out .= '&' . urlencode($k) . '=' . urlencode($v); - } - } - - return substr($out, 5); -} - -/** - * Get a package comment - * - * @param int $comment_id The ID of the comment - * - * @return array The user ID and comment OR null, null in case of an error - */ -function comment_by_id($comment_id) { - $dbh = DB::connect(); - $q = "SELECT UsersID, Comments FROM PackageComments "; - $q.= "WHERE ID = " . intval($comment_id); - $result = $dbh->query($q); - if (!$result) { - return array(null, null); - } - - return $result->fetch(PDO::FETCH_NUM); -} - -/** - * Process submitted comments so any links can be followed - * - * @param string $comment Raw user submitted package comment - * - * @return string User comment with links printed in HTML - */ -function parse_comment($comment) { - $url_pattern = '/(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' . - '(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))/iS'; - - $matches = preg_split($url_pattern, $comment, -1, - PREG_SPLIT_DELIM_CAPTURE); - - $html = ''; - for ($i = 0; $i < count($matches); $i++) { - if ($i % 2) { - # convert links - $html .= '' . htmlspecialchars($matches[$i]) . ''; - } - else { - # convert everything else - $html .= nl2br(htmlspecialchars($matches[$i])); - } - } - - return $html; -} - -/** - * Wrapper for beginning a database transaction - */ -function begin_atomic_commit() { - $dbh = DB::connect(); - $dbh->beginTransaction(); -} - -/** - * Wrapper for committing a database transaction - */ -function end_atomic_commit() { - $dbh = DB::connect(); - $dbh->commit(); -} - -/** - * Merge pkgbase and package options - * - * Merges entries of the first and the second array. If any key appears in both - * arrays and the corresponding value in the second array is either a non-array - * type or a non-empty array, the value from the second array replaces the - * value from the first array. If the value from the second array is an array - * containing a single empty string, the value in the resulting array becomes - * an empty array instead. If the value in the second array is empty, the - * resulting array contains the value from the first array. - * - * @param array $pkgbase_info Options from the pkgbase section - * @param array $section_info Options from the package section - * - * @return array Merged information from both sections - */ -function array_pkgbuild_merge($pkgbase_info, $section_info) { - $pi = $pkgbase_info; - foreach ($section_info as $opt_key => $opt_val) { - if (is_array($opt_val)) { - if ($opt_val == array('')) { - $pi[$opt_key] = array(); - } elseif (count($opt_val) > 0) { - $pi[$opt_key] = $opt_val; - } - } else { - $pi[$opt_key] = $opt_val; - } - } - return $pi; -} - -/** - * Bound an integer value between two values - * - * @param int $n Integer value to bound - * @param int $min Lower bound - * @param int $max Upper bound - * - * @return int Bounded integer value - */ -function bound($n, $min, $max) { - return min(max($n, $min), $max); -} - -/** - * Return the URL of the AUR root - * - * @return string The URL of the AUR root - */ -function aur_location() { - $location = config_get('options', 'aur_location'); - if (substr($location, -1) != '/') { - $location .= '/'; - } - return $location; -} - -/** - * Calculate pagination templates - * - * @return array The array of pagination templates, per page, and offset values - */ -function calculate_pagination($total_comment_count) { - /* Sanitize paging variables. */ - if (isset($_GET["O"])) { - $_GET["O"] = max(intval($_GET["O"]), 0); - } else { - $_GET["O"] = 0; - } - $offset = $_GET["O"]; - - if (isset($_GET["PP"])) { - $_GET["PP"] = bound(intval($_GET["PP"]), 1, 250); - } else { - $_GET["PP"] = 10; - } - $per_page = $_GET["PP"]; - - // Page offsets start at zero, so page 2 has offset 1, which means that we - // need to add 1 to the offset to get the current page. - $current_page = ceil($offset / $per_page) + 1; - $num_pages = ceil($total_comment_count / $per_page); - $pagination_templs = array(); - - if ($current_page > 1) { - $previous_page = $current_page - 1; - $previous_offset = ($previous_page - 1) * $per_page; - $pagination_templs['« ' . __('First')] = 0; - $pagination_templs['‹ ' . __('Previous')] = $previous_offset; - } - - if ($current_page - 5 > 1) { - $pagination_templs["..."] = false; - } - - for ($i = max($current_page - 5, 1); $i <= min($num_pages, $current_page + 5); $i++) { - $pagination_templs[$i] = ($i - 1) * $per_page; - } - - if ($current_page + 5 < $num_pages) - $pagination_templs["... "] = false; - - if ($current_page < $num_pages) { - $pagination_templs[__('Next') . ' ›'] = $current_page * $per_page; - $pagination_templs[__('Last') . ' »'] = ($num_pages - 1) * $per_page; - } - - return array($pagination_templs, $per_page, $offset); -} diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php deleted file mode 100644 index 81c27bd9..00000000 --- a/web/lib/aurjson.class.php +++ /dev/null @@ -1,710 +0,0 @@ -version = intval($http_data['v']); - } - if ($this->version < 1 || $this->version > 6) { - return $this->json_error('Invalid version specified.'); - } - - if (!isset($http_data['type']) || !isset($http_data['arg'])) { - return $this->json_error('No request type/data specified.'); - } - if (!in_array($http_data['type'], self::$exposed_methods)) { - return $this->json_error('Incorrect request type specified.'); - } - - if (isset($http_data['search_by']) && !isset($http_data['by'])) { - $http_data['by'] = $http_data['search_by']; - } - if (isset($http_data['by']) && !in_array($http_data['by'], self::$exposed_fields)) { - return $this->json_error('Incorrect by field specified.'); - } - - $this->dbh = DB::connect(); - - if ($this->check_ratelimit($_SERVER['REMOTE_ADDR'])) { - header("HTTP/1.1 429 Too Many Requests"); - return $this->json_error('Rate limit reached'); - } - - $type = str_replace('-', '_', $http_data['type']); - if ($type == 'info' && $this->version >= 5) { - $type = 'multiinfo'; - } - $json = call_user_func(array(&$this, $type), $http_data); - - $etag = md5($json); - header("Etag: \"$etag\""); - /* - * Make sure to strip a few things off the - * if-none-match header. Stripping whitespace may not - * be required, but removing the quote on the incoming - * header is required to make the equality test. - */ - $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? - trim($_SERVER['HTTP_IF_NONE_MATCH'], "\t\n\r\" ") : false; - if ($if_none_match && $if_none_match == $etag) { - header('HTTP/1.1 304 Not Modified'); - return; - } - - if (isset($http_data['callback'])) { - $callback = $http_data['callback']; - if (!preg_match('/^[a-zA-Z0-9()_.]{1,128}$/D', $callback)) { - return $this->json_error('Invalid callback name.'); - } - header('content-type: text/javascript'); - return '/**/' . $callback . '(' . $json . ')'; - } else { - header('content-type: application/json'); - return $json; - } - } - - /* - * Check if an IP needs to be rate limited. - * - * @param $ip IP of the current request - * - * @return true if IP needs to be rate limited, false otherwise. - */ - private function check_ratelimit($ip) { - $limit = config_get("ratelimit", "request_limit"); - if ($limit == 0) { - return false; - } - - $this->update_ratelimit($ip); - - $status = false; - $value = get_cache_value('ratelimit:' . $ip, $status); - if (!$status) { - $stmt = $this->dbh->prepare(" - SELECT Requests FROM ApiRateLimit - WHERE IP = :ip"); - $stmt->bindParam(":ip", $ip); - $result = $stmt->execute(); - - if (!$result) { - return false; - } - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - $value = $row['Requests']; - } - - return $value > $limit; - } - - /* - * Update a rate limit for an IP by increasing it's requests value by one. - * - * @param $ip IP of the current request - * - * @return void - */ - private function update_ratelimit($ip) { - $window_length = config_get("ratelimit", "window_length"); - $db_backend = config_get("database", "backend"); - $time = time(); - $deletion_time = $time - $window_length; - - /* Try to use the cache. */ - $status = false; - $value = get_cache_value('ratelimit-ws:' . $ip, $status); - if (!$status || ($status && $value < $deletion_time)) { - if (set_cache_value('ratelimit-ws:' . $ip, $time, $window_length) && - set_cache_value('ratelimit:' . $ip, 1, $window_length)) { - return; - } - } else { - $value = get_cache_value('ratelimit:' . $ip, $status); - if ($status && set_cache_value('ratelimit:' . $ip, $value + 1, $window_length)) - return; - } - - /* Clean up old windows. */ - $stmt = $this->dbh->prepare(" - DELETE FROM ApiRateLimit - WHERE WindowStart < :time"); - $stmt->bindParam(":time", $deletion_time); - $stmt->execute(); - - if ($db_backend == "mysql") { - $stmt = $this->dbh->prepare(" - INSERT INTO ApiRateLimit - (IP, Requests, WindowStart) - VALUES (:ip, 1, :window_start) - ON DUPLICATE KEY UPDATE Requests=Requests+1"); - $stmt->bindParam(":ip", $ip); - $stmt->bindParam(":window_start", $time); - $stmt->execute(); - } elseif ($db_backend == "sqlite") { - $stmt = $this->dbh->prepare(" - INSERT OR IGNORE INTO ApiRateLimit - (IP, Requests, WindowStart) - VALUES (:ip, 0, :window_start);"); - $stmt->bindParam(":ip", $ip); - $stmt->bindParam(":window_start", $time); - $stmt->execute(); - - $stmt = $this->dbh->prepare(" - UPDATE ApiRateLimit - SET Requests = Requests + 1 - WHERE IP = :ip"); - $stmt->bindParam(":ip", $ip); - $stmt->execute(); - } else { - throw new RuntimeException("Unknown database backend"); - } - } - - /* - * Returns a JSON formatted error string. - * - * @param $msg The error string to return - * - * @return mixed A json formatted error response. - */ - private function json_error($msg) { - header('content-type: application/json'); - if ($this->version < 3) { - return $this->json_results('error', 0, $msg, NULL); - } elseif ($this->version >= 3) { - return $this->json_results('error', 0, array(), $msg); - } - } - - /* - * Returns a JSON formatted result data. - * - * @param $type The response method type. - * @param $count The number of results to return - * @param $data The result data to return - * @param $error An error message to include in the response - * - * @return mixed A json formatted result response. - */ - private function json_results($type, $count, $data, $error) { - $json_array = array( - 'version' => $this->version, - 'type' => $type, - 'resultcount' => $count, - 'results' => $data - ); - - if ($this->version != 5) { - $json_array['warning'] = 'The use of versions lower than 5 is ' - . 'now deprecated and will soon be unsupported. To ensure ' - . 'your API client supports the change without issue, it ' - . 'should use version 5 and adjust for any changes in the ' - . 'API interface. See https://aur.archlinux.org/rpc for ' - . 'documentation related to v5.'; - } - - if ($error) { - $json_array['error'] = $error; - } - - return json_encode($json_array); - } - - /* - * Get extended package details (for info and multiinfo queries). - * - * @param $pkgid The ID of the package to retrieve details for. - * @param $base_id The ID of the package base to retrieve details for. - * - * @return array An array containing package details. - */ - private function get_extended_fields($pkgid, $base_id) { - $query = "SELECT DependencyTypes.Name AS Type, " . - "PackageDepends.DepName AS Name, " . - "PackageDepends.DepCondition AS Cond " . - "FROM PackageDepends " . - "LEFT JOIN DependencyTypes " . - "ON DependencyTypes.ID = PackageDepends.DepTypeID " . - "WHERE PackageDepends.PackageID = " . $pkgid . " " . - "UNION SELECT RelationTypes.Name AS Type, " . - "PackageRelations.RelName AS Name, " . - "PackageRelations.RelCondition AS Cond " . - "FROM PackageRelations " . - "LEFT JOIN RelationTypes " . - "ON RelationTypes.ID = PackageRelations.RelTypeID " . - "WHERE PackageRelations.PackageID = " . $pkgid . " " . - "UNION SELECT 'groups' AS Type, `Groups`.`Name`, '' AS Cond " . - "FROM `Groups` INNER JOIN PackageGroups " . - "ON PackageGroups.PackageID = " . $pkgid . " " . - "AND PackageGroups.GroupID = `Groups`.ID " . - "UNION SELECT 'license' AS Type, Licenses.Name, '' AS Cond " . - "FROM Licenses INNER JOIN PackageLicenses " . - "ON PackageLicenses.PackageID = " . $pkgid . " " . - "AND PackageLicenses.LicenseID = Licenses.ID"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($query, 'extended-fields:' . $pkgid, PDO::FETCH_ASSOC, $ttl); - - $type_map = array( - 'depends' => 'Depends', - 'makedepends' => 'MakeDepends', - 'checkdepends' => 'CheckDepends', - 'optdepends' => 'OptDepends', - 'conflicts' => 'Conflicts', - 'provides' => 'Provides', - 'replaces' => 'Replaces', - 'groups' => 'Groups', - 'license' => 'License', - ); - $data = array(); - foreach ($rows as $row) { - $type = $type_map[$row['Type']]; - $data[$type][] = $row['Name'] . $row['Cond']; - } - - if ($this->version >= 5) { - $query = "SELECT Keyword FROM PackageKeywords " . - "WHERE PackageBaseID = " . intval($base_id) . " " . - "ORDER BY Keyword ASC"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($query, 'keywords:' . intval($base_id), PDO::FETCH_NUM, $ttl); - $data['Keywords'] = array_map(function ($x) { return $x[0]; }, $rows); - } - - return $data; - } - - /* - * Retrieve package information (used in info, multiinfo, search and - * depends requests). - * - * @param $type The request type. - * @param $where_condition An SQL WHERE-condition to filter packages. - * - * @return mixed Returns an array of package matches. - */ - private function process_query($type, $where_condition) { - $max_results = config_get_int('options', 'max_rpc_results'); - - if ($this->version == 1) { - $fields = implode(',', self::$fields_v1); - $query = "SELECT {$fields} " . - "FROM Packages LEFT JOIN PackageBases " . - "ON PackageBases.ID = Packages.PackageBaseID " . - "LEFT JOIN Users " . - "ON PackageBases.MaintainerUID = Users.ID " . - "LEFT JOIN PackageLicenses " . - "ON PackageLicenses.PackageID = Packages.ID " . - "LEFT JOIN Licenses " . - "ON Licenses.ID = PackageLicenses.LicenseID " . - "WHERE ${where_condition} " . - "AND PackageBases.PackagerUID IS NOT NULL " . - "LIMIT $max_results"; - } elseif ($this->version >= 2) { - if ($this->version == 2 || $this->version == 3) { - $fields = implode(',', self::$fields_v2); - } else if ($this->version >= 4 && $this->version <= 6) { - $fields = implode(',', self::$fields_v4); - } - $query = "SELECT {$fields} " . - "FROM Packages LEFT JOIN PackageBases " . - "ON PackageBases.ID = Packages.PackageBaseID " . - "LEFT JOIN Users " . - "ON PackageBases.MaintainerUID = Users.ID " . - "WHERE ${where_condition} " . - "AND PackageBases.PackagerUID IS NOT NULL " . - "LIMIT $max_results"; - } - $result = $this->dbh->query($query); - - if ($result) { - $resultcount = 0; - $search_data = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $resultcount++; - $row['URLPath'] = sprintf(config_get('options', 'snapshot_uri'), urlencode($row['PackageBase'])); - if ($this->version < 4) { - $row['CategoryID'] = 1; - } - - /* - * Unfortunately, mysql_fetch_assoc() returns - * all fields as strings. We need to coerce - * numeric values into integers to provide - * proper data types in the JSON response. - */ - foreach (self::$numeric_fields as $field) { - if (isset($row[$field])) { - $row[$field] = intval($row[$field]); - } - } - - foreach (self::$decimal_fields as $field) { - if (isset($row[$field])) { - $row[$field] = floatval($row[$field]); - } - } - - if ($this->version >= 2 && ($type == 'info' || $type == 'multiinfo')) { - $extfields = $this->get_extended_fields($row['ID'], $row['PackageBaseID']); - if ($extfields) { - $row = array_merge($row, $extfields); - } - } - - if ($this->version < 3) { - if ($type == 'info') { - $search_data = $row; - break; - } else { - array_push($search_data, $row); - } - } elseif ($this->version >= 3) { - array_push($search_data, $row); - } - } - - if ($resultcount === $max_results) { - return $this->json_error('Too many package results.'); - } - - return $this->json_results($type, $resultcount, $search_data, NULL); - } else { - return $this->json_results($type, 0, array(), NULL); - } - } - - /* - * Parse the args to the multiinfo function. We may have a string or an - * array, so do the appropriate thing. Within the elements, both * package - * IDs and package names are valid; sort them into the relevant arrays and - * escape/quote the names. - * - * @param array $args Query parameters. - * - * @return mixed An array containing 'ids' and 'names'. - */ - private function parse_multiinfo_args($args) { - if (!is_array($args)) { - $args = array($args); - } - - $id_args = array(); - $name_args = array(); - foreach ($args as $arg) { - if (!$arg) { - continue; - } - if ($this->version < 5 && is_numeric($arg)) { - $id_args[] = intval($arg); - } else { - $name_args[] = $this->dbh->quote($arg); - } - } - - return array('ids' => $id_args, 'names' => $name_args); - } - - /* - * Performs a fulltext mysql search of the package database. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of package matches. - */ - private function search($http_data) { - $keyword_string = $http_data['arg']; - - if (isset($http_data['by'])) { - $search_by = $http_data['by']; - } else { - $search_by = 'name-desc'; - } - - if ($search_by === 'name' || $search_by === 'name-desc') { - if (strlen($keyword_string) < 2) { - return $this->json_error('Query arg too small.'); - } - - if ($this->version >= 6 && $search_by === 'name-desc') { - $where_condition = construct_keyword_search($this->dbh, - $keyword_string, true, false); - } else { - $keyword_string = $this->dbh->quote( - "%" . addcslashes($keyword_string, '%_') . "%"); - - if ($search_by === 'name') { - $where_condition = "(Packages.Name LIKE $keyword_string)"; - } else if ($search_by === 'name-desc') { - $where_condition = "(Packages.Name LIKE $keyword_string "; - $where_condition .= "OR Description LIKE $keyword_string)"; - } - - } - } else if ($search_by === 'maintainer') { - if (empty($keyword_string)) { - $where_condition = "Users.ID is NULL"; - } else { - $keyword_string = $this->dbh->quote($keyword_string); - $where_condition = "Users.Username = $keyword_string "; - } - } else if (in_array($search_by, self::$exposed_depfields)) { - if (empty($keyword_string)) { - return $this->json_error('Query arg is empty.'); - } else { - $keyword_string = $this->dbh->quote($keyword_string); - $search_by = $this->dbh->quote($search_by); - $subquery = "SELECT PackageDepends.DepName FROM PackageDepends "; - $subquery .= "LEFT JOIN DependencyTypes "; - $subquery .= "ON PackageDepends.DepTypeID = DependencyTypes.ID "; - $subquery .= "WHERE PackageDepends.PackageID = Packages.ID "; - $subquery .= "AND DependencyTypes.Name = $search_by"; - $where_condition = "$keyword_string IN ($subquery)"; - } - } - - return $this->process_query('search', $where_condition); - } - - /* - * Returns the info on a specific package. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of value data containing the package data - */ - private function info($http_data) { - $pqdata = $http_data['arg']; - if ($this->version < 5 && is_numeric($pqdata)) { - $where_condition = "Packages.ID = $pqdata"; - } else { - $where_condition = "Packages.Name = " . $this->dbh->quote($pqdata); - } - - return $this->process_query('info', $where_condition); - } - - /* - * Returns the info on multiple packages. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of results containing the package data - */ - private function multiinfo($http_data) { - $pqdata = $http_data['arg']; - $args = $this->parse_multiinfo_args($pqdata); - $ids = $args['ids']; - $names = $args['names']; - - if (!$ids && !$names) { - return $this->json_error('Invalid query arguments.'); - } - - $where_condition = ""; - if ($ids) { - $ids_value = implode(',', $args['ids']); - $where_condition .= "Packages.ID IN ($ids_value) "; - } - if ($ids && $names) { - $where_condition .= "OR "; - } - if ($names) { - /* - * Individual names were quoted in - * parse_multiinfo_args(). - */ - $names_value = implode(',', $args['names']); - $where_condition .= "Packages.Name IN ($names_value) "; - } - - return $this->process_query('multiinfo', $where_condition); - } - - /* - * Returns all the packages for a specific maintainer. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of value data containing the package data - */ - private function msearch($http_data) { - $http_data['by'] = 'maintainer'; - return $this->search($http_data); - } - - /* - * Get all package names that start with $search. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function suggest($http_data) { - $search = $http_data['arg']; - $query = "SELECT Packages.Name FROM Packages "; - $query.= "LEFT JOIN PackageBases "; - $query.= "ON PackageBases.ID = Packages.PackageBaseID "; - $query.= "WHERE Packages.Name LIKE "; - $query.= $this->dbh->quote(addcslashes($search, '%_') . '%'); - $query.= " AND PackageBases.PackagerUID IS NOT NULL "; - $query.= "ORDER BY Name ASC LIMIT 20"; - - $result = $this->dbh->query($query); - $result_array = array(); - - if ($result) { - $result_array = $result->fetchAll(PDO::FETCH_COLUMN, 0); - } - - return json_encode($result_array); - } - - /* - * Get all package base names that start with $search. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function suggest_pkgbase($http_data) { - $search = $http_data['arg']; - $query = "SELECT Name FROM PackageBases WHERE Name LIKE "; - $query.= $this->dbh->quote(addcslashes($search, '%_') . '%'); - $query.= " AND PackageBases.PackagerUID IS NOT NULL "; - $query.= "ORDER BY Name ASC LIMIT 20"; - - $result = $this->dbh->query($query); - $result_array = array(); - - if ($result) { - $result_array = $result->fetchAll(PDO::FETCH_COLUMN, 0); - } - - return json_encode($result_array); - } - - /** - * Get the HTML markup of the comment form. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function get_comment_form($http_data) { - if (!isset($http_data['base_id']) || !isset($http_data['pkgbase_name'])) { - $output = array( - 'success' => 0, - 'error' => __('Package base ID or package base name missing.') - ); - return json_encode($output); - } - - $comment_id = intval($http_data['arg']); - $base_id = intval($http_data['base_id']); - $pkgbase_name = $http_data['pkgbase_name']; - - list($user_id, $comment) = comment_by_id($comment_id); - - if (!has_credential(CRED_COMMENT_EDIT, array($user_id))) { - $output = array( - 'success' => 0, - 'error' => __('You are not allowed to edit this comment.') - ); - return json_encode($output); - } elseif (is_null($comment)) { - $output = array( - 'success' => 0, - 'error' => __('Comment does not exist.') - ); - return json_encode($output); - } - - ob_start(); - include('pkg_comment_form.php'); - $html = ob_get_clean(); - $output = array( - 'success' => 1, - 'form' => $html - ); - - return json_encode($output); - } -} diff --git a/web/lib/cachefuncs.inc.php b/web/lib/cachefuncs.inc.php deleted file mode 100644 index b2b96c24..00000000 --- a/web/lib/cachefuncs.inc.php +++ /dev/null @@ -1,99 +0,0 @@ -addServer($mcserver[0], intval($mcserver[1])); - } -} - -# Set a value in the cache (currently APC) if cache is available for use. If -# not available, this becomes effectively a no-op (return value is -# false). Accepts an optional TTL (defaults to 600 seconds). -function set_cache_value($key, $value, $ttl=600) { - $status = false; - if (defined('EXTENSION_LOADED_APC')) { - $status = apc_store(CACHE_PREFIX.$key, $value, $ttl); - } - if (defined('EXTENSION_LOADED_MEMCACHE')) { - global $memcache; - $status = $memcache->set(CACHE_PREFIX.$key, $value, $ttl); - } - return $status; -} - -# Get a value from the cache (currently APC) if cache is available for use. If -# not available, this returns false (optionally sets passed in variable $status -# to false, much like apc_fetch() behaves). This allows for testing the fetch -# result appropriately even in the event that a 'false' value was the value in -# the cache. -function get_cache_value($key, &$status=false) { - if(defined('EXTENSION_LOADED_APC')) { - $ret = apc_fetch(CACHE_PREFIX.$key, $status); - if ($status) { - return $ret; - } - } - if (defined('EXTENSION_LOADED_MEMCACHE')) { - global $memcache; - $ret = $memcache->get(CACHE_PREFIX.$key); - if (!$ret) { - $status = false; - } - else { - $status = true; - } - return $ret; - } - return $status; -} - -# Run a simple db query, retrieving and/or caching the value if APC is -# available for use. Accepts an optional TTL value (defaults to 600 seconds). -function db_cache_value($dbq, $key, $ttl=600) { - $dbh = DB::connect(); - $status = false; - $value = get_cache_value($key, $status); - if (!$status) { - $result = $dbh->query($dbq); - if (!$result) { - return false; - } - $row = $result->fetch(PDO::FETCH_NUM); - $value = $row[0]; - set_cache_value($key, $value, $ttl); - } - return $value; -} - -# Run a simple db query, retrieving and/or caching the result set if APC is -# available for use. Accepts an optional TTL value (defaults to 600 seconds). -function db_cache_result($dbq, $key, $fetch_style=PDO::FETCH_NUM, $ttl=600) { - $dbh = DB::connect(); - $status = false; - $value = get_cache_value($key, $status); - if (!$status) { - $result = $dbh->query($dbq); - if (!$result) { - return false; - } - $value = $result->fetchAll($fetch_style); - set_cache_value($key, $value, $ttl); - } - return $value; -} - -?> diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php deleted file mode 100644 index fdd2b78e..00000000 --- a/web/lib/confparser.inc.php +++ /dev/null @@ -1,59 +0,0 @@ -useCached(); // use cached version if age<1 hour -$rss->title = "PHP news"; -$rss->description = "daily news from the PHP scripting world"; - -//optional -$rss->descriptionTruncSize = 500; -$rss->descriptionHtmlSyndicated = true; - -$rss->link = "http://www.dailyphp.net/news"; -$rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"]; - -$image = new FeedImage(); -$image->title = "dailyphp.net logo"; -$image->url = "http://www.dailyphp.net/images/logo.gif"; -$image->link = "http://www.dailyphp.net"; -$image->description = "Feed provided by dailyphp.net. Click to visit."; - -//optional -$image->descriptionTruncSize = 500; -$image->descriptionHtmlSyndicated = true; - -$rss->image = $image; - -// get your news items from somewhere, e.g. your database: -mysql_select_db($dbHost, $dbUser, $dbPass); -$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); -while ($data = mysql_fetch_object($res)) { - $item = new FeedItem(); - $item->title = $data->title; - $item->link = $data->url; - $item->description = $data->short; - - //optional - item->descriptionTruncSize = 500; - item->descriptionHtmlSyndicated = true; - - $item->date = $data->newsdate; - $item->source = "http://www.dailyphp.net"; - $item->author = "John Doe"; - - $rss->addItem($item); -} - -// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated), -// MBOX, OPML, ATOM, ATOM0.3, HTML, JS -echo $rss->saveFeed("RSS1.0", "news/feed.xml"); - - -*************************************************************************** -* A little setup * -**************************************************************************/ - -// your local timezone, set to "" to disable or for GMT -define("TIME_ZONE","+01:00"); - - - - -/** - * Version string. - **/ -define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2"); - - - -/** - * A FeedItem is a part of a FeedCreator feed. - * - * @author Kai Blankenhorn - * @since 1.3 - */ -class FeedItem extends HtmlDescribable { - /** - * Mandatory attributes of an item. - */ - var $title, $description, $link; - - /** - * Optional attributes of an item. - */ - var $author, $authorEmail, $image, $category, $comments, $guid, $guidIsPermaLink, $source, $creator; - - /** - * Publishing date of an item. May be in one of the following formats: - * - * RFC 822: - * "Mon, 20 Jan 03 18:05:41 +0400" - * "20 Jan 03 18:05:41 +0000" - * - * ISO 8601: - * "2003-01-20T18:05:41+04:00" - * - * Unix: - * 1043082341 - */ - var $date; - - /** - * Any additional elements to include as an assiciated array. All $key => $value pairs - * will be included unencoded in the feed item in the form - * <$key>$value - * Again: No encoding will be used! This means you can invalidate or enhance the feed - * if $value contains markup. This may be abused to embed tags not implemented by - * the FeedCreator class used. - */ - var $additionalElements = Array(); - - // on hold - // var $source; -} - - - -/** - * An FeedImage may be added to a FeedCreator feed. - * @author Kai Blankenhorn - * @since 1.3 - */ -class FeedImage extends HtmlDescribable { - /** - * Mandatory attributes of an image. - */ - var $title, $url, $link; - - /** - * Optional attributes of an image. - */ - var $width, $height, $description; -} - - - -/** - * An HtmlDescribable is an item within a feed that can have a description that may - * include HTML markup. - */ -class HtmlDescribable { - /** - * Indicates whether the description field should be rendered in HTML. - */ - var $descriptionHtmlSyndicated; - - /** - * Indicates whether and to how many characters a description should be truncated. - */ - var $descriptionTruncSize; - - /** - * Returns a formatted description field, depending on descriptionHtmlSyndicated and - * $descriptionTruncSize properties - * @return string the formatted description - */ - function getDescription() { - $descriptionField = new FeedHtmlField($this->description); - $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated; - $descriptionField->truncSize = $this->descriptionTruncSize; - return $descriptionField->output(); - } - -} - - -/** - * An FeedHtmlField describes and generates - * a feed, item or image html field (probably a description). Output is - * generated based on $truncSize, $syndicateHtml properties. - * @author Pascal Van Hecke - * @version 1.6 - */ -class FeedHtmlField { - /** - * Mandatory attributes of a FeedHtmlField. - */ - var $rawFieldContent; - - /** - * Optional attributes of a FeedHtmlField. - * - */ - var $truncSize, $syndicateHtml; - - /** - * Creates a new instance of FeedHtmlField. - * @param $string: if given, sets the rawFieldContent property - */ - function FeedHtmlField($parFieldContent) { - if ($parFieldContent) { - $this->rawFieldContent = $parFieldContent; - } - } - - - /** - * Creates the right output, depending on $truncSize, $syndicateHtml properties. - * @return string the formatted field - */ - function output() { - // when field available and syndicated in html we assume - // - valid html in $rawFieldContent and we enclose in CDATA tags - // - no truncation (truncating risks producing invalid html) - if (!$this->rawFieldContent) { - $result = ""; - } elseif ($this->syndicateHtml) { - $result = "rawFieldContent."]]>"; - } else { - if ($this->truncSize and is_int($this->truncSize)) { - $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize); - } else { - $result = htmlspecialchars($this->rawFieldContent); - } - } - return $result; - } - -} - - - -/** - * UniversalFeedCreator lets you choose during runtime which - * format to build. - * For general usage of a feed class, see the FeedCreator class - * below or the example above. - * - * @since 1.3 - * @author Kai Blankenhorn - */ -class UniversalFeedCreator extends FeedCreator { - var $_feed; - - function _setFormat($format) { - switch (strtoupper($format)) { - - case "2.0": - // fall through - case "RSS2.0": - $this->_feed = new RSSCreator20(); - break; - - case "1.0": - // fall through - case "RSS1.0": - $this->_feed = new RSSCreator10(); - break; - - case "0.91": - // fall through - case "RSS0.91": - $this->_feed = new RSSCreator091(); - break; - - case "PIE0.1": - $this->_feed = new PIECreator01(); - break; - - case "MBOX": - $this->_feed = new MBOXCreator(); - break; - - case "OPML": - $this->_feed = new OPMLCreator(); - break; - - case "ATOM": - // fall through: always the latest ATOM version - - case "ATOM0.3": - $this->_feed = new AtomCreator03(); - break; - - case "HTML": - $this->_feed = new HTMLCreator(); - break; - - case "JS": - // fall through - case "JAVASCRIPT": - $this->_feed = new JSCreator(); - break; - - default: - $this->_feed = new RSSCreator091(); - break; - } - - $vars = get_object_vars($this); - foreach ($vars as $key => $value) { - // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself - if (!in_array($key, array("_feed", "contentType", "encoding"))) { - $this->_feed->{$key} = $this->{$key}; - } - } - } - - /** - * Creates a syndication feed based on the items previously added. - * - * @see FeedCreator::addItem() - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS" - * @return string the contents of the feed. - */ - function createFeed($format = "RSS0.91") { - $this->_setFormat($format); - return $this->_feed->createFeed(); - } - - - - /** - * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect - * header may be sent to redirect the use to the newly created file. - * @since 1.4 - * - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS" - * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param boolean displayContents optional send the content of the file or not. If true, the file will be sent in the body of the response. - */ - function saveFeed($format="RSS0.91", $filename="", $displayContents=true) { - $this->_setFormat($format); - $this->_feed->saveFeed($filename, $displayContents); - } - - - /** - * Turns on caching and checks if there is a recent version of this feed in the cache. - * If there is, an HTTP redirect header is sent. - * To effectively use caching, you should create the FeedCreator object and call this method - * before anything else, especially before you do the time consuming task to build the feed - * (web fetching, for example). - * - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3". - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) - */ - function useCached($format="RSS0.91", $filename="", $timeout=3600) { - $this->_setFormat($format); - $this->_feed->useCached($filename, $timeout); - } - -} - - -/** - * FeedCreator is the abstract base implementation for concrete - * implementations that implement a specific format of syndication. - * - * @abstract - * @author Kai Blankenhorn - * @since 1.4 - */ -class FeedCreator extends HtmlDescribable { - - /** - * Mandatory attributes of a feed. - */ - var $title, $description, $link; - - - /** - * Optional attributes of a feed. - */ - var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays; - - /** - * The url of the external xsl stylesheet used to format the naked rss feed. - * Ignored in the output when empty. - */ - var $xslStyleSheet = ""; - - - /** - * @access private - */ - var $items = Array(); - - - /** - * This feed's MIME content type. - * @since 1.4 - * @access private - */ - var $contentType = "application/xml"; - - - /** - * This feed's character encoding. - * @since 1.6.1 - **/ - var $encoding = "ISO-8859-1"; - - - /** - * Any additional elements to include as an assiciated array. All $key => $value pairs - * will be included unencoded in the feed in the form - * <$key>$value - * Again: No encoding will be used! This means you can invalidate or enhance the feed - * if $value contains markup. This may be abused to embed tags not implemented by - * the FeedCreator class used. - */ - var $additionalElements = Array(); - - - /** - * Adds an FeedItem to the feed. - * - * @param object FeedItem $item The FeedItem to add to the feed. - * @access public - */ - function addItem($item) { - $this->items[] = $item; - } - - - /** - * Truncates a string to a certain length at the most sensible point. - * First, if there's a '.' character near the end of the string, the string is truncated after this character. - * If there is no '.', the string is truncated after the last ' ' character. - * If the string is truncated, " ..." is appended. - * If the string is already shorter than $length, it is returned unchanged. - * - * @static - * @param string string A string to be truncated. - * @param int length the maximum length the string should be truncated to - * @return string the truncated string - */ - function iTrunc($string, $length) { - if (strlen($string)<=$length) { - return $string; - } - - $pos = strrpos($string,"."); - if ($pos>=$length-4) { - $string = substr($string,0,$length-4); - $pos = strrpos($string,"."); - } - if ($pos>=$length*0.4) { - return substr($string,0,$pos+1)." ..."; - } - - $pos = strrpos($string," "); - if ($pos>=$length-4) { - $string = substr($string,0,$length-4); - $pos = strrpos($string," "); - } - if ($pos>=$length*0.4) { - return substr($string,0,$pos)." ..."; - } - - return substr($string,0,$length-4)." ..."; - - } - - - /** - * Creates a comment indicating the generator of this feed. - * The format of this comment seems to be recognized by - * Syndic8.com. - */ - function _createGeneratorComment() { - return "\n"; - } - - - /** - * Creates a string containing all additional elements specified in - * $additionalElements. - * @param elements array an associative array containing key => value pairs - * @param indentString string a string that will be inserted before every generated line - * @return string the XML tags corresponding to $additionalElements - */ - function _createAdditionalElements($elements, $indentString="") { - $ae = ""; - if (is_array($elements)) { - foreach($elements AS $key => $value) { - $ae.= $indentString."<$key>$value\n"; - } - } - return $ae; - } - - function _createStylesheetReferences() { - $xml = ""; - if ($this->cssStyleSheet) $xml .= "cssStyleSheet."\" type=\"text/css\"?>\n"; - if ($this->xslStyleSheet) $xml .= "xslStyleSheet."\" type=\"text/xsl\"?>\n"; - return $xml; - } - - - /** - * Builds the feed's text. - * @abstract - * @return string the feed's complete text - */ - function createFeed() { - } - - /** - * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml. - * For example: - * - * echo $_SERVER["PHP_SELF"]."\n"; - * echo FeedCreator::_generateFilename(); - * - * would produce: - * - * /rss/latestnews.php - * latestnews.xml - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml"; - } - - - /** - * @since 1.4 - * @access private - */ - function _redirect($filename) { - // attention, heavily-commented-out-area - - // maybe use this in addition to file time checking - //Header("Expires: ".date("r",time()+$this->_timeout)); - - /* no caching at all, doesn't seem to work as good: - Header("Cache-Control: no-cache"); - Header("Pragma: no-cache"); - */ - - // HTTP redirect, some feed readers' simple HTTP implementations don't follow it - //Header("Location: ".$filename); - - Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); - Header("Content-Disposition: inline; filename=".basename($filename)); - readfile($filename, "r"); - die(); - } - - /** - * Turns on caching and checks if there is a recent version of this feed in the cache. - * If there is, an HTTP redirect header is sent. - * To effectively use caching, you should create the FeedCreator object and call this method - * before anything else, especially before you do the time consuming task to build the feed - * (web fetching, for example). - * @since 1.4 - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) - */ - function useCached($filename="", $timeout=3600) { - $this->_timeout = $timeout; - if ($filename=="") { - $filename = $this->_generateFilename(); - } - if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) { - $this->_redirect($filename); - } - } - - - /** - * Saves this feed as a file on the local disk. After the file is saved, a redirect - * header may be sent to redirect the user to the newly created file. - * @since 1.4 - * - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param redirect boolean optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file. - */ - function saveFeed($filename="", $displayContents=true) { - if ($filename=="") { - $filename = $this->_generateFilename(); - } - $feedFile = fopen($filename, "w+"); - if ($feedFile) { - fputs($feedFile,$this->createFeed()); - fclose($feedFile); - if ($displayContents) { - $this->_redirect($filename); - } - } else { - echo "
    Error creating feed file, please check write permissions.
    "; - } - } - -} - - -/** - * FeedDate is an internal class that stores a date for a feed or feed item. - * Usually, you won't need to use this. - */ -class FeedDate { - var $unix; - - /** - * Creates a new instance of FeedDate representing a given date. - * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps. - * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used. - */ - function FeedDate($dateString="") { - if ($dateString=="") $dateString = date("r"); - - if (is_integer($dateString)) { - $this->unix = $dateString; - return; - } - if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) { - $months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12); - $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]); - if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { - $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; - } else { - if (strlen($matches[7])==1) { - $oneHour = 3600; - $ord = ord($matches[7]); - if ($ord < ord("M")) { - $tzOffset = (ord("A") - $ord - 1) * $oneHour; - } elseif ($ord >= ord("M") AND $matches[7]!="Z") { - $tzOffset = ($ord - ord("M")) * $oneHour; - } elseif ($matches[7]=="Z") { - $tzOffset = 0; - } - } - switch ($matches[7]) { - case "UT": - case "GMT": $tzOffset = 0; - } - } - $this->unix += $tzOffset; - return; - } - if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) { - $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]); - if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { - $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; - } else { - if ($matches[7]=="Z") { - $tzOffset = 0; - } - } - $this->unix += $tzOffset; - return; - } - $this->unix = 0; - } - - /** - * Gets the date stored in this FeedDate as an RFC 822 date. - * - * @return a date in RFC 822 format - */ - function rfc822() { - //return gmdate("r",$this->unix); - $date = gmdate("D, d M Y H:i:s", $this->unix); - if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE); - return $date; - } - - /** - * Gets the date stored in this FeedDate as an ISO 8601 date. - * - * @return a date in ISO 8601 format - */ - function iso8601() { - $date = gmdate("Y-m-d\TH:i:sO",$this->unix); - $date = substr($date,0,22) . ':' . substr($date,-2); - if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date); - return $date; - } - - /** - * Gets the date stored in this FeedDate as unix time stamp. - * - * @return a date as a unix time stamp - */ - function unix() { - return $this->unix; - } -} - - -/** - * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0. - * - * @see http://www.purl.org/rss/1.0/ - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator10 extends FeedCreator { - - /** - * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. - * The feed will contain all items previously added in the same order. - * @return string the feed's complete text - */ - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - if ($this->cssStyleSheet=="") { - $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css"; - } - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " syndicationURL."\">\n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - $feed.= " ".htmlspecialchars($this->description)."\n"; - $feed.= " ".$this->link."\n"; - if ($this->image!=null) { - $feed.= " image->url."\" />\n"; - } - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->iso8601())."\n"; - $feed.= " \n"; - $feed.= " \n"; - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->link)."\"/>\n"; - } - $feed.= " \n"; - $feed.= " \n"; - $feed.= " \n"; - if ($this->image!=null) { - $feed.= " image->url."\">\n"; - $feed.= " ".$this->image->title."\n"; - $feed.= " ".$this->image->link."\n"; - $feed.= " ".$this->image->url."\n"; - $feed.= " \n"; - } - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->link)."\">\n"; - //$feed.= " Posting\n"; - $feed.= " text/html\n"; - if ($this->items[$i]->date!=null) { - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - } - if ($this->items[$i]->source!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; - } - if ($this->items[$i]->author!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - } - $feed.= " ".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - $feed.= " \n"; - } - $feed.= "\n"; - return $feed; - } -} - - - -/** - * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3. - * - * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator091 extends FeedCreator { - - /** - * Stores this RSS feed's version number. - * @access private - */ - var $RSSVersion; - - function RSSCreator091() { - $this->_setRSSVersion("0.91"); - $this->contentType = "application/rss+xml"; - } - - /** - * Sets this RSS feed's version number. - * @access private - */ - function _setRSSVersion($version) { - $this->RSSVersion = $version; - } - - /** - * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. - * The feed will contain all items previously added in the same order. - * @return string the feed's complete text - */ - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "RSSVersion."\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"; - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; - $this->descriptionTruncSize = 500; - $feed.= " ".$this->getDescription()."\n"; - $feed.= " ".$this->link."\n"; - $feed.= " syndicationURL."\" rel=\"self\" type=\"application/rss+xml\" />\n"; - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->rfc822())."\n"; - $feed.= " ".FEEDCREATOR_VERSION."\n"; - - if ($this->image!=null) { - $feed.= " \n"; - $feed.= " ".$this->image->url."\n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."\n"; - $feed.= " ".$this->image->link."\n"; - if ($this->image->width!="") { - $feed.= " ".$this->image->width."\n"; - } - if ($this->image->height!="") { - $feed.= " ".$this->image->height."\n"; - } - if ($this->image->description!="") { - $feed.= " ".$this->image->getDescription()."\n"; - } - $feed.= " \n"; - } - if ($this->language!="") { - $feed.= " ".$this->language."\n"; - } - if ($this->copyright!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."\n"; - } - if ($this->editor!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."\n"; - } - if ($this->webmaster!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."\n"; - } - if ($this->pubDate!="") { - $pubDate = new FeedDate($this->pubDate); - $feed.= " ".htmlspecialchars($pubDate->rfc822())."\n"; - } - if ($this->category!="") { - $feed.= " ".htmlspecialchars($this->category)."\n"; - } - if ($this->docs!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."\n"; - } - if ($this->ttl!="") { - $feed.= " ".htmlspecialchars($this->ttl)."\n"; - } - if ($this->rating!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."\n"; - } - if ($this->skipHours!="") { - $feed.= " ".htmlspecialchars($this->skipHours)."\n"; - } - if ($this->skipDays!="") { - $feed.= " ".htmlspecialchars($this->skipDays)."\n"; - } - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= " ".$this->items[$i]->getDescription()."\n"; - - if ($this->items[$i]->author!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - } - /* - // on hold - if ($this->items[$i]->source!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; - } - */ - if ($this->items[$i]->category!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->category)."\n"; - } - if ($this->items[$i]->comments!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->comments)."\n"; - } - if ($this->items[$i]->date!="") { - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->rfc822())."\n"; - } - if ($this->items[$i]->guid!="") { - $feed.= " items[$i]->guidIsPermaLink == false) { - $feed.= " isPermaLink=\"false\""; - } - $feed.= ">".htmlspecialchars($this->items[$i]->guid)."\n"; - } - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - $feed.= " \n"; - } - $feed.= " \n"; - $feed.= "\n"; - return $feed; - } -} - - - -/** - * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0. - * - * @see http://backend.userland.com/rss - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator20 extends RSSCreator091 { - - function RSSCreator20() { - parent::_setRSSVersion("2.0"); - } - -} - - -/** - * PIECreator01 is a FeedCreator that implements the emerging PIE specification, - * as in http://intertwingly.net/wiki/pie/Syntax. - * - * @deprecated - * @since 1.3 - * @author Scott Reynen and Kai Blankenhorn - */ -class PIECreator01 extends FeedCreator { - - function PIECreator01() { - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; - $this->truncSize = 500; - $feed.= " ".$this->getDescription()."\n"; - $feed.= " ".$this->link."\n"; - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; - if ($this->items[$i]->author!="") { - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - if ($this->items[$i]->authorEmail!="") { - $feed.= " ".$this->items[$i]->authorEmail."\n"; - } - $feed.=" \n"; - } - $feed.= " \n"; - $feed.= "
    ".$this->items[$i]->getDescription()."
    \n"; - $feed.= "
    \n"; - $feed.= "
    \n"; - } - $feed.= "
    \n"; - return $feed; - } -} - - -/** - * AtomCreator03 is a FeedCreator that implements the atom specification, - * as in http://www.intertwingly.net/wiki/pie/FrontPage. - * Please note that just by using AtomCreator03 you won't automatically - * produce valid atom files. For example, you have to specify either an editor - * for the feed or an author for every single feed item. - * - * Some elements have not been implemented yet. These are (incomplete list): - * author URL, item author's email and URL, item contents, alternate links, - * other link content types than text/html. Some of them may be created with - * AtomCreator03::additionalElements. - * - * @see FeedCreator#additionalElements - * @since 1.6 - * @author Kai Blankenhorn , Scott Reynen - */ -class AtomCreator03 extends FeedCreator { - - function AtomCreator03() { - $this->contentType = "application/atom+xml"; - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "language!="") { - $feed.= " xml:lang=\"".$this->language."\""; - } - $feed.= ">\n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - $feed.= " ".htmlspecialchars($this->description)."\n"; - $feed.= " link)."\"/>\n"; - $feed.= " ".htmlspecialchars($this->link)."\n"; - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->iso8601())."\n"; - if ($this->editor!="") { - $feed.= " \n"; - $feed.= " ".$this->editor."\n"; - if ($this->editorEmail!="") { - $feed.= " ".$this->editorEmail."\n"; - } - $feed.= " \n"; - } - $feed.= " ".FEEDCREATOR_VERSION."\n"; - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".htmlspecialchars(strip_tags($this->items[$i]->title))."\n"; - $feed.= " items[$i]->link)."\"/>\n"; - if ($this->items[$i]->date=="") { - $this->items[$i]->date = time(); - } - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - if ($this->items[$i]->author!="") { - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - $feed.= " \n"; - } - if ($this->items[$i]->description!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; - } - $feed.= " \n"; - } - $feed.= "\n"; - return $feed; - } -} - - -/** - * MBOXCreator is a FeedCreator that implements the mbox format - * as described in http://www.qmail.org/man/man5/mbox.html - * - * @since 1.3 - * @author Kai Blankenhorn - */ -class MBOXCreator extends FeedCreator { - - function MBOXCreator() { - $this->contentType = "text/plain"; - $this->encoding = "ISO-8859-15"; - } - - function qp_enc($input = "", $line_max = 76) { - $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); - $lines = preg_split("/(?:\r\n|\r|\n)/", $input); - $eol = "\r\n"; - $escape = "="; - $output = ""; - while( list(, $line) = each($lines) ) { - //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary - $linlen = strlen($line); - $newline = ""; - for($i = 0; $i < $linlen; $i++) { - $c = substr($line, $i, 1); - $dec = ord($c); - if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only - $c = "=20"; - } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required - $h2 = floor($dec/16); $h1 = floor($dec%16); - $c = $escape.$hex["$h2"].$hex["$h1"]; - } - if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted - $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay - $newline = ""; - } - $newline .= $c; - } // end of for - $output .= $newline.$eol; - } - return trim($output); - } - - - /** - * Builds the MBOX contents. - * @return string the feed's complete text - */ - function createFeed() { - for ($i=0;$iitems);$i++) { - if ($this->items[$i]->author!="") { - $from = $this->items[$i]->author; - } else { - $from = $this->title; - } - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n"; - $feed.= "Content-Type: text/plain;\n"; - $feed.= " charset=\"".$this->encoding."\"\n"; - $feed.= "Content-Transfer-Encoding: quoted-printable\n"; - $feed.= "Content-Type: text/plain\n"; - $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n"; - $feed.= "Date: ".$itemDate->rfc822()."\n"; - $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n"; - $feed.= "\n"; - $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description)); - $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body); - $feed.= "\n"; - $feed.= "\n"; - } - return $feed; - } - - /** - * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types. - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox"; - } -} - - -/** - * OPMLCreator is a FeedCreator that implements OPML 1.0. - * - * @see http://opml.scripting.com/spec - * @author Dirk Clemens, Kai Blankenhorn - * @since 1.5 - */ -class OPMLCreator extends FeedCreator { - - function OPMLCreator() { - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - if ($this->pubDate!="") { - $date = new FeedDate($this->pubDate); - $feed.= " ".$date->rfc822()."\n"; - } - if ($this->lastBuildDate!="") { - $date = new FeedDate($this->lastBuildDate); - $feed.= " ".$date->rfc822()."\n"; - } - if ($this->editor!="") { - $feed.= " ".$this->editor."\n"; - } - if ($this->editorEmail!="") { - $feed.= " ".$this->editorEmail."\n"; - } - $feed.= " \n"; - $feed.= " \n"; - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->title,"\n\r"," "))); - $feed.= " title=\"".$title."\""; - $feed.= " text=\"".$title."\""; - //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\""; - $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\""; - $feed.= "/>\n"; - } - $feed.= " \n"; - $feed.= "\n"; - return $feed; - } -} - - - -/** - * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific - * location, overriding the createFeed method of the parent FeedCreator. - * The HTML produced can be included over http by scripting languages, or serve - * as the source for an IFrame. - * All output by this class is embedded in
    tags to enable formatting - * using CSS. - * - * @author Pascal Van Hecke - * @since 1.7 - */ -class HTMLCreator extends FeedCreator { - - var $contentType = "text/html"; - - /** - * Contains HTML to be output at the start of the feed's html representation. - */ - var $header; - - /** - * Contains HTML to be output at the end of the feed's html representation. - */ - var $footer ; - - /** - * Contains HTML to be output between entries. A separator is only used in - * case of multiple entries. - */ - var $separator; - - /** - * Used to prefix the stylenames to make sure they are unique - * and do not clash with stylenames on the users' page. - */ - var $stylePrefix; - - /** - * Determines whether the links open in a new window or not. - */ - var $openInNewWindow = true; - - var $imageAlign ="right"; - - /** - * In case of very simple output you may want to get rid of the style tags, - * hence this variable. There's no equivalent on item level, but of course you can - * add strings to it while iterating over the items ($this->stylelessOutput .= ...) - * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored - * in the function createFeed(). - */ - var $stylelessOutput =""; - - /** - * Writes the HTML. - * @return string the scripts's complete text - */ - function createFeed() { - // if there is styleless output, use the content of this variable and ignore the rest - if ($this->stylelessOutput!="") { - return $this->stylelessOutput; - } - - //if no stylePrefix is set, generate it yourself depending on the script name - if ($this->stylePrefix=="") { - $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_"; - } - - //set an openInNewWindow_token_to be inserted or not - if ($this->openInNewWindow) { - $targetInsert = " target='_blank'"; - } - - // use this array to put the lines in and implode later with "document.write" javascript - $feedArray = array(); - if ($this->image!=null) { - $imageStr = "". - "".
-							FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
-							"image->width) { - $imageStr .=" width='".$this->image->width. "' "; - } - if ($this->image->height) { - $imageStr .=" height='".$this->image->height."' "; - } - $imageStr .="/>"; - $feedArray[] = $imageStr; - } - - if ($this->title) { - $feedArray[] = ""; - } - if ($this->getDescription()) { - $feedArray[] = "
    ". - str_replace("]]>", "", str_replace("getDescription())). - "
    "; - } - - if ($this->header) { - $feedArray[] = "
    ".$this->header."
    "; - } - - for ($i=0;$iitems);$i++) { - if ($this->separator and $i > 0) { - $feedArray[] = "
    ".$this->separator."
    "; - } - - if ($this->items[$i]->title) { - if ($this->items[$i]->link) { - $feedArray[] = - ""; - } else { - $feedArray[] = - "
    ". - FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100). - "
    "; - } - } - if ($this->items[$i]->getDescription()) { - $feedArray[] = - "
    ". - str_replace("]]>", "", str_replace("items[$i]->getDescription())). - "
    "; - } - } - if ($this->footer) { - $feedArray[] = "
    ".$this->footer."
    "; - } - - $feed= "".join($feedArray, "\r\n"); - return $feed; - } - - /** - * Overrrides parent to produce .html extensions - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html"; - } -} - - -/** - * JSCreator is a class that writes a js file to a specific - * location, overriding the createFeed method of the parent HTMLCreator. - * - * @author Pascal Van Hecke - */ -class JSCreator extends HTMLCreator { - var $contentType = "text/javascript"; - - /** - * writes the javascript - * @return string the scripts's complete text - */ - function createFeed() - { - $feed = parent::createFeed(); - $feedArray = explode("\n",$feed); - - $jsFeed = ""; - foreach ($feedArray as $value) { - $jsFeed .= "document.write('".trim(addslashes($value))."');\n"; - } - return $jsFeed; - } - - /** - * Overrrides parent to produce .js extensions - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js"; - } - -} - - - -/*** TEST SCRIPT ********************************************************* - -//include("feedcreator.class.php"); - -$rss = new UniversalFeedCreator(); -$rss->useCached(); -$rss->title = "PHP news"; -$rss->description = "daily news from the PHP scripting world"; - -//optional -//$rss->descriptionTruncSize = 500; -//$rss->descriptionHtmlSyndicated = true; -//$rss->xslStyleSheet = "http://feedster.com/rss20.xsl"; - -$rss->link = "http://www.dailyphp.net/news"; -$rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF; - -$image = new FeedImage(); -$image->title = "dailyphp.net logo"; -$image->url = "http://www.dailyphp.net/images/logo.gif"; -$image->link = "http://www.dailyphp.net"; -$image->description = "Feed provided by dailyphp.net. Click to visit."; - -//optional -$image->descriptionTruncSize = 500; -$image->descriptionHtmlSyndicated = true; - -$rss->image = $image; - -// get your news items from somewhere, e.g. your database: -//mysql_select_db($dbHost, $dbUser, $dbPass); -//$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); -//while ($data = mysql_fetch_object($res)) { - $item = new FeedItem(); - $item->title = "This is an the test title of an item"; - $item->link = "http://localhost/item/"; - $item->description = "description in
    HTML"; - - //optional - //item->descriptionTruncSize = 500; - $item->descriptionHtmlSyndicated = true; - - $item->date = time(); - $item->source = "http://www.dailyphp.net"; - $item->author = "John Doe"; - - $rss->addItem($item); -//} - -// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS -echo $rss->saveFeed("RSS0.91", "feed.xml"); - - - -***************************************************************************/ - -?> diff --git a/web/lib/gettext.php b/web/lib/gettext.php deleted file mode 100644 index 098f0e5e..00000000 --- a/web/lib/gettext.php +++ /dev/null @@ -1,432 +0,0 @@ -. - Copyright (c) 2005 Nico Kaiser - - This file is part of PHP-gettext. - - PHP-gettext is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PHP-gettext 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PHP-gettext; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/** - * Provides a simple gettext replacement that works independently from - * the system's gettext abilities. - * It can read MO files and use them for translating strings. - * The files are passed to gettext_reader as a Stream (see streams.php) - * - * This version has the ability to cache all strings and translations to - * speed up the string lookup. - * While the cache is enabled by default, it can be switched off with the - * second parameter in the constructor (e.g. whenusing very large MO files - * that you don't want to keep in memory) - */ -class gettext_reader { - //public: - var $error = 0; // public variable that holds error code (0 if no error) - - //private: - var $BYTEORDER = 0; // 0: low endian, 1: big endian - var $STREAM = NULL; - var $short_circuit = false; - var $enable_cache = false; - var $originals = NULL; // offset of original table - var $translations = NULL; // offset of translation table - var $pluralheader = NULL; // cache header field for plural forms - var $total = 0; // total string count - var $table_originals = NULL; // table for original strings (offsets) - var $table_translations = NULL; // table for translated strings (offsets) - var $cache_translations = NULL; // original -> translation mapping - - - /* Methods */ - - - /** - * Reads a 32bit Integer from the Stream - * - * @access private - * @return Integer from the Stream - */ - function readint() { - if ($this->BYTEORDER == 0) { - // low endian - $input=unpack('V', $this->STREAM->read(4)); - return array_shift($input); - } else { - // big endian - $input=unpack('N', $this->STREAM->read(4)); - return array_shift($input); - } - } - - function read($bytes) { - return $this->STREAM->read($bytes); - } - - /** - * Reads an array of Integers from the Stream - * - * @param int count How many elements should be read - * @return Array of Integers - */ - function readintarray($count) { - if ($this->BYTEORDER == 0) { - // low endian - return unpack('V'.$count, $this->STREAM->read(4 * $count)); - } else { - // big endian - return unpack('N'.$count, $this->STREAM->read(4 * $count)); - } - } - - /** - * Constructor - * - * @param object Reader the StreamReader object - * @param boolean enable_cache Enable or disable caching of strings (default on) - */ - function __construct($Reader, $enable_cache = true) { - // If there isn't a StreamReader, turn on short circuit mode. - if (! $Reader || isset($Reader->error) ) { - $this->short_circuit = true; - return; - } - - // Caching can be turned off - $this->enable_cache = $enable_cache; - - $MAGIC1 = "\x95\x04\x12\xde"; - $MAGIC2 = "\xde\x12\x04\x95"; - - $this->STREAM = $Reader; - $magic = $this->read(4); - if ($magic == $MAGIC1) { - $this->BYTEORDER = 1; - } elseif ($magic == $MAGIC2) { - $this->BYTEORDER = 0; - } else { - $this->error = 1; // not MO file - return false; - } - - // FIXME: Do we care about revision? We should. - $revision = $this->readint(); - - $this->total = $this->readint(); - $this->originals = $this->readint(); - $this->translations = $this->readint(); - } - - /** - * Loads the translation tables from the MO file into the cache - * If caching is enabled, also loads all strings into a cache - * to speed up translation lookups - * - * @access private - */ - function load_tables() { - if (is_array($this->cache_translations) && - is_array($this->table_originals) && - is_array($this->table_translations)) - return; - - /* get original and translations tables */ - if (!is_array($this->table_originals)) { - $this->STREAM->seekto($this->originals); - $this->table_originals = $this->readintarray($this->total * 2); - } - if (!is_array($this->table_translations)) { - $this->STREAM->seekto($this->translations); - $this->table_translations = $this->readintarray($this->total * 2); - } - - if ($this->enable_cache) { - $this->cache_translations = array (); - /* read all strings in the cache */ - for ($i = 0; $i < $this->total; $i++) { - $this->STREAM->seekto($this->table_originals[$i * 2 + 2]); - $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]); - $this->STREAM->seekto($this->table_translations[$i * 2 + 2]); - $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]); - $this->cache_translations[$original] = $translation; - } - } - } - - /** - * Returns a string from the "originals" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_original_string($num) { - $length = $this->table_originals[$num * 2 + 1]; - $offset = $this->table_originals[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Returns a string from the "translations" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_translation_string($num) { - $length = $this->table_translations[$num * 2 + 1]; - $offset = $this->table_translations[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Binary search for string - * - * @access private - * @param string string - * @param int start (internally used in recursive function) - * @param int end (internally used in recursive function) - * @return int string number (offset in originals table) - */ - function find_string($string, $start = -1, $end = -1) { - if (($start == -1) or ($end == -1)) { - // find_string is called with only one parameter, set start end end - $start = 0; - $end = $this->total; - } - if (abs($start - $end) <= 1) { - // We're done, now we either found the string, or it doesn't exist - $txt = $this->get_original_string($start); - if ($string == $txt) - return $start; - else - return -1; - } else if ($start > $end) { - // start > end -> turn around and start over - return $this->find_string($string, $end, $start); - } else { - // Divide table in two parts - $half = (int)(($start + $end) / 2); - $cmp = strcmp($string, $this->get_original_string($half)); - if ($cmp == 0) - // string is exactly in the middle => return it - return $half; - else if ($cmp < 0) - // The string is in the upper half - return $this->find_string($string, $start, $half); - else - // The string is in the lower half - return $this->find_string($string, $half, $end); - } - } - - /** - * Translates a string - * - * @access public - * @param string string to be translated - * @return string translated string (or original, if not found) - */ - function translate($string) { - if ($this->short_circuit) - return $string; - $this->load_tables(); - - if ($this->enable_cache) { - // Caching enabled, get translated string from cache - if (array_key_exists($string, $this->cache_translations)) - return $this->cache_translations[$string]; - else - return $string; - } else { - // Caching not enabled, try to find string - $num = $this->find_string($string); - if ($num == -1) - return $string; - else - return $this->get_translation_string($num); - } - } - - /** - * Sanitize plural form expression for use in PHP eval call. - * - * @access private - * @return string sanitized plural form expression - */ - function sanitize_plural_expression($expr) { - // Get rid of disallowed characters. - $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); - - // Add parenthesis for tertiary '?' operator. - $expr .= ';'; - $res = ''; - $p = 0; - for ($i = 0; $i < strlen($expr); $i++) { - $ch = $expr[$i]; - switch ($ch) { - case '?': - $res .= ' ? ('; - $p++; - break; - case ':': - $res .= ') : ('; - break; - case ';': - $res .= str_repeat( ')', $p) . ';'; - $p = 0; - break; - default: - $res .= $ch; - } - } - return $res; - } - - /** - * Parse full PO header and extract only plural forms line. - * - * @access private - * @return string verbatim plural form header field - */ - function extract_plural_forms_header_from_po_header($header) { - if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) - $expr = $regs[2]; - else - $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; - return $expr; - } - - /** - * Get possible plural forms from MO header - * - * @access private - * @return string plural form header - */ - function get_plural_forms() { - // lets assume message number 0 is header - // this is true, right? - $this->load_tables(); - - // cache header field for plural forms - if (! is_string($this->pluralheader)) { - if ($this->enable_cache) { - $header = $this->cache_translations[""]; - } else { - $header = $this->get_translation_string(0); - } - $expr = $this->extract_plural_forms_header_from_po_header($header); - $this->pluralheader = $this->sanitize_plural_expression($expr); - } - return $this->pluralheader; - } - - /** - * Detects which plural form to take - * - * @access private - * @param n count - * @return int array index of the right plural form - */ - function select_string($n) { - $string = $this->get_plural_forms(); - $string = str_replace('nplurals',"\$total",$string); - $string = str_replace("n",$n,$string); - $string = str_replace('plural',"\$plural",$string); - - $total = 0; - $plural = 0; - - eval("$string"); - if ($plural >= $total) $plural = $total - 1; - return $plural; - } - - /** - * Plural version of gettext - * - * @access public - * @param string single - * @param string plural - * @param string number - * @return translated plural form - */ - function ngettext($single, $plural, $number) { - if ($this->short_circuit) { - if ($number != 1) - return $plural; - else - return $single; - } - - // find out the appropriate form - $select = $this->select_string($number); - - // this should contains all strings separated by NULLs - $key = $single . chr(0) . $plural; - - - if ($this->enable_cache) { - if (! array_key_exists($key, $this->cache_translations)) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->cache_translations[$key]; - $list = explode(chr(0), $result); - return $list[$select]; - } - } else { - $num = $this->find_string($key); - if ($num == -1) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->get_translation_string($num); - $list = explode(chr(0), $result); - return $list[$select]; - } - } - } - - function pgettext($context, $msgid) { - $key = $context . chr(4) . $msgid; - $ret = $this->translate($key); - if (strpos($ret, "\004") !== false) { - return $msgid; - } else { - return $ret; - } - } - - function npgettext($context, $singular, $plural, $number) { - $key = $context . chr(4) . $singular; - $ret = $this->ngettext($key, $plural, $number); - if (strpos($ret, "\004") !== false) { - return $singular; - } else { - return $ret; - } - - } -} - -?> diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php deleted file mode 100644 index a053962e..00000000 --- a/web/lib/pkgbasefuncs.inc.php +++ /dev/null @@ -1,1253 +0,0 @@ -query($q); - if (!$result) { - return null; - } - - return $result->fetchColumn(0); -} - -/** - * Get all package comment information for a specific package base - * - * @param int $base_id The package base ID to get comments for - * @param int $limit Maximum number of comments to return (0 means unlimited) - * @param bool $include_deleted True if deleted comments should be included - * @param bool $only_pinned True when only pinned comments are to be included - * - * @return array All package comment information for a specific package base - */ -function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false, $offset=0) { - $base_id = intval($base_id); - $limit = intval($limit); - if (!$base_id) { - return null; - } - - $dbh = DB::connect(); - $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; - $q.= "PackageBaseID, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName, RenderedComment, "; - $q.= "PinnedTS FROM PackageComments "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; - $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; - $q.= "WHERE PackageBaseID = " . $base_id . " "; - - if (!$include_deleted) { - $q.= "AND DelTS IS NULL "; - } - if ($only_pinned) { - $q.= "AND NOT PinnedTS = 0 "; - } - $q.= "ORDER BY CommentTS DESC"; - if ($limit > 0) { - $q.=" LIMIT " . $limit; - } - if ($offset > 0) { - $q.=" OFFSET " . $offset; - } - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return $result->fetchAll(); -} - -/* - * Invoke the comment rendering script. - * - * @param int $id ID of the comment to render - * - * @return void - */ -function render_comment($id) { - $cmd = config_get('options', 'render-comment-cmd'); - $cmd .= ' ' . intval($id); - - $descspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); - - $p = proc_open($cmd, $descspec, $pipes); - - if (!is_resource($p)) { - return false; - } - - fclose($pipes[0]); - fclose($pipes[1]); - - return proc_close($p); -} - -/** - * Add a comment to a package page and send out appropriate notifications - * - * @param string $base_id The package base ID to add the comment on - * @param string $uid The user ID of the individual who left the comment - * @param string $comment The comment left on a package page - * - * @return void - */ -function pkgbase_add_comment($base_id, $uid, $comment) { - $dbh = DB::connect(); - - if (trim($comment) == '') { - return array(false, __('Comment cannot be empty.')); - } - - $q = "INSERT INTO PackageComments "; - $q.= "(PackageBaseID, UsersID, Comments, RenderedComment, CommentTS) "; - $q.= "VALUES (" . intval($base_id) . ", " . $uid . ", "; - $q.= $dbh->quote($comment) . ", '', " . strval(time()) . ")"; - $dbh->exec($q); - $comment_id = $dbh->lastInsertId(); - - render_comment($comment_id); - - notify(array('comment', $uid, $base_id, $comment_id)); - - return array(true, __('Comment has been added.')); -} - -/** - * Pin/unpin a package comment - * - * @param bool $unpin True if unpinning rather than pinning - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_pin_comment($unpin=false) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - if (!$unpin) { - if (pkgbase_comments_count($_POST['package_base'], false, true) >= 5){ - return array(false, __("No more than 5 comments can be pinned.")); - } - } - - if (!can_pin_comment($comment_id)) { - if (!$unpin) { - return array(false, __("You are not allowed to pin this comment.")); - } else { - return array(false, __("You are not allowed to unpin this comment.")); - } - } - - $dbh = DB::connect(); - $q = "UPDATE PackageComments "; - if (!$unpin) { - $q.= "SET PinnedTS = " . strval(time()) . " "; - } else { - $q.= "SET PinnedTS = 0 "; - } - $q.= "WHERE ID = " . intval($comment_id); - $dbh->exec($q); - - if (!$unpin) { - return array(true, __("Comment has been pinned.")); - } else { - return array(true, __("Comment has been unpinned.")); - } -} - -/** - - * Get a list of all packages a logged-in user has voted for - * - * @param string $sid The session ID of the visitor - * - * @return array All packages the visitor has voted for - */ -function pkgbase_votes_from_sid($sid="") { - $pkgs = array(); - if (!$sid) {return $pkgs;} - $dbh = DB::connect(); - $q = "SELECT PackageBaseID "; - $q.= "FROM PackageVotes, Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Users.ID = PackageVotes.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_NUM)) { - $pkgs[$row[0]] = 1; - } - } - return $pkgs; -} - -/** - * Get the package base details - * - * @param string $id The package base ID to get description for - * - * @return array The package base's details OR error message - **/ -function pkgbase_get_details($base_id) { - $dbh = DB::connect(); - - $q = "SELECT PackageBases.ID, PackageBases.Name, "; - $q.= "PackageBases.NumVotes, PackageBases.Popularity, "; - $q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, "; - $q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, "; - $q.= "PackageBases.MaintainerUID, PackageBases.PackagerUID, "; - $q.= "PackageBases.FlaggerUID, "; - $q.= "(SELECT COUNT(*) FROM PackageRequests "; - $q.= " WHERE PackageRequests.PackageBaseID = PackageBases.ID "; - $q.= " AND PackageRequests.Status = 0) AS RequestCount "; - $q.= "FROM PackageBases "; - $q.= "WHERE PackageBases.ID = " . intval($base_id); - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Display the package base details page - * - * @param string $id The package base ID to get details page for - * @param array $row Package base details retrieved by pkgbase_get_details() - * @param string $SID The session ID of the visitor - * - * @return void - */ -function pkgbase_display_details($base_id, $row, $SID="") { - if (isset($row['error'])) { - print "

    " . $row['error'] . "

    \n"; - } - else { - $pkgbase_name = pkgbase_name_from_id($base_id); - - include('pkgbase_details.php'); - - if ($SID) { - $comment_section = "package"; - include('pkg_comment_box.php'); - } - - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); - - $limit_pinned = isset($_GET['pinned']) ? 0 : 5; - $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); - if (!empty($pinned)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - unset($pinned); - - - $total_comment_count = pkgbase_comments_count($base_id, $include_deleted); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $comments = pkgbase_comments($base_id, $per_page, $include_deleted, false, $offset); - if (!empty($comments)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - } -} - -/** - * Convert a list of package IDs into a list of corresponding package bases. - * - * @param array|int $ids Array of package IDs to convert - * - * @return array|int List of package base IDs - */ -function pkgbase_from_pkgid($ids) { - $dbh = DB::connect(); - - if (is_array($ids)) { - $q = "SELECT PackageBaseID FROM Packages "; - $q.= "WHERE ID IN (" . implode(",", $ids) . ")"; - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - $q = "SELECT PackageBaseID FROM Packages "; - $q.= "WHERE ID = " . $ids; - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); - } -} - -/** - * Retrieve ID of a package base by name - * - * @param string $name The package base name to retrieve the ID for - * - * @return int The ID of the package base - */ -function pkgbase_from_name($name) { - $dbh = DB::connect(); - $q = "SELECT ID FROM PackageBases WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Retrieve the name of a package base given its ID - * - * @param int $base_id The ID of the package base to query - * - * @return string The name of the package base - */ -function pkgbase_name_from_id($base_id) { - $dbh = DB::connect(); - $q = "SELECT Name FROM PackageBases WHERE ID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Get the names of all packages belonging to a package base - * - * @param int $base_id The ID of the package base - * - * @return array The names of all packages belonging to the package base - */ -function pkgbase_get_pkgnames($base_id) { - $dbh = DB::connect(); - $q = "SELECT Name FROM Packages WHERE PackageBaseID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Determine whether a package base is (or contains a) VCS package - * - * @param int $base_id The ID of the package base - * - * @return bool True if the package base is/contains a VCS package - */ -function pkgbase_is_vcs($base_id) { - $suffixes = array("-cvs", "-svn", "-git", "-hg", "-bzr", "-darcs"); - $haystack = pkgbase_get_pkgnames($base_id); - array_push($haystack, pkgbase_name_from_id($base_id)); - foreach ($haystack as $pkgname) { - foreach ($suffixes as $suffix) { - if (substr_compare($pkgname, $suffix, -strlen($suffix)) === 0) { - return true; - } - } - } - return false; -} - -/** - * Delete all packages belonging to a package base - * - * @param int $base_id The ID of the package base - * - * @return void - */ -function pkgbase_delete_packages($base_id) { - $dbh = DB::connect(); - $q = "DELETE FROM Packages WHERE PackageBaseID = " . intval($base_id); - $dbh->exec($q); -} - -/** - * Retrieve the maintainer of a package base given its ID - * - * @param int $base_id The ID of the package base to query - * - * @return int The user ID of the current package maintainer - */ -function pkgbase_maintainer_uid($base_id) { - $dbh = DB::connect(); - $q = "SELECT MaintainerUID FROM PackageBases WHERE ID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Retrieve the maintainers of an array of package bases given by their ID - * - * @param int $base_ids The array of IDs of the package bases to query - * - * @return int The user ID of the current package maintainer - */ -function pkgbase_maintainer_uids($base_ids) { - $dbh = DB::connect(); - $q = "SELECT MaintainerUID FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")"; - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Flag package(s) as out-of-date - * - * @param array $base_ids Array of package base IDs to flag/unflag - * @param string $comment The comment to add - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_flag($base_ids, $comment) { - if (!has_credential(CRED_PKGBASE_FLAG)) { - return array(false, __("You must be logged in before you can flag packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to flag.")); - } - - if (strlen($comment) < 3) { - return array(false, __("The selected packages have not been flagged, please enter a comment.")); - } - - $uid = uid_from_sid($_COOKIE['AURSID']); - $dbh = DB::connect(); - - $q = "UPDATE PackageBases SET "; - $q.= "OutOfDateTS = " . strval(time()) . ", FlaggerUID = " . $uid . ", "; - $q.= "FlaggerComment = " . $dbh->quote($comment) . " "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $q.= "AND OutOfDateTS IS NULL"; - $dbh->exec($q); - - foreach ($base_ids as $base_id) { - notify(array('flag', $uid, $base_id)); - } - - return array(true, __("The selected packages have been flagged out-of-date.")); -} - -/** - * Unflag package(s) as out-of-date - * - * @param array $base_ids Array of package base IDs to flag/unflag - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_unflag($base_ids) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can unflag packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to unflag.")); - } - - $dbh = DB::connect(); - - $q = "UPDATE PackageBases SET "; - $q.= "OutOfDateTS = NULL "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - - $maintainers = array_merge(pkgbase_maintainer_uids($base_ids), pkgbase_get_comaintainer_uids($base_ids)); - if (!has_credential(CRED_PKGBASE_UNFLAG, $maintainers)) { - $q.= "AND (MaintainerUID = " . $uid . " OR FlaggerUID = " . $uid. ")"; - } - - $result = $dbh->exec($q); - - if ($result) { - return array(true, __("The selected packages have been unflagged.")); - } -} - -/** - * Get package flag OOD comment - * - * @param int $base_id - * - * @return array Tuple of pkgbase ID, reason for OOD, and user who flagged - */ -function pkgbase_get_flag_comment($base_id) { - $base_id = intval($base_id); - $dbh = DB::connect(); - - $q = "SELECT FlaggerComment,OutOfDateTS,Username FROM PackageBases "; - $q.= "LEFT JOIN Users ON FlaggerUID = Users.ID "; - $q.= "WHERE PackageBases.ID = " . $base_id . " "; - $q.= "AND PackageBases.OutOfDateTS IS NOT NULL"; - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Delete package bases - * - * @param array $base_ids Array of package base IDs to delete - * @param int $merge_base_id Package base to merge the deleted ones into - * @param int $via Package request to close upon deletion - * @param bool $grant Allow anyone to delete the package base - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) { - if (!$grant && !has_credential(CRED_PKGBASE_DELETE)) { - return array(false, __("You do not have permission to delete packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to delete.")); - } - - $dbh = DB::connect(); - - if ($merge_base_id) { - $merge_base_name = pkgbase_name_from_id($merge_base_id); - } - - $uid = uid_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - if ($merge_base_id) { - notify(array('delete', $uid, $base_id, $merge_base_id)); - } else { - notify(array('delete', $uid, $base_id)); - } - } - - /* - * Close package request if the deletion was initiated through the - * request interface. NOTE: This needs to happen *before* the actual - * deletion. Otherwise, the former maintainer will not be included in - * the Cc list of the request notification email. - */ - if ($via) { - pkgreq_close(intval($via), 'accepted', ''); - } - - /* Scan through pending deletion requests and close them. */ - $username = username_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - $pkgreq_ids = array_merge(pkgreq_by_pkgbase($base_id)); - foreach ($pkgreq_ids as $pkgreq_id) { - pkgreq_close(intval($pkgreq_id), 'accepted', - 'The user ' . $username . - ' deleted the package.', true); - } - } - - if ($merge_base_id) { - /* Merge comments */ - $q = "UPDATE PackageComments "; - $q.= "SET PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - /* Merge notifications */ - $q = "SELECT DISTINCT UserID FROM PackageNotifications cn "; - $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ") "; - $q.= "AND NOT EXISTS (SELECT * FROM PackageNotifications cn2 "; - $q.= "WHERE cn2.PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "AND cn2.UserID = cn.UserID)"; - $result = $dbh->query($q); - - while ($notify_uid = $result->fetch(PDO::FETCH_COLUMN, 0)) { - $q = "INSERT INTO PackageNotifications (UserID, PackageBaseID) "; - $q.= "VALUES (" . intval($notify_uid) . ", " . intval($merge_base_id) . ")"; - $dbh->exec($q); - } - - /* Merge votes */ - foreach ($base_ids as $base_id) { - $q = "UPDATE PackageVotes "; - $q.= "SET PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "WHERE PackageBaseID = " . $base_id . " "; - $q.= "AND UsersID NOT IN ("; - $q.= "SELECT * FROM (SELECT UsersID "; - $q.= "FROM PackageVotes "; - $q.= "WHERE PackageBaseID = " . intval($merge_base_id); - $q.= ") temp)"; - $dbh->exec($q); - } - - $q = "UPDATE PackageBases "; - $q.= "SET NumVotes = (SELECT COUNT(*) FROM PackageVotes "; - $q.= "WHERE PackageBaseID = " . intval($merge_base_id) . ") "; - $q.= "WHERE ID = " . intval($merge_base_id); - $dbh->exec($q); - } - - $q = "DELETE FROM Packages WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - $q = "DELETE FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - return array(true, __("The selected packages have been deleted.")); -} - -/** - * Adopt or disown packages - * - * @param array $base_ids Array of package base IDs to adopt/disown - * @param bool $action Adopts if true, disowns if false. Adopts by default - * @param int $via Package request to close upon adoption - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_adopt ($base_ids, $action=true, $via) { - $dbh = DB::connect(); - - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - if ($action) { - return array(false, __("You must be logged in before you can adopt packages.")); - } else { - return array(false, __("You must be logged in before you can disown packages.")); - } - } - - /* Verify package ownership. */ - $base_ids = sanitize_ids($base_ids); - - $q = "SELECT ID FROM PackageBases "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - - if ($action && !has_credential(CRED_PKGBASE_ADOPT)) { - /* Regular users may only adopt orphan packages. */ - $q.= "AND MaintainerUID IS NULL"; - } - if (!$action && !has_credential(CRED_PKGBASE_DISOWN)) { - /* Regular users may only disown their own packages. */ - $q.= "AND MaintainerUID = " . $uid; - } - - $result = $dbh->query($q); - $base_ids = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - /* Error out if the list of remaining packages is empty. */ - if (empty($base_ids)) { - if ($action) { - return array(false, __("You did not select any packages to adopt.")); - } else { - return array(false, __("You did not select any packages to disown.")); - } - } - - /* - * Close package request if the disownment was initiated through the - * request interface. NOTE: This needs to happen *before* the actual - * disown operation. Otherwise, the former maintainer will not be - * included in the Cc list of the request notification email. - */ - if ($via) { - pkgreq_close(intval($via), 'accepted', ''); - } - - /* Scan through pending orphan requests and close them. */ - if (!$action) { - $username = username_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - $pkgreq_ids = pkgreq_by_pkgbase($base_id, 'orphan'); - foreach ($pkgreq_ids as $pkgreq_id) { - pkgreq_close(intval($pkgreq_id), 'accepted', - 'The user ' . $username . - ' disowned the package.', true); - } - } - } - - /* Adopt or disown the package. */ - if ($action) { - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = $uid "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $dbh->exec($q); - - /* Add the new maintainer to the notification list. */ - pkgbase_notify($base_ids); - } else { - /* Update the co-maintainer list when disowning a package. */ - if (has_credential(CRED_PKGBASE_DISOWN)) { - foreach ($base_ids as $base_id) { - pkgbase_set_comaintainers($base_id, array()); - } - - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = NULL "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $dbh->exec($q); - } else { - foreach ($base_ids as $base_id) { - $comaintainers = pkgbase_get_comaintainers($base_id); - - if (count($comaintainers) > 0) { - $comaintainer_uid = uid_from_username($comaintainers[0]); - $comaintainers = array_diff($comaintainers, array($comaintainers[0])); - pkgbase_set_comaintainers($base_id, $comaintainers); - } else { - $comaintainer_uid = "NULL"; - } - - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = " . $comaintainer_uid . " "; - $q.= "WHERE ID = " . $base_id; - $dbh->exec($q); - } - } - } - - foreach ($base_ids as $base_id) { - notify(array($action ? 'adopt' : 'disown', $uid, $base_id)); - } - - if ($action) { - return array(true, __("The selected packages have been adopted.")); - } else { - return array(true, __("The selected packages have been disowned.")); - } -} - -/** - * Vote and un-vote for packages - * - * @param array $base_ids Array of package base IDs to vote/un-vote - * @param bool $action Votes if true, un-votes if false. Votes by default - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_vote ($base_ids, $action=true) { - if (!has_credential(CRED_PKGBASE_VOTE)) { - if ($action) { - return array(false, __("You must be logged in before you can vote for packages.")); - } else { - return array(false, __("You must be logged in before you can un-vote for packages.")); - } - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - if ($action) { - return array(false, __("You did not select any packages to vote for.")); - } else { - return array(false, __("Your votes have been removed from the selected packages.")); - } - } - - $dbh = DB::connect(); - $my_votes = pkgbase_votes_from_sid($_COOKIE["AURSID"]); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - $first = 1; - $vote_ids = ""; - $vote_clauses = ""; - foreach ($base_ids as $pid) { - if ($action) { - $check = !isset($my_votes[$pid]); - } else { - $check = isset($my_votes[$pid]); - } - - if ($check) { - if ($first) { - $first = 0; - $vote_ids = $pid; - if ($action) { - $vote_clauses = "($uid, $pid, " . strval(time()) . ")"; - } - } else { - $vote_ids .= ", $pid"; - if ($action) { - $vote_clauses .= ", ($uid, $pid, " . strval(time()) . ")"; - } - } - } - } - - if (!empty($vote_ids)) { - /* Only add votes for packages the user hasn't already voted for. */ - $op = $action ? "+" : "-"; - $q = "UPDATE PackageBases SET NumVotes = NumVotes $op 1 "; - $q.= "WHERE ID IN ($vote_ids)"; - - $dbh->exec($q); - - if ($action) { - $q = "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) VALUES "; - $q.= $vote_clauses; - } else { - $q = "DELETE FROM PackageVotes WHERE UsersID = $uid "; - $q.= "AND PackageBaseID IN ($vote_ids)"; - } - - $dbh->exec($q); - } - - if ($action) { - return array(true, __("Your votes have been cast for the selected packages.")); - } else { - return array(true, __("Your votes have been removed from the selected packages.")); - } -} - -/** - * Get all usernames and IDs that voted for a specific package base - * - * @param string $pkgbase_name The package base to retrieve votes for - * - * @return array User IDs and usernames that voted for a specific package base - */ -function pkgbase_votes_from_name($pkgbase_name) { - $dbh = DB::connect(); - - $q = "SELECT UsersID, Username, Name, VoteTS FROM PackageVotes "; - $q.= "LEFT JOIN Users ON UsersID = Users.ID "; - $q.= "LEFT JOIN PackageBases "; - $q.= "ON PackageVotes.PackageBaseID = PackageBases.ID "; - $q.= "WHERE PackageBases.Name = ". $dbh->quote($pkgbase_name) . " "; - $q.= "ORDER BY Username"; - $result = $dbh->query($q); - - if (!$result) { - return; - } - - $votes = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $votes[] = $row; - } - - return $votes; -} - -/** - * Determine if a user has already voted for a specific package base - * - * @param string $uid The user ID to check for an existing vote - * @param string $base_id The package base ID to check for an existing vote - * - * @return bool True if the user has already voted, otherwise false - */ -function pkgbase_user_voted($uid, $base_id) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM PackageVotes WHERE "; - $q.= "UsersID = ". $dbh->quote($uid) . " AND "; - $q.= "PackageBaseID = " . $dbh->quote($base_id); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return ($result->fetch(PDO::FETCH_COLUMN, 0) > 0); -} - -/** - * Determine if a user wants notifications for a specific package base - * - * @param string $uid User ID to check in the database - * @param string $base_id Package base ID to check notifications for - * - * @return bool True if the user wants notifications, otherwise false - */ -function pkgbase_user_notify($uid, $base_id) { - $dbh = DB::connect(); - - $q = "SELECT * FROM PackageNotifications WHERE UserID = " . $dbh->quote($uid); - $q.= " AND PackageBaseID = " . $dbh->quote($base_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - return ($result->fetch(PDO::FETCH_NUM) > 0); -} - -/** - * Toggle notification of packages - * - * @param array $base_ids Array of package base IDs to toggle - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_notify ($base_ids, $action=true) { - if (!has_credential(CRED_PKGBASE_NOTIFY)) { - return; - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("Couldn't add to notification list.")); - } - - $dbh = DB::connect(); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - $output = ""; - - $first = true; - - /* - * There currently shouldn't be multiple requests here, but the format - * in which it's sent requires this. - */ - foreach ($base_ids as $bid) { - $q = "SELECT Name FROM PackageBases WHERE ID = $bid"; - $result = $dbh->query($q); - if ($result) { - $row = $result->fetch(PDO::FETCH_NUM); - $basename = $row[0]; - } - else { - $basename = ''; - } - - if ($first) - $first = false; - else - $output .= ", "; - - - if ($action) { - $q = "SELECT COUNT(*) FROM PackageNotifications WHERE "; - $q .= "UserID = $uid AND PackageBaseID = $bid"; - - /* Notification already added. Don't add again. */ - $result = $dbh->query($q); - if ($result->fetchColumn() == 0) { - $q = "INSERT INTO PackageNotifications (PackageBaseID, UserID) VALUES ($bid, $uid)"; - $dbh->exec($q); - } - - $output .= $basename; - } - else { - $q = "DELETE FROM PackageNotifications WHERE PackageBaseID = $bid "; - $q .= "AND UserID = $uid"; - $dbh->exec($q); - - $output .= $basename; - } - } - - if ($action) { - $output = __("You have been added to the comment notification list for %s.", $output); - } - else { - $output = __("You have been removed from the comment notification list for %s.", $output); - } - - return array(true, $output); -} - -/** - * Delete a package comment - * - * @param boolean $undelete True if undeleting rather than deleting - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_delete_comment($undelete=false) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - $dbh = DB::connect(); - if ($undelete) { - if (!has_credential(CRED_COMMENT_UNDELETE)) { - return array(false, __("You are not allowed to undelete this comment.")); - } - - $q = "UPDATE PackageComments "; - $q.= "SET DelUsersID = NULL, "; - $q.= "DelTS = NULL "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - return array(true, __("Comment has been undeleted.")); - } else { - if (!can_delete_comment($comment_id)) { - return array(false, __("You are not allowed to delete this comment.")); - } - - $q = "UPDATE PackageComments "; - $q.= "SET DelUsersID = ".$uid.", "; - $q.= "DelTS = " . strval(time()) . " "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - return array(true, __("Comment has been deleted.")); - } -} - -/** - * Edit a package comment - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_edit_comment($comment) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - if (trim($comment) == '') { - return array(false, __('Comment cannot be empty.')); - } - - $dbh = DB::connect(); - if (can_edit_comment($comment_id)) { - $q = "UPDATE PackageComments "; - $q.= "SET EditedUsersID = ".$uid.", "; - $q.= "Comments = ".$dbh->quote($comment).", "; - $q.= "EditedTS = " . strval(time()) . " "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - - render_comment($comment_id); - - return array(true, __("Comment has been edited.")); - } else { - return array(false, __("You are not allowed to edit this comment.")); - } -} - -/** - * Get a list of package base keywords - * - * @param int $base_id The package base ID to retrieve the keywords for - * - * @return array An array of keywords - */ -function pkgbase_get_keywords($base_id) { - $dbh = DB::connect(); - $q = "SELECT Keyword FROM PackageKeywords "; - $q .= "WHERE PackageBaseID = " . intval($base_id) . " "; - $q .= "ORDER BY Keyword ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Update the list of keywords of a package base - * - * @param int $base_id The package base ID to update the keywords of - * @param array $users Array of keywords - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_set_keywords($base_id, $keywords) { - $base_id = intval($base_id); - - $maintainers = array_merge(array(pkgbase_maintainer_uid($base_id)), pkgbase_get_comaintainer_uids(array($base_id))); - if (!has_credential(CRED_PKGBASE_SET_KEYWORDS, $maintainers)) { - return array(false, __("You are not allowed to edit the keywords of this package base.")); - } - - /* Remove empty and duplicate user names. */ - $keywords = array_unique(array_filter(array_map('trim', $keywords))); - - $dbh = DB::connect(); - - $q = sprintf("DELETE FROM PackageKeywords WHERE PackageBaseID = %d", $base_id); - $dbh->exec($q); - - $i = 0; - foreach ($keywords as $keyword) { - $q = sprintf("INSERT INTO PackageKeywords (PackageBaseID, Keyword) VALUES (%d, %s)", $base_id, $dbh->quote($keyword)); - $dbh->exec($q); - - $i++; - if ($i >= 20) { - break; - } - } - - return array(true, __("The package base keywords have been updated.")); -} - -/** - * Get a list of package base co-maintainers - * - * @param int $base_id The package base ID to retrieve the co-maintainers for - * - * @return array An array of co-maintainer user names - */ -function pkgbase_get_comaintainers($base_id) { - $dbh = DB::connect(); - $q = "SELECT UserName FROM PackageComaintainers "; - $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q .= "WHERE PackageComaintainers.PackageBaseID = " . intval($base_id) . " "; - $q .= "ORDER BY Priority ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Get a list of package base co-maintainer IDs - * - * @param int $base_id The package base ID to retrieve the co-maintainers for - * - * @return array An array of co-maintainer user UDs - */ -function pkgbase_get_comaintainer_uids($base_ids) { - $dbh = DB::connect(); - $q = "SELECT UsersID FROM PackageComaintainers "; - $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q .= "WHERE PackageComaintainers.PackageBaseID IN (" . implode(",", $base_ids) . ") "; - $q .= "ORDER BY Priority ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Update the list of co-maintainers of a package base - * - * @param int $base_id The package base ID to update the co-maintainers of - * @param array $users Array of co-maintainer user names - * @param boolean $override Override credential check if true - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_set_comaintainers($base_id, $users, $override=false) { - $maintainer_uid = pkgbase_maintainer_uid($base_id); - if (!$override && !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array($maintainer_uid))) { - return array(false, __("You are not allowed to manage co-maintainers of this package base.")); - } - - /* Remove empty and duplicate user names. */ - $users = array_unique(array_filter(array_map('trim', $users))); - - $dbh = DB::connect(); - - $uids_new = array(); - foreach($users as $user) { - $q = "SELECT ID FROM Users "; - $q .= "WHERE UserName = " . $dbh->quote($user); - $result = $dbh->query($q); - $uid = $result->fetchColumn(0); - - if (!$uid) { - return array(false, __("Invalid user name: %s", $user)); - } elseif ($uid == $maintainer_uid) { - // silently ignore when maintainer == co-maintainer - continue; - } else { - $uids_new[] = $uid; - } - } - - $q = sprintf("SELECT UsersID FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id); - $result = $dbh->query($q); - $uids_old = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - $uids_add = array_diff($uids_new, $uids_old); - $uids_rem = array_diff($uids_old, $uids_new); - - $i = 1; - foreach ($uids_new as $uid) { - if (in_array($uid, $uids_add)) { - $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i); - notify(array('comaintainer-add', $uid, $base_id)); - } else { - $q = sprintf("UPDATE PackageComaintainers SET Priority = %d WHERE PackageBaseID = %d AND UsersID = %d", $i, $base_id, $uid); - } - - $dbh->exec($q); - $i++; - } - - foreach ($uids_rem as $uid) { - $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d AND UsersID = %d", $base_id, $uid); - $dbh->exec($q); - notify(array('comaintainer-remove', $uid, $base_id)); - } - - return array(true, __("The package base co-maintainers have been updated.")); -} - -function pkgbase_remove_comaintainer($base_id, $uid) { - $uname = username_from_id($uid); - $names = pkgbase_get_comaintainers($base_id); - $names = array_diff($names, array($uname)); - return pkgbase_set_comaintainers($base_id, $names, true); -} diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php deleted file mode 100644 index 140c7ec1..00000000 --- a/web/lib/pkgfuncs.inc.php +++ /dev/null @@ -1,957 +0,0 @@ -query($q); - - if (!$result) { - return false; - } - - $uid = $result->fetch(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_DELETE, array($uid)); -} - -/** - * Determine if the user can delete a specific package comment using an array - * - * Only the comment submitter, Trusted Users, and Developers can delete - * comments. This function is used for the frontend side of comment deletion. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can delete the comment, otherwise false - */ -function can_delete_comment_array($comment) { - return has_credential(CRED_COMMENT_DELETE, array($comment['UsersID'])); -} - -/** - * Determine if the user can edit a specific package comment - * - * Only the comment submitter, Trusted Users, and Developers can edit - * comments. This function is used for the backend side of comment editing. - * - * @param string $comment_id The comment ID in the database - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_edit_comment($comment_id=0) { - $dbh = DB::connect(); - - $q = "SELECT UsersID FROM PackageComments "; - $q.= "WHERE ID = " . intval($comment_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - $uid = $result->fetch(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_EDIT, array($uid)); -} - -/** - * Determine if the user can edit a specific package comment using an array - * - * Only the comment submitter, Trusted Users, and Developers can edit - * comments. This function is used for the frontend side of comment editing. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_edit_comment_array($comment) { - return has_credential(CRED_COMMENT_EDIT, array($comment['UsersID'])); -} - -/** - * Determine if the user can pin a specific package comment - * - * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and - * Developers can pin comments. This function is used for the backend side of - * comment pinning. - * - * @param string $comment_id The comment ID in the database - * - * @return bool True if the user can pin the comment, otherwise false - */ -function can_pin_comment($comment_id=0) { - $dbh = DB::connect(); - - $q = "SELECT MaintainerUID FROM PackageBases AS pb "; - $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; - $q.= "WHERE pc.ID = " . intval($comment_id) . " "; - $q.= "UNION "; - $q.= "SELECT pcm.UsersID FROM PackageComaintainers AS pcm "; - $q.= "LEFT JOIN PackageComments AS pc "; - $q.= "ON pcm.PackageBaseID = pc.PackageBaseID "; - $q.= "WHERE pc.ID = " . intval($comment_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - $uids = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_PIN, $uids); -} - -/** - * Determine if the user can edit a specific package comment using an array - * - * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and - * Developers can pin comments. This function is used for the frontend side of - * comment pinning. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_pin_comment_array($comment) { - return can_pin_comment($comment['ID']); -} - -/** - * Check to see if the package name already exists in the database - * - * @param string $name The package name to check - * - * @return string|void Package name if it already exists - */ -function pkg_from_name($name="") { - if (!$name) {return NULL;} - $dbh = DB::connect(); - $q = "SELECT ID FROM Packages "; - $q.= "WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - if (!$result) { - return; - } - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Get licenses for a specific package - * - * @param int $pkgid The package to get licenses for - * - * @return array All licenses for the package - */ -function pkg_licenses($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT l.Name FROM Licenses l "; - $q.= "INNER JOIN PackageLicenses pl ON pl.LicenseID = l.ID "; - $q.= "WHERE pl.PackageID = ". $pkgid; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($q, 'licenses:' . $pkgid, PDO::FETCH_NUM, $ttl); - return array_map(function ($x) { return $x[0]; }, $rows); -} - -/** - * Get package groups for a specific package - * - * @param int $pkgid The package to get groups for - * - * @return array All package groups for the package - */ -function pkg_groups($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT g.Name FROM `Groups` g "; - $q.= "INNER JOIN PackageGroups pg ON pg.GroupID = g.ID "; - $q.= "WHERE pg.PackageID = ". $pkgid; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($q, 'groups:' . $pkgid, PDO::FETCH_NUM, $ttl); - return array_map(function ($x) { return $x[0]; }, $rows); -} - -/** - * Get providers for a specific package - * - * @param string $name The name of the "package" to get providers for - * - * @return array The IDs and names of all providers of the package - */ -function pkg_providers($name) { - $dbh = DB::connect(); - $q = "SELECT p.ID, p.Name FROM Packages p "; - $q.= "WHERE p.Name = " . $dbh->quote($name) . " "; - $q.= "UNION "; - $q.= "SELECT p.ID, p.Name FROM Packages p "; - $q.= "LEFT JOIN PackageRelations pr ON pr.PackageID = p.ID "; - $q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; - $q.= "WHERE (rt.Name = 'provides' "; - $q.= "AND pr.RelName = " . $dbh->quote($name) . ")"; - $q.= "UNION "; - $q.= "SELECT 0, Name FROM OfficialProviders "; - $q.= "WHERE Provides = " . $dbh->quote($name); - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'providers:' . $name, PDO::FETCH_NUM, $ttl); -} - -/** - * Get package dependencies for a specific package - * - * @param int $pkgid The package to get dependencies for - * @param int $limit An upper bound for the number of packages to retrieve - * - * @return array All package dependencies for the package - */ -function pkg_dependencies($pkgid, $limit) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT pd.DepName, dt.Name, pd.DepDesc, "; - $q.= "pd.DepCondition, pd.DepArch, p.ID "; - $q.= "FROM PackageDepends pd "; - $q.= "LEFT JOIN Packages p ON pd.DepName = p.Name "; - $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; - $q.= "WHERE pd.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pd.DepName LIMIT " . intval($limit); - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'dependencies:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get package relations for a specific package - * - * @param int $pkgid The package to get relations for - * - * @return array All package relations for the package - */ -function pkg_relations($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT pr.RelName, rt.Name, pr.RelCondition, pr.RelArch, p.ID FROM PackageRelations pr "; - $q.= "LEFT JOIN Packages p ON pr.RelName = p.Name "; - $q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; - $q.= "WHERE pr.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pr.RelName"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'relations:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get the HTML code to display a package dependency link annotation - * (dependency type, architecture, ...) - * - * @param string $type The name of the dependency type - * @param string $arch The package dependency architecture - * @param string $desc An optdepends description - * - * @return string The HTML code of the label to display - */ -function pkg_deplink_annotation($type, $arch, $desc=false) { - if ($type == 'depends' && !$arch) { - return ''; - } - - $link = ' ('; - - if ($type == 'makedepends') { - $link .= 'make'; - } elseif ($type == 'checkdepends') { - $link .= 'check'; - } elseif ($type == 'optdepends') { - $link .= 'optional'; - } - - if ($type != 'depends' && $arch) { - $link .= ', '; - } - - if ($arch) { - $link .= htmlspecialchars($arch); - } - - $link .= ')'; - if ($type == 'optdepends' && $desc) { - $link .= ' – ' . htmlspecialchars($desc) . ' '; - } - $link .= ''; - - return $link; -} - -/** - * Get the HTML code to display a package provider link - * - * @param string $name The name of the provider - * @param bool $official True if the package is in the official repositories - * - * @return string The HTML code of the link to display - */ -function pkg_provider_link($name, $official) { - $link = ''; - $link .= htmlspecialchars($name) . ''; - - return $link; -} - -/** - * Get the HTML code to display a package dependency link - * - * @param string $name The name of the dependency - * @param string $type The name of the dependency type - * @param string $desc The (optional) description of the dependency - * @param string $cond The package dependency condition string - * @param string $arch The package dependency architecture - * @param int $pkg_id The package of the package to display the dependency for - * - * @return string The HTML code of the label to display - */ -function pkg_depend_link($name, $type, $desc, $cond, $arch, $pkg_id) { - /* - * TODO: We currently perform one SQL query per nonexistent package - * dependency. It would be much better if we could annotate dependency - * data with providers so that we already know whether a dependency is - * a "provision name" or a package from the official repositories at - * this point. - */ - $providers = pkg_providers($name); - - if (count($providers) == 0) { - $link = ''; - $link .= htmlspecialchars($name); - $link .= ''; - $link .= htmlspecialchars($cond) . ' '; - $link .= pkg_deplink_annotation($type, $arch, $desc); - return $link; - } - - $link = htmlspecialchars($name); - foreach ($providers as $provider) { - if ($provider[1] == $name) { - $is_official = ($provider[0] == 0); - $name = $provider[1]; - $link = pkg_provider_link($name, $is_official); - break; - } - } - $link .= htmlspecialchars($cond) . ' '; - - foreach ($providers as $key => $provider) { - if ($provider[1] == $name) { - unset($providers[$key]); - } - } - - if (count($providers) > 0) { - $link .= '('; - foreach ($providers as $provider) { - $is_official = ($provider[0] == 0); - $name = $provider[1]; - $link .= pkg_provider_link($name, $is_official) . ', '; - } - $link = substr($link, 0, -2); - $link .= ')'; - } - - $link .= pkg_deplink_annotation($type, $arch, $desc); - - return $link; -} - -/** - * Get the HTML code to display a package requirement link - * - * @param string $name The name of the requirement - * @param string $depends The (literal) name of the dependency of $name - * @param string $type The name of the dependency type - * @param string $arch The package dependency architecture - * @param string $pkgname The name of dependant package - * - * @return string The HTML code of the link to display - */ -function pkg_requiredby_link($name, $depends, $type, $arch, $pkgname) { - $link = ''; - $link .= htmlspecialchars($name) . ''; - - if ($depends != $pkgname) { - $link .= ' ('; - $link .= __('requires %s', htmlspecialchars($depends)); - $link .= ')'; - } - - return $link . pkg_deplink_annotation($type, $arch); -} - -/** - * Get the HTML code to display a package relation - * - * @param string $name The name of the relation - * @param string $cond The package relation condition string - * @param string $arch The package relation architecture - * - * @return string The HTML code of the label to display - */ -function pkg_rel_html($name, $cond, $arch) { - $html = htmlspecialchars($name) . htmlspecialchars($cond); - - if ($arch) { - $html .= ' (' . htmlspecialchars($arch) . ')'; - } - - return $html; -} - -/** - * Get the HTML code to display a source link - * - * @param string $url The URL of the source - * @param string $arch The source architecture - * @param string $package The name of the package - * - * @return string The HTML code of the label to display - */ -function pkg_source_link($url, $arch, $package) { - $url = explode('::', $url); - $parsed_url = parse_url($url[0]); - - if (isset($parsed_url['scheme']) || isset($url[1])) { - $link = '' . htmlspecialchars($url[0]) . ''; - } else { - $file_url = sprintf(config_get('options', 'source_file_uri'), htmlspecialchars($url[0]), $package); - $link = '' . htmlspecialchars($url[0]) . ''; - } - - if ($arch) { - $link .= ' (' . htmlspecialchars($arch) . ')'; - } - - return $link; -} - -/** - * Determine packages that depend on a package - * - * @param string $name The package name for the dependency search - * @param array $provides A list of virtual provisions of the package - * @param int $limit An upper bound for the number of packages to retrieve - * - * @return array All packages that depend on the specified package name - */ -function pkg_required($name="", $provides, $limit) { - $deps = array(); - if ($name != "") { - $dbh = DB::connect(); - - $name_list = $dbh->quote($name); - foreach ($provides as $p) { - $name_list .= ',' . $dbh->quote($p[0]); - } - - $q = "SELECT p.Name, pd.DepName, dt.Name, pd.DepArch "; - $q.= "FROM PackageDepends pd "; - $q.= "LEFT JOIN Packages p ON p.ID = pd.PackageID "; - $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; - $q.= "WHERE pd.DepName IN (" . $name_list . ") "; - $q.= "ORDER BY p.Name LIMIT " . intval($limit); - /* Not invalidated by package updates. */ - return db_cache_result($q, 'required:' . $name, PDO::FETCH_NUM); - } - return $deps; -} - -/** - * Get all package sources for a specific package - * - * @param string $pkgid The package ID to get the sources for - * - * @return array All sources associated with a specific package - */ -function pkg_sources($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT Source, SourceArch FROM PackageSources "; - $q.= "WHERE PackageID = " . $pkgid; - $q.= " ORDER BY Source"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'required:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get the package details - * - * @param string $id The package ID to get description for - * - * @return array The package's details OR error message - **/ -function pkg_get_details($id=0) { - $dbh = DB::connect(); - - $q = "SELECT Packages.*, PackageBases.ID AS BaseID, "; - $q.= "PackageBases.Name AS BaseName, PackageBases.NumVotes, "; - $q.= "PackageBases.Popularity, PackageBases.OutOfDateTS, "; - $q.= "PackageBases.SubmittedTS, PackageBases.ModifiedTS, "; - $q.= "PackageBases.SubmitterUID, PackageBases.MaintainerUID, "; - $q.= "PackageBases.PackagerUID, PackageBases.FlaggerUID, "; - $q.= "(SELECT COUNT(*) FROM PackageRequests "; - $q.= " WHERE PackageRequests.PackageBaseID = Packages.PackageBaseID "; - $q.= " AND PackageRequests.Status = 0) AS RequestCount "; - $q.= "FROM Packages, PackageBases "; - $q.= "WHERE PackageBases.ID = Packages.PackageBaseID "; - $q.= "AND Packages.ID = " . intval($id); - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Display the package details page - * - * @param string $id The package ID to get details page for - * @param array $row Package details retrieved by pkg_get_details() - * @param string $SID The session ID of the visitor - * - * @return void - */ -function pkg_display_details($id=0, $row, $SID="") { - $dbh = DB::connect(); - - if (isset($row['error'])) { - print "

    " . $row['error'] . "

    \n"; - } - else { - $base_id = pkgbase_from_pkgid($id); - $pkgbase_name = pkgbase_name_from_id($base_id); - - include('pkg_details.php'); - - if ($SID) { - include('pkg_comment_box.php'); - } - - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); - - $limit_pinned = isset($_GET['pinned']) ? 0 : 5; - $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); - if (!empty($pinned)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - unset($pinned); - - - $total_comment_count = pkgbase_comments_count($base_id, $include_deleted); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $comments = pkgbase_comments($base_id, $per_page, $include_deleted, false, $offset); - if (!empty($comments)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - } -} - -/** - * Output the body of the search results page - * - * @param array $params Search parameters - * @param bool $show_headers True if statistics should be included - * @param string $SID The session ID of the visitor - * - * @return int The total number of packages matching the query - */ -function pkg_search_page($params, $show_headers=true, $SID="") { - $dbh = DB::connect(); - - /* - * Get commonly used variables. - * TODO: Reduce the number of database queries! - */ - if ($SID) - $myuid = uid_from_sid($SID); - - /* Sanitize paging variables. */ - if (isset($params['O'])) { - $params['O'] = bound(intval($params['O']), 0, 2500); - } else { - $params['O'] = 0; - } - - if (isset($params["PP"])) { - $params["PP"] = bound(intval($params["PP"]), 50, 250); - } else { - $params["PP"] = 50; - } - - /* - * FIXME: Pull out DB-related code. All of it! This one's worth a - * choco-chip cookie, one of those nice big soft ones. - */ - - /* Build the package search query. */ - $q_select = "SELECT "; - if ($SID) { - $q_select .= "PackageNotifications.UserID AS Notify, - PackageVotes.UsersID AS Voted, "; - } - $q_select .= "Users.Username AS Maintainer, - Packages.Name, Packages.Version, Packages.Description, - PackageBases.NumVotes, PackageBases.Popularity, Packages.ID, - Packages.PackageBaseID, PackageBases.OutOfDateTS "; - - $q_from = "FROM Packages - LEFT JOIN PackageBases ON (PackageBases.ID = Packages.PackageBaseID) - LEFT JOIN Users ON (PackageBases.MaintainerUID = Users.ID) "; - if ($SID) { - /* This is not needed for the total row count query. */ - $q_from_extra = "LEFT JOIN PackageVotes - ON (PackageBases.ID = PackageVotes.PackageBaseID AND PackageVotes.UsersID = $myuid) - LEFT JOIN PackageNotifications - ON (PackageBases.ID = PackageNotifications.PackageBaseID AND PackageNotifications.UserID = $myuid) "; - } else { - $q_from_extra = ""; - } - - $q_where = 'WHERE PackageBases.PackagerUID IS NOT NULL '; - - if (isset($params['K'])) { - if (isset($params["SeB"]) && $params["SeB"] == "m") { - /* Search by maintainer. */ - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . " "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "c") { - /* Search by co-maintainer. */ - $q_where .= "AND EXISTS (SELECT * FROM PackageComaintainers "; - $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . ")"; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "M") { - /* Search by maintainer and co-maintainer. */ - $q_where .= "AND (Users.Username = " . $dbh->quote($params['K']) . " "; - $q_where .= "OR EXISTS (SELECT * FROM PackageComaintainers "; - $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . "))"; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "s") { - /* Search by submitter. */ - $q_where .= "AND SubmitterUID = " . intval(uid_from_username($params['K'])) . " "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "n") { - /* Search by name. */ - $K = "%" . addcslashes($params['K'], '%_') . "%"; - $q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "b") { - /* Search by package base name. */ - $K = "%" . addcslashes($params['K'], '%_') . "%"; - $q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "k") { - /* Search by name. */ - $q_where .= construct_keyword_search($dbh, $params['K'], false, true); - } - elseif (isset($params["SeB"]) && $params["SeB"] == "N") { - /* Search by name (exact match). */ - $q_where .= "AND (Packages.Name = " . $dbh->quote($params['K']) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "B") { - /* Search by package base name (exact match). */ - $q_where .= "AND (PackageBases.Name = " . $dbh->quote($params['K']) . ") "; - } - else { - /* Keyword search (default). */ - $q_where .= construct_keyword_search($dbh, $params['K'], true, true); - } - } - - if (isset($params["do_Orphans"])) { - $q_where .= "AND MaintainerUID IS NULL "; - } - - if (isset($params['outdated'])) { - if ($params['outdated'] == 'on') { - $q_where .= "AND OutOfDateTS IS NOT NULL "; - } - elseif ($params['outdated'] == 'off') { - $q_where .= "AND OutOfDateTS IS NULL "; - } - } - - $order = (isset($params["SO"]) && $params["SO"] == 'd') ? 'DESC' : 'ASC'; - - $q_sort = "ORDER BY "; - $sort_by = isset($params["SB"]) ? $params["SB"] : ''; - switch ($sort_by) { - case 'v': - $q_sort .= "NumVotes " . $order . ", "; - break; - case 'p': - $q_sort .= "Popularity " . $order . ", "; - break; - case 'w': - if ($SID) { - $q_sort .= "Voted " . $order . ", "; - } - break; - case 'o': - if ($SID) { - $q_sort .= "Notify " . $order . ", "; - } - break; - case 'm': - $q_sort .= "Maintainer " . $order . ", "; - break; - case 'l': - $q_sort .= "ModifiedTS " . $order . ", "; - break; - case 'a': - /* For compatibility with old search links. */ - $q_sort .= "-ModifiedTS " . $order . ", "; - break; - default: - break; - } - $q_sort .= " Packages.Name " . $order . " "; - - $q_limit = "LIMIT ".$params["PP"]." OFFSET ".$params["O"]; - - $q = $q_select . $q_from . $q_from_extra . $q_where . $q_sort . $q_limit; - $q_total = "SELECT COUNT(*) " . $q_from . $q_where; - - $result = $dbh->query($q); - $result_t = $dbh->query($q_total); - if ($result_t) { - $row = $result_t->fetch(PDO::FETCH_NUM); - $total = min($row[0], 2500); - } else { - $total = 0; - } - - if ($result && $total > 0) { - if (isset($params["SO"]) && $params["SO"] == "d"){ - $SO_next = "a"; - } - else { - $SO_next = "d"; - } - } - - /* Calculate the results to use. */ - $first = $params['O'] + 1; - - /* Calculation of pagination links. */ - $per_page = ($params['PP'] > 0) ? $params['PP'] : 50; - $current = ceil($first / $per_page); - $pages = ceil($total / $per_page); - $templ_pages = array(); - - if ($current > 1) { - $templ_pages['« ' . __('First')] = 0; - $templ_pages['‹ ' . __('Previous')] = ($current - 2) * $per_page; - } - - if ($current - 5 > 1) - $templ_pages["..."] = false; - - for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) { - $templ_pages[$i] = ($i - 1) * $per_page; - } - - if ($current + 5 < $pages) - $templ_pages["... "] = false; - - if ($current < $pages) { - $templ_pages[__('Next') . ' ›'] = $current * $per_page; - $templ_pages[__('Last') . ' »'] = ($pages - 1) * $per_page; - } - - $searchresults = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $searchresults[] = $row; - } - } - - include('pkg_search_results.php'); - - return $total; -} - -/** - * Construct the WHERE part of the sophisticated keyword search - * - * @param handle $dbh Database handle - * @param string $keywords The search term - * @param bool $namedesc Search name and description fields - * @param bool $keyword Search packages with a matching PackageBases.Keyword - * - * @return string WHERE part of the SQL clause - */ -function construct_keyword_search($dbh, $keywords, $namedesc, $keyword=false) { - $count = 0; - $where_part = ""; - $q_keywords = ""; - $op = ""; - - foreach (str_getcsv($keywords, ' ') as $term) { - if ($term == "") { - continue; - } - if ($count > 0 && strtolower($term) == "and") { - $op = "AND "; - continue; - } - if ($count > 0 && strtolower($term) == "or") { - $op = "OR "; - continue; - } - if ($count > 0 && strtolower($term) == "not") { - $op .= "NOT "; - continue; - } - - $term = "%" . addcslashes($term, '%_') . "%"; - $q_keywords .= $op . " ("; - $q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " "; - if ($namedesc) { - $q_keywords .= "OR Description LIKE " . $dbh->quote($term) . " "; - } - - if ($keyword) { - $q_keywords .= "OR EXISTS (SELECT * FROM PackageKeywords WHERE "; - $q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND "; - $q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) "; - } else { - $q_keywords .= ") "; - } - - $count++; - if ($count >= 20) { - break; - } - $op = "AND "; - } - - if (!empty($q_keywords)) { - $where_part = "AND (" . $q_keywords . ") "; - } - - return $where_part; -} - -/** - * Determine if a POST string has been sent by a visitor - * - * @param string $action String to check has been sent via POST - * - * @return bool True if the POST string was used, otherwise false - */ -function current_action($action) { - return (isset($_POST['action']) && $_POST['action'] == $action) || - isset($_POST[$action]); -} - -/** - * Determine if sent IDs are valid integers - * - * @param array $ids IDs to validate - * - * @return array All sent IDs that are valid integers - */ -function sanitize_ids($ids) { - $new_ids = array(); - foreach ($ids as $id) { - $id = intval($id); - if ($id > 0) { - $new_ids[] = $id; - } - } - return $new_ids; -} - -/** - * Determine package information for latest package - * - * @param int $numpkgs Number of packages to get information on - * - * @return array $packages Package info for the specified number of recent packages - */ -function latest_pkgs($numpkgs, $orderBy='SubmittedTS') { - $dbh = DB::connect(); - - $q = "SELECT Packages.*, MaintainerUID, SubmittedTS, ModifiedTS "; - $q.= "FROM Packages LEFT JOIN PackageBases ON "; - $q.= "PackageBases.ID = Packages.PackageBaseID "; - $q.= "ORDER BY " . $orderBy . " DESC "; - $q.= "LIMIT " . intval($numpkgs); - $result = $dbh->query($q); - - $packages = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $packages[] = $row; - } - } - - return $packages; -} - -/** - * Determine package information for latest modified packages - * - * @param int $numpkgs Number of packages to get information on - * - * @return array $packages Package info for the specified number of recently modified packages - */ -function latest_modified_pkgs($numpkgs) { - return latest_pkgs($numpkgs, 'ModifiedTS'); -} diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php deleted file mode 100644 index 7fce307c..00000000 --- a/web/lib/pkgreqfuncs.inc.php +++ /dev/null @@ -1,260 +0,0 @@ -query($q)->fetchColumn(); -} - -/** - * Get a list of all package requests - * - * @param int $offset The index of the first request to return - * @param int $limit The maximum number of requests to return - * @param int $uid Only return packages affecting the given user - * @param int $from Do not return packages older than the given date - * - * @return array List of package requests with details - */ -function pkgreq_list($offset, $limit, $uid=false, $from=false) { - $dbh = DB::connect(); - - $q = "SELECT PackageRequests.ID, "; - $q.= "PackageRequests.PackageBaseID AS BaseID, "; - $q.= "PackageRequests.PackageBaseName AS Name, "; - $q.= "PackageRequests.MergeBaseName AS MergeInto, "; - $q.= "RequestTypes.Name AS Type, PackageRequests.Comments, "; - $q.= "Users.Username AS User, PackageRequests.RequestTS, "; - $q.= "PackageRequests.Status, PackageRequests.Status = 0 AS Open "; - $q.= "FROM PackageRequests INNER JOIN RequestTypes ON "; - $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; - $q.= "INNER JOIN Users ON Users.ID = PackageRequests.UsersID "; - - if ($uid || $from) { - $q.= "WHERE "; - if ($uid) { - $q.= "(PackageRequests.UsersID = " . intval($uid). " "; - $q.= "OR Users.ID = " . intval($uid) . ") AND "; - } - if ($from) { - $q.= "RequestTS >= " . intval($from). " "; - } - } - - $q.= "ORDER BY Open DESC, RequestTS DESC "; - $q.= "LIMIT " . $limit . " OFFSET " . $offset; - - return $dbh->query($q)->fetchAll(); -} - -/** - * Get a list of all open package requests belonging to a certain package base - * - * @param int $baseid The package base ID to retrieve requests for - * @param int $type The type of requests to obtain - * - * @return array List of package request IDs - */ -function pkgreq_by_pkgbase($baseid, $type=false) { - $dbh = DB::connect(); - - $q = "SELECT PackageRequests.ID "; - $q.= "FROM PackageRequests INNER JOIN RequestTypes ON "; - $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; - $q.= "WHERE PackageRequests.Status = 0 "; - $q.= "AND PackageRequests.PackageBaseID = " . intval($baseid); - - if ($type) { - $q .= " AND RequestTypes.Name = " . $dbh->quote($type); - } - - return $dbh->query($q)->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Obtain the package base that belongs to a package request. - * - * @param int $id Package request ID to retrieve the package base for - * - * @return int The name of the corresponding package base - */ -function pkgreq_get_pkgbase_name($id) { - $dbh = DB::connect(); - - $q = "SELECT PackageBaseName FROM PackageRequests "; - $q.= "WHERE ID = " . intval($id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Obtain the email address of the creator of a package request - * - * @param int $id Package request ID to retrieve the creator for - * - * @return int The email address of the creator - */ -function pkgreq_get_creator_email($id) { - $dbh = DB::connect(); - - $q = "SELECT Email FROM Users INNER JOIN PackageRequests "; - $q.= "ON Users.ID = PackageRequests.UsersID "; - $q.= "WHERE PackageRequests.ID = " . intval($id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * File a deletion/orphan request against a package base - * - * @param string $ids The package base IDs to file the request against - * @param string $type The type of the request - * @param string $merge_into The target of a merge operation - * @param string $comments The comments to be added to the request - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgreq_file($ids, $type, $merge_into, $comments) { - if (!has_credential(CRED_PKGREQ_FILE)) { - return array(false, __("You must be logged in to file package requests.")); - } - - /* Ignore merge target for non-merge requests. */ - if ($type !== 'merge') { - $merge_into = ''; - } - - if (!empty($merge_into) && !preg_match("/^[a-z0-9][a-z0-9\.+_-]*$/D", $merge_into)) { - return array(false, __("Invalid name: only lowercase letters are allowed.")); - } - - if (!empty($merge_into) && !pkgbase_from_name($merge_into)) { - return array(false, __("Cannot find package to merge votes and comments into.")); - } - - if (empty($comments)) { - return array(false, __("The comment field must not be empty.")); - } - - $dbh = DB::connect(); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - /* TODO: Allow for filing multiple requests at once. */ - $base_id = intval($ids[0]); - $pkgbase_name = pkgbase_name_from_id($base_id); - - if ($merge_into == $pkgbase_name) { - return array(false, __("Cannot merge a package base with itself.")); - } - - $q = "SELECT ID FROM RequestTypes WHERE Name = " . $dbh->quote($type); - $result = $dbh->query($q); - if ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $type_id = $row['ID']; - } else { - return array(false, __("Invalid request type.")); - } - - $q = "INSERT INTO PackageRequests "; - $q.= "(ReqTypeID, PackageBaseID, PackageBaseName, MergeBaseName, "; - $q.= "UsersID, Comments, ClosureComment, RequestTS) VALUES (" . $type_id . ", "; - $q.= $base_id . ", " . $dbh->quote($pkgbase_name) . ", "; - $q.= $dbh->quote($merge_into) . ", " . $uid . ", "; - $q.= $dbh->quote($comments) . ", '', " . strval(time()) . ")"; - $dbh->exec($q); - $request_id = $dbh->lastInsertId(); - - /* Send e-mail notifications. */ - $params = array('request-open', $uid, $request_id, $type, $base_id); - if ($type === 'merge') { - $params[] = $merge_into; - } - notify($params); - - $auto_orphan_age = config_get('options', 'auto_orphan_age'); - $auto_delete_age = config_get('options', 'auto_delete_age'); - $details = pkgbase_get_details($base_id); - if ($type == 'orphan' && $details['OutOfDateTS'] > 0 && - time() - $details['OutOfDateTS'] >= $auto_orphan_age && - $auto_orphan_age > 0) { - /* - * Close package request. NOTE: This needs to happen *before* - * the actual disown operation. Otherwise, the former - * maintainer will not be included in the Cc list of the - * request notification email. - */ - $out_of_date_time = date("Y-m-d", intval($details["OutOfDateTS"])); - pkgreq_close($request_id, "accepted", - "The package base has been flagged out-of-date " . - "since " . $out_of_date_time . ".", true); - $q = "UPDATE PackageBases SET MaintainerUID = NULL "; - $q.= "WHERE ID = " . $base_id; - $dbh->exec($q); - } else if ($type == 'deletion' && $details['MaintainerUID'] == $uid && - $details['SubmittedTS'] > 0 && $auto_delete_age > 0 && - time() - $details['SubmittedTS'] <= $auto_delete_age) { - /* - * Close package request. NOTE: This needs to happen *before* - * the actual deletion operation. Otherwise, the former - * maintainer will not be included in the Cc list of the - * request notification email. - */ - pkgreq_close($request_id, "accepted", - "Deletion of a fresh package requested by its " . - "current maintainer.", true); - pkgbase_delete(array($base_id), NULL, NULL, true); - } - - return array(true, __("Added request successfully.")); -} - -/** - * Close a deletion/orphan request - * - * @param int $id The package request to close - * @param string $reason Whether the request was accepted or rejected - * @param string $comments Comments to be added to the notification email - * @param boolean $auto_close (optional) Whether the request is auto-closed - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgreq_close($id, $reason, $comments, $auto_close=false) { - switch ($reason) { - case 'accepted': - $status = 2; - break; - case 'rejected': - $status = 3; - break; - default: - return array(false, __("Invalid reason.")); - } - - $dbh = DB::connect(); - $id = intval($id); - $uid = $auto_close ? 0 : uid_from_sid($_COOKIE["AURSID"]); - - if (!$auto_close && !has_credential(CRED_PKGREQ_CLOSE)) { - return array(false, __("Only TUs and developers can close requests.")); - } - - $q = "UPDATE PackageRequests SET Status = " . intval($status) . ", "; - $q.= "ClosedTS = " . strval(time()) . ", "; - $q.= "ClosedUID = " . ($uid == 0 ? "NULL" : intval($uid)) . ", "; - $q.= "ClosureComment = " . $dbh->quote($comments) . " "; - $q.= "WHERE ID = " . intval($id); - $dbh->exec($q); - - /* Send e-mail notifications. */ - notify(array('request-close', $uid, $id, $reason)); - - return array(true, __("Request closed successfully.")); -} diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php deleted file mode 100644 index 73c667d2..00000000 --- a/web/lib/routing.inc.php +++ /dev/null @@ -1,85 +0,0 @@ - 'home.php', - '/index.php' => 'home.php', - '/packages' => 'packages.php', - '/pkgbase' => 'pkgbase.php', - '/requests' => 'pkgreq.php', - '/register' => 'register.php', - '/account' => 'account.php', - '/accounts' => 'account.php', - '/login' => 'login.php', - '/logout' => 'logout.php', - '/passreset' => 'passreset.php', - '/rpc' => 'rpc.php', - '/rss/modified' => 'modified-rss.php', - '/rss' => 'rss.php', - '/tos' => 'tos.php', - '/tu' => 'tu.php', - '/addvote' => 'addvote.php', -); - -$PKG_PATH = '/packages'; -$PKGBASE_PATH = '/pkgbase'; -$PKGREQ_PATH = '/requests'; -$USER_PATH = '/account'; - -function get_route($path) { - global $ROUTES; - - $path = rtrim($path, '/'); - if (isset($ROUTES[$path])) { - return $ROUTES[$path]; - } else { - return NULL; - } -} - -function get_uri($path, $absolute=false) { - if ($absolute) { - return rtrim(aur_location(), '/') . $path; - } else { - return $path; - } -} - -function get_pkg_route() { - global $PKG_PATH; - return $PKG_PATH; -} - -function get_pkgbase_route() { - global $PKGBASE_PATH; - return $PKGBASE_PATH; -} - -function get_pkgreq_route() { - global $PKGREQ_PATH; - return $PKGREQ_PATH; -} - -function get_pkg_uri($pkgname, $absolute=false) { - global $PKG_PATH; - $path = $PKG_PATH . '/' . urlencode($pkgname) . '/'; - return get_uri($path, $absolute); -} - -function get_pkgbase_uri($pkgbase_name, $absolute=false) { - global $PKGBASE_PATH; - $path = $PKGBASE_PATH . '/' . urlencode($pkgbase_name) . '/'; - return get_uri($path, $absolute); -} - -function get_user_route() { - global $USER_PATH; - return $USER_PATH; -} - -function get_user_uri($username, $absolute=false) { - global $USER_PATH; - $path = $USER_PATH . '/' . urlencode($username) . '/'; - return get_uri($path, $absolute); -} diff --git a/web/lib/stats.inc.php b/web/lib/stats.inc.php deleted file mode 100644 index f5692f96..00000000 --- a/web/lib/stats.inc.php +++ /dev/null @@ -1,108 +0,0 @@ -query($q); - - $newest_packages = new ArrayObject(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $newest_packages->append($row); - } - set_cache_value($key, $newest_packages); - } - } - include('stats/updates_table.php'); -} - -/** - * Display a user's statistics table - * - * @param string $userid The user ID of the person to get package statistics for - * - * @return void - */ -function user_table($userid) { - $base_q = "SELECT COUNT(*) FROM PackageBases "; - $base_q.= "WHERE MaintainerUID = " . $userid . " "; - $base_q.= "AND PackagerUID IS NOT NULL"; - - $user_pkg_count = db_cache_value($base_q, 'user_pkg_count:' . $userid); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE OutOfDateTS IS NOT NULL "; - $q.= "AND MaintainerUID = " . $userid . " "; - $q.= "AND PackagerUID IS NOT NULL"; - - $flagged_outdated = db_cache_value($q, 'user_flagged_outdated:' . $userid); - - include('stats/user_table.php'); -} - -/** - * Display the general package statistics table - * - * @return void - */ -function general_stats_table() { - # AUR statistics - $q = "SELECT COUNT(*) FROM PackageBases WHERE PackagerUID IS NOT NULL"; - $pkg_count = db_cache_value($q, 'pkg_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE MaintainerUID IS NULL "; - $q.= "AND PackagerUID IS NOT NULL"; - $orphan_count = db_cache_value($q, 'orphan_count'); - - $q = "SELECT count(*) FROM Users"; - $user_count = db_cache_value($q, 'user_count'); - - $q = "SELECT count(*) FROM Users,AccountTypes WHERE Users.AccountTypeID = AccountTypes.ID AND (AccountTypes.AccountType = 'Trusted User' OR AccountTypes.AccountType = 'Trusted User & Developer')"; - $tu_count = db_cache_value($q, 'tu_count'); - - $targstamp = intval(strtotime("-7 days")); - $yearstamp = intval(strtotime("-1 year")); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE SubmittedTS >= $targstamp "; - $q.= "AND PackagerUID IS NOT NULL"; - $add_count = db_cache_value($q, 'add_count'); - - /* - * A package whose last modification time differs less than an hour - * from the initial submission time is considered new. - */ - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS >= $targstamp "; - $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $update_count = db_cache_value($q, 'update_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS >= $yearstamp "; - $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $update_year_count = db_cache_value($q, 'update_year_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS - SubmittedTS < 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $never_update_count = db_cache_value($q, 'never_update_count'); - - include('stats/general_stats_table.php'); -} diff --git a/web/lib/streams.php b/web/lib/streams.php deleted file mode 100644 index 00cf6cc5..00000000 --- a/web/lib/streams.php +++ /dev/null @@ -1,167 +0,0 @@ -. - - This file is part of PHP-gettext. - - PHP-gettext is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PHP-gettext 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PHP-gettext; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - - - // Simple class to wrap file streams, string streams, etc. - // seek is essential, and it should be byte stream -class StreamReader { - // should return a string [FIXME: perhaps return array of bytes?] - function read($bytes) { - return false; - } - - // should return new position - function seekto($position) { - return false; - } - - // returns current position - function currentpos() { - return false; - } - - // returns length of entire stream (limit for seekto()s) - function length() { - return false; - } -}; - -class StringReader { - var $_pos; - var $_str; - - function __construct($str='') { - $this->_str = $str; - $this->_pos = 0; - } - - function read($bytes) { - $data = substr($this->_str, $this->_pos, $bytes); - $this->_pos += $bytes; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - - return $data; - } - - function seekto($pos) { - $this->_pos = $pos; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return strlen($this->_str); - } - -}; - - -class FileReader { - var $_pos; - var $_fd; - var $_length; - - function __construct($filename) { - if (file_exists($filename)) { - - $this->_length=filesize($filename); - $this->_pos = 0; - $this->_fd = fopen($filename,'rb'); - if (!$this->_fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - } else { - $this->error = 2; // File doesn't exist - return false; - } - } - - function read($bytes) { - if ($bytes) { - fseek($this->_fd, $this->_pos); - - // PHP 5.1.1 does not read more than 8192 bytes in one fread() - // the discussions at PHP Bugs suggest it's the intended behaviour - $data = ''; - while ($bytes > 0) { - $chunk = fread($this->_fd, $bytes); - $data .= $chunk; - $bytes -= strlen($chunk); - } - $this->_pos = ftell($this->_fd); - - return $data; - } else return ''; - } - - function seekto($pos) { - fseek($this->_fd, $pos); - $this->_pos = ftell($this->_fd); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return $this->_length; - } - - function close() { - fclose($this->_fd); - } - -}; - -// Preloads entire file in memory first, then creates a StringReader -// over it (it assumes knowledge of StringReader internals) -class CachedFileReader extends StringReader { - function __construct($filename) { - if (file_exists($filename)) { - - $length=filesize($filename); - $fd = fopen($filename,'rb'); - - if (!$fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - $this->_str = fread($fd, $length); - fclose($fd); - - } else { - $this->error = 2; // File doesn't exist - return false; - } - } -}; - - -?> diff --git a/web/lib/timezone.inc.php b/web/lib/timezone.inc.php deleted file mode 100644 index 949f846d..00000000 --- a/web/lib/timezone.inc.php +++ /dev/null @@ -1,63 +0,0 @@ - Displayed Description - */ -function generate_timezone_list() { - $php_timezones = DateTimeZone::listIdentifiers(DateTimeZone::ALL); - - $offsets = array(); - foreach ($php_timezones as $timezone) { - $tz = new DateTimeZone($timezone); - $offset = $tz->getOffset(new DateTime()); - $offsets[$timezone] = "(UTC" . ($offset < 0 ? "-" : "+") . gmdate("H:i", abs($offset)) . - ") " . $timezone; - } - - asort($offsets); - return $offsets; -} - -/** - * Set the timezone for the user. - * - * @return null - */ -function set_tz() { - $timezones = generate_timezone_list(); - $update_cookie = false; - - if (isset($_COOKIE["AURTZ"])) { - $timezone = $_COOKIE["AURTZ"]; - } elseif (isset($_COOKIE["AURSID"])) { - $dbh = DB::connect(); - $q = "SELECT Timezone FROM Users, Sessions "; - $q .= "WHERE Users.ID = Sessions.UsersID "; - $q .= "AND Sessions.SessionID = "; - $q .= $dbh->quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - - if ($result) { - $timezone = $result->fetchColumn(0); - if (!$timezone) { - unset($timezone); - } - } - - $update_cookie = true; - } - - if (!isset($timezone) || !array_key_exists($timezone, $timezones)) { - $timezone = config_get("options", "default_timezone"); - } - date_default_timezone_set($timezone); - - if ($update_cookie) { - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURTZ", $timezone, $cookie_time, "/"); - } -} diff --git a/web/lib/translator.inc.php b/web/lib/translator.inc.php deleted file mode 100644 index cbed1274..00000000 --- a/web/lib/translator.inc.php +++ /dev/null @@ -1,139 +0,0 @@ -", ""); - -include_once("confparser.inc.php"); -include_once('DB.class.php'); -include_once('gettext.php'); -include_once('streams.php'); - -global $streamer, $l10n; - -# Languages we have translations for -$SUPPORTED_LANGS = array( - "ar" => "العربية", - "ast" => "Asturianu", - "ca" => "Català", - "cs" => "Český", - "da" => "Dansk", - "de" => "Deutsch", - "en" => "English", - "el" => "Ελληνικά", - "es" => "Español", - "es_419" => "Español (Latinoamérica)", - "fi" => "Suomi", - "fr" => "Français", - "he" => "עברית", - "hr" => "Hrvatski", - "hu" => "Magyar", - "it" => "Italiano", - "ja" => "日本語", - "nb" => "Norsk", - "nl" => "Nederlands", - "pl" => "Polski", - "pt_BR" => "Português (Brasil)", - "pt_PT" => "Português (Portugal)", - "ro" => "Română", - "ru" => "Русский", - "sk" => "Slovenčina", - "sr" => "Srpski", - "tr" => "Türkçe", - "uk" => "Українська", - "zh_CN" => "简体中文", - "zh_TW" => "正體中文" -); - -function __() { - global $LANG; - global $l10n; - - # Create the translation. - $args = func_get_args(); - - # First argument is always string to be translated - $tag = array_shift($args); - - # Translate using gettext_reader initialized before. - $translated = $l10n->translate($tag); - $translated = htmlspecialchars($translated, ENT_QUOTES); - - # Subsequent arguments are strings to be formatted - if (count($args) > 0) { - $translated = vsprintf($translated, $args); - } - - return $translated; -} - -function _n($msgid1, $msgid2, $n) { - global $l10n; - - $translated = sprintf($l10n->ngettext($msgid1, $msgid2, $n), $n); - return htmlspecialchars($translated, ENT_QUOTES); -} - -# set up the visitor's language -# -function set_lang() { - global $LANG; - global $SUPPORTED_LANGS; - global $streamer, $l10n; - - $update_cookie = 0; - if (isset($_POST['setlang'])) { - # visitor is requesting a language change - # - $LANG = $_POST['setlang']; - $update_cookie = 1; - - } elseif (isset($_COOKIE['AURLANG'])) { - # If a cookie is set, use that - # - $LANG = $_COOKIE['AURLANG']; - - } elseif (isset($_COOKIE["AURSID"])) { - # No language but a session; use default lang preference - # - $dbh = DB::connect(); - $q = "SELECT LangPreference FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = "; - $q.= $dbh->quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - - if ($result) { - $LANG = $result->fetchColumn(0); - if (!$LANG) { - unset($LANG); - } - } - $update_cookie = 1; - } - - # Set $LANG to default if nothing is valid. - if (!isset($LANG) || !array_key_exists($LANG, $SUPPORTED_LANGS)) { - $LANG = config_get('options', 'default_lang'); - } - - if ($update_cookie) { - $timeout = intval(config_get('options', 'persistent_cookie_timeout')); - $cookie_time = time() + $timeout; - setcookie("AURLANG", $LANG, $cookie_time, "/"); - } - - $localedir = config_get('options', 'localedir'); - $streamer = new FileReader($localedir . '/' . $LANG . - '/LC_MESSAGES/aurweb.mo'); - $l10n = new gettext_reader($streamer, true); - - return; -} diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php deleted file mode 100644 index 81d960bc..00000000 --- a/web/lib/version.inc.php +++ /dev/null @@ -1,2 +0,0 @@ - - ' . htmlspecialchars($username) . '') ?> -

    -

    - ', '') ?> -

    - -
    -
    - - - -
    -
    -

    - - -

    - -

    - -

    - -

    - " /> -

    -
    -
    diff --git a/web/template/account_details.php b/web/template/account_details.php deleted file mode 100644 index 84f8b9c5..00000000 --- a/web/template/account_details.php +++ /dev/null @@ -1,93 +0,0 @@ - - - - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - " . __("hidden") . ""; - else: - ?> - "> - -
    " rel="nofollow">
    - -
    format('Y-m-d') ?>
    - -
    Links:
      -
    • - -
    • - - -
    • - -
    -
    diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php deleted file mode 100644 index 4ce6b875..00000000 --- a/web/template/account_edit_form.php +++ /dev/null @@ -1,222 +0,0 @@ - -

    - ', '') ?> - ', '') ?> - ', '') ?> -

    - -
    - - - -
    - - - - - -
    -
    -

    - - () -

    -

    - -

    - -

    - - -

    - -

    - - - - - - -

    - - - -

    - - /> -

    - - -

    - - () -

    -

    - -

    - -

    - - /> -

    -

    - -

    - -

    - - -

    -

    - - - - " . __("Hide Email Address") . "") ?> - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    -

    - - -

    -
    - - -
    - -

    - - -

    - -

    - - -

    -
    - - -
    - -

    - - -

    -
    - -
    - : -

    - - /> -

    -

    - - /> -

    -

    - - /> -

    -
    - -
    - - -

    - - -

    - - -

    - - () - -

    - -
    - -
    -

    - - - " />   - - " />   - - " /> -

    -
    -
    diff --git a/web/template/account_search_results.php b/web/template/account_search_results.php deleted file mode 100644 index 0f7eb7a4..00000000 --- a/web/template/account_search_results.php +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - $row): ?> - - - - - - - - - - - -
    "> - - - - "> - -   - -
    - - - - - - -
    -
    -
    - - - $ind): - ?> - - - " /> -
    -
    -
    -
    -
    - - - $ind): - ?> - - - -->" /> -
    -
    -
    - -

    - -

    - - diff --git a/web/template/cgit/footer.html b/web/template/cgit/footer.html deleted file mode 100644 index 14c358f1..00000000 --- a/web/template/cgit/footer.html +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/web/template/cgit/header.html b/web/template/cgit/header.html deleted file mode 100644 index 2d418702..00000000 --- a/web/template/cgit/header.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/web/template/comaintainers_form.php b/web/template/comaintainers_form.php deleted file mode 100644 index f61d494c..00000000 --- a/web/template/comaintainers_form.php +++ /dev/null @@ -1,19 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
    -
    - -

    - - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php deleted file mode 100644 index dc285a97..00000000 --- a/web/template/flag_comment.php +++ /dev/null @@ -1,26 +0,0 @@ -
    -

    -

    - - ', html_format_username($message['Username']), '', - '', htmlspecialchars($pkgbase_name), '', - '', date('Y-m-d', $message['OutOfDateTS']), ''); ?> - - ', htmlspecialchars($pkgbase_name), ''); ?> - -

    - -

    -

    -

    -
    -

    - -

    -

    - " /> -
    -

    -
    diff --git a/web/template/footer.php b/web/template/footer.php deleted file mode 100644 index 7f97aae0..00000000 --- a/web/template/footer.php +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/web/template/header.php b/web/template/header.php deleted file mode 100644 index 9631be91..00000000 --- a/web/template/header.php +++ /dev/null @@ -1,82 +0,0 @@ -'; ?> - - - - AUR (<?= htmlspecialchars($LANG); ?>)<?php if ($title != "") { print " - " . htmlspecialchars($title); } ?> - - - - ' /> - ' /> - - - - - - - - -
    -
    -
    "> -
    -
    - - -
    -
    -
    -
    -
    -
      - -
    • -
    • - -
    • - - -
    • - -
    • -
    • -
    • - -
    • AUR
    • -
    • -
    • - -
    • - -
    • - - -
    -
    - diff --git a/web/template/pkg_comment_box.php b/web/template/pkg_comment_box.php deleted file mode 100644 index 22f90d4a..00000000 --- a/web/template/pkg_comment_box.php +++ /dev/null @@ -1,4 +0,0 @@ -
    -

    - -
    diff --git a/web/template/pkg_comment_form.php b/web/template/pkg_comment_form.php deleted file mode 100644 index e8a516e3..00000000 --- a/web/template/pkg_comment_form.php +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    -
    - " /> - - - - - -
    -

    - - ', "") ?> -

    -

    - -

    -

    - " /> - - - - - - -

    -
    -
    diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php deleted file mode 100644 index ffa9e137..00000000 --- a/web/template/pkg_comments.php +++ /dev/null @@ -1,239 +0,0 @@ - - - - -
    - -
    - -
    -

    - - - - - - - - - - - - -

    - - 1): ?> -

    - $pagestart): ?> - - - - - - - - - - - - -

    - -
    - - $row): ?> - ' . $date_fmtd . ''; - if ($comment_section == "package") { - if ($row['UserName']) { - $user_fmtd = html_format_username($row['UserName']); - $heading = __('%s commented on %s', $user_fmtd, $date_link); - } else { - $heading = __('Anonymous comment on %s', $date_link); - } - } elseif ($comment_section == "account") { - $pkg_uri = '' . htmlspecialchars($row['PackageBaseName']) . ''; - $heading = __('Commented on package %s on %s', $pkg_uri, $date_link); - } - - $is_deleted = $row['DelTS']; - $is_edited = $row['EditedTS']; - $is_pinned = $row['PinnedTS']; - - if ($uid && $is_deleted) { - $date_fmtd = date('Y-m-d H:i', $row['DelTS']); - $heading .= ' ('; - if ($row['DelUserName']) { - $user_fmtd = html_format_username($row['DelUserName']); - $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); - } else { - $heading .= __('deleted on %s', $date_fmtd); - } - $heading .= ')'; - } elseif ($uid && $is_edited) { - $date_fmtd = date('Y-m-d H:i', $row['EditedTS']); - $heading .= ' ('; - if ($row['EditUserName']) { - $user_fmtd = html_format_username($row['EditUserName']); - $heading .= __('edited on %s by %s', $date_fmtd, $user_fmtd); - } else { - $heading .= __('edited on %s', $date_fmtd); - } - $heading .= ')'; - } - - $comment_classes = "comment-header"; - if ($is_deleted) { - $comment_classes .= " comment-deleted"; - } - ?> -

    - - -
    -
    - - - - " /> - -
    -
    - - - -
    -
    - - - - " /> - -
    -
    - - - - <?= __('Edit comment') ?> - - - = 5)): ?> -
    -
    - - - " /> - - " /> - -
    -
    - - - -
    -
    - - - - " /> - -
    -
    - -

    -
    -
    - - - -

    - -

    - -
    -
    - -
    - - diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php deleted file mode 100644 index 25d85b78..00000000 --- a/web/template/pkg_details.php +++ /dev/null @@ -1,317 +0,0 @@ - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0): -?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - (, ) - -
    () - -
    - -
    -
    - - - - - "/> - -
    -
    -' . htmlspecialchars($kw) . "\n"; - } -endif; -?> -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    = .2 ? 2 : 6) ?>
    - -
    -
    -

    - 0): ?> -
      - $darr): ?> -
    • - -
    - -
    -
    -

    - 0): ?> -
      - $darr): ?> -
    • - -
    - -
    -
    -

    -
    - 0): ?> -
    -
      - $src): ?> -
    • - -
    -
    - -
    -
    - - diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php deleted file mode 100644 index 3d0cde6c..00000000 --- a/web/template/pkg_search_form.php +++ /dev/null @@ -1,120 +0,0 @@ - __('Name, Description'), - 'n' => __('Name Only'), - 'b' => __('Package Base'), - 'N' => __('Exact Name'), - 'B' => __('Exact Package Base'), - 'k' => __('Keywords'), - 'm' => __('Maintainer'), - 'c' => __('Co-maintainer'), - 'M' => __('Maintainer, Co-maintainer'), - 's' => __('Submitter') -); - -$outdated_flags = array( - '' => __('All'), - 'on' => __('Flagged'), - 'off' => __('Not Flagged') -); - -$sortby = array( - 'n' => __('Name'), - 'v' => __('Votes'), - 'p' => __('Popularity'), - 'w' => __('Voted'), - 'o' => __('Notify'), - 'm' => __('Maintainer'), - 'l' => __('Last modified') -); - -$orderby = array( - 'a' => __('Ascending'), - 'd' => __('Descending') -); - -$per_page = array(50, 100, 250); -?> - - diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php deleted file mode 100644 index 61335560..00000000 --- a/web/template/pkg_search_results.php +++ /dev/null @@ -1,153 +0,0 @@ -'; - if ($sb) { - echo '' . $title . ''; - } else { - echo $title; - } - if ($hint) { - echo '?'; - } - echo ''; - }; -} else { - $fmtth = function($title, $sb=false, $so=false, $hint=false) { - echo '' . $title . ''; - }; -} - -if (!$result): ?> -

    - -

    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - -
    - - - - - - - - - - - - - - - - - - - - - $row): ?> - - - - - - class="flagged"> - - - - - - - - - - - - -
     
    ]" value="1" />"> - - - - - - - - - - - - - - - - - -
    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - -

    - - - - - - - - " /> -

    - - -
    - diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php deleted file mode 100644 index 3d208328..00000000 --- a/web/template/pkgbase_actions.php +++ /dev/null @@ -1,49 +0,0 @@ - diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php deleted file mode 100644 index bde29c1c..00000000 --- a/web/template/pkgbase_details.php +++ /dev/null @@ -1,146 +0,0 @@ - -
    -

    - - - - - - - - - 0): -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - (, ) - -
    () - -
    - -
    -
    - - - - - "/> - -
    -
    -' . htmlspecialchars($kw) . "\n"; - } -endif; -?> -
    = .2 ? 2 : 6) ?>
    - -
    -
    -

    - 0): ?> -
      - $pkg): -?> -
    • - -
    - -
    -
    -
    - - diff --git a/web/template/pkgreq_close_form.php b/web/template/pkgreq_close_form.php deleted file mode 100644 index 6228f6ab..00000000 --- a/web/template/pkgreq_close_form.php +++ /dev/null @@ -1,31 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -

    - : - -

    -
    -
    - - -

    - - -

    -

    - - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php deleted file mode 100644 index 9d74093e..00000000 --- a/web/template/pkgreq_form.php +++ /dev/null @@ -1,81 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
      - -
    • - -
    -
    -
    - - - -

    - - -

    - - -

    - - -

    -

    - - -

    -

    - -

    -

    - -

    -

    - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php deleted file mode 100644 index 1a565c3e..00000000 --- a/web/template/pkgreq_results.php +++ /dev/null @@ -1,129 +0,0 @@ - -

    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - - - - - - - - - - - - - - - $row): ?> - $idle_time); - if (!$due) { - $time_left = $idle_time - (time() - intval($row['RequestTS'])); - if ($time_left > 48 * 3600) { - $time_left_fmt = _n("~%d day left", "~%d days left", round($time_left / (24 * 3600))); - } elseif ($time_left > 3600) { - $time_left_fmt = _n("~%d hour left", "~%d hours left", round($time_left / 3600)); - } else { - $time_left_fmt = __("<1 hour left"); - } - } - ?> - - - - - - - - - - - - - - class="flagged"> - - - - - - - - - - - - - - - - - -
    "> - - - () - - - - - - - - - - - - - () - -
    - - -
    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - diff --git a/web/template/search_accounts_form.php b/web/template/search_accounts_form.php deleted file mode 100644 index f7824a94..00000000 --- a/web/template/search_accounts_form.php +++ /dev/null @@ -1,52 +0,0 @@ -
    -
    -
    - -
    -
    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - " />   - " /> -

    -
    -
    diff --git a/web/template/stats/general_stats_table.php b/web/template/stats/general_stats_table.php deleted file mode 100644 index 9dcc3aaf..00000000 --- a/web/template/stats/general_stats_table.php +++ /dev/null @@ -1,36 +0,0 @@ -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php deleted file mode 100644 index 23a86288..00000000 --- a/web/template/stats/updates_table.php +++ /dev/null @@ -1,19 +0,0 @@ -

    ()

    - -RSS Feed -RSS Feed - - - - getIterator() as $row): ?> - - - - - - -
    - " title=""> - - -
    diff --git a/web/template/stats/user_table.php b/web/template/stats/user_table.php deleted file mode 100644 index e7b00834..00000000 --- a/web/template/stats/user_table.php +++ /dev/null @@ -1,21 +0,0 @@ - - -

    - - - - - - - - - - -
    - - -
    - -
    diff --git a/web/template/template.phps b/web/template/template.phps deleted file mode 100644 index f1a0bb0d..00000000 --- a/web/template/template.phps +++ /dev/null @@ -1,19 +0,0 @@ -\n"; - - -html_footer(AURWEB_VERSION); diff --git a/web/template/tu_details.php b/web/template/tu_details.php deleted file mode 100644 index d739060d..00000000 --- a/web/template/tu_details.php +++ /dev/null @@ -1,123 +0,0 @@ - 0) { - $participation = $total / $active_tus; -} else { - $participation = 0; -} - -if ($yes > $active_tus / 2) { - $vote_accepted = true; -} elseif ($participation > $quorum && $yes > $no) { - $vote_accepted = true; -} else { - $vote_accepted = false; -} -?> -
    -

    - - -

    - -

    - - -

    - : - - - - - N/A - - -
    - -
    - : - - -
    - : - - - - - - - - -

    - -

    - \n", htmlspecialchars($row['Agenda'])) ?> -

    - - - - - - - - - - - - - - - - - - - - - 0): ?> - - - - - -
    - - - - - - %
    -
    - - -
    -

    -
      - -
    • - -
    -
    - - -
    - - -
    -
    - " /> - " /> - " /> - - -
    -
    - - -
    diff --git a/web/template/tu_last_votes_list.php b/web/template/tu_last_votes_list.php deleted file mode 100644 index 6e852581..00000000 --- a/web/template/tu_last_votes_list.php +++ /dev/null @@ -1,36 +0,0 @@ -
    -

    - - - - - - - - - - - - $row): - if ($indx % 2): - $c = "even"; - else: - $c = "odd"; - endif; - $username = username_from_id($row["UserID"]); - ?> - - - - - - -
    - - - -
    -
    diff --git a/web/template/tu_list.php b/web/template/tu_list.php deleted file mode 100644 index 204c89ea..00000000 --- a/web/template/tu_list.php +++ /dev/null @@ -1,82 +0,0 @@ -
    -

    - - -
      -
    • -
    - - - -

    - - - - - - - - - - - - - - - - - - $row): ?> - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - -
    -

    - - 0 && $off != 0): - $back = (($off - $limit) <= 0) ? 0 : $off - $limit; ?> - ?off=&by='>‹ - - - - - -

    - -
    From ad61c443f47686f41315735341cf53b4464cf0e0 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 29 Apr 2023 09:55:54 +0200 Subject: [PATCH 1735/1891] fix: restore & move cgit html files restore files accidentally deleted with PHP cleanup. https://gitlab.archlinux.org/archlinux/aurweb/-/tree/1325c71712a12c529d7a3defa9cbabfad296922e/web/template/cgit Signed-off-by: moson-mo --- conf/cgitrc.proto | 4 ++-- docker/cgit-entrypoint.sh | 4 ++-- static/html/cgit/footer.html | 6 ++++++ static/html/cgit/header.html | 15 +++++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 static/html/cgit/footer.html create mode 100644 static/html/cgit/header.html diff --git a/conf/cgitrc.proto b/conf/cgitrc.proto index 1b3eacbd..ed53c51c 100644 --- a/conf/cgitrc.proto +++ b/conf/cgitrc.proto @@ -20,8 +20,8 @@ cache-static-ttl=60 root-title=AUR Package Repositories root-desc=Web interface to the AUR Package Repositories -header=/srv/http/aurweb/web/template/cgit/header.html -footer=/srv/http/aurweb/web/template/cgit/footer.html +header=/srv/http/aurweb/static/html/cgit/header.html +footer=/srv/http/aurweb/static/html/cgit/footer.html max-repodesc-length=50 max-blob-size=2048 max-stats=year diff --git a/docker/cgit-entrypoint.sh b/docker/cgit-entrypoint.sh index a44675e2..282430e2 100755 --- a/docker/cgit-entrypoint.sh +++ b/docker/cgit-entrypoint.sh @@ -5,8 +5,8 @@ mkdir -p /var/data/cgit cp -vf conf/cgitrc.proto /etc/cgitrc sed -ri "s|clone-prefix=.*|clone-prefix=${CGIT_CLONE_PREFIX}|" /etc/cgitrc -sed -ri 's|header=.*|header=/aurweb/web/template/cgit/header.html|' /etc/cgitrc -sed -ri 's|footer=.*|footer=/aurweb/web/template/cgit/footer.html|' /etc/cgitrc +sed -ri 's|header=.*|header=/aurweb/static/html/cgit/header.html|' /etc/cgitrc +sed -ri 's|footer=.*|footer=/aurweb/static/html/cgit/footer.html|' /etc/cgitrc sed -ri 's|repo\.path=.*|repo.path=/aurweb/aur.git|' /etc/cgitrc sed -ri "s|^(css)=.*$|\1=${CGIT_CSS}|" /etc/cgitrc diff --git a/static/html/cgit/footer.html b/static/html/cgit/footer.html new file mode 100644 index 00000000..b3e79568 --- /dev/null +++ b/static/html/cgit/footer.html @@ -0,0 +1,6 @@ + diff --git a/static/html/cgit/header.html b/static/html/cgit/header.html new file mode 100644 index 00000000..2d418702 --- /dev/null +++ b/static/html/cgit/header.html @@ -0,0 +1,15 @@ + From bab17a9d262e1f184deece9003e67df8baae01c4 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 29 Apr 2023 09:59:34 +0200 Subject: [PATCH 1736/1891] doc: amend INSTALL instructions change path for metadata archive files Signed-off-by: moson-mo --- INSTALL | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/INSTALL b/INSTALL index 107fab4b..c6c71ca7 100644 --- a/INSTALL +++ b/INSTALL @@ -30,9 +30,6 @@ read the instructions below. ssl_certificate /etc/ssl/certs/aur.cert.pem; ssl_certificate_key /etc/ssl/private/aur.key.pem; - # Asset root. This is used to match against gzip archives. - root /srv/http/aurweb/web/html; - # TU Bylaws redirect. location = /trusted-user/TUbylaws.html { return 301 https://tu-bylaws.aur.archlinux.org; @@ -62,6 +59,9 @@ read the instructions below. # Static archive assets. location ~ \.gz$ { + # Asset root. This is used to match against gzip archives. + root /srv/http/aurweb/archives; + types { application/gzip text/plain } default_type text/plain; add_header Content-Encoding gzip; From e896edaccc3ef5666298d3c1a42816d35c8d2950 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sun, 30 Apr 2023 10:12:09 +0100 Subject: [PATCH 1737/1891] chore: support for python 3.11 and poetry.lock update Signed-off-by: Leonidas Spyropoulos --- poetry.lock | 259 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 128 insertions(+), 133 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1b98a5b8..5e933e70 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.10.3" +version = "1.10.4" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.10.3-py3-none-any.whl", hash = "sha256:b2e0a6cfd3a8ce936a1168320bcbe94aefa3f4463cd773a968a55071beb3cd37"}, - {file = "alembic-1.10.3.tar.gz", hash = "sha256:32a69b13a613aeb7e8093f242da60eff9daed13c0df02fff279c1b06c32965d2"}, + {file = "alembic-1.10.4-py3-none-any.whl", hash = "sha256:43942c3d4bf2620c466b91c0f4fca136fe51ae972394a0cc8b90810d664e4f5c"}, + {file = "alembic-1.10.4.tar.gz", hash = "sha256:295b54bbb92c4008ab6a7dcd1e227e668416d6f84b98b3c4446a2bc6214a556b"}, ] [package.dependencies] @@ -352,63 +352,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.3" +version = "7.2.4" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5"}, - {file = "coverage-7.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4"}, - {file = "coverage-7.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2"}, - {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013"}, - {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa"}, - {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b"}, - {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257"}, - {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535"}, - {file = "coverage-7.2.3-cp310-cp310-win32.whl", hash = "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91"}, - {file = "coverage-7.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e"}, - {file = "coverage-7.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79"}, - {file = "coverage-7.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc"}, - {file = "coverage-7.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df"}, - {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623"}, - {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d"}, - {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93"}, - {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312"}, - {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4"}, - {file = "coverage-7.2.3-cp311-cp311-win32.whl", hash = "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925"}, - {file = "coverage-7.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910"}, - {file = "coverage-7.2.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c"}, - {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9"}, - {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1"}, - {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1"}, - {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21"}, - {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841"}, - {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48"}, - {file = "coverage-7.2.3-cp37-cp37m-win32.whl", hash = "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1"}, - {file = "coverage-7.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f"}, - {file = "coverage-7.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab"}, - {file = "coverage-7.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040"}, - {file = "coverage-7.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1"}, - {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911"}, - {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462"}, - {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c"}, - {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd"}, - {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152"}, - {file = "coverage-7.2.3-cp38-cp38-win32.whl", hash = "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22"}, - {file = "coverage-7.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367"}, - {file = "coverage-7.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235"}, - {file = "coverage-7.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21"}, - {file = "coverage-7.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934"}, - {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859"}, - {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9"}, - {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539"}, - {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe"}, - {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4"}, - {file = "coverage-7.2.3-cp39-cp39-win32.whl", hash = "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30"}, - {file = "coverage-7.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a"}, - {file = "coverage-7.2.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0"}, - {file = "coverage-7.2.3.tar.gz", hash = "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259"}, + {file = "coverage-7.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e5eedde6e6e241ec3816f05767cc77e7456bf5ec6b373fb29917f0990e2078f"}, + {file = "coverage-7.2.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c6c6e3b8fb6411a2035da78d86516bfcfd450571d167304911814407697fb7a"}, + {file = "coverage-7.2.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7668a621afc52db29f6867e0e9c72a1eec9f02c94a7c36599119d557cf6e471"}, + {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfb53bef4b2739ff747ebbd76d6ac5384371fd3c7a8af08899074eba034d483"}, + {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c4f2e44a2ae15fa6883898e756552db5105ca4bd918634cbd5b7c00e19e8a1"}, + {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:700bc9fb1074e0c67c09fe96a803de66663830420781df8dc9fb90d7421d4ccb"}, + {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ac4861241e693e21b280f07844ae0e0707665e1dfcbf9466b793584984ae45c4"}, + {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3d6f3c5b6738a494f17c73b4aa3aa899865cc33a74aa85e3b5695943b79ad3ce"}, + {file = "coverage-7.2.4-cp310-cp310-win32.whl", hash = "sha256:437da7d2fcc35bf45e04b7e9cfecb7c459ec6f6dc17a8558ed52e8d666c2d9ab"}, + {file = "coverage-7.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:1d3893f285fd76f56651f04d1efd3bdce251c32992a64c51e5d6ec3ba9e3f9c9"}, + {file = "coverage-7.2.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a17bf32e9e3333d78606ac1073dd20655dc0752d5b923fa76afd3bc91674ab4"}, + {file = "coverage-7.2.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f7ffdb3af2a01ce91577f84fc0faa056029fe457f3183007cffe7b11ea78b23c"}, + {file = "coverage-7.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89e63b38c7b888e00fd42ce458f838dccb66de06baea2da71801b0fc9070bfa0"}, + {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4522dd9aeb9cc2c4c54ce23933beb37a4e106ec2ba94f69138c159024c8a906a"}, + {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29c7d88468f01a75231797173b52dc66d20a8d91b8bb75c88fc5861268578f52"}, + {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bc47015fc0455753e8aba1f38b81b731aaf7f004a0c390b404e0fcf1d6c1d72f"}, + {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c122d120c11a236558c339a59b4b60947b38ac9e3ad30a0e0e02540b37bf536"}, + {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:50fda3d33b705b9c01e3b772cfa7d14de8aec2ec2870e4320992c26d057fde12"}, + {file = "coverage-7.2.4-cp311-cp311-win32.whl", hash = "sha256:ab08af91cf4d847a6e15d7d5eeae5fead1487caf16ff3a2056dbe64d058fd246"}, + {file = "coverage-7.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:876e4ef3eff00b50787867c5bae84857a9af4c369a9d5b266cd9b19f61e48ef7"}, + {file = "coverage-7.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3fc9cde48de956bfbacea026936fbd4974ff1dc2f83397c6f1968f0142c9d50b"}, + {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12bc9127c8aca2f7c25c9acca53da3db6799b2999b40f28c2546237b7ea28459"}, + {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2857894c22833d3da6e113623a9b7440159b2295280b4e0d954cadbfa724b85a"}, + {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4db4e6c115d869cd5397d3d21fd99e4c7053205c33a4ae725c90d19dcd178af"}, + {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f37ae1804596f13d811e0247ffc8219f5261b3565bdf45fcbb4fc091b8e9ff35"}, + {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdee9a77fd0ce000781680b6a1f4b721c567f66f2f73a49be1843ff439d634f3"}, + {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b65a6a5484b7f2970393d6250553c05b2ede069e0e18abe907fdc7f3528252e"}, + {file = "coverage-7.2.4-cp37-cp37m-win32.whl", hash = "sha256:1a3e8697cb40f28e5bcfb6f4bda7852d96dbb6f6fd7cc306aba4ae690c9905ab"}, + {file = "coverage-7.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:4078939c4b7053e14e87c65aa68dbed7867e326e450f94038bfe1a1b22078ff9"}, + {file = "coverage-7.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:603a2b172126e3b08c11ca34200143089a088cd0297d4cfc4922d2c1c3a892f9"}, + {file = "coverage-7.2.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72751d117ceaad3b1ea3bcb9e85f5409bbe9fb8a40086e17333b994dbccc0718"}, + {file = "coverage-7.2.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f19ba9301e6fb0b94ba71fda9a1b02d11f0aab7f8e2455122a4e2921b6703c2f"}, + {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d784177a7fb9d0f58d24d3e60638c8b729c3693963bf67fa919120f750db237"}, + {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d2a9180beff1922b09bd7389e23454928e108449e646c26da5c62e29b0bf4e3"}, + {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:39747afc854a7ee14e5e132da7db179d6281faf97dc51e6d7806651811c47538"}, + {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60feb703abc8d78e9427d873bcf924c9e30cf540a21971ef5a17154da763b60f"}, + {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2becddfcbf3d994a8f4f9dd2b6015cae3a3eff50dedc6e4a17c3cccbe8f93d4"}, + {file = "coverage-7.2.4-cp38-cp38-win32.whl", hash = "sha256:56a674ad18d6b04008283ca03c012be913bf89d91c0803c54c24600b300d9e51"}, + {file = "coverage-7.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:ab08e03add2cf5793e66ac1bbbb24acfa90c125476f5724f5d44c56eeec1d635"}, + {file = "coverage-7.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92b565c51732ea2e7e541709ccce76391b39f4254260e5922e08e00971e88e33"}, + {file = "coverage-7.2.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8769a67e8816c7e94d5bf446fc0501641fde78fdff362feb28c2c64d45d0e9b1"}, + {file = "coverage-7.2.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d74d6fbd5a98a5629e8467b719b0abea9ca01a6b13555d125c84f8bf4ea23d"}, + {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9f770c6052d9b5c9b0e824fd8c003fe33276473b65b4f10ece9565ceb62438e"}, + {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3023ce23e41a6f006c09f7e6d62b6c069c36bdc9f7de16a5ef823acc02e6c63"}, + {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fabd1f4d12dfd6b4f309208c2f31b116dc5900e0b42dbafe4ee1bc7c998ffbb0"}, + {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e41a7f44e73b37c6f0132ecfdc1c8b67722f42a3d9b979e6ebc150c8e80cf13a"}, + {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:864e36947289be05abd83267c4bade35e772526d3e9653444a9dc891faf0d698"}, + {file = "coverage-7.2.4-cp39-cp39-win32.whl", hash = "sha256:ea534200efbf600e60130c48552f99f351cae2906898a9cd924c1c7f2fb02853"}, + {file = "coverage-7.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:00f8fd8a5fe1ffc3aef78ea2dbf553e5c0f4664324e878995e38d41f037eb2b3"}, + {file = "coverage-7.2.4-pp37.pp38.pp39-none-any.whl", hash = "sha256:856bcb837e96adede31018a0854ce7711a5d6174db1a84e629134970676c54fa"}, + {file = "coverage-7.2.4.tar.gz", hash = "sha256:7283f78d07a201ac7d9dc2ac2e4faaea99c4d302f243ee5b4e359f3e170dc008"}, ] [package.dependencies] @@ -528,14 +528,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.11.0" +version = "2.11.2" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.11.0-py3-none-any.whl", hash = "sha256:156ef67713dd53000c28dd341be61a365c20230bc17c8fb8320b0c123e667aff"}, - {file = "fakeredis-2.11.0.tar.gz", hash = "sha256:d25883dc52c31546e586b6ec3c49c5999b3025bfc4812532d71dedcfed56fee1"}, + {file = "fakeredis-2.11.2-py3-none-any.whl", hash = "sha256:69a504328a89e5e5f2d05a4236b570fb45244c96997c5002c8c6a0503b95f289"}, + {file = "fakeredis-2.11.2.tar.gz", hash = "sha256:e0fef512b8ec49679d373456aa4698a4103005ecd7ca0b13170a2c1d3af949c5"}, ] [package.dependencies] @@ -1101,68 +1101,63 @@ files = [ [[package]] name = "orjson" -version = "3.8.10" +version = "3.8.11" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false python-versions = ">= 3.7" files = [ - {file = "orjson-3.8.10-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4dfe0651e26492d5d929bbf4322de9afbd1c51ac2e3947a7f78492b20359711d"}, - {file = "orjson-3.8.10-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bc30de5c7b3a402eb59cc0656b8ee53ca36322fc52ab67739c92635174f88336"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c08b426fae7b9577b528f99af0f7e0ff3ce46858dd9a7d1bf86d30f18df89a4c"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bce970f293825e008dbf739268dfa41dfe583aa2a1b5ef4efe53a0e92e9671ea"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b23fb0264bbdd7218aa685cb6fc71f0dcecf34182f0a8596a3a0dff010c06f9"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0826ad2dc1cea1547edff14ce580374f0061d853cbac088c71162dbfe2e52205"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7bce6e61cea6426309259b04c6ee2295b3f823ea51a033749459fe2dd0423b2"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0b470d31244a6f647e5402aac7d2abaf7bb4f52379acf67722a09d35a45c9417"}, - {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:48824649019a25d3e52f6454435cf19fe1eb3d05ee697e65d257f58ae3aa94d9"}, - {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:faee89e885796a9cc493c930013fa5cfcec9bfaee431ddf00f0fbfb57166a8b3"}, - {file = "orjson-3.8.10-cp310-none-win_amd64.whl", hash = "sha256:3cfe32b1227fe029a5ad989fbec0b453a34e5e6d9a977723f7c3046d062d3537"}, - {file = "orjson-3.8.10-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:2073b62822738d6740bd2492f6035af5c2fd34aa198322b803dc0e70559a17b7"}, - {file = "orjson-3.8.10-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b2c4faf20b6bb5a2d7ac0c16f58eb1a3800abcef188c011296d1dc2bb2224d48"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c1825997232a324911d11c75d91e1e0338c7b723c149cf53a5fc24496c048a4"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7e85d4682f3ed7321d36846cad0503e944ea9579ef435d4c162e1b73ead8ac9"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8cdaacecb92997916603ab232bb096d0fa9e56b418ca956b9754187d65ca06"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ddabc5e44702d13137949adee3c60b7091e73a664f6e07c7b428eebb2dea7bbf"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27bb26e171e9cfdbec39c7ca4739b6bef8bd06c293d56d92d5e3a3fc017df17d"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1810e5446fe68d61732e9743592da0ec807e63972eef076d09e02878c2f5958e"}, - {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:61e2e51cefe7ef90c4fbbc9fd38ecc091575a3ea7751d56fad95cbebeae2a054"}, - {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f3e9ac9483c2b4cd794e760316966b7bd1e6afb52b0218f068a4e80c9b2db4f6"}, - {file = "orjson-3.8.10-cp311-none-win_amd64.whl", hash = "sha256:26aee557cf8c93b2a971b5a4a8e3cca19780573531493ce6573aa1002f5c4378"}, - {file = "orjson-3.8.10-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:11ae68f995a50724032af297c92f20bcde31005e0bf3653b12bff9356394615b"}, - {file = "orjson-3.8.10-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:35d879b46b8029e1e01e9f6067928b470a4efa1ca749b6d053232b873c2dcf66"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:345e41abd1d9e3ecfb554e1e75ff818cf42e268bd06ad25a96c34e00f73a327e"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:45a5afc9cda6b8aac066dd50d8194432fbc33e71f7164f95402999b725232d78"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad632dc330a7b39da42530c8d146f76f727d476c01b719dc6743c2b5701aaf6b"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bf2556ba99292c4dc550560384dd22e88b5cdbe6d98fb4e202e902b5775cf9f"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b88afd662190f19c3bb5036a903589f88b1d2c2608fbb97281ce000db6b08897"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:abce8d319aae800fd2d774db1106f926dee0e8a5ca85998fd76391fcb58ef94f"}, - {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e999abca892accada083f7079612307d94dd14cc105a699588a324f843216509"}, - {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3fdee68c4bb3c5d6f89ed4560f1384b5d6260e48fbf868bae1a245a3c693d4d"}, - {file = "orjson-3.8.10-cp37-none-win_amd64.whl", hash = "sha256:e5d7f82506212e047b184c06e4bcd48c1483e101969013623cebcf51cf12cad9"}, - {file = "orjson-3.8.10-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:d953e6c2087dcd990e794f8405011369ee11cf13e9aaae3172ee762ee63947f2"}, - {file = "orjson-3.8.10-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:81aa3f321d201bff0bd0f4014ea44e51d58a9a02d8f2b0eeab2cee22611be8e1"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d27b6182f75896dd8c10ea0f78b9265a3454be72d00632b97f84d7031900dd4"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1486600bc1dd1db26c588dd482689edba3d72d301accbe4301db4b2b28bd7aa4"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344ea91c556a2ce6423dc13401b83ab0392aa697a97fa4142c2c63a6fd0bbfef"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:979f231e3bad1c835627eef1a30db12a8af58bfb475a6758868ea7e81897211f"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa3a26dcf0f5f2912a8ce8e87273e68b2a9526854d19fd09ea671b154418e88"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:b6e79d8864794635974b18821b49a7f27859d17b93413d4603efadf2e92da7a5"}, - {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ce49999bcbbc14791c61844bc8a69af44f5205d219be540e074660038adae6bf"}, - {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2ef690335b24f9272dbf6639353c1ffc3f196623a92b851063e28e9515cf7dd"}, - {file = "orjson-3.8.10-cp38-none-win_amd64.whl", hash = "sha256:5a0b1f4e4fa75e26f814161196e365fc0e1a16e3c07428154505b680a17df02f"}, - {file = "orjson-3.8.10-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:af7601a78b99f0515af2f8ab12c955c0072ffcc1e437fb2556f4465783a4d813"}, - {file = "orjson-3.8.10-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6bbd7b3a3e2030b03c68c4d4b19a2ef5b89081cbb43c05fe2010767ef5e408db"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4355c9aedfefe60904e8bd7901315ebbc8bb828f665e4c9bc94b1432e67cb6f7"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b0ba074375e25c1594e770e2215941e2017c3cd121889150737fa1123e8bfe"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34b6901c110c06ab9e8d7d0496db4bc9a0c162ca8d77f67539d22cb39e0a1ef4"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb62ec16a1c26ad9487727b529103cb6a94a1d4969d5b32dd0eab5c3f4f5a6f2"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595e1e7d04aaaa3d41113e4eb9f765ab642173c4001182684ae9ddc621bb11c8"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:64ffd92328473a2f9af059410bd10c703206a4bbc7b70abb1bedcd8761e39eb8"}, - {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b1f648ec89c6a426098868460c0ef8c86b457ce1378d7569ff4acb6c0c454048"}, - {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6a286ad379972e4f46579e772f0477e6b505f1823aabcd64ef097dbb4549e1a4"}, - {file = "orjson-3.8.10-cp39-none-win_amd64.whl", hash = "sha256:d2874cee6856d7c386b596e50bc517d1973d73dc40b2bd6abec057b5e7c76b2f"}, - {file = "orjson-3.8.10.tar.gz", hash = "sha256:dcf6adb4471b69875034afab51a14b64f1026bc968175a2bb02c5f6b358bd413"}, + {file = "orjson-3.8.11-cp310-cp310-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:9fa900bdd84b4576c8dd6f3e2a00b35797f29283af328c6e3d70addfa4c2d599"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1103e597c16f82c241e1b02beadc9c91cecd93e60433ca73cb6464dcc235f37c"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d70b6db9d4e1e6057829cd7fe119c217cebaf989f88d14b2445fa69fc568d03e"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3afccf7f8684dca7f017837a315de0a1ab5c095de22a4eed206d079f9325ed72"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fedcc428416e23a6c9de62a000c22ae33bbe0108302ad5d5935e29ea739bf37"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf48ed8d4b6ab9f23b7ee642462369d7133412d72824bad89f9bf4311c06c6a1"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c55065bc2075a5ea6ffb30462d84fd3aa5bbb7ae600855c325ee5753feec715"}, + {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:08729e339ff3146e6de56c1166f014c3d2ec3e79ffb76d6c55d52cc892e5e477"}, + {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:358e515b8b19a275b259f5ee1e0efa2859b1d976b5ed5d016ac59f9e6c8788a3"}, + {file = "orjson-3.8.11-cp310-none-win_amd64.whl", hash = "sha256:62eb8bdcf6f4cdbe12743e88ad98696277a75f91a35e8fb93a7ea2b9f4a7000c"}, + {file = "orjson-3.8.11-cp311-cp311-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:982ab319b7a5ece4199caf2a2b3a28e62a8e289cb6418548ef98bced7e2a6cfe"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e14903bfeb591a9117b7d40d81e3ebca9700b4e77bd829d6f22ea57941bb0ebf"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58c068f93d701f9466f667bf3b5cb4e4946aee940df2b07ca5101f1cf1b60ce4"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9486963d2e65482c565dacb366adb36d22aa22acf7274b61490244c3d87fa631"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c3b5405edc3a5f9e34516ee1a729f6c46aecf6de960ae07a7b3e95ebdd0e1d9"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b65424ceee82b94e3613233b67ef110dc58f9d83b0076ec47a506289552a861"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:173b8f8c750590f432757292cfb197582e5c14347b913b4017561d47af0e759b"}, + {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37f38c8194ce086e6a9816b4b8dde5e7f383feeed92feec0385d99baf64f9b6e"}, + {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:553fdaf9f4b5060a0dcc517ae0c511c289c184a83d6719d03c5602ed0eef0390"}, + {file = "orjson-3.8.11-cp311-none-win_amd64.whl", hash = "sha256:12f647d4da0aab1997e25bed4fa2b76782b5b9d2d1bf3066b5f0a57d34d833c4"}, + {file = "orjson-3.8.11-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:71a656f1c62e84c69060093e20cedff6a92e472d53ff5b8b9026b1b298542a68"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:176d742f53434541e50a5e659694073aa51dcbd8f29a1708a4fa1a320193c615"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b369019e597b59c4b97e9f925a3b725321fa1481c129d76c74c6ea3823f5d1e8"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a53b3c02a38aadc5302661c2ca18645093971488992df77ce14fef16f598b2e"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d7b050135669d2335e40120215ad4120e29958c139f8bab68ce06a1cb1a1b2c"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66f0c9e4e8f6641497a7dc50591af3704b11468e9fc90cfb5874f28b0a61edb5"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:235926b38ed9b76ab2bca99ff26ece79c1c46bc10079b06e660b087aecffbe69"}, + {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c2d3e6b65458ed71b6797f321d6e8bfeeadee9d3d31cac47806a608ea745edd7"}, + {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4118dcd2b5a27a22af5ad92414073f25d93bca1868f1f580056003c84841062f"}, + {file = "orjson-3.8.11-cp37-none-win_amd64.whl", hash = "sha256:b68a07794834b7bd53ae2a8b4fe4bf010734cae3f0917d434c83b97acf8e5bce"}, + {file = "orjson-3.8.11-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:98befa717efaab7ddb847ebe47d473f6bd6f0cb53e98e6c3d487c7c58ba2e174"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f9415b86ef154bf247fa78a6918aac50089c296e26fb6cf15bc9d7e6402a1f8"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7aeefac55848aeb29f20b91fa55f9e488f446201bb1bb31dc17480d113d8955"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d47f97b99beb9bcac6e288a76b559543a61e0187443d8089204b757726b1d000"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7d5aecccfaf2052cd07ed5bec8efba9ddfea055682fcd346047b1a3e9da3034"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b60dfc1251742e79bb075d7a7c4e37078b932a02e6f005c45761bd90c69189"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:ef52f1d5a2f89ef9049781c90ea35d5edf74374ed6ed515c286a706d1b290267"}, + {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7b4fae3b8fc69c8e76f1c0694f3decfe8a57f87e7ac7779ebb59cd71135438"}, + {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f4e4a1001933166fd1c257b920b241b35322bef99ed7329338bf266ac053abe7"}, + {file = "orjson-3.8.11-cp38-none-win_amd64.whl", hash = "sha256:5ff10789cbc08a9fd94507c907ba55b9315e99f20345ff8ef34fac432dacd948"}, + {file = "orjson-3.8.11-cp39-cp39-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:c67ac094a4dde914297543af19f22532d7124f3a35245580d8b756c4ff2f5884"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf201e77d3fac9d8d6f68d872ef45dccfe46f30b268bb88b6c5af5065b433aa"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3485c458670c0edb79ca149fe201f199dd9ccfe7ca3acbdef617e3c683e7b97f"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e97fdbb779a3b8f5d9fc7dfddef5325f81ee45897eb7cb4638d5d9734d42514"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2fc050f8e7f2e4061c8c9968ad0be745b11b03913b77ffa8ceca65914696886c"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2ef933da50b31c112b252be03d1ef59e0d0552c1a08e48295bd529ce42aaab8"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:714c3e2be6ed7e4ff6e887926d6e171bfd94fdee76d7d3bfa74ee19237a2d49d"}, + {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7e4ded77ac7432a155d1d27a83bcadf722750aea3b9e6c4d47f2a92054ab71cb"}, + {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:382f15861a4bf447ab9d07106010e61b217ef6d4245c6cf64af0c12c4c5e2346"}, + {file = "orjson-3.8.11-cp39-none-win_amd64.whl", hash = "sha256:0bc3d1b93a73b46a698c054697eb2d27bdedbc5ea0d11ec5f1a6bfbec36346b5"}, + {file = "orjson-3.8.11.tar.gz", hash = "sha256:882c77126c42dd93bb35288632d69b1e393863a2b752de3e5fe0112833609496"}, ] [[package]] @@ -1566,14 +1561,14 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.28.2" +version = "2.29.0" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, + {file = "requests-2.29.0-py3-none-any.whl", hash = "sha256:e8f3c9be120d3333921d213eef078af392fba3933ab7ed2d1cba3b56f2568c3b"}, + {file = "requests-2.29.0.tar.gz", hash = "sha256:f2e34a75f4749019bb0e3effb66683630e4ffeaf75819fb51bebef1bf5aef059"}, ] [package.dependencies] @@ -1606,14 +1601,14 @@ idna2008 = ["idna"] [[package]] name = "setuptools" -version = "67.7.1" +version = "67.7.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.7.1-py3-none-any.whl", hash = "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67"}, - {file = "setuptools-67.7.1.tar.gz", hash = "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c"}, + {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, + {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, ] [package.extras] @@ -1807,14 +1802,14 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.7" +version = "0.11.8" description = "Style preserving TOML library" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.11.7-py3-none-any.whl", hash = "sha256:5325463a7da2ef0c6bbfefb62a3dc883aebe679984709aee32a317907d0a8d3c"}, - {file = "tomlkit-0.11.7.tar.gz", hash = "sha256:f392ef70ad87a672f02519f99967d28a4d3047133e2d1df936511465fbb3791d"}, + {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, + {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, ] [[package]] @@ -1910,21 +1905,21 @@ files = [ [[package]] name = "werkzeug" -version = "2.2.3" +version = "2.3.2" description = "The comprehensive WSGI web application library." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, - {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, + {file = "Werkzeug-2.3.2-py3-none-any.whl", hash = "sha256:b7b8bc1609f35ae8e45d48a9b58d7a4eb1e41eec148d37e977e5df6ebf3398b2"}, + {file = "Werkzeug-2.3.2.tar.gz", hash = "sha256:2f3278e9ef61511cdf82cc28fc5da0f5b501dd8f01ecf5ef6a5d810048f68702"}, ] [package.dependencies] MarkupSafe = ">=2.1.1" [package.extras] -watchdog = ["watchdog"] +watchdog = ["watchdog (>=2.3)"] [[package]] name = "wsproto" @@ -1959,5 +1954,5 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" -python-versions = ">=3.9,<3.11" -content-hash = "b82180015aa365bf55c890e8a3be5e549fa52f4e62cf4619fb71870939dda170" +python-versions = ">=3.9,<3.12" +content-hash = "7eba1b2d0fd17dacea153cb3f6ebdcb11d7888902cbb3a88a65f3c6c38f65699" diff --git a/pyproject.toml b/pyproject.toml index eaaa7221..d75a1d4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ build-backend = "poetry.masonry.api" "Request Mailing List" = "https://lists.archlinux.org/listinfo/aur-requests" [tool.poetry.dependencies] -python = ">=3.9,<3.11" +python = ">=3.9,<3.12" # poetry-dynamic-versioning is used to produce tool.poetry.version # based on git tags. From b3fcfb7679029bb8d72b2ac02c6d294f47224c38 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 30 Apr 2023 20:24:24 +0200 Subject: [PATCH 1738/1891] doc: improve instructions for setting up a dev/test env Provide more detailed information how to get started with a dev/test env. Signed-off-by: moson-mo --- CONTRIBUTING.md | 2 + TESTING | 207 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 155 insertions(+), 54 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a91e3eec..1957ae22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,6 +97,8 @@ Accessible services (on the host): Docker services, by default, are setup to be hot reloaded when source code is changed. +For detailed setup instructions have a look at [TESTING](TESTING) + #### Using INSTALL The [INSTALL](INSTALL) file describes steps to install the application on diff --git a/TESTING b/TESTING index 078d330b..e9cbf33b 100644 --- a/TESTING +++ b/TESTING @@ -1,59 +1,130 @@ Setup Testing Environment ========================= +The quickest way to get you hacking on aurweb is to utilize docker. +In case you prefer to run it bare-metal see instructions further below. + +Containerized environment +------------------------- + +1) Clone the aurweb project: + + $ git clone https://gitlab.archlinux.org/archlinux/aurweb.git + $ cd aurweb + +2) Install the necessary packages: + + # pacman -S --needed docker docker-compose + +3) Build the aurweb:latest image: + + # systemctl start docker + # docker compose build + +4) Run local Docker development instance: + + # docker compose up -d + +5) Browse to local aurweb development server. + + https://localhost:8444/ + +6) [Optionally] populate the database with dummy data: + + # docker compose exec mariadb /bin/bash + # pacman -S --noconfirm words fortune-mod + # poetry run schema/gendummydata.py dummy_data.sql + # mariadb -uaur -paur aurweb < dummy_data.sql + # exit + + Inspect `dummy_data.sql` for test credentials. + Passwords match usernames. + +We now have fully set up environment which we can start and stop with: + + # docker compose start + # docker compose stop + +Proceed with topic "Setup for running tests" + + +Bare Metal installation +----------------------- + Note that this setup is only to test the web interface. If you need to have a full aurweb instance with cgit, ssh interface, etc, follow the directions in INSTALL. -docker-compose --------------- - -1) Clone the aurweb project: - - $ git clone https://gitlab.archlinux.org/archlinux/aurweb.git - -2) Install the necessary packages: - - # pacman -S docker-compose - -2) Build the aurweb:latest image: - - $ cd /path/to/aurweb/ - $ docker-compose build - -3) Run local Docker development instance: - - $ cd /path/to/aurweb/ - $ docker-compose up -d nginx - -4) Browse to local aurweb development server. - - Python: https://localhost:8444/ - -5) [Optionally] populate the database with dummy data: - - $ docker-compose up mariadb - $ docker-compose exec mariadb /bin/sh - # pacman -S --noconfirm words fortune-mod - # poetry run schema/gendummydata.py dummy_data.sql - # mysql -uaur -paur aurweb < dummy_data.sql - -Inspect `dummy_data.sql` for test credentials. Passwords match usernames. - -Bare Metal ----------- - 1) Clone the aurweb project: $ git clone git://git.archlinux.org/aurweb.git + $ cd aurweb 2) Install the necessary packages: - # pacman -S python-poetry + # pacman -S --needed python-poetry mariadb words fortune-mod nginx -4) Install the package/dependencies via `poetry`: +3) Install the package/dependencies via `poetry`: + + $ poetry install + +4) Copy conf/config.dev to conf/config and replace YOUR_AUR_ROOT by the absolute + path to the root of your aurweb clone. sed can do both tasks for you: + + $ sed -e "s;YOUR_AUR_ROOT;$PWD;g" conf/config.dev > conf/config + + Note that when the upstream config.dev is updated, you should compare it to + your conf/config, or regenerate your configuration with the command above. + +5) Set up mariadb: + + # mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + # systemctl start mariadb + # mariadb -u root + > CREATE USER 'aur'@'localhost' IDENTIFIED BY 'aur'; + > GRANT ALL ON *.* TO 'aur'@'localhost' WITH GRANT OPTION; + > CREATE DATABASE aurweb; + > exit + +6) Prepare a database and insert dummy data: + + $ AUR_CONFIG=conf/config poetry run python -m aurweb.initdb + $ poetry run schema/gendummydata.py dummy_data.sql + $ mariadb -uaur -paur aurweb < dummy_data.sql + +7) Run the test server: + + ## set AUR_CONFIG to our locally created config + $ export AUR_CONFIG=conf/config + + ## with aurweb.spawn + $ poetry run python -m aurweb.spawn + + ## with systemd service + $ sudo install -m644 examples/aurweb.service /etc/systemd/system/ + # systemctl enable --now aurweb.service + + +Setup for running tests +----------------------- + +If you've set up a docker environment, you can run the full test-suite with: + # docker compose run test + +You can collect code-coverage data with: + $ ./util/fix-coverage data/.coverage + +See information further below on how to visualize the data. + +For running individual tests, we need to perform a couple of additional steps. +In case you did the bare-metal install, steps 2, 3, 4 and 5 should be skipped. + +1) Install the necessary packages: + + # pacman -S --needed python-poetry mariadb-libs asciidoc openssh + +2) Install the package/dependencies via `poetry`: - $ cd /path/to/aurweb/ $ poetry install 3) Copy conf/config.dev to conf/config and replace YOUR_AUR_ROOT by the absolute @@ -64,23 +135,51 @@ Bare Metal Note that when the upstream config.dev is updated, you should compare it to your conf/config, or regenerate your configuration with the command above. -4) Prepare a database: +4) Edit the config file conf/config and change the mysql/mariadb portion - $ cd /path/to/aurweb/ + We can make use of our mariadb docker container instead of having to install + mariadb. Change the config as follows: - $ AUR_CONFIG=conf/config poetry run python -m aurweb.initdb + --------------------------------------------------------------------- + ; MySQL database information. User defaults to root for containerized + ; testing with mysqldb. This should be set to a non-root user. + user = root + password = aur + host = 127.0.0.1 + port = 13306 + ;socket = /var/run/mysqld/mysqld.sock + --------------------------------------------------------------------- - $ poetry run schema/gendummydata.py dummy_data.sql - $ mysql -uaur -paur aurweb < dummy_data.sql +5) Start our mariadb docker container -5) Run the test server: + # docker compose start mariadb - ## set AUR_CONFIG to our locally created config - $ export AUR_CONFIG=conf/config +6) Set environment variables - ## with aurweb.spawn - $ poetry run python -m aurweb.spawn + $ export AUR_CONFIG=conf/config + $ export LOG_CONFIG=logging.test.conf - ## with systemd service - $ sudo install -m644 examples/aurweb.service /etc/systemd/system/ - $ systemctl enable --now aurweb.service +7) Compile translation & doc files + + $ make -C po install + $ make -C doc + +Now we can run our python test-suite or individual tests with: + + $ poetry run pytest test/ + $ poetry run pytest test/test_whatever.py + +To run Sharness tests: + + $ poetry run make -C test sh + +The e-Mails that have been generated can be found at test-emails/ + +After test runs, code-coverage reports can be created with: + ## CLI report + $ coverage report + + ## HTML version stored at htmlcov/ + $ coverage html + +More information about tests can be found at test/README.md From 8c5b85db5c7888a1fca661f098bd12a3ec76756f Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 30 Apr 2023 21:10:42 +0200 Subject: [PATCH 1739/1891] housekeep: remove fix for poetry installer The problems with the "modern installer" got fixed. We don't need this workaround anymore. https://github.com/python-poetry/poetry/issues/7572 Signed-off-by: moson-mo --- poetry.toml | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 poetry.toml diff --git a/poetry.toml b/poetry.toml deleted file mode 100644 index 8d4747a6..00000000 --- a/poetry.toml +++ /dev/null @@ -1,5 +0,0 @@ -# disable the modern installer until python-installer is fixed -# https://github.com/python-poetry/poetry/issues/7572 - -[installer] -modern-installation = false From a8d14e019457cef9e62cab2da0b4ed67a51ac46d Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Wed, 26 Apr 2023 23:39:10 +0100 Subject: [PATCH 1740/1891] housekeep: remove unused templates and rework existing ones Signed-off-by: Leonidas Spyropoulos --- .gitlab/issue_templates/Account Request.md | 14 ------ .gitlab/issue_templates/Bug.md | 26 +++++++--- .gitlab/issue_templates/Feature.md | 24 ++++++++- .gitlab/issue_templates/Feedback.md | 58 ---------------------- 4 files changed, 41 insertions(+), 81 deletions(-) delete mode 100644 .gitlab/issue_templates/Account Request.md delete mode 100644 .gitlab/issue_templates/Feedback.md diff --git a/.gitlab/issue_templates/Account Request.md b/.gitlab/issue_templates/Account Request.md deleted file mode 100644 index 6831d3ad..00000000 --- a/.gitlab/issue_templates/Account Request.md +++ /dev/null @@ -1,14 +0,0 @@ -## Checklist - -- [ ] I have set a Username in the Details section -- [ ] I have set an Email in the Details section -- [ ] I have set a valid Account Type in the Details section - -## Details - -- Instance: aur-dev.archlinux.org -- Username: the_username_you_want -- Email: valid@email.org -- Account Type: (User|Trusted User) - -/label account-request diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md index 3e7a04bf..9e20aadb 100644 --- a/.gitlab/issue_templates/Bug.md +++ b/.gitlab/issue_templates/Bug.md @@ -1,12 +1,24 @@ + +/label ~bug ~unconfirmed +/title [BUG] + + ### Checklist -This bug template is meant to provide bug issues for code existing in -the aurweb repository. This bug template is **not meant** to handle -bugs with user-uploaded packages. +**NOTE:** This bug template is meant to provide bug issues for code existing in +the aurweb repository. -To work out a bug you have found in a user-uploaded package, contact -the package's maintainer first. If you receive no response, file the -relevant package request against it so TUs can deal with cleanup. +**This bug template is not meant to handle bugs with user-uploaded packages.** +To report issues you might have found in a user-uploaded package, contact +the package's maintainer in comments. - [ ] I confirm that this is an issue with aurweb's code and not a user-uploaded package. @@ -29,7 +41,7 @@ this bug. ### Logs -If you have any logs relevent to the bug, include them here in +If you have any logs relevant to the bug, include them here in quoted or code blocks. ### Version(s) diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md index c907adcd..630c53c3 100644 --- a/.gitlab/issue_templates/Feature.md +++ b/.gitlab/issue_templates/Feature.md @@ -1,3 +1,25 @@ + +/label ~feature ~unconfirmed +/title [FEATURE] + + +### Checklist + +**NOTE:** This bug template is meant to provide bug issues for code existing in +the aurweb repository. + +**This bug template is not meant to handle bugs with user-uploaded packages.** +To report issues you might have found in a user-uploaded package, contact +the package's maintainer in comments. + - [ ] I have summed up the feature in concise words in the [Summary](#summary) section. - [ ] I have completely described the feature in the [Description](#description) section. - [ ] I have completed the [Blockers](#blockers) section. @@ -28,5 +50,3 @@ Example: - [Feature] Do not allow users to be Tyrants - \<(issue|merge_request)_link\> - -/label feature unconsidered diff --git a/.gitlab/issue_templates/Feedback.md b/.gitlab/issue_templates/Feedback.md deleted file mode 100644 index 950ec0c6..00000000 --- a/.gitlab/issue_templates/Feedback.md +++ /dev/null @@ -1,58 +0,0 @@ -**NOTE:** This issue template is only applicable to FastAPI implementations -in the code-base, which only exists within the `pu` branch. If you wish to -file an issue for the current PHP implementation of aurweb, please file a -standard issue prefixed with `[Bug]` or `[Feature]`. - - -**Checklist** - -- [ ] I have prefixed the issue title with `[Feedback]` along with a message - pointing to the route or feature tested. - - Example: `[Feedback] /packages/{name}` -- [ ] I have completed the [Changes](#changes) section. -- [ ] I have completed the [Bugs](#bugs) section. -- [ ] I have completed the [Improvements](#improvements) section. -- [ ] I have completed the [Summary](#summary) section. - -### Changes - -Please describe changes in user experience when compared to the PHP -implementation. This section can actually hold a lot of info if you -are up for it -- changes in routes, HTML rendering, back-end behavior, -etc. - -If you cannot see any changes from your standpoint, include a short -statement about that fact. - -### Bugs - -Please describe any bugs you've experienced while testing the route -pertaining to this issue. A "perfect" bug report would include your -specific experience, what you expected to occur, and what happened -otherwise. If you can, please include output of `docker-compose logs fastapi` -with your report; especially if any unintended exceptions occurred. - -### Improvements - -If you've experienced improvements in the route when compared to PHP, -please do include those here. We'd like to know if users are noticing -these improvements and how they feel about them. - -There are multiple routes with no improvements. For these, just include -a short sentence about the fact that you've experienced none. - -### Summary - -First: If you've gotten here and completed the [Changes](#changes), -[Bugs](#bugs), and [Improvements](#improvements) sections, we'd like -to thank you very much for your contribution and willingness to test. -We are not a company, and we are not a large team; any bit of assistance -here helps the project astronomically and moves us closer toward a -new release. - -That being said: please include an overall summary of your experience -and how you felt about the current implementation which you're testing -in comparison with PHP (current aur.archlinux.org, or https://localhost:8443 -through docker). - -/label feedback From af4239bcac0fd71ccc4168b70eed77ccf3d567c1 Mon Sep 17 00:00:00 2001 From: Christian Heusel Date: Wed, 22 Mar 2023 08:49:22 +0100 Subject: [PATCH 1741/1891] replace reference to AUR TU Guidelines with AUR Submission Guidelines Signed-off-by: Christian Heusel --- templates/home.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/home.html b/templates/home.html index e8296239..cb103f18 100644 --- a/templates/home.html +++ b/templates/home.html @@ -1,10 +1,10 @@

    AUR {% trans %}Home{% endtrans %}

    - {{ "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU Guidelines%s for more information." + {{ "Welcome to the AUR! Please read the %sAUR User Guidelines%s for more information and the %sAUR Submission Guidelines%s if you want to contribute a PKGBUILD." | tr | format('', "", - '', "") + '', "") | safe }} {{ "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s otherwise they will be deleted!" From b115aedf97bff1d1455d46298738bd8debd931bd Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 6 May 2023 20:29:05 +0200 Subject: [PATCH 1742/1891] chore(deps): update several dependencies - Removing rfc3986 (1.5.0) - Updating coverage (7.2.4 -> 7.2.5) - Updating fastapi (0.94.1 -> 0.95.1) - Updating httpcore (0.16.3 -> 0.17.0) - Updating sqlalchemy (1.4.47 -> 1.4.48) - Updating httpx (0.23.3 -> 0.24.0) - Updating prometheus-fastapi-instrumentator (5.11.2 -> 6.0.0) - Updating protobuf (4.22.3 -> 4.22.4) - Updating pytest-asyncio (0.20.3 -> 0.21.0) - Updating requests (2.29.0 -> 2.30.0) - Updating uvicorn (0.21.1 -> 0.22.0) - Updating watchfiles (0.18.1 -> 0.19.0) - Updating werkzeug (2.3.2 -> 2.3.3) Signed-off-by: moson-mo --- poetry.lock | 336 ++++++++++++++++++++++++------------------------- pyproject.toml | 41 +++--- 2 files changed, 182 insertions(+), 195 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5e933e70..54a7701d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -352,63 +352,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.4" +version = "7.2.5" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e5eedde6e6e241ec3816f05767cc77e7456bf5ec6b373fb29917f0990e2078f"}, - {file = "coverage-7.2.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c6c6e3b8fb6411a2035da78d86516bfcfd450571d167304911814407697fb7a"}, - {file = "coverage-7.2.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7668a621afc52db29f6867e0e9c72a1eec9f02c94a7c36599119d557cf6e471"}, - {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfb53bef4b2739ff747ebbd76d6ac5384371fd3c7a8af08899074eba034d483"}, - {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c4f2e44a2ae15fa6883898e756552db5105ca4bd918634cbd5b7c00e19e8a1"}, - {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:700bc9fb1074e0c67c09fe96a803de66663830420781df8dc9fb90d7421d4ccb"}, - {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ac4861241e693e21b280f07844ae0e0707665e1dfcbf9466b793584984ae45c4"}, - {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3d6f3c5b6738a494f17c73b4aa3aa899865cc33a74aa85e3b5695943b79ad3ce"}, - {file = "coverage-7.2.4-cp310-cp310-win32.whl", hash = "sha256:437da7d2fcc35bf45e04b7e9cfecb7c459ec6f6dc17a8558ed52e8d666c2d9ab"}, - {file = "coverage-7.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:1d3893f285fd76f56651f04d1efd3bdce251c32992a64c51e5d6ec3ba9e3f9c9"}, - {file = "coverage-7.2.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a17bf32e9e3333d78606ac1073dd20655dc0752d5b923fa76afd3bc91674ab4"}, - {file = "coverage-7.2.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f7ffdb3af2a01ce91577f84fc0faa056029fe457f3183007cffe7b11ea78b23c"}, - {file = "coverage-7.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89e63b38c7b888e00fd42ce458f838dccb66de06baea2da71801b0fc9070bfa0"}, - {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4522dd9aeb9cc2c4c54ce23933beb37a4e106ec2ba94f69138c159024c8a906a"}, - {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29c7d88468f01a75231797173b52dc66d20a8d91b8bb75c88fc5861268578f52"}, - {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bc47015fc0455753e8aba1f38b81b731aaf7f004a0c390b404e0fcf1d6c1d72f"}, - {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c122d120c11a236558c339a59b4b60947b38ac9e3ad30a0e0e02540b37bf536"}, - {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:50fda3d33b705b9c01e3b772cfa7d14de8aec2ec2870e4320992c26d057fde12"}, - {file = "coverage-7.2.4-cp311-cp311-win32.whl", hash = "sha256:ab08af91cf4d847a6e15d7d5eeae5fead1487caf16ff3a2056dbe64d058fd246"}, - {file = "coverage-7.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:876e4ef3eff00b50787867c5bae84857a9af4c369a9d5b266cd9b19f61e48ef7"}, - {file = "coverage-7.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3fc9cde48de956bfbacea026936fbd4974ff1dc2f83397c6f1968f0142c9d50b"}, - {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12bc9127c8aca2f7c25c9acca53da3db6799b2999b40f28c2546237b7ea28459"}, - {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2857894c22833d3da6e113623a9b7440159b2295280b4e0d954cadbfa724b85a"}, - {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4db4e6c115d869cd5397d3d21fd99e4c7053205c33a4ae725c90d19dcd178af"}, - {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f37ae1804596f13d811e0247ffc8219f5261b3565bdf45fcbb4fc091b8e9ff35"}, - {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdee9a77fd0ce000781680b6a1f4b721c567f66f2f73a49be1843ff439d634f3"}, - {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b65a6a5484b7f2970393d6250553c05b2ede069e0e18abe907fdc7f3528252e"}, - {file = "coverage-7.2.4-cp37-cp37m-win32.whl", hash = "sha256:1a3e8697cb40f28e5bcfb6f4bda7852d96dbb6f6fd7cc306aba4ae690c9905ab"}, - {file = "coverage-7.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:4078939c4b7053e14e87c65aa68dbed7867e326e450f94038bfe1a1b22078ff9"}, - {file = "coverage-7.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:603a2b172126e3b08c11ca34200143089a088cd0297d4cfc4922d2c1c3a892f9"}, - {file = "coverage-7.2.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72751d117ceaad3b1ea3bcb9e85f5409bbe9fb8a40086e17333b994dbccc0718"}, - {file = "coverage-7.2.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f19ba9301e6fb0b94ba71fda9a1b02d11f0aab7f8e2455122a4e2921b6703c2f"}, - {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d784177a7fb9d0f58d24d3e60638c8b729c3693963bf67fa919120f750db237"}, - {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d2a9180beff1922b09bd7389e23454928e108449e646c26da5c62e29b0bf4e3"}, - {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:39747afc854a7ee14e5e132da7db179d6281faf97dc51e6d7806651811c47538"}, - {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60feb703abc8d78e9427d873bcf924c9e30cf540a21971ef5a17154da763b60f"}, - {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2becddfcbf3d994a8f4f9dd2b6015cae3a3eff50dedc6e4a17c3cccbe8f93d4"}, - {file = "coverage-7.2.4-cp38-cp38-win32.whl", hash = "sha256:56a674ad18d6b04008283ca03c012be913bf89d91c0803c54c24600b300d9e51"}, - {file = "coverage-7.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:ab08e03add2cf5793e66ac1bbbb24acfa90c125476f5724f5d44c56eeec1d635"}, - {file = "coverage-7.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92b565c51732ea2e7e541709ccce76391b39f4254260e5922e08e00971e88e33"}, - {file = "coverage-7.2.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8769a67e8816c7e94d5bf446fc0501641fde78fdff362feb28c2c64d45d0e9b1"}, - {file = "coverage-7.2.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d74d6fbd5a98a5629e8467b719b0abea9ca01a6b13555d125c84f8bf4ea23d"}, - {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9f770c6052d9b5c9b0e824fd8c003fe33276473b65b4f10ece9565ceb62438e"}, - {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3023ce23e41a6f006c09f7e6d62b6c069c36bdc9f7de16a5ef823acc02e6c63"}, - {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fabd1f4d12dfd6b4f309208c2f31b116dc5900e0b42dbafe4ee1bc7c998ffbb0"}, - {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e41a7f44e73b37c6f0132ecfdc1c8b67722f42a3d9b979e6ebc150c8e80cf13a"}, - {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:864e36947289be05abd83267c4bade35e772526d3e9653444a9dc891faf0d698"}, - {file = "coverage-7.2.4-cp39-cp39-win32.whl", hash = "sha256:ea534200efbf600e60130c48552f99f351cae2906898a9cd924c1c7f2fb02853"}, - {file = "coverage-7.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:00f8fd8a5fe1ffc3aef78ea2dbf553e5c0f4664324e878995e38d41f037eb2b3"}, - {file = "coverage-7.2.4-pp37.pp38.pp39-none-any.whl", hash = "sha256:856bcb837e96adede31018a0854ce7711a5d6174db1a84e629134970676c54fa"}, - {file = "coverage-7.2.4.tar.gz", hash = "sha256:7283f78d07a201ac7d9dc2ac2e4faaea99c4d302f243ee5b4e359f3e170dc008"}, + {file = "coverage-7.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c"}, + {file = "coverage-7.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a"}, + {file = "coverage-7.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f"}, + {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a"}, + {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a"}, + {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11"}, + {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5"}, + {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c"}, + {file = "coverage-7.2.5-cp310-cp310-win32.whl", hash = "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5"}, + {file = "coverage-7.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c"}, + {file = "coverage-7.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce"}, + {file = "coverage-7.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88"}, + {file = "coverage-7.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e"}, + {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2"}, + {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139"}, + {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8"}, + {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed"}, + {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6"}, + {file = "coverage-7.2.5-cp311-cp311-win32.whl", hash = "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b"}, + {file = "coverage-7.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068"}, + {file = "coverage-7.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1"}, + {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33"}, + {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade"}, + {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5"}, + {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47"}, + {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd"}, + {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969"}, + {file = "coverage-7.2.5-cp37-cp37m-win32.whl", hash = "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718"}, + {file = "coverage-7.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0"}, + {file = "coverage-7.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84"}, + {file = "coverage-7.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790"}, + {file = "coverage-7.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771"}, + {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045"}, + {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614"}, + {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3"}, + {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd"}, + {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1"}, + {file = "coverage-7.2.5-cp38-cp38-win32.whl", hash = "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813"}, + {file = "coverage-7.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212"}, + {file = "coverage-7.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b"}, + {file = "coverage-7.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200"}, + {file = "coverage-7.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5"}, + {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e"}, + {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303"}, + {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3"}, + {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a"}, + {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1"}, + {file = "coverage-7.2.5-cp39-cp39-win32.whl", hash = "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31"}, + {file = "coverage-7.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252"}, + {file = "coverage-7.2.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3"}, + {file = "coverage-7.2.5.tar.gz", hash = "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"}, ] [package.dependencies] @@ -548,14 +548,14 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.94.1" +version = "0.95.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.94.1-py3-none-any.whl", hash = "sha256:451387550c2d25a972193f22e408a82e75a8e7867c834a03076704fe20df3256"}, - {file = "fastapi-0.94.1.tar.gz", hash = "sha256:4a75936dbf9eb74be5eb0d41a793adefe9f3fc6ba66dbdabd160120fd3c2d9cd"}, + {file = "fastapi-0.95.1-py3-none-any.whl", hash = "sha256:a870d443e5405982e1667dfe372663abf10754f246866056336d7f01c21dab07"}, + {file = "fastapi-0.95.1.tar.gz", hash = "sha256:9569f0a381f8a457ec479d90fa01005cfddaae07546eb1f3fa035bc4797ae7d5"}, ] [package.dependencies] @@ -736,14 +736,14 @@ files = [ [[package]] name = "httpcore" -version = "0.16.3" +version = "0.17.0" description = "A minimal low-level HTTP client." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, - {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, + {file = "httpcore-0.17.0-py3-none-any.whl", hash = "sha256:0fdfea45e94f0c9fd96eab9286077f9ff788dd186635ae61b312693e4d943599"}, + {file = "httpcore-0.17.0.tar.gz", hash = "sha256:cc045a3241afbf60ce056202301b4d8b6af08845e3294055eb26b09913ef903c"}, ] [package.dependencies] @@ -758,25 +758,25 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" -version = "0.23.3" +version = "0.24.0" description = "The next generation HTTP client." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, - {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, + {file = "httpx-0.24.0-py3-none-any.whl", hash = "sha256:447556b50c1921c351ea54b4fe79d91b724ed2b027462ab9a329465d147d5a4e"}, + {file = "httpx-0.24.0.tar.gz", hash = "sha256:507d676fc3e26110d41df7d35ebd8b3b8585052450f4097401c9be59d928c63e"}, ] [package.dependencies] certifi = "*" -httpcore = ">=0.15.0,<0.17.0" -rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +httpcore = ">=0.15.0,<0.18.0" +idna = "*" sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (>=1.0.0,<2.0.0)"] @@ -1255,14 +1255,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.11.2" +version = "6.0.0" description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus_fastapi_instrumentator-5.11.2-py3-none-any.whl", hash = "sha256:c84ae3dc98bebb44f29d0af0c17c9f0782c2fb964ef83353664d9858a632cf81"}, - {file = "prometheus_fastapi_instrumentator-5.11.2.tar.gz", hash = "sha256:9d8d0df8de7d6a73ae387121629dbf32fe022cdfc63e8bacd51f4b8ff21059ea"}, + {file = "prometheus_fastapi_instrumentator-6.0.0-py3-none-any.whl", hash = "sha256:6f66a951a4801667f7311d161f3aebfe0cd202391d0f067fbbe169792e2d987b"}, + {file = "prometheus_fastapi_instrumentator-6.0.0.tar.gz", hash = "sha256:f1ddd0b8ead75e71d055bdf4cb7e995ec6a6ca63543245e7bbc5ca9b14c45191"}, ] [package.dependencies] @@ -1271,25 +1271,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.22.3" +version = "4.22.4" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.22.3-cp310-abi3-win32.whl", hash = "sha256:8b54f56d13ae4a3ec140076c9d937221f887c8f64954673d46f63751209e839a"}, - {file = "protobuf-4.22.3-cp310-abi3-win_amd64.whl", hash = "sha256:7760730063329d42a9d4c4573b804289b738d4931e363ffbe684716b796bde51"}, - {file = "protobuf-4.22.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:d14fc1a41d1a1909998e8aff7e80d2a7ae14772c4a70e4bf7db8a36690b54425"}, - {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:70659847ee57a5262a65954538088a1d72dfc3e9882695cab9f0c54ffe71663b"}, - {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:13233ee2b9d3bd9a5f216c1fa2c321cd564b93d8f2e4f521a85b585447747997"}, - {file = "protobuf-4.22.3-cp37-cp37m-win32.whl", hash = "sha256:ecae944c6c2ce50dda6bf76ef5496196aeb1b85acb95df5843cd812615ec4b61"}, - {file = "protobuf-4.22.3-cp37-cp37m-win_amd64.whl", hash = "sha256:d4b66266965598ff4c291416be429cef7989d8fae88b55b62095a2331511b3fa"}, - {file = "protobuf-4.22.3-cp38-cp38-win32.whl", hash = "sha256:f08aa300b67f1c012100d8eb62d47129e53d1150f4469fd78a29fa3cb68c66f2"}, - {file = "protobuf-4.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:f2f4710543abec186aee332d6852ef5ae7ce2e9e807a3da570f36de5a732d88e"}, - {file = "protobuf-4.22.3-cp39-cp39-win32.whl", hash = "sha256:7cf56e31907c532e460bb62010a513408e6cdf5b03fb2611e4b67ed398ad046d"}, - {file = "protobuf-4.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:e0e630d8e6a79f48c557cd1835865b593d0547dce221c66ed1b827de59c66c97"}, - {file = "protobuf-4.22.3-py3-none-any.whl", hash = "sha256:52f0a78141078077cfe15fe333ac3e3a077420b9a3f5d1bf9b5fe9d286b4d881"}, - {file = "protobuf-4.22.3.tar.gz", hash = "sha256:23452f2fdea754a8251d0fc88c0317735ae47217e0d27bf330a30eec2848811a"}, + {file = "protobuf-4.22.4-cp310-abi3-win32.whl", hash = "sha256:a4e661247896c2ffea4b894bca2d8657e752bedb8f3c66d7befa2557291be1e8"}, + {file = "protobuf-4.22.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b42086d6027be2730151b49f27b2f5be40f3b036adf7b8da5917f4567f268c3"}, + {file = "protobuf-4.22.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4bfb28d48628deacdb66a95aaa7b6640f3dc82b4edd34db444c7a3cdd90b01fb"}, + {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e98e26328d7c668541d1052b02de4205b1094ef6b2ce57167440d3e39876db48"}, + {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd329e5dd7b6c4b878cab4b85bb6cec880e2adaf4e8aa2c75944dcbb05e1ff1"}, + {file = "protobuf-4.22.4-cp37-cp37m-win32.whl", hash = "sha256:b7728b5da9eee15c0aa3baaee79e94fa877ddcf7e3d2f34b1eab586cd26eea89"}, + {file = "protobuf-4.22.4-cp37-cp37m-win_amd64.whl", hash = "sha256:f4a711588c3a79b6f9c44af4d7f4a2ae868e27063654683932ab6462f90e9656"}, + {file = "protobuf-4.22.4-cp38-cp38-win32.whl", hash = "sha256:11b28b4e779d7f275e3ea0efa3938f4d4e8ed3ca818f9fec3b193f8e9ada99fd"}, + {file = "protobuf-4.22.4-cp38-cp38-win_amd64.whl", hash = "sha256:144d5b46df5e44f914f715accaadf88d617242ba5a40cacef4e8de7effa79954"}, + {file = "protobuf-4.22.4-cp39-cp39-win32.whl", hash = "sha256:5128b4d5efcaef92189e076077ae389700606ff81d2126b8361dc01f3e026197"}, + {file = "protobuf-4.22.4-cp39-cp39-win_amd64.whl", hash = "sha256:9537ae27d43318acf8ce27d0359fe28e6ebe4179c3350bc055bb60ff4dc4fcd3"}, + {file = "protobuf-4.22.4-py3-none-any.whl", hash = "sha256:3b21074b7fb748d8e123acaef9fa63a84fdc1436dc71199d2317b139f77dd6f4"}, + {file = "protobuf-4.22.4.tar.gz", hash = "sha256:21fbaef7f012232eb8d6cb8ba334e931fc6ff8570f5aaedc77d5b22a439aa909"}, ] [[package]] @@ -1437,18 +1437,18 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.20.3" +version = "0.21.0" description = "Pytest support for asyncio" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.20.3.tar.gz", hash = "sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36"}, - {file = "pytest_asyncio-0.20.3-py3-none-any.whl", hash = "sha256:f129998b209d04fcc65c96fc85c11e5316738358909a8399e93be553d7656442"}, + {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, + {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, ] [package.dependencies] -pytest = ">=6.1.0" +pytest = ">=7.0.0" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -1561,44 +1561,26 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.29.0" +version = "2.30.0" description = "Python HTTP for Humans." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "requests-2.29.0-py3-none-any.whl", hash = "sha256:e8f3c9be120d3333921d213eef078af392fba3933ab7ed2d1cba3b56f2568c3b"}, - {file = "requests-2.29.0.tar.gz", hash = "sha256:f2e34a75f4749019bb0e3effb66683630e4ffeaf75819fb51bebef1bf5aef059"}, + {file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"}, + {file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"}, ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "rfc3986" -version = "1.5.0" -description = "Validating URI References per RFC 3986" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, - {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, -] - -[package.dependencies] -idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} - -[package.extras] -idna2008 = ["idna"] - [[package]] name = "setuptools" version = "67.7.2" @@ -1654,53 +1636,53 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.47" +version = "1.4.48" description = "Database Abstraction Library" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.47-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:dcfb480bfc9e1fab726003ae00a6bfc67a29bad275b63a4e36d17fe7f13a624e"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28fda5a69d6182589892422c5a9b02a8fd1125787aab1d83f1392aa955bf8d0a"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27m-win32.whl", hash = "sha256:45e799c1a41822eba6bee4e59b0e38764e1a1ee69873ab2889079865e9ea0e23"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27m-win_amd64.whl", hash = "sha256:10edbb92a9ef611f01b086e271a9f6c1c3e5157c3b0c5ff62310fb2187acbd4a"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7a4df53472c9030a8ddb1cce517757ba38a7a25699bbcabd57dcc8a5d53f324e"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:511d4abc823152dec49461209607bbfb2df60033c8c88a3f7c93293b8ecbb13d"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbe57f39f531c5d68d5594ea4613daa60aba33bb51a8cc42f96f17bbd6305e8d"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca8ab6748e3ec66afccd8b23ec2f92787a58d5353ce9624dccd770427ee67c82"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299b5c5c060b9fbe51808d0d40d8475f7b3873317640b9b7617c7f988cf59fda"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-win32.whl", hash = "sha256:684e5c773222781775c7f77231f412633d8af22493bf35b7fa1029fdf8066d10"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-win_amd64.whl", hash = "sha256:2bba39b12b879c7b35cde18b6e14119c5f1a16bd064a48dd2ac62d21366a5e17"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:795b5b9db573d3ed61fae74285d57d396829e3157642794d3a8f72ec2a5c719b"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:989c62b96596b7938cbc032e39431e6c2d81b635034571d6a43a13920852fb65"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b67bda733da1dcdccaf354e71ef01b46db483a4f6236450d3f9a61efdba35a"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-win32.whl", hash = "sha256:9a198f690ac12a3a807e03a5a45df6a30cd215935f237a46f4248faed62e69c8"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-win_amd64.whl", hash = "sha256:03be6f3cb66e69fb3a09b5ea89d77e4bc942f3bf84b207dba84666a26799c166"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:16ee6fea316790980779268da47a9260d5dd665c96f225d28e7750b0bb2e2a04"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:557675e0befafa08d36d7a9284e8761c97490a248474d778373fb96b0d7fd8de"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb2797fee8a7914fb2c3dc7de404d3f96eb77f20fc60e9ee38dc6b0ca720f2c2"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28297aa29e035f29cba6b16aacd3680fbc6a9db682258d5f2e7b49ec215dbe40"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-win32.whl", hash = "sha256:998e782c8d9fd57fa8704d149ccd52acf03db30d7dd76f467fd21c1c21b414fa"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-win_amd64.whl", hash = "sha256:dde4d02213f1deb49eaaf8be8a6425948963a7af84983b3f22772c63826944de"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e98ef1babe34f37f443b7211cd3ee004d9577a19766e2dbacf62fce73c76245a"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14a3879853208a242b5913f3a17c6ac0eae9dc210ff99c8f10b19d4a1ed8ed9b"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7120a2f72599d4fed7c001fa1cbbc5b4d14929436135768050e284f53e9fbe5e"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:048509d7f3ac27b83ad82fd96a1ab90a34c8e906e4e09c8d677fc531d12c23c5"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-win32.whl", hash = "sha256:6572d7c96c2e3e126d0bb27bfb1d7e2a195b68d951fcc64c146b94f088e5421a"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-win_amd64.whl", hash = "sha256:a6c3929df5eeaf3867724003d5c19fed3f0c290f3edc7911616616684f200ecf"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71d4bf7768169c4502f6c2b0709a02a33703544f611810fb0c75406a9c576ee1"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd45c60cc4f6d68c30d5179e2c2c8098f7112983532897566bb69c47d87127d3"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fdbb8e9d4e9003f332a93d6a37bca48ba8095086c97a89826a136d8eddfc455"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f216a51451a0a0466e082e163591f6dcb2f9ec182adb3f1f4b1fd3688c7582c"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-win32.whl", hash = "sha256:bd988b3362d7e586ef581eb14771bbb48793a4edb6fcf62da75d3f0f3447060b"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-win_amd64.whl", hash = "sha256:32ab09f2863e3de51529aa84ff0e4fe89a2cb1bfbc11e225b6dbc60814e44c94"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:07764b240645627bc3e82596435bd1a1884646bfc0721642d24c26b12f1df194"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e2a42017984099ef6f56438a6b898ce0538f6fadddaa902870c5aa3e1d82583"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6b6d807c76c20b4bc143a49ad47782228a2ac98bdcdcb069da54280e138847fc"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a94632ba26a666e7be0a7d7cc3f7acab622a04259a3aa0ee50ff6d44ba9df0d"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-win32.whl", hash = "sha256:f80915681ea9001f19b65aee715115f2ad310730c8043127cf3e19b3009892dd"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-win_amd64.whl", hash = "sha256:fc700b862e0a859a37faf85367e205e7acaecae5a098794aff52fdd8aea77b12"}, - {file = "SQLAlchemy-1.4.47.tar.gz", hash = "sha256:95fc02f7fc1f3199aaa47a8a757437134cf618e9d994c84effd53f530c38586f"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4bac3aa3c3d8bc7408097e6fe8bf983caa6e9491c5d2e2488cfcfd8106f13b6a"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dbcae0e528d755f4522cad5842f0942e54b578d79f21a692c44d91352ea6d64e"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-win32.whl", hash = "sha256:cbbe8b8bffb199b225d2fe3804421b7b43a0d49983f81dc654d0431d2f855543"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-win_amd64.whl", hash = "sha256:627e04a5d54bd50628fc8734d5fc6df2a1aa5962f219c44aad50b00a6cdcf965"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9af1db7a287ef86e0f5cd990b38da6bd9328de739d17e8864f1817710da2d217"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:ce7915eecc9c14a93b73f4e1c9d779ca43e955b43ddf1e21df154184f39748e5"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5381ddd09a99638f429f4cbe1b71b025bed318f6a7b23e11d65f3eed5e181c33"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:87609f6d4e81a941a17e61a4c19fee57f795e96f834c4f0a30cee725fc3f81d9"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb0808ad34167f394fea21bd4587fc62f3bd81bba232a1e7fbdfa17e6cfa7cd7"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-win32.whl", hash = "sha256:d53cd8bc582da5c1c8c86b6acc4ef42e20985c57d0ebc906445989df566c5603"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-win_amd64.whl", hash = "sha256:4355e5915844afdc5cf22ec29fba1010166e35dd94a21305f49020022167556b"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:066c2b0413e8cb980e6d46bf9d35ca83be81c20af688fedaef01450b06e4aa5e"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c99bf13e07140601d111a7c6f1fc1519914dd4e5228315bbda255e08412f61a4"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee26276f12614d47cc07bc85490a70f559cba965fb178b1c45d46ffa8d73fda"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-win32.whl", hash = "sha256:49c312bcff4728bffc6fb5e5318b8020ed5c8b958a06800f91859fe9633ca20e"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-win_amd64.whl", hash = "sha256:cef2e2abc06eab187a533ec3e1067a71d7bbec69e582401afdf6d8cad4ba3515"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:3509159e050bd6d24189ec7af373359f07aed690db91909c131e5068176c5a5d"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc2ab4d9f6d9218a5caa4121bdcf1125303482a1cdcfcdbd8567be8518969c0"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1ddbbcef9bcedaa370c03771ebec7e39e3944782bef49e69430383c376a250b"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f82d8efea1ca92b24f51d3aea1a82897ed2409868a0af04247c8c1e4fef5890"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-win32.whl", hash = "sha256:e3e98d4907805b07743b583a99ecc58bf8807ecb6985576d82d5e8ae103b5272"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-win_amd64.whl", hash = "sha256:25887b4f716e085a1c5162f130b852f84e18d2633942c8ca40dfb8519367c14f"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:0817c181271b0ce5df1aa20949f0a9e2426830fed5ecdcc8db449618f12c2730"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1dd2562313dd9fe1778ed56739ad5d9aae10f9f43d9f4cf81d65b0c85168bb"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:68413aead943883b341b2b77acd7a7fe2377c34d82e64d1840860247cec7ff7c"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbde5642104ac6e95f96e8ad6d18d9382aa20672008cf26068fe36f3004491df"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-win32.whl", hash = "sha256:11c6b1de720f816c22d6ad3bbfa2f026f89c7b78a5c4ffafb220e0183956a92a"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-win_amd64.whl", hash = "sha256:eb5464ee8d4bb6549d368b578e9529d3c43265007193597ddca71c1bae6174e6"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:92e6133cf337c42bfee03ca08c62ba0f2d9695618c8abc14a564f47503157be9"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d29a3fc6d9c45962476b470a81983dd8add6ad26fdbfae6d463b509d5adcda"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:005e942b451cad5285015481ae4e557ff4154dde327840ba91b9ac379be3b6ce"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c8cfe951ed074ba5e708ed29c45397a95c4143255b0d022c7c8331a75ae61f3"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-win32.whl", hash = "sha256:2b9af65cc58726129d8414fc1a1a650dcdd594ba12e9c97909f1f57d48e393d3"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-win_amd64.whl", hash = "sha256:2b562e9d1e59be7833edf28b0968f156683d57cabd2137d8121806f38a9d58f4"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a1fc046756cf2a37d7277c93278566ddf8be135c6a58397b4c940abf837011f4"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d9b55252d2ca42a09bcd10a697fa041e696def9dfab0b78c0aaea1485551a08"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6dab89874e72a9ab5462997846d4c760cdb957958be27b03b49cf0de5e5c327c"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd8b5ee5a3acc4371f820934b36f8109ce604ee73cc668c724abb054cebcb6e"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-win32.whl", hash = "sha256:eee09350fd538e29cfe3a496ec6f148504d2da40dbf52adefb0d2f8e4d38ccc4"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-win_amd64.whl", hash = "sha256:7ad2b0f6520ed5038e795cc2852eb5c1f20fa6831d73301ced4aafbe3a10e1f6"}, + {file = "SQLAlchemy-1.4.48.tar.gz", hash = "sha256:b47bc287096d989a0838ce96f7d8e966914a24da877ed41a7531d44b55cdb8df"}, ] [package.dependencies] @@ -1843,14 +1825,14 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.21.1" +version = "0.22.0" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "uvicorn-0.21.1-py3-none-any.whl", hash = "sha256:e47cac98a6da10cd41e6fd036d472c6f58ede6c5dbee3dbee3ef7a100ed97742"}, - {file = "uvicorn-0.21.1.tar.gz", hash = "sha256:0fac9cb342ba099e0d582966005f3fdba5b0290579fed4a6266dc702ca7bb032"}, + {file = "uvicorn-0.22.0-py3-none-any.whl", hash = "sha256:e9434d3bbf05f310e762147f769c9f21235ee118ba2d2bf1155a7196448bd996"}, + {file = "uvicorn-0.22.0.tar.gz", hash = "sha256:79277ae03db57ce7d9aa0567830bbb51d7a612f54d6e1e3e92da3ef24c2c8ed8"}, ] [package.dependencies] @@ -1862,30 +1844,34 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", [[package]] name = "watchfiles" -version = "0.18.1" +version = "0.19.0" description = "Simple, modern and high performance file watching and code reload in python." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "watchfiles-0.18.1-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:9891d3c94272108bcecf5597a592e61105279def1313521e637f2d5acbe08bc9"}, - {file = "watchfiles-0.18.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:7102342d60207fa635e24c02a51c6628bf0472e5fef067f78a612386840407fc"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:00ea0081eca5e8e695cffbc3a726bb90da77f4e3f78ce29b86f0d95db4e70ef7"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8e6db99e49cd7125d8a4c9d33c0735eea7b75a942c6ad68b75be3e91c242fb"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc7c726855f04f22ac79131b51bf0c9f728cb2117419ed830a43828b2c4a5fcb"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbaff354d12235002e62d9d3fa8bcf326a8490c1179aa5c17195a300a9e5952f"}, - {file = "watchfiles-0.18.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:888db233e06907c555eccd10da99b9cd5ed45deca47e41766954292dc9f7b198"}, - {file = "watchfiles-0.18.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:dde79930d1b28f15994ad6613aa2865fc7a403d2bb14585a8714a53233b15717"}, - {file = "watchfiles-0.18.1-cp37-abi3-win32.whl", hash = "sha256:e2b2bdd26bf8d6ed90763e6020b475f7634f919dbd1730ea1b6f8cb88e21de5d"}, - {file = "watchfiles-0.18.1-cp37-abi3-win_amd64.whl", hash = "sha256:c541e0f2c3e95e83e4f84561c893284ba984e9d0025352057396d96dceb09f44"}, - {file = "watchfiles-0.18.1-cp37-abi3-win_arm64.whl", hash = "sha256:9a26272ef3e930330fc0c2c148cc29706cc2c40d25760c7ccea8d768a8feef8b"}, - {file = "watchfiles-0.18.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:9fb12a5e2b42e0b53769455ff93546e6bc9ab14007fbd436978d827a95ca5bd1"}, - {file = "watchfiles-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:548d6b42303d40264118178053c78820533b683b20dfbb254a8706ca48467357"}, - {file = "watchfiles-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0d8fdfebc50ac7569358f5c75f2b98bb473befccf9498cf23b3e39993bb45a"}, - {file = "watchfiles-0.18.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0f9a22fff1745e2bb930b1e971c4c5b67ea3b38ae17a6adb9019371f80961219"}, - {file = "watchfiles-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b02e7fa03cd4059dd61ff0600080a5a9e7a893a85cb8e5178943533656eec65e"}, - {file = "watchfiles-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a868ce2c7565137f852bd4c863a164dc81306cae7378dbdbe4e2aca51ddb8857"}, - {file = "watchfiles-0.18.1.tar.gz", hash = "sha256:4ec0134a5e31797eb3c6c624dbe9354f2a8ee9c720e0b46fc5b7bab472b7c6d4"}, + {file = "watchfiles-0.19.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:91633e64712df3051ca454ca7d1b976baf842d7a3640b87622b323c55f3345e7"}, + {file = "watchfiles-0.19.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b6577b8c6c8701ba8642ea9335a129836347894b666dd1ec2226830e263909d3"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18b28f6ad871b82df9542ff958d0c86bb0d8310bb09eb8e87d97318a3b5273af"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac19dc9cbc34052394dbe81e149411a62e71999c0a19e1e09ce537867f95ae0"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ea3397aecbc81c19ed7f025e051a7387feefdb789cf768ff994c1228182fda"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0376deac92377817e4fb8f347bf559b7d44ff556d9bc6f6208dd3f79f104aaf"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c75eff897786ee262c9f17a48886f4e98e6cfd335e011c591c305e5d083c056"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb5d45c4143c1dd60f98a16187fd123eda7248f84ef22244818c18d531a249d1"}, + {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:79c533ff593db861ae23436541f481ec896ee3da4e5db8962429b441bbaae16e"}, + {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3d7d267d27aceeeaa3de0dd161a0d64f0a282264d592e335fff7958cc0cbae7c"}, + {file = "watchfiles-0.19.0-cp37-abi3-win32.whl", hash = "sha256:176a9a7641ec2c97b24455135d58012a5be5c6217fc4d5fef0b2b9f75dbf5154"}, + {file = "watchfiles-0.19.0-cp37-abi3-win_amd64.whl", hash = "sha256:945be0baa3e2440151eb3718fd8846751e8b51d8de7b884c90b17d271d34cae8"}, + {file = "watchfiles-0.19.0-cp37-abi3-win_arm64.whl", hash = "sha256:0089c6dc24d436b373c3c57657bf4f9a453b13767150d17284fc6162b2791911"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cae3dde0b4b2078f31527acff6f486e23abed307ba4d3932466ba7cdd5ecec79"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f3920b1285a7d3ce898e303d84791b7bf40d57b7695ad549dc04e6a44c9f120"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9afd0d69429172c796164fd7fe8e821ade9be983f51c659a38da3faaaaac44dc"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68dce92b29575dda0f8d30c11742a8e2b9b8ec768ae414b54f7453f27bdf9545"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5569fc7f967429d4bc87e355cdfdcee6aabe4b620801e2cf5805ea245c06097c"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5471582658ea56fca122c0f0d0116a36807c63fefd6fdc92c71ca9a4491b6b48"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b538014a87f94d92f98f34d3e6d2635478e6be6423a9ea53e4dd96210065e193"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b44221764955b1e703f012c74015306fb7e79a00c15370785f309b1ed9aa8d"}, + {file = "watchfiles-0.19.0.tar.gz", hash = "sha256:d9b073073e048081e502b6c6b0b88714c026a1a4c890569238d04aca5f9ca74b"}, ] [package.dependencies] @@ -1905,14 +1891,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.3.2" +version = "2.3.3" description = "The comprehensive WSGI web application library." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.3.2-py3-none-any.whl", hash = "sha256:b7b8bc1609f35ae8e45d48a9b58d7a4eb1e41eec148d37e977e5df6ebf3398b2"}, - {file = "Werkzeug-2.3.2.tar.gz", hash = "sha256:2f3278e9ef61511cdf82cc28fc5da0f5b501dd8f01ecf5ef6a5d810048f68702"}, + {file = "Werkzeug-2.3.3-py3-none-any.whl", hash = "sha256:4866679a0722de00796a74086238bb3b98d90f423f05de039abb09315487254a"}, + {file = "Werkzeug-2.3.3.tar.gz", hash = "sha256:a987caf1092edc7523edb139edb20c70571c4a8d5eed02e0b547b4739174d091"}, ] [package.dependencies] @@ -1955,4 +1941,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "7eba1b2d0fd17dacea153cb3f6ebdcb11d7888902cbb3a88a65f3c6c38f65699" +content-hash = "9974b6c53a244765e15677b5266c0922601f51ea16068cb621184c89ce4b7f22" diff --git a/pyproject.toml b/pyproject.toml index d75a1d4c..ea94f2cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,48 +62,49 @@ asgiref = "^3.6.0" bcrypt = "^4.0.1" bleach = "^6.0.0" email-validator = "^1.3.1" -fakeredis = "^2.10.0" +fakeredis = "^2.11.2" feedgen = "^0.9.0" -httpx = "^0.23.3" +httpx = "^0.24.0" itsdangerous = "^2.1.2" lxml = "^4.9.2" -orjson = "^3.8.7" -protobuf = "^4.22.1" -pygit2 = "^1.11.1" +orjson = "^3.8.11" +protobuf = "^4.22.4" +pygit2 = "^1.12.0" python-multipart = "^0.0.6" -redis = "^4.5.1" -requests = "^2.28.2" +redis = "^4.5.4" +requests = "^2.30.0" paginate = "^0.5.6" +urllib3 = "^1.26.15" # SQL -alembic = "^1.10.2" +alembic = "^1.10.4" mysqlclient = "^2.1.1" Authlib = "^1.2.0" Jinja2 = "^3.1.2" -Markdown = "^3.4.1" -Werkzeug = "^2.2.3" -SQLAlchemy = "^1.4.46" +Markdown = "^3.4.3" +Werkzeug = "^2.3.3" +SQLAlchemy = "^1.4.48" # ASGI -uvicorn = "^0.21.0" +uvicorn = "^0.22.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.3" -prometheus-fastapi-instrumentator = "^5.11.1" +prometheus-fastapi-instrumentator = "^6.0.0" pytest-xdist = "^3.2.1" -filelock = "^3.9.1" +filelock = "^3.12.0" posix-ipc = "^1.1.1" pyalpm = "^0.10.6" -fastapi = "^0.94.1" +fastapi = "^0.95.1" srcinfo = "^0.1.2" -tomlkit = "^0.11.6" +tomlkit = "^0.11.8" [tool.poetry.dev-dependencies] -coverage = "^7.2.1" -pytest = "^7.2.2" -pytest-asyncio = "^0.20.3" +coverage = "^7.2.5" +pytest = "^7.3.1" +pytest-asyncio = "^0.21.0" pytest-cov = "^4.0.0" pytest-tap = "^3.3" -watchfiles = "^0.18.1" +watchfiles = "^0.19.0" [tool.poetry.scripts] aurweb-git-auth = "aurweb.git.auth:main" From 1d627edbe72de5267cbd8b4f239bb1c61cbaba4c Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 6 May 2023 20:34:54 +0100 Subject: [PATCH 1743/1891] chore(release): prepare for 6.2.3 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ea94f2cd..83d10b5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.2" +version = "v6.2.3" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From d2e8fa02491f1b7824daf37ca3a1646fd06c17e7 Mon Sep 17 00:00:00 2001 From: "Daniel M. Capella" Date: Sat, 6 May 2023 16:46:07 -0400 Subject: [PATCH 1744/1891] chore(deps): "Group all minor and patch updates together" Treat FastAPI separately due to regular breakage. Co-authored-by: moson-mo --- renovate.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 39a2b6e9..b6721721 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,13 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base" + "config:base", + "group:allNonMajor" + ], + "packageRules": [ + { + "groupName": "fastapi", + "matchPackageNames": ["fastapi"] + } ] } From 3253a6ad29dc3ed83d0fde90d8f93c8b0c1a6730 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 7 May 2023 09:58:17 +0200 Subject: [PATCH 1745/1891] fix(deps): remove urllib3 from dependency list Previously pinned urllib3 to v1.x. This is not needed though. The incompatibility of v2.x is with poetry itself, but not aurweb. Signed-off-by: moson-mo --- poetry.lock | 33 +++++++++++++++++---------------- pyproject.toml | 3 +-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/poetry.lock b/poetry.lock index 54a7701d..388379d9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -151,14 +151,14 @@ css = ["tinycss2 (>=1.1.0,<1.2)"] [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ] [[package]] @@ -482,18 +482,18 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] name = "email-validator" -version = "1.3.1" +version = "2.0.0.post2" description = "A robust email address syntax and deliverability validation library." category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" files = [ - {file = "email_validator-1.3.1-py2.py3-none-any.whl", hash = "sha256:49a72f5fa6ed26be1c964f0567d931d10bf3fdeeacdf97bc26ef1cd2a44e0bda"}, - {file = "email_validator-1.3.1.tar.gz", hash = "sha256:d178c5c6fa6c6824e9b04f199cf23e79ac15756786573c190d2ad13089411ad2"}, + {file = "email_validator-2.0.0.post2-py3-none-any.whl", hash = "sha256:2466ba57cda361fb7309fd3d5a225723c788ca4bbad32a0ebd5373b99730285c"}, + {file = "email_validator-2.0.0.post2.tar.gz", hash = "sha256:1ff6e86044200c56ae23595695c54e9614f4a9551e0e393614f764860b3d7900"}, ] [package.dependencies] -dnspython = ">=1.15.0" +dnspython = ">=2.0.0" idna = ">=2.0.0" [[package]] @@ -1808,20 +1808,21 @@ files = [ [[package]] name = "urllib3" -version = "1.26.15" +version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7" files = [ - {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, - {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, + {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, + {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" @@ -1941,4 +1942,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "9974b6c53a244765e15677b5266c0922601f51ea16068cb621184c89ce4b7f22" +content-hash = "6a96903be0358aa6d6ef1926edf6158dd36060f8bec66bd8bf8b0ee04e7795df" diff --git a/pyproject.toml b/pyproject.toml index 83d10b5d..b27d281a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ aiofiles = "^23.1.0" asgiref = "^3.6.0" bcrypt = "^4.0.1" bleach = "^6.0.0" -email-validator = "^1.3.1" +email-validator = "^2.0.0.post2" fakeredis = "^2.11.2" feedgen = "^0.9.0" httpx = "^0.24.0" @@ -74,7 +74,6 @@ python-multipart = "^0.0.6" redis = "^4.5.4" requests = "^2.30.0" paginate = "^0.5.6" -urllib3 = "^1.26.15" # SQL alembic = "^1.10.4" From d0b0e4d88b465796bf3ff5bfbd6f709e4e367560 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Wed, 17 May 2023 18:22:53 +0200 Subject: [PATCH 1746/1891] fix: update repo information with aurblup script Currently, the "Repo" column in "OfficialProviders" is not updated when a package is moved from one repository to another. Note that we only save a package/provides combination once, hence if a package is available in core and testing at the same time, it would only put just one record into the OfficialProviders table. We iterate through the repos one by one and the last value is kept for mapping a (package/provides) combination to a repo. Due to that, the repos listed in the "sync-db" config setting should be ordered such that the "testing" repos are listed first. Signed-off-by: moson-mo --- aurweb/scripts/aurblup.py | 11 +++++++++++ test/test_aurblup.py | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/aurweb/scripts/aurblup.py b/aurweb/scripts/aurblup.py index 340d1ccd..10da1d98 100755 --- a/aurweb/scripts/aurblup.py +++ b/aurweb/scripts/aurblup.py @@ -49,6 +49,7 @@ def _main(force: bool = False): .all() ) + # delete providers not existing in any of our alpm repos for name, provides in old_providers.difference(providers): db.delete_all( db.query(OfficialProvider).filter( @@ -59,10 +60,20 @@ def _main(force: bool = False): ) ) + # add new providers that do not yet exist in our DB for name, provides in providers.difference(old_providers): repo = repomap.get((name, provides)) db.create(OfficialProvider, Name=name, Repo=repo, Provides=provides) + # update providers where a pkg was moved from one repo to another + all_providers = db.query(OfficialProvider) + + for op in all_providers: + new_repo = repomap.get((op.Name, op.Provides)) + + if op.Repo != new_repo: + op.Repo = new_repo + def main(force: bool = False): db.get_engine() diff --git a/test/test_aurblup.py b/test/test_aurblup.py index 93a832f9..1489677d 100644 --- a/test/test_aurblup.py +++ b/test/test_aurblup.py @@ -87,3 +87,23 @@ def test_aurblup_cleanup(alpm_db: AlpmDatabase): db.query(OfficialProvider).filter(OfficialProvider.Name == "fake package").all() ) assert len(providers) == 0 + + +def test_aurblup_repo_change(alpm_db: AlpmDatabase): + # Add a package and sync up the database. + alpm_db.add("pkg", "1.0", "x86_64", provides=["pkg2", "pkg3"]) + aurblup.main() + + # We should find an entry with repo "test" + op = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg").first() + assert op.Repo == "test" + + # Modify the repo to something that does not exist. + op.Repo = "nonsense" + + # Run our script. + aurblup.main() + + # Repo should be set back to "test" + db.refresh(op) + assert op.Repo == "test" From 146943b3b6bccfb07cfbd534248810805774d09c Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 18 May 2023 13:06:21 +0200 Subject: [PATCH 1747/1891] housekeep: support new default repos after git migration community is merged into extra testing -> core-testing & extra-testing Announcement: https://archlinux.org/news/git-migration-announcement/ We list "testing" repos first: See d0b0e4d88b465796bf3ff5bfbd6f709e4e367560 Co-authored-by: artafinde Signed-off-by: moson-mo --- conf/config.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.defaults b/conf/config.defaults index 0cd4b9d4..bb390d8a 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -119,7 +119,7 @@ max-blob-size = 256000 [aurblup] db-path = /srv/http/aurweb/aurblup/ -sync-dbs = core extra community multilib testing community-testing +sync-dbs = core-testing extra-testing multilib-testing core extra multilib server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] From f24fae0ce6547367de6e99a1075ab1009d6e0d14 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 8 May 2023 18:22:16 +0200 Subject: [PATCH 1748/1891] feat: Add "Requests" filter option for package name - Add package name textbox for filtering requests (with auto-suggest) - Make "x pending requests" a link for TU/Dev on the package details page Signed-off-by: moson-mo --- aurweb/routers/requests.py | 16 +++++++++- po/aurweb.pot | 4 +++ static/js/typeahead-requests.js | 6 ++++ templates/partials/packages/actions.html | 18 +++++++---- templates/requests.html | 11 ++++++- test/test_packages_routes.py | 24 ++++++++++++++- test/test_requests.py | 38 ++++++++++++++++++++++++ 7 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 static/js/typeahead-requests.js diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index a259dd63..585dc157 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -40,13 +40,21 @@ async def requests( filter_accepted: bool = False, filter_rejected: bool = False, filter_maintainer_requests: bool = False, + filter_pkg_name: str = None, ): context = make_context(request, "Requests") context["q"] = dict(request.query_params) + # Set pending filter by default if no status filter was provided. + # In case we got a package name filter, but no status filter, + # we enable the other ones too. if not dict(request.query_params).keys() & FILTER_PARAMS: filter_pending = True + if filter_pkg_name: + filter_closed = True + filter_accepted = True + filter_rejected = True O, PP = util.sanitize_params(str(O), str(PP)) context["O"] = O @@ -56,6 +64,7 @@ async def requests( context["filter_accepted"] = filter_accepted context["filter_rejected"] = filter_rejected context["filter_maintainer_requests"] = filter_maintainer_requests + context["filter_pkg_name"] = filter_pkg_name Maintainer = orm.aliased(User) # A PackageRequest query @@ -78,7 +87,7 @@ async def requests( rejected_count = 0 + query.filter(PackageRequest.Status == REJECTED_ID).count() context["rejected_requests"] = rejected_count - # Apply filters + # Apply status filters in_filters = [] if filter_pending: in_filters.append(PENDING_ID) @@ -89,6 +98,11 @@ async def requests( if filter_rejected: in_filters.append(REJECTED_ID) filtered = query.filter(PackageRequest.Status.in_(in_filters)) + + # Name filter + if filter_pkg_name: + filtered = filtered.filter(PackageBase.Name == filter_pkg_name) + # Additionally filter for requests made from package maintainer if filter_maintainer_requests: filtered = filtered.filter(PackageRequest.UsersID == PackageBase.MaintainerUID) diff --git a/po/aurweb.pot b/po/aurweb.pot index f4e3c1ba..b975ab91 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2362,3 +2362,7 @@ msgstr "" #: templates/partials/packages/comment_form.html msgid "Cancel" msgstr "" + +#: templates/requests.html +msgid "Package name" +msgstr "" diff --git a/static/js/typeahead-requests.js b/static/js/typeahead-requests.js new file mode 100644 index 00000000..9f636eab --- /dev/null +++ b/static/js/typeahead-requests.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + const input = document.getElementById('id_filter_pkg_name'); + const form = document.getElementById('todolist_filter'); + const type = 'suggest-pkgbase'; + typeahead.init(type, input, form); +}); diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index fa8c994f..ae8cf141 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -97,11 +97,19 @@ {% endif %} {% if requests %} -

  • - - {{ requests | tn("%d pending request", "%d pending requests") | format(requests) }} - -
  • + {% if request.user.has_credential(creds.PKGREQ_LIST) %} +
  • + + {{ requests | tn("%d pending request", "%d pending requests") | format(requests) }} + +
  • + {% else %} +
  • + + {{ requests | tn("%d pending request", "%d pending requests") | format(requests) }} + +
  • + {% endif %} {% endif %}
  • diff --git a/templates/requests.html b/templates/requests.html index 697fbedb..9eb911f5 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -62,7 +62,13 @@ value="True" {{ "checked" if filter_maintainer_requests == true }}/>
  • - + + +
    +
    +
    +

    @@ -194,4 +200,7 @@ {% include "partials/pager.html" %} {% endif %} + + + {% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 21ccdd7b..93dc404a 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -555,6 +555,16 @@ def test_package_authenticated(client: TestClient, user: User, package: Package) for expected_text in expected: assert expected_text in resp.text + # make sure we don't have these. Only for Maintainer/TUs/Devs + not_expected = [ + "Disown Package", + "View Requests", + "Delete Package", + "Merge Package", + ] + for unexpected_text in not_expected: + assert unexpected_text not in resp.text + # When no requests are up, make sure we don't see the display for them. root = parse_root(resp.text) selector = '//div[@id="actionlist"]/ul/li/span[@class="flagged"]' @@ -586,8 +596,19 @@ def test_package_authenticated_maintainer( for expected_text in expected: assert expected_text in resp.text + # make sure we don't have these. Only for TUs/Devs + not_expected = [ + "1 pending request", + "Delete Package", + "Merge Package", + ] + for unexpected_text in not_expected: + assert unexpected_text not in resp.text -def test_package_authenticated_tu(client: TestClient, tu_user: User, package: Package): + +def test_package_authenticated_tu( + client: TestClient, tu_user: User, package: Package, pkgreq: PackageRequest +): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: request.cookies = cookies @@ -603,6 +624,7 @@ def test_package_authenticated_tu(client: TestClient, tu_user: User, package: Pa "Vote for this package", "Enable notifications", "Manage Co-Maintainers", + "1 pending request", "Submit Request", "Delete Package", "Merge Package", diff --git a/test/test_requests.py b/test/test_requests.py index eb05596c..7ddb76a0 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -912,6 +912,44 @@ def test_requests_for_maintainer_requests( assert len(rows) == 2 +def test_requests_with_package_name_filter( + client: TestClient, + tu_user: User, + user2: User, + packages: list[Package], + requests: list[PackageRequest], +): + # test as TU + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + request.cookies = cookies + resp = request.get( + "/requests", + params={"filter_pkg_name": packages[0].PackageBase.Name}, + ) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + # We only expect 1 request for our first package + assert len(rows) == 1 + + # test as regular user, not related to our package + cookies = {"AURSID": user2.login(Request(), "testPassword")} + with client as request: + request.cookies = cookies + resp = request.get( + "/requests", + params={"filter_pkg_name": packages[0].PackageBase.Name}, + ) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + # We don't expect to get any requests + assert len(rows) == 0 + + def test_requests_by_deleted_users( client: TestClient, user: User, tu_user: User, pkgreq: PackageRequest ): From 7a88aeb673c420da1dea0b0a29d5f0b8e921b3a0 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 8 May 2023 21:24:17 +0200 Subject: [PATCH 1749/1891] chore: update .gitignore for test-emails emails generated when running tests are stored in test-emails/ dir Signed-off-by: moson-mo --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 414077be..a3314c27 100644 --- a/.gitignore +++ b/.gitignore @@ -47,5 +47,9 @@ doc/rpc.html # Ignore coverage report coverage.xml + # Ignore pytest report report.xml + +# Ignore test emails +test-emails/ From 1b41e8572a087c8d9b1d2cc59fffa459e89ed5ac Mon Sep 17 00:00:00 2001 From: renovate Date: Fri, 26 May 2023 02:24:39 +0000 Subject: [PATCH 1750/1891] fix(deps): update all non-major dependencies --- poetry.lock | 360 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 180 insertions(+), 182 deletions(-) diff --git a/poetry.lock b/poetry.lock index 388379d9..3a273be4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.10.4" +version = "1.11.1" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.10.4-py3-none-any.whl", hash = "sha256:43942c3d4bf2620c466b91c0f4fca136fe51ae972394a0cc8b90810d664e4f5c"}, - {file = "alembic-1.10.4.tar.gz", hash = "sha256:295b54bbb92c4008ab6a7dcd1e227e668416d6f84b98b3c4446a2bc6214a556b"}, + {file = "alembic-1.11.1-py3-none-any.whl", hash = "sha256:dc871798a601fab38332e38d6ddb38d5e734f60034baeb8e2db5b642fccd8ab8"}, + {file = "alembic-1.11.1.tar.gz", hash = "sha256:6a810a6b012c88b33458fceb869aef09ac75d6ace5291915ba7fae44de372c01"}, ] [package.dependencies] @@ -55,16 +55,19 @@ trio = ["trio (>=0.16,<0.22)"] [[package]] name = "asgiref" -version = "3.6.0" +version = "3.7.1" description = "ASGI specs, helper code, and adapters" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "asgiref-3.6.0-py3-none-any.whl", hash = "sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac"}, - {file = "asgiref-3.6.0.tar.gz", hash = "sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506"}, + {file = "asgiref-3.7.1-py3-none-any.whl", hash = "sha256:33958cb2e4b3cd8b1b06ef295bd8605cde65b11df51d3beab39e2e149a610ab3"}, + {file = "asgiref-3.7.1.tar.gz", hash = "sha256:8de379fcc383bcfe4507e229fc31209ea23d4831c850f74063b2c11639474dd2"}, ] +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] @@ -352,63 +355,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.5" +version = "7.2.6" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c"}, - {file = "coverage-7.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a"}, - {file = "coverage-7.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f"}, - {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a"}, - {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a"}, - {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11"}, - {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5"}, - {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c"}, - {file = "coverage-7.2.5-cp310-cp310-win32.whl", hash = "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5"}, - {file = "coverage-7.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c"}, - {file = "coverage-7.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce"}, - {file = "coverage-7.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88"}, - {file = "coverage-7.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e"}, - {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2"}, - {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139"}, - {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8"}, - {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed"}, - {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6"}, - {file = "coverage-7.2.5-cp311-cp311-win32.whl", hash = "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b"}, - {file = "coverage-7.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068"}, - {file = "coverage-7.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1"}, - {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33"}, - {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade"}, - {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5"}, - {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47"}, - {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd"}, - {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969"}, - {file = "coverage-7.2.5-cp37-cp37m-win32.whl", hash = "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718"}, - {file = "coverage-7.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0"}, - {file = "coverage-7.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84"}, - {file = "coverage-7.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790"}, - {file = "coverage-7.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771"}, - {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045"}, - {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614"}, - {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3"}, - {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd"}, - {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1"}, - {file = "coverage-7.2.5-cp38-cp38-win32.whl", hash = "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813"}, - {file = "coverage-7.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212"}, - {file = "coverage-7.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b"}, - {file = "coverage-7.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200"}, - {file = "coverage-7.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5"}, - {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e"}, - {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303"}, - {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3"}, - {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a"}, - {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1"}, - {file = "coverage-7.2.5-cp39-cp39-win32.whl", hash = "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31"}, - {file = "coverage-7.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252"}, - {file = "coverage-7.2.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3"}, - {file = "coverage-7.2.5.tar.gz", hash = "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"}, + {file = "coverage-7.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:496b86f1fc9c81a1cd53d8842ef712e950a4611bba0c42d33366a7b91ba969ec"}, + {file = "coverage-7.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbe6e8c0a9a7193ba10ee52977d4d5e7652957c1f56ccefed0701db8801a2a3b"}, + {file = "coverage-7.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d06b721c2550c01a60e5d3093f417168658fb454e5dfd9a23570e9bffe39a1"}, + {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77a04b84d01f0e12c66f16e69e92616442dc675bbe51b90bfb074b1e5d1c7fbd"}, + {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35db06450272473eab4449e9c2ad9bc6a0a68dab8e81a0eae6b50d9c2838767e"}, + {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6727a0d929ff0028b1ed8b3e7f8701670b1d7032f219110b55476bb60c390bfb"}, + {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aac1d5fdc5378f6bac2c0c7ebe7635a6809f5b4376f6cf5d43243c1917a67087"}, + {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c9e4a5eb1bbc3675ee57bc31f8eea4cd7fb0cbcbe4912cf1cb2bf3b754f4a80"}, + {file = "coverage-7.2.6-cp310-cp310-win32.whl", hash = "sha256:71f739f97f5f80627f1fee2331e63261355fd1e9a9cce0016394b6707ac3f4ec"}, + {file = "coverage-7.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:fde5c7a9d9864d3e07992f66767a9817f24324f354caa3d8129735a3dc74f126"}, + {file = "coverage-7.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc7b667f8654376e9353dd93e55e12ce2a59fb6d8e29fce40de682273425e044"}, + {file = "coverage-7.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:697f4742aa3f26c107ddcb2b1784a74fe40180014edbd9adaa574eac0529914c"}, + {file = "coverage-7.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:541280dde49ce74a4262c5e395b48ea1207e78454788887118c421cb4ffbfcac"}, + {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7f1a8328eeec34c54f1d5968a708b50fc38d31e62ca8b0560e84a968fbf9a9"}, + {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbd58eb5a2371bf160590f4262109f66b6043b0b991930693134cb617bc0169"}, + {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae82c5f168d2a39a5d69a12a69d4dc23837a43cf2ca99be60dfe59996ea6b113"}, + {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f5440cdaf3099e7ab17a5a7065aed59aff8c8b079597b61c1f8be6f32fe60636"}, + {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a6f03f87fea579d55e0b690d28f5042ec1368650466520fbc400e7aeaf09e995"}, + {file = "coverage-7.2.6-cp311-cp311-win32.whl", hash = "sha256:dc4d5187ef4d53e0d4c8eaf530233685667844c5fb0b855fea71ae659017854b"}, + {file = "coverage-7.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:c93d52c3dc7b9c65e39473704988602300e3cc1bad08b5ab5b03ca98bbbc68c1"}, + {file = "coverage-7.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42c692b55a647a832025a4c048007034fe77b162b566ad537ce65ad824b12a84"}, + {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7786b2fa7809bf835f830779ad285215a04da76293164bb6745796873f0942d"}, + {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25bad4196104761bc26b1dae9b57383826542ec689ff0042f7f4f4dd7a815cba"}, + {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2692306d3d4cb32d2cceed1e47cebd6b1d2565c993d6d2eda8e6e6adf53301e6"}, + {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:392154d09bd4473b9d11351ab5d63391f3d5d24d752f27b3be7498b0ee2b5226"}, + {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fa079995432037b5e2ef5ddbb270bcd2ded9f52b8e191a5de11fe59a00ea30d8"}, + {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d712cefff15c712329113b01088ba71bbcef0f7ea58478ca0bbec63a824844cb"}, + {file = "coverage-7.2.6-cp37-cp37m-win32.whl", hash = "sha256:004948e296149644d208964300cb3d98affc5211e9e490e9979af4030b0d6473"}, + {file = "coverage-7.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:c1d7a31603c3483ac49c1726723b0934f88f2c011c660e6471e7bd735c2fa110"}, + {file = "coverage-7.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3436927d1794fa6763b89b60c896f9e3bd53212001026ebc9080d23f0c2733c1"}, + {file = "coverage-7.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44c9b9f1a245f3d0d202b1a8fa666a80b5ecbe4ad5d0859c0fb16a52d9763224"}, + {file = "coverage-7.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e3783a286d5a93a2921396d50ce45a909aa8f13eee964465012f110f0cbb611"}, + {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cff6980fe7100242170092bb40d2b1cdad79502cd532fd26b12a2b8a5f9aee0"}, + {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c534431153caffc7c495c3eddf7e6a6033e7f81d78385b4e41611b51e8870446"}, + {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3062fd5c62df988cea9f2972c593f77fed1182bfddc5a3b12b1e606cb7aba99e"}, + {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6284a2005e4f8061c58c814b1600ad0074ccb0289fe61ea709655c5969877b70"}, + {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:97729e6828643f168a2a3f07848e1b1b94a366b13a9f5aba5484c2215724edc8"}, + {file = "coverage-7.2.6-cp38-cp38-win32.whl", hash = "sha256:dc11b42fa61ff1e788dd095726a0aed6aad9c03d5c5984b54cb9e1e67b276aa5"}, + {file = "coverage-7.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:cbcc874f454ee51f158afd604a315f30c0e31dff1d5d5bf499fc529229d964dd"}, + {file = "coverage-7.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d3cacc6a665221108ecdf90517a8028d07a2783df3417d12dcfef1c517e67478"}, + {file = "coverage-7.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:272ab31228a9df857ab5df5d67936d8861464dc89c5d3fab35132626e9369379"}, + {file = "coverage-7.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a8723ccec4e564d4b9a79923246f7b9a8de4ec55fa03ec4ec804459dade3c4f"}, + {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5906f6a84b47f995cd1bf0aca1c72d591c55ee955f98074e93660d64dfc66eb9"}, + {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c139b7ab3f0b15f9aad0a3fedef5a1f8c0b2bdc291d88639ca2c97d3682416"}, + {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a5ffd45c6b93c23a8507e2f436983015c6457aa832496b6a095505ca2f63e8f1"}, + {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4f3c7c19581d471af0e9cb49d928172cd8492cd78a2b7a4e82345d33662929bb"}, + {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e8c0e79820cdd67978e1120983786422d279e07a381dbf89d03bbb23ec670a6"}, + {file = "coverage-7.2.6-cp39-cp39-win32.whl", hash = "sha256:13cde6bb0e58fb67d09e2f373de3899d1d1e866c5a9ff05d93615f2f54fbd2bb"}, + {file = "coverage-7.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:6b9f64526286255735847aed0221b189486e0b9ed943446936e41b7e44b08783"}, + {file = "coverage-7.2.6-pp37.pp38.pp39-none-any.whl", hash = "sha256:6babcbf1e66e46052442f10833cfc4a0d3554d8276aa37af8531a83ed3c1a01d"}, + {file = "coverage-7.2.6.tar.gz", hash = "sha256:2025f913f2edb0272ef15d00b1f335ff8908c921c8eb2013536fcaf61f5a683d"}, ] [package.dependencies] @@ -528,14 +531,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.11.2" +version = "2.13.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.11.2-py3-none-any.whl", hash = "sha256:69a504328a89e5e5f2d05a4236b570fb45244c96997c5002c8c6a0503b95f289"}, - {file = "fakeredis-2.11.2.tar.gz", hash = "sha256:e0fef512b8ec49679d373456aa4698a4103005ecd7ca0b13170a2c1d3af949c5"}, + {file = "fakeredis-2.13.0-py3-none-any.whl", hash = "sha256:df7bb44fb9e593970c626325230e1c321f954ce7b204d4c4452eae5233d554ed"}, + {file = "fakeredis-2.13.0.tar.gz", hash = "sha256:53f00f44f771d2b794f1ea036fa07a33476ab7368f1b0e908daab3eff80336f6"}, ] [package.dependencies] @@ -758,14 +761,14 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" -version = "0.24.0" +version = "0.24.1" description = "The next generation HTTP client." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "httpx-0.24.0-py3-none-any.whl", hash = "sha256:447556b50c1921c351ea54b4fe79d91b724ed2b027462ab9a329465d147d5a4e"}, - {file = "httpx-0.24.0.tar.gz", hash = "sha256:507d676fc3e26110d41df7d35ebd8b3b8585052450f4097401c9be59d928c63e"}, + {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, + {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, ] [package.dependencies] @@ -1101,63 +1104,58 @@ files = [ [[package]] name = "orjson" -version = "3.8.11" +version = "3.8.14" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.7" files = [ - {file = "orjson-3.8.11-cp310-cp310-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:9fa900bdd84b4576c8dd6f3e2a00b35797f29283af328c6e3d70addfa4c2d599"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1103e597c16f82c241e1b02beadc9c91cecd93e60433ca73cb6464dcc235f37c"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d70b6db9d4e1e6057829cd7fe119c217cebaf989f88d14b2445fa69fc568d03e"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3afccf7f8684dca7f017837a315de0a1ab5c095de22a4eed206d079f9325ed72"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fedcc428416e23a6c9de62a000c22ae33bbe0108302ad5d5935e29ea739bf37"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf48ed8d4b6ab9f23b7ee642462369d7133412d72824bad89f9bf4311c06c6a1"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c55065bc2075a5ea6ffb30462d84fd3aa5bbb7ae600855c325ee5753feec715"}, - {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:08729e339ff3146e6de56c1166f014c3d2ec3e79ffb76d6c55d52cc892e5e477"}, - {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:358e515b8b19a275b259f5ee1e0efa2859b1d976b5ed5d016ac59f9e6c8788a3"}, - {file = "orjson-3.8.11-cp310-none-win_amd64.whl", hash = "sha256:62eb8bdcf6f4cdbe12743e88ad98696277a75f91a35e8fb93a7ea2b9f4a7000c"}, - {file = "orjson-3.8.11-cp311-cp311-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:982ab319b7a5ece4199caf2a2b3a28e62a8e289cb6418548ef98bced7e2a6cfe"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e14903bfeb591a9117b7d40d81e3ebca9700b4e77bd829d6f22ea57941bb0ebf"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58c068f93d701f9466f667bf3b5cb4e4946aee940df2b07ca5101f1cf1b60ce4"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9486963d2e65482c565dacb366adb36d22aa22acf7274b61490244c3d87fa631"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c3b5405edc3a5f9e34516ee1a729f6c46aecf6de960ae07a7b3e95ebdd0e1d9"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b65424ceee82b94e3613233b67ef110dc58f9d83b0076ec47a506289552a861"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:173b8f8c750590f432757292cfb197582e5c14347b913b4017561d47af0e759b"}, - {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37f38c8194ce086e6a9816b4b8dde5e7f383feeed92feec0385d99baf64f9b6e"}, - {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:553fdaf9f4b5060a0dcc517ae0c511c289c184a83d6719d03c5602ed0eef0390"}, - {file = "orjson-3.8.11-cp311-none-win_amd64.whl", hash = "sha256:12f647d4da0aab1997e25bed4fa2b76782b5b9d2d1bf3066b5f0a57d34d833c4"}, - {file = "orjson-3.8.11-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:71a656f1c62e84c69060093e20cedff6a92e472d53ff5b8b9026b1b298542a68"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:176d742f53434541e50a5e659694073aa51dcbd8f29a1708a4fa1a320193c615"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b369019e597b59c4b97e9f925a3b725321fa1481c129d76c74c6ea3823f5d1e8"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a53b3c02a38aadc5302661c2ca18645093971488992df77ce14fef16f598b2e"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d7b050135669d2335e40120215ad4120e29958c139f8bab68ce06a1cb1a1b2c"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66f0c9e4e8f6641497a7dc50591af3704b11468e9fc90cfb5874f28b0a61edb5"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:235926b38ed9b76ab2bca99ff26ece79c1c46bc10079b06e660b087aecffbe69"}, - {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c2d3e6b65458ed71b6797f321d6e8bfeeadee9d3d31cac47806a608ea745edd7"}, - {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4118dcd2b5a27a22af5ad92414073f25d93bca1868f1f580056003c84841062f"}, - {file = "orjson-3.8.11-cp37-none-win_amd64.whl", hash = "sha256:b68a07794834b7bd53ae2a8b4fe4bf010734cae3f0917d434c83b97acf8e5bce"}, - {file = "orjson-3.8.11-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:98befa717efaab7ddb847ebe47d473f6bd6f0cb53e98e6c3d487c7c58ba2e174"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f9415b86ef154bf247fa78a6918aac50089c296e26fb6cf15bc9d7e6402a1f8"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7aeefac55848aeb29f20b91fa55f9e488f446201bb1bb31dc17480d113d8955"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d47f97b99beb9bcac6e288a76b559543a61e0187443d8089204b757726b1d000"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7d5aecccfaf2052cd07ed5bec8efba9ddfea055682fcd346047b1a3e9da3034"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b60dfc1251742e79bb075d7a7c4e37078b932a02e6f005c45761bd90c69189"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:ef52f1d5a2f89ef9049781c90ea35d5edf74374ed6ed515c286a706d1b290267"}, - {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7b4fae3b8fc69c8e76f1c0694f3decfe8a57f87e7ac7779ebb59cd71135438"}, - {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f4e4a1001933166fd1c257b920b241b35322bef99ed7329338bf266ac053abe7"}, - {file = "orjson-3.8.11-cp38-none-win_amd64.whl", hash = "sha256:5ff10789cbc08a9fd94507c907ba55b9315e99f20345ff8ef34fac432dacd948"}, - {file = "orjson-3.8.11-cp39-cp39-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:c67ac094a4dde914297543af19f22532d7124f3a35245580d8b756c4ff2f5884"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf201e77d3fac9d8d6f68d872ef45dccfe46f30b268bb88b6c5af5065b433aa"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3485c458670c0edb79ca149fe201f199dd9ccfe7ca3acbdef617e3c683e7b97f"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e97fdbb779a3b8f5d9fc7dfddef5325f81ee45897eb7cb4638d5d9734d42514"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2fc050f8e7f2e4061c8c9968ad0be745b11b03913b77ffa8ceca65914696886c"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2ef933da50b31c112b252be03d1ef59e0d0552c1a08e48295bd529ce42aaab8"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:714c3e2be6ed7e4ff6e887926d6e171bfd94fdee76d7d3bfa74ee19237a2d49d"}, - {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7e4ded77ac7432a155d1d27a83bcadf722750aea3b9e6c4d47f2a92054ab71cb"}, - {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:382f15861a4bf447ab9d07106010e61b217ef6d4245c6cf64af0c12c4c5e2346"}, - {file = "orjson-3.8.11-cp39-none-win_amd64.whl", hash = "sha256:0bc3d1b93a73b46a698c054697eb2d27bdedbc5ea0d11ec5f1a6bfbec36346b5"}, - {file = "orjson-3.8.11.tar.gz", hash = "sha256:882c77126c42dd93bb35288632d69b1e393863a2b752de3e5fe0112833609496"}, + {file = "orjson-3.8.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7a7b0fead2d0115ef927fa46ad005d7a3988a77187500bf895af67b365c10d1f"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca90db8f551b8960da95b0d4cad6c0489df52ea03585b6979595be7b31a3f946"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4ac01a3db4e6a98a8ad1bb1a3e8bfc777928939e87c04e93e0d5006df574a4b"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf6825e160e4eb0ef65ce37d8c221edcab96ff2ffba65e5da2437a60a12b3ad1"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80e62afe49e6bfc706e041faa351d7520b5f86572b8e31455802251ea989613"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6112194c11e611596eed72f46efb0e6b4812682eff3c7b48473d1146c3fa0efb"}, + {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:739f9f633e1544f2a477fa3bef380f488c8dca6e2521c8dc36424b12554ee31e"}, + {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d3d8faded5a514b80b56d0429eb38b429d7a810f8749d25dc10a0cc15b8a3c8"}, + {file = "orjson-3.8.14-cp310-none-win_amd64.whl", hash = "sha256:0bf00c42333412a9338297bf888d7428c99e281e20322070bde8c2314775508b"}, + {file = "orjson-3.8.14-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d66966fd94719beb84e8ed84833bc59c3c005d3d2d0c42f11d7552d3267c6de7"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087c0dc93379e8ba2d59e9f586fab8de8c137d164fccf8afd5523a2137570917"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04c70dc8ca79b0072a16d82f94b9d9dd6598a43dd753ab20039e9f7d2b14f017"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aedba48264fe87e5060c0e9c2b28909f1e60626e46dc2f77e0c8c16939e2e1f7"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01640ab79111dd97515cba9fab7c66cb3b0967b0892cc74756a801ff681a01b6"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b206cca6836a4c6683bcaa523ab467627b5f03902e5e1082dc59cd010e6925f"}, + {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee0299b2dda9afce351a5e8c148ea7a886de213f955aa0288fb874fb44829c36"}, + {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:31a2a29be559e92dcc5c278787b4166da6f0d45675b59a11c4867f5d1455ebf4"}, + {file = "orjson-3.8.14-cp311-none-win_amd64.whl", hash = "sha256:20b7ffc7736000ea205f9143df322b03961f287b4057606291c62c842ff3c5b5"}, + {file = "orjson-3.8.14-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de1ee13d6b6727ee1db38722695250984bae81b8fc9d05f1176c74d14b1322d9"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ee09bfbf1d54c127d3061f6721a1a11d2ce502b50597c3d0d2e1bd2d235b764"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:97ebb7fab5f1ae212a6501f17cb7750a6838ffc2f1cebbaa5dec1a90038ca3c6"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38ca39bae7fbc050332a374062d4cdec28095540fa8bb245eada467897a3a0bb"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:92374bc35b6da344a927d5a850f7db80a91c7b837de2f0ea90fc870314b1ff44"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9393a63cb0424515ec5e434078b3198de6ec9e057f1d33bad268683935f0a5d5"}, + {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5fb66f0ac23e861b817c858515ac1f74d1cd9e72e3f82a5b2c9bae9f92286adc"}, + {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19415aaf30525a5baff0d72a089fcdd68f19a3674998263c885c3908228c1086"}, + {file = "orjson-3.8.14-cp37-none-win_amd64.whl", hash = "sha256:87ba7882e146e24a7d8b4a7971c20212c2af75ead8096fc3d55330babb1015fb"}, + {file = "orjson-3.8.14-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9f5cf61b6db68f213c805c55bf0aab9b4cb75a4e9c7f5bfbd4deb3a0aef0ec53"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33bc310da4ad2ffe8f7f1c9e89692146d9ec5aec2d1c9ef6b67f8dc5e2d63241"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67a7e883b6f782b106683979ccc43d89b98c28a1f4a33fe3a22e253577499bb1"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9df820e6c8c84c52ec39ea2cc9c79f7999c839c7d1481a056908dce3b90ce9f9"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebca14ae80814219ea3327e3dfa7ff618621ff335e45781fac26f5cd0b48f2b4"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27967be4c16bd09f4aeff8896d9be9cbd00fd72f5815d5980e4776f821e2f77c"}, + {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:062829b5e20cd8648bf4c11c3a5ee7cf196fa138e573407b5312c849b0cf354d"}, + {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e53bc5beb612df8ddddb065f079d3fd30b5b4e73053518524423549d61177f3f"}, + {file = "orjson-3.8.14-cp38-none-win_amd64.whl", hash = "sha256:d03f29b0369bb1ab55c8a67103eb3a9675daaf92f04388568034fe16be48fa5d"}, + {file = "orjson-3.8.14-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:716a3994e039203f0a59056efa28185d4cac51b922cc5bf27ab9182cfa20e12e"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb35dd3ba062c1d984d57e6477768ed7b62ed9260f31362b2d69106f9c60ebd"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0bc6b7abf27f1dc192dadad249df9b513912506dd420ce50fd18864a33789b71"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2f75b7d9285e35c3d4dff9811185535ff2ea637f06b2b242cb84385f8ffe63"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:017de5ba22e58dfa6f41914f5edb8cd052d23f171000684c26b2d2ab219db31e"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09a3bf3154f40299b8bc95e9fb8da47436a59a2106fc22cae15f76d649e062da"}, + {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64b4fca0531030040e611c6037aaf05359e296877ab0a8e744c26ef9c32738b9"}, + {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8a896a12b38fe201a72593810abc1f4f1597e65b8c869d5fc83bbcf75d93398f"}, + {file = "orjson-3.8.14-cp39-none-win_amd64.whl", hash = "sha256:9725226478d1dafe46d26f758eadecc6cf98dcbb985445e14a9c74aaed6ccfea"}, + {file = "orjson-3.8.14.tar.gz", hash = "sha256:5ea93fd3ef7be7386f2516d728c877156de1559cda09453fc7dd7b696d0439b3"}, ] [[package]] @@ -1271,25 +1269,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.22.4" +version = "4.23.1" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.22.4-cp310-abi3-win32.whl", hash = "sha256:a4e661247896c2ffea4b894bca2d8657e752bedb8f3c66d7befa2557291be1e8"}, - {file = "protobuf-4.22.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b42086d6027be2730151b49f27b2f5be40f3b036adf7b8da5917f4567f268c3"}, - {file = "protobuf-4.22.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4bfb28d48628deacdb66a95aaa7b6640f3dc82b4edd34db444c7a3cdd90b01fb"}, - {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e98e26328d7c668541d1052b02de4205b1094ef6b2ce57167440d3e39876db48"}, - {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd329e5dd7b6c4b878cab4b85bb6cec880e2adaf4e8aa2c75944dcbb05e1ff1"}, - {file = "protobuf-4.22.4-cp37-cp37m-win32.whl", hash = "sha256:b7728b5da9eee15c0aa3baaee79e94fa877ddcf7e3d2f34b1eab586cd26eea89"}, - {file = "protobuf-4.22.4-cp37-cp37m-win_amd64.whl", hash = "sha256:f4a711588c3a79b6f9c44af4d7f4a2ae868e27063654683932ab6462f90e9656"}, - {file = "protobuf-4.22.4-cp38-cp38-win32.whl", hash = "sha256:11b28b4e779d7f275e3ea0efa3938f4d4e8ed3ca818f9fec3b193f8e9ada99fd"}, - {file = "protobuf-4.22.4-cp38-cp38-win_amd64.whl", hash = "sha256:144d5b46df5e44f914f715accaadf88d617242ba5a40cacef4e8de7effa79954"}, - {file = "protobuf-4.22.4-cp39-cp39-win32.whl", hash = "sha256:5128b4d5efcaef92189e076077ae389700606ff81d2126b8361dc01f3e026197"}, - {file = "protobuf-4.22.4-cp39-cp39-win_amd64.whl", hash = "sha256:9537ae27d43318acf8ce27d0359fe28e6ebe4179c3350bc055bb60ff4dc4fcd3"}, - {file = "protobuf-4.22.4-py3-none-any.whl", hash = "sha256:3b21074b7fb748d8e123acaef9fa63a84fdc1436dc71199d2317b139f77dd6f4"}, - {file = "protobuf-4.22.4.tar.gz", hash = "sha256:21fbaef7f012232eb8d6cb8ba334e931fc6ff8570f5aaedc77d5b22a439aa909"}, + {file = "protobuf-4.23.1-cp310-abi3-win32.whl", hash = "sha256:410bcc0a5b279f634d3e16082ce221dfef7c3392fac723500e2e64d1806dd2be"}, + {file = "protobuf-4.23.1-cp310-abi3-win_amd64.whl", hash = "sha256:32e78beda26d7a101fecf15d7a4a792278a0d26a31bc327ff05564a9d68ab8ee"}, + {file = "protobuf-4.23.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f9510cac91e764e86acd74e2b7f7bc5e6127a7f3fb646d7c8033cfb84fd1176a"}, + {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:346990f634272caac1f09efbcfbbacb23098b1f606d172534c6fa2d9758bb436"}, + {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3ce113b3f3362493bddc9069c2163a38f240a9ed685ff83e7bcb756b05e1deb0"}, + {file = "protobuf-4.23.1-cp37-cp37m-win32.whl", hash = "sha256:2036a3a1e7fc27f973fa0a7888dce712393af644f4695385f117886abc792e39"}, + {file = "protobuf-4.23.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3b8905eafe4439076e1f58e9d1fa327025fd2777cf90f14083092ae47f77b0aa"}, + {file = "protobuf-4.23.1-cp38-cp38-win32.whl", hash = "sha256:5b9cd6097e6acae48a68cb29b56bc79339be84eca65b486910bb1e7a30e2b7c1"}, + {file = "protobuf-4.23.1-cp38-cp38-win_amd64.whl", hash = "sha256:decf119d54e820f298ee6d89c72d6b289ea240c32c521f00433f9dc420595f38"}, + {file = "protobuf-4.23.1-cp39-cp39-win32.whl", hash = "sha256:91fac0753c3c4951fbb98a93271c43cc7cf3b93cf67747b3e600bb1e5cc14d61"}, + {file = "protobuf-4.23.1-cp39-cp39-win_amd64.whl", hash = "sha256:ac50be82491369a9ec3710565777e4da87c6d2e20404e0abb1f3a8f10ffd20f0"}, + {file = "protobuf-4.23.1-py3-none-any.whl", hash = "sha256:65f0ac96ef67d7dd09b19a46aad81a851b6f85f89725577f16de38f2d68ad477"}, + {file = "protobuf-4.23.1.tar.gz", hash = "sha256:95789b569418a3e32a53f43d7763be3d490a831e9c08042539462b6d972c2d7e"}, ] [[package]] @@ -1370,43 +1368,43 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.12.0" +version = "1.12.1" description = "Python bindings for libgit2." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b44a3b38e62dbf8cb559a40d2b39506a638d13542502ddb927f1c05565048f27"}, - {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:834cf5b54d9b49c562669ec986be54c7915585638690c11f1dc4e6a55bc5d79d"}, - {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecb096cdbbf142d8787cf879ab927fc9777d36580d2e5758d02c9474a3b015c"}, - {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15620696743ffac71cfdaf270944d9363b70442c1fbe96f5e4a69639c2fe7c23"}, - {file = "pygit2-1.12.0-cp310-cp310-win32.whl", hash = "sha256:de21194e18e4d93f793740b2b979dbe9dd6607f342a4fad3ecedeaf26ec743df"}, - {file = "pygit2-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:0a9d49f71bec7c4f2ff8273e0c7caba4b2f21bfc56e2071e429028b20ab9d762"}, - {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a428970b44827b703cc3267de8d71648f491546d5b9276505ef5f232a921a34e"}, - {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2bb7b674124a38b12a5aaacca3b8c1e29674f3b46cb907af0b3ba75d90e5952a"}, - {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de46940b46bee12f4c938aadf4f59617798f704c8ac5f08b5a84914459d604be"}, - {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fbfb3ebe7f57fe7873d86e84b476869f407d6bb204a39a3e7d04e4a7f0e43c1"}, - {file = "pygit2-1.12.0-cp311-cp311-win32.whl", hash = "sha256:db98978d559d6e84187d463fb3aa83cf6120dadf62058e3d05a97457f9f27247"}, - {file = "pygit2-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8734a44e0dab8a5e6668e4a926f7171b59b87d65981bd3732efba57c327cec6d"}, - {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1bb73ffb345400f8c6fe391431e06b93e26bc4d2048b1ac3f7c54dae5f7b6dc2"}, - {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fdeaf1631803616d303b808cd644ee17164fb675241ab1b0bb243d4a3d3de59f"}, - {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652b3f0510ad21ec6275b246aa3e7a2e20f2f9c37a9844804887fabc2db49ca3"}, - {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2419cd1034bf593847466b188a65bd9d512e13b7da0e8c3a74b487d8014a6c1"}, - {file = "pygit2-1.12.0-cp38-cp38-win32.whl", hash = "sha256:6a445a537de152364b334e73047af9225fe8c6f54c7d815d8c751cb23b79cbef"}, - {file = "pygit2-1.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:ad1cca4533beee034277fe01f0d4029da40d2bd1a944a8cd17bffccc0331cc53"}, - {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ad7b21e35e759d033dede5dc4971f6c9b3408f9096b26fabc7cedb49e319680"}, - {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e303aa9d7de6039cc4450a1fbd5911fab22867dc4e05f148b0cd7c56f7b84b2"}, - {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:869e68cfae7e0e00a799efa26bba3f829bdeafa1462225a7db1317dacb4e6a4e"}, - {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c779c15bf6ebce986cb753c8113ccfb329c12d4a73b303ee7ac2c8961288b8cd"}, - {file = "pygit2-1.12.0-cp39-cp39-win32.whl", hash = "sha256:c6ac2fd8ed30016235b06aacc28e5f10e1a17d0f02eab35f5f503138bbee763d"}, - {file = "pygit2-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2483e4aa8bb4290ab157d575b00b830528c669869d710646a1d4af7209d59e81"}, - {file = "pygit2-1.12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8fca4ca59928436fca5df3d54a7d591e7aa12ebaeaeb1801a99e09970fb8f1d3"}, - {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0746791741ba1879faafd12be0b7fb8edd06633508bbf8aabfd28415f1c0b13f"}, - {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b9d8b7e1d143415d462d82fc5d9dd5922c527474871c7b3c3a8aec009b74b1c"}, - {file = "pygit2-1.12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:69ee34f8b77fc60dcf93524fd843eacc416be906b7471746d2ee8214d5a591a0"}, - {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c290dadcf42e9d857ea20c37781168de1d1ac31b196b450400f962279aa405f"}, - {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d9bdd2837f9f1cacb571889ac4226844a41476509c325732af06b622293782"}, - {file = "pygit2-1.12.0.tar.gz", hash = "sha256:e9440d08665e35278989939590a53f37a938eada4f9446844930aa2ee30d73be"}, + {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:50a155528aa611e4a217be31a9d2d8da283cfd978dbba07494cd04ea3d7c8768"}, + {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:248e22ccb1ea31f569373a3da3fa73d110ba2585c6326ff74b03c9579fb7b913"}, + {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e575e672c5a6cb39234b0076423a560e016d6b88cd50947c2df3bf59c5ccdf3d"}, + {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad9b46b52997d131b31ff46f699b074e9745c8fea8d0efb6b72ace43ab25828c"}, + {file = "pygit2-1.12.1-cp310-cp310-win32.whl", hash = "sha256:a8f495df877da04c572ecec4d532ae195680b4781dbf229bab4e801fa9ef20e9"}, + {file = "pygit2-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f1e1355c7fe2938a2bca0d6204a00c02950d13008722879e54a335b3e874006"}, + {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a5c56b0b5dc8a317561070ef7557e180d4937d8b115c5a762d85e0109a216f3"}, + {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7c9ca8bc8a722863fc873234748fef3422007d5a6ea90ba3ae338d2907d3d6e"}, + {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c02a11f10bc4e329ab941f0c70874d39053c8f78544aefeb506f04cedb621a"}, + {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b3af334adf325b7c973417efa220fd5a9ce946b936262eceabc8ad8d46e0310"}, + {file = "pygit2-1.12.1-cp311-cp311-win32.whl", hash = "sha256:86c393962d1341893bbfa91829b3b8545e8ac7622f8b53b9a0b835b9cc1b5198"}, + {file = "pygit2-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:86c7e75ddc76f4e5593b47f9c2074fff242322ed9f4126116749f7c86021520a"}, + {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:939d11677f434024ea25a9137d8a525ef9f9ac474fb8b86399bc9526e6a7bff5"}, + {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:946f9215c0442995042ea512f764f7a6638d3a09f9d0484d3aeedbf8833f89e6"}, + {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd574620d3cc80df0b23bf2b7b08d8726e75a338d0fa1b67e4d6738d3ee56635"}, + {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24d0adeff5c43229913f3bdae71c36e77ed19f36bd8dd6b5c141820964b1f5b3"}, + {file = "pygit2-1.12.1-cp38-cp38-win32.whl", hash = "sha256:ed8e2ef97171e994bf4d46c6c6534a3c12dd2dbbc47741e5995eaf8c2c92f71c"}, + {file = "pygit2-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:5318817055a3ca3906bf88344b9a6dc70c640f9b6bc236ac9e767d12bad54361"}, + {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cb9c803151ffeb0b8de52a93381108a2c6a9a446c55d659a135f52645e1650eb"}, + {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47bf1e196dc23fe38018ad49b021d425edc319328169c597df45d73cf46b62ef"}, + {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:948479df72223bbcd16b2a88904dc2a3886c15a0107a7cf3b5373c8e34f52f31"}, + {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4bebe8b310edc2662cbffb94ef1a758252fe2e4c92bc83fac0eaf2bedf8b871"}, + {file = "pygit2-1.12.1-cp39-cp39-win32.whl", hash = "sha256:77bc0ab778ab6fe631f5f9eb831b426376a7b71426c5a913aaa9088382ef1dc9"}, + {file = "pygit2-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:e87b2306a266f6abca94ab37dda807033a6f40faad05c4d1e089f9e8354130a8"}, + {file = "pygit2-1.12.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5d5e8a3b67f5d4ba8e3838c492254688997747989b184b5f1a3af4fef7f9f53e"}, + {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2500b749759f2efdfa5096c0aafeb2d92152766708f5700284427bd658e5c407"}, + {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c21759ca9cc755faa2d17180cd49af004486ca84f3166cac089a2083dcb09114"}, + {file = "pygit2-1.12.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d73074ab64b383e3a1ab03e8070f6b195ef89b9d379ca5682c38dd9c289cc6e2"}, + {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:865c0d1925c52426455317f29c1db718187ec69ed5474faaf3e1c68ff2135767"}, + {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebebbe9125b068337b5415565ec94c9e092c708e430851b2d02e51217bdce4a"}, + {file = "pygit2-1.12.1.tar.gz", hash = "sha256:8218922abedc88a65d5092308d533ca4c4ed634aec86a3493d3bdf1a25aeeff3"}, ] [package.dependencies] @@ -1456,14 +1454,14 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy [[package]] name = "pytest-cov" -version = "4.0.0" +version = "4.1.0" description = "Pytest plugin for measuring coverage." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] [package.dependencies] @@ -1491,14 +1489,14 @@ pytest = ">=3.0" [[package]] name = "pytest-xdist" -version = "3.2.1" +version = "3.3.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.2.1.tar.gz", hash = "sha256:1849bd98d8b242b948e472db7478e090bf3361912a8fed87992ed94085f54727"}, - {file = "pytest_xdist-3.2.1-py3-none-any.whl", hash = "sha256:37290d161638a20b672401deef1cba812d110ac27e35d213f091d15b8beb40c9"}, + {file = "pytest-xdist-3.3.1.tar.gz", hash = "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93"}, + {file = "pytest_xdist-3.3.1-py3-none-any.whl", hash = "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"}, ] [package.dependencies] @@ -1542,18 +1540,18 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc [[package]] name = "redis" -version = "4.5.4" +version = "4.5.5" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, - {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, + {file = "redis-4.5.5-py3-none-any.whl", hash = "sha256:77929bc7f5dab9adf3acba2d3bb7d7658f1e0c2f1cafe7eb36434e751c471119"}, + {file = "redis-4.5.5.tar.gz", hash = "sha256:dc87a0bdef6c8bfe1ef1e1c40be7034390c2ae02d92dcd0c7ca1729443899880"}, ] [package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} +async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1561,14 +1559,14 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.30.0" +version = "2.31.0" description = "Python HTTP for Humans." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"}, - {file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"}, + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] @@ -1892,14 +1890,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.3.3" +version = "2.3.4" description = "The comprehensive WSGI web application library." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.3.3-py3-none-any.whl", hash = "sha256:4866679a0722de00796a74086238bb3b98d90f423f05de039abb09315487254a"}, - {file = "Werkzeug-2.3.3.tar.gz", hash = "sha256:a987caf1092edc7523edb139edb20c70571c4a8d5eed02e0b547b4739174d091"}, + {file = "Werkzeug-2.3.4-py3-none-any.whl", hash = "sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f"}, + {file = "Werkzeug-2.3.4.tar.gz", hash = "sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76"}, ] [package.dependencies] @@ -1942,4 +1940,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "6a96903be0358aa6d6ef1926edf6158dd36060f8bec66bd8bf8b0ee04e7795df" +content-hash = "caf2a21e3bff699216e53a37697a7a544103fdea9f84a5d54ee94ded3e810973" diff --git a/pyproject.toml b/pyproject.toml index b27d281a..f04deb14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ aiofiles = "^23.1.0" asgiref = "^3.6.0" bcrypt = "^4.0.1" bleach = "^6.0.0" -email-validator = "^2.0.0.post2" +email-validator = "^2.0.0-post.0" fakeredis = "^2.11.2" feedgen = "^0.9.0" httpx = "^0.24.0" From 5fe375bdc3c5ee1bb39acc3c92e6791b3606b942 Mon Sep 17 00:00:00 2001 From: "Daniel M. Capella" Date: Thu, 25 May 2023 17:18:30 -0400 Subject: [PATCH 1751/1891] feat: add link to MergeBaseName in requests.html --- templates/requests.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/requests.html b/templates/requests.html index 9eb911f5..352ed820 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -109,7 +109,9 @@ {{ result.RequestType.name_display() | tr }} {# If the RequestType is a merge and request.MergeBaseName is valid... #} {% if result.RequestType.ID == 3 and result.MergeBaseName %} - ({{ result.MergeBaseName }}) + + ({{ result.MergeBaseName }}) + {% endif %} {# Comments #} From 2eacc84cd02802704a9d686843d3c2224f35dcb5 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 13:23:37 +0200 Subject: [PATCH 1752/1891] fix: properly evaluate AURREMEMBER cookie Whenever the AURREMEMBER cookie was defined, regardless of its value, "remember_me" is always set to True The get method of a dict returns a string, converting a value of str "False" into a bool -> True We have to check AURREMEMBERs value instead. Signed-off-by: moson-mo --- aurweb/auth/__init__.py | 4 +--- aurweb/cookies.py | 2 +- aurweb/users/update.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 5a1fc8d0..83dd424c 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -104,9 +104,7 @@ class BasicAuthBackend(AuthenticationBackend): return unauthenticated timeout = aurweb.config.getint("options", "login_timeout") - remembered = "AURREMEMBER" in conn.cookies and bool( - conn.cookies.get("AURREMEMBER") - ) + remembered = conn.cookies.get("AURREMEMBER") == "True" if remembered: timeout = aurweb.config.getint("options", "persistent_cookie_timeout") diff --git a/aurweb/cookies.py b/aurweb/cookies.py index 841e9adc..2bfcf7a7 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -65,7 +65,7 @@ def update_response_cookies( "AURLANG", aurlang, secure=secure, httponly=secure, samesite=samesite() ) if aursid: - remember_me = bool(request.cookies.get("AURREMEMBER", False)) + remember_me = request.cookies.get("AURREMEMBER") == "True" response.set_cookie( "AURSID", aursid, diff --git a/aurweb/users/update.py b/aurweb/users/update.py index 21349a39..ace9dace 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -131,7 +131,7 @@ def password( user.update_password(P) if user == request.user: - remember_me = request.cookies.get("AURREMEMBER", False) + remember_me = request.cookies.get("AURREMEMBER") == "True" # If the target user is the request user, login with # the updated password to update the Session record. From edc4ac332d1872c8b4b5fab5d9e789d66d36f795 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 13:41:59 +0200 Subject: [PATCH 1753/1891] chore: remove setting AURLANG and AURTZ on account edit We don't need to set these cookies when an account is edited. These settings are saved to the DB anyways. (and they are picked up from there as well for any web requests, when no cookies are given) Setting these cookies can even be counter-productive: Imagine a TU/Dev editing another users account. They would overwrite their own cookies with the other users TZ/LANG settings. Signed-off-by: moson-mo --- aurweb/cookies.py | 12 ------------ aurweb/routers/accounts.py | 6 ++---- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/aurweb/cookies.py b/aurweb/cookies.py index 2bfcf7a7..cb4396d7 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -38,8 +38,6 @@ def timeout(extended: bool) -> int: def update_response_cookies( request: Request, response: Response, - aurtz: str = None, - aurlang: str = None, aursid: str = None, ) -> Response: """Update session cookies. This method is particularly useful @@ -50,20 +48,10 @@ def update_response_cookies( :param request: FastAPI request :param response: FastAPI response - :param aurtz: Optional AURTZ cookie value - :param aurlang: Optional AURLANG cookie value :param aursid: Optional AURSID cookie value :returns: Updated response """ secure = config.getboolean("options", "disable_http_login") - if aurtz: - response.set_cookie( - "AURTZ", aurtz, secure=secure, httponly=secure, samesite=samesite() - ) - if aurlang: - response.set_cookie( - "AURLANG", aurlang, secure=secure, httponly=secure, samesite=samesite() - ) if aursid: remember_me = request.cookies.get("AURREMEMBER") == "True" response.set_cookie( diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 77988d7f..010aae58 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -8,7 +8,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, or_ import aurweb.config -from aurweb import aur_logging, cookies, db, l10n, models, util +from aurweb import aur_logging, db, l10n, models, util from aurweb.auth import account_type_required, creds, requires_auth, requires_guest from aurweb.captcha import get_captcha_salts from aurweb.exceptions import ValidationError, handle_form_exceptions @@ -473,9 +473,7 @@ async def account_edit_post( if not errors: context["complete"] = True - # Update cookies with requests, in case they were changed. - response = render_template(request, "account/edit.html", context) - return cookies.update_response_cookies(request, response, aurtz=TZ, aurlang=L) + return render_template(request, "account/edit.html", context) @router.get("/account/{username}") From 638ca7b1d081f14c21db6d5c40e23678b865d258 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 13:47:50 +0200 Subject: [PATCH 1754/1891] chore: remove setting AURLANG and AURTZ on login We don't need to set these cookies when logging in. These settings are saved to the DB anyways. (and they are picked up from there as well for any web requests, when no cookies are given) Signed-off-by: moson-mo --- aurweb/routers/auth.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 0e675559..71547429 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -85,20 +85,6 @@ async def login_post( httponly=secure, samesite=cookies.samesite(), ) - response.set_cookie( - "AURTZ", - user.Timezone, - secure=secure, - httponly=secure, - samesite=cookies.samesite(), - ) - response.set_cookie( - "AURLANG", - user.LangPreference, - secure=secure, - httponly=secure, - samesite=cookies.samesite(), - ) response.set_cookie( "AURREMEMBER", remember_me, @@ -125,5 +111,5 @@ async def logout(request: Request, next: str = Form(default="/")): # to redirect to a get request. response = RedirectResponse(url=next, status_code=HTTPStatus.SEE_OTHER) response.delete_cookie("AURSID") - response.delete_cookie("AURTZ") + response.delete_cookie("AURREMEMBER") return response From 57c154a72cc6dbc997c07b159e76a1ddd5cc02ee Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 14:07:27 +0200 Subject: [PATCH 1755/1891] fix: increase expiry for AURLANG cookie; only set when needed We add a new config option for cookies with a 400 day lifetime. AURLANG should survive longer for unauthenticated users. Today they have to set this again after each browser restart. (for users whose browsers wipe session cookies on close) authenticated users don't need this cookie since the setting is saved to the DB Signed-off-by: moson-mo --- aurweb/routers/html.py | 29 +++++++++++++++++++---------- conf/config.defaults | 4 ++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 33aeb904..38303837 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -56,19 +56,28 @@ async def language( query_string = "?" + q if q else str() - # If the user is authenticated, update the user's LangPreference. - if request.user.is_authenticated(): - with db.begin(): - request.user.LangPreference = set_lang - - # In any case, set the response's AURLANG cookie that never expires. response = RedirectResponse( url=f"{next}{query_string}", status_code=HTTPStatus.SEE_OTHER ) - secure = aurweb.config.getboolean("options", "disable_http_login") - response.set_cookie( - "AURLANG", set_lang, secure=secure, httponly=secure, samesite=cookies.samesite() - ) + + # If the user is authenticated, update the user's LangPreference. + # Otherwise set an AURLANG cookie + if request.user.is_authenticated(): + with db.begin(): + request.user.LangPreference = set_lang + else: + secure = aurweb.config.getboolean("options", "disable_http_login") + perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") + + response.set_cookie( + "AURLANG", + set_lang, + secure=secure, + httponly=secure, + max_age=perma_timeout, + samesite=cookies.samesite(), + ) + return response diff --git a/conf/config.defaults b/conf/config.defaults index bb390d8a..17e81b7b 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -14,8 +14,12 @@ passwd_min_len = 8 default_lang = en default_timezone = UTC sql_debug = 0 +; 2 hours - default login_timeout login_timeout = 7200 +; 30 days - default persistent_cookie_timeout persistent_cookie_timeout = 2592000 +; 400 days - default permanent_cookie_timeout +permanent_cookie_timeout = 34560000 max_filesize_uncompressed = 8388608 disable_http_login = 1 aur_location = https://aur.archlinux.org From d3663772313037d3734b7795f0f8828e625a5e2e Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 14:20:38 +0200 Subject: [PATCH 1756/1891] fix: make AURREMEMBER cookie a permanent one If it's a session cookie it poses issues for users whose browsers wipe session cookies after close. They'd be logged out early even if they chose the "remember me" option when they log in. Signed-off-by: moson-mo --- aurweb/routers/auth.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 71547429..98a655e3 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -70,6 +70,7 @@ async def login_post( return await login_template(request, next, errors=["Account Suspended"]) cookie_timeout = cookies.timeout(remember_me) + perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") sid = _retry_login(request, user, passwd, cookie_timeout) if not sid: return await login_template(request, next, errors=["Bad username or password."]) @@ -88,6 +89,7 @@ async def login_post( response.set_cookie( "AURREMEMBER", remember_me, + max_age=perma_timeout, secure=secure, httponly=secure, samesite=cookies.samesite(), From 0807ae6b7caada569c8fab45c4f3403ff950b6d1 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 14:22:51 +0200 Subject: [PATCH 1757/1891] test: add tests for cookie handling add a bunch of test cases to ensure our cookies work properly Signed-off-by: moson-mo --- test/test_cookies.py | 145 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 test/test_cookies.py diff --git a/test/test_cookies.py b/test/test_cookies.py new file mode 100644 index 00000000..a0ace68f --- /dev/null +++ b/test/test_cookies.py @@ -0,0 +1,145 @@ +from datetime import datetime + +import pytest +from fastapi.testclient import TestClient + +from aurweb import config, db +from aurweb.asgi import app +from aurweb.models.account_type import USER_ID +from aurweb.models.user import User +from aurweb.testing.requests import Request + +# Some test global constants. +TEST_USERNAME = "test" +TEST_EMAIL = "test@example.org" +TEST_REFERER = { + "referer": config.get("options", "aur_location") + "/login", +} + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture +def client() -> TestClient: + client = TestClient(app=app) + + # Necessary for forged login CSRF protection on the login route. Set here + # instead of only on the necessary requests for convenience. + client.headers.update(TEST_REFERER) + + # disable redirects for our tests + client.follow_redirects = False + yield client + + +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create( + User, + Username=TEST_USERNAME, + Email=TEST_EMAIL, + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) + yield user + + +def test_cookies_login(client: TestClient, user: User): + # Log in with "Remember me" disabled + data = {"user": user.Username, "passwd": "testPassword", "next": "/"} + with client as request: + resp = request.post("/login", data=data) + + local_time = int(datetime.now().timestamp()) + expected_timeout = local_time + config.getint("options", "login_timeout") + expected_permanent = local_time + config.getint( + "options", "permanent_cookie_timeout" + ) + + # Check if we got permanent cookies with expected expiry date. + # Allow 1 second difference to account for timing issues + # between the request and current time. + assert "AURSID", "AURREMEMBER" in resp.cookies + for cookie in resp.cookies.jar: + if cookie.name == "AURSID": + assert abs(cookie.expires - expected_timeout) < 2 + + if cookie.name == "AURREMEMBER": + assert abs(cookie.expires - expected_permanent) < 2 + + # Make some random http call. + # We should get an (updated) AURSID cookie with each request. + sid = resp.cookies.get("AURSID") + with client as request: + request.cookies = {"AURSID": sid} + resp = request.get("/") + + assert "AURSID" in resp.cookies + + # Log out + with client as request: + request.cookies = resp.cookies + resp = request.post("/logout", data=data) + + # Make sure AURSID cookie is removed after logout + assert "AURSID" not in resp.cookies + + # Log in with "Remember me" enabled + data = { + "user": user.Username, + "passwd": "testPassword", + "next": "/", + "remember_me": "True", + } + with client as request: + resp = request.post("/login", data=data) + + # Check if we got a permanent cookie with expected expiry date. + # Allow 1 second difference to account for timing issues + # between the request and current time. + expected_persistent = local_time + config.getint( + "options", "persistent_cookie_timeout" + ) + assert "AURSID" in resp.cookies + for cookie in resp.cookies.jar: + if cookie.name in "AURSID": + assert abs(cookie.expires - expected_persistent) < 2 + + +def test_cookie_language(client: TestClient, user: User): + # Unauthenticated reqeuests should set AURLANG cookie + data = {"set_lang": "en", "next": "/"} + with client as request: + resp = request.post("/language", data=data) + + local_time = int(datetime.now().timestamp()) + expected_permanent = local_time + config.getint( + "options", "permanent_cookie_timeout" + ) + + # Make sure we got an AURLANG cookie + assert "AURLANG" in resp.cookies + assert resp.cookies.get("AURLANG") == "en" + + # Check if we got a permanent cookie with expected expiry date. + # Allow 1 second difference to account for timing issues + # between the request and current time. + for cookie in resp.cookies.jar: + if cookie.name in "AURLANG": + assert abs(cookie.expires - expected_permanent) < 2 + + # Login and change the language + # We should not get a cookie since we store + # our language setting in the DB anyways + sid = user.login(Request(), "testPassword") + data = {"set_lang": "en", "next": "/"} + with client as request: + request.cookies = {"AURSID": sid} + resp = request.post("/language", data=data) + + assert "AURLANG" not in resp.cookies From 22fe4a988a31c78f01ddc62bd1d9cb9c5074046b Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 26 May 2023 11:21:16 +0200 Subject: [PATCH 1758/1891] fix: make AURSID a session cookie if "remember me" is not checked This should match more closely the expectation of a user. A session cookie should vanish on browser close and you thus they need to authenticate again. There is no need to bump the expiration of AURSID either, so we can remove that part. Signed-off-by: moson-mo --- aurweb/cookies.py | 33 --------------------------------- aurweb/routers/auth.py | 7 ++++++- aurweb/templates.py | 13 ++----------- doc/web-auth.md | 18 ++++++------------ test/test_cookies.py | 30 ++++++++++++++++++------------ 5 files changed, 32 insertions(+), 69 deletions(-) diff --git a/aurweb/cookies.py b/aurweb/cookies.py index cb4396d7..022cff1e 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -1,6 +1,3 @@ -from fastapi import Request -from fastapi.responses import Response - from aurweb import config @@ -33,33 +30,3 @@ def timeout(extended: bool) -> int: if bool(extended): timeout = config.getint("options", "persistent_cookie_timeout") return timeout - - -def update_response_cookies( - request: Request, - response: Response, - aursid: str = None, -) -> Response: - """Update session cookies. This method is particularly useful - when updating a cookie which was already set. - - The AURSID cookie's expiration is based on the AURREMEMBER cookie, - which is retrieved from `request`. - - :param request: FastAPI request - :param response: FastAPI response - :param aursid: Optional AURSID cookie value - :returns: Updated response - """ - secure = config.getboolean("options", "disable_http_login") - if aursid: - remember_me = request.cookies.get("AURREMEMBER") == "True" - response.set_cookie( - "AURSID", - aursid, - secure=secure, - httponly=secure, - max_age=timeout(remember_me), - samesite=samesite(), - ) - return response diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 98a655e3..46dee3a4 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -69,7 +69,12 @@ async def login_post( if user.Suspended: return await login_template(request, next, errors=["Account Suspended"]) - cookie_timeout = cookies.timeout(remember_me) + # If "remember me" was not ticked, we set a session cookie for AURSID, + # otherwise we make it a persistent cookie + cookie_timeout = None + if remember_me: + cookie_timeout = aurweb.config.getint("options", "persistent_cookie_timeout") + perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") sid = _retry_login(request, user, passwd, cookie_timeout) if not sid: diff --git a/aurweb/templates.py b/aurweb/templates.py index 89316d6d..d20cbe85 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -10,7 +10,7 @@ from fastapi import Request from fastapi.responses import HTMLResponse import aurweb.config -from aurweb import cookies, l10n, time +from aurweb import l10n, time # Prepare jinja2 objects. _loader = jinja2.FileSystemLoader( @@ -145,13 +145,4 @@ def render_template( ): """Render a template as an HTMLResponse.""" rendered = render_raw_template(request, path, context) - response = HTMLResponse(rendered, status_code=int(status_code)) - - sid = None - if request.user.is_authenticated(): - sid = request.cookies.get("AURSID") - - # Re-emit SID via update_response_cookies with an updated expiration. - # This extends the life of a user session based on the AURREMEMBER - # cookie, which is always set to the "Remember Me" state on login. - return cookies.update_response_cookies(request, response, aursid=sid) + return HTMLResponse(rendered, status_code=int(status_code)) diff --git a/doc/web-auth.md b/doc/web-auth.md index dbb4403d..c8604fed 100644 --- a/doc/web-auth.md +++ b/doc/web-auth.md @@ -22,17 +22,11 @@ in the following ways: ### Max-Age The value used for the `AURSID` Max-Age attribute is decided based -off of the "Remember Me" checkbox on the login page. Both paths -use their own independent configuration for the number of seconds -that each type of session should stay alive. - -- "Remember Me" unchecked while logging in - - `options.login_timeout` is used -- "Remember Me" checked while logging in - - `options.persistent_cookie_timeout` is used - -Both `options.login_timeout` and `options.persistent_cookie_timeout` -indicate the number of seconds the session should live. +off of the "Remember Me" checkbox on the login page. If it was not +checked, we don't set Max-Age and it becomes a session cookie. +Otherwise we make it a persistent cookie and for the expiry date +we use `options.persistent_cookie_timeout`. +It indicates the number of seconds the session should live. ### Notes @@ -89,7 +83,7 @@ The following list of steps describes exactly how this verification works: 1. Was the `AURSID` cookie delivered? 1. No, the algorithm ends, you are considered unauthenticated 2. Yes, move on to 2 -2. Was the `AURREMEMBER` cookie delivered with a value of 1? +2. Was the `AURREMEMBER` cookie delivered with a value of `True`? 1. No, set the expected session timeout **T** to `options.login_timeout` 2. Yes, set the expected session timeout **T** to `options.persistent_cookie_timeout` diff --git a/test/test_cookies.py b/test/test_cookies.py index a0ace68f..dd4143cb 100644 --- a/test/test_cookies.py +++ b/test/test_cookies.py @@ -1,4 +1,5 @@ from datetime import datetime +from http import HTTPStatus import pytest from fastapi.testclient import TestClient @@ -56,7 +57,6 @@ def test_cookies_login(client: TestClient, user: User): resp = request.post("/login", data=data) local_time = int(datetime.now().timestamp()) - expected_timeout = local_time + config.getint("options", "login_timeout") expected_permanent = local_time + config.getint( "options", "permanent_cookie_timeout" ) @@ -64,22 +64,15 @@ def test_cookies_login(client: TestClient, user: User): # Check if we got permanent cookies with expected expiry date. # Allow 1 second difference to account for timing issues # between the request and current time. + # AURSID should be a session cookie (no expiry date) assert "AURSID", "AURREMEMBER" in resp.cookies for cookie in resp.cookies.jar: if cookie.name == "AURSID": - assert abs(cookie.expires - expected_timeout) < 2 + assert cookie.expires is None if cookie.name == "AURREMEMBER": assert abs(cookie.expires - expected_permanent) < 2 - - # Make some random http call. - # We should get an (updated) AURSID cookie with each request. - sid = resp.cookies.get("AURSID") - with client as request: - request.cookies = {"AURSID": sid} - resp = request.get("/") - - assert "AURSID" in resp.cookies + assert cookie.value == "False" # Log out with client as request: @@ -102,14 +95,27 @@ def test_cookies_login(client: TestClient, user: User): # Check if we got a permanent cookie with expected expiry date. # Allow 1 second difference to account for timing issues # between the request and current time. + # AURSID should be a persistent cookie expected_persistent = local_time + config.getint( "options", "persistent_cookie_timeout" ) - assert "AURSID" in resp.cookies + assert "AURSID", "AURREMEMBER" in resp.cookies for cookie in resp.cookies.jar: if cookie.name in "AURSID": assert abs(cookie.expires - expected_persistent) < 2 + if cookie.name == "AURREMEMBER": + assert abs(cookie.expires - expected_permanent) < 2 + assert cookie.value == "True" + + # log in again even though we already have a session + with client as request: + resp = request.post("/login", data=data) + + # we are logged in already and should have been redirected + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == "/" + def test_cookie_language(client: TestClient, user: User): # Unauthenticated reqeuests should set AURLANG cookie From a7882c75339189dbb32145fcf88f02c08a4ff7b9 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 26 May 2023 23:02:38 +0200 Subject: [PATCH 1759/1891] refactor: remove session_time from user.login The parameter is not used, we can remove it and adapt the callers. Signed-off-by: moson-mo --- aurweb/cookies.py | 24 ------------------------ aurweb/models/user.py | 2 +- aurweb/routers/auth.py | 6 +++--- aurweb/users/update.py | 6 ++---- 4 files changed, 6 insertions(+), 32 deletions(-) diff --git a/aurweb/cookies.py b/aurweb/cookies.py index 022cff1e..84c43f9b 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -1,6 +1,3 @@ -from aurweb import config - - def samesite() -> str: """Produce cookie SameSite value. @@ -9,24 +6,3 @@ def samesite() -> str: :returns "lax" """ return "lax" - - -def timeout(extended: bool) -> int: - """Produce a session timeout based on `remember_me`. - - This method returns one of AUR_CONFIG's options.persistent_cookie_timeout - and options.login_timeout based on the `extended` argument. - - The `extended` argument is typically the value of the AURREMEMBER - cookie, defaulted to False. - - If `extended` is False, options.login_timeout is returned. Otherwise, - if `extended` is True, options.persistent_cookie_timeout is returned. - - :param extended: Flag which generates an extended timeout when True - :returns: Cookie timeout based on configuration options - """ - timeout = config.getint("options", "login_timeout") - if bool(extended): - timeout = config.getint("options", "persistent_cookie_timeout") - return timeout diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 9846d996..8612c259 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -95,7 +95,7 @@ class User(Base): def _login_approved(self, request: Request): return not is_banned(request) and not self.Suspended - def login(self, request: Request, password: str, session_time: int = 0) -> str: + def login(self, request: Request, password: str) -> str: """Login and authenticate a request.""" from aurweb import db diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 46dee3a4..88eaa0e6 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -29,8 +29,8 @@ async def login_get(request: Request, next: str = "/"): @db.retry_deadlock -def _retry_login(request: Request, user: User, passwd: str, cookie_timeout: int) -> str: - return user.login(request, passwd, cookie_timeout) +def _retry_login(request: Request, user: User, passwd: str) -> str: + return user.login(request, passwd) @router.post("/login", response_class=HTMLResponse) @@ -76,7 +76,7 @@ async def login_post( cookie_timeout = aurweb.config.getint("options", "persistent_cookie_timeout") perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") - sid = _retry_login(request, user, passwd, cookie_timeout) + sid = _retry_login(request, user, passwd) if not sid: return await login_template(request, next, errors=["Bad username or password."]) diff --git a/aurweb/users/update.py b/aurweb/users/update.py index ace9dace..759088cd 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -2,7 +2,7 @@ from typing import Any from fastapi import Request -from aurweb import cookies, db, models, time, util +from aurweb import db, models, time, util from aurweb.models import SSHPubKey from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.util import strtobool @@ -131,11 +131,9 @@ def password( user.update_password(P) if user == request.user: - remember_me = request.cookies.get("AURREMEMBER") == "True" - # If the target user is the request user, login with # the updated password to update the Session record. - user.login(request, P, cookies.timeout(remember_me)) + user.login(request, P) @db.retry_deadlock From 49e98d64f4f1d6770f067db087f741eb8420548e Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 26 May 2023 23:03:38 +0200 Subject: [PATCH 1760/1891] chore: increase default session/cookie timeout change from 2 to 4 hours. Signed-off-by: moson-mo --- conf/config.defaults | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/config.defaults b/conf/config.defaults index 17e81b7b..c059444d 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -14,8 +14,8 @@ passwd_min_len = 8 default_lang = en default_timezone = UTC sql_debug = 0 -; 2 hours - default login_timeout -login_timeout = 7200 +; 4 hours - default login_timeout +login_timeout = 14400 ; 30 days - default persistent_cookie_timeout persistent_cookie_timeout = 2592000 ; 400 days - default permanent_cookie_timeout From d1a3fee9fe98ebc3bcdb4f472f8812fa738d3b12 Mon Sep 17 00:00:00 2001 From: renovate Date: Fri, 26 May 2023 18:24:33 +0000 Subject: [PATCH 1761/1891] fix(deps): update all non-major dependencies --- poetry.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3a273be4..06855cac 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1269,25 +1269,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.23.1" +version = "4.23.2" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.23.1-cp310-abi3-win32.whl", hash = "sha256:410bcc0a5b279f634d3e16082ce221dfef7c3392fac723500e2e64d1806dd2be"}, - {file = "protobuf-4.23.1-cp310-abi3-win_amd64.whl", hash = "sha256:32e78beda26d7a101fecf15d7a4a792278a0d26a31bc327ff05564a9d68ab8ee"}, - {file = "protobuf-4.23.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f9510cac91e764e86acd74e2b7f7bc5e6127a7f3fb646d7c8033cfb84fd1176a"}, - {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:346990f634272caac1f09efbcfbbacb23098b1f606d172534c6fa2d9758bb436"}, - {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3ce113b3f3362493bddc9069c2163a38f240a9ed685ff83e7bcb756b05e1deb0"}, - {file = "protobuf-4.23.1-cp37-cp37m-win32.whl", hash = "sha256:2036a3a1e7fc27f973fa0a7888dce712393af644f4695385f117886abc792e39"}, - {file = "protobuf-4.23.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3b8905eafe4439076e1f58e9d1fa327025fd2777cf90f14083092ae47f77b0aa"}, - {file = "protobuf-4.23.1-cp38-cp38-win32.whl", hash = "sha256:5b9cd6097e6acae48a68cb29b56bc79339be84eca65b486910bb1e7a30e2b7c1"}, - {file = "protobuf-4.23.1-cp38-cp38-win_amd64.whl", hash = "sha256:decf119d54e820f298ee6d89c72d6b289ea240c32c521f00433f9dc420595f38"}, - {file = "protobuf-4.23.1-cp39-cp39-win32.whl", hash = "sha256:91fac0753c3c4951fbb98a93271c43cc7cf3b93cf67747b3e600bb1e5cc14d61"}, - {file = "protobuf-4.23.1-cp39-cp39-win_amd64.whl", hash = "sha256:ac50be82491369a9ec3710565777e4da87c6d2e20404e0abb1f3a8f10ffd20f0"}, - {file = "protobuf-4.23.1-py3-none-any.whl", hash = "sha256:65f0ac96ef67d7dd09b19a46aad81a851b6f85f89725577f16de38f2d68ad477"}, - {file = "protobuf-4.23.1.tar.gz", hash = "sha256:95789b569418a3e32a53f43d7763be3d490a831e9c08042539462b6d972c2d7e"}, + {file = "protobuf-4.23.2-cp310-abi3-win32.whl", hash = "sha256:384dd44cb4c43f2ccddd3645389a23ae61aeb8cfa15ca3a0f60e7c3ea09b28b3"}, + {file = "protobuf-4.23.2-cp310-abi3-win_amd64.whl", hash = "sha256:09310bce43353b46d73ba7e3bca78273b9bc50349509b9698e64d288c6372c2a"}, + {file = "protobuf-4.23.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2cfab63a230b39ae603834718db74ac11e52bccaaf19bf20f5cce1a84cf76df"}, + {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:c52cfcbfba8eb791255edd675c1fe6056f723bf832fa67f0442218f8817c076e"}, + {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:86df87016d290143c7ce3be3ad52d055714ebaebb57cc659c387e76cfacd81aa"}, + {file = "protobuf-4.23.2-cp37-cp37m-win32.whl", hash = "sha256:281342ea5eb631c86697e1e048cb7e73b8a4e85f3299a128c116f05f5c668f8f"}, + {file = "protobuf-4.23.2-cp37-cp37m-win_amd64.whl", hash = "sha256:ce744938406de1e64b91410f473736e815f28c3b71201302612a68bf01517fea"}, + {file = "protobuf-4.23.2-cp38-cp38-win32.whl", hash = "sha256:6c081863c379bb1741be8f8193e893511312b1d7329b4a75445d1ea9955be69e"}, + {file = "protobuf-4.23.2-cp38-cp38-win_amd64.whl", hash = "sha256:25e3370eda26469b58b602e29dff069cfaae8eaa0ef4550039cc5ef8dc004511"}, + {file = "protobuf-4.23.2-cp39-cp39-win32.whl", hash = "sha256:efabbbbac1ab519a514579ba9ec52f006c28ae19d97915951f69fa70da2c9e91"}, + {file = "protobuf-4.23.2-cp39-cp39-win_amd64.whl", hash = "sha256:54a533b971288af3b9926e53850c7eb186886c0c84e61daa8444385a4720297f"}, + {file = "protobuf-4.23.2-py3-none-any.whl", hash = "sha256:8da6070310d634c99c0db7df48f10da495cc283fd9e9234877f0cd182d43ab7f"}, + {file = "protobuf-4.23.2.tar.gz", hash = "sha256:20874e7ca4436f683b64ebdbee2129a5a2c301579a67d1a7dda2cdf62fb7f5f7"}, ] [[package]] From 2709585a70a9437d10736e18141e44af053b3b55 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 27 May 2023 11:24:46 +0000 Subject: [PATCH 1762/1891] fix(deps): update dependency fastapi to v0.95.2 --- poetry.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 06855cac..16b0f15a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -551,19 +551,19 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.95.1" +version = "0.95.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.95.1-py3-none-any.whl", hash = "sha256:a870d443e5405982e1667dfe372663abf10754f246866056336d7f01c21dab07"}, - {file = "fastapi-0.95.1.tar.gz", hash = "sha256:9569f0a381f8a457ec479d90fa01005cfddaae07546eb1f3fa035bc4797ae7d5"}, + {file = "fastapi-0.95.2-py3-none-any.whl", hash = "sha256:d374dbc4ef2ad9b803899bd3360d34c534adc574546e25314ab72c0c4411749f"}, + {file = "fastapi-0.95.2.tar.gz", hash = "sha256:4d9d3e8c71c73f11874bcf5e33626258d143252e329a01002f767306c64fb982"}, ] [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = ">=0.26.1,<0.27.0" +starlette = ">=0.27.0,<0.28.0" [package.extras] all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] @@ -1724,14 +1724,14 @@ parse = ">=1.19.0,<2.0.0" [[package]] name = "starlette" -version = "0.26.1" +version = "0.27.0" description = "The little ASGI library that shines." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"}, - {file = "starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"}, + {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, + {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, ] [package.dependencies] From ed2f85ad047f4659b03f7b3730ff117522feaaa6 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 27 May 2023 14:28:48 +0100 Subject: [PATCH 1763/1891] chore(release): prepare for 6.2.4 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f04deb14..e25fe90a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.3" +version = "v6.2.4" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From e9cc2fb4373cae8c24bab5043f24c019829ceb99 Mon Sep 17 00:00:00 2001 From: Christian Heusel Date: Fri, 2 Jun 2023 16:19:44 +0200 Subject: [PATCH 1764/1891] change: only require .SRCINFO in the latest revision This is done in order to relax the constraints so that dropping packages from the official repos can be done with preserving their history. Its sufficient to also have this present in the latest commit of a push. Signed-off-by: Christian Heusel --- aurweb/git/update.py | 163 +++++++++++++++++++--------------------- test/t1300-git-update.t | 4 +- 2 files changed, 80 insertions(+), 87 deletions(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index b1256fdb..467b540f 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -258,6 +258,63 @@ def die_commit(msg, commit): exit(1) +def validate_metadata(metadata, commit): # noqa: C901 + try: + metadata_pkgbase = metadata["pkgbase"] + except KeyError: + die_commit( + "invalid .SRCINFO, does not contain a pkgbase (is the file empty?)", + str(commit.id), + ) + if not re.match(repo_regex, metadata_pkgbase): + die_commit("invalid pkgbase: {:s}".format(metadata_pkgbase), str(commit.id)) + + if not metadata["packages"]: + die_commit("missing pkgname entry", str(commit.id)) + + for pkgname in set(metadata["packages"].keys()): + pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) + + for field in ("pkgver", "pkgrel", "pkgname"): + if field not in pkginfo: + die_commit( + "missing mandatory field: {:s}".format(field), str(commit.id) + ) + + if "epoch" in pkginfo and not pkginfo["epoch"].isdigit(): + die_commit("invalid epoch: {:s}".format(pkginfo["epoch"]), str(commit.id)) + + if not re.match(r"[a-z0-9][a-z0-9\.+_-]*$", pkginfo["pkgname"]): + die_commit( + "invalid package name: {:s}".format(pkginfo["pkgname"]), + str(commit.id), + ) + + max_len = {"pkgname": 255, "pkgdesc": 255, "url": 8000} + for field in max_len.keys(): + if field in pkginfo and len(pkginfo[field]) > max_len[field]: + die_commit( + "{:s} field too long: {:s}".format(field, pkginfo[field]), + str(commit.id), + ) + + for field in ("install", "changelog"): + if field in pkginfo and not pkginfo[field] in commit.tree: + die_commit( + "missing {:s} file: {:s}".format(field, pkginfo[field]), + str(commit.id), + ) + + for field in extract_arch_fields(pkginfo, "source"): + fname = field["value"] + if len(fname) > 8000: + die_commit("source entry too long: {:s}".format(fname), str(commit.id)) + if "://" in fname or "lp:" in fname: + continue + if fname not in commit.tree: + die_commit("missing source file: {:s}".format(fname), str(commit.id)) + + def main(): # noqa: C901 repo = pygit2.Repository(repo_path) @@ -295,12 +352,30 @@ def main(): # noqa: C901 if sha1_old != "0" * 40: walker.hide(sha1_old) + head_commit = repo[sha1_new] + if ".SRCINFO" not in head_commit.tree: + die_commit("missing .SRCINFO", str(head_commit.id)) + + # Read .SRCINFO from the HEAD commit. + metadata_raw = repo[head_commit.tree[".SRCINFO"].id].data.decode() + (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) + if errors: + sys.stderr.write( + "error: The following errors occurred " "when parsing .SRCINFO in commit\n" + ) + sys.stderr.write("error: {:s}:\n".format(str(head_commit.id))) + for error in errors: + for err in error["error"]: + sys.stderr.write("error: line {:d}: {:s}\n".format(error["line"], err)) + exit(1) + + # check if there is a correct .SRCINFO file in the latest revision + validate_metadata(metadata, head_commit) + # Validate all new commits. for commit in walker: - for fname in (".SRCINFO", "PKGBUILD"): - if fname not in commit.tree: - die_commit("missing {:s}".format(fname), str(commit.id)) - + if "PKGBUILD" not in commit.tree: + die_commit("missing PKGBUILD", str(commit.id)) for treeobj in commit.tree: blob = repo[treeobj.id] @@ -320,82 +395,6 @@ def main(): # noqa: C901 str(commit.id), ) - metadata_raw = repo[commit.tree[".SRCINFO"].id].data.decode() - (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) - if errors: - sys.stderr.write( - "error: The following errors occurred " - "when parsing .SRCINFO in commit\n" - ) - sys.stderr.write("error: {:s}:\n".format(str(commit.id))) - for error in errors: - for err in error["error"]: - sys.stderr.write( - "error: line {:d}: {:s}\n".format(error["line"], err) - ) - exit(1) - - try: - metadata_pkgbase = metadata["pkgbase"] - except KeyError: - die_commit( - "invalid .SRCINFO, does not contain a pkgbase (is the file empty?)", - str(commit.id), - ) - if not re.match(repo_regex, metadata_pkgbase): - die_commit("invalid pkgbase: {:s}".format(metadata_pkgbase), str(commit.id)) - - if not metadata["packages"]: - die_commit("missing pkgname entry", str(commit.id)) - - for pkgname in set(metadata["packages"].keys()): - pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) - - for field in ("pkgver", "pkgrel", "pkgname"): - if field not in pkginfo: - die_commit( - "missing mandatory field: {:s}".format(field), str(commit.id) - ) - - if "epoch" in pkginfo and not pkginfo["epoch"].isdigit(): - die_commit( - "invalid epoch: {:s}".format(pkginfo["epoch"]), str(commit.id) - ) - - if not re.match(r"[a-z0-9][a-z0-9\.+_-]*$", pkginfo["pkgname"]): - die_commit( - "invalid package name: {:s}".format(pkginfo["pkgname"]), - str(commit.id), - ) - - max_len = {"pkgname": 255, "pkgdesc": 255, "url": 8000} - for field in max_len.keys(): - if field in pkginfo and len(pkginfo[field]) > max_len[field]: - die_commit( - "{:s} field too long: {:s}".format(field, pkginfo[field]), - str(commit.id), - ) - - for field in ("install", "changelog"): - if field in pkginfo and not pkginfo[field] in commit.tree: - die_commit( - "missing {:s} file: {:s}".format(field, pkginfo[field]), - str(commit.id), - ) - - for field in extract_arch_fields(pkginfo, "source"): - fname = field["value"] - if len(fname) > 8000: - die_commit( - "source entry too long: {:s}".format(fname), str(commit.id) - ) - if "://" in fname or "lp:" in fname: - continue - if fname not in commit.tree: - die_commit( - "missing source file: {:s}".format(fname), str(commit.id) - ) - # Display a warning if .SRCINFO is unchanged. if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): srcinfo_id_old = repo[sha1_old].tree[".SRCINFO"].id @@ -403,10 +402,6 @@ def main(): # noqa: C901 if srcinfo_id_old == srcinfo_id_new: warn(".SRCINFO unchanged. " "The package database will not be updated!") - # Read .SRCINFO from the HEAD commit. - metadata_raw = repo[repo[sha1_new].tree[".SRCINFO"].id].data.decode() - (metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) - # Ensure that the package base name matches the repository name. metadata_pkgbase = metadata["pkgbase"] if metadata_pkgbase != pkgbase: diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index e9d943c0..a8ea5cab 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -175,10 +175,8 @@ test_expect_success 'Removing .SRCINFO with a follow-up fix.' ' git -C aur.git commit -q -m "Remove .SRCINFO" && git -C aur.git revert --no-edit HEAD && new=$(git -C aur.git rev-parse HEAD) && - test_must_fail \ env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && - grep -q "^error: missing .SRCINFO$" actual + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 ' test_expect_success 'Removing PKGBUILD.' ' From 26b2566b3fa5fe7165deaedd6e0be6b7da6a3b0f Mon Sep 17 00:00:00 2001 From: Christian Heusel Date: Thu, 8 Jun 2023 12:42:31 +0200 Subject: [PATCH 1765/1891] change: print the user name if connecting via ssh this is similar to the message that gitlab produces: $ ssh -T aur.archlinux.org Welcome to AUR, gromit! Interactive shell is disabled. Try `ssh ssh://aur@aur.archlinux.org help` for a list of commands. $ ssh -T gitlab.archlinux.org Welcome to GitLab, @gromit! Signed-off-by: Christian Heusel --- aurweb/git/serve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 8dbbf3f7..2ac1f10e 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -648,7 +648,7 @@ def main(): ssh_client = os.environ.get("SSH_CLIENT") if not ssh_cmd: - die_with_help("Interactive shell is disabled.") + die_with_help(f"Welcome to AUR, {user}! Interactive shell is disabled.") cmdargv = shlex.split(ssh_cmd) action = cmdargv[0] remote_addr = ssh_client.split(" ")[0] if ssh_client else None From 1c11c901a2d389bf497e886c990b634a70a4df7a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 10 Jun 2023 09:40:35 +0200 Subject: [PATCH 1766/1891] feat: switch requests filter for pkgname to "contains" Use "contains" filtering instead of an exact match when a package name filter is given. This makes it easier to find requests for a "group" of packages. Signed-off-by: moson-mo --- aurweb/routers/requests.py | 4 ++-- test/test_requests.py | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 585dc157..4cfda269 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -99,9 +99,9 @@ async def requests( in_filters.append(REJECTED_ID) filtered = query.filter(PackageRequest.Status.in_(in_filters)) - # Name filter + # Name filter (contains) if filter_pkg_name: - filtered = filtered.filter(PackageBase.Name == filter_pkg_name) + filtered = filtered.filter(PackageBase.Name.like(f"%{filter_pkg_name}%")) # Additionally filter for requests made from package maintainer if filter_maintainer_requests: diff --git a/test/test_requests.py b/test/test_requests.py index 7ddb76a0..eb88cd94 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -925,14 +925,28 @@ def test_requests_with_package_name_filter( request.cookies = cookies resp = request.get( "/requests", - params={"filter_pkg_name": packages[0].PackageBase.Name}, + params={"filter_pkg_name": "kg_1"}, ) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - # We only expect 1 request for our first package - assert len(rows) == 1 + # We expect 11 requests for all packages containing "kg_1" + assert len(rows) == 11 + + # test as TU, no results + with client as request: + request.cookies = cookies + resp = request.get( + "/requests", + params={"filter_pkg_name": "x"}, + ) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + # We expect 0 requests since we don't have anything containing "x" + assert len(rows) == 0 # test as regular user, not related to our package cookies = {"AURSID": user2.login(Request(), "testPassword")} From ed17486da6ada6c6bb1ca6fb1fddfbd1ccee4708 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 11 Jun 2023 12:20:02 +0200 Subject: [PATCH 1767/1891] change(git): allow keys/pgp subdir with .asc files This allows migration of git history for packages dropped from a repo to AUR in case they contain PGP key material Signed-off-by: moson-mo --- aurweb/git/update.py | 53 +++++++++++++++------ test/t1300-git-update.t | 103 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 141 insertions(+), 15 deletions(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 467b540f..cd7813e0 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -315,6 +315,14 @@ def validate_metadata(metadata, commit): # noqa: C901 die_commit("missing source file: {:s}".format(fname), str(commit.id)) +def validate_blob_size(blob: pygit2.Object, commit: pygit2.Commit): + if isinstance(blob, pygit2.Blob) and blob.size > max_blob_size: + die_commit( + "maximum blob size ({:s}) exceeded".format(size_humanize(max_blob_size)), + str(commit.id), + ) + + def main(): # noqa: C901 repo = pygit2.Repository(repo_path) @@ -376,25 +384,42 @@ def main(): # noqa: C901 for commit in walker: if "PKGBUILD" not in commit.tree: die_commit("missing PKGBUILD", str(commit.id)) + + # Iterate over files in root dir for treeobj in commit.tree: - blob = repo[treeobj.id] - - if isinstance(blob, pygit2.Tree): + # Don't allow any subdirs besides "keys/" + if isinstance(treeobj, pygit2.Tree) and treeobj.name != "keys": die_commit( - "the repository must not contain subdirectories", str(commit.id) - ) - - if not isinstance(blob, pygit2.Blob): - die_commit("not a blob object: {:s}".format(treeobj), str(commit.id)) - - if blob.size > max_blob_size: - die_commit( - "maximum blob size ({:s}) exceeded".format( - size_humanize(max_blob_size) - ), + "the repository must not contain subdirectories", str(commit.id), ) + # Check size of files in root dir + validate_blob_size(treeobj, commit) + + # If we got a subdir keys/, + # make sure it only contains a pgp/ subdir with key files + if "keys" in commit.tree: + # Check for forbidden files/dirs in keys/ + for keyobj in commit.tree["keys"]: + if not isinstance(keyobj, pygit2.Tree) or keyobj.name != "pgp": + die_commit( + "the keys/ subdir may only contain a pgp/ directory", + str(commit.id), + ) + # Check for forbidden files in keys/pgp/ + if "keys/pgp" in commit.tree: + for pgpobj in commit.tree["keys/pgp"]: + if not isinstance(pgpobj, pygit2.Blob) or not pgpobj.name.endswith( + ".asc" + ): + die_commit( + "the subdir may only contain .asc (PGP pub key) files", + str(commit.id), + ) + # Check file size for pgp key files + validate_blob_size(pgpobj, commit) + # Display a warning if .SRCINFO is unchanged. if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): srcinfo_id_old = repo[sha1_old].tree[".SRCINFO"].id diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index a8ea5cab..4fdb487b 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -191,7 +191,7 @@ test_expect_success 'Removing PKGBUILD.' ' grep -q "^error: missing PKGBUILD$" actual ' -test_expect_success 'Pushing a tree with a subdirectory.' ' +test_expect_success 'Pushing a tree with a forbidden subdirectory.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && mkdir aur.git/subdir && @@ -205,6 +205,107 @@ test_expect_success 'Pushing a tree with a subdirectory.' ' grep -q "^error: the repository must not contain subdirectories$" actual ' +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; wrong files.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/nonsense && + git -C aur.git add keys/pgp/nonsense && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the subdir may only contain .asc (PGP pub key) files$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; another subdir.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/bla/ && + touch aur.git/keys/pgp/bla/x.asc && + git -C aur.git add keys/pgp/bla/x.asc && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the subdir may only contain .asc (PGP pub key) files$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; wrong subdir.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/xyz/ && + touch aur.git/keys/xyz/x.asc && + git -C aur.git add keys/xyz/x.asc && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the keys/ subdir may only contain a pgp/ directory$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; additional files' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/x.asc && + touch aur.git/keys/nonsense && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git add keys/nonsense && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the keys/ subdir may only contain a pgp/ directory$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; additional subdir' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + mkdir -p aur.git/somedir/ && + touch aur.git/keys/pgp/x.asc && + touch aur.git/somedir/nonsense && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git add somedir/nonsense && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the repository must not contain subdirectories$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; keys to large' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + printf "%256001s" x > aur.git/keys/pgp/x.asc && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/x.asc && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + test_expect_success 'Pushing a tree with a large blob.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && From 58158505b06c1856420c22b1827f42eec450b477 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 11 Jun 2023 21:04:35 +0200 Subject: [PATCH 1768/1891] fix: browser hints for password fields Co-authored-by: eNV25 Signed-off-by: moson-mo --- templates/partials/account_form.html | 6 +++--- templates/passreset.html | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 4d135a56..28dc0cd5 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -246,7 +246,7 @@ -

    @@ -255,7 +255,7 @@ {% trans %}Re-type password{% endtrans %}: -

    @@ -333,7 +333,7 @@ -

    {% else %} diff --git a/templates/passreset.html b/templates/passreset.html index 6a31109f..08493fe9 100644 --- a/templates/passreset.html +++ b/templates/passreset.html @@ -26,14 +26,14 @@ {% trans %}Enter your new password:{% endtrans %} - {% trans %}Confirm your new password:{% endtrans %} - From 32461f28eaf786b34d9ee3a8a27d97ee1356228a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 15 Jun 2023 14:16:38 +0200 Subject: [PATCH 1769/1891] fix(docker): Suppress error PEP-668 When using docker (compose), we don't create a venv and just install python packages system-wide. With python 3.11 (PEP 668) we need to explicitly tell pip to allow this. Signed-off-by: moson-mo --- docker/scripts/install-python-deps.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docker/scripts/install-python-deps.sh b/docker/scripts/install-python-deps.sh index 01a6eaa7..f1942498 100755 --- a/docker/scripts/install-python-deps.sh +++ b/docker/scripts/install-python-deps.sh @@ -1,10 +1,8 @@ #!/bin/bash set -eou pipefail -# Upgrade PIP; Arch Linux's version of pip is outdated for Poetry. -pip install --upgrade pip - if [ ! -z "${COMPOSE+x}" ]; then + export PIP_BREAK_SYSTEM_PACKAGES=1 poetry config virtualenvs.create false fi poetry install --no-interaction --no-ansi From c6c81f0789e72e2a99dd4474941344350dd246c9 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 16 Jun 2023 13:33:39 +0200 Subject: [PATCH 1770/1891] housekeep: Amend .gitignore and .dockerignore Prevent some files/dirs to end up in the repo / docker image: * directories typically used for python virtualenvs * files that are being generated by running tests Signed-off-by: moson-mo --- .dockerignore | 19 ++++++++++++++++++- .gitignore | 8 ++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.dockerignore b/.dockerignore index 6ec5547d..56ac1964 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,23 @@ -*/*.mo +# Config files conf/config conf/config.sqlite conf/config.sqlite.defaults conf/docker conf/docker.defaults + +# Compiled translation files +**/*.mo + +# Typical virtualenv directories +env/ +venv/ +.venv/ + +# Test output +htmlcov/ +test-emails/ +test/__pycache__ +test/test-results +test/trash_directory* +.coverage +.pytest_cache diff --git a/.gitignore b/.gitignore index a3314c27..68de7cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,6 @@ conf/docker conf/docker.defaults data.sql dummy-data.sql* -env/ fastapi_aw/ htmlcov/ po/*.mo @@ -32,7 +31,7 @@ po/*.po~ po/POTFILES schema/aur-schema-sqlite.sql test/test-results/ -test/trash directory* +test/trash_directory* web/locale/*/ web/html/*.gz @@ -53,3 +52,8 @@ report.xml # Ignore test emails test-emails/ + +# Ignore typical virtualenv directories +env/ +venv/ +.venv/ From 143575c9dec9d1126e087dc451417b1910352ed2 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 11 Jun 2023 20:31:51 +0200 Subject: [PATCH 1771/1891] fix: restore command, remove premature creation of pkgbase We're currently creating a "PackageBases" when the "restore" command is executed. This is problematic for pkgbases that never existed before. In those cases it will create the record but fail in the update.py script. Thus it leaves an orphan "PackageBases" record in the DB (which does not have any related "Packages" record(s)) Navigating to such a packages /pkgbase/... URL will result in a crash since it is not foreseen to have "orphan" pkgbase records. We can safely remove the early creation of that record because it'll be taken care of in the update.py script that is being called We'll also fix some tests. Before it was executing a dummy script instead of "update.py" which might be a bit misleading since it did not check the real outcome of our "restore" action. Signed-off-by: moson-mo --- aurweb/git/serve.py | 24 +++++------------------- test/setup.sh | 9 +-------- test/t1200-git-serve.t | 23 +++++++++++++++-------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 2ac1f10e..333d0394 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -52,7 +52,7 @@ def list_repos(user): conn.close() -def create_pkgbase(pkgbase, user): +def validate_pkgbase(pkgbase, user): if not re.match(repo_regex, pkgbase): raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase) if pkgbase_exists(pkgbase): @@ -62,26 +62,12 @@ def create_pkgbase(pkgbase, user): cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] + + conn.close() + if userid == 0: raise aurweb.exceptions.InvalidUserException(user) - now = int(time.time()) - cur = conn.execute( - "INSERT INTO PackageBases (Name, SubmittedTS, " - + "ModifiedTS, SubmitterUID, MaintainerUID, " - + "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')", - [pkgbase, now, now, userid, userid], - ) - pkgbase_id = cur.lastrowid - - cur = conn.execute( - "INSERT INTO PackageNotifications " + "(PackageBaseID, UserID) VALUES (?, ?)", - [pkgbase_id, userid], - ) - - conn.commit() - conn.close() - def pkgbase_adopt(pkgbase, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) @@ -577,7 +563,7 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901 checkarg(cmdargv, "repository name") pkgbase = cmdargv[1] - create_pkgbase(pkgbase, user) + validate_pkgbase(pkgbase, user) os.environ["AUR_USER"] = user os.environ["AUR_PKGBASE"] = pkgbase diff --git a/test/setup.sh b/test/setup.sh index 2db897bf..ccf24086 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -56,7 +56,7 @@ ssh-options = restrict repo-path = ./aur.git/ repo-regex = [a-z0-9][a-z0-9.+_-]*$ git-shell-cmd = ./git-shell.sh -git-update-cmd = ./update.sh +git-update-cmd = $GIT_UPDATE ssh-cmdline = ssh aur@aur.archlinux.org [update] @@ -90,13 +90,6 @@ echo $GIT_NAMESPACE EOF chmod +x git-shell.sh -cat >update.sh <<-\EOF -#!/bin/sh -echo $AUR_USER -echo $AUR_PKGBASE -EOF -chmod +x update.sh - AUR_CONFIG=config export AUR_CONFIG diff --git a/test/t1200-git-serve.t b/test/t1200-git-serve.t index dbb465bc..bb3a004f 100755 --- a/test/t1200-git-serve.t +++ b/test/t1200-git-serve.t @@ -137,14 +137,21 @@ test_expect_success "Try to push to someone else's repository as Trusted User." ' test_expect_success "Test restore." ' + # Delete from DB echo "DELETE FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ sqlite3 aur.db && - cat >expected <<-EOF && - user - foobar - EOF + # "Create branch" as if it had been there + new=$(git -C aur.git rev-parse HEAD^) && + echo $new > aur.git/.git/refs/heads/foobar && + # Restore deleted package SSH_ORIGINAL_COMMAND="restore foobar" AUR_USER=user AUR_PRIVILEGED=0 \ - cover "$GIT_SERVE" 2>&1 >actual + cover "$GIT_SERVE" 2>&1 && + # We should find foobar with a new ID (3) in the DB after restore + echo "SELECT ID FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ + sqlite3 aur.db >actual && + cat >expected <<-EOF && + 3 + EOF test_cmp expected actual ' @@ -174,7 +181,7 @@ test_expect_success "Adopt a package base as a regular user." ' SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && - *foobar + foobar EOF SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 >actual && @@ -252,7 +259,7 @@ test_expect_success "Try to steal another user's package as a Trusted User." ' cover "$GIT_SERVE" 2>&1 >actual && test_cmp expected actual && cat >expected <<-EOF && - *foobar + foobar EOF SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ cover "$GIT_SERVE" 2>&1 >actual && @@ -340,7 +347,7 @@ test_expect_success "Disown a package base and check (co-)maintainer list." ' SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && - *foobar + foobar EOF SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user2 AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 >actual && From e2c113caee0f42584d1a25644423a5d9455ffde0 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 22 Jun 2023 19:22:56 +0100 Subject: [PATCH 1772/1891] chore(release): prepare for 6.2.5 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e25fe90a..69f04fab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.4" +version = "v6.2.5" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From c41f2e854a1aeb4aab963a3756cf0768374a742b Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 2 Jul 2023 13:21:11 +0200 Subject: [PATCH 1773/1891] perf: tweak some search queries We currently sorting on two columns in different tables which is quite expensive in terms of performance: MariaDB is first merging the data into some temporary table to apply the sorting and record limiting. We can tweak a couple of these queries by changing the "order by" clause such that they refer to columns within the same table (PackageBases). So instead performing the second sorting on "Packages.Name", we do this on "PackageBases.Name" instead. This should still be "good enough" to produce properly sorted results. Signed-off-by: moson-mo --- aurweb/packages/search.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 62de1ea8..78b27a9a 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -195,13 +195,13 @@ class PackageSearch: def _sort_by_votes(self, order: str): column = getattr(models.PackageBase.NumVotes, order) - name = getattr(models.Package.Name, order) + name = getattr(models.PackageBase.Name, order) self.query = self.query.order_by(column(), name()) return self def _sort_by_popularity(self, order: str): column = getattr(models.PackageBase.Popularity, order) - name = getattr(models.Package.Name, order) + name = getattr(models.PackageBase.Name, order) self.query = self.query.order_by(column(), name()) return self @@ -236,7 +236,7 @@ class PackageSearch: def _sort_by_last_modified(self, order: str): column = getattr(models.PackageBase.ModifiedTS, order) - name = getattr(models.Package.Name, order) + name = getattr(models.PackageBase.Name, order) self.query = self.query.order_by(column(), name()) return self From 7c8b9ba6bcacfe45e416ec37cf16fa1824659825 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 2 Jul 2023 13:55:21 +0200 Subject: [PATCH 1774/1891] perf: add index to tweak our default search query Adds an index on PackageBases.Popularity and PackageBases.Name to improve performance of our default search query sorted by "Popularity" Signed-off-by: moson-mo --- ...0_add_index_on_packagebases_popularity_.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py diff --git a/migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py b/migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py new file mode 100644 index 00000000..12f97028 --- /dev/null +++ b/migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py @@ -0,0 +1,24 @@ +"""Add index on PackageBases.Popularity and .Name + +Revision ID: c5a6a9b661a0 +Revises: e4e49ffce091 +Create Date: 2023-07-02 13:46:52.522146 + +""" +from alembic import op + +# revision identifiers, used by Alembic. +revision = "c5a6a9b661a0" +down_revision = "e4e49ffce091" +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_index( + "BasesPopularityName", "PackageBases", ["Popularity", "Name"], unique=False + ) + + +def downgrade(): + op.drop_index("BasesPopularityName", table_name="PackageBases") From 3acfb08a0f839ce3582d9ce92c01e321e99e69f3 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 2 Jul 2023 01:06:34 +0200 Subject: [PATCH 1775/1891] feat: cache package search results with Redis The queries being done on the package search page are quite costly. (Especially the default one ordered by "Popularity" when navigating to /packages) Let's add the search results to the Redis cache: Every result of a search query is being pushed to Redis until we hit our maximum of 50k. An entry expires after 3 minutes before it's evicted from the cache. Lifetime an Max values are configurable. Signed-off-by: moson-mo --- aurweb/cache.py | 38 ++++++++--- aurweb/routers/html.py | 20 +++--- aurweb/routers/packages.py | 15 ++++- aurweb/util.py | 8 +++ conf/config.defaults | 6 ++ test/test_cache.py | 121 ++++++++++++++++++++--------------- test/test_packages_routes.py | 13 +++- test/test_util.py | 26 +++++++- 8 files changed, 173 insertions(+), 74 deletions(-) diff --git a/aurweb/cache.py b/aurweb/cache.py index 1572e2fc..56bb45b7 100644 --- a/aurweb/cache.py +++ b/aurweb/cache.py @@ -1,21 +1,43 @@ -from redis import Redis +import pickle + from sqlalchemy import orm +from aurweb import config +from aurweb.aur_redis import redis_connection -async def db_count_cache( - redis: Redis, key: str, query: orm.Query, expire: int = None -) -> int: +_redis = redis_connection() + + +async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: """Store and retrieve a query.count() via redis cache. - :param redis: Redis handle :param key: Redis key :param query: SQLAlchemy ORM query :param expire: Optional expiration in seconds :return: query.count() """ - result = redis.get(key) + result = _redis.get(key) if result is None: - redis.set(key, (result := int(query.count()))) + _redis.set(key, (result := int(query.count()))) if expire: - redis.expire(key, expire) + _redis.expire(key, expire) return int(result) + + +async def db_query_cache(key: str, query: orm.Query, expire: int = None): + """Store and retrieve query results via redis cache. + + :param key: Redis key + :param query: SQLAlchemy ORM query + :param expire: Optional expiration in seconds + :return: query.all() + """ + result = _redis.get(key) + if result is None: + if _redis.dbsize() > config.getint("cache", "max_search_entries", 50000): + return query.all() + _redis.set(key, (result := pickle.dumps(query.all())), ex=expire) + if expire: + _redis.expire(key, expire) + + return pickle.loads(result) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 38303837..fc9f3519 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -89,22 +89,20 @@ async def index(request: Request): bases = db.query(models.PackageBase) - redis = aurweb.aur_redis.redis_connection() - cache_expire = 300 # Five minutes. - + cache_expire = aurweb.config.getint("cache", "expiry_time") # Package statistics. context["package_count"] = await db_count_cache( - redis, "package_count", bases, expire=cache_expire + "package_count", bases, expire=cache_expire ) query = bases.filter(models.PackageBase.MaintainerUID.is_(None)) context["orphan_count"] = await db_count_cache( - redis, "orphan_count", query, expire=cache_expire + "orphan_count", query, expire=cache_expire ) query = db.query(models.User) context["user_count"] = await db_count_cache( - redis, "user_count", query, expire=cache_expire + "user_count", query, expire=cache_expire ) query = query.filter( @@ -114,7 +112,7 @@ async def index(request: Request): ) ) context["trusted_user_count"] = await db_count_cache( - redis, "trusted_user_count", query, expire=cache_expire + "trusted_user_count", query, expire=cache_expire ) # Current timestamp. @@ -130,26 +128,26 @@ async def index(request: Request): query = bases.filter(models.PackageBase.SubmittedTS >= seven_days_ago) context["seven_days_old_added"] = await db_count_cache( - redis, "seven_days_old_added", query, expire=cache_expire + "seven_days_old_added", query, expire=cache_expire ) query = updated.filter(models.PackageBase.ModifiedTS >= seven_days_ago) context["seven_days_old_updated"] = await db_count_cache( - redis, "seven_days_old_updated", query, expire=cache_expire + "seven_days_old_updated", query, expire=cache_expire ) year = seven_days * 52 # Fifty two weeks worth: one year. year_ago = now - year query = updated.filter(models.PackageBase.ModifiedTS >= year_ago) context["year_old_updated"] = await db_count_cache( - redis, "year_old_updated", query, expire=cache_expire + "year_old_updated", query, expire=cache_expire ) query = bases.filter( models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600 ) context["never_updated"] = await db_count_cache( - redis, "never_updated", query, expire=cache_expire + "never_updated", query, expire=cache_expire ) # Get the 15 most recently updated packages. diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 83bfe6e2..779efb4b 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -7,6 +7,7 @@ from fastapi import APIRouter, Form, Query, Request, Response import aurweb.filters # noqa: F401 from aurweb import aur_logging, config, db, defaults, models, util from aurweb.auth import creds, requires_auth +from aurweb.cache import db_count_cache, db_query_cache from aurweb.exceptions import InvariantError, handle_form_exceptions from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.packages import util as pkgutil @@ -14,6 +15,7 @@ from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base from aurweb.pkgbase import actions as pkgbase_actions, util as pkgbaseutil from aurweb.templates import make_context, make_variable_context, render_template +from aurweb.util import hash_query logger = aur_logging.get_logger(__name__) router = APIRouter() @@ -87,7 +89,11 @@ async def packages_get( # Collect search result count here; we've applied our keywords. # Including more query operations below, like ordering, will # increase the amount of time required to collect a count. - num_packages = search.count() + # we use redis for caching the results of the query + cache_expire = config.getint("cache", "expiry_time") + num_packages = await db_count_cache( + hash_query(search.query), search.query, cache_expire + ) # Apply user-specified sort column and ordering. search.sort_by(sort_by, sort_order) @@ -108,7 +114,12 @@ async def packages_get( models.PackageNotification.PackageBaseID.label("Notify"), ) - packages = results.limit(per_page).offset(offset) + # paging + results = results.limit(per_page).offset(offset) + + # we use redis for caching the results of the query + packages = await db_query_cache(hash_query(results), results, cache_expire) + context["packages"] = packages context["packages_count"] = num_packages diff --git a/aurweb/util.py b/aurweb/util.py index d80b0311..7050b482 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -4,6 +4,7 @@ import secrets import shlex import string from datetime import datetime +from hashlib import sha1 from http import HTTPStatus from subprocess import PIPE, Popen from typing import Callable, Iterable, Tuple, Union @@ -13,6 +14,7 @@ import fastapi import pygit2 from email_validator import EmailSyntaxError, validate_email from fastapi.responses import JSONResponse +from sqlalchemy.orm import Query import aurweb.config from aurweb import aur_logging, defaults @@ -200,3 +202,9 @@ def shell_exec(cmdline: str, cwd: str) -> Tuple[int, str, str]: proc = Popen(args, cwd=cwd, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() return proc.returncode, out.decode().strip(), err.decode().strip() + + +def hash_query(query: Query): + return sha1( + str(query.statement.compile(compile_kwargs={"literal_binds": True})).encode() + ).hexdigest() diff --git a/conf/config.defaults b/conf/config.defaults index c059444d..4e2415ed 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -165,3 +165,9 @@ commit_url = https://gitlab.archlinux.org/archlinux/aurweb/-/commits/%s ; voted on based on `now + range_start <= End <= now + range_end`. range_start = 500 range_end = 172800 + +[cache] +; maximum number of keys/entries (for search results) in our redis cache, default is 50000 +max_search_entries = 50000 +; number of seconds after a cache entry expires, default is 3 minutes +expiry_time = 180 diff --git a/test/test_cache.py b/test/test_cache.py index 83a9755a..e19fa6a2 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -1,6 +1,8 @@ +from unittest import mock + import pytest -from aurweb import cache, db +from aurweb import cache, config, db from aurweb.models.account_type import USER_ID from aurweb.models.user import User @@ -10,68 +12,85 @@ def setup(db_test): return -class StubRedis: - """A class which acts as a RedisConnection without using Redis.""" - - cache = dict() - expires = dict() - - def get(self, key, *args): - if "key" not in self.cache: - self.cache[key] = None - return self.cache[key] - - def set(self, key, *args): - self.cache[key] = list(args)[0] - - def expire(self, key, *args): - self.expires[key] = list(args)[0] - - async def execute(self, command, key, *args): - f = getattr(self, command) - return f(key, *args) - - @pytest.fixture -def redis(): - yield StubRedis() +def user() -> User: + with db.begin(): + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) + yield user + + +@pytest.fixture(autouse=True) +def clear_fakeredis_cache(): + cache._redis.flushall() @pytest.mark.asyncio -async def test_db_count_cache(redis): - db.create( - User, - Username="user1", - Email="user1@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID, - ) - +async def test_db_count_cache(user): query = db.query(User) - # Now, perform several checks that db_count_cache matches query.count(). - # We have no cached value yet. - assert await cache.db_count_cache(redis, "key1", query) == query.count() + assert cache._redis.get("key1") is None + + # Add to cache + assert await cache.db_count_cache("key1", query) == query.count() # It's cached now. - assert await cache.db_count_cache(redis, "key1", query) == query.count() + assert cache._redis.get("key1") is not None + + # It does not expire + assert cache._redis.ttl("key1") == -1 + + # Cache a query with an expire. + value = await cache.db_count_cache("key2", query, 100) + assert value == query.count() + + assert cache._redis.ttl("key2") == 100 @pytest.mark.asyncio -async def test_db_count_cache_expires(redis): - db.create( - User, - Username="user1", - Email="user1@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID, - ) - +async def test_db_query_cache(user): query = db.query(User) - # Cache a query with an expire. - value = await cache.db_count_cache(redis, "key1", query, 100) - assert value == query.count() + # We have no cached value yet. + assert cache._redis.get("key1") is None - assert redis.expires["key1"] == 100 + # Add to cache + await cache.db_query_cache("key1", query) + + # It's cached now. + assert cache._redis.get("key1") is not None + + # Modify our user and make sure we got a cached value + user.Username = "changed" + cached = await cache.db_query_cache("key1", query) + assert cached[0].Username != query.all()[0].Username + + # It does not expire + assert cache._redis.ttl("key1") == -1 + + # Cache a query with an expire. + value = await cache.db_query_cache("key2", query, 100) + assert len(value) == query.count() + assert value[0].Username == query.all()[0].Username + + assert cache._redis.ttl("key2") == 100 + + # Test "max_search_entries" options + def mock_max_search_entries(section: str, key: str, fallback: int) -> str: + if section == "cache" and key == "max_search_entries": + return 1 + return config.getint(section, key) + + with mock.patch("aurweb.config.getint", side_effect=mock_max_search_entries): + # Try to add another entry (we already have 2) + await cache.db_query_cache("key3", query) + + # Make sure it was not added because it exceeds our max. + assert cache._redis.get("key3") is None diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 93dc404a..fb12e65e 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -5,7 +5,7 @@ from unittest import mock import pytest from fastapi.testclient import TestClient -from aurweb import asgi, config, db, time +from aurweb import asgi, cache, config, db, time from aurweb.filters import datetime_display from aurweb.models import License, PackageLicense from aurweb.models.account_type import USER_ID, AccountType @@ -63,6 +63,11 @@ def setup(db_test): return +@pytest.fixture(autouse=True) +def clear_fakeredis_cache(): + cache._redis.flushall() + + @pytest.fixture def client() -> TestClient: """Yield a FastAPI TestClient.""" @@ -815,6 +820,8 @@ def test_packages_search_by_keywords(client: TestClient, packages: list[Package] # And request packages with that keyword, we should get 1 result. with client as request: + # clear fakeredis cache + cache._redis.flushall() response = request.get("/packages", params={"SeB": "k", "K": "testKeyword"}) assert response.status_code == int(HTTPStatus.OK) @@ -870,6 +877,8 @@ def test_packages_search_by_maintainer( # This time, we should get `package` returned, since it's now an orphan. with client as request: + # clear fakeredis cache + cache._redis.flushall() response = request.get("/packages", params={"SeB": "m"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -902,6 +911,8 @@ def test_packages_search_by_comaintainer( # Then test that it's returned by our search. with client as request: + # clear fakeredis cache + cache._redis.flushall() response = request.get( "/packages", params={"SeB": "c", "K": maintainer.Username} ) diff --git a/test/test_util.py b/test/test_util.py index a138d912..042b9ad9 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -5,7 +5,8 @@ import fastapi import pytest from fastapi.responses import JSONResponse -from aurweb import filters, util +from aurweb import db, filters, util +from aurweb.models.user import User from aurweb.testing.requests import Request @@ -146,3 +147,26 @@ def assert_multiple_keys(pks): assert key1 == k1[1] assert pfx2 == k2[0] assert key2 == k2[1] + + +def test_hash_query(): + # No conditions + query = db.query(User) + assert util.hash_query(query) == "75e76026b7d576536e745ec22892cf8f5d7b5d62" + + # With where clause + query = db.query(User).filter(User.Username == "bla") + assert util.hash_query(query) == "4dca710f33b1344c27ec6a3c266970f4fa6a8a00" + + # With where clause and sorting + query = db.query(User).filter(User.Username == "bla").order_by(User.Username) + assert util.hash_query(query) == "ee2c7846fede430776e140f8dfe1d83cd21d2eed" + + # With where clause, sorting and specific columns + query = ( + db.query(User) + .filter(User.Username == "bla") + .order_by(User.Username) + .with_entities(User.Username) + ) + assert util.hash_query(query) == "c1db751be61443d266cf643005eee7a884dac103" From 814ccf6b04e97659c30ecc18dd63607a3ba485e6 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 4 Jul 2023 09:40:39 +0200 Subject: [PATCH 1776/1891] feat: add Prometheus metrics for Redis cache Adding a Prometheus counter to be able to monitor cache hits/misses for search queries Signed-off-by: moson-mo --- aurweb/cache.py | 13 +++++++++++-- test/test_metrics.py | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 test/test_metrics.py diff --git a/aurweb/cache.py b/aurweb/cache.py index 56bb45b7..fe1e5f1d 100644 --- a/aurweb/cache.py +++ b/aurweb/cache.py @@ -1,5 +1,6 @@ import pickle +from prometheus_client import Counter from sqlalchemy import orm from aurweb import config @@ -7,6 +8,11 @@ from aurweb.aur_redis import redis_connection _redis = redis_connection() +# Prometheus metrics +SEARCH_REQUESTS = Counter( + "search_requests", "Number of search requests by cache hit/miss", ["cache"] +) + async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: """Store and retrieve a query.count() via redis cache. @@ -24,7 +30,7 @@ async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: return int(result) -async def db_query_cache(key: str, query: orm.Query, expire: int = None): +async def db_query_cache(key: str, query: orm.Query, expire: int = None) -> list: """Store and retrieve query results via redis cache. :param key: Redis key @@ -34,10 +40,13 @@ async def db_query_cache(key: str, query: orm.Query, expire: int = None): """ result = _redis.get(key) if result is None: + SEARCH_REQUESTS.labels(cache="miss").inc() if _redis.dbsize() > config.getint("cache", "max_search_entries", 50000): return query.all() - _redis.set(key, (result := pickle.dumps(query.all())), ex=expire) + _redis.set(key, (result := pickle.dumps(query.all()))) if expire: _redis.expire(key, expire) + else: + SEARCH_REQUESTS.labels(cache="hit").inc() return pickle.loads(result) diff --git a/test/test_metrics.py b/test/test_metrics.py new file mode 100644 index 00000000..1859d8cb --- /dev/null +++ b/test/test_metrics.py @@ -0,0 +1,40 @@ +import pytest +from prometheus_client import REGISTRY, generate_latest + +from aurweb import db +from aurweb.cache import db_query_cache +from aurweb.models.account_type import USER_ID +from aurweb.models.user import User + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture +def user() -> User: + with db.begin(): + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) + yield user + + +@pytest.mark.asyncio +async def test_search_cache_metrics(user: User): + # Fire off 3 identical queries for caching + for _ in range(3): + await db_query_cache("key", db.query(User)) + + # Get metrics + metrics = str(generate_latest(REGISTRY)) + + # We should have 1 miss and 2 hits + assert 'search_requests_total{cache="miss"} 1.0' in metrics + assert 'search_requests_total{cache="hit"} 2.0' in metrics From 9fe8d524ffabcbd171cbadbbe9b42edc1f5fa91d Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 8 Jul 2023 10:32:26 +0200 Subject: [PATCH 1777/1891] fix(test): MariaDB 11 upgrade, query result order Fix order of recipients for "FlagNotification" test. Apply sorting to the recipients query. (only relevant for tests, but who knows when they change things again) MariaDB 11 includes some changes related to the query optimizer. Turns out that this might have effects on how records are ordered for certain queries. (in case no ORDER BY clause was specified) https://mariadb.com/kb/en/mariadb-11-0-0-release-notes/ Signed-off-by: moson --- aurweb/scripts/notify.py | 1 + test/test_notify.py | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index ac9022c3..f55254d7 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -334,6 +334,7 @@ class FlagNotification(Notification): .filter(and_(PackageBase.ID == pkgbase_id, User.Suspended == 0)) .with_entities(User.Email, User.LangPreference) .distinct() + .order_by(User.Email) ) self._recipients = [(u.Email, u.LangPreference) for u in query] diff --git a/test/test_notify.py b/test/test_notify.py index 9e61d9ee..1fd7cd83 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -127,20 +127,20 @@ def test_out_of_date(user: User, user1: User, user2: User, pkgbases: list[Packag # Should've gotten three emails: maintainer + the two comaintainers. assert Email.count() == 3 - # Comaintainer 1. + # Maintainer. first = Email(1).parse() - assert first.headers.get("To") == user1.Email + assert first.headers.get("To") == user.Email expected = f"AUR Out-of-date Notification for {pkgbase.Name}" assert first.headers.get("Subject") == expected - # Comaintainer 2. + # Comaintainer 1. second = Email(2).parse() - assert second.headers.get("To") == user2.Email + assert second.headers.get("To") == user1.Email - # Maintainer. + # Comaintainer 2. third = Email(3).parse() - assert third.headers.get("To") == user.Email + assert third.headers.get("To") == user2.Email def test_reset(user: User): From f3f8c0a8710838ba176f4486eb886ce37565b78a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 1 Jul 2023 12:55:14 +0200 Subject: [PATCH 1778/1891] fix: add recipients to BCC when email is hidden Package requests are sent to the ML as well as users (CC). For those who chose to hide their mail address, we should add them to the BCC list instead. Signed-off-by: moson-mo --- aurweb/scripts/notify.py | 21 +++++++++++---- po/aurweb.pot | 8 ++++++ templates/partials/account_form.html | 7 ++++- test/test_notify.py | 38 ++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index f55254d7..a85339ce 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -45,6 +45,9 @@ class Notification: def get_cc(self): return [] + def get_bcc(self): + return [] + def get_body_fmt(self, lang): body = "" for line in self.get_body(lang).splitlines(): @@ -114,7 +117,7 @@ class Notification: server.login(user, passwd) server.set_debuglevel(0) - deliver_to = [to] + self.get_cc() + deliver_to = [to] + self.get_cc() + self.get_bcc() server.sendmail(sender, deliver_to, msg.as_bytes()) server.quit() @@ -578,10 +581,11 @@ class RequestOpenNotification(Notification): ), ) .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0)) - .with_entities(User.Email) + .with_entities(User.Email, User.HideEmail) .distinct() ) - self._cc = [u.Email for u in query] + self._cc = [u.Email for u in query if u.HideEmail == 0] + self._bcc = [u.Email for u in query if u.HideEmail == 1] pkgreq = ( db.query(PackageRequest.Comments).filter(PackageRequest.ID == reqid).first() @@ -598,6 +602,9 @@ class RequestOpenNotification(Notification): def get_cc(self): return self._cc + def get_bcc(self): + return self._bcc + def get_subject(self, lang): return "[PRQ#%d] %s Request for %s" % ( self._reqid, @@ -665,10 +672,11 @@ class RequestCloseNotification(Notification): ), ) .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0)) - .with_entities(User.Email) + .with_entities(User.Email, User.HideEmail) .distinct() ) - self._cc = [u.Email for u in query] + self._cc = [u.Email for u in query if u.HideEmail == 0] + self._bcc = [u.Email for u in query if u.HideEmail == 1] pkgreq = ( db.query(PackageRequest) @@ -695,6 +703,9 @@ class RequestCloseNotification(Notification): def get_cc(self): return self._cc + def get_bcc(self): + return self._bcc + def get_subject(self, lang): return "[PRQ#%d] %s Request for %s %s" % ( self._reqid, diff --git a/po/aurweb.pot b/po/aurweb.pot index b975ab91..77bca3b0 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2366,3 +2366,11 @@ msgstr "" #: templates/requests.html msgid "Package name" msgstr "" + +#: templates/partials/account_form.html +msgid "Note that if you hide your email address, it'll " +"end up on the BCC list for any request notifications. " +"In case someone replies to these notifications, you won't " +"receive an email. However, replies are typically sent to the " +"mailing-list and would then be visible in the archive." +msgstr "" diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 28dc0cd5..7595dcaf 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -115,7 +115,12 @@ {{ "If you do not hide your email address, it is " "visible to all registered AUR users. If you hide your " "email address, it is visible to members of the Arch " - "Linux staff only." | tr }} + "Linux staff only." | tr }}
    + {{ "Note that if you hide your email address, it'll " + "end up on the BCC list for any request notifications. " + "In case someone replies to these notifications, you won't " + "receive an email. However, replies are typically sent to the " + "mailing-list and would then be visible in the archive." | tr }}

    diff --git a/test/test_notify.py b/test/test_notify.py index 1fd7cd83..fbcf350b 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -479,6 +479,44 @@ def test_close_request_comaintainer_cc( assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) +def test_open_close_request_hidden_email( + user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase] +): + pkgbase = pkgbases[0] + + # Enable the "HideEmail" option for our requester + with db.begin(): + user2.HideEmail = 1 + + # Send an open request notification. + notif = notify.RequestOpenNotification( + user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID + ) + + # Make sure our address got added to the bcc list + assert user2.Email in notif.get_bcc() + + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + # Make sure we don't have our address in the Cc header + assert user2.Email not in email.headers.get("Cc") + + # Create a closure notification on the pkgbase we just opened. + notif = notify.RequestCloseNotification(user2.ID, pkgreq.ID, "rejected") + + # Make sure our address got added to the bcc list + assert user2.Email in notif.get_bcc() + + notif.send() + assert Email.count() == 2 + + email = Email(2).parse() + # Make sure we don't have our address in the Cc header + assert user2.Email not in email.headers.get("Cc") + + def test_close_request_closure_comment( user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase] ): From 7cde1ca56041afb9aa00d2d0c46bfd10c2291080 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 8 Jul 2023 09:25:09 +0000 Subject: [PATCH 1779/1891] fix(deps): update all non-major dependencies --- poetry.lock | 622 +++++++++++++++++++++++++++------------------------- 1 file changed, 321 insertions(+), 301 deletions(-) diff --git a/poetry.lock b/poetry.lock index 16b0f15a..dcdcf819 100644 --- a/poetry.lock +++ b/poetry.lock @@ -55,14 +55,14 @@ trio = ["trio (>=0.16,<0.22)"] [[package]] name = "asgiref" -version = "3.7.1" +version = "3.7.2" description = "ASGI specs, helper code, and adapters" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "asgiref-3.7.1-py3-none-any.whl", hash = "sha256:33958cb2e4b3cd8b1b06ef295bd8605cde65b11df51d3beab39e2e149a610ab3"}, - {file = "asgiref-3.7.1.tar.gz", hash = "sha256:8de379fcc383bcfe4507e229fc31209ea23d4831c850f74063b2c11639474dd2"}, + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, ] [package.dependencies] @@ -85,14 +85,14 @@ files = [ [[package]] name = "authlib" -version = "1.2.0" +version = "1.2.1" description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." category = "main" optional = false python-versions = "*" files = [ - {file = "Authlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:4ddf4fd6cfa75c9a460b361d4bd9dac71ffda0be879dbe4292a02e92349ad55a"}, - {file = "Authlib-1.2.0.tar.gz", hash = "sha256:4fa3e80883a5915ef9f5bc28630564bc4ed5b5af39812a3ff130ec76bd631e9d"}, + {file = "Authlib-1.2.1-py2.py3-none-any.whl", hash = "sha256:c88984ea00149a90e3537c964327da930779afa4564e354edfd98410bea01911"}, + {file = "Authlib-1.2.1.tar.gz", hash = "sha256:421f7c6b468d907ca2d9afede256f068f87e34d23dd221c07d13d4c234726afb"}, ] [package.dependencies] @@ -355,63 +355,72 @@ files = [ [[package]] name = "coverage" -version = "7.2.6" +version = "7.2.7" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:496b86f1fc9c81a1cd53d8842ef712e950a4611bba0c42d33366a7b91ba969ec"}, - {file = "coverage-7.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbe6e8c0a9a7193ba10ee52977d4d5e7652957c1f56ccefed0701db8801a2a3b"}, - {file = "coverage-7.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d06b721c2550c01a60e5d3093f417168658fb454e5dfd9a23570e9bffe39a1"}, - {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77a04b84d01f0e12c66f16e69e92616442dc675bbe51b90bfb074b1e5d1c7fbd"}, - {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35db06450272473eab4449e9c2ad9bc6a0a68dab8e81a0eae6b50d9c2838767e"}, - {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6727a0d929ff0028b1ed8b3e7f8701670b1d7032f219110b55476bb60c390bfb"}, - {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aac1d5fdc5378f6bac2c0c7ebe7635a6809f5b4376f6cf5d43243c1917a67087"}, - {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c9e4a5eb1bbc3675ee57bc31f8eea4cd7fb0cbcbe4912cf1cb2bf3b754f4a80"}, - {file = "coverage-7.2.6-cp310-cp310-win32.whl", hash = "sha256:71f739f97f5f80627f1fee2331e63261355fd1e9a9cce0016394b6707ac3f4ec"}, - {file = "coverage-7.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:fde5c7a9d9864d3e07992f66767a9817f24324f354caa3d8129735a3dc74f126"}, - {file = "coverage-7.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc7b667f8654376e9353dd93e55e12ce2a59fb6d8e29fce40de682273425e044"}, - {file = "coverage-7.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:697f4742aa3f26c107ddcb2b1784a74fe40180014edbd9adaa574eac0529914c"}, - {file = "coverage-7.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:541280dde49ce74a4262c5e395b48ea1207e78454788887118c421cb4ffbfcac"}, - {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7f1a8328eeec34c54f1d5968a708b50fc38d31e62ca8b0560e84a968fbf9a9"}, - {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbd58eb5a2371bf160590f4262109f66b6043b0b991930693134cb617bc0169"}, - {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae82c5f168d2a39a5d69a12a69d4dc23837a43cf2ca99be60dfe59996ea6b113"}, - {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f5440cdaf3099e7ab17a5a7065aed59aff8c8b079597b61c1f8be6f32fe60636"}, - {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a6f03f87fea579d55e0b690d28f5042ec1368650466520fbc400e7aeaf09e995"}, - {file = "coverage-7.2.6-cp311-cp311-win32.whl", hash = "sha256:dc4d5187ef4d53e0d4c8eaf530233685667844c5fb0b855fea71ae659017854b"}, - {file = "coverage-7.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:c93d52c3dc7b9c65e39473704988602300e3cc1bad08b5ab5b03ca98bbbc68c1"}, - {file = "coverage-7.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42c692b55a647a832025a4c048007034fe77b162b566ad537ce65ad824b12a84"}, - {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7786b2fa7809bf835f830779ad285215a04da76293164bb6745796873f0942d"}, - {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25bad4196104761bc26b1dae9b57383826542ec689ff0042f7f4f4dd7a815cba"}, - {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2692306d3d4cb32d2cceed1e47cebd6b1d2565c993d6d2eda8e6e6adf53301e6"}, - {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:392154d09bd4473b9d11351ab5d63391f3d5d24d752f27b3be7498b0ee2b5226"}, - {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fa079995432037b5e2ef5ddbb270bcd2ded9f52b8e191a5de11fe59a00ea30d8"}, - {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d712cefff15c712329113b01088ba71bbcef0f7ea58478ca0bbec63a824844cb"}, - {file = "coverage-7.2.6-cp37-cp37m-win32.whl", hash = "sha256:004948e296149644d208964300cb3d98affc5211e9e490e9979af4030b0d6473"}, - {file = "coverage-7.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:c1d7a31603c3483ac49c1726723b0934f88f2c011c660e6471e7bd735c2fa110"}, - {file = "coverage-7.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3436927d1794fa6763b89b60c896f9e3bd53212001026ebc9080d23f0c2733c1"}, - {file = "coverage-7.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44c9b9f1a245f3d0d202b1a8fa666a80b5ecbe4ad5d0859c0fb16a52d9763224"}, - {file = "coverage-7.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e3783a286d5a93a2921396d50ce45a909aa8f13eee964465012f110f0cbb611"}, - {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cff6980fe7100242170092bb40d2b1cdad79502cd532fd26b12a2b8a5f9aee0"}, - {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c534431153caffc7c495c3eddf7e6a6033e7f81d78385b4e41611b51e8870446"}, - {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3062fd5c62df988cea9f2972c593f77fed1182bfddc5a3b12b1e606cb7aba99e"}, - {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6284a2005e4f8061c58c814b1600ad0074ccb0289fe61ea709655c5969877b70"}, - {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:97729e6828643f168a2a3f07848e1b1b94a366b13a9f5aba5484c2215724edc8"}, - {file = "coverage-7.2.6-cp38-cp38-win32.whl", hash = "sha256:dc11b42fa61ff1e788dd095726a0aed6aad9c03d5c5984b54cb9e1e67b276aa5"}, - {file = "coverage-7.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:cbcc874f454ee51f158afd604a315f30c0e31dff1d5d5bf499fc529229d964dd"}, - {file = "coverage-7.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d3cacc6a665221108ecdf90517a8028d07a2783df3417d12dcfef1c517e67478"}, - {file = "coverage-7.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:272ab31228a9df857ab5df5d67936d8861464dc89c5d3fab35132626e9369379"}, - {file = "coverage-7.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a8723ccec4e564d4b9a79923246f7b9a8de4ec55fa03ec4ec804459dade3c4f"}, - {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5906f6a84b47f995cd1bf0aca1c72d591c55ee955f98074e93660d64dfc66eb9"}, - {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c139b7ab3f0b15f9aad0a3fedef5a1f8c0b2bdc291d88639ca2c97d3682416"}, - {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a5ffd45c6b93c23a8507e2f436983015c6457aa832496b6a095505ca2f63e8f1"}, - {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4f3c7c19581d471af0e9cb49d928172cd8492cd78a2b7a4e82345d33662929bb"}, - {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e8c0e79820cdd67978e1120983786422d279e07a381dbf89d03bbb23ec670a6"}, - {file = "coverage-7.2.6-cp39-cp39-win32.whl", hash = "sha256:13cde6bb0e58fb67d09e2f373de3899d1d1e866c5a9ff05d93615f2f54fbd2bb"}, - {file = "coverage-7.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:6b9f64526286255735847aed0221b189486e0b9ed943446936e41b7e44b08783"}, - {file = "coverage-7.2.6-pp37.pp38.pp39-none-any.whl", hash = "sha256:6babcbf1e66e46052442f10833cfc4a0d3554d8276aa37af8531a83ed3c1a01d"}, - {file = "coverage-7.2.6.tar.gz", hash = "sha256:2025f913f2edb0272ef15d00b1f335ff8908c921c8eb2013536fcaf61f5a683d"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, ] [package.dependencies] @@ -531,19 +540,19 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.13.0" -description = "Fake implementation of redis API for testing purposes." +version = "2.16.0" +description = "Python implementation of redis API, can be used for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.13.0-py3-none-any.whl", hash = "sha256:df7bb44fb9e593970c626325230e1c321f954ce7b204d4c4452eae5233d554ed"}, - {file = "fakeredis-2.13.0.tar.gz", hash = "sha256:53f00f44f771d2b794f1ea036fa07a33476ab7368f1b0e908daab3eff80336f6"}, + {file = "fakeredis-2.16.0-py3-none-any.whl", hash = "sha256:188514cbd7120ff28c88f2a31e2fddd18fb1b28504478dfa3669c683134c4d82"}, + {file = "fakeredis-2.16.0.tar.gz", hash = "sha256:5abdd734de4ead9d6c7acbd3add1c4aa9b3ab35219339530472d9dd2bdf13057"}, ] [package.dependencies] redis = ">=4" -sortedcontainers = ">=2.4,<3.0" +sortedcontainers = ">=2,<3" [package.extras] json = ["jsonpath-ng (>=1.5,<2.0)"] @@ -588,19 +597,19 @@ python-dateutil = "*" [[package]] name = "filelock" -version = "3.12.0" +version = "3.12.2" description = "A platform independent file lock." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, - {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "greenlet" @@ -896,96 +905,109 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "lxml" -version = "4.9.2" +version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ - {file = "lxml-4.9.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a"}, - {file = "lxml-4.9.2-cp27-cp27m-win32.whl", hash = "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de"}, - {file = "lxml-4.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975"}, - {file = "lxml-4.9.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184"}, - {file = "lxml-4.9.2-cp310-cp310-win32.whl", hash = "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda"}, - {file = "lxml-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1"}, - {file = "lxml-4.9.2-cp311-cp311-win32.whl", hash = "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33"}, - {file = "lxml-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e"}, - {file = "lxml-4.9.2-cp35-cp35m-win32.whl", hash = "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df"}, - {file = "lxml-4.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5"}, - {file = "lxml-4.9.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38"}, - {file = "lxml-4.9.2-cp36-cp36m-win32.whl", hash = "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5"}, - {file = "lxml-4.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3"}, - {file = "lxml-4.9.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b"}, - {file = "lxml-4.9.2-cp37-cp37m-win32.whl", hash = "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe"}, - {file = "lxml-4.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9"}, - {file = "lxml-4.9.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457"}, - {file = "lxml-4.9.2-cp38-cp38-win32.whl", hash = "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b"}, - {file = "lxml-4.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7"}, - {file = "lxml-4.9.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2"}, - {file = "lxml-4.9.2-cp39-cp39-win32.whl", hash = "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1"}, - {file = "lxml-4.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409"}, - {file = "lxml-4.9.2.tar.gz", hash = "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67"}, + {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, + {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, + {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, + {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, + {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, + {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, + {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, + {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, + {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, + {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, + {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, + {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, + {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, + {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, + {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, + {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, + {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, + {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, + {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, + {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, + {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, + {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, + {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.7)"] +source = ["Cython (>=0.29.35)"] [[package]] name = "mako" @@ -1087,75 +1109,75 @@ files = [ [[package]] name = "mysqlclient" -version = "2.1.1" +version = "2.2.0" description = "Python interface to MySQL" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "mysqlclient-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c1ed71bd6244993b526113cca3df66428609f90e4652f37eb51c33496d478b37"}, - {file = "mysqlclient-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:c812b67e90082a840efb82a8978369e6e69fc62ce1bda4ca8f3084a9d862308b"}, - {file = "mysqlclient-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0d1cd3a5a4d28c222fa199002810e8146cffd821410b67851af4cc80aeccd97c"}, - {file = "mysqlclient-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b355c8b5a7d58f2e909acdbb050858390ee1b0e13672ae759e5e784110022994"}, - {file = "mysqlclient-2.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:996924f3483fd36a34a5812210c69e71dea5a3d5978d01199b78b7f6d485c855"}, - {file = "mysqlclient-2.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:dea88c8d3f5a5d9293dfe7f087c16dd350ceb175f2f6631c9cf4caf3e19b7a96"}, - {file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"}, + {file = "mysqlclient-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:68837b6bb23170acffb43ae411e47533a560b6360c06dac39aa55700972c93b2"}, + {file = "mysqlclient-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5670679ff1be1cc3fef0fa81bf39f0cd70605ba121141050f02743eb878ac114"}, + {file = "mysqlclient-2.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:004fe1d30d2c2ff8072f8ea513bcec235fd9b896f70dad369461d0ad7e570e98"}, + {file = "mysqlclient-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c6b142836c7dba4f723bf9c93cc46b6e5081d65b2af807f400dda9eb85a16d0"}, + {file = "mysqlclient-2.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:955dba905a7443ce4788c63fdb9f8d688316260cf60b20ff51ac3b1c77616ede"}, + {file = "mysqlclient-2.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:530ece9995a36cadb6211b9787f0c9e05cdab6702549bdb4236af5e9b535ed6a"}, + {file = "mysqlclient-2.2.0.tar.gz", hash = "sha256:04368445f9c487d8abb7a878e3d23e923e6072c04a6c320f9e0dc8a82efba14e"}, ] [[package]] name = "orjson" -version = "3.8.14" +version = "3.9.2" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "orjson-3.8.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7a7b0fead2d0115ef927fa46ad005d7a3988a77187500bf895af67b365c10d1f"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca90db8f551b8960da95b0d4cad6c0489df52ea03585b6979595be7b31a3f946"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4ac01a3db4e6a98a8ad1bb1a3e8bfc777928939e87c04e93e0d5006df574a4b"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf6825e160e4eb0ef65ce37d8c221edcab96ff2ffba65e5da2437a60a12b3ad1"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80e62afe49e6bfc706e041faa351d7520b5f86572b8e31455802251ea989613"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6112194c11e611596eed72f46efb0e6b4812682eff3c7b48473d1146c3fa0efb"}, - {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:739f9f633e1544f2a477fa3bef380f488c8dca6e2521c8dc36424b12554ee31e"}, - {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d3d8faded5a514b80b56d0429eb38b429d7a810f8749d25dc10a0cc15b8a3c8"}, - {file = "orjson-3.8.14-cp310-none-win_amd64.whl", hash = "sha256:0bf00c42333412a9338297bf888d7428c99e281e20322070bde8c2314775508b"}, - {file = "orjson-3.8.14-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d66966fd94719beb84e8ed84833bc59c3c005d3d2d0c42f11d7552d3267c6de7"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087c0dc93379e8ba2d59e9f586fab8de8c137d164fccf8afd5523a2137570917"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04c70dc8ca79b0072a16d82f94b9d9dd6598a43dd753ab20039e9f7d2b14f017"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aedba48264fe87e5060c0e9c2b28909f1e60626e46dc2f77e0c8c16939e2e1f7"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01640ab79111dd97515cba9fab7c66cb3b0967b0892cc74756a801ff681a01b6"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b206cca6836a4c6683bcaa523ab467627b5f03902e5e1082dc59cd010e6925f"}, - {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee0299b2dda9afce351a5e8c148ea7a886de213f955aa0288fb874fb44829c36"}, - {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:31a2a29be559e92dcc5c278787b4166da6f0d45675b59a11c4867f5d1455ebf4"}, - {file = "orjson-3.8.14-cp311-none-win_amd64.whl", hash = "sha256:20b7ffc7736000ea205f9143df322b03961f287b4057606291c62c842ff3c5b5"}, - {file = "orjson-3.8.14-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de1ee13d6b6727ee1db38722695250984bae81b8fc9d05f1176c74d14b1322d9"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ee09bfbf1d54c127d3061f6721a1a11d2ce502b50597c3d0d2e1bd2d235b764"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:97ebb7fab5f1ae212a6501f17cb7750a6838ffc2f1cebbaa5dec1a90038ca3c6"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38ca39bae7fbc050332a374062d4cdec28095540fa8bb245eada467897a3a0bb"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:92374bc35b6da344a927d5a850f7db80a91c7b837de2f0ea90fc870314b1ff44"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9393a63cb0424515ec5e434078b3198de6ec9e057f1d33bad268683935f0a5d5"}, - {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5fb66f0ac23e861b817c858515ac1f74d1cd9e72e3f82a5b2c9bae9f92286adc"}, - {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19415aaf30525a5baff0d72a089fcdd68f19a3674998263c885c3908228c1086"}, - {file = "orjson-3.8.14-cp37-none-win_amd64.whl", hash = "sha256:87ba7882e146e24a7d8b4a7971c20212c2af75ead8096fc3d55330babb1015fb"}, - {file = "orjson-3.8.14-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9f5cf61b6db68f213c805c55bf0aab9b4cb75a4e9c7f5bfbd4deb3a0aef0ec53"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33bc310da4ad2ffe8f7f1c9e89692146d9ec5aec2d1c9ef6b67f8dc5e2d63241"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67a7e883b6f782b106683979ccc43d89b98c28a1f4a33fe3a22e253577499bb1"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9df820e6c8c84c52ec39ea2cc9c79f7999c839c7d1481a056908dce3b90ce9f9"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebca14ae80814219ea3327e3dfa7ff618621ff335e45781fac26f5cd0b48f2b4"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27967be4c16bd09f4aeff8896d9be9cbd00fd72f5815d5980e4776f821e2f77c"}, - {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:062829b5e20cd8648bf4c11c3a5ee7cf196fa138e573407b5312c849b0cf354d"}, - {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e53bc5beb612df8ddddb065f079d3fd30b5b4e73053518524423549d61177f3f"}, - {file = "orjson-3.8.14-cp38-none-win_amd64.whl", hash = "sha256:d03f29b0369bb1ab55c8a67103eb3a9675daaf92f04388568034fe16be48fa5d"}, - {file = "orjson-3.8.14-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:716a3994e039203f0a59056efa28185d4cac51b922cc5bf27ab9182cfa20e12e"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb35dd3ba062c1d984d57e6477768ed7b62ed9260f31362b2d69106f9c60ebd"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0bc6b7abf27f1dc192dadad249df9b513912506dd420ce50fd18864a33789b71"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2f75b7d9285e35c3d4dff9811185535ff2ea637f06b2b242cb84385f8ffe63"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:017de5ba22e58dfa6f41914f5edb8cd052d23f171000684c26b2d2ab219db31e"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09a3bf3154f40299b8bc95e9fb8da47436a59a2106fc22cae15f76d649e062da"}, - {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64b4fca0531030040e611c6037aaf05359e296877ab0a8e744c26ef9c32738b9"}, - {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8a896a12b38fe201a72593810abc1f4f1597e65b8c869d5fc83bbcf75d93398f"}, - {file = "orjson-3.8.14-cp39-none-win_amd64.whl", hash = "sha256:9725226478d1dafe46d26f758eadecc6cf98dcbb985445e14a9c74aaed6ccfea"}, - {file = "orjson-3.8.14.tar.gz", hash = "sha256:5ea93fd3ef7be7386f2516d728c877156de1559cda09453fc7dd7b696d0439b3"}, + {file = "orjson-3.9.2-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7323e4ca8322b1ecb87562f1ec2491831c086d9faa9a6c6503f489dadbed37d7"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1272688ea1865f711b01ba479dea2d53e037ea00892fd04196b5875f7021d9d3"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b9a26f1d1427a9101a1e8910f2e2df1f44d3d18ad5480ba031b15d5c1cb282e"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a5ca55b0d8f25f18b471e34abaee4b175924b6cd62f59992945b25963443141"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:877872db2c0f41fbe21f852ff642ca842a43bc34895b70f71c9d575df31fffb4"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a39c2529d75373b7167bf84c814ef9b8f3737a339c225ed6c0df40736df8748"}, + {file = "orjson-3.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:84ebd6fdf138eb0eb4280045442331ee71c0aab5e16397ba6645f32f911bfb37"}, + {file = "orjson-3.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a60a1cfcfe310547a1946506dd4f1ed0a7d5bd5b02c8697d9d5dcd8d2e9245e"}, + {file = "orjson-3.9.2-cp310-none-win_amd64.whl", hash = "sha256:c290c4f81e8fd0c1683638802c11610b2f722b540f8e5e858b6914b495cf90c8"}, + {file = "orjson-3.9.2-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:02ef014f9a605e84b675060785e37ec9c0d2347a04f1307a9d6840ab8ecd6f55"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:992af54265ada1c1579500d6594ed73fe333e726de70d64919cf37f93defdd06"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a40958f7af7c6d992ee67b2da4098dca8b770fc3b4b3834d540477788bfa76d3"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93864dec3e3dd058a2dbe488d11ac0345214a6a12697f53a63e34de7d28d4257"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16fdf5a82df80c544c3c91516ab3882cd1ac4f1f84eefeafa642e05cef5f6699"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275b5a18fd9ed60b2720543d3ddac170051c43d680e47d04ff5203d2c6d8ebf1"}, + {file = "orjson-3.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b9aea6dcb99fcbc9f6d1dd84fca92322fda261da7fb014514bb4689c7c2097a8"}, + {file = "orjson-3.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7d74ae0e101d17c22ef67b741ba356ab896fc0fa64b301c2bf2bb0a4d874b190"}, + {file = "orjson-3.9.2-cp311-none-win_amd64.whl", hash = "sha256:6320b28e7bdb58c3a3a5efffe04b9edad3318d82409e84670a9b24e8035a249d"}, + {file = "orjson-3.9.2-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:368e9cc91ecb7ac21f2aa475e1901204110cf3e714e98649c2502227d248f947"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58e9e70f0dcd6a802c35887f306b555ff7a214840aad7de24901fc8bd9cf5dde"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00c983896c2e01c94c0ef72fd7373b2aa06d0c0eed0342c4884559f812a6835b"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ee743e8890b16c87a2f89733f983370672272b61ee77429c0a5899b2c98c1a7"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7b065942d362aad4818ff599d2f104c35a565c2cbcbab8c09ec49edba91da75"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e46e9c5b404bb9e41d5555762fd410d5466b7eb1ec170ad1b1609cbebe71df21"}, + {file = "orjson-3.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8170157288714678ffd64f5de33039e1164a73fd8b6be40a8a273f80093f5c4f"}, + {file = "orjson-3.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e3e2f087161947dafe8319ea2cfcb9cea4bb9d2172ecc60ac3c9738f72ef2909"}, + {file = "orjson-3.9.2-cp37-none-win_amd64.whl", hash = "sha256:d7de3dbbe74109ae598692113cec327fd30c5a30ebca819b21dfa4052f7b08ef"}, + {file = "orjson-3.9.2-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8cd4385c59bbc1433cad4a80aca65d2d9039646a9c57f8084897549b55913b17"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a74036aab1a80c361039290cdbc51aa7adc7ea13f56e5ef94e9be536abd227bd"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1aaa46d7d4ae55335f635eadc9be0bd9bcf742e6757209fc6dc697e390010adc"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e52c67ed6bb368083aa2078ea3ccbd9721920b93d4b06c43eb4e20c4c860046"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a6cdfcf9c7dd4026b2b01fdff56986251dc0cc1e980c690c79eec3ae07b36e7"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1882a70bb69595b9ec5aac0040a819e94d2833fe54901e2b32f5e734bc259a8b"}, + {file = "orjson-3.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fc05e060d452145ab3c0b5420769e7356050ea311fc03cb9d79c481982917cca"}, + {file = "orjson-3.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f8bc2c40d9bb26efefb10949d261a47ca196772c308babc538dd9f4b73e8d386"}, + {file = "orjson-3.9.2-cp38-none-win_amd64.whl", hash = "sha256:3164fc20a585ec30a9aff33ad5de3b20ce85702b2b2a456852c413e3f0d7ab09"}, + {file = "orjson-3.9.2-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7a6ccadf788531595ed4728aa746bc271955448d2460ff0ef8e21eb3f2a281ba"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3245d230370f571c945f69aab823c279a868dc877352817e22e551de155cb06c"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:205925b179550a4ee39b8418dd4c94ad6b777d165d7d22614771c771d44f57bd"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0325fe2d69512187761f7368c8cda1959bcb75fc56b8e7a884e9569112320e57"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:806704cd58708acc66a064a9a58e3be25cf1c3f9f159e8757bd3f515bfabdfa1"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03fb36f187a0c19ff38f6289418863df8b9b7880cdbe279e920bef3a09d8dab1"}, + {file = "orjson-3.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:20925d07a97c49c6305bff1635318d9fc1804aa4ccacb5fb0deb8a910e57d97a"}, + {file = "orjson-3.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eebfed53bec5674e981ebe8ed2cf00b3f7bcda62d634733ff779c264307ea505"}, + {file = "orjson-3.9.2-cp39-none-win_amd64.whl", hash = "sha256:869b961df5fcedf6c79f4096119b35679b63272362e9b745e668f0391a892d39"}, + {file = "orjson-3.9.2.tar.gz", hash = "sha256:24257c8f641979bf25ecd3e27251b5cc194cdd3a6e96004aac8446f5e63d9664"}, ] [[package]] @@ -1189,6 +1211,7 @@ category = "main" optional = false python-versions = "*" files = [ + {file = "parse-1.19.0-py2.py3-none-any.whl", hash = "sha256:6ce007645384a91150cb7cd7c8a9db2559e273c2e2542b508cd1e342508c2601"}, {file = "parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"}, ] @@ -1269,25 +1292,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.23.2" +version = "4.23.4" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.23.2-cp310-abi3-win32.whl", hash = "sha256:384dd44cb4c43f2ccddd3645389a23ae61aeb8cfa15ca3a0f60e7c3ea09b28b3"}, - {file = "protobuf-4.23.2-cp310-abi3-win_amd64.whl", hash = "sha256:09310bce43353b46d73ba7e3bca78273b9bc50349509b9698e64d288c6372c2a"}, - {file = "protobuf-4.23.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2cfab63a230b39ae603834718db74ac11e52bccaaf19bf20f5cce1a84cf76df"}, - {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:c52cfcbfba8eb791255edd675c1fe6056f723bf832fa67f0442218f8817c076e"}, - {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:86df87016d290143c7ce3be3ad52d055714ebaebb57cc659c387e76cfacd81aa"}, - {file = "protobuf-4.23.2-cp37-cp37m-win32.whl", hash = "sha256:281342ea5eb631c86697e1e048cb7e73b8a4e85f3299a128c116f05f5c668f8f"}, - {file = "protobuf-4.23.2-cp37-cp37m-win_amd64.whl", hash = "sha256:ce744938406de1e64b91410f473736e815f28c3b71201302612a68bf01517fea"}, - {file = "protobuf-4.23.2-cp38-cp38-win32.whl", hash = "sha256:6c081863c379bb1741be8f8193e893511312b1d7329b4a75445d1ea9955be69e"}, - {file = "protobuf-4.23.2-cp38-cp38-win_amd64.whl", hash = "sha256:25e3370eda26469b58b602e29dff069cfaae8eaa0ef4550039cc5ef8dc004511"}, - {file = "protobuf-4.23.2-cp39-cp39-win32.whl", hash = "sha256:efabbbbac1ab519a514579ba9ec52f006c28ae19d97915951f69fa70da2c9e91"}, - {file = "protobuf-4.23.2-cp39-cp39-win_amd64.whl", hash = "sha256:54a533b971288af3b9926e53850c7eb186886c0c84e61daa8444385a4720297f"}, - {file = "protobuf-4.23.2-py3-none-any.whl", hash = "sha256:8da6070310d634c99c0db7df48f10da495cc283fd9e9234877f0cd182d43ab7f"}, - {file = "protobuf-4.23.2.tar.gz", hash = "sha256:20874e7ca4436f683b64ebdbee2129a5a2c301579a67d1a7dda2cdf62fb7f5f7"}, + {file = "protobuf-4.23.4-cp310-abi3-win32.whl", hash = "sha256:5fea3c64d41ea5ecf5697b83e41d09b9589e6f20b677ab3c48e5f242d9b7897b"}, + {file = "protobuf-4.23.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b19b6266d92ca6a2a87effa88ecc4af73ebc5cfde194dc737cf8ef23a9a3b12"}, + {file = "protobuf-4.23.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8547bf44fe8cec3c69e3042f5c4fb3e36eb2a7a013bb0a44c018fc1e427aafbd"}, + {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fee88269a090ada09ca63551bf2f573eb2424035bcf2cb1b121895b01a46594a"}, + {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:effeac51ab79332d44fba74660d40ae79985901ac21bca408f8dc335a81aa597"}, + {file = "protobuf-4.23.4-cp37-cp37m-win32.whl", hash = "sha256:c3e0939433c40796ca4cfc0fac08af50b00eb66a40bbbc5dee711998fb0bbc1e"}, + {file = "protobuf-4.23.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9053df6df8e5a76c84339ee4a9f5a2661ceee4a0dab019e8663c50ba324208b0"}, + {file = "protobuf-4.23.4-cp38-cp38-win32.whl", hash = "sha256:e1c915778d8ced71e26fcf43c0866d7499891bca14c4368448a82edc61fdbc70"}, + {file = "protobuf-4.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:351cc90f7d10839c480aeb9b870a211e322bf05f6ab3f55fcb2f51331f80a7d2"}, + {file = "protobuf-4.23.4-cp39-cp39-win32.whl", hash = "sha256:6dd9b9940e3f17077e820b75851126615ee38643c2c5332aa7a359988820c720"}, + {file = "protobuf-4.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:0a5759f5696895de8cc913f084e27fd4125e8fb0914bb729a17816a33819f474"}, + {file = "protobuf-4.23.4-py3-none-any.whl", hash = "sha256:e9d0be5bf34b275b9f87ba7407796556abeeba635455d036c7351f7c183ef8ff"}, + {file = "protobuf-4.23.4.tar.gz", hash = "sha256:ccd9430c0719dce806b93f89c91de7977304729e55377f872a92465d548329a9"}, ] [[package]] @@ -1368,43 +1391,43 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.12.1" +version = "1.12.2" description = "Python bindings for libgit2." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:50a155528aa611e4a217be31a9d2d8da283cfd978dbba07494cd04ea3d7c8768"}, - {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:248e22ccb1ea31f569373a3da3fa73d110ba2585c6326ff74b03c9579fb7b913"}, - {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e575e672c5a6cb39234b0076423a560e016d6b88cd50947c2df3bf59c5ccdf3d"}, - {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad9b46b52997d131b31ff46f699b074e9745c8fea8d0efb6b72ace43ab25828c"}, - {file = "pygit2-1.12.1-cp310-cp310-win32.whl", hash = "sha256:a8f495df877da04c572ecec4d532ae195680b4781dbf229bab4e801fa9ef20e9"}, - {file = "pygit2-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f1e1355c7fe2938a2bca0d6204a00c02950d13008722879e54a335b3e874006"}, - {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a5c56b0b5dc8a317561070ef7557e180d4937d8b115c5a762d85e0109a216f3"}, - {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7c9ca8bc8a722863fc873234748fef3422007d5a6ea90ba3ae338d2907d3d6e"}, - {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c02a11f10bc4e329ab941f0c70874d39053c8f78544aefeb506f04cedb621a"}, - {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b3af334adf325b7c973417efa220fd5a9ce946b936262eceabc8ad8d46e0310"}, - {file = "pygit2-1.12.1-cp311-cp311-win32.whl", hash = "sha256:86c393962d1341893bbfa91829b3b8545e8ac7622f8b53b9a0b835b9cc1b5198"}, - {file = "pygit2-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:86c7e75ddc76f4e5593b47f9c2074fff242322ed9f4126116749f7c86021520a"}, - {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:939d11677f434024ea25a9137d8a525ef9f9ac474fb8b86399bc9526e6a7bff5"}, - {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:946f9215c0442995042ea512f764f7a6638d3a09f9d0484d3aeedbf8833f89e6"}, - {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd574620d3cc80df0b23bf2b7b08d8726e75a338d0fa1b67e4d6738d3ee56635"}, - {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24d0adeff5c43229913f3bdae71c36e77ed19f36bd8dd6b5c141820964b1f5b3"}, - {file = "pygit2-1.12.1-cp38-cp38-win32.whl", hash = "sha256:ed8e2ef97171e994bf4d46c6c6534a3c12dd2dbbc47741e5995eaf8c2c92f71c"}, - {file = "pygit2-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:5318817055a3ca3906bf88344b9a6dc70c640f9b6bc236ac9e767d12bad54361"}, - {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cb9c803151ffeb0b8de52a93381108a2c6a9a446c55d659a135f52645e1650eb"}, - {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47bf1e196dc23fe38018ad49b021d425edc319328169c597df45d73cf46b62ef"}, - {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:948479df72223bbcd16b2a88904dc2a3886c15a0107a7cf3b5373c8e34f52f31"}, - {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4bebe8b310edc2662cbffb94ef1a758252fe2e4c92bc83fac0eaf2bedf8b871"}, - {file = "pygit2-1.12.1-cp39-cp39-win32.whl", hash = "sha256:77bc0ab778ab6fe631f5f9eb831b426376a7b71426c5a913aaa9088382ef1dc9"}, - {file = "pygit2-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:e87b2306a266f6abca94ab37dda807033a6f40faad05c4d1e089f9e8354130a8"}, - {file = "pygit2-1.12.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5d5e8a3b67f5d4ba8e3838c492254688997747989b184b5f1a3af4fef7f9f53e"}, - {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2500b749759f2efdfa5096c0aafeb2d92152766708f5700284427bd658e5c407"}, - {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c21759ca9cc755faa2d17180cd49af004486ca84f3166cac089a2083dcb09114"}, - {file = "pygit2-1.12.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d73074ab64b383e3a1ab03e8070f6b195ef89b9d379ca5682c38dd9c289cc6e2"}, - {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:865c0d1925c52426455317f29c1db718187ec69ed5474faaf3e1c68ff2135767"}, - {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebebbe9125b068337b5415565ec94c9e092c708e430851b2d02e51217bdce4a"}, - {file = "pygit2-1.12.1.tar.gz", hash = "sha256:8218922abedc88a65d5092308d533ca4c4ed634aec86a3493d3bdf1a25aeeff3"}, + {file = "pygit2-1.12.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:79fbd99d3e08ca7478150eeba28ca4d4103f564148eab8d00aba8f1e6fc60654"}, + {file = "pygit2-1.12.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be3bb0139f464947523022a5af343a2e862c4ff250a57ec9f631449e7c0ba7c0"}, + {file = "pygit2-1.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4df3e5745fdf3111a6ccc905eae99f22f1a180728f714795138ca540cc2a50a"}, + {file = "pygit2-1.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:214bd214784fcbef7a8494d1d59e0cd3a731c0d24ce0f230dcc843322ee33b08"}, + {file = "pygit2-1.12.2-cp310-cp310-win32.whl", hash = "sha256:336c864ac961e7be8ba06e9ed8c999e4f624a8ccd90121cc4e40956d8b57acac"}, + {file = "pygit2-1.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:fb9eb57b75ce586928053692a25aae2a50fef3ad36661c57c07d4902899b1df3"}, + {file = "pygit2-1.12.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f8f813d35d836c5b0d1962c387754786bcc7f1c3c8e11207b9eeb30238ac4cc7"}, + {file = "pygit2-1.12.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25a6548930328c5247bfb7c67d29104e63b036cb5390f032d9f91f63efb70434"}, + {file = "pygit2-1.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a365ffca23d910381749fdbcc367db52fe808f9aa4852914dd9ef8b711384a32"}, + {file = "pygit2-1.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec04c27be5d5af1ceecdcc0464e07081222f91f285f156dc53b23751d146569a"}, + {file = "pygit2-1.12.2-cp311-cp311-win32.whl", hash = "sha256:546091316c9a8c37b9867ddcc6c9f7402ca4d0b9db3f349212a7b5e71988e359"}, + {file = "pygit2-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:8bf14196cbfffbcd286f459a1d4fc660c5d5dfa8fb422e21216961df575410d6"}, + {file = "pygit2-1.12.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7bb30ab1fdaa4c30821fed33892958b6d92d50dbd03c76f7775b4e5d62f53a2e"}, + {file = "pygit2-1.12.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e7e705aaecad85b883022e81e054fbd27d26023fc031618ee61c51516580517e"}, + {file = "pygit2-1.12.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac2b5f408eb882e79645ebb43039ac37739c3edd25d857cc97d7482a684b613f"}, + {file = "pygit2-1.12.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7f3ad2b7b0c80be991bb47d8a2f2535cc9bf090746eb8679231ee565fde81"}, + {file = "pygit2-1.12.2-cp38-cp38-win32.whl", hash = "sha256:5b3ab4d6302990f7adb2b015bcbda1f0715277008d0c66440497e6f8313bf9cb"}, + {file = "pygit2-1.12.2-cp38-cp38-win_amd64.whl", hash = "sha256:c74e7601cb8b8dc3d02fd32274e200a7761cffd20ee531442bf1fa115c8f99a5"}, + {file = "pygit2-1.12.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a4083ba093c69142e0400114a4ef75e87834637d2bbfd77b964614bf70f624f"}, + {file = "pygit2-1.12.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:926f2e48c4eaa179249d417b8382290b86b0f01dbf41d289f763576209276b9f"}, + {file = "pygit2-1.12.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14ae27491347a0ac4bbe8347b09d752cfe7fea1121c14525415e0cca6db4a836"}, + {file = "pygit2-1.12.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f65483ab5e3563c58f60debe2acc0979fdf6fd633432fcfbddf727a9a265ba4"}, + {file = "pygit2-1.12.2-cp39-cp39-win32.whl", hash = "sha256:8da8517809635ea3da950d9cf99c6d1851352d92b6db309382db88a01c3b0bfd"}, + {file = "pygit2-1.12.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9c2359b99eed8e7fac30c06e6b4ae277a6a0537d6b4b88a190828c3d7eb9ef2"}, + {file = "pygit2-1.12.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:685378852ef8eb081333bc80dbdfc4f1333cf4a8f3baf614c4135e02ad1ee38a"}, + {file = "pygit2-1.12.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf655e5f801990f5cad721b6ccbe7610962f0a4f1c20373dbf9c0be39374a81"}, + {file = "pygit2-1.12.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:857c5cde635d470f58803d67bfb281dc4f6336065a0253bfbed001f18e2d0767"}, + {file = "pygit2-1.12.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fe35a72af61961dbb7fb4abcdaa36d5f1c85b2cd3daae94137eeb9c07215cdd3"}, + {file = "pygit2-1.12.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f443d3641762b2bb9c76400bb18beb4ba27dd35bc098a8bfae82e6a190c52ab"}, + {file = "pygit2-1.12.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1e26649e1540b6a774f812e2fc9890320ff4d33f16db1bb02626318b5ceae2"}, + {file = "pygit2-1.12.2.tar.gz", hash = "sha256:56e85d0e66de957d599d1efb2409d39afeefd8f01009bfda0796b42a4b678358"}, ] [package.dependencies] @@ -1412,14 +1435,14 @@ cffi = ">=1.9.1" [[package]] name = "pytest" -version = "7.3.1" +version = "7.4.0" description = "pytest: simple powerful testing with Python" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, - {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, ] [package.dependencies] @@ -1431,7 +1454,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -1540,14 +1563,14 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc [[package]] name = "redis" -version = "4.5.5" +version = "4.6.0" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.5-py3-none-any.whl", hash = "sha256:77929bc7f5dab9adf3acba2d3bb7d7658f1e0c2f1cafe7eb36434e751c471119"}, - {file = "redis-4.5.5.tar.gz", hash = "sha256:dc87a0bdef6c8bfe1ef1e1c40be7034390c2ae02d92dcd0c7ca1729443899880"}, + {file = "redis-4.6.0-py3-none-any.whl", hash = "sha256:e2b03db868160ee4591de3cb90d40ebb50a90dd302138775937f6a42b7ed183c"}, + {file = "redis-4.6.0.tar.gz", hash = "sha256:585dc516b9eb042a619ef0a39c3d7d55fe81bdb4df09a52c9cdde0d07bf1aa7d"}, ] [package.dependencies] @@ -1634,53 +1657,50 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.48" +version = "1.4.49" description = "Database Abstraction Library" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.48-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4bac3aa3c3d8bc7408097e6fe8bf983caa6e9491c5d2e2488cfcfd8106f13b6a"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dbcae0e528d755f4522cad5842f0942e54b578d79f21a692c44d91352ea6d64e"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27m-win32.whl", hash = "sha256:cbbe8b8bffb199b225d2fe3804421b7b43a0d49983f81dc654d0431d2f855543"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27m-win_amd64.whl", hash = "sha256:627e04a5d54bd50628fc8734d5fc6df2a1aa5962f219c44aad50b00a6cdcf965"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9af1db7a287ef86e0f5cd990b38da6bd9328de739d17e8864f1817710da2d217"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:ce7915eecc9c14a93b73f4e1c9d779ca43e955b43ddf1e21df154184f39748e5"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5381ddd09a99638f429f4cbe1b71b025bed318f6a7b23e11d65f3eed5e181c33"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:87609f6d4e81a941a17e61a4c19fee57f795e96f834c4f0a30cee725fc3f81d9"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb0808ad34167f394fea21bd4587fc62f3bd81bba232a1e7fbdfa17e6cfa7cd7"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-win32.whl", hash = "sha256:d53cd8bc582da5c1c8c86b6acc4ef42e20985c57d0ebc906445989df566c5603"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-win_amd64.whl", hash = "sha256:4355e5915844afdc5cf22ec29fba1010166e35dd94a21305f49020022167556b"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:066c2b0413e8cb980e6d46bf9d35ca83be81c20af688fedaef01450b06e4aa5e"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c99bf13e07140601d111a7c6f1fc1519914dd4e5228315bbda255e08412f61a4"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee26276f12614d47cc07bc85490a70f559cba965fb178b1c45d46ffa8d73fda"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-win32.whl", hash = "sha256:49c312bcff4728bffc6fb5e5318b8020ed5c8b958a06800f91859fe9633ca20e"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-win_amd64.whl", hash = "sha256:cef2e2abc06eab187a533ec3e1067a71d7bbec69e582401afdf6d8cad4ba3515"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:3509159e050bd6d24189ec7af373359f07aed690db91909c131e5068176c5a5d"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc2ab4d9f6d9218a5caa4121bdcf1125303482a1cdcfcdbd8567be8518969c0"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1ddbbcef9bcedaa370c03771ebec7e39e3944782bef49e69430383c376a250b"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f82d8efea1ca92b24f51d3aea1a82897ed2409868a0af04247c8c1e4fef5890"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-win32.whl", hash = "sha256:e3e98d4907805b07743b583a99ecc58bf8807ecb6985576d82d5e8ae103b5272"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-win_amd64.whl", hash = "sha256:25887b4f716e085a1c5162f130b852f84e18d2633942c8ca40dfb8519367c14f"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:0817c181271b0ce5df1aa20949f0a9e2426830fed5ecdcc8db449618f12c2730"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1dd2562313dd9fe1778ed56739ad5d9aae10f9f43d9f4cf81d65b0c85168bb"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:68413aead943883b341b2b77acd7a7fe2377c34d82e64d1840860247cec7ff7c"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbde5642104ac6e95f96e8ad6d18d9382aa20672008cf26068fe36f3004491df"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-win32.whl", hash = "sha256:11c6b1de720f816c22d6ad3bbfa2f026f89c7b78a5c4ffafb220e0183956a92a"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-win_amd64.whl", hash = "sha256:eb5464ee8d4bb6549d368b578e9529d3c43265007193597ddca71c1bae6174e6"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:92e6133cf337c42bfee03ca08c62ba0f2d9695618c8abc14a564f47503157be9"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d29a3fc6d9c45962476b470a81983dd8add6ad26fdbfae6d463b509d5adcda"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:005e942b451cad5285015481ae4e557ff4154dde327840ba91b9ac379be3b6ce"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c8cfe951ed074ba5e708ed29c45397a95c4143255b0d022c7c8331a75ae61f3"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-win32.whl", hash = "sha256:2b9af65cc58726129d8414fc1a1a650dcdd594ba12e9c97909f1f57d48e393d3"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-win_amd64.whl", hash = "sha256:2b562e9d1e59be7833edf28b0968f156683d57cabd2137d8121806f38a9d58f4"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a1fc046756cf2a37d7277c93278566ddf8be135c6a58397b4c940abf837011f4"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d9b55252d2ca42a09bcd10a697fa041e696def9dfab0b78c0aaea1485551a08"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6dab89874e72a9ab5462997846d4c760cdb957958be27b03b49cf0de5e5c327c"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd8b5ee5a3acc4371f820934b36f8109ce604ee73cc668c724abb054cebcb6e"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-win32.whl", hash = "sha256:eee09350fd538e29cfe3a496ec6f148504d2da40dbf52adefb0d2f8e4d38ccc4"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-win_amd64.whl", hash = "sha256:7ad2b0f6520ed5038e795cc2852eb5c1f20fa6831d73301ced4aafbe3a10e1f6"}, - {file = "SQLAlchemy-1.4.48.tar.gz", hash = "sha256:b47bc287096d989a0838ce96f7d8e966914a24da877ed41a7531d44b55cdb8df"}, + {file = "SQLAlchemy-1.4.49-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e126cf98b7fd38f1e33c64484406b78e937b1a280e078ef558b95bf5b6895f6"}, + {file = "SQLAlchemy-1.4.49-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:03db81b89fe7ef3857b4a00b63dedd632d6183d4ea5a31c5d8a92e000a41fc71"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:95b9df9afd680b7a3b13b38adf6e3a38995da5e162cc7524ef08e3be4e5ed3e1"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63e43bf3f668c11bb0444ce6e809c1227b8f067ca1068898f3008a273f52b09"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f835c050ebaa4e48b18403bed2c0fda986525896efd76c245bdd4db995e51a4c"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c21b172dfb22e0db303ff6419451f0cac891d2e911bb9fbf8003d717f1bcf91"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-win32.whl", hash = "sha256:5fb1ebdfc8373b5a291485757bd6431de8d7ed42c27439f543c81f6c8febd729"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-win_amd64.whl", hash = "sha256:f8a65990c9c490f4651b5c02abccc9f113a7f56fa482031ac8cb88b70bc8ccaa"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8923dfdf24d5aa8a3adb59723f54118dd4fe62cf59ed0d0d65d940579c1170a4"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9ab2c507a7a439f13ca4499db6d3f50423d1d65dc9b5ed897e70941d9e135b0"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5debe7d49b8acf1f3035317e63d9ec8d5e4d904c6e75a2a9246a119f5f2fdf3d"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-win32.whl", hash = "sha256:82b08e82da3756765c2e75f327b9bf6b0f043c9c3925fb95fb51e1567fa4ee87"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-win_amd64.whl", hash = "sha256:171e04eeb5d1c0d96a544caf982621a1711d078dbc5c96f11d6469169bd003f1"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:36e58f8c4fe43984384e3fbe6341ac99b6b4e083de2fe838f0fdb91cebe9e9cb"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b31e67ff419013f99ad6f8fc73ee19ea31585e1e9fe773744c0f3ce58c039c30"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c14b29d9e1529f99efd550cd04dbb6db6ba5d690abb96d52de2bff4ed518bc95"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c40f3470e084d31247aea228aa1c39bbc0904c2b9ccbf5d3cfa2ea2dac06f26d"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-win32.whl", hash = "sha256:706bfa02157b97c136547c406f263e4c6274a7b061b3eb9742915dd774bbc264"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-win_amd64.whl", hash = "sha256:a7f7b5c07ae5c0cfd24c2db86071fb2a3d947da7bd487e359cc91e67ac1c6d2e"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:4afbbf5ef41ac18e02c8dc1f86c04b22b7a2125f2a030e25bbb4aff31abb224b"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24e300c0c2147484a002b175f4e1361f102e82c345bf263242f0449672a4bccf"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:201de072b818f8ad55c80d18d1a788729cccf9be6d9dc3b9d8613b053cd4836d"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653ed6817c710d0c95558232aba799307d14ae084cc9b1f4c389157ec50df5c"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-win32.whl", hash = "sha256:647e0b309cb4512b1f1b78471fdaf72921b6fa6e750b9f891e09c6e2f0e5326f"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-win_amd64.whl", hash = "sha256:ab73ed1a05ff539afc4a7f8cf371764cdf79768ecb7d2ec691e3ff89abbc541e"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:37ce517c011560d68f1ffb28af65d7e06f873f191eb3a73af5671e9c3fada08a"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1878ce508edea4a879015ab5215546c444233881301e97ca16fe251e89f1c55"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e8e608983e6f85d0852ca61f97e521b62e67969e6e640fe6c6b575d4db68557"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccf956da45290df6e809ea12c54c02ace7f8ff4d765d6d3dfb3655ee876ce58d"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-win32.whl", hash = "sha256:f167c8175ab908ce48bd6550679cc6ea20ae169379e73c7720a28f89e53aa532"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-win_amd64.whl", hash = "sha256:45806315aae81a0c202752558f0df52b42d11dd7ba0097bf71e253b4215f34f4"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b6d0c4b15d65087738a6e22e0ff461b407533ff65a73b818089efc8eb2b3e1de"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a843e34abfd4c797018fd8d00ffffa99fd5184c421f190b6ca99def4087689bd"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c890421651b45a681181301b3497e4d57c0d01dc001e10438a40e9a9c25ee77"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d26f280b8f0a8f497bc10573849ad6dc62e671d2468826e5c748d04ed9e670d5"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-win32.whl", hash = "sha256:ec2268de67f73b43320383947e74700e95c6770d0c68c4e615e9897e46296294"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-win_amd64.whl", hash = "sha256:bbdf16372859b8ed3f4d05f925a984771cd2abd18bd187042f24be4886c2a15f"}, + {file = "SQLAlchemy-1.4.49.tar.gz", hash = "sha256:06ff25cbae30c396c4b7737464f2a7fc37a67b7da409993b182b024cec80aed9"}, ] [package.dependencies] @@ -1890,14 +1910,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.3.4" +version = "2.3.6" description = "The comprehensive WSGI web application library." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.3.4-py3-none-any.whl", hash = "sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f"}, - {file = "Werkzeug-2.3.4.tar.gz", hash = "sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76"}, + {file = "Werkzeug-2.3.6-py3-none-any.whl", hash = "sha256:935539fa1413afbb9195b24880778422ed620c0fc09670945185cce4d91a8890"}, + {file = "Werkzeug-2.3.6.tar.gz", hash = "sha256:98c774df2f91b05550078891dee5f0eb0cb797a522c757a2452b9cee5b202330"}, ] [package.dependencies] From 81d29b4c66b284459a020b92c8db8de0f2c71bfc Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 8 Jul 2023 11:24:29 +0000 Subject: [PATCH 1780/1891] fix(deps): update dependency fastapi to ^0.100.0 --- poetry.lock | 16 +++++++--------- pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/poetry.lock b/poetry.lock index dcdcf819..f3f19d11 100644 --- a/poetry.lock +++ b/poetry.lock @@ -560,25 +560,23 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.95.2" +version = "0.100.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.95.2-py3-none-any.whl", hash = "sha256:d374dbc4ef2ad9b803899bd3360d34c534adc574546e25314ab72c0c4411749f"}, - {file = "fastapi-0.95.2.tar.gz", hash = "sha256:4d9d3e8c71c73f11874bcf5e33626258d143252e329a01002f767306c64fb982"}, + {file = "fastapi-0.100.0-py3-none-any.whl", hash = "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f"}, + {file = "fastapi-0.100.0.tar.gz", hash = "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e"}, ] [package.dependencies] -pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<3.0.0" starlette = ">=0.27.0,<0.28.0" +typing-extensions = ">=4.5.0" [package.extras] -all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "feedgen" @@ -1960,4 +1958,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "caf2a21e3bff699216e53a37697a7a544103fdea9f84a5d54ee94ded3e810973" +content-hash = "bbab458ee508b073ea3693caaa5d8704ff1a800ddecd816bf39a6561729777c0" diff --git a/pyproject.toml b/pyproject.toml index 69f04fab..34c5a135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,7 @@ pytest-xdist = "^3.2.1" filelock = "^3.12.0" posix-ipc = "^1.1.1" pyalpm = "^0.10.6" -fastapi = "^0.95.1" +fastapi = "^0.100.0" srcinfo = "^0.1.2" tomlkit = "^0.11.8" From 1f40f6c5a0a6c22a071e0729d5bdff60018b303c Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 8 Jul 2023 12:38:19 +0100 Subject: [PATCH 1781/1891] housekeep: set current maintainers Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 34c5a135..012658a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,8 @@ authors = [ "Kevin Morris " ] maintainers = [ - "Eli Schwartz " + "Leonidas Spyropoulos ", + "Mario Oenning " ] packages = [ { include = "aurweb" } From 4821fc131286bcea51ca0ea257d90b9ae20b85b0 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 8 Jul 2023 13:23:32 +0200 Subject: [PATCH 1782/1891] fix: show placeholder for deleted user in comments show "" in comment headers in case a user deleted their account. Signed-off-by: moson --- templates/partials/packages/comment.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index faac0753..3573a914 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -1,5 +1,9 @@ {% set header_cls = "comment-header" %} {% set article_cls = "article-content" %} +{% set comment_by = comment.User.Username %} +{% if not comment.User %} + {% set comment_by = "<deleted-account>" %} +{% endif %} {% if comment.Deleter %} {% set header_cls = "%s %s" | format(header_cls, "comment-deleted") %} {% set article_cls = "%s %s" | format(article_cls, "comment-deleted") %} @@ -9,15 +13,15 @@ {% if not (request.user.HideDeletedComments and comment.DelTS) %}

    {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} - {% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %} + {% set view_account_info = 'View account information for %s' | tr | format(comment_by) %} {{ "%s commented on %s" | tr | format( ('%s' | format( - comment.User.Username, + comment_by, view_account_info, - comment.User.Username - )) if request.user.is_authenticated() else - (comment.User.Username), + comment_by + )) if request.user.is_authenticated() and comment.User else + (comment_by), '%s' | format( comment.ID, datetime_display(comment.CommentTS) From 225ce23761938dcfbb02809ac2371697038c037b Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 8 Jul 2023 12:54:43 +0100 Subject: [PATCH 1783/1891] chore(release): prepare for 6.2.6 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 012658a0..ddd4f638 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.5" +version = "v6.2.6" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 5ccfa7c0fdc491df8556550092fac40fb0027284 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 9 Jul 2023 14:52:15 +0200 Subject: [PATCH 1784/1891] fix: same ssh key entered multiple times Users might accidentally past their ssh key multiple times when they try to register or edit their account. Convert our of list of keys to a set, removing any double keys. Signed-off-by: moson --- aurweb/util.py | 4 ++-- test/test_accounts_routes.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index 7050b482..3410e4d8 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -192,9 +192,9 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: return prefix, key -def parse_ssh_keys(string: str) -> list[Tuple[str, str]]: +def parse_ssh_keys(string: str) -> set[Tuple[str, str]]: """Parse a list of SSH public keys.""" - return [parse_ssh_key(e) for e in string.strip().splitlines(True) if e.strip()] + return set([parse_ssh_key(e) for e in string.strip().splitlines(True) if e.strip()]) def shell_exec(cmdline: str, cwd: str) -> Tuple[int, str, str]: diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index d3ddb174..c9d77c1f 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -644,6 +644,18 @@ def test_post_register_with_ssh_pubkey(client: TestClient): assert response.status_code == int(HTTPStatus.OK) + # Let's create another user accidentally pasting their key twice + with db.begin(): + db.query(SSHPubKey).delete() + + pk_double = pk + "\n" + pk + with client as request: + response = post_register( + request, U="doubleKey", E="doubleKey@email.org", PK=pk_double + ) + + assert response.status_code == int(HTTPStatus.OK) + def test_get_account_edit_tu_as_tu(client: TestClient, tu_user: User): """Test edit get route of another TU as a TU.""" @@ -1082,6 +1094,19 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): assert response.status_code == int(HTTPStatus.OK) + # Accidentally enter the same key twice + pk = make_ssh_pubkey() + post_data["PK"] = pk + "\n" + pk + + with client as request: + request.cookies = {"AURSID": sid} + response = request.post( + "/account/test/edit", + data=post_data, + ) + + assert response.status_code == int(HTTPStatus.OK) + def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): request = Request() From c0bbe21d8183ed2d07eadcb5e0fd27526c70b78f Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 9 Jul 2023 16:13:02 +0200 Subject: [PATCH 1785/1891] fix(test): correct test for ssh-key parsing Our set of keys returned by "util.parse_ssh_keys" is unordered so we have to adapt our test to not rely on a specific order for multiple keys. Fixes: 5ccfa7c0fdc4 ("fix: same ssh key entered multiple times") Signed-off-by: moson --- test/test_util.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/test_util.py b/test/test_util.py index 042b9ad9..1c3b51af 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -142,11 +142,8 @@ def assert_multiple_keys(pks): keys = util.parse_ssh_keys(pks) assert len(keys) == 2 pfx1, key1, pfx2, key2 = pks.split() - k1, k2 = keys - assert pfx1 == k1[0] - assert key1 == k1[1] - assert pfx2 == k2[0] - assert key2 == k2[1] + assert (pfx1, key1) in keys + assert (pfx2, key2) in keys def test_hash_query(): From fa1212f2dee216bd02b321e3747c22fc854b31a5 Mon Sep 17 00:00:00 2001 From: moson Date: Mon, 10 Jul 2023 18:02:20 +0200 Subject: [PATCH 1786/1891] fix: translations not containing string formatting In some translations we might be missing replacement placeholders (%). This turns out to be problematic when calling the format function. Wrap the jinja2 format function and just return the string unformatted when % is missing. Fixes: #341 Signed-off-by: moson --- aurweb/filters.py | 15 +++++++++++++++ test/test_filters.py | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/aurweb/filters.py b/aurweb/filters.py index 893f21af..38322cdf 100644 --- a/aurweb/filters.py +++ b/aurweb/filters.py @@ -8,6 +8,7 @@ from zoneinfo import ZoneInfo import fastapi import paginate from jinja2 import pass_context +from jinja2.filters import do_format import aurweb.models from aurweb import config, l10n @@ -164,3 +165,17 @@ def date_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: @pass_context def datetime_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: return date_strftime(context, dt, "%Y-%m-%d %H:%M (%Z)") + + +@register_filter("format") +def safe_format(value: str, *args: Any, **kwargs: Any) -> str: + """Wrapper for jinja2 format function to perform additional checks.""" + + # If we don't have anything to be formatted, just return the value. + # We have some translations that do not contain placeholders for replacement. + # In these cases the jinja2 function is throwing an error: + # "TypeError: not all arguments converted during string formatting" + if "%" not in value: + return value + + return do_format(value, *args, **kwargs) diff --git a/test/test_filters.py b/test/test_filters.py index e74ddb87..b56b80ab 100644 --- a/test/test_filters.py +++ b/test/test_filters.py @@ -1,6 +1,8 @@ from datetime import datetime from zoneinfo import ZoneInfo +import pytest + from aurweb import filters, time @@ -34,3 +36,18 @@ def test_to_qs(): query = {"a": "b", "c": [1, 2, 3]} qs = filters.to_qs(query) assert qs == "a=b&c=1&c=2&c=3" + + +@pytest.mark.parametrize( + "value, args, expected", + [ + ("", (), ""), + ("a", (), "a"), + ("a", (1,), "a"), + ("%s", ("a",), "a"), + ("%s", ("ab",), "ab"), + ("%s%d", ("a", 1), "a1"), + ], +) +def test_safe_format(value: str, args: tuple, expected: str): + assert filters.safe_format(value, *args) == expected From 27819b4465cd6cde7ef86caca812b1dd6f285880 Mon Sep 17 00:00:00 2001 From: moson Date: Thu, 13 Jul 2023 18:27:02 +0200 Subject: [PATCH 1787/1891] fix: /rss lazy load issue & perf improvements Some fixes for the /rss endpoints * Load all data in one go: Previously data was lazy loaded thus it made several sub-queries per package (> 200 queries for composing the rss data for a single request). Now we are performing a single SQL query. (request time improvement: 550ms -> 130ms) This also fixes aurweb-errors#510 and alike * Remove some "dead code": The fields "source, author, link" were never included in the rss output (wrong or insufficient data passed to the different entry.xyz functions) Nobody seems to be missing them anyways, so let's remove em. * Remove "Last-Modified" header: Obsolete since nginx can/will only handle "If-Modified-Since" requests in it's current configuration. All requests are passed to fastapi anyways. Signed-off-by: moson --- aurweb/routers/rss.py | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/aurweb/routers/rss.py b/aurweb/routers/rss.py index ee85b738..727d2b6a 100644 --- a/aurweb/routers/rss.py +++ b/aurweb/routers/rss.py @@ -1,5 +1,3 @@ -from datetime import datetime - from fastapi import APIRouter, Request from fastapi.responses import Response from feedgen.feed import FeedGenerator @@ -10,12 +8,11 @@ from aurweb.models import Package, PackageBase router = APIRouter() -def make_rss_feed(request: Request, packages: list, date_attr: str): +def make_rss_feed(request: Request, packages: list): """Create an RSS Feed string for some packages. :param request: A FastAPI request :param packages: A list of packages to add to the RSS feed - :param date_attr: The date attribute (DB column) to use :return: RSS Feed string """ @@ -36,18 +33,11 @@ def make_rss_feed(request: Request, packages: list, date_attr: str): entry = feed.add_entry(order="append") entry.title(pkg.Name) entry.link(href=f"{base}/packages/{pkg.Name}", rel="alternate") - entry.link(href=f"{base}/rss", rel="self", type="application/rss+xml") entry.description(pkg.Description or str()) - - attr = getattr(pkg.PackageBase, date_attr) - dt = filters.timestamp_to_datetime(attr) + dt = filters.timestamp_to_datetime(pkg.Timestamp) dt = filters.as_timezone(dt, request.user.Timezone) entry.pubDate(dt.strftime("%Y-%m-%d %H:%M:%S%z")) - - entry.source(f"{base}") - if pkg.PackageBase.Maintainer: - entry.author(author={"name": pkg.PackageBase.Maintainer.Username}) - entry.guid(f"{pkg.Name} - {attr}") + entry.guid(f"{pkg.Name}-{pkg.Timestamp}") return feed.rss_str() @@ -59,15 +49,15 @@ async def rss(request: Request): .join(PackageBase) .order_by(PackageBase.SubmittedTS.desc()) .limit(100) + .with_entities( + Package.Name, + Package.Description, + PackageBase.SubmittedTS.label("Timestamp"), + ) ) - feed = make_rss_feed(request, packages, "SubmittedTS") + feed = make_rss_feed(request, packages) response = Response(feed, media_type="application/rss+xml") - package = packages.first() - if package: - dt = datetime.utcfromtimestamp(package.PackageBase.SubmittedTS) - modified = dt.strftime("%a, %d %m %Y %H:%M:%S GMT") - response.headers["Last-Modified"] = modified return response @@ -79,14 +69,14 @@ async def rss_modified(request: Request): .join(PackageBase) .order_by(PackageBase.ModifiedTS.desc()) .limit(100) + .with_entities( + Package.Name, + Package.Description, + PackageBase.ModifiedTS.label("Timestamp"), + ) ) - feed = make_rss_feed(request, packages, "ModifiedTS") + feed = make_rss_feed(request, packages) response = Response(feed, media_type="application/rss+xml") - package = packages.first() - if package: - dt = datetime.utcfromtimestamp(package.PackageBase.ModifiedTS) - modified = dt.strftime("%a, %d %m %Y %H:%M:%S GMT") - response.headers["Last-Modified"] = modified return response From 862221f5ce244323208f9034b5c14bb0852d2cf8 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 15 Jul 2023 20:27:12 +0000 Subject: [PATCH 1788/1891] fix(deps): update all non-major dependencies --- poetry.lock | 52 ++++++++++++++++++++------------------------------ pyproject.toml | 2 +- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/poetry.lock b/poetry.lock index f3f19d11..368371db 100644 --- a/poetry.lock +++ b/poetry.lock @@ -792,27 +792,27 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "hypercorn" -version = "0.14.3" +version = "0.14.4" description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Hypercorn-0.14.3-py3-none-any.whl", hash = "sha256:7c491d5184f28ee960dcdc14ab45d14633ca79d72ddd13cf4fcb4cb854d679ab"}, - {file = "Hypercorn-0.14.3.tar.gz", hash = "sha256:4a87a0b7bbe9dc75fab06dbe4b301b9b90416e9866c23a377df21a969d6ab8dd"}, + {file = "hypercorn-0.14.4-py3-none-any.whl", hash = "sha256:f956200dbf8677684e6e976219ffa6691d6cf795281184b41dbb0b135ab37b8d"}, + {file = "hypercorn-0.14.4.tar.gz", hash = "sha256:3fa504efc46a271640023c9b88c3184fd64993f47a282e8ae1a13ccb285c2f67"}, ] [package.dependencies] h11 = "*" h2 = ">=3.1.0" priority = "*" -toml = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} wsproto = ">=0.14.0" [package.extras] docs = ["pydata_sphinx_theme"] h3 = ["aioquic (>=0.9.0,<1.0)"] -trio = ["trio (>=0.11.0)"] +trio = ["exceptiongroup (>=1.1.0)", "trio (>=0.22.0)"] uvloop = ["uvloop"] [[package]] @@ -912,6 +912,8 @@ files = [ {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, + {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, @@ -1274,14 +1276,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "6.0.0" +version = "6.1.0" description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus_fastapi_instrumentator-6.0.0-py3-none-any.whl", hash = "sha256:6f66a951a4801667f7311d161f3aebfe0cd202391d0f067fbbe169792e2d987b"}, - {file = "prometheus_fastapi_instrumentator-6.0.0.tar.gz", hash = "sha256:f1ddd0b8ead75e71d055bdf4cb7e995ec6a6ca63543245e7bbc5ca9b14c45191"}, + {file = "prometheus_fastapi_instrumentator-6.1.0-py3-none-any.whl", hash = "sha256:2279ac1cf5b9566a4c3a07f78c9c5ee19648ed90976ab87d73d672abc1bfa017"}, + {file = "prometheus_fastapi_instrumentator-6.1.0.tar.gz", hash = "sha256:1820d7a90389ce100f7d1285495ead388818ae0882e761c1f3e6e62a410bdf13"}, ] [package.dependencies] @@ -1456,14 +1458,14 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.21.0" +version = "0.21.1" description = "Pytest support for asyncio" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, - {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, ] [package.dependencies] @@ -1494,14 +1496,14 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-tap" -version = "3.3" +version = "3.4" description = "Test Anything Protocol (TAP) reporting plugin for pytest" category = "dev" optional = false python-versions = "*" files = [ - {file = "pytest-tap-3.3.tar.gz", hash = "sha256:5f0919a147cf0396b2f10d64d365a0bf8062e06543e93c675c9d37f5605e983c"}, - {file = "pytest_tap-3.3-py3-none-any.whl", hash = "sha256:4fbbc0e090c2e94f6199bee4e4f68ab3c5e176b37a72a589ad84e0f72a2fce55"}, + {file = "pytest-tap-3.4.tar.gz", hash = "sha256:a7c2a4a3e8b4bf18522e46d74208f8579a191dd972c59182104ad9a4967318fb"}, + {file = "pytest_tap-3.4-py3-none-any.whl", hash = "sha256:d97a2115c94415086f6faec395d243b3c18ea846ce1c1653a4b2588082be35d8"}, ] [package.dependencies] @@ -1774,18 +1776,6 @@ files = [ [package.extras] yaml = ["PyYAML (>=5.1)", "more-itertools"] -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "main" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] - [[package]] name = "tomli" version = "2.0.1" @@ -1842,14 +1832,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.22.0" +version = "0.23.0" description = "The lightning-fast ASGI server." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "uvicorn-0.22.0-py3-none-any.whl", hash = "sha256:e9434d3bbf05f310e762147f769c9f21235ee118ba2d2bf1155a7196448bd996"}, - {file = "uvicorn-0.22.0.tar.gz", hash = "sha256:79277ae03db57ce7d9aa0567830bbb51d7a612f54d6e1e3e92da3ef24c2c8ed8"}, + {file = "uvicorn-0.23.0-py3-none-any.whl", hash = "sha256:479599b2c0bb1b9b394c6d43901a1eb0c1ec72c7d237b5bafea23c5b2d4cdf10"}, + {file = "uvicorn-0.23.0.tar.gz", hash = "sha256:d38ab90c0e2c6fe3a054cddeb962cfd5d0e0e6608eaaff4a01d5c36a67f3168c"}, ] [package.dependencies] @@ -1958,4 +1948,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "bbab458ee508b073ea3693caaa5d8704ff1a800ddecd816bf39a6561729777c0" +content-hash = "b67f1b1599794a6890b0a31b2b127880d75c84beeeae3df4ecb3ae92296948da" diff --git a/pyproject.toml b/pyproject.toml index ddd4f638..e98e887f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ Werkzeug = "^2.3.3" SQLAlchemy = "^1.4.48" # ASGI -uvicorn = "^0.22.0" +uvicorn = "^0.23.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.3" prometheus-fastapi-instrumentator = "^6.0.0" From 5729d6787f43574e70f6b87543065838d475f880 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 16 Jul 2023 13:27:02 +0200 Subject: [PATCH 1789/1891] fix: git links in comments for multiple OIDs The chance of finding multiple object IDs when performing lookups with a shortened SHA1 hash (7 digits) seems to be quite high. In those cases pygit2 will throw an error. Let's catch those exceptions and gracefully handle them. Fixes: aurweb-errors#496 (and alike) Signed-off-by: moson --- aurweb/scripts/rendercomment.py | 9 ++++++-- test/test_rendercomment.py | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index e640c1d4..31f3fdd4 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -72,8 +72,13 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): def handleMatch(self, m, data): oid = m.group(1) - if oid not in self._repo: - # Unknown OID; preserve the orginal text. + # Lookup might raise ValueError in case multiple object ID's were found + try: + if oid not in self._repo: + # Unknown OID; preserve the orginal text. + return None, None, None + except ValueError: + # Multiple OID's found; preserve the orginal text. return None, None, None el = Element("a") diff --git a/test/test_rendercomment.py b/test/test_rendercomment.py index 59eb7191..f9edb45b 100644 --- a/test/test_rendercomment.py +++ b/test/test_rendercomment.py @@ -1,5 +1,7 @@ +import os from unittest import mock +import pygit2 import pytest from aurweb import aur_logging, config, db, time @@ -166,6 +168,43 @@ http://example.com/{commit_hash}\ assert comment.RenderedComment == expected +def test_git_commit_link_multiple_oids( + git: GitRepository, user: User, package: Package +): + # Make sure we get reproducible hashes by hardcoding the dates + date = "Sun, 16 Jul 2023 06:06:06 +0200" + os.environ["GIT_COMMITTER_DATE"] = date + os.environ["GIT_AUTHOR_DATE"] = date + + # Package names that cause two object IDs starting with "09a3468" + pkgnames = [ + "bfa3e330-23c5-11ee-9b6c-9c2dcdf2810d", + "54c6a420-23c6-11ee-9b6c-9c2dcdf2810d", + ] + + # Create our commits + for pkgname in pkgnames: + with db.begin(): + package = db.create( + Package, PackageBase=package.PackageBase, Name=pkgname, Version="1.0" + ) + git.commit(package, pkgname) + + repo_path = config.get("serve", "repo-path") + repo = pygit2.Repository(repo_path) + + # Make sure we get an error when we search the git repo for "09a3468" + with pytest.raises(ValueError) as oid_error: + assert "09a3468" in repo + assert "ambiguous OID prefix" in oid_error + + # Create a comment, referencing "09a3468" + comment = create_comment(user, package.PackageBase, "Commit 09a3468 is nasty!") + + # Make sure our comment does not contain a link. + assert comment.RenderedComment == "

    Commit 09a3468 is nasty!

    " + + def test_flyspray_issue_link(user: User, pkgbase: PackageBase): text = """\ FS#1234567. From bc03d8b8f20ac0a1e6a2b03069632c8a064332f0 Mon Sep 17 00:00:00 2001 From: moson Date: Thu, 20 Jul 2023 18:21:05 +0200 Subject: [PATCH 1790/1891] fix: Fix middleware checking for accepted terms The current query is a bit mixed up. The intention was to return the number of unaccepted records. Now it does also count all records that were accepted by some other user though. Let's check the total number of terms vs. the number of accepted records (by our user) instead. Signed-off-by: moson --- aurweb/asgi.py | 19 ++++++++----------- test/test_accounts_routes.py | 6 ++++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index eb02413b..1be77ff9 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -14,7 +14,7 @@ from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from jinja2 import TemplateNotFound from prometheus_client import multiprocess -from sqlalchemy import and_, or_ +from sqlalchemy import and_ from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.middleware.authentication import AuthenticationMiddleware from starlette.middleware.sessions import SessionMiddleware @@ -277,21 +277,18 @@ async def check_terms_of_service(request: Request, call_next: typing.Callable): """This middleware function redirects authenticated users if they have any outstanding Terms to agree to.""" if request.user.is_authenticated() and request.url.path != "/tos": - unaccepted = ( + accepted = ( query(Term) .join(AcceptedTerm) .filter( - or_( - AcceptedTerm.UsersID != request.user.ID, - and_( - AcceptedTerm.UsersID == request.user.ID, - AcceptedTerm.TermsID == Term.ID, - AcceptedTerm.Revision < Term.Revision, - ), - ) + and_( + AcceptedTerm.UsersID == request.user.ID, + AcceptedTerm.TermsID == Term.ID, + AcceptedTerm.Revision >= Term.Revision, + ), ) ) - if query(Term).count() > unaccepted.count(): + if query(Term).count() - accepted.count() > 0: return RedirectResponse("/tos", status_code=int(http.HTTPStatus.SEE_OTHER)) return await util.error_or_result(call_next, request) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index c9d77c1f..3c481d0a 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -1915,6 +1915,12 @@ def test_get_terms_of_service(client: TestClient, user: User): # We accepted the term, there's nothing left to accept. assert response.status_code == int(HTTPStatus.SEE_OTHER) + # Make sure we don't get redirected to /tos when browsing "Home" + with client as request: + request.cookies = cookies + response = request.get("/") + assert response.status_code == int(HTTPStatus.OK) + # Bump the term's revision. with db.begin(): term.Revision = 2 From 347c2ce721b5782ff0324eb80fdc5613b4ebe478 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 22 Jul 2023 10:43:19 +0200 Subject: [PATCH 1791/1891] change: Change order of commit validation routine We currently validate all commits going from latest -> oldest. It would be nicer to go oldest -> latest so that, in case of errors, we would indicate which commit "introduced" the problem. Signed-off-by: moson --- aurweb/git/update.py | 2 +- test/t1300-git-update.t | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index cd7813e0..4c4fff0f 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -356,7 +356,7 @@ def main(): # noqa: C901 die("denying non-fast-forward (you should pull first)") # Prepare the walker that validates new commits. - walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) + walker = repo.walk(sha1_new, pygit2.GIT_SORT_REVERSE) if sha1_old != "0" * 40: walker.hide(sha1_old) diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index 4fdb487b..0fb2da17 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -312,11 +312,16 @@ test_expect_success 'Pushing a tree with a large blob.' ' printf "%256001s" x >aur.git/file && git -C aur.git add file && git -C aur.git commit -q -m "Add large blob" && + first_error=$(git -C aur.git rev-parse HEAD) && + touch aur.git/another.file && + git -C aur.git add another.file && + git -C aur.git commit -q -m "Add another commit" && new=$(git -C aur.git rev-parse HEAD) && test_must_fail \ env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && - grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual + grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual && + grep -q "^error: $first_error:$" actual ' test_expect_success 'Pushing .SRCINFO with a non-matching package base.' ' From 44c158b8c2667ace8e44d2cac3b7aed4efcc1464 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 22 Jul 2023 16:31:50 +0200 Subject: [PATCH 1792/1891] feat: Implement statistics class & additional metrics The new module/class helps us constructing queries and count records to expose various statistics on the homepage. We also utilize for some new prometheus metrics (package and user gauges). Record counts are being cached with Redis. Signed-off-by: moson --- aurweb/cache.py | 11 ++-- aurweb/prometheus.py | 18 ++++++- aurweb/routers/html.py | 72 ++++---------------------- aurweb/routers/packages.py | 6 +-- aurweb/statistics.py | 102 +++++++++++++++++++++++++++++++++++++ test/test_cache.py | 18 +++---- test/test_metrics.py | 5 +- 7 files changed, 143 insertions(+), 89 deletions(-) create mode 100644 aurweb/statistics.py diff --git a/aurweb/cache.py b/aurweb/cache.py index fe1e5f1d..bb374e57 100644 --- a/aurweb/cache.py +++ b/aurweb/cache.py @@ -1,20 +1,15 @@ import pickle -from prometheus_client import Counter from sqlalchemy import orm from aurweb import config from aurweb.aur_redis import redis_connection +from aurweb.prometheus import SEARCH_REQUESTS _redis = redis_connection() -# Prometheus metrics -SEARCH_REQUESTS = Counter( - "search_requests", "Number of search requests by cache hit/miss", ["cache"] -) - -async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: +def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: """Store and retrieve a query.count() via redis cache. :param key: Redis key @@ -30,7 +25,7 @@ async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: return int(result) -async def db_query_cache(key: str, query: orm.Query, expire: int = None) -> list: +def db_query_cache(key: str, query: orm.Query, expire: int = None) -> list: """Store and retrieve query results via redis cache. :param key: Redis key diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index b8b7984f..d3455551 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -1,6 +1,6 @@ from typing import Any, Callable, Optional -from prometheus_client import Counter +from prometheus_client import Counter, Gauge from prometheus_fastapi_instrumentator import Instrumentator from prometheus_fastapi_instrumentator.metrics import Info from starlette.routing import Match, Route @@ -11,10 +11,26 @@ logger = aur_logging.get_logger(__name__) _instrumentator = Instrumentator() +# Custom metrics +SEARCH_REQUESTS = Counter( + "aur_search_requests", "Number of search requests by cache hit/miss", ["cache"] +) +USERS = Gauge( + "aur_users", "Number of AUR users by type", ["type"], multiprocess_mode="livemax" +) +PACKAGES = Gauge( + "aur_packages", + "Number of AUR packages by state", + ["state"], + multiprocess_mode="livemax", +) + + def instrumentator(): return _instrumentator +# FastAPI metrics # Taken from https://github.com/stephenhillier/starlette_exporter # Their license is included in LICENSES/starlette_exporter. # The code has been modified to remove child route checks diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index fc9f3519..c3bcee49 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -17,11 +17,10 @@ from sqlalchemy import case, or_ import aurweb.config import aurweb.models.package_request from aurweb import aur_logging, cookies, db, models, time, util -from aurweb.cache import db_count_cache from aurweb.exceptions import handle_form_exceptions -from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID from aurweb.models.package_request import PENDING_ID from aurweb.packages.util import query_notified, query_voted, updated_packages +from aurweb.statistics import Statistics, update_prometheus_metrics from aurweb.templates import make_context, render_template logger = aur_logging.get_logger(__name__) @@ -87,68 +86,12 @@ async def index(request: Request): context = make_context(request, "Home") context["ssh_fingerprints"] = util.get_ssh_fingerprints() - bases = db.query(models.PackageBase) - cache_expire = aurweb.config.getint("cache", "expiry_time") + # Package statistics. - context["package_count"] = await db_count_cache( - "package_count", bases, expire=cache_expire - ) - - query = bases.filter(models.PackageBase.MaintainerUID.is_(None)) - context["orphan_count"] = await db_count_cache( - "orphan_count", query, expire=cache_expire - ) - - query = db.query(models.User) - context["user_count"] = await db_count_cache( - "user_count", query, expire=cache_expire - ) - - query = query.filter( - or_( - models.User.AccountTypeID == TRUSTED_USER_ID, - models.User.AccountTypeID == TRUSTED_USER_AND_DEV_ID, - ) - ) - context["trusted_user_count"] = await db_count_cache( - "trusted_user_count", query, expire=cache_expire - ) - - # Current timestamp. - now = time.utcnow() - - seven_days = 86400 * 7 # Seven days worth of seconds. - seven_days_ago = now - seven_days - - one_hour = 3600 - updated = bases.filter( - models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS >= one_hour - ) - - query = bases.filter(models.PackageBase.SubmittedTS >= seven_days_ago) - context["seven_days_old_added"] = await db_count_cache( - "seven_days_old_added", query, expire=cache_expire - ) - - query = updated.filter(models.PackageBase.ModifiedTS >= seven_days_ago) - context["seven_days_old_updated"] = await db_count_cache( - "seven_days_old_updated", query, expire=cache_expire - ) - - year = seven_days * 52 # Fifty two weeks worth: one year. - year_ago = now - year - query = updated.filter(models.PackageBase.ModifiedTS >= year_ago) - context["year_old_updated"] = await db_count_cache( - "year_old_updated", query, expire=cache_expire - ) - - query = bases.filter( - models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600 - ) - context["never_updated"] = await db_count_cache( - "never_updated", query, expire=cache_expire - ) + stats = Statistics(cache_expire) + for counter in stats.HOMEPAGE_COUNTERS: + context[counter] = stats.get_count(counter) # Get the 15 most recently updated packages. context["package_updates"] = updated_packages(15, cache_expire) @@ -193,7 +136,7 @@ async def index(request: Request): ) archive_time = aurweb.config.getint("options", "request_archive_time") - start = now - archive_time + start = time.utcnow() - archive_time # Package requests created by request.user. context["package_requests"] = ( @@ -269,6 +212,9 @@ async def metrics(request: Request): status_code=HTTPStatus.SERVICE_UNAVAILABLE, ) + # update prometheus gauges for packages and users + update_prometheus_metrics() + registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) data = generate_latest(registry) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 779efb4b..f1b2a138 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -91,9 +91,7 @@ async def packages_get( # increase the amount of time required to collect a count. # we use redis for caching the results of the query cache_expire = config.getint("cache", "expiry_time") - num_packages = await db_count_cache( - hash_query(search.query), search.query, cache_expire - ) + num_packages = db_count_cache(hash_query(search.query), search.query, cache_expire) # Apply user-specified sort column and ordering. search.sort_by(sort_by, sort_order) @@ -118,7 +116,7 @@ async def packages_get( results = results.limit(per_page).offset(offset) # we use redis for caching the results of the query - packages = await db_query_cache(hash_query(results), results, cache_expire) + packages = db_query_cache(hash_query(results), results, cache_expire) context["packages"] = packages context["packages_count"] = num_packages diff --git a/aurweb/statistics.py b/aurweb/statistics.py new file mode 100644 index 00000000..934caa37 --- /dev/null +++ b/aurweb/statistics.py @@ -0,0 +1,102 @@ +from aurweb import config, db, time +from aurweb.cache import db_count_cache +from aurweb.models import PackageBase, User +from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.prometheus import PACKAGES, USERS + + +class Statistics: + HOMEPAGE_COUNTERS = [ + "package_count", + "orphan_count", + "seven_days_old_added", + "seven_days_old_updated", + "year_old_updated", + "never_updated", + "user_count", + "trusted_user_count", + ] + PROMETHEUS_USER_COUNTERS = [ + ("trusted_user_count", "tu"), + ("regular_user_count", "user"), + ] + PROMETHEUS_PACKAGE_COUNTERS = [ + ("orphan_count", "orphan"), + ("never_updated", "not_updated"), + ("updated_packages", "updated"), + ] + + seven_days = 86400 * 7 + one_hour = 3600 + year = seven_days * 52 + + def __init__(self, cache_expire: int = None) -> "Statistics": + self.expiry_time = cache_expire + self.now = time.utcnow() + self.seven_days_ago = self.now - self.seven_days + self.year_ago = self.now - self.year + self.user_query = db.query(User) + self.bases_query = db.query(PackageBase) + self.updated_query = db.query(PackageBase).filter( + PackageBase.ModifiedTS - PackageBase.SubmittedTS >= self.one_hour + ) + + def get_count(self, counter: str) -> int: + query = None + match counter: + case "package_count": + query = self.bases_query + case "orphan_count": + query = self.bases_query.filter(PackageBase.MaintainerUID.is_(None)) + case "seven_days_old_added": + query = self.bases_query.filter( + PackageBase.SubmittedTS >= self.seven_days_ago + ) + case "seven_days_old_updated": + query = self.updated_query.filter( + PackageBase.ModifiedTS >= self.seven_days_ago + ) + case "year_old_updated": + query = self.updated_query.filter( + PackageBase.ModifiedTS >= self.year_ago + ) + case "never_updated": + query = self.bases_query.filter( + PackageBase.ModifiedTS - PackageBase.SubmittedTS < self.one_hour + ) + case "updated_packages": + query = self.bases_query.filter( + PackageBase.ModifiedTS - PackageBase.SubmittedTS > self.one_hour, + ~PackageBase.MaintainerUID.is_(None), + ) + case "user_count": + query = self.user_query + case "trusted_user_count": + query = self.user_query.filter( + User.AccountTypeID.in_( + ( + TRUSTED_USER_ID, + TRUSTED_USER_AND_DEV_ID, + ) + ) + ) + case "regular_user_count": + query = self.user_query.filter(User.AccountTypeID == USER_ID) + case _: + return -1 + + return db_count_cache(counter, query, expire=self.expiry_time) + + +def update_prometheus_metrics(): + cache_expire = config.getint("cache", "expiry_time") + stats = Statistics(cache_expire) + # Users gauge + for counter, utype in stats.PROMETHEUS_USER_COUNTERS: + count = stats.get_count(counter) + USERS.labels(utype).set(count) + + # Packages gauge + for counter, state in stats.PROMETHEUS_PACKAGE_COUNTERS: + count = stats.get_count(counter) + PACKAGES.labels(state).set(count) diff --git a/test/test_cache.py b/test/test_cache.py index e19fa6a2..a599ab32 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -31,15 +31,14 @@ def clear_fakeredis_cache(): cache._redis.flushall() -@pytest.mark.asyncio -async def test_db_count_cache(user): +def test_db_count_cache(user): query = db.query(User) # We have no cached value yet. assert cache._redis.get("key1") is None # Add to cache - assert await cache.db_count_cache("key1", query) == query.count() + assert cache.db_count_cache("key1", query) == query.count() # It's cached now. assert cache._redis.get("key1") is not None @@ -48,35 +47,34 @@ async def test_db_count_cache(user): assert cache._redis.ttl("key1") == -1 # Cache a query with an expire. - value = await cache.db_count_cache("key2", query, 100) + value = cache.db_count_cache("key2", query, 100) assert value == query.count() assert cache._redis.ttl("key2") == 100 -@pytest.mark.asyncio -async def test_db_query_cache(user): +def test_db_query_cache(user): query = db.query(User) # We have no cached value yet. assert cache._redis.get("key1") is None # Add to cache - await cache.db_query_cache("key1", query) + cache.db_query_cache("key1", query) # It's cached now. assert cache._redis.get("key1") is not None # Modify our user and make sure we got a cached value user.Username = "changed" - cached = await cache.db_query_cache("key1", query) + cached = cache.db_query_cache("key1", query) assert cached[0].Username != query.all()[0].Username # It does not expire assert cache._redis.ttl("key1") == -1 # Cache a query with an expire. - value = await cache.db_query_cache("key2", query, 100) + value = cache.db_query_cache("key2", query, 100) assert len(value) == query.count() assert value[0].Username == query.all()[0].Username @@ -90,7 +88,7 @@ async def test_db_query_cache(user): with mock.patch("aurweb.config.getint", side_effect=mock_max_search_entries): # Try to add another entry (we already have 2) - await cache.db_query_cache("key3", query) + cache.db_query_cache("key3", query) # Make sure it was not added because it exceeds our max. assert cache._redis.get("key3") is None diff --git a/test/test_metrics.py b/test/test_metrics.py index 1859d8cb..6f67d926 100644 --- a/test/test_metrics.py +++ b/test/test_metrics.py @@ -26,11 +26,10 @@ def user() -> User: yield user -@pytest.mark.asyncio -async def test_search_cache_metrics(user: User): +def test_search_cache_metrics(user: User): # Fire off 3 identical queries for caching for _ in range(3): - await db_query_cache("key", db.query(User)) + db_query_cache("key", db.query(User)) # Get metrics metrics = str(generate_latest(REGISTRY)) From 8699457917a05caae41a7cd2b7ecb6d94a7955b7 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 22 Jul 2023 21:23:16 +0200 Subject: [PATCH 1793/1891] feat: Separate cache expiry for stats and search Allows us to set different cache eviction timespans for search queries and statistics. Stats and especially "last package updates" should probably be refreshed more often, whereas we might want to cache search results for a bit longer. So this gives us a bit more flexibility playing around with different settings and tweak things. Signed-off-by: moson --- aurweb/routers/html.py | 2 +- aurweb/routers/packages.py | 2 +- aurweb/statistics.py | 2 +- conf/config.defaults | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index c3bcee49..2ec497bd 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -86,7 +86,7 @@ async def index(request: Request): context = make_context(request, "Home") context["ssh_fingerprints"] = util.get_ssh_fingerprints() - cache_expire = aurweb.config.getint("cache", "expiry_time") + cache_expire = aurweb.config.getint("cache", "expiry_time_statistics", 300) # Package statistics. stats = Statistics(cache_expire) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index f1b2a138..3f96d71c 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -90,7 +90,7 @@ async def packages_get( # Including more query operations below, like ordering, will # increase the amount of time required to collect a count. # we use redis for caching the results of the query - cache_expire = config.getint("cache", "expiry_time") + cache_expire = config.getint("cache", "expiry_time_search", 600) num_packages = db_count_cache(hash_query(search.query), search.query, cache_expire) # Apply user-specified sort column and ordering. diff --git a/aurweb/statistics.py b/aurweb/statistics.py index 934caa37..6e9dbe1f 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -89,7 +89,7 @@ class Statistics: def update_prometheus_metrics(): - cache_expire = config.getint("cache", "expiry_time") + cache_expire = config.getint("cache", "expiry_time_statistics", 300) stats = Statistics(cache_expire) # Users gauge for counter, utype in stats.PROMETHEUS_USER_COUNTERS: diff --git a/conf/config.defaults b/conf/config.defaults index 4e2415ed..ab0a9b67 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -169,5 +169,7 @@ range_end = 172800 [cache] ; maximum number of keys/entries (for search results) in our redis cache, default is 50000 max_search_entries = 50000 -; number of seconds after a cache entry expires, default is 3 minutes -expiry_time = 180 +; number of seconds after a cache entry for search queries expires, default is 10 minutes +expiry_time_search = 600 +; number of seconds after a cache entry for statistics queries expires, default is 5 minutes +expiry_time_statistics = 300 From 6cd70a5c9fb57c42af7c2254045eba9fe6aa17e0 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 23 Jul 2023 11:34:50 +0200 Subject: [PATCH 1794/1891] test: Add tests for user/package statistics Signed-off-by: moson --- test/test_statistics.py | 125 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 test/test_statistics.py diff --git a/test/test_statistics.py b/test/test_statistics.py new file mode 100644 index 00000000..dda7b357 --- /dev/null +++ b/test/test_statistics.py @@ -0,0 +1,125 @@ +import pytest +from prometheus_client import REGISTRY, generate_latest + +from aurweb import cache, db, time +from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.user import User +from aurweb.statistics import Statistics, update_prometheus_metrics + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture(autouse=True) +def clear_fakeredis_cache(): + cache._redis.flushall() + + +@pytest.fixture +def test_data(): + # Create some test data (users and packages) + with db.begin(): + for i in range(10): + user = db.create( + User, + Username=f"test{i}", + Email=f"test{i}@example.org", + RealName=f"Test User {i}", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) + + now = time.utcnow() + old = now - 60 * 60 * 24 * 8 # 8 days + older = now - 60 * 60 * 24 * 400 # 400 days + + pkgbase = db.create( + PackageBase, + Name=f"test-package{i}", + Maintainer=user, + SubmittedTS=old, + ModifiedTS=now, + ) + db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + + # Modify some data to get some variances for our counters + if i == 1: + user.AccountTypeID = TRUSTED_USER_ID + pkgbase.Maintainer = None + pkgbase.SubmittedTS = now + + if i == 2: + pkgbase.SubmittedTS = older + + if i == 3: + pkgbase.SubmittedTS = older + pkgbase.ModifiedTS = old + yield + + +@pytest.fixture +def stats() -> Statistics: + yield Statistics() + + +@pytest.mark.parametrize( + "counter, expected", + [ + ("package_count", 10), + ("orphan_count", 1), + ("seven_days_old_added", 1), + ("seven_days_old_updated", 8), + ("year_old_updated", 9), + ("never_updated", 1), + ("user_count", 10), + ("trusted_user_count", 1), + ("regular_user_count", 9), + ("updated_packages", 9), + ("nonsense", -1), + ], +) +def test_get_count(stats: Statistics, test_data, counter: str, expected: int): + assert stats.get_count(counter) == expected + + +def test_get_count_change(stats: Statistics, test_data): + pkgs_before = stats.get_count("package_count") + tus_before = stats.get_count("trusted_user_count") + + assert pkgs_before == 10 + assert tus_before == 1 + + # Let's delete a package and promote a user to TU + with db.begin(): + pkgbase = db.query(PackageBase).first() + db.delete(pkgbase) + + user = db.query(User).filter(User.AccountTypeID == USER_ID).first() + user.AccountTypeID = TRUSTED_USER_ID + + # Values should end up in (fake) redis cache so they should be the same + assert stats.get_count("package_count") == pkgs_before + assert stats.get_count("trusted_user_count") == tus_before + + # Let's clear the cache and check again + cache._redis.flushall() + assert stats.get_count("package_count") != pkgs_before + assert stats.get_count("trusted_user_count") != tus_before + + +def test_update_prometheus_metrics(test_data): + metrics = str(generate_latest(REGISTRY)) + + assert "aur_users{" not in metrics + assert "aur_packages{" not in metrics + + # Let's update our metrics. We should find our gauges now + update_prometheus_metrics() + metrics = str(generate_latest(REGISTRY)) + + assert 'aur_users{type="user"} 9.0' in metrics + assert 'aur_packages{state="updated"} 9.0' in metrics From e45878a058071e59f0f08eb3dca597f560448298 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 23 Jul 2023 18:53:58 +0200 Subject: [PATCH 1795/1891] fix: Fix issue with requests totals Problem is that we join with PackageBase, thus we are missing requests for packages that were deleted. Fixes: #483 Signed-off-by: moson --- aurweb/routers/html.py | 11 ++--- aurweb/routers/requests.py | 16 ++----- aurweb/statistics.py | 95 ++++++++++++++++++++++++++++---------- test/test_statistics.py | 32 ++++++++++++- 4 files changed, 111 insertions(+), 43 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 2ec497bd..63cc3bb8 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -16,11 +16,10 @@ from sqlalchemy import case, or_ import aurweb.config import aurweb.models.package_request -from aurweb import aur_logging, cookies, db, models, time, util +from aurweb import aur_logging, cookies, db, models, statistics, time, util from aurweb.exceptions import handle_form_exceptions from aurweb.models.package_request import PENDING_ID from aurweb.packages.util import query_notified, query_voted, updated_packages -from aurweb.statistics import Statistics, update_prometheus_metrics from aurweb.templates import make_context, render_template logger = aur_logging.get_logger(__name__) @@ -89,9 +88,9 @@ async def index(request: Request): cache_expire = aurweb.config.getint("cache", "expiry_time_statistics", 300) # Package statistics. - stats = Statistics(cache_expire) - for counter in stats.HOMEPAGE_COUNTERS: - context[counter] = stats.get_count(counter) + counts = statistics.get_homepage_counts() + for k in counts: + context[k] = counts[k] # Get the 15 most recently updated packages. context["package_updates"] = updated_packages(15, cache_expire) @@ -213,7 +212,7 @@ async def metrics(request: Request): ) # update prometheus gauges for packages and users - update_prometheus_metrics() + statistics.update_prometheus_metrics() registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 4cfda269..a67419fe 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -16,6 +16,7 @@ from aurweb.models.package_request import ( ) from aurweb.requests.util import get_pkgreq_by_id from aurweb.scripts import notify +from aurweb.statistics import get_request_counts from aurweb.templates import make_context, render_template FILTER_PARAMS = { @@ -31,7 +32,7 @@ router = APIRouter() @router.get("/requests") @requires_auth -async def requests( +async def requests( # noqa: C901 request: Request, O: int = Query(default=defaults.O), PP: int = Query(default=defaults.PP), @@ -74,18 +75,11 @@ async def requests( .join(User, PackageRequest.UsersID == User.ID, isouter=True) .join(Maintainer, PackageBase.MaintainerUID == Maintainer.ID, isouter=True) ) - # query = db.query(PackageRequest).join(User) # Requests statistics - context["total_requests"] = query.count() - pending_count = 0 + query.filter(PackageRequest.Status == PENDING_ID).count() - context["pending_requests"] = pending_count - closed_count = 0 + query.filter(PackageRequest.Status == CLOSED_ID).count() - context["closed_requests"] = closed_count - accepted_count = 0 + query.filter(PackageRequest.Status == ACCEPTED_ID).count() - context["accepted_requests"] = accepted_count - rejected_count = 0 + query.filter(PackageRequest.Status == REJECTED_ID).count() - context["rejected_requests"] = rejected_count + counts = get_request_counts() + for k in counts: + context[k] = counts[k] # Apply status filters in_filters = [] diff --git a/aurweb/statistics.py b/aurweb/statistics.py index 6e9dbe1f..3c1298b7 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -1,31 +1,46 @@ from aurweb import config, db, time from aurweb.cache import db_count_cache -from aurweb.models import PackageBase, User +from aurweb.models import PackageBase, PackageRequest, User from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.models.package_request import ( + ACCEPTED_ID, + CLOSED_ID, + PENDING_ID, + REJECTED_ID, +) from aurweb.prometheus import PACKAGES, USERS +cache_expire = config.getint("cache", "expiry_time_statistics", 300) + +HOMEPAGE_COUNTERS = [ + "package_count", + "orphan_count", + "seven_days_old_added", + "seven_days_old_updated", + "year_old_updated", + "never_updated", + "user_count", + "trusted_user_count", +] +REQUEST_COUNTERS = [ + "total_requests", + "pending_requests", + "closed_requests", + "accepted_requests", + "rejected_requests", +] +PROMETHEUS_USER_COUNTERS = [ + ("trusted_user_count", "tu"), + ("regular_user_count", "user"), +] +PROMETHEUS_PACKAGE_COUNTERS = [ + ("orphan_count", "orphan"), + ("never_updated", "not_updated"), + ("updated_packages", "updated"), +] + class Statistics: - HOMEPAGE_COUNTERS = [ - "package_count", - "orphan_count", - "seven_days_old_added", - "seven_days_old_updated", - "year_old_updated", - "never_updated", - "user_count", - "trusted_user_count", - ] - PROMETHEUS_USER_COUNTERS = [ - ("trusted_user_count", "tu"), - ("regular_user_count", "user"), - ] - PROMETHEUS_PACKAGE_COUNTERS = [ - ("orphan_count", "orphan"), - ("never_updated", "not_updated"), - ("updated_packages", "updated"), - ] - seven_days = 86400 * 7 one_hour = 3600 year = seven_days * 52 @@ -35,15 +50,18 @@ class Statistics: self.now = time.utcnow() self.seven_days_ago = self.now - self.seven_days self.year_ago = self.now - self.year + self.user_query = db.query(User) self.bases_query = db.query(PackageBase) self.updated_query = db.query(PackageBase).filter( PackageBase.ModifiedTS - PackageBase.SubmittedTS >= self.one_hour ) + self.request_query = db.query(PackageRequest) def get_count(self, counter: str) -> int: query = None match counter: + # Packages case "package_count": query = self.bases_query case "orphan_count": @@ -69,6 +87,7 @@ class Statistics: PackageBase.ModifiedTS - PackageBase.SubmittedTS > self.one_hour, ~PackageBase.MaintainerUID.is_(None), ) + # Users case "user_count": query = self.user_query case "trusted_user_count": @@ -82,6 +101,18 @@ class Statistics: ) case "regular_user_count": query = self.user_query.filter(User.AccountTypeID == USER_ID) + + # Requests + case "total_requests": + query = self.request_query + case "pending_requests": + query = self.request_query.filter(PackageRequest.Status == PENDING_ID) + case "closed_requests": + query = self.request_query.filter(PackageRequest.Status == CLOSED_ID) + case "accepted_requests": + query = self.request_query.filter(PackageRequest.Status == ACCEPTED_ID) + case "rejected_requests": + query = self.request_query.filter(PackageRequest.Status == REJECTED_ID) case _: return -1 @@ -89,14 +120,30 @@ class Statistics: def update_prometheus_metrics(): - cache_expire = config.getint("cache", "expiry_time_statistics", 300) stats = Statistics(cache_expire) # Users gauge - for counter, utype in stats.PROMETHEUS_USER_COUNTERS: + for counter, utype in PROMETHEUS_USER_COUNTERS: count = stats.get_count(counter) USERS.labels(utype).set(count) # Packages gauge - for counter, state in stats.PROMETHEUS_PACKAGE_COUNTERS: + for counter, state in PROMETHEUS_PACKAGE_COUNTERS: count = stats.get_count(counter) PACKAGES.labels(state).set(count) + + +def _get_counts(counters: list[str]) -> dict[str, int]: + stats = Statistics(cache_expire) + result = dict() + for counter in counters: + result[counter] = stats.get_count(counter) + + return result + + +def get_homepage_counts() -> dict[str, int]: + return _get_counts(HOMEPAGE_COUNTERS) + + +def get_request_counts() -> dict[str, int]: + return _get_counts(REQUEST_COUNTERS) diff --git a/test/test_statistics.py b/test/test_statistics.py index dda7b357..a6a814c5 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -2,9 +2,15 @@ import pytest from prometheus_client import REGISTRY, generate_latest from aurweb import cache, db, time +from aurweb.models import Package, PackageBase, PackageRequest from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID -from aurweb.models.package import Package -from aurweb.models.package_base import PackageBase +from aurweb.models.package_request import ( + ACCEPTED_ID, + CLOSED_ID, + PENDING_ID, + REJECTED_ID, +) +from aurweb.models.request_type import DELETION_ID, ORPHAN_ID from aurweb.models.user import User from aurweb.statistics import Statistics, update_prometheus_metrics @@ -45,19 +51,36 @@ def test_data(): ModifiedTS=now, ) db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + pkgreq = db.create( + PackageRequest, + ReqTypeID=ORPHAN_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + RequestTS=now, + Comments=str(), + ClosureComment=str(), + ) # Modify some data to get some variances for our counters if i == 1: user.AccountTypeID = TRUSTED_USER_ID pkgbase.Maintainer = None pkgbase.SubmittedTS = now + pkgreq.Status = PENDING_ID + pkgreq.ReqTypeID = DELETION_ID if i == 2: pkgbase.SubmittedTS = older + pkgreq.Status = ACCEPTED_ID if i == 3: pkgbase.SubmittedTS = older pkgbase.ModifiedTS = old + pkgreq.Status = CLOSED_ID + + if i == 4: + pkgreq.Status = REJECTED_ID yield @@ -79,6 +102,11 @@ def stats() -> Statistics: ("trusted_user_count", 1), ("regular_user_count", 9), ("updated_packages", 9), + ("total_requests", 10), + ("pending_requests", 7), + ("closed_requests", 1), + ("accepted_requests", 1), + ("rejected_requests", 1), ("nonsense", -1), ], ) From 375895f08011c2c91b52b79a2d41fe1504524acf Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 23 Jul 2023 22:46:44 +0200 Subject: [PATCH 1796/1891] feat: Add Prometheus metrics for requests Adds gauge for requests by type and status Signed-off-by: moson --- aurweb/prometheus.py | 6 ++++++ aurweb/statistics.py | 22 +++++++++++++++++++--- test/test_statistics.py | 6 ++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index d3455551..40b99a90 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -24,6 +24,12 @@ PACKAGES = Gauge( ["state"], multiprocess_mode="livemax", ) +REQUESTS = Gauge( + "aur_requests", + "Number of AUR requests by type and status", + ["type", "status"], + multiprocess_mode="livemax", +) def instrumentator(): diff --git a/aurweb/statistics.py b/aurweb/statistics.py index 3c1298b7..f301b59c 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -1,6 +1,8 @@ +from sqlalchemy import func + from aurweb import config, db, time -from aurweb.cache import db_count_cache -from aurweb.models import PackageBase, PackageRequest, User +from aurweb.cache import db_count_cache, db_query_cache +from aurweb.models import PackageBase, PackageRequest, RequestType, User from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID from aurweb.models.package_request import ( ACCEPTED_ID, @@ -8,7 +10,7 @@ from aurweb.models.package_request import ( PENDING_ID, REJECTED_ID, ) -from aurweb.prometheus import PACKAGES, USERS +from aurweb.prometheus import PACKAGES, REQUESTS, USERS cache_expire = config.getint("cache", "expiry_time_statistics", 300) @@ -131,6 +133,20 @@ def update_prometheus_metrics(): count = stats.get_count(counter) PACKAGES.labels(state).set(count) + # Requests gauge + query = ( + db.get_session() + .query(PackageRequest, func.count(PackageRequest.ID), RequestType.Name) + .join(RequestType) + .group_by(RequestType.Name, PackageRequest.Status) + ) + results = db_query_cache("request_metrics", query, cache_expire) + for record in results: + status = record[0].status_display() + count = record[1] + rtype = record[2] + REQUESTS.labels(type=rtype, status=status).set(count) + def _get_counts(counters: list[str]) -> dict[str, int]: stats = Statistics(cache_expire) diff --git a/test/test_statistics.py b/test/test_statistics.py index a6a814c5..db262fa3 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -144,6 +144,7 @@ def test_update_prometheus_metrics(test_data): assert "aur_users{" not in metrics assert "aur_packages{" not in metrics + assert "aur_requests{" not in metrics # Let's update our metrics. We should find our gauges now update_prometheus_metrics() @@ -151,3 +152,8 @@ def test_update_prometheus_metrics(test_data): assert 'aur_users{type="user"} 9.0' in metrics assert 'aur_packages{state="updated"} 9.0' in metrics + assert 'aur_requests{status="Pending",type="orphan"} 6.0' in metrics + assert 'aur_requests{status="Closed",type="orphan"} 1.0' in metrics + assert 'aur_requests{status="Accepted",type="orphan"} 1.0' in metrics + assert 'aur_requests{status="Rejected",type="orphan"} 1.0' in metrics + assert 'aur_requests{status="Pending",type="deletion"} 1.0' in metrics From f74f94b50170d82c1d3f899037dc0debd2222725 Mon Sep 17 00:00:00 2001 From: renovate Date: Mon, 24 Jul 2023 11:24:26 +0000 Subject: [PATCH 1797/1891] fix(deps): update dependency gunicorn to v21 --- poetry.lock | 27 +++++---------------------- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/poetry.lock b/poetry.lock index 368371db..42010de5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -685,18 +685,18 @@ test = ["objgraph", "psutil"] [[package]] name = "gunicorn" -version = "20.1.0" +version = "21.2.0" description = "WSGI HTTP Server for UNIX" category = "main" optional = false python-versions = ">=3.5" files = [ - {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, - {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, ] [package.dependencies] -setuptools = ">=3.0" +packaging = "*" [package.extras] eventlet = ["eventlet (>=0.24.1)"] @@ -1602,23 +1602,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "setuptools" -version = "67.7.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, - {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" version = "1.16.0" @@ -1948,4 +1931,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "b67f1b1599794a6890b0a31b2b127880d75c84beeeae3df4ecb3ae92296948da" +content-hash = "48d66bc7145b8cdac8da9977d6d2b0d554b382193a28f275743697d0a17d2f58" diff --git a/pyproject.toml b/pyproject.toml index e98e887f..e743e675 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,7 +87,7 @@ SQLAlchemy = "^1.4.48" # ASGI uvicorn = "^0.23.0" -gunicorn = "^20.1.0" +gunicorn = "^21.0.0" Hypercorn = "^0.14.3" prometheus-fastapi-instrumentator = "^6.0.0" pytest-xdist = "^3.2.1" From 969b84afe4f2d74a005bd35594d9a76de5351e95 Mon Sep 17 00:00:00 2001 From: renovate Date: Tue, 25 Jul 2023 11:24:30 +0000 Subject: [PATCH 1798/1891] fix(deps): update all non-major dependencies --- poetry.lock | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 42010de5..9897fafb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -540,14 +540,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.16.0" +version = "2.17.0" description = "Python implementation of redis API, can be used for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.16.0-py3-none-any.whl", hash = "sha256:188514cbd7120ff28c88f2a31e2fddd18fb1b28504478dfa3669c683134c4d82"}, - {file = "fakeredis-2.16.0.tar.gz", hash = "sha256:5abdd734de4ead9d6c7acbd3add1c4aa9b3ab35219339530472d9dd2bdf13057"}, + {file = "fakeredis-2.17.0-py3-none-any.whl", hash = "sha256:a99ef6e5642c31e91d36be78809fec3743e2bf7aaa682685b0d65a849fecd148"}, + {file = "fakeredis-2.17.0.tar.gz", hash = "sha256:e304bc7addb2f862c3550cb7db58548418a0fadd4cd78a4de66464c84fbc2195"}, ] [package.dependencies] @@ -1815,19 +1815,20 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.23.0" +version = "0.23.1" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.23.0-py3-none-any.whl", hash = "sha256:479599b2c0bb1b9b394c6d43901a1eb0c1ec72c7d237b5bafea23c5b2d4cdf10"}, - {file = "uvicorn-0.23.0.tar.gz", hash = "sha256:d38ab90c0e2c6fe3a054cddeb962cfd5d0e0e6608eaaff4a01d5c36a67f3168c"}, + {file = "uvicorn-0.23.1-py3-none-any.whl", hash = "sha256:1d55d46b83ee4ce82b4e82f621f2050adb3eb7b5481c13f9af1744951cae2f1f"}, + {file = "uvicorn-0.23.1.tar.gz", hash = "sha256:da9b0c8443b2d7ee9db00a345f1eee6db7317432c9d4400f5049cc8d358383be"}, ] [package.dependencies] click = ">=7.0" h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] From 7a44f379687cb10817b8b2b3f6a636e289832b36 Mon Sep 17 00:00:00 2001 From: renovate Date: Thu, 27 Jul 2023 19:24:28 +0000 Subject: [PATCH 1799/1891] fix(deps): update dependency fastapi to v0.100.1 --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9897fafb..c4d3adb6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -560,14 +560,14 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.100.0" +version = "0.100.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.100.0-py3-none-any.whl", hash = "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f"}, - {file = "fastapi-0.100.0.tar.gz", hash = "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e"}, + {file = "fastapi-0.100.1-py3-none-any.whl", hash = "sha256:ec6dd52bfc4eff3063cfcd0713b43c87640fefb2687bbbe3d8a08d94049cdf32"}, + {file = "fastapi-0.100.1.tar.gz", hash = "sha256:522700d7a469e4a973d92321ab93312448fbe20fca9c8da97effc7e7bc56df23"}, ] [package.dependencies] From 94b62d2949c0b627bbeac4107c681ab7eccfff7d Mon Sep 17 00:00:00 2001 From: moson Date: Fri, 4 Aug 2023 14:12:50 +0200 Subject: [PATCH 1800/1891] fix: Check if user exists when editing account We should check if a user (target) exists before validating permissions. Otherwise things crash when a TU is trying to edit an account that does not exist. Fixes: aurweb-errors#529 Signed-off-by: moson --- aurweb/routers/accounts.py | 3 +++ test/test_accounts_routes.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 010aae58..1c81ec1d 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -374,6 +374,9 @@ def cannot_edit( :param user: Target user to be edited :return: RedirectResponse if approval != granted else None """ + # raise 404 if user does not exist + if not user: + raise HTTPException(status_code=HTTPStatus.NOT_FOUND) approved = request.user.can_edit_user(user) if not approved and (to := "/"): if user: diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 3c481d0a..3ff6291a 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -764,6 +764,17 @@ def test_get_account_edit_unauthorized(client: TestClient, user: User): assert response.headers.get("location") == expected +def test_get_account_edit_not_exists(client: TestClient, tu_user: User): + """Test that users do not have an Account Type field.""" + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + endpoint = "/account/doesnotexist/edit" + + with client as request: + request.cookies = cookies + response = request.get(endpoint) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + def test_post_account_edit(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -872,6 +883,19 @@ def test_post_account_edit_dev(client: TestClient, tu_user: User): assert expected in response.content.decode() +def test_post_account_edit_not_exists(client: TestClient, tu_user: User): + request = Request() + sid = tu_user.login(request, "testPassword") + + post_data = {"U": "test", "E": "test666@example.org", "passwd": "testPassword"} + + endpoint = "/account/doesnotexist/edit" + with client as request: + request.cookies = {"AURSID": sid} + response = request.post(endpoint, data=post_data) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + def test_post_account_edit_language(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") From 8ad03522de34a40992165649fc0605390db93a98 Mon Sep 17 00:00:00 2001 From: renovate Date: Fri, 4 Aug 2023 14:25:22 +0000 Subject: [PATCH 1801/1891] fix(deps): update all non-major dependencies --- poetry.lock | 27 ++++++++++++++------------- pyproject.toml | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index c4d3adb6..623884a0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.11.1" +version = "1.11.2" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.11.1-py3-none-any.whl", hash = "sha256:dc871798a601fab38332e38d6ddb38d5e734f60034baeb8e2db5b642fccd8ab8"}, - {file = "alembic-1.11.1.tar.gz", hash = "sha256:6a810a6b012c88b33458fceb869aef09ac75d6ace5291915ba7fae44de372c01"}, + {file = "alembic-1.11.2-py3-none-any.whl", hash = "sha256:7981ab0c4fad4fe1be0cf183aae17689fe394ff874fd2464adb774396faf0796"}, + {file = "alembic-1.11.2.tar.gz", hash = "sha256:678f662130dc540dac12de0ea73de9f89caea9dbea138f60ef6263149bf84657"}, ] [package.dependencies] @@ -1031,20 +1031,21 @@ testing = ["pytest"] [[package]] name = "markdown" -version = "3.4.3" +version = "3.4.4" description = "Python implementation of John Gruber's Markdown." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Markdown-3.4.3-py3-none-any.whl", hash = "sha256:065fd4df22da73a625f14890dd77eb8040edcbd68794bcd35943be14490608b2"}, - {file = "Markdown-3.4.3.tar.gz", hash = "sha256:8bf101198e004dc93e84a12a7395e31aac6a9c9942848ae1d99b9d72cf9b3520"}, + {file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"}, + {file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"}, ] [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"] testing = ["coverage", "pyyaml"] [[package]] @@ -1773,14 +1774,14 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.8" +version = "0.12.1" description = "Style preserving TOML library" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, - {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, + {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, + {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, ] [[package]] @@ -1815,14 +1816,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.23.1" +version = "0.23.2" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.23.1-py3-none-any.whl", hash = "sha256:1d55d46b83ee4ce82b4e82f621f2050adb3eb7b5481c13f9af1744951cae2f1f"}, - {file = "uvicorn-0.23.1.tar.gz", hash = "sha256:da9b0c8443b2d7ee9db00a345f1eee6db7317432c9d4400f5049cc8d358383be"}, + {file = "uvicorn-0.23.2-py3-none-any.whl", hash = "sha256:1f9be6558f01239d4fdf22ef8126c39cb1ad0addf76c40e760549d2c2f43ab53"}, + {file = "uvicorn-0.23.2.tar.gz", hash = "sha256:4d3cc12d7727ba72b64d12d3cc7743124074c0a69f7b201512fc50c3e3f1569a"}, ] [package.dependencies] @@ -1932,4 +1933,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "48d66bc7145b8cdac8da9977d6d2b0d554b382193a28f275743697d0a17d2f58" +content-hash = "ac9dbb5b28292c4a3dd2318a2f5c9120dfaa117ee834fac05995c5d0cbdc460d" diff --git a/pyproject.toml b/pyproject.toml index e743e675..f4682bad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,7 @@ posix-ipc = "^1.1.1" pyalpm = "^0.10.6" fastapi = "^0.100.0" srcinfo = "^0.1.2" -tomlkit = "^0.11.8" +tomlkit = "^0.12.0" [tool.poetry.dev-dependencies] coverage = "^7.2.5" From f05f1dbac798c5fd41e0f19c9b0419fa302c9bf4 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 4 Aug 2023 19:18:38 +0300 Subject: [PATCH 1802/1891] chore(release): prepare for 6.2.7 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f4682bad..359923a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.6" +version = "v6.2.7" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 3005e82f607e7b20ac5e32d50f0ffb124a8737e0 Mon Sep 17 00:00:00 2001 From: moson Date: Fri, 18 Aug 2023 22:04:55 +0200 Subject: [PATCH 1803/1891] fix: Cleanup prometheus metrics for dead workers The current "cleanup" function that is removing orphan prometheus files is actually never invoked. We move this to a default gunicorn config file to register our hook(s). https://docs.gunicorn.org/en/stable/configure.html https://docs.gunicorn.org/en/stable/settings.html#child-exit Signed-off-by: moson --- aurweb/asgi.py | 7 ------- gunicorn.conf.py | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 gunicorn.conf.py diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 1be77ff9..9b6ffcb3 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -13,7 +13,6 @@ from fastapi import FastAPI, HTTPException, Request, Response from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from jinja2 import TemplateNotFound -from prometheus_client import multiprocess from sqlalchemy import and_ from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.middleware.authentication import AuthenticationMiddleware @@ -91,12 +90,6 @@ async def app_startup(): get_engine() -def child_exit(server, worker): # pragma: no cover - """This function is required for gunicorn customization - of prometheus multiprocessing.""" - multiprocess.mark_process_dead(worker.pid) - - async def internal_server_error(request: Request, exc: Exception) -> Response: """ Catch all uncaught Exceptions thrown in a route. diff --git a/gunicorn.conf.py b/gunicorn.conf.py new file mode 100644 index 00000000..4f1c3a8c --- /dev/null +++ b/gunicorn.conf.py @@ -0,0 +1,7 @@ +from prometheus_client import multiprocess + + +def child_exit(server, worker): # pragma: no cover + """This function is required for gunicorn customization + of prometheus multiprocessing.""" + multiprocess.mark_process_dead(worker.pid) From 6c610b26a39a56db562e4b1ed3c95420a73ee766 Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Fri, 28 Jul 2023 22:42:44 +0200 Subject: [PATCH 1804/1891] feat: Add terraform config for review-app[1] Also removed the logic for deploying to the long gone aur-dev box. Ansible will be added in a upcoming commit for configurating and deploying aurweb on the VM. [1] https://docs.gitlab.com/ee/ci/review_apps/ --- .gitignore | 4 +++ .gitlab-ci.yml | 71 +++++++++++++++++++++++---------------- ci/tf/.terraform.lock.hcl | 61 +++++++++++++++++++++++++++++++++ ci/tf/main.tf | 67 ++++++++++++++++++++++++++++++++++++ ci/tf/terraform.tfvars | 4 +++ ci/tf/variables.tf | 36 ++++++++++++++++++++ ci/tf/versions.tf | 13 +++++++ 7 files changed, 227 insertions(+), 29 deletions(-) create mode 100644 ci/tf/.terraform.lock.hcl create mode 100644 ci/tf/main.tf create mode 100644 ci/tf/terraform.tfvars create mode 100644 ci/tf/variables.tf create mode 100644 ci/tf/versions.tf diff --git a/.gitignore b/.gitignore index 68de7cd5..97157118 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,7 @@ test-emails/ env/ venv/ .venv/ + +# Ignore some terraform files +/ci/tf/.terraform +/ci/tf/terraform.tfstate* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10dd1787..4bd71920 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -61,34 +61,47 @@ test: coverage_format: cobertura path: coverage.xml -deploy: - stage: deploy - tags: - - secure - rules: - - if: $CI_COMMIT_BRANCH == "pu" - when: manual - variables: - FASTAPI_BACKEND: gunicorn - FASTAPI_WORKERS: 5 - AURWEB_FASTAPI_PREFIX: https://aur-dev.archlinux.org - AURWEB_SSHD_PREFIX: ssh://aur@aur-dev.archlinux.org:2222 - COMMIT_HASH: $CI_COMMIT_SHA - GIT_DATA_DIR: git_data - script: - - pacman -Syu --noconfirm docker docker-compose socat openssh - - chmod 600 ${SSH_KEY} - - socat "UNIX-LISTEN:/tmp/docker.sock,reuseaddr,fork" EXEC:"ssh -o UserKnownHostsFile=${SSH_KNOWN_HOSTS} -Ti ${SSH_KEY} ${SSH_USER}@${SSH_HOST}" & - - export DOCKER_HOST="unix:///tmp/docker.sock" - # Set secure login config for aurweb. - - sed -ri "s/^(disable_http_login).*$/\1 = 1/" conf/config.dev - - docker-compose build - - docker-compose -f docker-compose.yml -f docker-compose.aur-dev.yml down --remove-orphans - - docker-compose -f docker-compose.yml -f docker-compose.aur-dev.yml up -d - - docker image prune -f - - docker container prune -f - - docker volume prune -f +.init_tf: &init_tf + - pacman -Syu --needed --noconfirm --cachedir .pkg-cache terraform + - export TF_VAR_name="aurweb-${CI_COMMIT_REF_SLUG}" + - TF_ADDRESS="${CI_API_V4_URL}/projects/${TF_STATE_PROJECT}/terraform/state/${CI_COMMIT_REF_SLUG}" + - cd ci/tf + - > + terraform init \ + -backend-config="address=${TF_ADDRESS}" \ + -backend-config="lock_address=${TF_ADDRESS}/lock" \ + -backend-config="unlock_address=${TF_ADDRESS}/lock" \ + -backend-config="username=x-access-token" \ + -backend-config="password=${TF_STATE_GITLAB_ACCESS_TOKEN}" \ + -backend-config="lock_method=POST" \ + -backend-config="unlock_method=DELETE" \ + -backend-config="retry_wait_min=5" +deploy_review: + stage: deploy + script: + - *init_tf + - terraform apply -auto-approve environment: - name: development - url: https://aur-dev.archlinux.org + name: review/$CI_COMMIT_REF_NAME + url: https://aurweb-$CI_ENVIRONMENT_SLUG.sandbox.archlinux.page + on_stop: stop_review + auto_stop_in: 1 week + rules: + - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" + when: manual + +stop_review: + stage: deploy + needs: + - deploy_review + script: + - *init_tf + - terraform destroy -auto-approve + - 'curl --silent --show-error --fail --header "Private-Token: ${TF_STATE_GITLAB_ACCESS_TOKEN}" --request DELETE "${CI_API_V4_URL}/projects/${TF_STATE_PROJECT}/terraform/state/${CI_COMMIT_REF_SLUG}"' + environment: + name: review/$CI_COMMIT_REF_NAME + action: stop + rules: + - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" + when: manual diff --git a/ci/tf/.terraform.lock.hcl b/ci/tf/.terraform.lock.hcl new file mode 100644 index 00000000..aa5501c4 --- /dev/null +++ b/ci/tf/.terraform.lock.hcl @@ -0,0 +1,61 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/dns" { + version = "3.3.2" + hashes = [ + "h1:HjskPLRqmCw8Q/kiSuzti3iJBSpcAvcBFdlwFFQuoDE=", + "zh:05d2d50e301318362a4a82e6b7a9734ace07bc01abaaa649c566baf98814755f", + "zh:1e9fd1c3bfdda777e83e42831dd45b7b9e794250a0f351e5fd39762e8a0fe15b", + "zh:40e715fc7a2ede21f919567249b613844692c2f8a64f93ee64e5b68bae7ac2a2", + "zh:454d7aa83000a6e2ba7a7bfde4bcf5d7ed36298b22d760995ca5738ab02ee468", + "zh:46124ded51b4153ad90f12b0305fdbe0c23261b9669aa58a94a31c9cca2f4b19", + "zh:55a4f13d20f73534515a6b05701abdbfc54f4e375ba25b2dffa12afdad20e49d", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7903b1ceb8211e2b8c79290e2e70906a4b88f4fba71c900eb3a425ce12f1716a", + "zh:b79fc4f444ef7a2fd7111a80428c070ad824f43a681699e99ab7f83074dfedbd", + "zh:ca9f45e0c4cb94e7d62536c226024afef3018b1de84f1ea4608b51bcd497a2a0", + "zh:ddc8bd894559d7d176e0ceb0bb1ae266519b01b315362ebfee8327bb7e7e5fa8", + "zh:e77334c0794ef8f9354b10e606040f6b0b67b373f5ff1db65bddcdd4569b428b", + ] +} + +provider "registry.terraform.io/hashicorp/tls" { + version = "4.0.4" + hashes = [ + "h1:pe9vq86dZZKCm+8k1RhzARwENslF3SXb9ErHbQfgjXU=", + "zh:23671ed83e1fcf79745534841e10291bbf34046b27d6e68a5d0aab77206f4a55", + "zh:45292421211ffd9e8e3eb3655677700e3c5047f71d8f7650d2ce30242335f848", + "zh:59fedb519f4433c0fdb1d58b27c210b27415fddd0cd73c5312530b4309c088be", + "zh:5a8eec2409a9ff7cd0758a9d818c74bcba92a240e6c5e54b99df68fff312bbd5", + "zh:5e6a4b39f3171f53292ab88058a59e64825f2b842760a4869e64dc1dc093d1fe", + "zh:810547d0bf9311d21c81cc306126d3547e7bd3f194fc295836acf164b9f8424e", + "zh:824a5f3617624243bed0259d7dd37d76017097dc3193dac669be342b90b2ab48", + "zh:9361ccc7048be5dcbc2fafe2d8216939765b3160bd52734f7a9fd917a39ecbd8", + "zh:aa02ea625aaf672e649296bce7580f62d724268189fe9ad7c1b36bb0fa12fa60", + "zh:c71b4cd40d6ec7815dfeefd57d88bc592c0c42f5e5858dcc88245d371b4b8b1e", + "zh:dabcd52f36b43d250a3d71ad7abfa07b5622c69068d989e60b79b2bb4f220316", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hetznercloud/hcloud" { + version = "1.42.0" + hashes = [ + "h1:cr9lh26H3YbWSHb7OUnCoYw169cYO3Cjpt3yPnRhXS0=", + "zh:153b5f39d780e9a18bc1ea377d872647d328d943813cbd25d3d20863f8a37782", + "zh:35b9e95760c58cca756e34ad5f4138ac6126aa3e8c41b4a0f1d5dc9ee5666c73", + "zh:47a3cdbce982f2b4e17f73d4934bdb3e905a849b36fb59b80f87d852496ed049", + "zh:6a718c244c2ba300fbd43791661a061ad1ab16225ef3e8aeaa3db8c9eff12c85", + "zh:a2cbfc95c5e2c9422ed0a7b6292192c38241220d5b7813c678f937ab3ef962ae", + "zh:b837e118e08fd36aa8be48af7e9d0d3d112d2680c79cfc71cfe2501fb40dbefa", + "zh:bf66db8c680e18b77e16dc1f20ed1cdcc7876bfb7848c320ccb86f0fb80661ed", + "zh:c1ad80bbe48dc8a272a02dcdb4b12f019606f445606651c01e561b9d72d816b1", + "zh:d4e616701128ad14a6b5a427b0e9145ece4cad02aa3b5f9945c6d0b9ada8ab70", + "zh:d9d01f727037d028720100a5bc9fd213cb01e63e4b439a16f2f482c147976530", + "zh:dea047ee4d679370d4376fb746c4b959bf51dd06047c1c2656b32789c2433643", + "zh:e5ad7a3c556894bd40b28a874e7d2f6924876fa75fa443136a7d6ab9a00abbaa", + "zh:edf6e7e129157bd45e3da4a330d1ace17a336d417c3b77c620f302d440c368e8", + "zh:f610bc729866d58da9cffa4deae34dbfdba96655e855a87c6bb2cb7b35a8961c", + ] +} diff --git a/ci/tf/main.tf b/ci/tf/main.tf new file mode 100644 index 00000000..b149a621 --- /dev/null +++ b/ci/tf/main.tf @@ -0,0 +1,67 @@ +terraform { + backend "http" { + } +} + +provider "hcloud" { + token = var.hcloud_token +} + +provider "dns" { + update { + server = var.dns_server + key_name = var.dns_tsig_key + key_algorithm = var.dns_tsig_algorithm + key_secret = var.dns_tsig_secret + } +} + +resource "tls_private_key" "this" { + algorithm = "ED25519" +} + +resource "hcloud_ssh_key" "this" { + name = var.name + public_key = tls_private_key.this.public_key_openssh +} + +data "hcloud_image" "this" { + with_selector = "custom_image=archlinux" + most_recent = true + with_status = ["available"] +} + +resource "hcloud_server" "this" { + name = var.name + image = data.hcloud_image.this.id + server_type = var.server_type + datacenter = var.datacenter + ssh_keys = [hcloud_ssh_key.this.name] + + public_net { + ipv4_enabled = true + ipv6_enabled = true + } +} + +resource "hcloud_rdns" "this" { + for_each = { ipv4 : hcloud_server.this.ipv4_address, ipv6 : hcloud_server.this.ipv6_address } + + server_id = hcloud_server.this.id + ip_address = each.value + dns_ptr = "${var.name}.${var.dns_zone}" +} + +resource "dns_a_record_set" "this" { + zone = "${var.dns_zone}." + name = var.name + addresses = [hcloud_server.this.ipv4_address] + ttl = 300 +} + +resource "dns_aaaa_record_set" "this" { + zone = "${var.dns_zone}." + name = var.name + addresses = [hcloud_server.this.ipv6_address] + ttl = 300 +} diff --git a/ci/tf/terraform.tfvars b/ci/tf/terraform.tfvars new file mode 100644 index 00000000..14818592 --- /dev/null +++ b/ci/tf/terraform.tfvars @@ -0,0 +1,4 @@ +server_type = "cpx11" +datacenter = "fsn1-dc14" +dns_server = "redirect.archlinux.org" +dns_zone = "sandbox.archlinux.page" diff --git a/ci/tf/variables.tf b/ci/tf/variables.tf new file mode 100644 index 00000000..a4e710ee --- /dev/null +++ b/ci/tf/variables.tf @@ -0,0 +1,36 @@ +variable "hcloud_token" { + type = string + sensitive = true +} + +variable "dns_server" { + type = string +} + +variable "dns_tsig_key" { + type = string +} + +variable "dns_tsig_algorithm" { + type = string +} + +variable "dns_tsig_secret" { + type = string +} + +variable "dns_zone" { + type = string +} + +variable "name" { + type = string +} + +variable "server_type" { + type = string +} + +variable "datacenter" { + type = string +} diff --git a/ci/tf/versions.tf b/ci/tf/versions.tf new file mode 100644 index 00000000..2c72215a --- /dev/null +++ b/ci/tf/versions.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + tls = { + source = "hashicorp/tls" + } + hcloud = { + source = "hetznercloud/hcloud" + } + dns = { + source = "hashicorp/dns" + } + } +} From 9eda6a42c69581dfdc14dc1b0d51f744985c7202 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 27 Aug 2023 13:54:39 +0200 Subject: [PATCH 1805/1891] feat: Add ansible provisioning step for review-app Clone infrastructure repository and run playbook to provision our VM with aurweb. Signed-off-by: moson --- .gitlab-ci.yml | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4bd71920..cf80ab24 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,8 @@ variables: TEST_RECURSION_LIMIT: 10000 CURRENT_DIR: "$(pwd)" LOG_CONFIG: logging.test.conf + DEV_FQDN: aurweb-$CI_COMMIT_REF_SLUG.sandbox.archlinux.page + INFRASTRUCTURE_REPO: https://gitlab.archlinux.org/archlinux/infrastructure.git lint: stage: .pre @@ -84,13 +86,63 @@ deploy_review: - terraform apply -auto-approve environment: name: review/$CI_COMMIT_REF_NAME - url: https://aurweb-$CI_ENVIRONMENT_SLUG.sandbox.archlinux.page + url: https://$DEV_FQDN on_stop: stop_review auto_stop_in: 1 week rules: - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" when: manual +provision_review: + stage: deploy + needs: + - deploy_review + script: + - *init_tf + - pacman -Syu --noconfirm --needed --cachedir .pkg-cache ansible git openssh jq + # Get ssh key from terraform state file + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - terraform show -json | + jq -r '.values.root_module.resources[] | + select(.address == "tls_private_key.this") | + .values.private_key_openssh' > ~/.ssh/id_ed25519 + - chmod 400 ~/.ssh/id_ed25519 + # Clone infra repo + - git clone $INFRASTRUCTURE_REPO + - cd infrastructure + # Remove vault files + - rm $(git grep -l 'ANSIBLE_VAULT;1.1;AES256$') + # Remove vault config + - sed -i '/^vault/d' ansible.cfg + # Add host config + - mkdir -p host_vars/$DEV_FQDN + - 'echo "filesystem: btrfs" > host_vars/$DEV_FQDN/misc' + # Add host + - echo "$DEV_FQDN" > hosts + # Add our pubkey and hostkeys + - ssh-keyscan $DEV_FQDN >> ~/.ssh/known_hosts + - ssh-keygen -f ~/.ssh/id_ed25519 -y > pubkeys/aurweb-dev.pub + # Run our ansible playbook + - > + ansible-playbook playbooks/aur-dev.archlinux.org.yml \ + -e "aurdev_fqdn=$DEV_FQDN" \ + -e "aurweb_repository=$CI_REPOSITORY_URL" \ + -e "aurweb_version=$CI_COMMIT_SHA" \ + -e "{\"vault_mariadb_users\":{\"root\":\"aur\"}}" \ + -e "vault_aurweb_db_password=aur" \ + -e "vault_aurweb_gitlab_instance=https://does.not.exist" \ + -e "vault_aurweb_error_project=aur" \ + -e "vault_aurweb_error_token=aur" \ + -e "vault_aurweb_secret=aur" \ + -e "vault_goaurrpc_metrics_token=aur" \ + -e '{"root_additional_keys": ["moson.pub", "aurweb-dev.pub"]}' + environment: + name: review/$CI_COMMIT_REF_NAME + action: access + rules: + - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" + stop_review: stage: deploy needs: From 5699e9bb41638fc1d6040f3e70a90fab38257458 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 26 Aug 2023 14:47:21 +0200 Subject: [PATCH 1806/1891] fix(test): Remove file locking and semaphore All tests within a file run in the same worker and out test DB names are unique per file as well. We don't really need a locking mechanism here. Same is valid for the test-emails. The only potential issue is that it might try to create the same directory multiple times and thus run into an error. However, that can be covered by specifying "exist_ok=True" with os.makedirs such that those errors are ignored. Signed-off-by: moson --- test/conftest.py | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 15a982aa..c36f78dd 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -43,7 +43,6 @@ from multiprocessing import Lock import py import pytest -from posix_ipc import O_CREAT, Semaphore from sqlalchemy import create_engine from sqlalchemy.engine import URL from sqlalchemy.engine.base import Engine @@ -54,7 +53,6 @@ import aurweb.config import aurweb.db from aurweb import aur_logging, initdb, testing from aurweb.testing.email import Email -from aurweb.testing.filelock import FileLock from aurweb.testing.git import GitRepository logger = aur_logging.get_logger(__name__) @@ -133,20 +131,16 @@ def _drop_database(engine: Engine, dbname: str) -> None: def setup_email(): - # TODO: Fix this data race! This try/catch is ugly; why is it even - # racing here? Perhaps we need to multiproc + multithread lock - # inside of setup_database to block the check? - with Semaphore("/test-emails", flags=O_CREAT, initial_value=1): - if not os.path.exists(Email.TEST_DIR): - # Create the directory. - os.makedirs(Email.TEST_DIR) + if not os.path.exists(Email.TEST_DIR): + # Create the directory. + os.makedirs(Email.TEST_DIR, exist_ok=True) - # Cleanup all email files for this test suite. - prefix = Email.email_prefix(suite=True) - files = os.listdir(Email.TEST_DIR) - for file in files: - if file.startswith(prefix): - os.remove(os.path.join(Email.TEST_DIR, file)) + # Cleanup all email files for this test suite. + prefix = Email.email_prefix(suite=True) + files = os.listdir(Email.TEST_DIR) + for file in files: + if file.startswith(prefix): + os.remove(os.path.join(Email.TEST_DIR, file)) @pytest.fixture(scope="module") @@ -155,20 +149,8 @@ def setup_database(tmp_path_factory: pathlib.Path, worker_id: str) -> None: engine = test_engine() dbname = aurweb.db.name() - if worker_id == "master": # pragma: no cover - # If we're not running tests through multiproc pytest-xdist. - setup_email() - yield _create_database(engine, dbname) - _drop_database(engine, dbname) - return - - def setup(path): - setup_email() - _create_database(engine, dbname) - - tmpdir = tmp_path_factory.getbasetemp().parent - file_lock = FileLock(tmpdir, dbname) - file_lock.lock(on_create=setup) + setup_email() + _create_database(engine, dbname) yield # Run the test function depending on this fixture. _drop_database(engine, dbname) # Cleanup the database. From 1433553c05993b097e812e43496bf140df49144c Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 26 Aug 2023 17:08:36 +0200 Subject: [PATCH 1807/1891] fix(test): Clear previous prometheus data for test It could happen that test data is already generated by a previous test. (running in the same worker) Make sure we clear everything before performing our checks. Signed-off-by: moson --- test/test_statistics.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_statistics.py b/test/test_statistics.py index db262fa3..80223cbd 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -1,7 +1,7 @@ import pytest from prometheus_client import REGISTRY, generate_latest -from aurweb import cache, db, time +from aurweb import cache, db, prometheus, time from aurweb.models import Package, PackageBase, PackageRequest from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID from aurweb.models.package_request import ( @@ -140,6 +140,11 @@ def test_get_count_change(stats: Statistics, test_data): def test_update_prometheus_metrics(test_data): + # Make sure any previous data is cleared + prometheus.USERS.clear() + prometheus.PACKAGES.clear() + prometheus.REQUESTS.clear() + metrics = str(generate_latest(REGISTRY)) assert "aur_users{" not in metrics From 0a7b02956feeaaeea4813650b12ead15cfc822af Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 3 Sep 2023 14:17:11 +0200 Subject: [PATCH 1808/1891] feat: Indicate dependency source Dependencies might reside in the AUR or official repositories. Add "AUR" as superscript letters to indicate if a package/provider is present in the AUR. Signed-off-by: moson --- aurweb/models/package_dependency.py | 7 +++- aurweb/packages/util.py | 8 ++-- .../partials/packages/package_metadata.html | 7 +++- test/test_package_dependency.py | 17 ++++++++ test/test_packages_util.py | 40 +++++++++++++++++++ 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index 587ba68d..9cf1eda0 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -57,14 +57,17 @@ class PackageDependency(Base): params=("NULL"), ) - def is_package(self) -> bool: + def is_aur_package(self) -> bool: pkg = db.query(_Package).filter(_Package.Name == self.DepName).exists() + return db.query(pkg).scalar() + + def is_package(self) -> bool: official = ( db.query(_OfficialProvider) .filter(_OfficialProvider.Name == self.DepName) .exists() ) - return db.query(pkg).scalar() or db.query(official).scalar() + return self.is_aur_package() or db.query(official).scalar() def provides(self) -> list[PackageRelation]: from aurweb.models.relation_type import PROVIDES_ID diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 78d79508..cfd1e9e9 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -83,9 +83,11 @@ def package_link(package: Union[Package, OfficialProvider]) -> str: @register_filter("provides_markup") def provides_markup(provides: Providers) -> str: - return ", ".join( - [f'{pkg.Name}' for pkg in provides] - ) + links = [] + for pkg in provides: + aur = "ᴬᵁᴿ" if not pkg.is_official else "" + links.append(f'{pkg.Name}{aur}') + return ", ".join(links) def get_pkg_or_base( diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html index 50d38b48..c8d583a1 100644 --- a/templates/partials/packages/package_metadata.html +++ b/templates/partials/packages/package_metadata.html @@ -14,12 +14,15 @@ {% endif %} {{ dep.DepName }} - {% if broken %} + {%- if broken %} {% if not provides %} {% endif %} - {% else %} + {% else -%} + {%- if dep.is_aur_package() -%} + ᴬᵁᴿ + {% endif %} {% endif %} {% if provides %} diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py index 9366bb55..1cd2d305 100644 --- a/test/test_package_dependency.py +++ b/test/test_package_dependency.py @@ -4,6 +4,7 @@ from sqlalchemy.exc import IntegrityError from aurweb import db from aurweb.models.account_type import USER_ID from aurweb.models.dependency_type import DEPENDS_ID +from aurweb.models.official_provider import OfficialProvider from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency @@ -58,6 +59,22 @@ def test_package_dependencies(user: User, package: Package): db.create(Package, PackageBase=base, Name=pkgdep.DepName) assert pkgdep.is_package() + assert pkgdep.is_aur_package() + + # Test with OfficialProvider + with db.begin(): + pkgdep = db.create( + PackageDependency, + Package=package, + DepTypeID=DEPENDS_ID, + DepName="test-repo-pkg", + ) + db.create( + OfficialProvider, Name=pkgdep.DepName, Repo="extra", Provides=pkgdep.DepName + ) + + assert pkgdep.is_package() + assert not pkgdep.is_aur_package() def test_package_dependencies_null_package_raises(): diff --git a/test/test_packages_util.py b/test/test_packages_util.py index bae84614..b429181b 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -10,8 +10,10 @@ from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_notification import PackageNotification +from aurweb.models.package_relation import PackageRelation from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote +from aurweb.models.relation_type import PROVIDES_ID from aurweb.models.user import User from aurweb.packages import util @@ -155,3 +157,41 @@ def test_pkg_required(package: Package): # We should have 1 record assert qry.count() == 1 + + +def test_provides_markup(package: Package): + # Create dependency and provider for AUR pkg + with db.begin(): + dep = db.create( + PackageDependency, + Package=package, + DepName="test", + DepTypeID=DEPENDS_ID, + ) + rel_pkg = db.create(Package, PackageBase=package.PackageBase, Name=dep.DepName) + db.create( + PackageRelation, + Package=rel_pkg, + RelName=dep.DepName, + RelTypeID=PROVIDES_ID, + ) + + # AUR provider links should end with ᴬᵁᴿ + link = util.provides_markup(dep.provides()) + assert link.endswith("ᴬᵁᴿ") + assert OFFICIAL_BASE not in link + + # Remove AUR provider and add official one + with db.begin(): + db.delete(rel_pkg) + db.create( + OfficialProvider, + Name="official-pkg", + Repo="extra", + Provides=dep.DepName, + ) + + # Repo provider links should not have any suffix + link = util.provides_markup(dep.provides()) + assert link.endswith("") + assert OFFICIAL_BASE in link From 7466e964498cd9d19b93e1f38394ae358a5e6a5f Mon Sep 17 00:00:00 2001 From: moson Date: Tue, 26 Sep 2023 13:47:03 +0200 Subject: [PATCH 1809/1891] fix(ci): Exclude review-app jobs for renovate MR's Signed-off-by: moson --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cf80ab24..fb40d414 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,6 +90,8 @@ deploy_review: on_stop: stop_review auto_stop_in: 1 week rules: + - if: $CI_COMMIT_REF_NAME =~ /^renovate\// + when: never - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" when: manual @@ -141,6 +143,8 @@ provision_review: name: review/$CI_COMMIT_REF_NAME action: access rules: + - if: $CI_COMMIT_REF_NAME =~ /^renovate\// + when: never - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" stop_review: @@ -155,5 +159,7 @@ stop_review: name: review/$CI_COMMIT_REF_NAME action: stop rules: + - if: $CI_COMMIT_REF_NAME =~ /^renovate\// + when: never - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" when: manual From 1702075875514de8170b4393d5326cb61e7c5e6e Mon Sep 17 00:00:00 2001 From: moson Date: Fri, 1 Sep 2023 13:25:21 +0200 Subject: [PATCH 1810/1891] housekeep: TU rename - code changes Renaming of symbols. Functions, variables, values, DB values, etc. Basically everything that is not user-facing. This only covers "Trusted User" things: tests, comments, etc. will covered in a following commit. --- aurweb/auth/__init__.py | 4 +- aurweb/auth/creds.py | 76 ++++++++++--------- aurweb/initdb.py | 4 +- aurweb/models/account_type.py | 12 +-- aurweb/models/user.py | 12 +-- aurweb/pkgbase/actions.py | 2 +- aurweb/routers/__init__.py | 4 +- aurweb/routers/accounts.py | 16 ++-- ...{trusted_user.py => package_maintainer.py} | 59 +++++++------- aurweb/statistics.py | 16 ++-- aurweb/users/validate.py | 2 +- ...d126029_rename_tu_to_package_maintainer.py | 37 +++++++++ schema/gendummydata.py | 28 +++---- templates/addvote.html | 12 +-- templates/partials/archdev-navbar.html | 2 +- .../partials/packages/search_actions.html | 2 +- templates/partials/packages/statistics.html | 2 +- templates/partials/tu/proposals.html | 2 +- templates/tu/index.html | 6 +- test/test_accounts_routes.py | 48 ++++++------ test/test_adduser.py | 4 +- test/test_auth.py | 4 +- test/test_homepage.py | 2 +- test/test_html.py | 10 +-- test/test_notify.py | 4 +- test/test_packages_routes.py | 4 +- test/test_pkgbase_routes.py | 4 +- test/test_requests.py | 4 +- test/test_statistics.py | 14 ++-- test/test_trusted_user_routes.py | 14 ++-- test/test_tu_vote.py | 4 +- test/test_tu_voteinfo.py | 4 +- test/test_tuvotereminder.py | 8 +- test/test_user.py | 42 +++++----- 34 files changed, 265 insertions(+), 203 deletions(-) rename aurweb/routers/{trusted_user.py => package_maintainer.py} (88%) create mode 100644 migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 83dd424c..e895dcdb 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -71,7 +71,7 @@ class AnonymousUser: return False @staticmethod - def is_trusted_user(): + def is_package_maintainer(): return False @staticmethod @@ -205,7 +205,7 @@ def account_type_required(one_of: set): @router.get('/some_route') @auth_required(True) - @account_type_required({"Trusted User", "Trusted User & Developer"}) + @account_type_required({"Package Maintainer", "Package Maintainer & Developer"}) async def some_route(request: fastapi.Request): return Response() diff --git a/aurweb/auth/creds.py b/aurweb/auth/creds.py index 17d02a5b..594188ca 100644 --- a/aurweb/auth/creds.py +++ b/aurweb/auth/creds.py @@ -1,7 +1,7 @@ from aurweb.models.account_type import ( DEVELOPER_ID, - TRUSTED_USER_AND_DEV_ID, - TRUSTED_USER_ID, + PACKAGE_MAINTAINER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, USER_ID, ) from aurweb.models.user import User @@ -30,47 +30,49 @@ PKGBASE_VOTE = 16 PKGREQ_FILE = 23 PKGREQ_CLOSE = 17 PKGREQ_LIST = 18 -TU_ADD_VOTE = 19 -TU_LIST_VOTES = 20 -TU_VOTE = 21 +PM_ADD_VOTE = 19 +PM_LIST_VOTES = 20 +PM_VOTE = 21 PKGBASE_MERGE = 29 -user_developer_or_trusted_user = set( - [USER_ID, TRUSTED_USER_ID, DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID] +user_developer_or_package_maintainer = set( + [USER_ID, PACKAGE_MAINTAINER_ID, DEVELOPER_ID, PACKAGE_MAINTAINER_AND_DEV_ID] ) -trusted_user_or_dev = set([TRUSTED_USER_ID, DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID]) -developer = set([DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID]) -trusted_user = set([TRUSTED_USER_ID, TRUSTED_USER_AND_DEV_ID]) +package_maintainer_or_dev = set( + [PACKAGE_MAINTAINER_ID, DEVELOPER_ID, PACKAGE_MAINTAINER_AND_DEV_ID] +) +developer = set([DEVELOPER_ID, PACKAGE_MAINTAINER_AND_DEV_ID]) +package_maintainer = set([PACKAGE_MAINTAINER_ID, PACKAGE_MAINTAINER_AND_DEV_ID]) cred_filters = { - PKGBASE_FLAG: user_developer_or_trusted_user, - PKGBASE_NOTIFY: user_developer_or_trusted_user, - PKGBASE_VOTE: user_developer_or_trusted_user, - PKGREQ_FILE: user_developer_or_trusted_user, - ACCOUNT_CHANGE_TYPE: trusted_user_or_dev, - ACCOUNT_EDIT: trusted_user_or_dev, - ACCOUNT_LAST_LOGIN: trusted_user_or_dev, - ACCOUNT_LIST_COMMENTS: trusted_user_or_dev, - ACCOUNT_SEARCH: trusted_user_or_dev, - COMMENT_DELETE: trusted_user_or_dev, - COMMENT_UNDELETE: trusted_user_or_dev, - COMMENT_VIEW_DELETED: trusted_user_or_dev, - COMMENT_EDIT: trusted_user_or_dev, - COMMENT_PIN: trusted_user_or_dev, - PKGBASE_ADOPT: trusted_user_or_dev, - PKGBASE_SET_KEYWORDS: trusted_user_or_dev, - PKGBASE_DELETE: trusted_user_or_dev, - PKGBASE_EDIT_COMAINTAINERS: trusted_user_or_dev, - PKGBASE_DISOWN: trusted_user_or_dev, - PKGBASE_LIST_VOTERS: trusted_user_or_dev, - PKGBASE_UNFLAG: trusted_user_or_dev, - PKGREQ_CLOSE: trusted_user_or_dev, - PKGREQ_LIST: trusted_user_or_dev, - TU_ADD_VOTE: trusted_user, - TU_LIST_VOTES: trusted_user_or_dev, - TU_VOTE: trusted_user, + PKGBASE_FLAG: user_developer_or_package_maintainer, + PKGBASE_NOTIFY: user_developer_or_package_maintainer, + PKGBASE_VOTE: user_developer_or_package_maintainer, + PKGREQ_FILE: user_developer_or_package_maintainer, + ACCOUNT_CHANGE_TYPE: package_maintainer_or_dev, + ACCOUNT_EDIT: package_maintainer_or_dev, + ACCOUNT_LAST_LOGIN: package_maintainer_or_dev, + ACCOUNT_LIST_COMMENTS: package_maintainer_or_dev, + ACCOUNT_SEARCH: package_maintainer_or_dev, + COMMENT_DELETE: package_maintainer_or_dev, + COMMENT_UNDELETE: package_maintainer_or_dev, + COMMENT_VIEW_DELETED: package_maintainer_or_dev, + COMMENT_EDIT: package_maintainer_or_dev, + COMMENT_PIN: package_maintainer_or_dev, + PKGBASE_ADOPT: package_maintainer_or_dev, + PKGBASE_SET_KEYWORDS: package_maintainer_or_dev, + PKGBASE_DELETE: package_maintainer_or_dev, + PKGBASE_EDIT_COMAINTAINERS: package_maintainer_or_dev, + PKGBASE_DISOWN: package_maintainer_or_dev, + PKGBASE_LIST_VOTERS: package_maintainer_or_dev, + PKGBASE_UNFLAG: package_maintainer_or_dev, + PKGREQ_CLOSE: package_maintainer_or_dev, + PKGREQ_LIST: package_maintainer_or_dev, + PM_ADD_VOTE: package_maintainer, + PM_LIST_VOTES: package_maintainer_or_dev, + PM_VOTE: package_maintainer, ACCOUNT_EDIT_DEV: developer, - PKGBASE_MERGE: trusted_user_or_dev, + PKGBASE_MERGE: package_maintainer_or_dev, } diff --git a/aurweb/initdb.py b/aurweb/initdb.py index ee59212c..7181ea3e 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -13,9 +13,9 @@ def feed_initial_data(conn): aurweb.schema.AccountTypes.insert(), [ {"ID": 1, "AccountType": "User"}, - {"ID": 2, "AccountType": "Trusted User"}, + {"ID": 2, "AccountType": "Package Maintainer"}, {"ID": 3, "AccountType": "Developer"}, - {"ID": 4, "AccountType": "Trusted User & Developer"}, + {"ID": 4, "AccountType": "Package Maintainer & Developer"}, ], ) conn.execute( diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py index 315800a7..70bfc2c5 100644 --- a/aurweb/models/account_type.py +++ b/aurweb/models/account_type.py @@ -2,21 +2,21 @@ from aurweb import schema from aurweb.models.declarative import Base USER = "User" -TRUSTED_USER = "Trusted User" +PACKAGE_MAINTAINER = "Package Maintainer" DEVELOPER = "Developer" -TRUSTED_USER_AND_DEV = "Trusted User & Developer" +PACKAGE_MAINTAINER_AND_DEV = "Package Maintainer & Developer" USER_ID = 1 -TRUSTED_USER_ID = 2 +PACKAGE_MAINTAINER_ID = 2 DEVELOPER_ID = 3 -TRUSTED_USER_AND_DEV_ID = 4 +PACKAGE_MAINTAINER_AND_DEV_ID = 4 # Map string constants to integer constants. ACCOUNT_TYPE_ID = { USER: USER_ID, - TRUSTED_USER: TRUSTED_USER_ID, + PACKAGE_MAINTAINER: PACKAGE_MAINTAINER_ID, DEVELOPER: DEVELOPER_ID, - TRUSTED_USER_AND_DEV: TRUSTED_USER_AND_DEV_ID, + PACKAGE_MAINTAINER_AND_DEV: PACKAGE_MAINTAINER_AND_DEV_ID, } # Reversed ACCOUNT_TYPE_ID mapping. diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 8612c259..f90d19eb 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -157,25 +157,25 @@ class User(Base): with db.begin(): db.delete(self.session) - def is_trusted_user(self): + def is_package_maintainer(self): return self.AccountType.ID in { - aurweb.models.account_type.TRUSTED_USER_ID, - aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID, + aurweb.models.account_type.PACKAGE_MAINTAINER_ID, + aurweb.models.account_type.PACKAGE_MAINTAINER_AND_DEV_ID, } def is_developer(self): return self.AccountType.ID in { aurweb.models.account_type.DEVELOPER_ID, - aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID, + aurweb.models.account_type.PACKAGE_MAINTAINER_AND_DEV_ID, } def is_elevated(self): """A User is 'elevated' when they have either a Trusted User or Developer AccountType.""" return self.AccountType.ID in { - aurweb.models.account_type.TRUSTED_USER_ID, + aurweb.models.account_type.PACKAGE_MAINTAINER_ID, aurweb.models.account_type.DEVELOPER_ID, - aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID, + aurweb.models.account_type.PACKAGE_MAINTAINER_AND_DEV_ID, } def can_edit_user(self, target: "User") -> bool: diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 00efc1ff..f3688f54 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -187,7 +187,7 @@ def pkgbase_merge_instance( # Log this out for accountability purposes. logger.info( - f"Trusted User '{request.user.Username}' merged " + f"Package Maintainer '{request.user.Username}' merged " f"'{pkgbasename}' into '{target.Name}'." ) diff --git a/aurweb/routers/__init__.py b/aurweb/routers/__init__.py index f77bce4f..ccd70662 100644 --- a/aurweb/routers/__init__.py +++ b/aurweb/routers/__init__.py @@ -7,13 +7,13 @@ from . import ( accounts, auth, html, + package_maintainer, packages, pkgbase, requests, rpc, rss, sso, - trusted_user, ) """ @@ -28,7 +28,7 @@ APP_ROUTES = [ packages, pkgbase, requests, - trusted_user, + package_maintainer, rss, rpc, sso, diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 1c81ec1d..a2d167bc 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -184,9 +184,9 @@ def make_account_form_context( lambda e: request.user.AccountTypeID >= e[0], [ (at.USER_ID, f"Normal {at.USER}"), - (at.TRUSTED_USER_ID, at.TRUSTED_USER), + (at.PACKAGE_MAINTAINER_ID, at.PACKAGE_MAINTAINER), (at.DEVELOPER_ID, at.DEVELOPER), - (at.TRUSTED_USER_AND_DEV_ID, at.TRUSTED_USER_AND_DEV), + (at.PACKAGE_MAINTAINER_AND_DEV_ID, at.PACKAGE_MAINTAINER_AND_DEV), ], ) ) @@ -520,7 +520,9 @@ async def account_comments(request: Request, username: str): @router.get("/accounts") @requires_auth -@account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) +@account_type_required( + {at.PACKAGE_MAINTAINER, at.DEVELOPER, at.PACKAGE_MAINTAINER_AND_DEV} +) async def accounts(request: Request): context = make_context(request, "Accounts") return render_template(request, "account/search.html", context) @@ -529,7 +531,9 @@ async def accounts(request: Request): @router.post("/accounts") @handle_form_exceptions @requires_auth -@account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) +@account_type_required( + {at.PACKAGE_MAINTAINER, at.DEVELOPER, at.PACKAGE_MAINTAINER_AND_DEV} +) async def accounts_post( request: Request, O: int = Form(default=0), # Offset @@ -564,9 +568,9 @@ async def accounts_post( # Convert parameter T to an AccountType ID. account_types = { "u": at.USER_ID, - "t": at.TRUSTED_USER_ID, + "t": at.PACKAGE_MAINTAINER_ID, "d": at.DEVELOPER_ID, - "td": at.TRUSTED_USER_AND_DEV_ID, + "td": at.PACKAGE_MAINTAINER_AND_DEV_ID, } account_type_id = account_types.get(T, None) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/package_maintainer.py similarity index 88% rename from aurweb/routers/trusted_user.py rename to aurweb/routers/package_maintainer.py index 4248347d..c5e70dcf 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/package_maintainer.py @@ -11,7 +11,10 @@ from aurweb import aur_logging, db, l10n, models, time from aurweb.auth import creds, requires_auth from aurweb.exceptions import handle_form_exceptions from aurweb.models import User -from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID +from aurweb.models.account_type import ( + PACKAGE_MAINTAINER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, +) from aurweb.templates import make_context, make_variable_context, render_template router = APIRouter() @@ -26,32 +29,32 @@ ADDVOTE_SPECIFICS = { # When a proposal is added, duration is added to the current # timestamp. # "addvote_type": (duration, quorum) - "add_tu": (7 * 24 * 60 * 60, 0.66), - "remove_tu": (7 * 24 * 60 * 60, 0.75), - "remove_inactive_tu": (5 * 24 * 60 * 60, 0.66), + "add_pm": (7 * 24 * 60 * 60, 0.66), + "remove_pm": (7 * 24 * 60 * 60, 0.75), + "remove_inactive_pm": (5 * 24 * 60 * 60, 0.66), "bylaws": (7 * 24 * 60 * 60, 0.75), } -def populate_trusted_user_counts(context: dict[str, Any]) -> None: - tu_query = db.query(User).filter( +def populate_package_maintainer_counts(context: dict[str, Any]) -> None: + pm_query = db.query(User).filter( or_( - User.AccountTypeID == TRUSTED_USER_ID, - User.AccountTypeID == TRUSTED_USER_AND_DEV_ID, + User.AccountTypeID == PACKAGE_MAINTAINER_ID, + User.AccountTypeID == PACKAGE_MAINTAINER_AND_DEV_ID, ) ) - context["trusted_user_count"] = tu_query.count() + context["package_maintainer_count"] = pm_query.count() # In case any records have a None InactivityTS. - active_tu_query = tu_query.filter( + active_pm_query = pm_query.filter( or_(User.InactivityTS.is_(None), User.InactivityTS == 0) ) - context["active_trusted_user_count"] = active_tu_query.count() + context["active_package_maintainer_count"] = active_pm_query.count() @router.get("/tu") @requires_auth -async def trusted_user( +async def package_maintainer( request: Request, coff: int = 0, # current offset cby: str = "desc", # current by @@ -63,7 +66,7 @@ async def trusted_user( if not request.user.has_credential(creds.TU_LIST_VOTES): return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) - context = make_context(request, "Trusted User") + context = make_context(request, "Package Maintainer") current_by, past_by = cby, pby current_off, past_off = coff, poff @@ -108,7 +111,7 @@ async def trusted_user( context["past_off"] = past_off last_vote = func.max(models.TUVote.VoteID).label("LastVote") - last_votes_by_tu = ( + last_votes_by_pm = ( db.query(models.TUVote) .join(models.User) .join(models.TUVoteInfo, models.TUVoteInfo.ID == models.TUVote.VoteID) @@ -124,12 +127,12 @@ async def trusted_user( .group_by(models.TUVote.UserID) .order_by(last_vote.desc(), models.User.Username.asc()) ) - context["last_votes_by_tu"] = last_votes_by_tu.all() + context["last_votes_by_pm"] = last_votes_by_pm.all() context["current_by_next"] = "asc" if current_by == "desc" else "desc" context["past_by_next"] = "asc" if past_by == "desc" else "desc" - populate_trusted_user_counts(context) + populate_package_maintainer_counts(context) context["q"] = { "coff": current_off, @@ -178,11 +181,11 @@ def render_proposal( @router.get("/tu/{proposal}") @requires_auth -async def trusted_user_proposal(request: Request, proposal: int): +async def package_maintainer_proposal(request: Request, proposal: int): if not request.user.has_credential(creds.TU_LIST_VOTES): return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER) - context = await make_variable_context(request, "Trusted User") + context = await make_variable_context(request, "Package Maintainer") proposal = int(proposal) voteinfo = ( @@ -221,13 +224,13 @@ async def trusted_user_proposal(request: Request, proposal: int): @router.post("/tu/{proposal}") @handle_form_exceptions @requires_auth -async def trusted_user_proposal_post( +async def package_maintainer_proposal_post( request: Request, proposal: int, decision: str = Form(...) ): if not request.user.has_credential(creds.TU_LIST_VOTES): return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER) - context = await make_variable_context(request, "Trusted User") + context = await make_variable_context(request, "Package Maintainer") proposal = int(proposal) # Make sure it's an int. voteinfo = ( @@ -285,8 +288,8 @@ async def trusted_user_proposal_post( @router.get("/addvote") @requires_auth -async def trusted_user_addvote( - request: Request, user: str = str(), type: str = "add_tu", agenda: str = str() +async def package_maintainer_addvote( + request: Request, user: str = str(), type: str = "add_pm", agenda: str = str() ): if not request.user.has_credential(creds.TU_ADD_VOTE): return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER) @@ -295,7 +298,7 @@ async def trusted_user_addvote( if type not in ADDVOTE_SPECIFICS: context["error"] = "Invalid type." - type = "add_tu" # Default it. + type = "add_pm" # Default it. context["user"] = user context["type"] = type @@ -308,7 +311,7 @@ async def trusted_user_addvote( @router.post("/addvote") @handle_form_exceptions @requires_auth -async def trusted_user_addvote_post( +async def package_maintainer_addvote_post( request: Request, user: str = Form(default=str()), type: str = Form(default=str()), @@ -352,7 +355,7 @@ async def trusted_user_addvote_post( if type not in ADDVOTE_SPECIFICS: context["error"] = "Invalid type." - context["type"] = type = "add_tu" # Default for rendering. + context["type"] = type = "add_pm" # Default for rendering. return render_addvote(context, HTTPStatus.BAD_REQUEST) if not agenda: @@ -364,11 +367,11 @@ async def trusted_user_addvote_post( timestamp = time.utcnow() # Active TU types we filter for. - types = {TRUSTED_USER_ID, TRUSTED_USER_AND_DEV_ID} + types = {PACKAGE_MAINTAINER_ID, PACKAGE_MAINTAINER_AND_DEV_ID} # Create a new TUVoteInfo (proposal)! with db.begin(): - active_tus = ( + active_pms = ( db.query(User) .filter( and_( @@ -386,7 +389,7 @@ async def trusted_user_addvote_post( Submitted=timestamp, End=(timestamp + duration), Quorum=quorum, - ActiveTUs=active_tus, + ActiveTUs=active_pms, Submitter=request.user, ) diff --git a/aurweb/statistics.py b/aurweb/statistics.py index f301b59c..00a5c151 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -3,7 +3,11 @@ from sqlalchemy import func from aurweb import config, db, time from aurweb.cache import db_count_cache, db_query_cache from aurweb.models import PackageBase, PackageRequest, RequestType, User -from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.models.account_type import ( + PACKAGE_MAINTAINER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, + USER_ID, +) from aurweb.models.package_request import ( ACCEPTED_ID, CLOSED_ID, @@ -22,7 +26,7 @@ HOMEPAGE_COUNTERS = [ "year_old_updated", "never_updated", "user_count", - "trusted_user_count", + "package_maintainer_count", ] REQUEST_COUNTERS = [ "total_requests", @@ -32,7 +36,7 @@ REQUEST_COUNTERS = [ "rejected_requests", ] PROMETHEUS_USER_COUNTERS = [ - ("trusted_user_count", "tu"), + ("package_maintainer_count", "package_maintainer"), ("regular_user_count", "user"), ] PROMETHEUS_PACKAGE_COUNTERS = [ @@ -92,12 +96,12 @@ class Statistics: # Users case "user_count": query = self.user_query - case "trusted_user_count": + case "package_maintainer_count": query = self.user_query.filter( User.AccountTypeID.in_( ( - TRUSTED_USER_ID, - TRUSTED_USER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, + PACKAGE_MAINTAINER_AND_DEV_ID, ) ) ) diff --git a/aurweb/users/validate.py b/aurweb/users/validate.py index 8fc68864..5f1fcd43 100644 --- a/aurweb/users/validate.py +++ b/aurweb/users/validate.py @@ -220,7 +220,7 @@ def invalid_account_type( raise ValidationError([error]) logger.debug( - f"Trusted User '{request.user.Username}' has " + f"Package Maintainer '{request.user.Username}' has " f"modified '{user.Username}' account's type to" f" {name}." ) diff --git a/migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py b/migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py new file mode 100644 index 00000000..005549b0 --- /dev/null +++ b/migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py @@ -0,0 +1,37 @@ +"""Rename TU to Package Maintainer + +Revision ID: 6a64dd126029 +Revises: c5a6a9b661a0 +Create Date: 2023-09-01 13:48:15.315244 + +""" +from aurweb import db +from aurweb.models import AccountType + +# revision identifiers, used by Alembic. +revision = "6a64dd126029" +down_revision = "c5a6a9b661a0" +branch_labels = None +depends_on = None + +# AccountTypes +# ID 2 -> Trusted User / Package Maintainer +# ID 4 -> Trusted User & Developer / Package Maintainer & Developer + + +def upgrade(): + with db.begin(): + tu = db.query(AccountType).filter(AccountType.ID == 2).first() + tudev = db.query(AccountType).filter(AccountType.ID == 4).first() + + tu.AccountType = "Package Maintainer" + tudev.AccountType = "Package Maintainer & Developer" + + +def downgrade(): + with db.begin(): + pm = db.query(AccountType).filter(AccountType.ID == 2).first() + pmdev = db.query(AccountType).filter(AccountType.ID == 4).first() + + pm.AccountType = "Trusted User" + pmdev.AccountType = "Trusted User & Developer" diff --git a/schema/gendummydata.py b/schema/gendummydata.py index dfc8eee5..25f85c74 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -156,9 +156,9 @@ contents = None # developer/tu IDs # developers = [] -trustedusers = [] +packagemaintainers = [] has_devs = 0 -has_tus = 0 +has_pms = 0 # Just let python throw the errors if any happen # @@ -170,7 +170,7 @@ out.write("BEGIN;\n") log.debug("Creating SQL statements for users.") for u in user_keys: account_type = 1 # default to normal user - if not has_devs or not has_tus: + if not has_devs or not has_pms: account_type = random.randrange(1, 4) if account_type == 3 and not has_devs: # this will be a dev account @@ -178,12 +178,12 @@ for u in user_keys: developers.append(seen_users[u]) if len(developers) >= MAX_DEVS * MAX_USERS: has_devs = 1 - elif account_type == 2 and not has_tus: + elif account_type == 2 and not has_pms: # this will be a trusted user account # - trustedusers.append(seen_users[u]) - if len(trustedusers) >= MAX_TUS * MAX_USERS: - has_tus = 1 + packagemaintainers.append(seen_users[u]) + if len(packagemaintainers) >= MAX_TUS * MAX_USERS: + has_pms = 1 else: # a normal user account # @@ -205,8 +205,10 @@ for u in user_keys: out.write(s) log.debug("Number of developers: %d" % len(developers)) -log.debug("Number of trusted users: %d" % len(trustedusers)) -log.debug("Number of users: %d" % (MAX_USERS - len(developers) - len(trustedusers))) +log.debug("Number of package maintainers: %d" % len(packagemaintainers)) +log.debug( + "Number of users: %d" % (MAX_USERS - len(developers) - len(packagemaintainers)) +) log.debug("Number of packages: %d" % MAX_PKGS) log.debug("Gathering text from fortune file...") @@ -224,8 +226,8 @@ for p in list(seen_pkgs.keys()): muid = developers[random.randrange(0, len(developers))] puid = developers[random.randrange(0, len(developers))] else: - muid = trustedusers[random.randrange(0, len(trustedusers))] - puid = trustedusers[random.randrange(0, len(trustedusers))] + muid = packagemaintainers[random.randrange(0, len(packagemaintainers))] + puid = packagemaintainers[random.randrange(0, len(packagemaintainers))] if count % 20 == 0: # every so often, there are orphans... muid = "NULL" @@ -339,7 +341,7 @@ for p in seen_pkgs_keys: # Create trusted user proposals # -log.debug("Creating SQL statements for trusted user proposals.") +log.debug("Creating SQL statements for package maintainer proposals.") count = 0 for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS): now = int(time.time()) @@ -353,7 +355,7 @@ for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS): user = "" else: user = user_keys[random.randrange(0, len(user_keys))] - suid = trustedusers[random.randrange(0, len(trustedusers))] + suid = packagemaintainers[random.randrange(0, len(packagemaintainers))] s = ( "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End," " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n" diff --git a/templates/addvote.html b/templates/addvote.html index 8777cbf3..30b65c0e 100644 --- a/templates/addvote.html +++ b/templates/addvote.html @@ -19,22 +19,22 @@

    - + - +

    diff --git a/templates/addvote.html b/templates/addvote.html index 30b65c0e..cc12f42b 100644 --- a/templates/addvote.html +++ b/templates/addvote.html @@ -24,21 +24,21 @@ selected {% endif %} > - {{ "Addition of a TU" | tr }} + {{ "Addition of a Package Maintainer" | tr }}

  • - {% trans %}Trusted User{% endtrans %} + {% trans %}Package Maintainer{% endtrans %}
  • {% endif %} diff --git a/templates/partials/packages/statistics.html b/templates/partials/packages/statistics.html index 7c3c3ef6..7ce5fba1 100644 --- a/templates/partials/packages/statistics.html +++ b/templates/partials/packages/statistics.html @@ -42,7 +42,7 @@ - {{ "Trusted Users" | tr }} + {{ "Package Maintainers" | tr }} {{ package_maintainer_count }} diff --git a/templates/partials/support.html b/templates/partials/support.html index a2890cc5..b175a040 100644 --- a/templates/partials/support.html +++ b/templates/partials/support.html @@ -10,7 +10,7 @@

    • {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
    • -
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
    • +
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the maintainer and file orphan request if necessary.{% endtrans %}
    • {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}

    @@ -44,7 +44,7 @@

    {% trans %}Discussion{% endtrans %}

    - {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." + {{ "General discussion regarding the Arch User Repository (AUR) and Package Maintainer structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." | tr | format('', "", '', "") @@ -55,7 +55,7 @@

    {% trans %}Bug Reporting{% endtrans %}

    - {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page." + {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the maintainer or leave a comment on the appropriate package page." | tr | format('', "", "", "") diff --git a/templates/partials/tu/proposal/details.html b/templates/partials/tu/proposal/details.html index 4cbee9ad..c74a5c5e 100644 --- a/templates/partials/tu/proposal/details.html +++ b/templates/partials/tu/proposal/details.html @@ -22,7 +22,7 @@

    - {{ "Active" | tr }} {{ "Trusted Users" | tr }} {{ "assigned" | tr }}: + {{ "Active" | tr }} {{ "Package Maintainers" | tr }} {{ "assigned" | tr }}: {{ voteinfo.ActiveTUs }}
    diff --git a/templates/pkgbase/request.html b/templates/pkgbase/request.html index 61654a49..3ffa2d2d 100644 --- a/templates/pkgbase/request.html +++ b/templates/pkgbase/request.html @@ -69,8 +69,8 @@

    {{ - "By submitting a deletion request, you ask a Trusted " - "User to delete the package base. This type of " + "By submitting a deletion request, you ask a Package " + "Maintainer to delete the package base. This type of " "request should be used for duplicates, software " "abandoned by upstream, as well as illegal and " "irreparably broken packages." | tr @@ -79,8 +79,8 @@